commit 50868cd2d277149c3733f051facfa3c67568700c Author: Adam Date: Sun May 17 10:49:37 2020 -0700 inital commit diff --git a/AG.DOC b/AG.DOC new file mode 100644 index 0000000..668588a --- /dev/null +++ b/AG.DOC @@ -0,0 +1,7051 @@ + + + + + + +MICROSOFT(R) + +MS(tm)-DOS + +Adaptation Guide + +Last Updated on JULY 24, 1987 +in conjunction with the MS-DOS 3.30 FINAL RELEASE + + + + + + + + + + + + + +Microsoft Corporation + + +Information in this document is subject to change without +notice and does not represent a commitment on the part of +Microsoft Corporation. The software described in this +document is furnished under a license agreement or +non-disclosure agreement. The software may be used or +copied only in accordance with the terms of that agreement. +It is against the law to copy the MS-DOS Disk Operating +System on magnetic tape, disk, or any other medium for any +purpose other than the purchaser's personal use. + + + +Copyright (C) Microsoft Corporation, 1982, 1983, 1984, 1985, 1986 + + + + + + + + + +INTEL is a registered trademark of Intel Corporation. + +IBM is a registered trademark of International Business +Machines Corporation. + +Microsoft, the Microsoft logo, and MS-DOS are registered +trademarks of Microsoft Corporation. + +XENIX is a trademark of Microsoft Corporation. + + + + + TABLE OF CONTENTS + + + +CHAPTER 1 MS-DOS INSTALLATION KIT + + 1.1 README.DOC File 1-1 + +CHAPTER 2 MS-DOS DEVELOPMENT TOOLS + +CHAPTER 3 INSTALLING MS-DOS + +CHAPTER 4 DISK STRUCTURE AND BOOTSTRAP LOADING + +CHAPTER 5 RESIDENT DEVICE DRIVERS + +CHAPTER 6 SYSINIT AND MS-DOS INITIALIZATION + +CHAPTER 7 WRITING THE FORMAT MODULE + +CHAPTER 8 TROUBLE SHOOTING + +APPENDIX A CUSTOMIZATION OF MS-DOS AND + INTERNATIONALIZATION + + A.1 Customizing MS-DOS A-1 + A.2 ECS Considerations -- MS-DOS 2.25 A-2 + A.3 Input A-3 + A.4 Output A-3 + +APPENDIX B HOW TO UPGRADE A 2.X BIOS TO 3.X + +APPENDIX C HOW TO UPGRADE A 3.1 BIOS TO 3.2 + +APPENDIX D DEVICE DRIVERS - CHAPTER 2 MS-DOS 3.20 PROGRAMMER'S REFERENCE + +APPENDIX E MS-DOS 2.25 DEVICE DRIVER EXTENSIONS + +APPENDIX F MS-DOS 2.25 APPLICATION LEVEL INTERFACE EXTENSION + +APPENDIX G SPECIAL DOC + +APPENDIX H PROGRAMMING RECOMMENDATIONS - CHAPTER 7 MS-DOS 3.20 + PROGRAMMER'S REFERENCE + +GLOSSARY OF MS-DOS TERMS + + + + + CONTENTS + +CHAPTER 1 MS-DOS INSTALLATION KIT + + 1.1 README.DOC File 1-1 + + 1.2 Contents 1-1 + + 1.3 Common Questions and Answers 1-2 + + 1.4 MS-DOS Hardware Requirements 1-3 + + 1.5 MS-DOS Overview 1-5 + + + + + + CHAPTER 1 + + MS-DOS INSTALLATION KIT + + + +1.1 README.DOC FILE + +Check the README.DOC file on DISTRIBUTION DISKETTES for +version specific information and any addenda to this document. + + + +1.2 CONTENTS + +The MS-DOS 3.21 Installation Kit is provided on 5-1/4" high capacity +1.2 Megabyte disks. It consists of the MS-DOS DISTRIBUTION +DISKETTES that include files formerly found +version. + +Included with the kit is a Sample MS-DOS 2.XX/3.XX Implementation. +The sample implementation runs on all members of the IBM PC family and +is intended to be functionally equivalent to the IBM implementation. +The purpose of this sample is to assist Microsoft OEMs with their +MS-DOS installations, but can also be used directly as part of the OEMs +product. IO.SYS, the BIOS, has been intended to be self documenting and +Microsoft will support services for it as it run on IBM PCs. + +Included in the kit is a copy of the current Microsoft(R) Macro Assembler +featuring SYMDEB, the symbolic debugger. The full MASM retail package is +no longer provided. + +The installation kit also includes four manuals: + + MS-DOS User's Guide. This is an introduction to ______ ______ _____ + MS-DOS, including how to start the system and use + applications. + + MS-DOS User's Reference Manual. This manual ______ ______ _________ ______ + explains hierarchical directories, the MS-DOS file + structure, and MS-DOS commands and utilities. This + manual is new in 3.XX. + + MS-DOS Programmer's Reference Manual. This manual ______ ____________ _________ ______ + includes a summary of all published system calls + and MS-DOS structures. + + MS-DOS Adaptation Guide. This manual describes how ______ __________ _____ + to implement MS-DOS on OEM machines. This guide is + available on diskette only and is the text you are + now reading. + + MS-DOS INSTALLATION KIT Page 1-2 + + +1.3 COMMON QUESTIONS AND ANSWERS + +Q. What kind of development machine do you recommend? + +A. Microsoft recommends that an MS-DOS machine be used as a + development tool in preparing software for your target + machine. Using an MS-DOS machine avoids problems with + incompatible assemblers and object module formats. You + may want to read standard MS-DOS disk formats. Using + the development machine to build a system disk for the + target machine simplifies the implementation process. + +Q. Are sources available? + +A. Sources for MS-DOS are not available (except for the sample + BIOS implementation). + +Q. What language is MS-DOS written in? + +A. The source code for MS-DOS and most utilities is written + in 8086 assembler code. It is compatible with the macro + facility found in Microsoft Macro Assembler for the + MS-DOS operating system. The format of the object + modules provided is a subset of the INTEL(R) format, and + may not be compatible with non-Microsoft linkers. + +Q. What does an MS-DOS implementor need to know? + +A. To install MS-DOS, you will need to be familiar with + systems programming in 8086 assembler language. This + means you should have experience in writing device + drivers for disk drives, keyboards, printers, and other + peripherals. + +Q. How long does it take to install MS-DOS? + +A. This depends on whether the low-level I/O routines are + already written. The record time for getting MS-DOS up + and running on a new machine is one weekend. In this + case, all of the low-level routines were in ROM. + Typically, a complete customer-ready MS-DOS + implementation takes two or more months. + + MS-DOS INSTALLATION KIT Page 1-3 + + +Q. Are there any consultants who do MS-DOS implementations? + +A. Microsoft can supply a list of consultants who have done + MS-DOS implementations. Microsoft cannot make any + recommendations regarding the competence of these + consultants. + +Q. Do you recommend that we have an In Circuit Emulator + (ICE) for our machine? + +A. Yes. Since there are no MS-DOS debugging tools that can + be used to debug the boot sequence, an ICE is very + helpful. + + + +1.4 MS-DOS HARDWARE REQUIREMENTS + +To be compatible with the MS-DOS operating system, a machine +must conform to certain hardware characteristics. These +characteristics are as follows: + + + o The processor must be INTEL 8086 compatible. + + o The Interrupt vector locations 20H through 3FH must + be reserved for MS-DOS. + + o Four character device drivers and one block device + driver are required. They must recognize the + MS-DOS device driver call format. + + o An ANSI terminal driver must be implemented. + (MS-DOS sends an ANSI escape sequence to clear the + console.) + + o A logical disk, as described in this document, must + be available to MS-DOS. A disk format table, as + described in this document, should be present in + the first logical sector of each disk. Logical + sectors must be a multiple of 64 bytes in size. + + o Random Access Memory (RAM) should be contiguous + from the point where MS-DOS is located through top + of memory. + + o MS-DOS requires a minimum of 128K of RAM (depending + on IO.SYS size). Microsoft recommends a minimum + configuration of 128K non-video RAM and 192K for + future products. + +The sample BIOS that is provided has been designed to only run on +a machine with the exact architecture of IBM PC family. +If MS-DOS can run on the OEMs hardware using the sample BIOS, then +the hardware is compatible with the IBM PC family architecture. + + MS-DOS INSTALLATION KIT Page 1-4 + +In addition to these minimum requirements, the following +hardware features are recommended for optimum performance as +well as compatibility with new Microsoft products. Features +recommended for performance on 2.0 and higher systems are +starred. + + + o *An interrupt-driven keyboard with a type-ahead + buffer (Interrupt-driven I/O for all devices). + + o *Direct memory access. + + o *Non-interlaced disks. + + o *Disk door locks or a detection mechanism to check + if disks have been changed. + + o Support of standard MS-DOS disk formats. + + o User-addressable bit-mapped video display with + minimum resolution of 640 by 200 pixels. + + o Programmable interval timer. + + o Mouse support. + + o RS-232 and printer interfaces. + + o Minimum 192K RAM memory. + + o A Scroll Lock/Break key that puts a Control-S and + Control-C at the beginning of the keyboard + type-ahead buffer when pressed. + + MS-DOS INSTALLATION KIT Page 1-5 + + +1.5 MS-DOS OVERVIEW + +An MS-DOS implementation requires seven components: + + + 1. The resident device drivers (the IO.SYS file), a + collection of hardware-specific device drivers that + must be written by the OEM. The resident device + drivers are called by MS-DOS to handle I/O + requests. These device drivers may be partly ROM + resident or may be completely RAM resident. + + + 2. The SYSINIT Module(s), (SYSINIT1.OBJ and SYSINIT2.OBJ + in 3.xx and only SYSINIT.OBJ in 2.xx) and SYSIMES.OBJ, + Microsoft-supplied modules which are linked to the + resident device drivers and initialize the system. + The file that contains these device drivers is + named IO.SYS (on the IBM(R) PC, this file is named + IBMBIO.COM). + + + 3. MSDOS.SYS, the hardware-independent disk operating + system supplied by Microsoft. (On the IBM PC, this + file is named IBMDOS.COM.) + + + 4. COMMAND.COM, the command interpreter program that + reads and interprets keyboard input, executes + "built-in" commands like DIR, and initiates + external programs. + + + 5. Bootstrap loader, the OEM-supplied module that + loads the IO.SYS and MSDOS.SYS files into memory. + MSDOS.SYS may optionally be loaded by IO.SYS. + A sample bootstrap loader has been provided with + the OEM kit. This sample bootstrap loader is + compatible with the IBM PC family. + + + 6. A system ROM which may optionally perform + diagnostics on power-up or reset. The system ROM + loads the boot sector into RAM and transfers + control to it. + + + 7. MS-DOS utilities, including FORMAT, for which + Microsoft modules are provided and a + hardware-specific section must be written by the + OEM. NOTE: Refer to the MS-DOS 3.3 specific portions + for use of the hardware independent FORMAT utility. + + + MS-DOS INSTALLATION KIT + + + CONTENTS + +CHAPTER 2 MS-DOS DEVELOPMENT TOOLS + + EDLIN Text Editor 2-1 + + Microsoft Macro Assembler 2-1 + + Microsoft Linker (MS-LINK) 2-2 + + MS-DEBUG 2-2 + + EXE2BIN 2-2 + + FORMAT 2-2 + + + + + + + + + + + + + + CHAPTER 2 + + MS-DOS DEVELOPMENT TOOLS + + + +An assembler, text editor, linker, and other utilities are +required for completing an MS-DOS implementation. We assume +that your development machine has the following standard +utilities: + +EDLIN Text Editor + + The EDLIN text editor provided with MS-DOS for your + development machine may be used to prepare assembler + source files. The version of EDLIN on MS-DOS 2.x and + 3.x release disks is for versions 2.x and 3.x only, and + will not run under MS-DOS 1.x. A third party full screen + text editor (not a word processor) may be more efficient + for manipulating source files. + +Microsoft Macro Assembler + + A complimentary copy of the current Microsoft Macro Assembler + is provided with the MS-DOS installation kit. + The assembler is not actually a part of MS-DOS; it must be + licensed separately if you wish to ship it to your + customers. The Cross-Reference Utility (MS-CREF), + included with Microsoft Macro Assembler, can be used to + make cross-reference listings of assembler programs. + The Microsoft Macro Assembler package will only run + under MS-DOS 2.XX and later operating systems. The + output of the assembler is a relocatable object module + (.OBJ file type) which conforms to a subset of the + INTEL MCS 86 object module format description. Refer + to the MS-DOS Programmer's Reference Manual for ______ ____________ _________ ______ + information on the INTEL MCS 86 object module format + description. + + MS-DOS DEVELOPMENT TOOLS Page 2-2 + + +Microsoft Linker (MS-LINK) + + Your MS-DOS development machine should include a linker + named LINK.EXE. Use LINK.EXE for linking object + modules (.OBJ files) produced by the Microsoft Macro + Assembler. The output of the Linker is a file with an + .EXE format. This is an executable program requiring a + special loader that is part of MS-DOS. Refer to the + MS-DOS Programmer's Reference Manual for details on ______ ____________ _________ ______ + .EXE formats. + +SYMDEB + + SYMDEB.EXE is the MS-DOS symbolic debugger. The debugger + can do absolute disk reads and writes. You may use this + facility to write your bootstrap loader program into + the boot sector. Note that since MS-DOS is not + reentrant, this debugger may not be used to set break + points within the DOS or device drivers. + + +EXE2BIN + + The EXE2BIN.EXE utility supplied with your MS-DOS + development machine must be used for converting output + from the Linker (.EXE files) to a pure binary (core + image) format not requiring a special loader. Note + that only .COM files may execute out of ROM. + +FORMAT + + The FORMAT program (FORMAT.EXE) supplied with your + MS-DOS development machine may be used to format a boot + disk for the target machine, assuming both machines + have compatible media. + +EXEFIX + + EXEFIX is a special purpose utility used for building + SORT. It sets the maximum memory allocation. + + MS-DOS DEVELOPMENT TOOLS + + + CONTENTS + + +CHAPTER 3 INSTALLING MS-DOS + + + + + + CHAPTER 3 + + INSTALLING MS-DOS + + + +If you are using an MS-DOS machine for development and your +target machine will read MS-DOS standard disk formats, +follow these steps to implement MS-DOS. + +NOTE: The steps involved in developing IO.SYS are not necessary + if the sample BIOS provided with the OEM kit is used. + This sample can also be used for technical reference. + + 1. Using a text editor on your development machine, + write the 8086 assembler source code for the + resident device drivers. The resident device + drivers are the hardware-specific routines that + will be accessed by MS-DOS to perform I/O. There + must be a minimum of five device drivers: four ____ + character drivers and one block device driver (the + disk drive on most systems). In addition to the + device drivers, you may want to include some code + for hardware initialization. The source file + should be named IO.ASM and must not contain a STACK + segment. + + For more information, see: + MS-DOS Programmer's Reference Manual ______ ____________ _________ ______ + IO.ASM on the distribution disk + The resident device driver section of this manual + + 2. Use MASM.EXE, the macro assembler provided with + your MS-DOS installation kit to assemble your + device driver code. MASM will create a file called + IO.OBJ, which is in a special object module format + (a subset of INTEL's object module format). + + For more information, see: + Microsoft Macro Assembler Manual (Macro Assembler _________ _____ _________ ______ + section) + + 3. Use LINK.EXE, the Microsoft Linker, to link your + IO.OBJ module to appropriate SYSINIT.OBJ module(s)and the + appropriate SYSIMES.OBJ module. The + modules must be linked in this order: + + 2.xx IO.OBJ+SYSINIT.OBJ+SYSIMES.OBJ + + 3.XX IO.OBJ+SYSINIT1.OBJ+SYSINIT2.OBJ+SYSIMES.OBJ + + The output file should be named IO.EXE. You + INSTALLING MS-DOS Page 3-2 + + + may get the message "Warning, no STACK segment" while + linking the module. This is a warning message and + is normal with some versions of the linker. + + For more information, see: + Microsoft Macro Assembler Manual (Chapter 3 LINK: _________ _____ _________ ______ + A Linker) + + 4. The file created in step 3 is an .EXE file which is + in a special format recognized by the .EXE loader. + Since the .EXE loader is not available at boot + time, the IO.EXE file must be converted to a pure + binary core image file. This is done with the + EXE2BIN utility provided with the MS-DOS release on + your development machine. The EXE2BIN utility must + know exactly where the code will reside in memory + to resolve any FAR references. You will be + prompted for the base address, the absolute segment + address where the code will begin. The resultant + file must be named IO.SYS. EXE2BIN will change the + name when you type the following command line: + + EXE2BIN IO.EXE IO.SYS + +------------------------------------------------------------ +| | +| Note | +| | +| It is the responsibility of the bootstrap loader to | +| locate IO.SYS at the location you specified as the base | +| address. The location itself is arbitrary, since one | +| of the parameters that the resident device driver code | +| passes to SYSINIT is the location of the first device | +| driver. | +| | +|__________________________________________________________| + + For more information, see: + MS-DOS User's Reference Manual (Chapter 3) ______ ______ _________ ______ + + 5. Customize the function key table in DOSMES.ASM. + + 6. Use MSDOSBLD.BAT on the distribution disk to assemble + appropriate object modules and link them with those + already provided to form MSDOS.SYS. + + 7. Write a bootstrap loader program using the text + editor. This step is not necessary if the sample + bootstrap loader included in the OEM kit is used. + The sample bootstrap loader can also be used for + technical reference. + Name this file BOOT.ASM. We assume that you have + a system ROM which will load the first sector of + the system disk into memory when you turn + on or reset the compter. Ideally, the bootstrap + loader fits into the first sector of the boot disk. + In addition to the loader, information relating to + the BIOS Parameter Block (BPB) should be kept in the + boot sector of the disk. The format of the boot + INSTALLING MS-DOS Page 3-3 + + + sector is described in Chapter 4. + + The bootstrap loader loads IO.SYS and MSDOS.SYS into + memory. MS-DOS can be located any place in memory + above IO.SYS. (IO.SYS can alternately be used to + load MSDOS.SYS.) Loading IO.SYS and MSDOS.SYS is + simple because these two files must always be the + first files on the disk. This means that a + bootstrap loader could simply load a series of + consecutive sectors into memory. Your bootstrap + loader may also read in the first sector of the + directory before it loads IO.SYS to verify that + these files are the first files on the disk. + + For more information, see: + MS-DOS Programmer's Reference Manual ______ ____________ _________ ______ + (Chapter 2) + MS-DOS Adaptation Guide (Chapter 4) ______ __________ _____ + + 8. Assemble, link, and convert to binary (using + EXE2BIN) the BOOT.ASM file to produce BOOT.BIN. + + 9. Format a non-system disk using your MS-DOS + development machine. + + 10. Using the MS-DOS Copy command, copy IO.SYS, + MSDOS.SYS, and appropriate version of + COMMAND.COM to the formatted disk. + + 11. Using DEBUG.COM on the development machine, load + BOOT.BIN and write it to the first sector of the + formatted disk. This can be done as follows: + + + DEBUG + -N BOOT.BIN + -L (loads BOOT.BIN) + -W 100 0 0 1 (writes BOOT.BIN to drive 0 + sector 0) + -Q + + Note: More operations may be required depending on + how your boot program is organized. + + For more information, see: + Microsoft Macro Assembler Manual (Chapter 4 SYMDEB: _________ _____ _________ ______ + A Symbolic Debug Utility + + The formatted disk should now be bootable by your + system. + INSTALLING MS-DOS Page 3-4 + + + 12. Write the source code for the hardware-specific part + of the FORMAT program. The MS-DOS 3.3 version of the + FORMAT utility has been structured so that the hardware + specific portions have been placed solely in IO.SYS. + Minimal work should be required for the OEM use of the + MS-DOS 3.2 FORMAT utility. + Assemble and link this to the FORMAT.OBJ and FORMES.OBJ + files supplied by Microsoft. The modules must be linked + in the following order: + + 2.XX: FORMAT.OBJ+FORMES.OBJ+OEMFOR.OBJ + + + where OEMFOR.OBJ is your hardware-specific module. + Use EXE2BIN to convert the OEMFOR.EXE file produced + to FORMAT.COM. + + 3.XX: FORMAT.OBJ+FORPROC.OBJ+FORMES.OBJ+OEMFOR.OBJ+PRINTF.OBJ + + + where OEMFOR is your hardware-specific module. + Although the PRINTF.OBJ module is the last module + specified, it does not follow the OEM module in the + memory image. + + For more information, see: + + MS-DOS Adaptation Guide (Chapter 7) ______ __________ _____ + OEMFOR.ASM Disk file of sample OEM FORMAT module + MS-DOS User's Reference Manual (Format Command, ______ ______ _________ ______ + Chapter 3) + MS-DOS Programmer's Reference Manual (Chapter 3) ______ ____________ _________ ______ + + 13. Install the MS-DOS OEM serial number. + + For information on how this is done, refer to the README.DOC + on the distribution diskette. + + 14. Modify SORTMES.ASM as appropriate. + + 15. Build SORT executable with SORTBLD.BAT. + + 16. Modify PRINT source modules as appropriate + + 17. Build PRINT executable with PRINTBLD.BAT + + + + INSTALLING MS-DOS + + + CONTENTS + +CHAPTER 4 DISK STRUCTURE AND BOOTSTRAP LOADING + + 4.1 Reserved Area 4-1 + + 4.2 File Allocation Table 4-2 + + 4.3 MS-DOS File System Limits 4-4 + + 4.3.1 Disk Format Identification 4-6 + + 4.4 The role of the Boot Sector 4-7 + + + + + + + + + + + + + + + CHAPTER 4 + + DISK STRUCTURE AND BOOTSTRAP LOADING + + + +MS-DOS disks are divided into four logical data areas. + + 1. Reserved sectors (boot sector) + + 2. File Allocation Tables + + 3. Root directory + + 4. Data area which may include subdirectories + as well as program and data files + +When creating non-standard disks or non-removable media +(such as hard disks), the logical disk which your device _______ +driver presents to MS-DOS must conform to the above +standard. The physical layout may be completely different. ________ +For example, you may want to implement a partitioning scheme +on the hard disk so that it can be shared by multiple +operating systems. In this case, either the device driver +or firmware maps the physical structure into an MS-DOS +logical layout. The MS-DOS file system can even be +logically implemented within another operating system's file +structure. + + + +4.1 RESERVED AREA + + +The reserved area is the first part of the disk and is +typically used for boot purposes. Some machines not +specifically designed for MS-DOS may use track 0 for special +purposes (it may even have a different sector size than the +rest of the disk). In this case, the entire track should be +marked as reserved so that the device driver will map +MS-DOS's logical sector 0 to the beginning of track 1 +instead of track 0. + +It may be difficult to fit the required boot information +into a single sector. Note that disk formats using 128- or +256-byte sectors and without any firmware support may + DISK STRUCTURE AND BOOTSTRAP LOADING Page 4-2 + + +require several sectors. + + + + +4.2 FILE ALLOCATION TABLE + +The File Allocation Table (FAT) is the most important data +structure on the disk. Two copies are usually kept at the +OEM's option. (Two copies need not be kept for a virtual +RAM disk because, in this case, the media cannot be damaged.) +MS-DOS files are allocated in "allocation units" or "clusters". +Each cluster is some number of sectors. The number of sectors +per allocation unit must be a power of 2 which fits in a byte. +Thus, the complete list of possible values is: + 1, 2, 4, 8, 16, 32, 64, 128. + +The FAT is a physical map of the allocation units in the +data area of the disk. There is one FAT entry for each +allocation unit on the disk plus two reserved entries at the +beginning of the FAT. The entries serve as a linked list of +pointers. For a complete discussion of FAT structure, refer +to Chapter 3 of the MS-DOS Programmer's Reference Manual. ______ ____________ _________ ______ + +FAT size can be determined by the following formula: + + + FAT = Q * ( T - R - D + 2) + -------------------- + Q * N + ( A * S ) + + +FAT is the number of sectors needed for one FAT and will + usually not be an integer. It must be rounded up to + the next integer value. + +Q is the number 1.5 for 12-bit FAT entries and 2.0 + for 16-bit FAT entries. + +T is the total number of sectors on the disk. + +R is the number of reserved sectors. + +D is the number of root directory sectors (there must + be 32 bytes for each directory entry). + +A is the number of sectors per cluster or allocation + unit. + +N is the number of file allocation tables on the disk. + +S is the number of bytes per sector. + + +MS-DOS 3.x can use 16-bit FAT pointers whenever the total + DISK STRUCTURE AND BOOTSTRAP LOADING Page 4-3 + + +number of clusters on the disk exceeds 4085 (=4096-10; two +are reserved at the beginning, and eight are reserved at the +end). Although the FAT entries are 16 bits, the present +software only works with 15 bits (up to 32766 clusters). + +____________________________________________________________ +| | +| Important | +| | +| Be careful when reducing cluster size as it can cause | +| significant performance degradation. Reducing cluster | +| size results in increased fragmentation, a larger FAT | +| to buffer (increasing the number of disk accesses); and | +| increasing the FAT entries from 12 to 16-bit expands | +| the FAT size by 33%. | +| | +|__________________________________________________________| + +The FORMAT program will create a proper FAT. The FAT has an +entry for each allocation unit in the data area of the disk. +It also contains two extra entries at the beginning. These +represent reserved clusters. The first cluster of the data +region of the disk is cluster 2. + +The first (0th cluster) of these two reserved entries can be +used to indicate the format of the disk. Only the low 8 +bits are used, and this byte is often referred to as the +FATID byte. The high 4 bits (high byte if a 16-bit FAT) of +this first cluster are all set (=1). + +The FATID byte is restricted to be in the range 0F8H to +0FFH, inclusive (8 possible values). The FATID byte is also +an end-of-file (EOF) mark. If a FAT chain contains a zero +entry (which should never happen), it will point to this EOF +marker. The second (1st cluster) of these two reserved +entries is always 0FFFH (0FFFFH for a 16-bit FAT), which is +an end-of-file mark. + + DISK STRUCTURE AND BOOTSTRAP LOADING Page 4-4 + + +Figure 4.1 illustrates the first two clusters of a 12-bit +File Allocation Table. + + + FAT BYTE 00 01 02 03 + XXH XXH XXH XXH----->Byte 3 + || || || + Middle 4 bits | || High and middle 4 bits of + of cluster 0 | || cluster 1 (always F) + | | High 4 bits of + Low 4 bits of | cluster 0 (always F) + cluster 0 | + | | Low 4 bits of cluster + |------------------| 1 (always F) + | + FATID BYTE + + + +Figure 4.1. First Two Entries of the FAT (12-bit) + + + + + +4.3 MS-DOS FILE SYSTEM LIMITS + +The following figure shows the file storage limitations +within MS-DOS. + + | MS-DOS 2.x | Both | MS-DOS 3.x + _______________|______________|_____________|_______________ +|FAT entry size |12 bits | |12 or 16 bits | +|Sector size | |64b-32Kb | | +|No. of Sectors | |Max of 64K | | +|Cluster size | |1-128 sectors| | +|Max. disk size |4085 clusters |64K sectors |32766 clusters| +|Max. file size | |Disk size | | +________________|______________|_____________|______________| + +All ranges in the table are inclusive. As well as the above +limitations, there are also various limits as noted below: + + + 1. FAT entry size. + This is the only file storage limit difference + between MS-DOS 2.XX and 3.XX; it significantly + increases the maximum number of clusters and hence + the maximum disk size allowed. MS-DOS 3.x + determines whether a 12- or 16-bit FAT is in use by + calculating the number of disk clusters from the + BPB. If the number of clusters is less than or + equal to 4085, a 12-bit FAT is in use; otherwise, + a 16-bit FAT is assumed. A 16-bit FAT cannot be + used if the total number of clusters is less than + DISK STRUCTURE AND BOOTSTRAP LOADING Page 4-5 + + + or equal to 4085. + + Some existing MS-DOS applications (such as copy + protection schemes and disk maintenance utilities) + bypass MS-DOS and manipulate the FAT directly. + These existing applications will cause problems + with 16-bit FATs until the applications are updated + to recognize the 16-bit FATs. + + 2. Sector Size. + Must be a multiple of 64 bytes. + + 3. No. of Sectors. + The number of sectors is limited to 64K because + 16-bit sector numbers are passed to the device + drivers. + + 4. Cluster Size. + The cluster size (bytes/cluster = sectors/cluster * + bytes/sector) must be less than 64K because MS-DOS + uses 16-bit arithmetic. + + Sectors/Cluster must be a power of 2 in the range + 1-128. + + Excessively small cluster sizes can seriously + degrade performance. Refer to the MS-DOS ______ + Programmer's Reference Manual for sample disk ____________ _________ ______ + formats. + + 5. Max. Disk Size. + MS-DOS 2.XX: Lesser of 4085 clusters or 64K sectors + (For example, 64K*512 byte sectors = 32Mb disk). + MS-DOS 3.XX: Lesser of 32766 clusters or 64K + sectors. + + The total number of sectors is limited to 64K due + to the use of 16-bit arithmetic. + + The maximum number of possible clusters is + calculated by the following: + + FAT entry size + (2 -10 Reserved) + + Reserved: 8 FAT ID/EOF (F8-FF) + 2 RESERVED (0,1) + + ------------------------------------------------------------ + | | + | Note | + | | + | However, some MS-DOS utilities (such as Chkdsk and | + | Recover) restrict the total FAT size to 32K entries, | + DISK STRUCTURE AND BOOTSTRAP LOADING Page 4-6 + + + | hence the MS-DOS 3.x limit of 32,766 clusters and not | + | 65,525 (216-11). | + | | + |__________________________________________________________| + + There are 10 MS-DOS reserved FAT entries; two at + the front of the FAT, and eight at the end: + DISK STRUCTURE AND BOOTSTRAP LOADING Page 4-7 + + + 4086 = 4K -10 + 32766 = 32K -2 + + The 8 reserved clusters + are in the range 65528-65536. + + 6. Max. File Size. + Files cannot be split across disks; therefore, the + maximum file size is normally the maximum disk + size. The file size is also restricted by a 32-bit + file pointer. This means that the maximum possible + file size is 4 gigabytes: + + 32 + 4 million K, 2 -1 + + + + +4.3.1 Disk Format Identification + +Beginning with MS-DOS 2.0, Microsoft is promoting the use of +a media descriptor table in the boot sector. This table +contains both a physical description (number of sectors, +sides, tracks, etc.) and a logical description (number of +FATs, directory entries, etc.) of the disk layout. The +media description table allows MS-DOS to accommodate future +floppy disk formats, or formats defined by other +manufacturers but not generated by your FORMAT utility. +Your device driver should assume that the media description +table exists if the first byte of the boot sector is the +first byte of a 3-byte (near) jump or a 2-byte jump. + DISK STRUCTURE AND BOOTSTRAP LOADING Page 4-8 + + +4.4 THE ROLE OF THE BOOT SECTOR + +Typically, the system ROM will load the reserved (boot) +sector or sectors into memory at power-up or restart. We +recommend that the boot sector do the following: + + + 1. It should read the first sector of the directory + and verify that the first two files on the disk are + IO.SYS and MSDOS.SYS, in that order. + + You may choose to have your FORMAT utility generate + different boot sectors for each disk format. Or, + you may create a universal boot sector to read the + media description table and determine where to find + the first directory sector both logically and + physically. + + + 2. If the boot code does not find the MS-DOS files in + the directory, then the boot sector should prompt + the operator that an attempt has been made to boot + from a non-bootable disk. You determine how the + user should continue ("Strike any key" or "Turn + power off"). + + + 3. The boot sector must read in the IO.SYS and + MSDOS.SYS files. Alternatively, the boot sector may + read in only IO.SYS, and IO.SYS may then read in + MSDOS.SYS. Only IO.SYS needs to be contiguous on the + disk. + + The boot sector must know or calculate where those + files physically begin on the disk (right after the + last directory sector) and how long they are + (contained in directory entries). You must code + (or calculate) the location at which they should be + loaded into memory in the boot sector. + + + 4. The boot sector must transfer control to your entry + point in IO.SYS. + + The boot sector does not load COMMAND.COM, as it + will be loaded by SYSINIT. + + +The SYS command allows users to transfer the operating +system onto a formatted disk that contains no files or +contains an old version of the operating system of equal or +greater size. For the MS-DOS 2.XX version on the IBM PC, the +SYS command was modified to transfer MS-DOS 2.XX system files +onto old 1.XX disks. The new MSDOS.SYS can be placed on the +disk in a non-contiguous format. (IO.SYS is still +contiguous because the new IO.SYS is smaller than the + DISK STRUCTURE AND BOOTSTRAP LOADING Page 4-9 + + +combined sizes of the old IO.SYS and MSDOS.SYS.) The boot +sector is only responsible for loading IO.SYS, although it +must check that MSDOS.SYS is the second file on the disk. +Therefore, IO.SYS may load a non-contiguous MSDOS.SYS. + +The logic to facilitate checking through the FAT entries +must be added to IO.SYS because the logic normally resides +in the not-yet-loaded MSDOS.SYS. The logic resides in the +installation part of IO.SYS so that it will be overwritten +when MSDOS.SYS is loaded. This technique should only be +used to use the SYS command to transfer a new, bigger MS-DOS +onto an old disk. It is not useful if you do not have old +disks to support in the field. Note that the various FAT +entries for a non-contiguous MSDOS.SYS may reside in +different FAT sectors making it necessary to read more than +just the first FAT sector into memory. + +There is an example of a boot sector on the OEM Sample MS-DOS +Implementation Diskette. + DISK STRUCTURE AND BOOTSTRAP LOADING + + + CONTENTS + +CHAPTER 5 RESIDENT DEVICE DRIVERS + + 5.1 Introduction 5-1 + + 5.2 Bit 4 5-3 + + 5.3 Installation of Device Drivers 5-5 + + 5.4 The CLOCK Device 5-5 + + 5.5 INIT (Command Code 0) 5-6 + + 5.6 Media Check 5-7 + + 5.7 DMA Boundary Violation 5-9 + + + + + + + + + + + + + + CHAPTER 5 + + RESIDENT DEVICE DRIVERS + + + +------------------------------------------------------------ +| | +| Note | +| | +| Chapter 2, "Device Drivers," in the MS-DOS Programmer's | +| Reference Manual contains a description of MS-DOS | +| device drivers. Additional information applicable to | +| OEM is included here. | +| | +------------------------------------------------------------ + + + +5.1 INTRODUCTION + +The IO.SYS file is composed of the "resident" device +drivers. This forms the MS-DOS Basic Input Output System +(BIOS), and these drivers are called upon by MS-DOS to +handle I/O requests initiated by application programs. + +One of the most powerful features of MS-DOS is the ability +to add new devices such as printers, plotters, or mouse +input devices without rewriting the BIOS. The MS-DOS BIOS +is "configurable;" that is, new drivers can be added and +existing drivers can be pre-empted. Non-resident device +drivers may be easily added by a user at boot time via the +"DEVICE =" entry in the CONFIG.SYS file. In this section, +these non-resident drivers are called "installable" device +drivers to distinguish them from drivers in the IO.SYS file, +which are considered the resident drivers. + +At boot time, a minimum of five resident device drivers (four +character devices and one block device) must be present. +These drivers are in a linked list: the header +of each one contains a DWORD pointer to the next. The last +driver in the chain has an end-of-list marker of -1, -1 (all +bits on). + +Each driver in the chain has two entry points: the strategy +entry point and the interrupt entry point. MS-DOS 2.XX/3.XX +does not take advantage of the two entry points: it calls + RESIDENT DEVICE DRIVERS Page 5-2 + + +the strategy routine, then immediately calls the interrupt +routine. + +The dual entry points facilitate future multitasking +versions of MS-DOS. In multitasking environments, I/O must +be asynchronous; to accomplish this, the strategy routine +will be called to (internally) queue a request and return +quickly. It is then the responsibility of the interrupt +routine to perform the I/O at interrupt time by getting +requests from the internal queue and processing them. When +a request is completed, it is flagged as "done" by the +interrupt routine. MS-DOS periodically scans the list of +requests looking for those that are flagged as done, and +"wakes up" the process waiting for the completion of the +request. + +When requests are queued in this manner, it is no longer +sufficient to pass I/O information in registers, since many +requests may be pending at any time. Therefore, the MS-DOS +2.x/3.x device interface uses "packets" to pass request +information. These request packets are of variable size and +format, and are composed of two parts: + + + 1. The static request header, which has the same + format for all requests. + + 2. A section that has information specific to the type + of request. + + +A driver is called with a pointer to a packet. In +multitasking versions, this packet will be linked into a +global chain of all pending I/O requests maintained by +MS-DOS. + +The 2.XX and 3.XX versions of MS-DOS do not implement a +global or local queue. Only one request is pending at any +one time. The strategy routine must store the address of +the packet at a fixed location, and the interrupt routine +(which is called immediately after the strategy routine) +should process the packet by completing the request and +returning. It is assumed that the request is completed when +the interrupt routine returns. + +To make a device driver that SYSINIT can install, a .BIN +(core image) or .EXE format file must be created with the +device driver header at the beginning of the file. The link +field should be initialized to -1 (SYSINIT fills it in). +Device drivers that are part of the BIOS should have their +headers point to the next device in the list and the last +header should be initialized to -1,-1. The BIOS must be a +BIN (core image) format file produced by using the utility +EXE2BIN. + +.EXE format installable device drivers may be used in + RESIDENT DEVICE DRIVERS Page 5-3 + + +non-IBM versions of MS-DOS before 3.0. The reason for this +restriction is that on the IBM PC, the .EXE loader is located +in COMMAND.COM, which is not present at the time that installable +devices are being loaded. + +The attribute field and entry points must be set correctly. +If the device is a character device, the name field must be +filled in. (This name can be any 8-character legal +filename). If it is a block device, SYSINIT will fill in the +correct unit count. SYSINIT always installs character +devices at the start of the device list, so if you want to +install a new CON device, simply name it CON. The new one +will be placed ahead of the old one in the list and will +pre-empt the old one because the search for devices stops on +the first match. + +Be sure to set the standard input (sti) and standard output +(sto) bits on a new CON device. + +------------------------------------------------------------ +| | +| Note | +| | +| Since SYSINIT may install the driver anywhere, be | +| careful when coding FAR memory references. You | +| should NOT expect that your installable driver will be | +| located in the same place every time. This does not | +| apply for the resident device drivers. | +| | +|__________________________________________________________| + + + + +5.2 BIT 4 + +In the MS-DOS Programmer's Reference Manual, bit 4 of the ______ ____________ _________ ______ +device driver header format is defined as reserved. It +actually has special meaning. + +Bit 4, the special bit, applies to CON drivers. The new +interface supports many new features, but it is slower than +MS-DOS 1.x if old style "single-byte" system calls are made. +To make most efficient use of the interface, all +applications should block their I/O as much as possible. +For example, you should make one XENIX-style system call to +output x number of bytes rather than x system calls to +output one byte each. + + RESIDENT DEVICE DRIVERS Page 5-4 + + +Putting a device channel in raw mode provides an even faster +way to output characters. (See the Glossary for an +explanation of "raw" mode.) Bit 4, has been implemented to +alleviate the CON output speed problem for older programs +that use system calls 01H to 0BH to output large amounts of +data. If this bit is 1, the device is CON and an Interrupt +29H has been implemented, where the 29H handler is defined +as follows: + + CONSOLE OUTPUT via INT 29H handler + + Input: Character in AL + + Function: Output the character in AL + to the screen at the current + cursor location. + + Output: None + + Registers: All registers except BX must be + preserved. No registers except + AL have a known or consistent + value. + + +If a character device implements the special bit, the driver +must install an address at the correct location in the +interrupt table for Interrupt 29H. Only one device driver +can have the special bit set in the system. There is no +check to ensure this state. + +____________________________________________________________ +| | +| Warning | +| | +| This feature may not be supported in future versions of | +| MS-DOS. Any application (not device driver) that uses | +| Interrupt 29H directly will not work on future versions.| +| In addition, the console device driver must be tested | +| with bit 4 not set to ensure that it will work with such | +| future versions of MS-DOS. | +| | +____________________________________________________________ + +The headers of resident drivers should point to the next +device in the list and the last header should be initialized +to -1,-1. IO.SYS must be a .COM format file. + + RESIDENT DEVICE DRIVERS Page 5-5 + + +5.3 INSTALLATION OF DEVICE DRIVERS + + +MS-DOS 2.XX/3.XX allows new device drivers to be installed +dynamically at boot time. This is accomplished by the +SYSINIT module(s) supplied by Microsoft, which read(s) and +processes the CONFIG.SYS file. The resident driver source +file (IO.ASM) is assembled and linked to the appropriate SYSINIT +module(s) and SYSIMES.OBJ. The resultant .EXE file must +be converted via EXE2BIN to create the file IO.SYS. This +should be the first file that appears on the system disk. + +When block drivers are installed, the logical drive letters +are assigned in list order; thus, the driver that will have +logical A must be the first unit of the first block device +in the list. The order of character devices is also +important. There must be at least four character devices +defined at boot time. The first four character devices must +be as follows: + + + 1. Standard input, standard output, and standard error + output (CON) + + 2. Standard auxiliary input and output (AUX) + + 3. Standard list output (PRN) + + 4. Date/time (CLOCK) + +The linked list of device drivers must look like this: + + ->CON->AUX->PRN->CLOCK->any other block or + character devices + + + + +5.4 THE CLOCK DEVICE + + +The CLOCK device is used by MS-DOS 2.XX/3.XX for marking file +control blocks and directory entries with date and time as +well as providing date/time services to application +programs. It is unique in that MS-DOS will read or write a +6-byte sequence which encodes the date and time. A write to +this device will set the date and time and a read will get +the date and time. + +Figure 5.1 illustrates the binary date and time format used +by the CLOCK device. + RESIDENT DEVICE DRIVERS Page 5-6 + + + + + byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 ++--------+--------+---------+--------+--------+---------+ +| | | | | | | +|days since 1-1-80| minutes | hours | sec/100| seconds | +|low byte|hi byte | | | | | ++--------+--------+---------+--------+--------+---------+ + + Figure 5.1. CLOCK Device Format + + + +5.5 INIT (COMMAND CODE 0) + +One of the functions defined for each device is INIT. This +routine is called only when the device is installed. It is +used for initializing character and block devices. + +Figure 5.2 illustrates the format of INIT. + + + +------------------------------------+ + | 13-BYTE Request Header | + +------------------------------------+ + | BYTE # of units | + +------------------------------------+ + | DWORD Break Address | + +------------------------------------+ + | DWORD Pointer to BPB array | + | (not set by character devices) | + +------------------------------------+ + + Figure 5.2. INIT Format + + +For resident character devices:___ ________ _________ _______ + +No parameters are passed, and none are returned. + + +For resident block drivers:___ ________ _____ _______ + +Unlike character device drivers, block device drivers must +return a number of parameters. The following data are +returned: + + + 1. The number of units defined by this block device + driver. This is used to determine logical device + names. If the current maximum logical device + letter is F at the time of installation, and the + INIT routine returns 4 as the number of units, then + those units will have the logical names G, H, I and + J. This mapping is determined by the position of + RESIDENT DEVICE DRIVERS Page 5-7 + + + the driver in the device list and the number of + units defined by the device (stored in the first + byte of the device name field). You must return + this number at offset 13D in the INIT call, even + though the number of units is stored in the device + header. + + 2. A DWORD pointer to an array of WORD offsets to BPBs + (BIOS Parameter Blocks). There must be one entry + for each unit defined by the device driver. If the + device driver defines two units, then the DWORD + pointer points to the first of two one-word offsets + which, in turn, point to BPBs. If both BPBs are + the same, this will allow you to save space by + entering two offsets to the same location. + + +The BPB is used by MS-DOS to create an internal DOS +structure. The BPBs that are returned by the resident +device drivers are scanned to determine the largest sector +size. This number is used to set the cache buffer size. + +Installable block devices cannot have larger sector sizes +than those defined by the resident drivers. For this +reason, you may want to use dummy BPBs to reserve space. +Use an invalid media byte so that when you later report the +correct BPB for the unit. MS-DOS will build the correct +internal DOS structure for the particular drive unit. + + + +5.6 MEDIA CHECK + +The MEDIA CHECK function is called when there is a pending +drive access call other than a file read or write (i.e access +to the "FILENAME space" - Open, Close, Get_disk_size, INT 25H, +INT 26H, etc.). Its purpose is to determine whether the media +in the drive has been changed. Note that the previous media ID +byte is passed to the device driver. Although the old media ID +byte is the same as the new one, the disk may have been changed +and a new disk may be in the drive; therefore, the FAT, and +directory and data sectors for the unit are invalid. + +MS-DOS 3.XX imposes stricter conditions than MS-DOS 2.XX on +when media changes are allowed. This can lead to MEDIA +CHECK routines that seemed to work correctly under MS-DOS +2.XX causing problems under MS-DOS 3.XX. + +MS-DOS performance is greatly improved if MEDIA CHECK uses a +doorlock or some other detection method so that it can +guarantee that no disk change has occurred; then MS-DOS +does not have to reread the FAT before each directory +access. + +MEDIA CHECK can directly use the door-lock mechanism to +return "Disk not changed." However, the door-lock mechanism + + + + +RESIDENT DEVICE DRIVERS Page 5-8 + + +indicating that the door has been opened does not +necessarily mean that the disk has been changed, since the +user could have reinserted the same disk. MEDIA CHECK +routines that return "Disk has been changed" just because +the door has been opened will cause problems under MS-DOS +3.x, but not under MS-DOS 2.XX. + +The recommended behavior for MEDIA CHECK is to return as +follows: + + Disk has not been changed - whenever the door lock + indicates that the door + has not been opened + + Don't know - under all other + circumstances + +It is possible for MEDIA CHECK to try to determine whether a +disk has really been changed by checking the Volume ID; +however, many disks have no Volume ID. Therefore, it is +safer and quicker for MEDIA CHECK to simply return "Don't +know." The action that MS-DOS takes depends on the state of +its internal file storage buffers. In general, if "Don't +know" is returned when MS-DOS has data in its internal +buffers (data that needs to be written out), MS-DOS will +assume no disk change has occurred. Otherwise, with empty +buffers or all buffers "clean", MS-DOS assumes the disk has +been changed. + +The possible problems caused by an incorrect MEDIA CHECK +routine can be checked as follows: + + 1. Load MS-DOS 3.XX + 2. Ensure the disk is write-protected + 3. COPY FILE1 FILE2 + 4. Write Protect Error from MS-DOS + 5. Remove the write protection from the disk + 6. Reinsert the disk in the drive + 7. Press "R" to cause MS-DOS to retry + 8. Copy success message + +If an incorrect MEDIA CHECK routine is in use, the Dir +command will show FILE2 with a size of zero bytes, and +Chkdsk will report "lost clusters." Note that the copy +process always returns the success message even with an +incorrect MEDIA CHECK routine. + +The above test should also be repeated with a "Drive Not +Ready" error condition instead of the Write Protect error. +The same symptoms will be displayed. + +For more information on MEDIA CHECK, refer to the MS-DOS ______ +Programmer's Reference Manual.____________ _________ _______ + RESIDENT DEVICE DRIVERS Page 5-9 + +5.7 DMA BOUNDARY VIOLATIONS + +Some OEMs check for any DMA boundary violations on disk +operations. If a DMA boundary violation error is detected +then action is taken to prevent this error from being +reported to the DOS. The sample IO.SYS handles the problem in +the following way. The operation is tried and if a DMA boundary +violation is reported, then a flag (in this case bl) is set +to indicate that we need to do a memory swap to avoid the +boundary problem. The sector of data that causes the DMA +boundary violation is transfered into an internal buffer +that belongs to IO.SYS and then is copied into the buffer +specified in the original request. + +In other words, the request is broken into several pieces +consisting of a request for the data up to the DMA boundary +violation, then the one sector of data that causes the DMA boundary +violation (in the sample IO.SYS SwapMemory routine is responsible +for doing this), and then the rest of the request as specified +by the original disk operation. + +Applications do not depend on this feature in any direct way. +However, if you do not implement the DMA boundary checking then +it would be possible for an application to get an INT24 error because +of the DMA boundary problem and thus behave differently +depending on how the BIOS was implemented. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CHAPTER 6 SYSINIT AND MS-DOS INITIALIZATION + + 6.1 Introduction 6-1 + + 6.2 The Role of SYSINIT 6-3 + + 6.3 COMMAND.COM 6-5 + + + + + + + + + + + + + + CHAPTER 6 + + SYSINIT AND MS-DOS INITIALIZATION + + + +6.1 INTRODUCTION + + +In addition to implementing the resident drivers and +performing any hardware initialization, the IO.ASM code must +initialize certain external variables. These variables are +declared public in the SYSINIT module(s) to which the IO.OBJ +module is linked. The public variables and their functions +are described below. + +CURRENT_DOS_LOCATION WORD + +This is the paragraph location where the bootstrap loader +(or, optionally, IO.SYS) has loaded MSDOS.SYS into memory. +Typically, MSDOS.SYS is located immediately after IO.SYS. + +FINAL_DOS_LOCATION WORD + +Since SYSINIT immediately relocates itself to high memory, +there will be a hole right after the resident drivers. By +telling SYSINIT the paragraph where you want it to relocate +MSDOS.SYS, you can fill up this hole plus overlay any code +that IO.SYS used for hardware initialization at boot time. +SYSINIT will move MSDOS.SYS down to this location, +conserving space. This location also defines where memory +starts for MS-DOS. + +DEVICE_LIST DWORD + +IO.SYS must tell SYSINIT where the linked list of device +drivers begins. This is the location of the CON device +driver header; the information is passed to MS-DOS so that +the drivers can be accessed. + SYSINIT AND MS-DOS INITIALIZATION Page 6-2 + + +MEMORY_SIZE WORD + +This word is the paragraph number of the highest location in +RAM. If you do not initialize MEMORY_SIZE, SYSINIT will do +a memory scan to determine the amount of memory. It does +this by reading every 16 bytes starting at 32K, writing an +arbitrary pattern, reading it back for a match, and +returning the original value. It stops when it gets a +mismatch. If your system has parity memory, you must +declare this value, since writing to nonexistent memory will +cause a parity error. + +MS-DOS should be implemented in systems with contiguous +memory. + +DEFAULT_DRIVE BYTE + +If you can boot MS-DOS from several drives, you must tell +SYSINIT which drive you booted from so it can find +CONFIG.SYS and COMMAND.COM. This variable should be set as +follows: drive A = 1, drive B = 2, etc. If DEFAULT_DRIVE +is not set, the default drive (drive A) is assumed. + +BUFFERS BYTE + +This is the default number of sector buffers for the system. +The BUFFERS value may be overridden by the user in the +CONFIG.SYS file. On versions of MS-DOS up to 3.1, the default +number of buffers is 2. On versions of MS-DOS after 3.1, +3 buffers will be allocated if there is a floppy drive in the +hardware configuration with a capacity greater than 360KB. +Beginning with 3.3, if memory size is greater than 128K, then +5 buffers will be allocated, and if memory is greater than +256K 10 will be allocated; if memory is greater than 512K, 15 +buffers will be allocated. +The value specified for the number of buffers must be greater +than or equal to 1. + +FILES BYTE + +This is the default number of open files that system calls +2FH-62H can access. This value may be overridden by the +user in the CONFIG.SYS file. Its default setting in SYSINIT +is 8. Values of less than 5 are ignored. + +The entry point in SYSINIT should be defined as a FAR label +in IO.SYS as follows: + + EXTRN SYSINIT:FAR + +After IO.SYS code has performed any hardware initialization +and has set the above external variables, it should do a FAR +jump to this label. + + SYSINIT AND MS-DOS INITIALIZATION Page 6-3 + + +You must provide a FAR procedure in the IO.ASM code which is +not subject to being overlayed when SYSINIT relocates +MS-DOS. This procedure is called RE_INIT. It should be +declared as follows: + + + + RE_INIT: PROC FAR + ........ + ........ + RET + RE_INIT ENDP + + + +The RE_INIT procedure is called by SYSINIT after MS-DOS is +installed. On entry, DS:0 points to a 100H-byte program +segment prefix which represents the Program Segment Prefix +of SYSINIT and IO.SYS taken together. This is not a normal +program because no memory is allocated to it; therefore, if +you allocate and load or Exec, you may overlay this block. +SYSINIT is located in the top 10K of memory. Do not write __ ___ _____ +there. The space above the 100H byte header at DS:100 is_____ +available for temporary use during RE_INIT. + +The RE_INIT routine can be used to perform functions such as +to print headers and read files, and it is handy for IO.SYS +debugging. If you don't need to use this procedure, simply +do a return (RET). Note that starting with MS-DOS 3.XX, +RE_INIT may not use FCB system calls. + +------------------------------------------------------------ +| | +| Warning | +| | +| RE_INIT must not change any registers or flags. | +| | +|__________________________________________________________| + + +Beginning with MS-DOS 3.2, another FAR procedure must be provided in +IO.ASM. The name of this procedure is STACKINIT. +The purpose of this procedure is to initialize a hardware stack +switching algorithm. If some of the hardware interrupt handlers in the +ROM BIOS of the OEM hardware system are stack intensive, then +this initialization routine would be used to direct the processing +of the hardware interrupt handlers to another portion of code in +IO.ASM. This code will save the current stack setup and switch stacks to +an internal space on occurrence of a hardware interrupt. +When the stack has been switched the original interrupt handler +is called. The rest of the interrupt handling will use the internal +stack and not the stack that was in use when the interrupt occurred. +When the interrupt handler returns the stack is set to its original +state. +The advantage of this feature is that there is greater system reliability +since a dedicated stack space is being used for interrupt handling. +The OEM should determine which hardware interrupt handlers are stack +intensive and redirect only those interrupts to the stack switching code +in IO.ASM. +This procedure is similar to the FAR procedure RE_INIT in that the code +is not subject to being overlayed when SYSINIT relocates MS-DOS. +The procedure STACKINIT should be declared in the same fashion as RE_INIT. +After MS-DOS is installed, SYSINIT calls the procedure STACKINIT. If this +procedure is not going to be used, then simply do a return or the OEM +can assemble SYSINIT with the conditional STACKSW set to FALSE. On entry +to this routine, there are three data variables that are available. +These pieces of data reside in the SYSINIT segment. The following +declarations should be made in IO.ASM to access these variables. + + SYSINITSEG SEGMENT PUBLIC 'SYSTEM_INIT' + EXTRN STACK_ADDR:DWORD + EXTRN STACK_SIZE:WORD + EXTRN STACK_COUNT:WORD + SYSINITSEG ENDS + +These variables are set by SYSINIT and can be changed by using the +STACKS option in CONFIG.SYS. The full syntax of the STACKS option is: + + STACKS=STACK_COUNT,STACK_SIZE + + where + STACK_COUNT is the number of stacks + (range 8 to 64, default 9) + STACK_SIZE is the stack size + (range 32 to 512 bytes, default 128) + +The variable STACK_ADDR is the FAR address of the space that SYSINIT +has allocated for the internal stacks. + +Beginning with MS DOS 3.3, there is a special case for STACKS=0,0. +This will result in no dynamic stacks being provided. DOS will not +intercept any interrupts and will only use it own standard stack. + +____________________________________________________________ +| | +| Warning | +| | +| STACKINIT must not change any registers or flags. | +| | +------------------------------------------------------------ + +6.2 THE ROLE OF SYSINIT + +The following steps illustrate the role of SYSINIT in MS-DOS +initialization: + + + 1. When SYSINIT gains control from the IO.SYS + initialization code, it determines the size of + memory (performing a scan if requested, based on + value of MEMORY-SIZE) and, based on the highest + paragraph and the size of SYSINIT, it relocates + itself to high memory. + SYSINIT AND MS-DOS INITIALIZATION Page 6-4 + + + 2. Running in high memory, SYSINIT moves MSDOS.SYS + from the CURRENT_DOS_LOCATION to the + FINAL_DOS_LOCATION as specified by IO.SYS (see the + memory maps in Section 6.3, "COMMAND.COM"). + + 3. SYSINIT does a FAR call to MS-DOS. MS-DOS has + initialization code which steps through the linked + list of device drivers and performs the INIT call + to each. The copyright message is then printed out + on the screen. + + 4. After initializing the resident devices, building + drive parameter blocks for the resident block + devices, and installing a sector buffer, MS-DOS + does a FAR return to SYSINIT. + + During MS-DOS initialization, MS-DOS examines the + BIOS Parameter Blocks (BPBs) returned by the INIT + call to the block devices. It uses the largest + sector size it finds as the default buffer size for + all buffers. For this reason, the initial BPBs may + be used to reserve space for an installable device + with a larger sector size rather than reflecting + the format of the installed disk. In this case, + these dummy BPBs must have media bytes that do not + have the same value as those used in real BPBs. + + + 5. SYSINIT calls RE_INIT in IO.ASM to allow the OEM to + print headers or handle any other initialization. + +------------------------------------------------------------ +| | +| Warning | +| | +| Do not attempt to modify memory. | +| | +|__________________________________________________________| + + + 6. After IO.SYS returns control to SYSINIT, SYSINIT + attempts to open the CONFIG.SYS file. If found, + this file is loaded in memory and all characters + are turned to uppercase. It is then parsed looking + for keywords such as DEVICE, BUFFERS, and SHELL. + Any new devices are loaded, added to the linked + list, and installed via the INIT call. Character + devices are added to the front of the list, and new + block devices are added to the end. Thus, a new + CON device can supplant an existing resident CON + device. This provides the facility to reconfigure + IO.SYS except for the Resident Disk Block device + driver. + + SYSINIT AND MS-DOS INITIALIZATION Page 6-5 + + + 7. SYSINIT allocates all of the memory it needs to + protect the buffers, installed device driver code, + and IO.SYS. It sets the "owner" of the memory to a + special value to ensure that this block of memory + is never deallocated. + + 8. SYSINIT closes all file handles, and then reopens + CON, AUX, and PRN. This enables a new CON, AUX or + PRN device to replace the resident devices. + + 9. SYSINIT allocates memory for the buffers. + + 10. SYSINIT allocates memory for hardware stacks and + calls STACKINIT to initialize the hardware stack + switching algorithm (only in versions of DOS 3.2 + and later). + + 11. SYSINIT executes COMMAND.COM. + + 12. COMMAND.COM allocates memory for its transient portion + and moves it. + +MS-DOS is now up and running. + + + +6.3 COMMAND.COM + +During its initialization, COMMAND.COM allocates memory for +its transient part and reloads it. The transient part of +COMMAND, which contains the internal commands (Copy, Dir, +Date, Time, etc.), resides in unprotected memory when a +user's program is loaded into the Transient Program Area +(TPA). It will be overlaid by programs needing the space. +When a user program terminates to the COMMAND resident, the +transient is checked to see if reloading is necessary. + SYSINIT AND MS-DOS INITIALIZATION Page 6-6 + + +Each of the following memory maps represents a step in the +MS-DOS initialization process. + ++-----------------------------+ +| | High memory +| | +| | +| | ++-----------------------------+ Loaded at arbitrary +| Bootstrap loader | location by system ROM ++-----------------------------+ XX:00 +| | +| | +| | +| | +| | +| | +| | +| | +| | +| | +| | ++-----------------------------+ Segment 40H +| Interrupt Vector Table | ++-----------------------------+ -0:00 + +Memory organization in an MS-DOS +system after the system ROM +has loaded the boot sector. + SYSINIT AND MS-DOS INITIALIZATION Page 6-7 + + ++-----------------------------+ +| | High memory +| | +| | ++- - - - - - - - - - - - - - -+ +| Spent bootstrap loader | ++- - - - - - - - - - - - - - -+ +| | +| | +| | ++-----------------------------+ +| | MS-DOS disk operating +| MSDOS.SYS | system in temporary +| | location +| | ++-----------------------------+ Microsoft-supplied +| SYSINIT | system initialization ++- - - - - - - - - - - - - - -+ module (part of IO.SYS) +| | +| IO.SYS | IO.SYS (may begin at ++-----------------------------+ any location) +| Interrupt Vector Table | ++-----------------------------+ + +Memory after bootstrap loader +loads IO.SYS and MSDOS.SYS. + SYSINIT AND MS-DOS INITIALIZATION Page 6-8 + + ++-----------------------------+ +| SYSINIT | High memory +| relocates itself to highmem | ++-----------------------------+ +| | +| | +| | +| | +| | ++-----------------------------+ +| | +| MS-DOS structures, buffers, | SYSINIT loads installable +| hardware stack space, | drivers and buffers here +| and installable drivers | ++-----------------------------+ +| | +| MSDOS.SYS relocated by | SYSINIT moves MS-DOS +| SYSINIT to fill hole in | down to OEM-designated +| memory. | FINAL_DOS_LOCATION +| | ++-----------------------------+ +| IO.SYS | ++-----------------------------+ +| Interrupt Vector Table | ++-----------------------------+ + +Memory during system initialization +performed by SYSINIT module. + SYSINIT AND MS-DOS INITIALIZATION Page 6-9 + + ++-----------------------------+ +| COMMAND.COM | High memory +| (transient) | ++-----------------------------+ +| | Start of TPA will vary +| Transient Program Area | with # of drivers, +| (TPA) | buffers, etc. ++-----------------------------+ +| COMMAND.COM (resident) | COMMAND.COM loads its ++-----------------------------+ transient part into top +| | of largest available +| MS-DOS structures, buffers | memory +| hardware stack space, | +| and installable drivers | ++-----------------------------+ +| | +| | +| MSDOS.SYS | +| | +| | ++-----------------------------+ +| | +| IO.SYS | +| resident device drivers | ++-----------------------------+ +| Interrupt Vector Table | ++-----------------------------+ + +Memory after SYSINIT installs command interpreter. + +This represents the normal configuration +during MS-DOS operation. + SYSINIT AND MS-DOS INITIALIZATION + + + + + + + + + CONTENTS + + +CHAPTER 7A WRITING THE FORMAT MODULE FOR MS-DOS 3.20/3.21 + + 7.1 Introduction 7-1 + 7.2 Format Modules and the ES Register 7-9 + 7.3 Changing the Logical Format of Disks 7-9 + + + + + CHAPTER 7B + + WRITING THE FORMAT MODULE + MS-DOS 3.20/3.21 + + + +HIGHLIGHTS OF CHANGES IN 3.2X OVER PREVIOUS 2.XX FORMAT VERSION: + + + o FORMAT is now designed to be an .EXE file. + + o The FBIGFAT variable has been introduced for 16-bit + FAT support. + + o ALLOCATEFAT routine allows space for the FAT to be + dynamically allocated. + + o Hardware specific functionality assumed to be provided + by device drivers. + + +HIGHLIGHTS OF CHANGES IN 3.20 OVER PREVIOUS FORMAT VERSIONS: + + The intention of the MS-DOS 3.2 FORMAT utility is to + reduce the amount of OEM work and also move any machine + dependencies to the device drivers (software BIOS). + The following are the new features of the MS-DOS 3.2 + FORMAT utility: + + o FORMAT is now designed to be hardware independent. + The FORMAT utility no longer makes calls directly to + the ROM BIOS to perform the format operation. The direct + calls to the ROM BIOS have been replaced with MS-DOS + system calls (Generic IOCTL's) that perform the necessary + format functions. The responsibility for interacting + with the ROM BIOS to deal with the formating functions is now + placed in the OEM's device drivers. + + o The current head and cylinder being formated is displayed in the + layout: + Head: %d Cylinder: %d + + o Two new switches have been added to FORMAT. The new switches + are: + /N:xx - Specifies the number of sectors/cylinder + on the media. + + /T:yy - Specifies the number of tracks on the media. + + These two options will only be useful if the ROM BIOS has support + to deal with changing of the disk drive parameters. + + o FORMAT will no longer format the default drive if no drive was + specified on the command line. + + + +7.1 INTRODUCTION + +The MS-DOS Format command formats a new disk, clears the FAT +and directory, and optionally copies system files and +COMMAND.COM to the new disk. The 3.2X Format utility no +longer requires the hardware specific code supplied by the +OEM in previous versions. Instead, Format relies on the +drive device driver to provide the functionality required +to format a track on that drive. The Format utility uses a +GENERIC_IOCTL function request to access the drive device +driver to format a track on the drive. If the device driver +does not support a format track function the Format utility +will not be able to format the drive. + +FORMAT is shipped in two hardware-independent object +modules. These must be linked to a system configuration +dependant module written by the OEM. The following section +describes the routines required in this module. A sample +OEM format module is included on the MS-DOS release disks +to assist in writing these routines. + +The syntax for the Format command is: + + + Format drive: [/switch1][/switch2]...[/switch16] + + "drive:" is a legal drive specification. As many as 16 + legal switches can be included in the command line. + + +7.2 CODE AND DATA FROM THE OEM + + +As the OEM may need to tailor the FORMAT module for a particular +system configuration the OEM must supply the routines and data +items which are specific to that configuration. The OEM should +produce a module, eg. OEMFOR.ASM, which contains the following +(NEAR) data items; + + SWITCHLIST + DOSFILE + BIOSFILE + +and the following (NEAR) routines; + + OEMDONE + WRITEBOOTSECTOR + CHECKSWITCHES + LASTCHANCETOSAVEIT + + +The detailed description of the data items required to be declared +public in the OEM's module is as follows; + + +SWITCHLIST + + A string of bytes. The first byte is count + n, followed by n characters that are the + switches to be accepted by the command line + scanner. Alphabetic characters must be in + uppercase (the numeric characters 0-9 are + allowed). The last six switches, normally + "/N","/T","/C","/O", "/V" and "/S", have + predefined meanings. + + The "/S" switch is the switch that causes the + system files IO.SYS, MSDOS.SYS, and + COMMAND.COM to be transferred to the disk + after it is formatted, thus making a system + disk. The switch can be some letter other + than "S", but the last switch in the list is + assumed to have the meaning "transfer + system," regardless of what the particular + letter is. + + The second to the last switch, "/V", causes + FORMAT to prompt the user for a volume label + after the disk is formatted. As with "/S", + the particular letter is not important but + rather the position in the list. + + The third to the last switch, "/O", causes + FORMAT to produce an IBM Personal Computer + DOS version 1.x-compatible disk. Normally + FORMAT causes a 0 byte to be placed in the + first byte of each directory entry instead of + the 0E5H free entry designator. This + markedly increases the performance of a + directory search due to an optimization in + the DOS. Disks made with this switch cause + trouble on IBM PC DOS 1.x versions which did + not have this optimization. The 0 byte fools + IBM 1.x versions into thinking these entries + are allocated instead of free. Note that IBM + Personal Computer DOS version 2.10 and MS-DOS + version 1.25 have no trouble with these + disks, since they have the same optimization. + The "/O" switch causes FORMAT to redo the + directory with a 0E5H byte at the start of + each entry so that the disk may be used with + 1.x versions of IBM PC DOS, as well as with + MS-DOS 1.25/2.XX and IBM PC DOS 2.00/2.10. + This switch should only be given when needed + because it takes a fair amount of time for + FORMAT to perform the conversion, and it + noticeably decreases 1.25 and 2.x performance + on disks with few directory entries. + + A "/C" switch is specified for "Clear". This + switch should cause the formatting operation + to be bypassed (within DISKFORMAT or + BADSECTOR). This is provided as a + time-saving convenience to the user, who may + wish to "start fresh" on a previously + formatted and used disk. + + The "/T:" option is used to specify the + number of tracks that Format will place on + a floppy disk. + + The "/N:" option is used to specify the + number of sectors per track that Format will + use to format a floppy disk. + + +BIOSFILE & DOSFILE + + The BIOSFILE and DOSFILE data strings are used to + specify the filenames for the hidden BIOS and DOS + system files written to the formatted disk when + the /s option is selected. + The filename strings should be null terminated root + directory specifications commencing with a dummy + non-zero drive letter byte which will be modified + by the FORMAT module at run-time. + eg. + + BIOSFILE db "x:\IO.SYS",0 + DOSFILE db "x:\MSDOS.SYS",0 + + +The following data is declared PUBLIC in Microsoft's +FORMAT module and may be used by the OEM's module +as required. + +SWITCHMAP + + A WORD value with a bit vector indicating + which switches are included in the command + line. The correspondence of the bits to the + switches is determined by SWITCHLIST. The + extreme right (highest-addressed) switch in + SWITCHLIST (which must be the system transfer + switch, normally "/S") corresponds to bit 0, + the second from the right, normally "/V" to + bit 1, etc. For example, if SWITCHLIST is + the string "7,'AGI2OVS'", and the user + specifies "/G/S" on the command line, then + bit 6 will be 0 (/A not specified), bit 5 + will be 1 (/G specified), bits 4,3,2 and 1 + will be 0 (neither I,2,O or V specified), and + bit 0 will be 1 (/S specified). + + +FBIGFAT + + BYTE which takes on one of two possible + values, 0 or 0FFH. WARNING: Any value other + than 0 or 0FFH will cause FORMAT to do very + odd things. The value 0 indicates that the + disk being formatted will have a 12-bit FAT. + The value 0FFH means that the disk being + formatted will have a 16-bit FAT. + + +DRIVE + + A byte value containing the drive specified + in the command line. 0=A, 1=B, etc. + + +DRIVELETTER + + A byte value containing the ASCII value of + the drive letter specified in the command + line. + + +DEVICEPARAMETES + + A structue containing the device parameters of + the drive to be formatted. The format of the + DEVICEPARAMETERS data structure is as follows; + + DP_SpecialFunctions : BYTE + DP_DeviceType : BYTE + DP_DeviceAttributes : WORD + DP_Cylinders : WORD + DP_MediaType : BYTE + DP_BPB : BPB + DP_TrackTableEntries : WORD + DP_sectorTable : BYTE TABLE + +INBUFF + + A string buffer used to return a character + string entered from the keyboard in the + user_string routine in the FORMAT module. + +CURRENTHEAD + + A word value containing the drive head + which was being formatted when an error + occurred. + + +CURRENTCYLINDER + + A word value containing the drive cylinder + which was being formatted when an error + occured. + +FLASTCHANCE + + A byte value used to flag whether a format + message is to printed at the start of + a format attempt. + + +NUMSECTORS + + A word value containing the number of + sectors specified in the command line + with the /n switch. + + +TRACKCNT + + A word value containing the number of + sectors specified in the command line + with the /t switch. + + + +The detailed description of the routines required to be declared +public in the OEM's module is as follows; + + +OEMDONE + + This routine is called after the formatting has + been completed, the disk directory has been + initialized and the system has been transferred + if specified. It is called once for each disk to + be formatted. This gives the chance for any + finishing up operations, if needed. If the OEM + desires extra files to be put on the formatted + disk by default, or according to a switch, this + could be done in OEMDONE. + The OEMDONE routine should also check for the /b + switch and, if present, should notify the FORMAT + module of a non-standard system size by calling + the ADDTOSYSTEMSIZE routine in the FORMAT module. + + The following data items form the inputs to the + OEMDONE routine; + + SwitchMap : A WORD vaule indicating which + switches were selected. The + format of the SwitchMap is + as described previously. + + + The OEMDONE outputs should be; + + Carry Flag : Set on error, else clear. + If an error status is returned + by OEMDONE, the error message + "Format failure" and a prompt + for another disk will be + displayed. + +WRITEBOOTSECTOR + + This routine is called once for each disk formatted + after the format has occured but prior to installing + a system on the disk. + The routine writes the OEM specific boot sector(s) + to the disk. The first boot sector must be written + to the disk with an initialized BPB. The boot code + may be contained within the OEMFOR module and copied + to the boot sectors by this routine or may be + written to the boot sectors after the format using a + separate OEM utility as long as the BPB is written + in this routine. + The functionality of the code and data required in + the boot sector(s) is discussed in detail in + section 4.4 . + If an error occurs while writing the boot sector(s) + the routine should display an error message and + return with the carry flag set. + + +CHECKSWITCHES + + + This routine is called once before any disks have + been formatted. It is used to verify that the + switches selected are a legal combination for the + drive type to be formatted and to modify the drive + device parameters according to the selected switches + if they are valid. For example the valid swith + combinations for supported drive types could be; + + + Disk Type Valid switches + + 160/180KB /l /4 /8 /b /n /t /v /s + 320/360KB /l /4 /8 /b /n /t /v /s + 720KB /n /t /v /s + 1.2MB /n /t /v /s + Hard disk /v /s + + + The CHECKSWITCH routine is included in the OEMFOR + module so that the OEM may decide what action to + take for an OEM specific drive type with the switch + combination selected. + + The following data items form the inputs to the + CHECKSWITCHES routine; + + + deviceParameters : A data structure containing + the drive parameters for the + drive to be formatted. The + fields of this structure are + as descibed previously. + + SwitchMap : A WORD vaule indicating which + switches were selected. The + format of the SwitchMap is + as described previously. + + NumSectors : A WORD value containing the + number of sectors specified + with the /n switch if it was + present in the command line. + + NumTracks : A WORD value containing the + number of tracks specified + with the /t option if it was + present in the command line. + + The CHECKSWITCHES outputs should be; + + Carry Flag : Set on error, else clear. + + deviceParameters : Device parameters to use in + the format operation. Should + have been modified by + CHECKSWITCES if a legal switch + combination specifies parameter + modification. + + NumSectors : If the /n switch was not present + in the command line then the + CHECKSWITCHES routine should + initialize the NumSectors WORD + from the deviceParamaters + structure. + + Trackcnt : If the /t switch was not present + in the command line then the + CHECKSWITCHES routine should + initialize the Trackcnt WORD + from the deviceParamaters + structure. + +LASTCHANCETOSAVEIT + + This routine is called when an error, other + than a write protect or not ready error, + occurs during the disk format. It gives the + OEM a chance to modify the disk parameters + to be used in the format operation. The + format will then be tried with these parameters. + An example of when this could be used is if + the format fails on the second head (track + zero), the OEM may want to try formatting + the disk single sided. + + + The LASTCHANCETOSAVEIT inputs are: + + deviceParameters : A data structure containing + the drive parameters for the + drive being formatted when + the error occurred. The fields + of this structure are as + described previously. + + currentCylinder : A WORD value indicating the + drive cylinder on which the + error occurred. + + currentHead : A WORD value indicating the + drive head on which the error + occurred. + + The LASTCHANCETOSAVEIT outputs should are: + + Carry Flag : Set if the error was fatal and + no attempt is to be made to + re-format the drive, else clear. + + deviceParameters : Modified to contain the new + parameters for the re-format, + if a re-format attempt required. + + fLastChance : A BYTE value set to TRUE if an + attempt to re-format the drive + is required. This prevents + multiple format messages for + a single drive format. + + +The following routines are declared PUBLIC in Microsoft's +FORMAT module and may be used by the OEMFOR module +as required. + + +ADDTOSYSTEMSIZE + + Adds to the number of sectors reserved for the system. + + INPUTS : ax = size of system file in bytes. + + OUTPUTS : None. + + +PRINTSTRING + + Displays a character string. + + INPUTS : dx = near pointer to null terminated string. + + OUTPUTS : None. + + +STD_PRINTF + + Displays a character string. + + INPUTS : dx = near pointer to a near pointer to a + null terminated string. + + OUTPUTS : None. + + +CRLF + + Outputs a carriage return and linefeed to the console. + + INPUTS : None. + + OUTPUTS : None. + + +USER_STRING + + Get a string from the keyboard. + + INPUTS : None. + + OUTPUTS : Zero flag set if only was enterred. + String length in BYTE at offset INBUFF + 1. + Console input in INBUFF commencing at offset + INBUFF +2. + + + +Once the OEM-supplied module has been prepared, it must be +linked with Microsoft's FORMAT.OBJ module, and the +FORMES.OBJ module. In 3.XX, there are additional format +modules that must be linked in. If the OEM-supplied module +is called OEMFOR.OBJ, then use the following linker command; + + link format forproc formes oemfor printf; + +This command produces an executable file called FORMAT.EXE. +NOTE: The OEM's module CAN NOT make the assumption, as it +could in the previous versions, that it is at the "end" of +the memory image. It must use function 48h (allocate +memory) if required. + + + +7.3 FORMAT MODULES AND THE ES REGISTER + +If an OEM-written FORMAT module, such as OEMDONE, makes use of +the ES register, the value of ES should be established by the +OEM's code. The contents of the ES register cannot be assumed. + + + + + + + + + CONTENTS + + +CHAPTER 7B WRITING THE FORMAT MODULE FOR MS-DOS 2.25/3.10 + + 7.1 Introduction 7-1 + 7.2 Format Modules and the ES Register 7-9 + 7.3 Changing the Logical Format of Disks 7-9 + + + + + + + + + CHAPTER 7B + + WRITING THE FORMAT MODULE + MS-DOS 2.25/3.10 + + + +HIGHLIGHTS OF CHANGES IN 3.XX OVER PREVIOUS 2.XX FORMAT VERSION: + + + o FORMAT is now designed to be an .EXE file. + + o The FBIGFAT variable has been introduced for 16-bit + FAT support. + + o ALLOCATEFAT routine allows space for the FAT to be + dynamically allocated. + + + + +7.1 INTRODUCTION + +The MS-DOS Format command formats a new disk, clears the FAT +and directory, and optionally copies system files and +COMMAND.COM to the new disk. Since the Format command must +perform functions that have no equivalent in MS-DOS function +calls, FORMAT is shipped in two hardware-independent object +modules. These must be linked to a hardware-specific module +written by the OEM. The following section describes the +routines required in this module. A sample OEM format +module is included on the MS-DOS release disks to assist in +writing these routines. + +The syntax for the Format command is: + + + Format [drive:][/switch1][/switch2]...[/switch16] + + "drive:" is a legal drive specification. If it is + omitted, the default drive will be used. As many as 16 + legal switches can be included in the command line. + + WRITING THE FORMAT MODULE Page 7-2 + + +In 3.XX the OEM must supply six (NEAR) routines to the program along +with seven data items. In 2.XX the OEM must supply five (NEAR) routines +to the program along with six data items. The names of the routines are: + + ALLOCATEFAT + INIT + DISKFORMAT + BADSECTOR + WRTFAT + DONE + +ALLOCATEFAT is used only in 3.XX. + +Their flow of control (by the Microsoft module) is like +this: + + | + +-------------+ + | ALLOCATEFAT | + +-------------+ + | + +---------+ + | INIT | + +---------+ + | + |<------------------------------+ ++------------+ | +| DISKFORMAT | | ++------------+ | + |<-------+ | ++-----------+ |-This loop is done |- This loop is +| BADSECTOR | | for each group of | done once for ++-----------+ | bad sectors | each disk to be + |----->--+ | formatted. If + | | variable HARDFLAG ++----------+ | is set then the +| | | loop is only +| WRTFAT | | performed once. ++----------+ | + | | + +------+ | + | DONE | | + +------+ | + +---->--------------------------+ + +The ALLOCATEFAT, INIT, DISKFORMAT, and BADSECTOR routines +are free to use any MS-DOS system calls, except for calls +that cause disk accesses on the disk being formatted. DONE +may use any calls, since by the time it is called the new ___ +disk has been formatted. + WRITING THE FORMAT MODULE Page 7-3 + + +The following data must be declared PUBLIC in a module +provided by the OEM: + +SWITCHLIST + + A string of bytes. The first byte is count + n, followed by n characters that are the + switches to be accepted by the command line + scanner. Alphabetic characters must be in + uppercase (the numeric characters 0-9 are + allowed). The last three switches, normally + "/O", "/V" and "/S", have pre-defined + meanings. + + The "/S" switch is the switch that causes the + system files IO.SYS, MSDOS.SYS, and + COMMAND.COM to be transferred to the disk + after it is formatted, thus making a system + disk. The switch can be some letter other + than "S", but the last switch in the list is + assumed to have the meaning "transfer + system," regardless of what the particular + letter is. + + The second to the last switch, "/V", causes + FORMAT to prompt the user for a volume label + after the disk is formatted. As with "/S", + the particular letter is not important but + rather the position in the list. + + The third to the last switch, "/O", causes + FORMAT to produce an IBM Personal Computer + DOS version 1.x-compatible disk. Normally + FORMAT causes a 0 byte to be placed in the + first byte of each directory entry instead of + the 0E5H free entry designator. This + markedly increases the performance of a + directory search due to an optimization in + the DOS. Disks made with this switch cause + trouble on IBM PC DOS 1.x versions which did + not have this optimization. The 0 byte fools + IBM 1.x versions into thinking these entries + are allocated instead of free. Note that IBM + Personal Computer DOS version 2.10 and MS-DOS + version 1.25 have no trouble with these + disks, since they have the same optimization. + The "/O" switch causes FORMAT to redo the + directory with a 0E5H byte at the start of + each entry so that the disk may be used with + 1.x versions of IBM PC DOS, as well as with + MS-DOS 1.25/2.XX and IBM PC DOS 2.00/2.10. + This switch should only be given when needed + because it takes a fair amount of time for + WRITING THE FORMAT MODULE Page 7-4 + + + FORMAT to perform the conversion, and it + noticeably decreases 1.25 and 2.x performance + on disks with few directory entries. + + Up to 16 switches are permitted. Normally a + "/C" switch is specified for "Clear". This + switch should cause the formatting operation + to be bypassed (within DISKFORMAT or + BADSECTOR). This is provided as a + time-saving convenience to the user, who may + wish to "start fresh" on a previously + formatted and used disk. + +HARDFLAG + + BYTE location which specifies whether the OEM + routine is formatting a fixed disk or a drive + with removable media. A zero means removable + media; any other value indicates a fixed + disk. The status of this byte only affects + the messages printed by the main FORMAT + module. This value should be set or reset by + the OEM-supplied INIT routine. + +FATID + + BYTE location containing the value to be used + in the first byte of the FAT. Must be in the + range F8H to FFH. + +STARTSECTOR + + WORD location containing the sector number of + the first sector of the data area. + +FATSPACE + + WORD location containing the address of the + start of the FAT area. A FAT built in this + area will be written to disk using the + OEM-supplied WRTFAT subroutine. 6K is + sufficient to store any 12-bit FAT. This + area must not overlap the FREESPACE area. + +FREESPACE + + WORD location that contains the address of + the start of free memory space. This is + where the system will be loaded by the + Microsoft module for transferring to the + newly formatted disk. Memory should be + available from this address to the end of + memory, so it is typically the address of the + end of the OEM module. + WRITING THE FORMAT MODULE Page 7-5 + + +FBIGFAT + + BYTE which takes on one of two possible + values, 0 or 0FFH. WARNING: Any value other + than 0 or 0FFH will cause FORMAT to do very + odd things. The value 0 indicates that the + disk being formatted will have a 12-bit FAT. + The value 0FFH means that the disk being + formatted will have a 16-bit FAT. See + ALLOCATEFAT call, below, for details. + FBIGFAT is used only in 3.XX. + +The following routines must be declared PUBLIC in the +OEM-supplied module: + +ALLOCATEFAT + + ALLOCATEFAT is used only in 3.XX. It is + an initialization routine. This routine is + called once at the start of the FORMAT run + after the switches have been processed. This + routine must set the correct values of + FBIGFAT, FATSPACE, and FREESPACE. + + With only 12-bit FATs it was convenient to + allocate a FAT area of 6K (maximum size of a + 12-bit FAT) as part of the memory image of + FORMAT. With the advent of 16-bit FATs in + DOS 3.XX this is no longer convenient; the + maximum size of of a FAT is 32K. + + ALLOCATEFAT is a dynamic space allocator that + allocates enough memory to hold the FAT by setting + the values of FATSPACE and FREESPACE. + ALLOCATEFAT must also set FBIGFAT so that + FORMAT knows whether the disk has a 12 or a + 16-bit FAT. + + FBIGFAT must be set consistently with the + following FAT rule (see below). + + The 16-bit FAT rule: + + - Any disk with less than 4086 clusters has a ____ ____ + 12-bit FAT. + - Any disk with greater than or equal to 4086 _______ ____ __ _____ __ + clusters has a 16-bit FAT. + + The OEM FORMAT module cannot force a 16-bit + FAT if the total number of clusters is less + than 4086. Similarly, you cannot have a + 12-bit FAT on a disk with more than 4085 + clusters. If the OEM module does not set + FBIGFAT consistently with the 16-bit FAT + rule, the disk will not be formatted + correctly, and MS-DOS will not access the + disk in the proper manner. + WRITING THE FORMAT MODULE Page 7-6 + + + Currently, there is no error return from + ALLOCATEFAT. It should exit with CARRY + CLEAR, however, so that it is consistent with + the other routines. + + The Microsoft 3.XX FORMAT.OBJ is responsible for + checking that the memory needed for the FAT is + actually available to the system. It will + produce a "Insufficient memory for system transfer" + error when memory is inadequate. This error + is produced when memory is inadequate for both + "/S" and non "/S" procedures. + + +INIT + + An initialization routine. This routine is + called once at the start of the FORMAT run + after the switches have been processed. This + routine should perform any functions that + need to be done once per FORMAT run. An + example of what this routine might do is read + the boot sector into a buffer so that it can + be transferred to the new disks by + DISKFORMAT. If this routine returns with the + CARRY flag set, it indicates an error, and + FORMAT will print "Format failure" and quit. + This feature detects conflicting switches + (like specifying both single and double + density) and causes the FORMAT routine to + abort. + +DISKFORMAT + + Formats the disk according to the options + indicated by the switches and the value of + FATID must be defined when it returns + (although INIT may have already done it). + This routine is called once for each disk to + be formatted. If necessary, it must transfer + the bootstrap loader. If any error + conditions are detected, the carry flag is + set. FORMAT will report a "Format failure" + and prompt for another disk. (If you only + require a clear directory and FAT, all that + DISKFORMAT must do is set the appropriate + FATID, if this has not already been done by + INIT. + + + + + + + + + + + + +BADSECTOR + + Reports the sector number of any bad sectors + that may have been found during the + formatting of the disk. This routine is + called at least once for each disk to be + formatted, and is called repeatedly until the + AX register is zero or the carry flag is set. + The carry flag is used just as in DISKFORMAT + to indicate an error, and FORMAT handles it + in the same way. The first sector in the + data area must be in STARTSECTOR for the + returns from this routine to be interpreted + correctly. If there are bad sectors, + BADSECTOR must return a sector number in + WRITING THE FORMAT MODULE Page 7-7 + + + register BX, the number of consecutive bad + sectors in register AX, and clear the carry + flag. FORMAT will then process the bad + sectors and call BADSECTOR again. When + BADSECTOR returns with AX = 0, there are no + more bad sectors; FORMAT clears the + directory and goes on to DONE. For this last + return, BX need not contain anything + meaningful. + + FORMAT processes bad sectors by determining + their corresponding allocation unit and + marking that unit with an FF7H in the File + Allocation Table. CHKDSK understands the + FF7H mark as a flag for bad sectors and + accordingly reports the number of bytes + marked in this way. + + Actual formatting of the disk can be done in + BADSECTOR instead of DISKFORMAT on a "report + as you go" basis. Formatting continues until + a group of bad sectors is encountered; + BADSECTOR then reports them by returning with + AX and BX set. FORMAT will then call + BADSECTOR again and formatting can continue. + +WRTFAT + + This routine is called after the disk is + formatted and bad sectors have been reported. + It writes all copies of the FAT from the area + of memory referenced by FATSPACE to the drive + just formatted. It may be possible to use + INT 26H to perform the write, or a direct + BIOS call. Whether this is possible depends + on whether the FAT ID byte is used by the + BIOS to determine the media in the drive. If + it is, these methods will probably fail + because there is no FATID byte on the disk + yet (in this case WRTFAT's primary job is to + get the FATID byte out on the disk). + +DONE + + This routine is called after the formatting + has been completed, the disk directory has + been initialized, and the system has been + transferred if specified. It is called once + for each disk to be formatted. This gives + the chance for any finishing-up operations, + if needed. If the OEM desires extra files to + be put on the disk by default, or according + to a switch, this could be done in DONE. + WRITING THE FORMAT MODULE Page 7-8 + + + Again, as in BADSECTOR and DISKFORMAT, carry + flag set on return means an error has + occurred; "Format failure" will be printed + and FORMAT will prompt for another disk. + +The following data is declared PUBLIC in Microsoft's +FORMAT module: + +SWITCHMAP + + A WORD value with a bit vector indicating + which switches are included in the command + line. The correspondence of the bits to the + switches is determined by SWITCHLIST. The + extreme right (highest-addressed) switch in + SWITCHLIST (which must be the system transfer + switch, normally "/S") corresponds to bit 0, + the second from the right, normally "/V" to + bit 1, etc. For example, if SWITCHLIST is + the string "7,'AGI2OVS'", and the user + specifies "/G/S" on the command line, then + bit 6 will be 0 (/A not specified), bit 5 + will be 1 (/G specified), bits 4,3,2 and 1 + will be 0 (neither I,2,O or V specified), and + bit 0 will be 1 (/S specified). + + Bits 0,1 and 2 are the only switches used in + Microsoft's FORMAT module. These switches + are used 1) after INIT has been called to + determine if it must load the system; 2) + after the last BADSECTOR call to determine if + the system should be written, E5 directory + conversion should be done, and/or a volume + label should be asked for. INIT may force + these bits set or reset if desired (for + example, some drives may never be used as + system disk, such as hard disks). After + INIT, the "/S" bit may be turned off (but not + on, since the system was never read) if + something happens that means the system + should not be transferred. + + After INIT, a second copy of SWITCHMAP is + made internally.It is used to restore + SWITCHMAP for each disk to be formatted. + FORMAT will turn off the system bit if bad + sectors are reported in the system area; + DISKFORMAT and BADSECTOR are also allowed to + change the map. However, these changes + affect only the current disk being formatted, + since SWITCHMAP is restored after each disk. + (Changes made to SWITCHMAP by INIT affect all + disks.) + WRITING THE FORMAT MODULE Page 7-9 + + +DRIVE + + A byte value containing the drive specified + in the command line. 0=A, 1=B, etc. + +Once the OEM-supplied module has been prepared, it must +linked with Microsoft's FORMAT.OBJ module, and the +FORMES.OBJ module. In 3.XX, there are additional format +that must be linked in. If the OEM-supplied module is called +OEMFOR.OBJ, then use the appropriate linker command. + +2.XX LINK FORMAT.OBJ+FORMES.OBJ+OEMFOR.OBJ + +3.XX LINK FORMAT.OBJ+FORPROC.OBJ+FORMES.OBJ+OEMFOR.OBJ.PRINTF.OBJ + +For 3.XX, the command produces an executable file called +FORMAT.EXE. Note that although the PRINTF.OBJ module +is the last module specified, it does not follow the +OEMFOR module in the memory image. The OEMFOR module +can still make the assumption, as it has in the past, +that it is at the "end" of the memory image. + +For 2.XX, the command produces a FORMAT.EXE file which +must be changed to a simple binary. This should be done +with the following command. + + EXE2BIN FORMAT.EXE FORMAT.COM + +This produces the 2.XX file, FORMAT.COM. + + +7.2 FORMAT MODULES AND THE ES REGISTER + +If an OEM-written FORMAT module makes use of the ES +register, such as DISKFORMAT, the value of ES should be +established by the OEM's code. The contents of the ES +register cannot be assumed. + + + + + + + + + + + + + + + + + + + + + + + +WRITING THE FORMAT MODULE PAGE 7-10 + + +7.3 CHANGING THE LOGICAL FORMAT OF DISKS + +MS-DOS has an internal table which it builds from +information returned by the BIOS BUILDBPB routine. +There is a table maintained for each drive within the +system and it is updated to reflect the media type +whenever a new disk is loaded. Before any access to +the disk directory, MS-DOS calls the BIOS MEDIACHECK +routine. If a disk change is reported, MS-DOS calls +the BIOS BUILDBPB routine to get the new media +information and updates its internal table. It is +important to realize that MS-DOS operates with its own +table and not with any table within the BIOS. + +FORMAT can be used to physically reformat the disk from +single to double-sided use. Therefore, the WRTFAT +routine should ensure that the next call to the BIOS +MEDIA CHECK/BUILD BPB routines made by the DOS will set +the media type to the type just formatted. This is +because when the format operation is started, the DPB +(Drive Parameter Block) reflects the media that existed +before the format. This may need to be changed because +the disk media may have been changed due to the format +process. Since this is basically a communication +between the OEM part of the FORMAT utility and the OEM +BIOS, it is up to the OEM to determine the most +efficient and appropriate way to determine the correct +media type. As an example, the FORMAT utility can call +the BIOS and cause the BIOS to return "media changed" +on the next MEDIA CHECK call made by the DOS. The DOS +will then call the BUILDBPB BIOS routine; it must +return the correct BPB for the disk just formatted. + +Trying to determine media change externally with the +FORMAT utility calling the DOS will not work. You +must: + + + o Have the correct BPB in the BIOS, and your + FORMAT utility must communicate that + information down to your BIOS, or + + o Your BIOS must detect that the disk has been + changed when the FORMAT utility is used. + Then, the BIOS can look on the disk for the + BPB and tell the DOS what the new BPB is. + + +The OEM may decide how this can be structured. The +BIOS can be in control and inform FORMAT what was done, +or FORMAT can be in control and inform the BIOS that +the media has changed. + +There is an example of an OEM written FORMAT module on the +Sample MS-DOS Implementation Diskette. + + + + + + + + CONTENTS + +CHAPTER 8 TROUBLE-SHOOTING + + + + + + + + + + + + + + CHAPTER 8 + + TROUBLE-SHOOTING + + + +The following section addresses typical problems that you +may encounter when installing MS-DOS. + + +Problem: + + When I type "r" for Retry when a disk error occurs, the + system crashes. + + Typical Cause: + + When an error occurs during I/O, your device driver + must report the number of sectors or characters + correctly transferred. If you just set the error bit, + MS-DOS will assume that it was able to read all of the + sectors since the sector count will be the same as that + set by MS-DOS. + + Recommendation: + + Report the actual number of sectors/bytes transferred + in addition to reporting the error. + + +Problem: + + I am booting up MS-DOS. I see the MS-DOS copyright + message on the screen, but then I get the message "Bad + or missing command interpreter." + + Typical Cause: + + SYSINIT is executing COMMAND.COM. This is the + conclusion of MS-DOS initialization and is the first + time that the disk must be read successfully. (Failure + to find CONFIG.SYS is not an error.) Either COMMAND.COM + is not on the disk or an invalid Bios Parameter Block + (BPB) has been returned to MS-DOS so it does not + correctly understand the format of the disk. + TROUBLE-SHOOTING Page 8-2 + + + Recommendation: + + Check that the correct BPB is being returned and that + COMMAND.COM is on disk. Install debugging code in the + device driver to make sure requests to the device + driver make sense. + + +Problem: + + I am booting up MS-DOS. I get the MS-DOS copyright + message on the screen, but then I get the message "Bad + or missing /DEV/CON." + + Typical Cause: + + SYSINIT has closed all file handles and is now + reopening them. The first file it opens is /DEV/CON, + which is your console device. The system file table is + examined for this device. /DEV/CON should be present. + If it is not found, some of your IO.SYS code has + destroyed the system file table or MS-DOS itself. This + may happen if you have blown the MS-DOS stack, causing + MS-DOS to write over the file table. + + Recommendation: + + Use a local stack in your device drivers. + + +Problem: + + MS-DOS is trying to read some sectors starting at an + extremely large or invalid sector number. + + Typical Cause: + + The BPB that you returned for the drive is bad. + + Recommendation: + + The INIT and BUILD BPB device driver routines should be + checked. + + +Problem: + + After I jump to SYSINIT, control never comes back. + + Typical Cause 1: + + You may not have loaded MS-DOS correctly with your + bootstrap loader. SYSINIT must know exactly where + MS-DOS is. MS-DOS must be on a paragraph boundary and + CURRENT_DOS_LOCATION and FINAL_DOS_LOCATION must be + set up accordingly. + + TROUBLE-SHOOTING Page 8-3 + + + Recommendation: + + Check the location of MSDOS.SYS after bootstrap + loading. + + Typical Cause 2: + + You are incorrectly reporting the amount of memory in + the system or the memory scan is failing because of a + discontinuity. + + Recommendation: + + Don't move MS-DOS after bootstrap loading. Don't + request a memory scan. Make sure memory is contiguous. + + Typical Cause 3: + + MS-DOS can't find the beginning of the device list. + + Recommendation: + + Check the value passed to SYSINIT to make sure that it + is the correct value for the beginning of the list. + + Typical Cause 4: + + The driver attributes are wrong. MS-DOS will not look + for the end of list mark if the attributes are wrong. + + Recommendation: + + Check the device driver attribute words. + + Typical Cause 5: + + You do not have a driver in the linked list of device + drivers with the CLOCK attribute bit set. This is + necessary before SYSINIT will start looking for FFFF, + FFFF in the last device driver. + + Recommendation: + + Be sure you have a CLOCK device in your linked list + with its attribute word set properly. + + +Problem: + + Everything was working great, but when I tried to + install a new device, the system wouldn't boot. + + Typical Cause: + + You are failing to set the BREAK ADDRESS during the + TROUBLE-SHOOTING Page 8-4 + + + device INIT routine. This points to the first byte of + free memory after the device code and data. + + Recommendation: + + Set the break address. + +Problem: + + Everything works OK until I define a new drive in + IO.SYS. Then the system won't come up. + + Typical Cause: + + You are returning invalid data from the INIT call to + the block device driver. + + Recommendation: + + Examine the INIT call. This is probably not being + handled correctly. You should return a DWORD pointer + to an array of WORD POINTERS to BPBs. The array must be + below the 'break address' returned by INIT. There should + be one array element for each drive defined. The number + of subunits is also returned by the INIT call. + + +Problem: + + My device driver defines two drives, but when I try to + use drive B, I get an "Invalid drive specification" + message. + + Typical Cause: + + You are not handling the INIT call to the device driver + properly. + + Recommendation: + + The INIT call should return the value "2" at offset 13 + from the beginning of the static request header. + +Problem: + + When I have a single-sided disk in drive B and remove + it and install a double-sided disk, MS-DOS treats the + double-sided disk like a single-sided disk. I am + returning the correct BPB for the double-sided disk. + + Typical Cause: + + The media bytes in the BPBs are not unique. + + Recommendation: + TROUBLE-SHOOTING Page 8-5 + + + Each BPB has a unique media byte. MS-DOS will not + rebuild its internal DPB structure if the media byte + doesn't change. + +Problem: + + I have a one-drive system. When I type B:, I + get an "Invalid drive specification" message, but on + some single-drive machines, MS-DOS prompts me for the + "disk for drive B:." + + Typical Cause: + + The INIT call is only defining one disk drive and + support for swapping has not been implemented in + IO.SYS. + + Recommendation: + + Support for disk swapping is implemented at the IO.SYS + file level rather than at the MS-DOS level. The driver + reports two drives and when it sees a request for unit + 1 (the second drive), it prints the swap message + directly on the screen. + +Problem: + + Everything is running fine, but when I run Chkdsk I + find that I only have 60K bytes free, but I have a 128K + machine. I know that DOS and IO.SYS only take up 24K. + What is happening to the missing bytes? + + Typical Cause: + + The Block Device Driver INIT call is returning a bad + BPB pointer which reports an absurdly large sector + size. This sector size is used to make all of the + sector buffers, and consequently wastes thousands of + bytes. You could have incorrectly set FINAL_DOS_LOCATION + or installed a device driver that returned an 'absurdly + large' break address. + + Recommendation: + + Fix the block device driver INIT call. + + +Problem: + + Every time I try to do an Allocate Memory call + (Function 48H) or an EXEC call, I get a return code of + 8, "Not enough memory." + + Typical Cause: + + There is no free memory. + TROUBLE-SHOOTING Page 8-6 + + + Recommendation: + + Do a Set Block (Function 4AH) call to shrink the size + of the currently allocated block, freeing some memory. + See the section on arenas in the Glossary. + + +Problem: + + When running a program that opens a number of files via + Function Request 3DH, the file open fails even though + the file is present on the disk. + + Typical Cause: + + You have run out of entries in the system file table. + + Recommendation: + + Increase the "FILES = " entry in CONFIG.SYS and reboot. + + +Problem: + + Control-S, Control-P, and the other control characters + seem to be ignored by MS-DOS. + + Typical Cause: + + The non-destructive console read routine is not + implemented properly. + + Recommendation: + + Check the non-destructive read routine in the console + or other character driver where this problem is + occurring. + + +Problem: + + Sometimes when I am typing a long file to the screen + and press Control-S, the Control-S is ignored and + doesn't stop the scrolling of the file. I have the + same problem with Control-C. + + Typical Cause: + + Another character has been typed into the type-ahead + buffer first, and the nondestructive read keyboard + status check never sees the Control-S or the Control-C. + + Recommendation: + + Implement Scroll Lock and Break keys which flush the + TROUBLE-SHOOTING Page 8-7 + + + input queue and put the Control-S/Control-C at the + beginning of the type-ahead buffer. + + +Problem: + + I am trying to use EXE2BIN to convert IO.EXE to IO.SYS. + I get the message "File cannot be converted." + + Typical Cause: + + You have a "SEGMENT AT NNNN" statement and there is + code or initialized data in that segment. You may also + have a stack segment, which is not permitted. + + Recommendation: + + Remove the "SEGMENT AT" statement or remove code or + initialized data from the segment. + + It is possible, if your code contains FAR references, that + EXE2BIN may request a 'Fixup' address. If your IO.SYS will + always be loaded at the same place in memory, this may be + OK. Check your FAR references in any case. + + + + + + + + + + + + + + APPENDIX A + + CUSTOMIZATION OF MS-DOS AND INTERNATIONALIZATION + + + +A.1 CUSTOMIZING MS-DOS + +Many manufacturers find it necessary to customize MS-DOS (as +distinct from IO.SYS) to some degree. The function key +table and OEM serial number are often modified. The +function key table is found in the DOSMES.ASM file. Extensive +modification to this table may require modifying the line +input routines in STRIN.ASM, which is available to source +licensees only. + +OEM Serial Numbers: + +Each OEM is eligible for a unique OEM Serial Number. The Series +is 0 to FF (255). IBM is 00 and we are currently at about 50H +on list. + +These numbers are assigned sequentially by MS-DOS Product Marketing +as requested through the OEM's Account Manager. + +Once the OEM has this number they can modify the default FF +value in the file DOSMES.ASM that is part of the adaptation +kit. If this is done, when MSDOS.SYS file is built +it will the right value. + +It can be patched after they MSDOS.SYS is built by following +the instructions in the README.DOC on the MS-DOS DISTRIBUTION +DISKETTES. + +Function Request 30H - Get MS-DOS Version Number will +return the version of the DOS that is being run, the OEM +Serial number and the OEM user number. + +To implement OEM user number concept properly each individual +disk shipped should have to have a separate user number patched +in according to the directions in the README.DOC on the +MS-DOS DISTRIBUTION DISKETTES. + +The OEM serial number can, however, be used without using the +OEM User Number. + +With these numbers properly installed, an application program +could tell which version of MS-DOS was being run, which +OEM had sold it and which customer had bought it. + +Internationalization may also require customizing MS-DOS. +The file named DOSMES.ASM contains a case conversion routine +and a table used to translate foreign characters into their +uppercase equivalents. This routine defaults to no case +conversion, and a sample for the IBM PC character set is +included. Note that this table is country-dependent. You +should not translate a lowercase character available on the +keyboard into a uppercase equivalent that is not on the ___ +keyboard. For example, in France, translate lowercase c +cedilla into uppercase C (not C cedilla); in Germany, +translate lowercase "a umlaut" into uppercase A umlaut. + +DOSMES.ASM also contains country-dependent tables used by +the international system call (Function 38H). MS-DOS +utilities and COMMAND.COM make two system calls to determine +time and date formats and the location of the case +conversion routine. You may supply as many tables as you +wish; however, it is not necessary to supply tables for all +countries in all translations. You should include tables +for all countries into which a language translation is +distributed. For example, French might include tables for +France, Belgium, and Switzerland. All versions should +include a U.S. table as well. There is a pointer in +DOSMES.ASM to the table to which MS-DOS should default if +the user specifies no "COUNTRY =" parameter in CONFIG.SYS. +Country numbers follow the information telephone codes where +two-digit numbers are employed. + + CUSTOMIZATION OF MS-DOS AND INTERNATIONALIZATION Page A-2 + + +A non-ASCII character text is represented by variables +equated at the beginning of the file. These default to the +IBM PC character set. If your character set is different, +redefine the equates and reassemble, linking the message +file with the code files. + +The SORTMES.ASM file contains a table for collating +sequences. This defaults to no mapping; all uppercase +ASCII is sorted before all lowercase ASCII. A sample table +for the IBM PC character set is included. Note that there +is no capability for equating a single character to a +multiple character string or vice versa. Therefore, German +implementations cannot equate an umlaut to "ae", but may +choose to equate it to "a" or have it fall between "a" and +"b". + + + + + +A.2 EXTENDED CHARACTER SET (ECS) CONSIDERATIONS - MS-DOS 2.25 + +All ECS characters are two-byte quantities which also display as two +physical character positions (double-written) on the screen and +printer. This imposes some constraints on the IO.SYS keyboard and +screen drivers. MS-DOS ensures that 16-bit ECS characters are treated +as a single logical character from the user's standpoint, rather +than being confused for two characters. + CUSTOMIZATION OF MS-DOS AND INTERNATIONALIZATION Page A-3 + + +A.3 INPUT + +On input, it is the responsibility of IO.SYS to pass ECS +characters to MS-DOS. IO.SYS must handle all +Kata-kana-to-ECS conversion or any other method used to +enter ECS. IO.SYS always places both bytes of the ECS +character into its buffer at once; however, they are passed +to MS-DOS as if they are two separate single-byte +characters. Therefore, even non-interrupt-driven keyboards +should always have the second byte of the ECS character +waiting by the time the first byte is accepted by MS-DOS. +IO.SYS should never pass an invalid ECS sequence to +MS-DOS. + + + +A.4 OUTPUT + +On output, IO.SYS must identify the first byte of an ECS +character, set a flag, and wait for the second byte. Once +the entire ECS character has been received, IO.SYS indexes +into the font table. The font table may be in memory, on +disk, or in a combined memory-disk caching scheme. IO.SYS +may call MS-DOS to read font files stored on the disk in +MS-DOS format. These files should be opened in IO.SYS when +control is passed back to RE_INIT, after MS-DOS has been +initialized. + +IO.SYS performs error recovery in case the font files are on +a disk that has been removed. Door lock detection is most +helpful here. Files should be reopened whenever the +potential for a changed disk occurs. MS-DOS screen and +keyboard routines are not reentrant, and cannot be called +from within IO.SYS to facilitate recovery from this error. +A solution to the problem of missing font files is to +display all ECS characters for which no font is in memory +as double-width reverse video blanks. + +IO.SYS also must perform error handling in the data stream +where an invalid ECS sequence is sent. Although invalid +characters should never be input from the keyboard, they can +be output by several occurrences: + + + 1. The user can display a garbage file, such as a + binary executable file. + + 2. A program may have executed a file with bad ECS + data. + + 3. The manipulation of fixed length fields may have + split a ECS character between its two bytes. + + + CUSTOMIZATION OF MS-DOS AND INTERNATIONALIZATION Page A-4 + + +If any of these occur, the recommended procedure is to +display a double-width reverse video blank character +followed by the single-byte ASCII value for the character +outside of the valid second-byte range. This will help to +resynchronize the data stream as soon as possible. + +MS-DOS recognizes double-byte values, such as blank space, +over ECS in its line editing procedures. It also will +accept and display (if appropriate) the second byte where a +single-byte response is anticipated ("Strike any key"). + +IO.SYS should ensure that a ECS character is never split +across the last column of one physical line and the first +column of the next line. The entire ECS character must +start on the next line. IO.SYS must keep a flag for each +line to determine whether one or two logical backspace +operations should be performed. The "Backspace-Space- +Backspace" destructive operation issued by MS-DOS will work +properly. + +For example, starting with column 1, assume that text runs +up to and includes column 79. MS-DOS requests that a +double-byte ECS character be displayed. IO.SYS: + + + 1. Blanks column 80. + + 2. Sets a flag for that physical line. + + 3. Moves to the beginning of the next line. + + 4. Displays both bytes. + + +MS-DOS requests two backspaces over this ECS character. +If a third backspace is issued, IO.SYS must clear the flag +and perform an extra backspace, returning to column 79 +instead of 80. If a space is issued, column 79 will be +blanked. Remember that column 80 was originally blank, so +there is no need to reset it. + +If the ANSI screen driver is also implemented, the driver +should never allow only one-half of a ECS character to be +block transferred without blanking it in scrolling regions. +This rule also applies to both the region being moved and +the area into which it is being moved. + + + + + + + + + + + + + + APPENDIX B + + HOW TO UPGRADE A 2.XX BIOS TO 3.XX + + + +MS-DOS 3.XX provides very few new services that impact device +drivers. The basic BIOS mechanisms are identical to those +in MS-DOS 2.XX. The only changes are that a few new device +driver calls have been added. These calls are not required. ___ +There are new device attribute bits that indicate the +presence of these new functions. Old device drivers do not +have these bits set, and thus indicate that the functions +are not present. + +There are several new CONFIG.SYS commands. The code for +these is contained in the SYSINIT modules, and there are no +new PUBLICs in SYSINIT, or expected EXTERNs in the BIOS. + +First, to quickly bring up MS-DOS 3.XX with a 2.XX set of +device drivers, all that you need to do is build a new BIOS +with the new 3.XX SYSINIT and SYSIMES modules in the same way +that the 2.XX BIOS was built. This will produce a perfectly +functional BIOS, but none of the devices will have any of +the new 3.XX functions implemented. + +Since you have not modified your BIOS, you cannot support +the following features: + + + 1. The IOCTL is Changeable (Function 4408H) call. + This is useful for FORMAT and other programs that + want to prompt for a change of media. + + 2. The character device OPEN and CLOSE device driver + calls. These are useful for flushing + interrupt-driven I/O. + + 3. The background print utility spooling to a network + printer. + + 4. Output-until-busy device driver call for + PRINT/PSPRINT spool devices. + + + HOW TO UPGRADE A 2.XX BIOS TO 3.XX Page B-2 + + + 1. IOCTL Is Changeable Call + + The IOCTL Is Changeable (Function 4408H) call is + fairly easy to implement. Set the appropriate bit + in the device-attribute word for your block device + drivers, and add the necessary code to return the + particular value for your floppies and hard disks. + + + 2. OPEN and CLOSE calls + + OPEN and CLOSE device driver calls are needed only ____ + if you have interrupt-driven I/O. If you omitted + this feature, then you have nothing to do. If you + support interrupt-driven I/O, set the appropriate + bit in the attribute word for your character device + driver and add the necessary code to wait until + your buffers are empty. + +____________________________________________________________ +| | +| Note | +| | +| The same bit in the attribute word is used to indicate | +| that Is-Removable and OPEN/CLOSE is present. This | +| means that you must put in NO-OP stubs for those | +| functions you will not use (simply return with no error | +| for OPEN/CLOSE). MS-DOS assumes that all three of | +| these new functions exist if this attribute bit is set. | +| | +|__________________________________________________________| + + + 3. Background Print Utility + + The third feature (background print spooling to a + network printer) is difficult to implement. You + MAY need to add code to the output loop of the + character device driver that tells the network + portion of MS-DOS that you sent a character to a + particular device. You will also need to modify + the code in NETPS (part of the Redirector) to + receive this input. The skeleton code in NETPS is + for INT 17H (output-to-printer) on the IBM PC. So + there is NO SPECIAL CODE in the IBM PC printer + device drivers as everything is handled by INT 17H. + Your architecture may require a different mechanism. + You may wish to use the INT 2FH mechanism to achieve + this. + + If your architecture doesn't provide for Redirection + at the ROM BIOS entry level (INT 17H on the IBM PC), + your added code in the device driver will signal + the network piece that you have a character + destined for a particular device. The network + piece will decide whether or not that output should + be routed across the network. If so, it will + handle the character and return an indication that + the character was handled. Otherwise, it will + indicate that the device driver should take care of + HOW TO UPGRADE A 2.XX BIOS TO 3.XX Page B-3 + + + it. After this call in the device driver, the code + should examine the return to see if the device + driver should process the character or return. The + code required to do this is quite small, typically + less than 100 bytes. + + There is more information about how this is done + in the Redirector Adaptation Guide that is available + on the MS-NET distribution diskette. + + + + 4. Output-Until-Busy Call + + The fourth feature is a new device call that helps + the performance of the PRINT and PSPRINT + (networking print) utilities. Most printers have + RAM buffers which typically hold a line of + characters or some fixed amount of characters. + These buffers fill up without the printer going + busy. This yields a "burst" type of behavior. A + line of characters can be very quickly output to + the printer, then the printer goes busy for a long + time while the characters are being printed. This + new device call allows the background spooling + programs PRINT and PSPRINT to use this burst + behavior efficiently. Rather than take the + overhead of a device driver call for each + character, or risk getting "stuck" in the device + driver outputting a block of characters, this call + allows a burst of characters to be output without + getting stuck in the device driver waiting for the + device to come ready. + + + APPENDIX C + + HOW TO UPGRADE A 3.10 BIOS TO 3.20 + +The major change in the MS-DOS 3.2 BIOS is in the device drivers. +The device drivers provide the support for the new Generic IOCTL +requests. If some of the new MS-DOS 3.2 features are going to be +used, then the Generic IOCTL functions have to implemented in the +device drivers. For example, the new MS-DOS 3.2 FORMAT utility +has been designed to be hardware independent and uses Generic IOCTL's +extensively. If the Generic IOCTL's are implemented in the device +drivers, then the OEM will not have to modify the FORMAT utility. +Refer to the MS-DOS 3.2 Device Drivers Guide and the MS-DOS 3.2 +Technical Guide for a complete listing of the use of Generic IOCTL's. + +NOTE: Old device drivers will still work under MS-DOS 3.2 without +the Generic IOCTL's, but will not get the benefit of this feature. + +The MS-DOS 3.2 BIOS makes use of a new data structure called +the Block Data Structure (BDS). The BDS is listed in the file +MSBDS.ASM in the sample BIOS disk. This data structure describes +the characteristics of a physical block device. The BDS is filled +in at BIOS initialization time. The physical characteristics +within the BDS can be changed after initialization time by using the +DRVPARM option in the CONFIG.SYS file. Any block device drivers that +have the special MS-DOS 3.2 version bit set in the attribute word +must contain a BDS. The BDS in the device driver will be linked with +the other BDS's of the system at initialization time. +The BDS structure must be used if the Generic Device Driver (DRIVER.SYS) +is to used in the OEM's system. + +The MS-DOS 3.2 BIOS has extended the concept of logical drives. +There can now be more than one logical drive associated with each physical +drive. This logical drive mapping is achieved by using the Generic Device +Driver, DRIVER.SYS. +The extension of logical drives has prompted the idea of "Present Physical +Drive Owner". The Present Physical Drive Owner is the last logical drive +to have accessed a physical drive. This is an important concept because +when a reference is made to a logical drive that is NOT the Present +Physical Drive Owner, the BIOS displays the following message: + + Insert diskette for drive d: and strike + any key when ready + +where d: is the logical drive that was referenced. The Present Physical +Drive Owner is stored in the BDS for the particular physical drive. +Two new IOCTL calls have been introduced in connection with logical +drives. The new calls are GET/SET LOGICAL DRIVE MAP. These two IOCTL's +are important for applications that want to control the printing of the +message to swap disks. The message to swap disks will only be displayed +if the Present Physical Drive Owner is not the same as the logical drive +being referenced. Applications that want to control the printing of this +message (for example, full screen applications that want to display +the swap disk message in a dialogue box) would use these calls to get and +set the Present Physical Drive Owner. + + + + APPENDIX D + + +This material was taken from the MS-DOS 3.20 Programmer's Reference +Manual. It is intended be used with the MS-DOS 2.XX/3.XX Adaptation +Guide. + + + CHAPTER 2 + + MS-DOS DEVICE DRIVERS + + + +2.1 INTRODUCTION + +The IO.SYS file is composed of the "resident" device +drivers, and forms the MS-DOS BIOS. MS-DOS calls upon these +resident drivers to handle I/O requests initiated by +application programs. + +One of the most powerful features of MS-DOS is that it lets +you add new devices such as printers, plotters, or mouse +input devices without rewriting the BIOS. The MS-DOS BIOS +is "configurable;" that is, you can add and preempt new +drivers and existing drivers. You can also add non-resident +device drivers at boot time by using the "DEVICE =" entry in +the CONFIG.SYS file. In this section, these non-resident +drivers are referred to as "installable" to distinguish them +from drivers which, in the IO.SYS file, are considered as +the resident drivers. + +At boot time, a minimum of five resident device drivers must +be present. These drivers are in a linked list. The +"header" of each driver contains a DWORD pointer to the +next. The last driver in the chain has an end-of-list +marker of -1, -1 (all bits on). + +Each driver in the chain has two entry points--the strategy +entry point and the interrupt entry point. MS-DOS does not +take advantage of the two entry points. Instead, it first +calls the strategy routine, then immediately calls the +interrupt routine. + +The dual entry points are provided for future multitasking +versions of MS-DOS. In multitasking environments, I/O must +be asynchronous; to accomplish this, the strategy routine +will be called to (internally) queue a request and return +quickly. It is then the responsibility of the interrupt +routine to perform the I/O at interrupt time by getting +requests from the internal queue and processing them. When +a request is completed, the interrupt routine flags it as +"done." MS-DOS periodically scans the list of requests, +looking for those requests with done flags, and "wakes up" + MS-DOS DEVICE DRIVERS Page 2-2 + + +the process that is waiting for the completion of the +request. + +When requests are queued in this manner, it is no longer +sufficient to pass I/O information in registers, since many +requests may be pending at any one time. Therefore, the +MS-DOS device interface uses "packets" to pass request +information. These request packets vary in size and format +and are composed of two parts: + + + 1. The static request header section, which has the + same format for all requests. + + 2. A section that has information specific to the type + of request. + + +A driver is called with a pointer to a packet. In +multitasking versions, this packet will be linked into a +global chain of all pending I/O requests maintained by +MS-DOS. + +MS-DOS does not implement a global or local queue. Only one +request is pending at any one time. The strategy routine +must store the address of the packet at a fixed location, +and the interrupt routine, which is called immediately after +the strategy routine, should process the packet by +completing the request and returning. MS-DOS assumes that +the request is complete when the interrupt routine returns. + +To make a device driver that SYSINIT can install, you must +create a .BIN (core image) or .EXE format file that contains +the device driver header at the beginning of the file. The +link field should be initialized to -1 (SYSINIT fills it +in). Device drivers that are part of the BIOS should have +their headers point to the next device in the list and the +last header should be initialized to -1,-1. The BIOS must +be a .BIN (core image) format file. + +If you have a non-IBM compatible version of MS-DOS 2.x, you +can use installable device drivers that are in .EXE format. +On the IBM PC (or compatible) DOS 2.x versions, the .EXE +loader is located in COMMAND.COM, which is not present at +the time that MS-DOS is loading the installable devices. + + + +2.2 FORMAT OF A DEVICE DRIVER + +A device driver is a program segment responsible for +communication between DOS and the system hardware. It has a +special header at the beginning identifying it as a device +driver, defining its entry points, and describing its +various attributes. + MS-DOS DEVICE DRIVERS Page 2-3 + + + +------------------------------------------------------------ +| | +| Note | +| | +| For device drivers, the file must not use the ORG 100H | +| (like .COM files). Because it does not use the Program | +| Segment Prefix, the device driver is simply loaded; | +| therefore, the file must have an origin of zero (ORG 0 | +| or no ORG statement). | +| | +|__________________________________________________________| + +There are two kinds of device drivers: + + 1. Character device drivers + + 2. Block device drivers + +Character devices perform serial character I/O. Examples +are the console, communications port, and printer. These +devices have specific names (i.e., CON, AUX, CLOCK, etc.), +and programs may open channels (handles or FCBs) to send I/O +to them. + +Block devices are the "disk drives" on the system. They can +perform random I/O in structured pieces called blocks +(usually the physical sector size). These devices are not +named as the character devices are, and therefore cannot be +opened directly. Instead they have unit numbers and are +identified by drive letters such as A, B, and C. + +A single block device driver may be responsible for one or +more logically contiguous disk drives. For example, the +block device driver ALPHA may be responsible for drives A, +B, C, and D. This means that it has four units defined +(0-3). The position of the driver in the list of all +drivers determines which units correspond to which drive +letters. For example, if driver ALPHA is the first block +driver in the device list, and it defines 4 units (0-3), +then they will be A, B, C, and D. If BETA is the second +block driver and defines three units (0-2), then they will +be E, F, and G, and so on. The theoretical limit is 63, but +the device installation code does not allow the installation +of a device if it would result in a drive letter >`Z' (5AH). +All block device drivers present in the standard resident +BIOS are placed ahead of installable block-device drivers in +the list. + MS-DOS DEVICE DRIVERS Page 2-4 + + +------------------------------------------------------------ +| | +| Note | +| | +| Character devices cannot define multiple units | +| because they have only one name. | +| | +|__________________________________________________________| + + + +2.3 HOW TO CREATE A DEVICE DRIVER + +To create a device driver that MS-DOS can install, you must +create a binary file (.COM or .EXE format) with a device +header at its beginning. Device driver code should not +originate at 100H, but at 0. The device header contains a +link field (pointer to next device header) which should be +-1, unless there is more than one device driver in the file. + +You must also correctly set the attribute field and entry +points. The name field for a character device should +contain the name of that device. This name can be any legal +8-character filename. But if it is less than eight +characters, you should pad it out to eight by typing spaces +(20H). Note that device names do not include colons (:). +The fact that "CON" is the same as "CON:" is a property of +the default MS-DOS command interpreter (COMMAND.COM) and not +of the device driver or MS-DOS interface. All character +device names are handled in this way. + +MS-DOS always processes installable device drivers before +handling the default devices, so to install a new CON +device, simply name the device "CON". Remember to set the +standard input and standard output device bits in the +attribute word on a new CON device. The scan of the device +list stops on the first match, so the installable device +driver takes precedence. + +It is not possible to replace the "resident" disk block +device driver with an installable device driver as you would +replace other device drivers in the BIOS. Block drivers can +be used only for devices not supported directly by the +default disk drivers in IO.SYS. + +------------------------------------------------------------ +| | +| Note | +| | +| Because MS-DOS can install the driver anywhere in | +| memory, you must be careful when making far memory | +| references. You should not expect that your driver | +| will always be loaded in the same place every time. | +| | +|__________________________________________________________| + MS-DOS DEVICE DRIVERS Page 2-5 + + +2.3.1 Device Strategy Routine + + +This routine, which MS-DOS calls for each device driver +service request, is primarily responsible for queuing these +requests in the order in which they are to be processed by +the Device Interrupt Routine. Such queuing can be an +important performance feature in a multitasking environment, +or where asynchronous I/O is supported. Since MS-DOS does +not currently support these facilities, only one request +(usually a short one) can be serviced at a time. In the +coding examples in Section 2.12, each request is simply +stored in a single pointer area. + + + + +2.3.2 Device Interrupt Routine + + +This routine contains the code necessary for processing the +service request. It may interface to the hardware, or it +may use ROM BIOS calls. It usually consists of a series of +procedures, which handle the specific command codes to be +supported, as well as some exit and error-handling routines. +See the coding examples in Section 2.12. + + + + +2.4 INSTALLATION OF DEVICE DRIVERS + +MS-DOS allows new device drivers to be installed dynamically +at boot time. This is accomplished by IO.SYS initialization +code which reads and processes the CONFIG.SYS file. + +MS-DOS calls upon the device drivers to perform their +functions in the following manner: + + + 1. MS-DOS makes a far call to strategy entry. + + 2. MS-DOS passes device driver information in a + request header to the strategy routine. + + 3. MS-DOS then makes a far call to the interrupt + entry. + +This structure can be easily upgraded to support any future +multitasking environment. + MS-DOS DEVICE DRIVERS Page 2-6 + + +2.5 DEVICE HEADERS + +A device header, which is required at the beginning of every +device driver, looks like this: + + +--------------------------------------+ + | DWORD Pointer to next device | + | (Usually set to -1 if this driver | + | is the last or only driver in the | + | file) | + +--------------------------------------+ + | WORD Attributes | + +--------------------------------------+ + | WORD Pointer to device strategy | + | entry point | + +--------------------------------------+ + | WORD Pointer to device interrupt | + | entry point | + +--------------------------------------+ + | 8-BYTE Character device name field | + | Character devices set a device name. | + | For block devices the first byte is | + | the number of units. | + +--------------------------------------+ + + Figure 2.1. Sample Device Header + +Note that the device entry points are words. They must be +offsets from the same segment number used to point to this +table. For example, if XXX:YYY points to the start of this +table, then XXX:strategy and XXX:interrupt are the entry +points. + +The device header fields are described in the following +section. + + + +2.5.1 Pointer to Next Device Field + +This pointer is a double word field (offset followed by +segment). MS-DOS sets this field so that it points to the +next driver in the system list at the time the device driver +is loaded. Unless there is more than one device driver in +the file, it is important that you set this field to -1 +prior to loading (when it is on the disk as a file). If +there is more than one driver in the file, the first word of +the double word pointer should be the offset of the next +driver's device header. + MS-DOS DEVICE DRIVERS Page 2-7 + + + +------------------------------------------------------------ +| | +| Note | +| | +| If there is more than one device driver in the | +| file, the last driver in the file must have the pointer | +| to the next device header field set to -1. | +| | +|__________________________________________________________| + + + +2.5.2 Attribute Field + +The attribute field identifies the type of device this +driver is responsible for. In addition to distinguishing +between block and character devices, these bits give +selected character devices special treatment. (Note that if +a bit in the attribute word is defined only for one type of +device, a driver for the other type of device must set that +bit to 0.) + +For character devices: + + Bit Value Meaning + + 15 1 Character device + 14 1 Device supports + IOCTL control strings + 13 1 Device supports + Output Until Busy (OUB) + 12 RESERVED + 11 1 Device understands + OPEN/CLOSE + 10-7 RESERVED + 6 1 Device supports 3.2 functions + 5-4 RESERVED + 3 1 Device is CLOCK device + 2 1 Device is NUL device + 1 1 Device is console output (STO) + 0 1 Device is console input (STI) + +For Block Devices: + + Bit Value Meaning + + 15 0 Block device + 14 1 Device supports IOCTL control + strings + 13 1 Device determines the media by + examining the FATID byte. + 12 RESERVED + 11 1 Device understands + OPEN/CLOSE/Removable Media. + MS-DOS DEVICE DRIVERS Page 2-8 + + + 10-7 RESERVED + 6 1 Device supports 3.2 functions + 5-0 RESERVED + +For example, assume that you have a new device driver that +you want to use as the standard input and output. In +addition to installing the driver, you must tell MS-DOS that +you want this new driver to override the current standard +input and standard output (the CON device). You do this by +setting bits 0 and 1 to 1 (note that they are separate!). +Similarly, you could install a new CLOCK device by setting +the appropriate attribute. (Refer to Section 2.10, "The +CLOCK Device," in this chapter for more information.) +Although there is a NUL device attribute, you cannot +reassign the NUL device. This attribute exists so that +MS-DOS can determine whether the NUL device is being used. + +The IOCTL bit, bit 14, allows IOCTL functions to send and +receive data to character and block devices for their own +use. This allows them to set baud rate, stop bits, form +length, etc., instead of passing data over the device +channel as a normal read or write does. The interpretation +of the passed information is up to the device, but the +device must not treat this information as normal I/O. This +bit tells MS-DOS whether the device can handle control +strings via the IOCTL system call, Function 44H. + +If a driver cannot process control strings, it should set +this bit initially to 0. This tells MS-DOS to return an +error if an attempt is made (via Function 44H) to send or +receive control strings to this device. A device which can +process control strings should initialize the IOCTL bit to +1. For drivers of this type, MS-DOS makes calls to the +IOCTL INPUT and OUTPUT device functions to send and receive +IOCTL strings. + +For block devices, bit 13 affects the operation of the BUILD +BPB (BIOS Parameter Block) device call. If set, it requires +the first sector of the FAT to reside ALWAYS in the same +place. Bit 13 has a different meaning on character devices, +indicating that the device implements the OUTPUT UNTIL BUSY +device call. + +The OPEN/CLOSE/RM bit, bit 11, signals to MS-DOS 3.x, and +later versions, whether this driver supports additional +MS-DOS 3.0 functionality. But to support these old drivers, +it is necessary to detect them. Bit 11 was reserved in +MS-DOS 2.x, and is 0. All new devices, however, should +support the OPEN, CLOSE, and REMOVABLE MEDIA calls and set +this bit to 1. Since MS-DOS 2.x never makes these calls, +the driver will be backwardly compatible. + +The MS-DOS 3.2 bit, bit 6, signals whether the device +supports logical drive mapping via Function 440EH (Get +Logical Drive Map) and Function 440FH (Set Logical Drive + MS-DOS DEVICE DRIVERS Page 2-9 + + +Map). This bit also supports generic IOCTL functions via +Function 440C (Generic IOCTL for Handles) and Function 440D +(Generic IOCTL for Block Devices). + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +____________________________________________________________ +| C | I | O | | O | | | | | 3 | | | C | N | S | S | +| H | O | Y | | P | | | | | . | | | L | U | T | T | +| R | C | B | | N | | | | | 2 | | | K | L | O | I | +|___|___|___|___|___|___|__|__|__|___|__|__|___|___|___|___| + + Figure 2.? Attribute Word for character devices + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +____________________________________________________________ +| | I | F | | O | | | | | 3 | | | | | | | +| | O | A | | P | | | | | . | | | | | | | +| | C | T | | N | | | | | 2 | | | | | | | +|___|___|___|___|___|___|__|__|__|___|__|__|___|___|___|___| + + Figure 2.? Attribute Word for block devices + + + +2.5.3 Strategy And Interrupt Routines + +These two fields are the pointers to the entry points of the +strategy and interrupt routines. They are word values, so +they must be in the same segment as the device header. + + + +2.5.4 Name Field + +This is an 8-byte field that contains the name of a +character device or the number of units of a block device. +If it is a block device, the number of units can be put in +the first byte. This is optional, because MS-DOS fills in +this location with the value returned by the driver's INIT +code. Refer to Section 2.4, "Installation of Device +Drivers," for more information. + + + +2.6 REQUEST HEADER + +When MS-DOS calls a device driver to perform a function, it +passes a request header in ES:BX to the strategy entry +point. This is a fixed length header, followed by data +pertinent to the function being performed. Note that it is +the device driver's responsibility to preserve the machine +state (for example, save all registers including flags on +entry and restore them on exit). There is enough room on +the stack to do about 20 pushes, when MS-DOS calls either +the strategy or the interrupt routines. If more stack is + MS-DOS DEVICE DRIVERS Page 2-10 + + +needed, the driver should set up its own stack. + +The following figure illustrates a request header. + +REQUEST HEADER -> + +-----------------------------+ + | BYTE Length of record | + | Length in bytes of this | + | request header | + +-----------------------------+ + | BYTE Unit code | + | The subunit the operation | + | is for (minor device) | + | (no meaning on character | + | devices) | + +-----------------------------+ + | BYTE Command code | + +-----------------------------+ + | WORD Status | + +-----------------------------+ + | 8 BYTES Reserved | + | | + |-----------------------------| + + Figure 2.2. Request Header + +The request header fields are described below. + + + +2.6.1 Length of Record + +This field contains the length (in bytes) of the request +header. + + + +2.6.2 Unit Code Field + +The unit code field identifies which unit in your device +driver the request is for. For example, if your device +driver has 3 units defined, the possible values of the unit +code field would be 0, 1, and 2. + + + +2.6.3 Command Code Field + +The command code field in the request header can have the +following values: + + Command Function + Code + + 0 INIT + MS-DOS DEVICE DRIVERS Page 2-11 + + + 1 MEDIA CHECK (Block devices only) + 2 BUILD BPB (Block devices only) + 3 IOCTL INPUT (Only called if device has IOCTL) + 4 INPUT (read) + 5 NON-DESTRUCTIVE INPUT NO WAIT (Char devs only) + 6 INPUT STATUS (Char devs only) + 7 INPUT FLUSH (Char devs only) + 8 OUTPUT (write) + 9 OUTPUT (Write) with verify + 10 OUTPUT STATUS (Char devs only) + 11 OUTPUT FLUSH (Char devs only) + 12 IOCTL OUTPUT (Only called if device has IOCTL) + 13 DEVICE OPEN (Only called if OPEN/CLOSE/RM bit set) + 14 DEVICE CLOSE (Only called if OPEN/CLOSE/RM bit set) + 15 REMOVABLE MEDIA (Only called if OPEN/CLOSE/RM bit + set and device is block) + 16 OUTPUT UNTIL BUSY (Only called if bit 13 is set on + character devices) + 19 Generic IOCTL Request (Only called if bit 0 is set + for block devices) + 23 Get Drive Map (Only called if bit 6 is set on + block devices) + 24 Set Drive Map (Only called if bit 6 is set on + block devices) + +Unused command codes are reserved. + + + +2.6.4 Status Field + +The following figure illustrates the status field in the +request header. + + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ + | E | | B | D | | + | R | RESERVED | U | O | ERROR CODE (bit 15 on)| + | R | | S | N | | + | | | Y | E | | + +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ + +The status word is zero on entry and is set by the driver +interrupt routine on return. + +Bit 8 is the done bit. When set, it means the operation has +completed. The driver sets it to 1 when it exits. + +Bit 15 is the error bit. If it is set, the low 8 bits +indicate the error. The errors are: + + 0 Write protect violation + 1 Unknown unit + 2 Drive not ready + MS-DOS DEVICE DRIVERS Page 2-12 + + + 3 Unknown command + 4 CRC error + 5 Bad drive request structure length + 6 Seek error + 7 Unknown media + 8 Sector not found + 9 Printer out of paper + A Write fault + B Read fault + C General failure + D Reserved + E Reserved + F Invalid disk change + +Bit 9 is the busy bit, which is set only by status calls and +the removable media call. + + + +2.7 DEVICE DRIVER FUNCTIONS + +Device drivers may perform all or some of these nine general +functions. In some cases, these functions break down into +several command codes. Each is described in this section. + + + 1. INIT + + 2. MEDIA CHECK + + 3. BUILD BPB + + 4. READ or WRITE or WRITE TIL BUSY or Write with + Verify or Read IOCTL or Write IOCTL + + 5. NON DESTRUCTIVE READ NO WAIT + + 6. OPEN or CLOSE (3.x) + + 7. REMOVABLE MEDIA (3.x) + + 8. STATUS + + 9. FLUSH + + 10. Generic IOCTL + + 11. Get Logical Device + + 12. Set Logical Device + + +All strategy routines are called with ES:BX pointing to the +Request Header. The interrupt routines get the pointers to +the Request Header from the queue in which the strategy + MS-DOS DEVICE DRIVERS Page 2-13 + + +routines store them. The command code in the request header +tells the driver which function to perform and what data +follows the request header. + +------------------------------------------------------------ +| | +| Note | +| | +| All DWORD pointers are stored offset first, segment | +| second. | +| | +|__________________________________________________________| + + + +2.7.1 INIT + + +Command code = 0 + +INIT - ES:BX -> + +------------------------------------+ + | 13-BYTE Request header | + +------------------------------------+ + | BYTE Number of units | + +------------------------------------+ + | DWORD End Address | + +------------------------------------+ + | DWORD Pointer to BPB array | + | (Not set by character devices) | + +------------------------------------+ + | BYTE Block device number | + +------------------------------------+ + +One of the functions defined for each device driver is INIT. +This routine is called only once when the device is +installed. The INIT routine must return the END ADDRESS, +which is a DWORD pointer to the end of the resident portion +of the device driver. To save space you can use this +pointer method to delete init code that is needed only once. + +The driver sets the number of units, end address, and BPB +pointer. For installable block device drivers, the DWORD +pointer to BPB array now points to the first character after +the equal sign (=) on the line in CONFIG.SYS (the line that +caused this device to be loaded). This line is terminated +by a RETURN or a linefeed. This data is read-only and lets +the device driver scan the CONFIG.SYS line for arguments. + + device=\dev\vt52.sys /l + ^ + |_____BPB address points here + +Also, the block device driver defines the first unit and +assigns it to the drive number in the block device number + MS-DOS DEVICE DRIVERS Page 2-14 + + +field (for example, A=0). This field is also read-only. + +Installable character devices must return only the end +address parameter. This parameter is a pointer to the first +available byte of memory above the location of the driver +and which the driver may use to throw away initialization +code. + + +Block devices must return the following information: + + + 1. The number of units. MS-DOS uses this number to + determine logical device names. At the time of the + install call, if the current maximum logical device + letter is F, and the INIT routine returns 4 as the + number of units, these units will have logical + names G, H, I and J. This mapping is determined by + the position of the driver in the device list and + by the number of units on the device (stored in the + first byte of the device name field). + + + 2. A DWORD pointer to an array of one-word offsets + (pointers) to BPBs (BIOS Parameter Blocks). MS-DOS + creates an internal structure by using the BPBs + passed by the device driver. There must be one + entry in this array for each unit defined by the + device driver. In this way, if all units are the + same, all the pointers can point to the same BPB, + saving space. If the device driver defines two + units, the DWORD pointer points to the first of two + one-word offsets. In turn these offsets point to + BPBs. The format of the BPB is described later in + this chapter in Section 2.7.3, "BUILD BPB." + + Note that this array of one-word offsets must not + be above the free pointer set by the return, + because the device driver builds an internal DOS + structure, starting at the byte pointed to by the + free pointer. The defined sector size must be less + than or equal to the maximum sector size defined by + the resident device drivers (BIOS) during + initialization. If it isn't, the installation will + fail. + + 3. The media descriptor byte. This byte, which is the + last byte returned by INIT, means nothing to + MS-DOS, but is passed to devices so that they know + which parameters MS-DOS is currently using for a + particular drive unit. + + +Block devices may be either dumb or smart. A dumb device ____ _____ +defines a unit (and therefore an internal DOS structure) for + MS-DOS DEVICE DRIVERS Page 2-15 + + +each possible media-drive combination. For example, unit 0 += drive 0, single sided; unit 1 = drive 0, double sided. +For the "dumb device" approach, media descriptor bytes do +not mean anything. A smart device allows multiple media per +unit. In the case of a smart device, the BPB table returned +upon INIT must define sufficient space to accommodate the +largest possible media. Smart drivers use the media +descriptor byte to pass information about what media is +currently in a unit. + +For more information on the media descriptor byte, see +Section 2.8, "Media Descriptor Byte." + +------------------------------------------------------------ +| | +| Note | +| | +| If a file contains multiple device drivers, MS-DOS uses | +| the ending address returned by the last INIT called. | +| All the device drivers in a single file should return | +| the same ending address. The code to remain resident | +| for all the devices in a file should be grouped | +| together in low memory with the initialization code for | +| all devices following it. | +| | +|__________________________________________________________| + + + +2.7.2 MEDIA CHECK + + + +Command Code = 1 + +MEDIA CHECK - ES:BX -> + +------------------------------------+ + | 13-BYTE Request header | + +------------------------------------+ + | BYTE Media descriptor from BPB | + +------------------------------------+ + | BYTE Returned | + +------------------------------------+ + | Returned DWORD pointer to previous | + | Volume ID if bit 11 set and | + | Media Changed is returned | + +------------------------------------+ + + + +The MEDIA CHECK function is used with block devices only. +It is called when there is a pending drive access call other +than a file read or write, such as open, close, delete, or +rename. Its purpose is to determine whether the media in +the drive has been changed. If the driver can ensure that + MS-DOS DEVICE DRIVERS Page 2-16 + + +the media has not been changed (through a door-lock or other +interlock mechanism), MS-DOS does not need to reread the FAT +and invalidate in-memory buffers for each directory access. + +When such a disk access call to the DOS occurs (other than a +file read or write), the following sequence of events takes +place: + + + 1. The DOS converts the drive letter into the unit + number of a particular block device. + + 2. The device driver is then called to request a media + check on that subunit to see if the disk might have + been changed. MS-DOS passes the old media + descriptor byte. The driver returns: + + Media not changed...... (1) + Don't know if changed...(0) + Media changed...........(-1) + Error + + If the media has not been changed, MS-DOS proceeds + with the disk access. + + If the value returned is "Don't know," and if there + are any disk sectors that have been modified and + not yet written back to the disk for this unit, + MS-DOS assumes that the disk has not been changed + and proceeds. MS-DOS invalidates any other buffers + for the unit and does a BUILD BPB device call (see + step 3, below). + + If the media has been changed, MS-DOS invalidates + all buffers associated with this unit including + buffers with modified data that are waiting to be + written, and requests a new BIOS Parameter Block + via the BUILD BPB call (see step 3, below). + + + 3. Once the BPB has returned, MS-DOS corrects its + internal structure for the drive from the new BPB + and, after reading the directory and the FAT, + proceeds with the access. + + +Note that the previous media ID byte is passed to the device +driver. If the old media ID byte is the same as the new +one, the disk might have been changed and a new disk may be +in the drive. Therefore, all FAT, directory, and data +sectors that are buffered in memory for the unit are +considered invalid. + +If the driver has bit 11 of the device attribute word set to +1, and the driver returns -1, "Media Changed," it must set + MS-DOS DEVICE DRIVERS Page 2-17 + + +the DWORD pointer to the previous Volume ID field. If the +DOS determines that "Media Changed" is an error based on the +state of the DOS buffer cache, it generates a 0FH error on +behalf of the device. If the driver does not implement +Volume ID support, but has bit 11 set, it should set a +static pointer to the string, "NO NAME",0. + +It is not possible for a user to change a disk in less than +2 seconds. So when MEDIA CHECK occurs within 2 seconds of a +disk access, the driver reports "1," "Media not changed." +This action increases performance tremendously. + + +------------------------------------------------------------ +| | +| Note | +| | +| For MS-DOS versions before 3.2 if the media ID byte in | +| the returned BPB is the same as the previous media ID | +| byte, MS-DOS assumes that the format of the disk is the | +| same (even though the disk may have been changed) and | +| skips the step of updating its internal structure. All | +| BPBs, therefore, must have unique media bytes regardless| +| of FAT ID bytes. | +| | +|__________________________________________________________| + + + + +2.7.3 BUILD BPB (BIOS Parameter Block) + + +Command code = 2 + +BUILD BPB - ES:BX -> + +------------------------------------+ + | 13-BYTE Request header | + +------------------------------------+ + | BYTE Media descriptor from BPB | + +------------------------------------+ + | DWORD Transfer address | + | (Points to one sector worth of | + | scratch space or first sector | + | of FAT depending on the value | + | of Bit 13 in the device attribute | + | word.) | + +------------------------------------+ + | DWORD Pointer to BPB | + +------------------------------------+ + +The Build BPB function is used with block devices only. As +described in the MEDIA CHECK function, the BUILD BPB +function is called any time that a preceding MEDIA CHECK +call indicates that the disk has been, or might have been, + MS-DOS DEVICE DRIVERS Page 2-18 + + +changed. The device driver must return a pointer to a BPB. +This is different from the INIT call where the device driver +returns a pointer to an array of word offsets to BPBs. + +The BUILD BPB call gets a DWORD pointer to a one-sector +buffer. The contents of this buffer are determined by the +NON FAT ID bit (bit 13) in the attribute field. If the bit +is zero, the buffer contains the first sector of the first +FAT. The FAT ID byte is the first byte of this buffer, so +in this case, the driver must not alter the buffer. Note +that the location of the FAT must be the same as for all +possible media because the DOS must read this FAT sector +before the driver returns the BPB that the DOS called. If +the NON FAT ID bit is set, the pointer points to one sector +of scratch space (space which may be used for anything). +Refer to Section 2.8, "Media Descriptor Byte,"" and Section +2.9, "Format of a Media Descriptor Table," for information +on how to construct the BPB. + +MS-DOS 3.x includes additional support for devices that have +door-locks or some other means of telling when a disk has +been changed. Error 15, a new error that the device driver +can return, means "the disk has been changed when it +shouldn't have been." The user is prompted for the correct +disk using a Volume ID. The driver may generate this error +for READ or WRITE. The DOS may generate the error for MEDIA +CHECK if the driver reports media changed, and there are +buffers in the DOS buffer cache that need to be flushed to +the previous disk. + +For drivers that support this error, the BUILD BPB function +is a trigger that causes the driver to read a new Volume ID +from the disk. This action indicates that the disk has been +legally changed. The FORMAT or LABEL utility places a +Volume ID on the disk. This ID is simply an entry in the +root directory of the disk that has the Volume ID attribute. +The driver stores the Volume ID as an ASCIZ string. + +The requirement that the driver return a Volume ID does not +exclude some other Volume identifier scheme as long as the +scheme uses ASCIZ strings. A NUL (nonexistent or +unsupported) Volume ID is by convention the string: + + DB "NO NAME ",0 + + + + MS-DOS DEVICE DRIVERS Page 2-19 +2.7.4 READ or WRITE + + +Command codes = 3,4,8,9, 12, and 16 + +READ OR WRITE (Including IOCTL) or + OUTPUT UNTIL BUSY - ES:BX -> + +------------------------------------+ + | 13-BYTE Request header | + +------------------------------------+ + | BYTE Media descriptor from BPB | + +------------------------------------+ + | DWORD Transfer address | + +------------------------------------+ + | WORD Byte/sector count | + +------------------------------------+ + | WORD Starting sector number | + | (Ignored on character devices) | + +------------------------------------+ + | Returned DWORD pointer to requested| + | Volume ID if error 0FH | + +------------------------------------+ + + COMMAND CODE REQUEST + + 3 IOCTL READ + 4 READ (block or character) + 8 WRITE (block or character) + 9 WRITE WITH VERIFY + 12 IOCTL WRITE + 16 OUTPUT TIL BUSY (char devs only) + + +The driver must perform the READ or WRITE call depending on +which command code is set. Block devices read or write +sectors; character devices read or write bytes. + +When I/O completes, the device driver must set the status +word and report the number of sectors or bytes successfully +transferred, even if an error prevented the transfer from +being completed. Setting the error bit and error code alone _______ ___ _____ ___ ___ _____ ____ _____ +is not sufficient.__ ___ __________ + +In addition to setting the status word, the driver must set +the sector count to the actual number of sectors (or bytes) +transferred. No error check is performed on an IOCTL I/O +call. + +If the verify switch is on, the device driver is called with +command code 9 (WRITE WITH VERIFY). Your device driver is +then responsible for verifying the write. + +If the driver returns error code 0FH (Invalid disk change), +it must return a DWORD pointer to an ASCIZ string (which is +the correct Volume ID). The return of this error code +triggers the DOS to prompt the user to re-insert the disk. +The device driver should have read the Volume ID as a result +of the BUILD BPB function. + +Drivers may maintain a reference count of open files on the +disk by monitoring the OPEN and CLOSE functions. This +allows the driver to determine when to return error 0FH. If +there are no open files (reference count = 0), and the disk + MS-DOS DEVICE DRIVERS Page 2-20 + + +has been changed, the I/O is okay. If there are open files, +however, an 0FH error may exist. + +The OUTPUT UNTIL BUSY call is a speed optimization on +character devices only for print spoolers. The device +driver is expected to output all the characters possible +until the device returns busy. Under no circumstances +should the device driver block during this function. Note +that it is not an error if the device driver returns a +smaller number of bytes output than bytes requested. + +The OUTPUT UNTIL BUSY call allows spooler programs to take +advantage of the burst behavior of most printers. Many +printers have on-board RAM buffers which typically hold a +line or a fixed amount of characters. These buffers fill up +without making the printer "busy" between characters for a +relatively short time (or at least not for more than ten +instructions). The device driver can quickly output a line +of characters to the printer, which is then busy for a +comparatively longer time while it prints. This new device +call allows background spooling programs to use this burst +behavior efficiently. Rather than take the overhead of a +device driver call for each character, or risk getting stuck +in the device driver outputting a block of characters, this +call allows a burst of characters to be output without the +device driver having to wait until the device is ready. + +If the MS-DOS 3.2 bit is set, then MS-DOS can configure the +number of retries (allowed by the device driver) that the +printer can make before returning "busy." + +THE FOLLOWING APPLIES TO BLOCK DEVICE DRIVERS:___ _________ _______ __ _____ ______ _______ + +Under certain circumstances, the device driver may request +that the BIOS perform a write operation of 64K bytes, which +seems to be a "wrap around" of the transfer address in the +BIOS I/O packet. This request arises due to an optimization +added to the write code in MS-DOS. It will only manifest +itself on user writes within a sector size of 64K bytes to +files "growing" past the current EOF. The BIOS may ignore ___ ____ ___ ______ +the balance of the write that "wraps around," if it so___ _______ __ ___ _____ ____ ______ ________ __ __ __ +chooses. For example, a write of 10000H bytes worth of________ +sectors with a transfer address of XXX:1 could ignore the +last two bytes. A user program can never request an I/O of +more than FFFFH bytes and cannot wrap around (even to 0) in +the transfer segment. Therefore, in this case the BIOS +ignores the last two bytes. + +MS-DOS maintains two FATs. If the DOS has problems reading +the first, it automatically tries the second before +reporting the error. The BIOS is responsible for all +retries. + +Although the COMMAND.COM handler does no automatic retries, +there are applications that have their own Interrupt 24H + MS-DOS DEVICE DRIVERS Page 2-21 + + +handlers. These handles do automatic retries on certain +types of Interrupt 24H errors before reporting them. + + + + +2.7.5 NON DESTRUCTIVE READ NO WAIT + + +Command code = 5 + +NON DESTRUCTIVE READ NO WAIT - ES:BX -> + +------------------------------------+ + | 13-BYTE Request header | + +------------------------------------+ + | BYTE read from device | + +------------------------------------+ + +This call lets MS-DOS look ahead one input character. The +device sets the done bit in the status word. + +If the character device returns busy bit = 0, characters are +in the buffer and the next character that would be read is +returned. This character is not removed from the input ___ +buffer (hence the term "Non Destructive Read"). If the +character device returns busy bit = 1, there are no +characters in the buffer. + + + +2.7.6 OPEN or CLOSE + + +Command codes = 13 and 14 + +OPEN or CLOSE - ES:BX -> + +------------------------------------+ + | 13-BYTE Static request header | + +------------------------------------+ + +These functions are called by MS-DOS 3.x only if the device +driver sets the OPEN/CLOSE/RM attribute bit in the device +header. They are designed to inform the device about its +current file activity. On block devices, these functions +can manage local buffering, and the device can keep a +reference count. + +Every OPEN causes the device to increment the count, every +CLOSE to decrement. When the count goes to zero no open +files are on the device. Also, the device should flush any +buffers that it may have used in case the media has been +changed. + +Block devices can have problems with this mechanism because +programs that use FCB calls can open files without closing + MS-DOS DEVICE DRIVERS Page 2-22 + + +them. Therefore, when the media has been changed and the +BUILD BPB call has been made to the device, you should reset +the count to zero without flushing the buffers. + +These calls are more useful on character devices. For +example, the device could use the OPEN call to send a device +initialization string. For example, this string might set a +printer's default characteristics for font and page size. +Using IOCTL to set these pre- and post-strings provides a +flexible mechanism of serial I/O device stream control. A +driver could also use the reference count mechanism to +detect a simultaneous access error. You may not want to +allow more than one OPEN on a device at any given time, +since, in this case, a second OPEN would result in an error. + +Note that since all processes have access to stdin, stdout, +stderr, stdaux, and stdprn (handles 0,1,2,3,4), the CON, +AUX, and PRN devices are always open. ______ + + + +2.7.7 REMOVABLE MEDIA + + +Command code = 15 + +REMOVABLE MEDIA - ES:BX -> + +------------------------------------+ + | 13-BYTE Static request header | + +------------------------------------+ + +This function is called by MS-DOS 3.x only if the device +driver sets the OPEN/CLOSE/RM attribute bit in the device +header. Only a subfunction of the IOCTL system call can +issue this call to block devices. Sometimes it is necessary +for a utility to know whether it is using a non-removable +media drive (a hard disk), or a removable media drive (a +floppy). For example, the FORMAT utility prints different +prompts depending on the media. + +The information returns in the busy bit of the status word. +If the busy bit is 1, the media is non-removable, and if the +busy bit is 0, the media is removable. Note that the device +driver does not check the error bit; it just assumes that +this call always succeeds. + + + + MS-DOS DEVICE DRIVERS Page 2-23 +2.7.8 STATUS + + +Command codes = 6 and 10 + +STATUS Calls ES:BX -> + +------------------------------------+ + | 13-BYTE request header | + +------------------------------------+ + +This call returns information to the DOS to let it know if +data is waiting for input or output. All the driver must do +is set the status word and the busy bit as follows: + + For output on character devices: If the driver ___ ______ __ _________ _______ + sets bit 9 to 1 on return, it informs the DOS that + a write request (if made) would wait for completion + of a current request. If bit 9 is 0, there is no + current request and a write request (if made) would + start immediately. + + For input on character devices with a buffer: If ___ _____ __ _________ _______ ____ _ ______ + bit 9 equals 1 this implies that the buffer is + empty and that a read request (if made) would go to + the physical device. If bit 9 is 0 on return, + characters are in the device buffer and a read + request would start immediately. A return of 0 + implies that you have typed something. MS-DOS + assumes that all character devices have an input + type-ahead buffer; devices that do not should + always return busy = 0 so that the DOS does not + wait for you to put something into a non-existent + buffer. + + + + +2.7.9 FLUSH + + +Command codes = 7 and 11 + +FLUSH Calls - ES:BX -> + +------------------------------------+ + | 13-BYTE request header | + +------------------------------------+ + +The FLUSH call tells the driver to flush (terminate) all +pending requests. This call is used to flush the input +queue on character devices. The device driver performs the +flush function, sets the status word, and returns. + + + + MS-DOS DEVICE DRIVERS Page 2-24 +2.7.10 Generic IOCTL Request + + +Command code = 19 + +ES:BX --> +----------------------------------+ + | 13-BYTE Static Request Header | + +----------------------------------+ + | BYTE Category (Major) Code | + +----------------------------------+ + | BYTE Function (Minor) Code | + +----------------------------------+ + | WORD (SI) contents | + +----------------------------------+ + | WORD (DI) contents | + +----------------------------------+ + | DWORD pointer to data buffer | + +----------------------------------+ + +This function provides a generic, expandable IOCTL facility +that replaces and makes the Read IOCTL and Write IOCTL +device driver functions obsolete. The MS-DOS 2.0 IOCTL +functions remain to support existing uses of the IOCTL +system call (subfunctions 2, 3, 4 and 5), but new device +drivers should use this generic MS-DOS IOCTL facility. + +The generic IOCTL function contains both a category and +function code. The DOS examines the category field in order +to intercept and obey device commands that are actually +serviced by the DOS code; all other command categories are +forwarded to the device driver for servicing. + +For more information on these category and function codes, +refer to Functions 440CH (Generic IOCTL for handles) and +Function 440DH (Generic IOCTL for block devices) in Chapter +1, "System Calls." + + + +2.7.11 Get/Set Logical Drive Map + + +Command code = 23 (Get) or 24 (Set) + + +-------------------------------------------+ + | 13-byte Static Request Header | + +-------------------------------------------+ + | BYTE Input (unit code) | + +-------------------------------------------+ + | BYTE Output (last device referenced) | + +-------------------------------------------+ + | BYTE Command code | + +-------------------------------------------+ + | WORD Status | + +-------------------------------------------+ + | DWORD Reserved | + +-------------------------------------------+ + +This function is only called by MS-DOS if the device driver +sets the DOS 3.2 attribute bit in the device header. The +call is only issued to block devices by a subfunction of the +IOCTL system call. The logical drive is passed in the UNIT +field of the header to the device driver, which returns the + MS-DOS DEVICE DRIVERS Page 2-25 + + +current logical drive that is mapped on the physical drive +in the UNIT field of the header. + + + +2.8 MEDIA DESCRIPTOR BYTE + +In MS-DOS, the media descriptor byte informs the DOS that a +different type of media is present. The media descriptor +byte can be any value between 0 and FFH. It does not have +to be the same as the FAT ID byte. The FAT ID byte, which +is the first byte of the FAT, was used in MS-DOS 1.00 to +distinguish between different types of disk media. This +byte may also be used under 2.x and 3.x disk device drivers. +However, FAT ID bytes have significance only for block +device drivers where the NON FAT ID bit is not set (0). + +Values of the media descriptor byte or the FAT ID byte have +no significance to MS-DOS. They are passed directly to the +device driver so that programs can determine the media type. + + + +2.9 FORMAT OF A MEDIA DESCRIPTOR TABLE + +The MS-DOS file system uses a linked list of pointers (one +for each cluster or allocation unit) called the File +Allocation Table (FAT). Unused clusters are represented by +zero and end-of-file by FFF (or FFFF on units with 16-bit +FAT entries). No valid entry should ever point to a zero +entry, but if one does, the first FAT entry (which would be +pointed to by a zero entry) should be reserved and set to +end-of-chain. Eventually, several end-of-chain values can +be defined ([F]FF8-[F]FFF), and used to distinguish +different media types. + +A preferrable technique is to write a complete media +descriptor table in the boot sector and use it for media +identification. To ensure backward compatibility for +systems whose drivers do not set the NON FAT ID bit +(including the IBM PC implementation), it is necessary to +write the FAT ID bytes during the FORMAT process. + +In the future to allow more flexibile support for many +different disk formats, you should keep the information +relating to the BPB for a particular media in the boot +sector. Figure 2.3 shows the format of such a boot sector. + MS-DOS DEVICE DRIVERS Page 2-26 + + + + +------------------------------------+ + | 3 BYTE Near JUMP to boot code | + +------------------------------------+ + | 8 BYTES OEM name and version | + ---+------------------------------------+--- + B | WORD Bytes per sector | + P +------------------------------------+ + B | BYTE Sectors per allocation unit | + +------------------------------------+ + | | WORD Reserved sectors | + V +------------------------------------+ + | BYTE Number of FATs | + +------------------------------------+ + | WORD Number of root dir entries | + +------------------------------------+ + | WORD Number of sectors in logical | + ^ | image | + | +------------------------------------+ + B | BYTE Media descriptor | + P +------------------------------------+ + B | WORD Number of sectors per FAT | + ---+------------------------------------+--- + | WORD Sectors per track | + +------------------------------------+ + | WORD Number of heads | + +------------------------------------+ + | WORD Number of hidden sectors | + +------------------------------------+ + | WORD High order number of hidden | + | sectors | + +------------------------------------+ + | DWORD Number of logical sectors | + +------------------------------------+ + + Figure 2.3. Format of Boot Sector + +Although MS-DOS does not use the five fields that follow the +BPB, they may be used by a device driver to help it +understand the media. + +The "Sectors per track" and "Number of heads" fields are +useful for supporting different media which may have the +same logical layout, but a different physical layout (e.g., +40 track double-sided versus 80 track single-sided). +"Sectors per track" tells the device driver how the logical +disk format is laid out on the physical disk. + +The "Number of hidden sectors" and the "High order number of +hidden sectors" fields may be used to suport +drive-partitioning schemes. + +The "Number of logical sectors" field is not currently used +but will tell the device driver how many sectors to reserve +if the "Number of sectors in logical image" field is zero. + MS-DOS DEVICE DRIVERS Page 2-27 + + +(This is intended for supporting drives that access more +than 32 megabytes.) + +NON FAT ID format drivers should use the following procedure +to determine media type: + + + 1. Read the boot sector of the drive into the 1-sector + scratch space pointed to by the DWORD Transfer + address. + + 2. Determine whether the first byte of the boot sector + is either E9H (the first byte of a 3-byte NEAR or + 2-byte short jump) or EBH (the first byte of a + 2-byte jump followed by a NOP). If it is, return a + pointer to a BPB beginning at offset 3. + + + 3. If the boot sector does not have a BPB table, it is + probably a disk formatted under a 1.x version of + MS-DOS. Therefore, it probably uses a FAT ID byte + for determining media. + + As an option, the driver may attempt to read the + first sector of the FAT into the 1-sector scratch + space and then read the first byte to determine the + media type. Return a pointer to a hard-coded BPB. + + + + +2.10 THE CLOCK DEVICE + +MS-DOS assumes that some sort of clock is available in the +system. This clock may be either a CMOS real-time clock or +an interval timer which the user initializes at boot time. +The CLOCK device defines and performs functions like any +other character device except that the DOS identifies it by +a bit in the attribute word. Consequently this device may +take any name. The IBM version uses "$CLOCK" to avoid +conflict with existing files named "CLOCK." + +The CLOCK device is unique because MS-DOS reads or writes a +6-byte sequence that encodes the date and time. A write to +this device sets the date and time, and a read gets the date +and time. + +Figure 2.4 illustrates the binary time format which the +CLOCK device uses: + + + MS-DOS DEVICE DRIVERS Page 2-28 + + byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 ++--------+--------+---------+--------+--------+---------+ +| | | | | | | +|days since 1-1-80| minutes | hours | sec/100| seconds | +|low byte|hi byte | | | | | ++--------+--------+---------+--------+--------+---------+ + + Figure 2.4. CLOCK Device Format + + + +2.11 ANATOMY OF A DEVICE CALL + +The following steps illustrate what happens when MS-DOS +calls on a block device driver to perform a WRITE request: + + + 1. MS-DOS writes a request packet in a reserved area + of memory. + + + 2. It then calls the block device driver strategy + entry point. + + + 3. The device driver saves the ES and BX registers + (ES:BX points to the request packet) and does a FAR + return. + + + 4. MS-DOS calls the interrupt entry point. + + + 5. The device driver retrieves the pointer to the + request packet and reads the command code (offset + 2) to determine that this is a write request. The + device driver converts the command code for an + index into a dispatch table and passes control to + the disk write routine. + + + 6. The device driver reads the unit code (offset 1) to + determine which disk drive it should write to. + + + 7. Since the command is a disk write, the device + driver must get the transfer address (offset 14), + the sector count (offset 18), and the start sector + (offset 20) in the request packet. + + + 8. The device driver translates the first logical + sector number into a track, head, and sector + number. + + MS-DOS DEVICE DRIVERS Page 2-29 + + + 9. The device driver writes the specified number of + sectors, starting at the beginning sector on the + drive defined by the unit code (the subunit defined + by this device driver), and transfers data from the + address indicated in the request packet. Note that + this may involve multiple write commands to the + disk controller. + + + 10. After the transfer is complete, the device driver + must report the status of the request to MS-DOS by + setting the done bit in the status word (offset 3 + in the request packet). It reports the number of + sectors actually transferred in the sector count + area of the request packet. + + + 11. If an error occurs, the driver sets the done bit + and the error bit in the status word and fills in + the error code in the lower half of the status + word. The number of sectors actually transferred + must be written in the request header. It is not + sufficient just to set the error bit of the status + word. + + + 12. Finally, the device driver does a FAR return to + MS-DOS. + + +The device drivers should preserve the state of MS-DOS, +including all registers (and flags). In particular, the +direction flag and interrupt enable bits are critical. When +the interrupt entry point in the device driver is called, +MS-DOS has room for about 40 to 50 bytes on its internal +stack. Your device driver should switch to a local stack if +it uses extensive stack operations. + APPENDIX E + + + MSDOS 2.25 Device Driver Interface Extension. + + + MSDOS 2.25 is designed so as to be able to run with + CONSOLE DEVICE DRIVERS FROM PREVIOUS VERSIONS. If this is + the case then no interim character processing can be done, + and all character composition must be handled directly by + the console device driver. + + The MSDOS 2.25 BIOS interface (IO.SYS) has the + following differences from the standard MSDOS 2.11 BIOS. + These changes are extensions to the CON (Console) Device + driver for hardware which will be utilizing Interim + Character support. Consult the MSDOS Adapatation Guide + for overall description of device driver design and + funtionality + + 1) On the INPUT and NON-DESTRUCTIVE INPUT calls to the + device driver (DD) the DD must check bit 0 of the byte at + offset 14 in the request packet. If the bit is 0 then it + should return only final characters, if the bit is 1 then + the device driver should return interim as well as final + characters to the dos. + + Also on INPUT, if the request is for more than ONE byte + then the DD should return ONLY final characters, no matter + what the state of bit 0 in the byte at offset 14. + + 2) On return from INPUT, NON-DESTRUCTIVE INPUT and + INPUT STATUS calls, the device driver should return to the + dos with bit 10 of the status word SET if the character + read, or the character available is an interim character, or + the bit RESET if the character is a final character. (Pre + 2.25 DD's always return with this bit reset). If more than + one character is read on an INPUT call then bit 10 should be + RESET as all the characters returned should be final + characters (see above). + + 3) On Console WRITE function the device driver should + check bit 0 of the byte at offset 14 in the request packet. + If the bit is reset then the character should be output as a + regular character by printing the character and advancing + the cursor to the next position. If the bit is SET then the + character is an interim character and should be treated by + the device driver display routine accordingly. In most cases + the character should be displayed without advancing the + cursor to the next character position. When using interim 16 + bit characters that are output a byte at a time, then the + routine should handle this correctly, displaying the 16 bit + interim and not advancing the cursor to the next character + position. + + Special considerations / requirements. + + If a console device driver is going to return interim + characters then the device driver MUST be able to handle the + extension made to character WRITE (described above in 3). + + Device drivers should be able to support requests for + final / interim characters in any order. Application + programs may at any time change the way they want + characters, and device drivers should be capable of changing + without any other indication than the DD request itself. + + Device drivers should be capable of handling + composition somehow for those applications that do not do it + themselves. + + The keyboard typeahead buffer should be kept at the key + level, without further interpretation. All processing of + interims in case of an input request for a final character + is issued (and there are interims in the buffer that have to + be composed to obtain a final character), should be done at + the time the request is done to the device driver. + + + +Sample Device Driver for DOS 2.25 Interim Character Support +WARNING!! Not Assembleable. This code must be modified for +the OEM's own hardware and firmware. + + +PAGE + +CODE SEGMENT BYTE + + ASSUME CS:CODE,DS:NOTHING,ES:NOTHING +;---------------------------------------------------------------- +; +; C O N - CONSOLE DEVICE DRIVER +; + DW -1,-1 + DW 1000000000010011B ; CON IN AND CON OUT + Special bit + DW STRATEGY + DW ENTRY + DB 'CON ' + + +InterH db 0 ; Interim character flag +ALTAH DB 0 ; Special key handling + + +;---------------------------------------------------------------- +; +; COMMAND JUMP TABLES +CONTBL: + DW CON$INIT + DW EXIT + DW EXIT + DW CMDERR + DW CON$READ + DW CON$RDND + DW EXIT + DW CON$FLSH + DW CON$WRIT + DW CON$WRIT + DW EXIT + DW EXIT + + +PAGE +;---------------------------------------------------------------- +; +; Device entry point +; +CMDLEN = 0 ;LENGTH OF THIS COMMAND +UNIT = 1 ;SUB UNIT SPECIFIER +CMD = 2 ;COMMAND CODE +STATUS = 3 ;STATUS +MEDIA = 13 ;MEDIA DESCRIPTOR +TRANS = 14 ;TRANSFER ADDRESS +COUNT = 18 ;COUNT OF BLOCKS OR CHARACTERS +START = 20 ;FIRST BLOCK TO TRANSFER + +BRKADR = Oem_Brk ; Break Vector Address +CHROUT = 29H ; fast con int + + +PAGE +;---------------------------------------------------------------- +; +; Entry Procedures +; + +PTRSAV DD 0 + +STRATP PROC FAR + +STRATEGY: + MOV WORD PTR CS:[PTRSAV],BX + MOV WORD PTR CS:[PTRSAV+2],ES + RET + +STRATP ENDP + +ENTRY: + PUSH SI + PUSH AX + PUSH CX + PUSH DX + PUSH DI + PUSH BP + PUSH DS + PUSH ES + PUSH BX + + LDS BX,CS:[PTRSAV] ; DS:BX points to IO packet + + mov cx,word ptr ds:[bx].count ; CX = count + mov dl,byte ptr ds:[bx].media ; DL = input type flag + mov al,byte ptr ds:[bx].cmd ; AL = command code + cbw + MOV SI,OFFSET CONTBL ; command table + ADD SI,AX + ADD SI,AX + CMP AL,11 + JA CMDERR ; command code out of range + + LES DI,DWORD PTR DS:[BX].TRANS ; transfer address + PUSH CS + POP DS + ASSUME DS:CODE + + JMP WORD PTR [SI] ; GO DO COMMAND + + +PAGE +;---------------------------------------------------------------- +; +; EXIT - ALL ROUTINES RETURN THROUGH THIS PATH +; + +CMDERR: + MOV AL,3 ; Unknown Command Error +ERR$EXIT: + mov ah,10000001b ; Mark Error Return + jmp short err1 + +BUS$EXIT: + mov ah,00000011b ; Device Busy Exit + jmp short err1 + +HanExit: + mov [InterH],0 ; reset interim flag + mov ah,00000101b ; Bit 10 Set for interim chars + jmp short err1 + + +EXITP PROC FAR + +EXIT: MOV AH,00000001B +ERR1: LDS BX,CS:[PTRSAV] + MOV WORD PTR [BX].STATUS,AX ; Mark Operation Complete + + POP BX + POP ES + POP DS + POP BP + POP DI + POP DX + POP CX + POP AX + POP SI + RET ; RESTORE REGS AND RETURN +EXITP ENDP + + +PAGE +;---------------------------------------------------------------- +; +; BREAK KEY HANDLING +; +BREAK: + MOV CS:ALTAH,3 ; INDICATE BREAK KEY SET + IRET + + +;---------------------------------------------------------------- +; +; CHROUT - WRITE OUT CHAR IN AL USING CURRENT ATTRIBUTE +; +; CALLED VIA INT 29H +; + +OUTCHR: + INT OEM_Char_Output + RET + + +PAGE +;---------------------------------------------------------------- +; +; INPUT SINGLE CHAR INTO AL +; + +ChrIn: + xor ax,ax + xchg al,ALTAH ; Get Character & Zero ALTAH + or al,al + jnz sj3 + mov ah,Request_Interim ; assume interim char input + or dl,dl ; Interim chars wanted? + jnz sj0 + mov ah,Request_Char ; regular whole char input +sj0: + int OEM_Kybd_Input ; Get character + or ax,ax ; Check for non-key after BREAK + jz ChrIn + or al,al ; Special Case? + jnz ChkInter + mov ALTAH,ah ; Save Special Key +sj3: + mov [InterH],0 ; reset interim flag + ret + +ChkInter: + cmp ah,Hangeul_Interim ; a Hangeul interim? + jne sj3 + mov [InterH],1 ; yes flag it + ret + +PAGE +;---------------------------------------------------------------- +; +; CONSOLE READ ROUTINE +; +; Input: +; CX = transfer count +; DL = input type flag (0 = whole chars, 1 = interim allowed) +; ES:DI = transfer addess +; + +CON$READ: + JCXZ CON$EXIT +CON$LOOP: + CALL CHRIN ; GET CHAR IN AL + STOSB ; STORE CHAR AT ES:DI + LOOP CON$LOOP +CON$EXIT: + cmp [InterH],1 ; An Intermidiate Char? + jne ExVec ; no, regulear exit + JMP HanExit ; yes, reset flag and exit new way + + +PAGE +;---------------------------------------------------------------- +; +; KEYBOARD FLUSH ROUTINE +; + +CON$FLSH: + MOV [ALTAH],0 ; Clear out holding buffer + mov [InterH],0 + mov ah,Flush_Buffer + int OEM_Kybd_Input + JMP EXIT + +PAGE +;---------------------------------------------------------------- +; +; KEYBOARD NON DESTRUCTIVE READ, NO WAIT +; Input: +; DL = input type flag (0 = whole chars, 1 = interim allowed) +; + +EXVEC: JMP EXIT +CONBUS: JMP BUS$EXIT + +CON$RDND: + MOV AL,[ALTAH] + OR AL,AL + JNZ sj6 + MOV AH,Request_Interim_Status ;Assume interim allowed + or dl,dl ; check interim flag + jnz sj4 + mov ah,Requst_Std_Status ; regular status wanted +sj4: + INT OEM_Kybd_Input ; Get status + JZ CONBUS + OR AX,AX + JNZ sj6 ; CHECK FOR NULL AFTER BREAK + MOV AH,Request_Char + INT OEM_Kybd_Input ; READ THE NULL + JMP short CON$RDND ; AND GET A REAL STATUS +sj6: + MOV [InterH],0 ; not interim +sj7: + LDS BX,[PTRSAV] + MOV [BX].MEDIA,AL ; return the char to dos + cmp [InterH],0 + je EXVEC + jmp HanExit +sj8: + cmp ah,Interim_Char ; a Hangeul interim? + jne sj6 + mov [InterH],1 + jmp short sj7 + + + + +PAGE +;---------------------------------------------------------------- +; +; CONSOLE WRITE ROUTINE +; + +CON$WRIT: + JCXZ EXVEC + cmp dl,01h ; write and not ad cursor? + je CON$LP2 +CON$LP: MOV AL,ES:[DI] ; GET CHAR + INC DI + MOV AH,Output_Char + INT CHROUT ; OUTPUT CHAR + LOOP CON$LP ; REPEAT UNTIL ALL THROUGH + JMP EXIT + +CON$LP2: ; write but do not advance cursor + MOV AL,ES:[DI] ; GET CHAR + INC DI + MOV AH,Output_No_Advance + INT CHROUT + LOOP CON$LP2 ; REPEAT UNTIL ALL THROUGH + JMP EXIT + + +PAGE +;---------------------------------------------------------------- +; +; Initialization Code +; + +CON$INIT: + XOR BX,BX + MOV DS,BX + MOV BX,BRKADR + MOV WORD PTR [BX],OFFSET BREAK + MOV WORD PTR [BX+2],CS + + MOV BX,CHROUT*4 + MOV WORD PTR [BX],OFFSET OUTCHR + MOV WORD PTR [BX+2],CS + + LDS BX,CS:[PTRSAV] + MOV WORD PTR [BX].TRANS,OFFSET CON$INIT ; SET BREAK ADDRESS + MOV [BX].TRANS+2,CS + JMP EXIT + +CODE ENDS + END + + + APPENDIX F + + + + MSDOS 2.25 Application Level Interface Extension + + + + 1) System call 63H, get_lead_tbl. + + This call takes an argument in register AL. This + argument determines what function will this call execute. + Valid values for the function code are 0, 1 and 2. + + If AL = 0, then the call returns in DS:SI a pointer to + a table containing the lead byte ranges for the 16 bit + alphabet in question. The table consists of byte pairs that + are the boundaries for the lead bytes (both values + inclusive). The end of the table is marked by two zero byte + entries. + + Example, for japanese kanji the table would look like + + db 81H,9FH + db 0E0h,0FCh + db 0,0 + + Note that the values should be read as byte values not + as word values since otherwise the ranges would be + transposed due to the byte ordering in the 8086/88. + + This table is empty in the regular version of the dos + (as there are no 16 bit characters). The table if obtained + would point to a pair of zero bytes. + + If AL = 1 then the call will set (or reset) the interim + console flag in the dos depending on the value in DL. If DL + = 1, then the interim flag will be SET, and certain console + system calls will return interim characters if these are + available. If DL = 0 then the interim flag is RESET and only + final characters will be returned. The default value of the + flag is RESET. All application programs start with the flag + RESET. The flag is allways restored to the parents setting + when an application terminates. + + If AL = 2 then the dos will return in DL the current + value of the console interim flag (0 if RESET, 1 if SET). + + If an invalid code is used the call will reurn with + carry set and error code 0 (error_invalid_function). + + IMPORTANT NOTE: This system call unlike all other + system calls make NO GUARANTEE to preserve ANY registers + other than SS:SP upon return. So care should be taken to + save all relevant registers before issuing the call. It is + advisable that an application either copy the table to its + + + + + + + private data area or save the pointer to the table at + initialization time. This should save considerable execution + time as there is no need to reissue the call everytime a + check for 16 bit characters is necessary, and consequently + there is no need to save any registers before issuing the + call. + + 2) Console i/o system calls. + + Some console i/o system calls are capable of returning + interim character information to application programs. Only + those applications that have enabled the feature through the + 63H call (function 1) will receive interim characters on + these system calls, otherwise the dos will never return + interim characters and the system calls will work as in + previous versions of 2.00. + + * Call 01H, Read & Echo. + + This call never returns interim characters no matter + what mode the console is on. Composition if any will take + place at the cursor. It will return when the first byte of + the final character is obtained. + + + * Call 06H, Direct Console i/o. + + Always returns final characters, never interims. Only + returns character available when a final character is + available, not when interims are available. Composition if + any is handled as in call 01H. + + * Call 07H, Direct Console Input. + + Returns interim characters if one is available and the + console mode has been set to interim through the 63H call. + Interim characters are returned with the zero flag SET, + final characters have the flag RESET. In non interim support + (the default) the zero flag value is undefined. + + * Call 08H, Read Keyboard. + + Same as system call 07H. + + * Call 0AH, Buffered Keyboard input. + + Always returns a string of final characters, + composition if any, is handled by the dos. + + * Call 0BH, Check Keyboard Status. + + This call supports interim characters if the console + has been placed in interim mode through the ioctl call. If a + character is available (AL = 0FFH) then the zero flag will + + + + + + + be SET if the character is an interim, or RESET if the + character is a final character. The zero flag is undefined + if either there is no character available, or the console is + not in interim mode. + + * Call 0CH, Flush Buffer, Read Keyboard. + + This call will flush the type-ahead buffer and execute + the specified console i/o call. The con i/o call will work + as described above for each specific case. + + * Call 3FH, Xenix Read. + + This call always returns final characters, no matter + what the state of the dos. This call when directed to the + console it ends up in the buffered console input code, and + so it will act as that call (0AH) when used to read from the + console. + + APPENDIX G + + +This file is part of what was formerly supplied with MS-DOS 2.11 +as SPECIAL.DOC. It has information about undocumented COMMAND.COM +switches and the version dependent system call (GET_DPB) which +OEM's may use when writing format. + +The remaining portions of this file have been incorporated into +printed MS-DOS documentation. + + +COMMAND invocation + +COMMAND [[:]] [] [/D] [/P] [/C ] [/E:nnnn] + + /P If present COMMAND will be permanent, otherwise + this is a transient command. + + /D If present COMMAND will not prompt for DATE and + TIME when it comes up. + + d: Specifies device where command will look for + COMMAND.COM current default drive if absent. + + Specifies a directory on device d: root + directory if absent. + + Name of the CTTY device. \DEV\CON if absent + and command is permanent. The \DEV\ may be left + off if AVAILDEV is TRUE (see sysinit doc). + + /C If present /C must be the last switch. + This causes COMMAND to try to execute the string + as if the user had typed it at the standard input. + COMMAND executes this single command string and + then exits. If the /P switch is present it is + ignored (can't have a single command, permanent + COMMAND). NOTE: ALL of the text on the command + line after the /C is just passed on. It is not + processed for more arguments, this is why /C must + be last. + + /E:nnnn Set the environment size to nnnn (specified in + decimal bytes). The environment size can be between + 128 bytes and 32768 bytes. NOTE: This feature is only + available in versions of MS-DOS starting with 3.20. + + +GET_DPB UNDOCUMENTED SYSTEM CALL. THIS CALL MAY BE USED +TO GET A POINTER TO THE PHYSICAL LOCATION OF THE DISK DEVICE +DRIVER. CONSULT THE DBP STRUCTURE DOCUMENTED IN DOSSYM.ASM + + ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +| C A V E A T P R O G R A M M E R | +| | + + Name: * GET_DPB - get pointer to drive parameter + block + + Assembler usage: + MOV AH,GET_DPB + INT 21h + ; DS:BX has address of drive parameter block + + Description: + Return pointer to default drive parameter block. + + Error returns: + None. + + Assembler usage: + MOV DL,DrvNUM + MOV AH,32H + INT 21h + ; DS:BX has address of drive parameter block + + Description: + Return pointer to drive parameter block for drive + designated in DL (0=Default, A=1, B=2 ...) + + Error returns: + AL = FF + The drive given in DL is invalid. +| | +| C A V E A T P R O G R A M M E R | ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + + + APPENDIX H + + +This material was taken from the MS-DOS 3.10 Programmer's Reference +Manual. It is intended be used with the MS-DOS 2.XX/3.XX Adaptation +Guide. + +7.1 INTRODUCTION + +This chapter describes recommended MS-DOS 3.1 programming +procedures. By using these programming hints, you can +ensure compatibility with future versions of MS-DOS. + +The hints are organized into the following categories: + + Interrupts + + System Calls + + Device Management + + Memory Management + + Process Management + + File and Directory Management + + Miscellaneous + + + + + +7.2 INTERRUPTS + +Never explicitly issue Interrupt 22H (Terminate Process Exit +Address). + + This should only be done by the DOS. To change the + terminate address, use Function 35H (Get Interrupt + Vector) to get the current address and save it, then + use Function 25H (Set Interrupt Vector) to change + the Interrupt 22H entry in the vector table to point + to the new terminate address. + PROGRAMMING HINTS Page 7-2 + + +Use Interrupt 24H (Critical Error Handler Address) with +care. + + The Interrupt 24H handler must preserve the ES + register. + + Only system calls 01H-0CH can be made by an + Interrupt 24H handler. Making any other calls will + destroy the MS-DOS stack and prevent successful use + of the Retry or Ignore options. + + The registers SS, SP, DS, BX, CX, and DX must be + preserved when using the Retry or Ignore options. + +When an Interrupt 24H (Critical Error Handler Address) is +received, always IRET back to MS-DOS with one of the +standard responses. + + Programs that do not IRET from Interrupt 24H leave + the system in an unpredictable state until a + function call other than 01H-0CH is made. The + Ignore option may leave data in internal system + buffers that is incorrect or invalid. + +Avoid trapping Interrupt 23H (Control-C Handler Address) and +Interrupt 24H (Critical Error Handler Address). Don't rely +on trapping errors via Interrupt 24H as part of a copy +protection scheme. + + These might not be included in future releases of + the operating system. + +Interrupt 23H (Control-C Handler Address) must never be +issued by a user program. + + Interrupt 23H must be issued only by MS-DOS. + +Save any registers your program uses before issuing +Interrupt 25H (Absolute Disk Read) or Interrupt 26H +(Absolute Disk Write). + + These interrupts destroy all registers except for + the segment registers. + + Avoid writing or reading an interrupt vector + directly to or from memory. + +Use Functions 25H and 35H (Set Interrupt Vector and Get +Interrupt Vector) to set and get values in the interrupt +table. + + PROGRAMMING HINTS Page 7-3 + + +7.3 SYSTEM CALLS + +Use new system calls. + + Avoid using system calls that have been superseded + by new calls unless a program must maintain backward ____ + compatibility with pre-2.0 versions of MS-DOS. See + Section 1.8, "Old System Calls," of this manual for + a list of these new calls. + +Avoid using system calls 01H-0CH and 26H (Create New PSP). + + Use the new "tools" approach for reading and writing + on standard input and output. Use Function 4B00H + (Load and Execute Program) instead of 26H to execute + a child process. + +Use file-sharing calls if more than one process is in +effect. + + See "File Sharing," in Section 1.5.2, "File-Related + Function Requests" in Chapter 1 for more + information. + +Use networking calls where appropriate. + + Some forms of IOCTL can only be used with Microsoft + Networks. See Section 1.6, "Microsoft Networks," in + this manual for a list of these calls. + +When selecting a disk with Function 0EH (Select Disk), treat +the value returned in AL with care. + + The value in AL specifies the maximum number of + logical drives; it does not specify which drives + are valid. + + + + +7.4 DEVICE MANAGEMENT + +Use installable device drivers. + + MS-DOS provides a modular device driver structure + for the BIOS, allowing you to configure and install + device drivers at boot time. Block device drivers + transmit a block of data at a time, while character + device drivers transmit a byte of data at a time. + + Examples of both types of device drivers are given + in Chapter 2, "MS-DOS Device Drivers." + PROGRAMMING HINTS Page 7-4 + + +Use buffered I/O. + + The device drivers can handle streams of data up to + 64K. When sending a large amount of output to the + screen, you can send it with one system call. This + will increase performance. + +Programs that use direct console I/O via Function 06H and +07H (Direct Console I/O and Direct Console Input) and that +want to read Control-C as data should ensure that Control-C +checking is off. + + The program should ensure that Control-C checking is + off by using Function 33H (Control-C Check). + +Be compatible with international support. + + To provide support for international character sets, + MS-DOS recognizes all possible byte values as + significant characters in filenames and data + streams. Pre-2.x versions ignored the high bit in + the MS-DOS filename. + + + + +7.5 MEMORY MANAGEMENT + +Use memory management. + + MS-DOS keeps track of allocated memory by writing a + memory control block at the beginning of each area + of memory. Programs should use Functions 48H + (Allocate Memory), 49H (Free Allocated Memory), and + 4AH (Set Block) to release unneeded memory. + + This will allow for future compatibility. + + See Section 1.3, "Memory Management," for more + information. + +Only use allocated memory. + + Don't directly access memory that was not provided + as a result of a system call. Do not use fixed + addressing, use only relative references. + + A program that uses memory that has not been + allocated to it may destroy other memory control + blocks or cause other applications to fail. + + PROGRAMMING HINTS Page 7-5 + + +7.6 PROCESS MANAGEMENT + +Use the EXEC Function Call to load and execute programs. + + The EXEC Function (4B00H) is the preferred way to + load programs and program overlays. Using the EXEC + call instead of hard-coding information about how to + load an .EXE file (or always assuming that your file + is a .COM file) will isolate your program from + changes in future releases of MS-DOS and .EXE file + formats. + +Use Function 31H (Keep Process), instead of Interrupt 27H +(Terminate But Stay Resident). Function 31H allows programs +to terminate and stay resident that are greater than 64K. + +Programs should terminate using End Process (4CH). + +Programs that terminate by + - a long jump to offset 0 in the PSP, + - issuing an Interrupt 20H with CS:0 pointing at the PSP, + - issuing an Interrupt 21H with AH=0, CS:0 pointing at the + PSP, or + - a long call to location 50H in the PSP with AH=0 + +must ensure that the CS register contains the segment +address of the PSP. + + + + +7.7 FILE AND DIRECTORY MANAGEMENT + +Use the MS-DOS file management system. + + Using the MS-DOS file system will ensure program + compatibility with future MS-DOS versions through + compatible disk formats and consistent internal + storage. This will ensure compatibility with future + MS-DOS versions. + +Use file handles instead of FCBs. + + A handle is a 16-bit number that is returned by + MS-DOS when a file is opened or created using + Functions 3CH, 3DH, 5AH, or 5BH (Create Handle, Open + Handle, Create Temporary File, or Create New File). + The MS-DOS file-related function requests that use + handles are listed in Table 1.5 in Chapter 1, + "System Calls." + + These calls should be used instead of the old + file-related functions that use FCBs (file control + blocks). This is because a file operation can + simply pass its handle rather than having to + PROGRAMMING HINTS Page 7-6 + + + maintain FCB information. If FCBs must be used, be + sure the program closes them and does not move them + around in memory. + +Close all files that have changed in length before issuing +an Interrupt 20H (Program Terminate), Function 00H +(Terminate Program), Function 4CH (End Process), or Function +0DH (Reset Disk). + + If a changed file is not closed, its length will not + be recorded correctly in the directory. + +Close all files when they are no longer needed. + + Closing unneeded files will optimize performance in + a networking environment. + +Only change disks if all files on the disk are closed. + + Information in internal system buffers may be + written incorrectly to a changed disk. + + + + +7.7.1 Locking Files + +Programs should not rely on being denied access to a locked +region. + + Determine the status of the region by attempting to + lock it, and examine the error code. + +Programs should not close a file with a locked region or +terminate with an open file that contains a locked region. + + The result is undefined. Programs that might be + terminated by an Interrupt 23H or Interrupt 24H + (Control-C Handler Address or Critical Error Handler + Address) should trap these interrupts and unlock any + locked regions before exiting. + + + + +7.8 MISCELLANEOUS + +Avoid timing dependencies. + + Various machines use CPUs of different speeds. + Also, programs that rely upon the speed of the clock + for timing will not be dependable in a networking + environment. + PROGRAMMING HINTS Page 7-7 + + +Use the documented interface to the operating system. If +either the hardware or media change, the operating system +will be able to use the features without modification. + + Don't use the OEM (Original Equipment Manufacturer) + -provided ROM support. + + Don't directly address the video memory. + + Don't use undocumented function calls, interrupts, + or features. These items may change or not continue + to exist in future versions of MS-DOS. Use of these + features would make your program highly + non-portable. + +Use the .EXE format rather than the .COM format. + + .EXE files are relocatable and .COM files are direct + memory images that load at a specific place and have + no room for additional control information to be + placed in them. .EXE files have headers that can be + expanded for compatibility with future versions of + MS-DOS. + +Use the environment to pass information to applications. + + The environment allows a parent process to pass + information to a child process. COMMAND.COM is + usually the parent process to every application, so + default drive and path information can easily be + passed to the application. + + + + + + + GLOSSARY OF MS-DOS TERMS + + + +Allocation Unit + + (See Cluster) + + + +Arena + + MS-DOS uses a software memory management scheme. + Blocks in memory are either owned by processes or + are free. An owned block has an ID number, which + is the initial paragraph of the Program Segment + GLOSSARY OF MS-DOS TERMS + + + Prefix of a process in memory (your program). Each + block has a size as well. When your process is in + memory, there is a 16-byte arena block which + identifies it and specifies how much memory is + allocated. + + + +ASCIZ + + Any null (zero byte) terminated ASCII string. + + + +Cluster + + The storage unit that MS-DOS uses to allocate space + for files on a disk. All files are allocated in + multiples of clusters. A cluster must be a power + of two sectors (i.e., 1, 2, 4, 8 ... ). This term + is synonymous with allocation unit. + + Block device drivers perform I/O in + sectors, not clusters. + + + +Cooked/Raw Mode + + + Character devices have two modes that have + significance when performing I/O via the Read + Handle and Write Handle calls (Functions 3FH and + 40H). These are "raw" and "cooked" mode. A device + driver can be set to raw mode via the IOCTL + Function Request 44H. + + Cooked mode input is buffered input with echoing to + the screen (if console) and Control-C checking. + Cooked mode input of a certain number of characters + will return when the specified number of characters + is returned or a carriage return is typed. Cooked + mode output performs Control-C checking between + characters. + + Raw mode I/O is very fast. When raw mode I/O of + "n" characters is requested, MS-DOS passes the + request directly to the indicated device driver. + The device driver does not return to MS-DOS until + the I/O has completed. Characters are written or + read directly from the process buffer. No checking + of any kind is performed. No characters have any + significance, including Control-C. + + GLOSSARY OF MS-DOS TERMS + + + For example, if the requesting program puts a + device in raw mode and requests a write of 50,000 + characters to the AUX device, the device driver + will get a request from MS-DOS to write 50,000 + characters from the buffer located at the DWORD + transfer address. The driver will not return until + the request has completed. + + In cooked mode, MS-DOS performs a Control-C check + at the console after each single character write. + This is an overhead of 50,000 Control-C checks. + + + + +Environment + + The environment is a maximum of 32K data area which + consists of ASCIZ strings of the form: + AAAA=BBBBBBB. The end of the environment is marked + by two consecutive nulls. The word at 2CH in the + Program Segment Prefix points to the segment + containing the start of a program's environment. + New variables can be added to the environment by + using the MS-DOS Set command. Since nulls have + significance, the environment cannot be used for + storing binary data. + + When a parent process (such as COMMAND.COM) + executes a child process (any other program), the + child is given a copy of the parent's environment. + Parameters such as Prompt, which specifies the + style of prompt used by COMMAND.COM, are stored in + the environment. Application programs can use the + environment to find overlays or special files which + may not be located in the current directory. + COMMAND.COM uses this technique to examine the + elements of the Path looking for binaries and batch + files. Of course the application program must be + specifically coded to find the environment and + parse it for variables. + + + +FATID Byte + + The FATID byte is the first byte of the File + Allocation Table that starts at the sector + immediately after the reserved sectors of the disk. + The FATID byte was used by OEMs in MS-DOS 1.x for + identification of disk media. This byte should be + between F8H and FFH. To read MS-DOS 1.x disks, one + must read this byte, determine which of the four + predefined FATID bytes is present and return a + pointer to the appropriate BPB. This method of + GLOSSARY OF MS-DOS TERMS + + + determining media is less general and less + desirable than the BPB table method (see MEDIA ID + Byte). + + + +File Handle + + In versions of MS-DOS that are 2.0 and higher, + there is a system file table set up at boot time. + By the time COMMAND.COM gets control, all of the + character devices have been entered into the system + file table. The first five handles are initialized + as follows. + + + HANDLE XENIX NAME DEFAULT SETTING + + 0 Standard Input CON + 1 Standard Output CON + 2 Standard Error CON + 3 Standard AUX AUX + 4 Standard PRN PRN + + As new files are opened via XENIX-compatible calls, + they are assigned the first available numbers. + When COMMAND.COM executes a program, the child + process inherits all of the handles that + COMMAND.COM has open. Typing + + prog < infyle > outfyle + + on the command line means that you want PROG to + read its input from INFYLE and write its output to + OUTFYLE instead of to console out. COMMAND.COM + will close handle 0 and open INFYLE; it will DUP + handle 0. It will then close handle 1, standard + out, and open OUTFYLE (which is assigned to + standard out). COMMAND will exec PROG, which + inherits this environment. When PROG reads from + standard in, or writes to standard out, it reads + from and writes to INFYLE and OUTFYLE, + respectively. + + If a child is executed, it inherits the files of + its parent. The converse is not true. When a + child process which opens AUX as standard in and + PRN as standard out returns, the parent does not ___ + inherit the files of its child. + + + + + GLOSSARY OF MS-DOS TERMS + + +MEDIA ID Byte + + The MEDIA ID byte is the byte in the Bios Parameter + Block (BPB) located at offset 0AH. The MEDIA ID + byte may have any value between 0 and 0FFH. It may + or may not have the same value as the FATID byte. + The major significance of the MEDIA ID byte is that + there be a one-to-one relationship between unique + MEDIA ID bytes and disk formats. For disk + compatibility with other OEMs as well as with + future releases of MS-DOS, Microsoft recommends + that the BPB table be located at offset 0BH in the + first reserved (boot) sector. OEMs may register + their media byte/format combinations with OEM + Customer Support. The BPB technique of determining + disk format is much more general than the limited + FATID byte method and is the preferred method. + + The significance of the media byte and FATID byte + depends on whether you have decided to make your + block device driver IBM format-compatible. You + must indicate this by setting bit 13 in the device + driver header. This will alter the way MS-DOS + performs the GET BPB device call. With the NON + FATID bit set, you can support various media, + including IBM format media. If the device driver + is IBM-format compatible, use FATID bytes to + determine the media in the drive. The + correspondence between FATID bytes and various + media is defined in the MS-DOS Programmer's ______ ____________ + Reference Manual. _________ ______ + + If your system is not IBM Format-compatible, you + are given a pointer to a one-sector scratch buffer + when your block device gets called by MS-DOS to do + a BUILD BPB. Follow these steps: + + 1. Read the boot sector of the disk into that + buffer and check the first byte. If it is an + E9H, it is the first byte of a 3-byte JMP and + there is a BIOS Parameter Block table in the + boot sector. + + Alternately, EBH may be the first byte. This + is also a 3-byte JMP (actually, a 2-byte JMP + followed by a NOP). + GLOSSARY OF MS-DOS TERMS + + + 2. Return a pointer to the BPB. Set the status + word and return. If the first byte of the boot + sector is not an E9H, then there is not a BPB + table in the boot sector. You can assume that + the disk is an IBM format disk and the FAT + begins with the second sector of the disk. + Read the FAT into the scratch buffer and check + the first byte. Determine which one of the + four defined FATID bytes it is, and return a + pointer to the appropriate BPB. + + Refer to the MS-DOS Programmer's Reference ______ ____________ _________ + Manual for a list of valid FATID bytes. Any ______ + other media should be defined in the boot + sector and should use a FATID byte of FFH. + + + + +Paragraph + + Any location in the memory of the 8086 which has an + address that is a multiple of 16 (i.e., 0, 16, 32). + + + + diff --git a/PROGREF/0_CONTS.A b/PROGREF/0_CONTS.A new file mode 100644 index 0000000..70fd8c3 --- /dev/null +++ b/PROGREF/0_CONTS.A @@ -0,0 +1,227 @@ + +_ _ | | _ _ + + +Contents + +_ ________________________________________________________________ + +1 System Calls 1 + + 1.1 Introduction 3 + 1.2 Standard Character Device I/O 4 + 1.3 Memory Management 5 + 1.4 Process Management 7 + 1.5 File and Directory Management 9 + 1.6 Microsoft Networks 14 + 1.7 National Language Support 15 + 1.8 Miscellaneous System-Management Functions 16 + 1.9 Old System Calls 17 + 1.10 Using the System Calls 21 + 1.11 Interrupts 35 + 1.12 Function Requests 53 + +2 MS-DOS Device Drivers 323 + + 2.1 Introduction 325 + 2.2 Format of a Device Driver 326 + 2.3 How to Create a Device Driver 328 + 2.4 Installing Device Drivers 329 + 2.5 Device Headers 330 + 2.6 Request Header 334 + 2.7 Device Driver Functions 337 + 2.8 The Media Descriptor Byte 351 + 2.9 Format of a Media Descriptor Table 351 + 2.10 The CLOCK Device 353 + 2.11 Anatomy of a Device Call 354 + 2.12 Two Sample Device Drivers 355 + +3 MS-DOS Technical Information 383 + + 3.1 Introduction 385 + 3.2 MS-DOS Initialization 385 + 3.3 The Command Processor 386 + 3.4 MS-DOS Disk Allocation 387 + 3.5 MS-DOS Disk Directory 387 + 3.6 File Allocation Table (FAT) 390 + 3.7 MS-DOS Standard Disk Formats 392 + +4 MS-DOS Control Blocks + and Work Areas 395 + + iii + +_ _ | | _ _ + + +_ _ | | _ _ + +Contents + + 4.1 Introduction 397 + 4.2 Typical Contents of an MS-DOS Memory Map 397 + 4.3 MS-DOS Program Segment 398 + +5 National Language Support 403 + + 5.1 Introduction 405 + 5.2 National Language Support Calls 405 + 5.3 Font Files 406 + +6 .Exe File Structure and Loading 411 + + 6.1 Format of a File Header 413 + 6.2 The Relocation Table 414 + +7 Microsoft Relocatable + Object Module Formats 417 + + 7.1 Introduction 419 + 7.2 Module Identification and Attributes 423 + 7.3 Conceptual Framework for Fixups 425 + 7.4 Record Sequence 431 + 7.5 Introducing the Record Formats 433 + 7.6 Microsoft Type Representations + for Communal Variables 460 + +8 Programming Hints 463 + + 8.1 Introduction 465 + 8.2 Interrupts 465 + 8.3 System Calls 466 + 8.4 Device Management 467 + 8.5 Memory Management 468 + 8.6 Process Management 468 + 8.7 File and Directory Management 469 + 8.8 Miscellaneous 471 + + +iv + +_ _ | | _ _ + + +_ _ | | _ _ + + +Figures + +_ ________________________________________________________________ + +Figure 1.1 Example of the 8088 Registers 25 + +Figure 1.2 Sample Program with Common Skeleton 26 + +Figure 2.1 Sample Device Header 330 + +Figure 2.2 Attribute Word for Character Devices 333 + +Figure 2.3 Attribute Word for Block Devices 333 + +Figure 2.4 Request Header 335 + +Figure 2.5 Format of a Boot Sector 352 + +Figure 2.6 Format of a Clock Device 354 + +Figure 4.1 Program Segment Prefix 402 + +Figure 5.1 Font File Structure 407 + +Figure 7.1 Location Types 427 + + + + v + +_ _ | | _ _ + + +_ _ | | _ _ + + +Tables + +_ ________________________________________________________________ + +Table 1.1 Standard Character I/O Function Requests 4 + +Table 1.2 Memory Management Function Requests 5 + +Table 1.3 Process-Management Function Requests 7 + +Table 1.4 Predefined Device Handles 9 + +Table 1.5 File-Related Function Requests 10 + +Table 1.6 File-Sharing Function Requests 11 + +Table 1.7 Device-Related Function Requests 12 + +Table 1.8 Directory-Related Function Requests 12 + +Table 1.9 File Attributes 13 + +Table 1.10 Microsoft Networks Function Requests 14 + +Table 1.11 National Language-Support Function Requests 15 + +Table 1.12 Miscellaneous System-Management Function Requests 16 + +Table 1.13 Old System Calls and Their Replacements 17 + +Table 1.14 Format of the File Control Block (FCB) 18 + +Table 1.15 Error Codes Returned in AX 22 + +Table 1.16 MS-DOS Interrupts, Numeric Order 27 + +Table 1.17 MS-DOS Interrupts, Alphabetic Order 27 + +Table 1.18 MS-DOS Function Requests, Numeric Order 28 + +Table 1.19 MS-DOS Function Requests, Alphabetic Order 31 + +Table 1.20 Bit values for Function 29H 133 + +Table 1.21 Sharing Mode Bit Values 174 + +Table 1.22 Access Code Bit Values 175 + +Table 1.23 MS-DOS Data Bit Values 193 + +Table 1.24 Contents of the Parameter Block 239 + +Table 1.25 Contents of the Parameter Block 243 + +Table 1.26 250 + +Table 1.27 Allocation Strategy 263 + +Table 2.1 For Character Devices: 331 + +vi + +_ _ | | _ _ + + +_ _ | | _ _ + + Contents + +Table 2.2 For Block Devices: 331 + +Table 3.1 MS-DOS Standard Removable-Disk Formats 393 + +Table 3.2 MS-DOS Standard Removable Disk Formats (High-Density) 393 + +Table 7.1 Object Module Record Formats 419 + +Table 7.2 Combination Attribute Example 438 + + + + vii + +_ _ | | _ _ + diff --git a/PROGREF/0_FRONT.A b/PROGREF/0_FRONT.A new file mode 100644 index 0000000..7cfde16 --- /dev/null +++ b/PROGREF/0_FRONT.A @@ -0,0 +1,34 @@ + +_ _ | | _ _ + + +Microsoft (R) MS-DOS +Version 3.3 +_ ________________________________________________________________ + +Programmer's Reference + +Microsoft Corporation + +_ _ | | _ _ + + +_ _ | | _ _ + +All rights reserved. + +Simultaneously published in the United States and +Canada. + +Microsoft(R), the Microsoft logo, MS-DOS(R), and XENIX(R) are registered trademarks +of Microsoft Corporation. + +IBM(R), IBM Personal Computer(R), IBM PC(R), and PC-DOS(R) are registered trade- +marks of International Business Machines Corporation. + +INTEL(R) is a registered trademark of Intel Corporation. + +Document No. 410630014-330-R04-0787 + +_ _ | | _ _ + diff --git a/PROGREF/1A_CALLS.A b/PROGREF/1A_CALLS.A new file mode 100644 index 0000000..e5cc52a --- /dev/null +++ b/PROGREF/1A_CALLS.A @@ -0,0 +1,3175 @@ + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +1.1 Introduction + +The routines that MS-DOS uses to manage system operation and resources +can be called by any application program. Using these system calls makes +it easier to write machine-independent programs and increases the likeli- +hood that a program will be compatible with future versions of MS-DOS. +MS-DOS system calls fall into several categories: + + o Standard character device I/O + + o Memory management + + o Process management + + o File and directory management + + o Microsoft Network calls + + o National Language Support calls + + o Miscellaneous system functions + +Applications invoke MS-DOS services by using software interrupts. The +current range of interrupts used for MS-DOS is 20H-27H; 28H-40H are +reserved. Interrupt 21H is the function request service; it provides access +to a wide variety of MS-DOS services. In some cases, the full AX register +is used to specify the requested function. Each interrupt or function +request uses values in various registers to receive or return function- +specific information. + +1.1.1 System Calls That Have Been Superseded + +Many system calls introduced in versions of MS-DOS earlier than 2.0 have +been superseded by function requests that are more efficient and easier to +use. Although MS-DOS still includes these old system calls, they should +not be used unless it is imperative that a program maintain backward- +compatibility with versions of MS-DOS before 2.0. + +A table of the pre-2.0 system calls and a description of the File Control +Block (required by some of the old calls) appears in Section 1.8, "Old Sys- +tem Calls." + +The first part of this chapter explains how DOS manages its resources\(em +such as memory, files, and processes\(emand briefly describes the purpose of +most of the system calls. The remainder of the chapter describes each +interrupt and function request in detail. + +The system-call descriptions are in numeric order, interrupts followed by +function requests. These descriptions include further detail on how +MS-DOS manages its resources. + + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +Chapter 2 of this manual describes how to write an MS-DOS device driver. +Chapters 3, 4, and 5 contain more detailed information about MS-DOS, +including how it manages disk space, the control blocks it uses, and how it +loads and executes relocatable programs (files with an extension of .exe). +Chapter 6 describes the Intel object module format. Chapter 7 gives some +programming hints. + +1.2 Standard Character Device I/O + +The standard character function requests handle all input and output to +and from character devices such as consoles, printers, and serial ports. If a +program uses these function requests, its input and output can be +redirected. + +Table 1.1 lists the MS-DOS function requests for managing standard char- +acter input and output. + +Table 1.1 + +Standard Character I/O Function Requests + +_ _________________________________________________________________________ + +01H + + Read Keyboard and + Echo + + Gets a character from standard input and echoes + it to standard output + +02H Display Character Sends a character to standard output + +03H Auxiliary Input + + Gets a character from standard auxiliary + +04H Auxiliary Output + + Sends a character to standard auxiliary + +05H Print Character + + Sends a character to the standard printer + +06H Direct Console I/O + + Gets a character from standard input or sends a + character to standard output + +07H + + Direct Console Input + + Gets a character from standard input + +08H Read Keyboard + + Gets a character from standard input + +09H Display String Sends a string to standard output + +0AH Gets a string from standard input + + Buffered Keyboard + Input + +0BH + + Check Keyboard + Status + + Reports on the status of the standard input + buffer + +0CH + + Flush Buffer, Read + Keyboard + + Empties the standard input buffer and calls one + of the other standard character I/O function + requests + +_ _________________________________________________________________________ + +Although several of these standard character I/O function requests seem +to do the same thing, they are distinguished by whether they check for +control characters or echo characters from standard input to standard + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +output. The detailed descriptions later in this chapter point out the +differences. + +1.3 Memory Management + +MS-DOS keeps track of which areas of memory are allocated by writing a +memory control block at the beginning of each. This control block specifies +the size of the memory area; the name of the process, if any, that owns the +memory area; and a pointer to the next area of memory. If the memory +area is not owned, it is available. + +Table 1.2 lists the MS-DOS function requests for managing memory. + +Table 1.2 + +Memory Management Function Requests + +_ _________________________________________________________________________ + +48H Allocate Memory Requests a block of memory + +49H + + Free Allocated + Memory + + Frees a block of memory previously allocated with 48H + + +4AH Set Block + + Changes the size of an allocated memory block + +_ _________________________________________________________________________ + +When a process requests additional memory with Function 48H (Allocate +Memory), MS-DOS searches for a block of available memory large enough +to satisfy the request. If it finds such a block of memory, it changes the +memory control block to show the owning process. If the block of memory +is larger than the requested amount, MS-DOS changes the size field of the +memory control block to the requested amount, writes a new memory con- +trol block at the beginning of the unneeded portion showing that it is +available, and updates the pointers to add this memory to the chain of +memory control blocks. MS-DOS then returns the segment address of the +first byte of the allocated memory to the requesting process. + +When a process releases an allocated block of memory with Function 49H +(Free Allocated Memory), MS-DOS changes the memory control block to +show that it is available (not owned by any process). + +When a process uses Function 4AH (Set Block) to shrink an allocated +block of memory, MS-DOS builds a memory control block for the memory +being released and adds it to the chain of memory control blocks. When a +process tries to use Function 4AH (Set Block) to expand an allocated block +of memory, MS-DOS treats it as a request for additional memory rather +than returning the segment address of the additional memory to the +requesting process. However, MS-DOS simply chains the additional +memory to the existing memory block. + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +If MS-DOS can't find a block of available memory large enough to satisfy a +request for additional memory made with either Function 48H (Allocate +Memory) or Function 4AH (Set Block), MS-DOS returns an error code to +the requesting process. + +When a program receives control, it should call Function 4AH (Set Block) +to shrink its initial memory-allocation block (the block that begins with +its Program Segment Prefix) to the minimum it requires. This frees +unneeded memory and makes the best application design for portability to +future multitasking environments. + +When a program exits, MS-DOS automatically frees its initial memory- +allocation block before returning control to the calling program +(command.com is usually the calling program for application programs). +The DOS frees any memory owned by the exiting process. + +Any program that changes memory that is not allocated to it will most +likely destroy at least one memory-management control block. This +causes a memory-allocation error the next time MS-DOS tries to use the +chain of memory control blocks; the only cure is to restart the system. + +1.4 Process Management + +MS-DOS uses several function requests to load, execute, and terminate +programs. Application programs can use these same function requests to +manage other programs. + +Table 1.3 lists the MS-DOS function requests for managing processes. + +Table 1.3 + +Process-Management Function Requests + +_ _________________________________________________________________________ + +31H Keep Process + + Terminates a process and returns control to the + invoking process, but keeps the terminated + process in memory + +4BH Loads and executes a program + + Load and Execute + Program + +4B03H Load Overlay + + Loads a program overlay without executing it + +4CH End Process + + Returns control to the invoking process + +4DH + + Get Return Code of + Child Process + + Returns a code passed by an exiting child process + + +62H Get PSP + + Returns the segment address of the current + process's Program Segment Prefix + +_ _________________________________________________________________________ + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +1.4.1 Loading and Executing a Program + +When a program uses Function 4BH (Load and Execute Program) to load +and execute another program, MS-DOS allocates memory, writes a Pro- +gram Segment Prefix (PSP) for the new program at offset 0 of the allo- +cated memory, loads the new program, and passes control to it. When the +invoked program exits, control returns to the calling program. + +Command.com uses Function 4BH to load and execute command files. +Application programs have the same degree of control over process +management as does command.com. + +In addition to these common features, there are some differences in the +way MS-DOS loads .com and .exe files. + +Loading a .Com Program + +When command.com loads and executes a .com program, it allocates all +available memory to the application and sets the stack pointer 100H bytes +from the end of available memory. A .com program should set up its own +stack before shrinking its initial memory-allocation block with Function +4AH (Set Block) because the default stack is in the memory to be released. + +If a newly loaded program is allocated all of memory\(emas a .com program +is\(emor requests all of available memory by using Function 48H (Allocate +Memory), MS-DOS allocates to it the memory occupied by the transient +part of command.com. If the program changes this memory, MS-DOS +must reload the transient portion of command.com before it can continue. +If a program exits (via Function 31H, Keep Process) without releasing +enough memory, the system halts and must be reset. To minimize this pos- +sibility, a .com program should use Function 4AH (Set Block) to shrink its +initial allocation block before doing anything else, and before exiting, all +programs must release all memory they allocate by using Function 48H +(Allocate Memory). + +Loading an .Exe Program + +When command.com loads and executes an .exe program, it allocates the +size of the program's memory image plus either the value in the +MAX_ALLOC field (offset 0CH) of the file header (if that much memory is +available) or the value in the MIN_ALLOC field (offset 0AH). The linker +sets these fields. Before passing control to the .exe file, MS-DOS uses the +relocation information in the file header to calculate the correct relocation +addresses. + + + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +For a more detailed description of how MS-DOS loads .com and .exe files, +see Chapter 3, "MS-DOS Technical Information," and Chapter 4, "MS- +DOS Control Blocks and Work Areas." + +Executing a Program from Within Another Program + +Since command.com builds pathnames, searches directory paths for exe- +cutable files, and relocates .exe files, the simplest way to load and execute +a program is to load and execute an additional copy of command.com, +passing it a command line that includes the /C switch, which invokes the +.com or .exe file. The description of Function 4B00H (Load and Execute +Program) describes how to do this. + +1.4.2 Loading an Overlay + +When a program uses Function 4B03H (Load Overlay) to load an overlay, +it must pass MS-DOS the segment address at which the overlay is to be +loaded. The program must call the overlay, which then returns directly to +the calling program. The calling program is in complete control: MS-DOS +does not write a PSP for the overlay or intervene in any other way. + +MS-DOS does not check to see if the calling program owns the memory +where the overlay is to be loaded. If the calling program does not own the +memory, loading the overlay will most likely destroy a memory-control +block, causing an eventual memory-allocation error. + +Therefore, a program that loads an overlay must either allow room for the +overlay when it calls Function 4AH (Set Block) to shrink its initial +memory-allocation block, or shrink its initial memory-allocation block to +the minimum and then use Function 48H (Allocate Memory) to allocate +memory for the overlay. + +1.5 File and Directory Management + +The MS-DOS hierarchical (multilevel) file system is similar to that of the +XENIX operating system. For a description of the multilevel directory sys- +tem and how to use it, see the MS-DOS User's Reference. + +1.5.1 Handles + +To create or open a file, a program passes MS-DOS a pathname and the +attribute to be assigned to the file. MS-DOS returns a 16-bit number, +called a handle. For most subsequent actions, MS-DOS requires only this +handle to identify the file. + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +A handle can refer to either a file or a device. MS-DOS predefines five stan- +dard handles. These handles are always open, so you needn't open them +before you use them. Table 1.4 lists these predefined handles. + +Table 1.4 + +Predefined Device Handles + +_ _________________________________________________________________________ + +Handle Standard device Comment + +_ _________________________________________________________________________ + +0 Input Can be redirected from command line +1 Output Can be redirected from command line +2 Error +3 Auxiliary +4 Printer + +_ _________________________________________________________________________ + +When MS-DOS creates or opens a file, it assigns the first available handle. +Since a program can have 20 open handles, including the five predefined +handles, it typically can open 15 extra files. By using Function 46H (Force +Duplicate File Handle), MS-DOS can temporarily force any of the five +predefined handles to refer to an alternate file or device. For more infor- +mation about Function 46H, see its description later in this chapter. + +1.5.2 File-Related Function Requests + +MS-DOS treats a file as a string of bytes; it assumes no record structure or +access technique. An application program imposes whatever record struc- +ture it needs on this string of bytes. Reading from or writing to a file +requires only pointing to the data buffer and specifying the number of +bytes to read or write. + +Table 1.5 lists the MS-DOS function requests for managing files. + +Table 1.5 + +File-Related Function Requests + +_ _________________________________________________________________________ + +3CH Create Handle Creates a file + +3DH Open Handle Opens a file + +3EH Close Handle Closes a file + +3FH Read Handle Reads from a file + +40H Write Handle Writes to a file + +42H Move File Pointer Sets the read/write pointer in a file + +45H Duplicate File Handle + + Creates a new handle that refers to the same + file as an existing handle + + + + 9 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +46H Force Duplicate File Handle + + Makes an existing handle refer to the same file + as another existing handle + +5AH Create Temporary File Creates a file with a unique name + +5BH Create New File + + Attempts to create a file, but fails if a file with + the same name exists + +67H Set Handle Count + + Increases or decreases the number of files a + program can have open at one time + +68H Commit File + + Flushes buffered data for a file without closing + it to ensure the disk image of that file is + current + +_ _________________________________________________________________________ + + +File Sharing + +Version 3.1 of MS-DOS introduces file sharing, which lets more than one +process share access to a file. File sharing operates only after the share +command has been executed to load file-sharing support. That is, you +must use the share command to take advantage of file sharing. + +Table 1.6 lists the MS-DOS function requests for sharing files; if file shar- +ing is not in effect, these function requests cannot be used. Function 3DH +(Open Handle) can operate in several modes. Here it is referred to in the +file-sharing modes, which require file sharing to be in effect. (Compatibil- +ity mode is usable without file sharing in effect.) + +Table 1.6 + +File-Sharing Function Requests + +_ _________________________________________________________________________ + +3DH Open Handle + + Opens a file by using one of the file-sharing modes + +440BH IOCtl Retry + + (before Interrupt 24 is issued) Specifies how many + times to retry an I/O operation that fails due to a file- + sharing violation + +5C00H Lock Locks a region of a file + +5C01H Unlock Unlocks a region of a file + +_ _________________________________________________________________________ + + +1.5.3 Device-Related Function Requests + +I/O Control for devices is implemented with Function 44H (IOCtl), which +includes several subfunctions necessary to perform device-related tasks. +Some forms of the IOCtl function request require that the device driver be +written to support the IOCtl interface. Table 1.7 lists the MS-DOS func- +tion requests for managing devices. + +Table 1.7 + +Device-Related Function Requests + +10 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +_ _________________________________________________________________________ + +4400H,01H IOCtl Data Gets or sets device description + +4402H,03H IOCtl Character + + Gets or sets character-device control data + +4404H,05H IOCtl Block + + Gets or sets block-device control data + +4406H,07H IOCtl Status + + Checks device input or output status + +4408H IOCtl Is Changeable + + Checks whether block device contains + removable medium + +440CH Generic IOCtl (for handles) + + Sets Generic IOCtl for handles and + supports code pages for devices + +440DH Generic IOCtl (for devices) Sets Generic IOCtl for devices + +440E,0FH Get/Set IOCtl Drive Map Gets or sets logical drive map + +_ _________________________________________________________________________ + +Some forms of the IOCtl function request can be used only with Microsoft +Networks; these forms are listed in Section 1.6, "Microsoft Networks." + +1.5.4 Directory-Related Function Requests + +A directory entry is a 32-byte record that includes the file's name, exten- +sion, date and time of last change, and size. An entry in a subdirectory is +identical to an entry in the root directory. Directory entries are described +in detail in Chapter 3. + +The root directory on a disk has room for a fixed number of entries: 64 on +a standard single-sided disk, 112 on a standard double-sided disk. For +hard disks, the number of directories depends on the DOS partition size. +A subdirectory is simply a file with a unique attribute; there can be as +many subdirectories on a disk as space allows. The depth of a directory +structure, therefore, is limited only by the amount of storage on a disk and +the maximum pathname length of 64 characters. Pre-2.0 disks appear to +have only a root directory that contains files but no subdirectories. + +Table 1.8 lists the MS-DOS function requests for managing directories. + +Table 1.8 + +Directory-Related Function Requests + +_ _________________________________________________________________________ + +39H Create Directory Creates a subdirectory + +3AH Remove Directory Deletes a subdirectory + +3BH Change Current Directory Changes the current directory + +41H Delete Directory Entry (Unlink) Deletes a file + +43H Get/Set File Attributes (Chmod) + + Retrieves or changes the attributes of a file + +47H Get Current Directory + + Returns current directory for a given drive + + + + 11 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +4EH Find First File + + Searches a directory for the first entry that + matches a filename + +4FH Find Next File + + Searches a directory for the next entry that + matches a filename + +56H Change Directory Entry Renames a file + +57H Get/Set Date/Time of File + + Changes the time and date of last change in a + directory entry + +_ _________________________________________________________________________ + + +1.5.5 File Attributes + +Table 1.9 describes the file attributes and how they are represented in the +attribute byte of the directory entry (offset 0BH). The attributes can be +inspected or changed with Function 43H (Get/Set File Attributes +[Chmod]). + +Table 1.9 + +File Attributes + +_ _________________________________________________________________________ + +Code Description + +_ _________________________________________________________________________ + +00H + + Normal; can be read or written without restriction + +01H + + Read-only; cannot be opened for write; a file with the same name + cannot be created + +02H Hidden; not found by directory search + +04H System; not found by directory search + +08H + + VolumeID; only one file can have this attribute; it must be in the root + directory + +10H Subdirectory + +20H + + Archive; set whenever the file is changed, or cleared by the Backup + command + +_ _________________________________________________________________________ + +The VolumeID (08H) and Subdirectory (10H) attributes cannot be changed +with Function 43H (Get/Set File Attributes [Chmod]). + +1.6 Microsoft Networks + +Microsoft Networks consists of a server and one or more workstations. +MS-DOS maintains an assign list that keeps track of which workstation +drives and devices have been redirected to the server. For a description of +operation and use of the network, see the Microsoft Networks 1.0 +Manager's Guide and Microsoft Networks 1.0 User's Guide. + +12 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +Table 1.10 lists the MS-DOS function requests for managing a Microsoft +Networks workstation. + +Table 1.10 + +Microsoft Networks Function Requests + +_ _________________________________________________________________________ + +4409H + + IOCtl Is Redirected + Block + + Checks whether a drive letter refers to a local or + redirected drive + +440AH + + IOCtl Is Redirected + Handle + + Checks whether a device name refers to a local or + redirected device + +5E00H Get Machine Name Gets the network name of the workstation + +5E02H Printer Setup + + Defines a string of control characters to be added + at the beginning of each file that is sent to a + network printer + +5F02H + + Get Assign-List + Entry + + Gets an entry from the assign list, which shows + the workstation drive letter or device name and + the net name of the directory or device on the + server to which the entry is reassigned + +5F03H + + Make Assign-List + Entry + + Redirects a workstation drive or device to a + server directory or device + +5F04H + + Cancel Assign-List + Entry + + Cancels the redirection of a workstation drive or + device to a server directory or device + +_ _________________________________________________________________________ + + +1.7 National Language Support + +National language support for this version of MS-DOS includes these +major features: + + o Country-dependent information + + o Support for national keyboard layouts + + o Programming interfaces for national language support + + o Utility commands + +Country-dependent information is available on a per-country basis and +includes the following: + + o Time, date, and currency + + o Lowercase-to-uppercase character-conversion tables + + o Collating sequence for character sorting + + o Valid single-byte characters used in filenames + +Keyboard support for different keyboard layouts is provided and + + 13 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +selectable. + +Table 1.11 lists the MS-DOS national-language-support system calls that +allow applications to use the country-dependent information just +described. + +Table 1.11 + +National Language-Support Function Requests + +_ _________________________________________________________________________ + +65H Get Extended Country Information + + Returns standard country + information, pointer to uppercase + table, pointer to filename + uppercasing table, or pointer to + collating table + +66H Get/Set Global Code Page + + Gets or sets the code page used by + the kernel and all devices. + +_ _________________________________________________________________________ + + +1.8 Miscellaneous System-Management Func- +tions + +The remaining system calls manage other system functions and resources +such as drives, addresses, and the clock. Table 1.12 lists the MS-DOS func- +tion requests for managing miscellaneous system resources and operation. + +Table 1.12 + +Miscellaneous System-Management Function Requests + +_ _________________________________________________________________________ + +0DH Reset Disk Empties all file buffers + +0EH Select Disk Sets the default drive + +19H Get Current Disk Returns the default drive + +1AH Establishes the disk I/O buffer + + Set Disk Transfer + Address + +1BH Returns disk-format data + + Get Default Drive Data + +1CH Get Drive Data Returns disk-format data + +25H Set Interrupt Vector Sets interrupt-handler address + +29H Parse File Name Checks string for valid filename + +2AH Get Date Returns system date + +2BH Set Date Sets system date + +2CH Get Time Returns system time + +2DH Set Time Sets system time + +2EH Set/Reset Verify Flag Turns disk verify on or off + +14 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +2FH + + Get Disk Transfer + Address + + Returns system-disk-I/O-buffer address + + +30H Returns MS-DOS version number + + Get MS-DOS Version + Number + +33H CONTROL-C Check + + Returns CONTROL-C check status + +35H Get Interrupt Vector + + Returns address of interrupt handler + +36H Get Disk Free Space Returns disk-space data + +38H Get/Set Country Data + + Sets current country or retrieves country + information + +54H Get Verify State Returns status of disk verify + +_ _________________________________________________________________________ + + +1.9 Old System Calls + +Most of the superseded system calls deal with files. Table 1.13 lists these +old calls and the function requests that have superseded them. + +Although MS-DOS still includes these old system calls, they should not be +used unless a program must maintain backward-compatibility with earlier +versions of MS-DOS. + +Table 1.13 + +Old System Calls and Their Replacements + +_ _________________________________________________________________________ + +Old System Call Has Been Superseded By + +Code Function Code Function + +_ _________________________________________________________________________ + +00H Terminate Program 4CH End Process +0FH Open File 3DH Open Handle +10H Close File 3EH Close Handle +11H Search for First Entry 4EH Find First File +12H Search for Next Entry 4FH Find Next File +13H Delete File 41H Delete Directory Entry +14H Sequential Read 3FH Read Handle +15H Sequential Write 40H Write Handle +16H Create File 3CH Create Handle + 5AH Create Temporary File + 5BH Create New File +17H Rename File 56H Change Directory Entry +21H Random Read 3FH Read Handle +22H Random Write 40H Write Handle +23H Get File Size 42H Move File Pointer +24H Set Relative Record 42H Move File Pointer +26H Create New PSP 4BH Load and Execute Program +27H Random Block Read 42H Move File Pointer + 3FH Read Handle + + 15 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +28H Random Block Write 42H Move File Pointer + 40H Write Handle + +Code Interrupt Code Function + +_ _________________________________________________________________________ + +20H Program Terminate 4CH End Process +27H Terminate But Stay Resident 31H Keep Process + +_ _________________________________________________________________________ + + +1.9.1 File Control Block (FCB) + +The old file-related function requests require that a program maintain a +File Control Block (FCB) for each file; this control block contains such +information as a file's name, size, record length, and pointer to current +record. MS-DOS does most of this housekeeping for the newer, handle- +oriented function requests. + +Some descriptions of the old function requests refer to unopened and +opened FCBs. An unopened FCB contains only a drive specifier and +filename. An opened FCB contains all fields filled by Function 0FH (Open +File). + +The Program Segment Prefix (PSP) includes room for two FCBs at offsets +5CH and 6CH. For a description of how to use the PSP and FCB calls, see +Chapter 4, "MS-DOS Control Blocks and Work Areas," Table 1.14 +describes the FCB fields. + +Table 1.14 + +Format of the File Control Block (FCB) + +_ _________________________________________________________________________ + + Offset +Hex Dec Bytes Field + +_ _________________________________________________________________________ + +00H 0 1 Drive Number +01H 1 8 Filename +09H 9 3 Extension +0CH 12 2 Current Block + +0EH 14 2 Record Size +10H 16 4 File Size +14H 20 2 Date of Last Write +16H 22 2 Time of Last Write + +18H 24 8 Reserved +20H 32 1 Current Record +21H 33 4 Relative Record + +_ _________________________________________________________________________ + + + +16 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +Fields of the FCB + +Drive Number (offset 00H): Specifies the disk drive; 1 means drive A and 2 +means drive B. If you use the FCB to create or open a file, you can set this +field to 0 to specify the default drive; Function 0FH (Open File) sets the +field to the number of the default drive. + +Filename (offset 01H): Eight characters, left-aligned and padded (if neces- +sary) with blanks. If you specify a reserved device name (such as PRN), do +not put a colon at the end. + +Extension (offset 09H): Three characters, left-aligned and padded (if neces- +sary) with blanks. This field can be all blanks (no extension). + +Current Block (offset 0CH): Points to the block (group of 128 records) that +contains the current record. This field and the Current Record field (offset +1FH) make up the record pointer. This field is set to zero by the Open File +system call. + +Record Size (offset 0EH): The size of a logical record, in bytes. Set to 128 +by the Open File system call. If the record size is not 128 bytes, you must +set this field after opening the file. + +File Size (offset 0FH): The size of the file, in bytes. The first word of this +4-byte field is the low-order part of the size. + +Date of Last Write (offset 13H): The date the file was created or last +updated. The year, month, and day are mapped into two bytes as follows: + +Off set 14H Offset 13H +|Y|Y|Y|Y|Y|Y|Y|M| |M|M|M|D|D|D|D|D| +15 9 8 5 4 0 + +Time of Last Write (offset 15H): The time the file was created or last +updated. The hour, minutes, and seconds are mapped into two bytes as +follows: + +Offset 16H Offset 15H +|H|H|H|H|H|M|M|M| |M|M|M|S|S|S|S|S| +15 11 10 5 4 0 + +Reserved (offset 17H): These fields are reserved for use by MS-DOS. + +Current Record (offset 1FH): Points to one of the 128 records in the +current block. This field and the Current Block field (offset 0CH) make up +the record pointer. The Open File system call does not initialize this field. +You must set it before doing a sequential read or write to the file. + + + + 17 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +Relative Record (offset 20H): Points to the currently selected record, count- +ing from the beginning of the file (starting with 0). The Open File system +call does not initialize this field. You must set it before doing a random +read or write to the file. If the record size is less than 64 bytes, both words +of this field are used; if the record size is 64 bytes or more, only the first +three bytes are used. + +_ ________________________________________________________________ + +Note + + If you use the FCB at offset 5CH of the Program Segment Prefix, the + last byte of the Relative Record field is the first byte of the unformat- + ted parameter area that starts at offset 80H. This is the default Disk + Transfer Area. + +_ ________________________________________________________________ + + +Extended FCB + +The Extended File Control Block is used to create or search for directory +entries of files with special attributes. It adds the following 7-byte prefix to +the FCB: + +Name Bytes Offset + +_ ________________________________________________________________ + +Flag byte (FFH) 1 07H +Reserved 5 06H +Attribute byte 1 01H + +_ ________________________________________________________________ + +File attributes are described earlier in this chapter in Section 1.5.5, "File +Attributes." + +_ ________________________________________________________________ + +Note + + You must remember to point to the beginning of the extended FCB if + you are using Functions 0FH-16H with extended FCBs. + +_ ________________________________________________________________ + + + +18 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +1.10 Using the System Calls + +The remainder of this chapter describes how to use the system calls in +application programs, and it lists the calls in numeric and alphabetic +order, describing each call in detail. + +1.10.1 Issuing an Interrupt + +MS-DOS reserves Interrupts 28H through 3FH for its own use, and main- +tains the table of interrupt-handler addresses (the vector table) in loca- +tions 80H-FCH. Also, in case you need to write your own routines for +three particular MS-DOS interrupt handlers (Program Terminate, +CONTROL-C, and Critical Error), this chapter includes descriptions of each. +Function requests have superseded most of these interrupts. + +To issue an interrupt, move any required data into the registers and give +the INT instruction with the number of the interrupt you want. + +1.10.2 Calling a Function Request + +A function request is an MS-DOS routine for managing system resources. +Use the following procedure to call a function request: + + 1. Move any required data into the registers. + + 2. Move the function number into AH. + + 3. Move the action code, if required, into AL. + + 4. Issue Interrupt 21H. + + +1.10.3 Using the Calls from a High-Level Language + +The system calls can be executed from any high-level language whose +modules can be linked with assembly-language modules. In addition to this +linking technique, you can: + + o Use the DOSXQQ function of Pascal-86 to call a function request + directly. + + o Use the CALL statement or USER function to execute the required + assembly-language code from the BASIC interpreter. + + + + 19 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + + +1.10.4 Treatment of Registers + +When MS-DOS takes control after a function request, it switches to an +internal stack, and preserves any registers not used to return information +(except AX). The calling program's stack must be large enough to accom- +modate the interrupt system\(emat least 128 bytes in addition to other +needs. + +1.10.5 Handling Errors + +Most of the function requests introduced with version 2.0 or later set the +Carry flag if there is an error, identifying the specific error by returning a +number in the AX register. Table 1.15 lists these error codes and their +meanings. + +Table 1.15 + +Error Codes Returned in AX + +_ _________________________________________________________________________ + +Code Meaning + +_ _________________________________________________________________________ + + 1 Invalid function code + 2 File not found + 3 Path not found + 4 Too many open files (no open handles left) + 5 Access denied + 6 Invalid handle + 7 Memory control blocks destroyed + 8 Insufficient memory + 9 Invalid memory block address + +10 Invalid environment +11 Invalid format +12 Invalid access code +13 Invalid data +14 Reserved +15 Invalid drive +16 Attempt to remove the current directory +17 Not same device +18 No more files +19 Disk is write-protected + +20 Bad disk unit +21 Drive not ready +22 Invalid disk command +23 CRC error +24 Invalid length (disk operation) +25 Seek error +26 Not an MS-DOS disk +27 Sector not found +28 Out of paper +29 Write fault + +20 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +30 Read fault +31 General failure +32 Sharing violation +33 Lock violation +34 Wrong disk +35 FCB unavailable +36-49 Reserved + +50 Network request not supported +51 Remote computer not listening +52 Duplicate name on network +53 Network name not found +54 Network busy +55 Network device no longer exists +56 Net BIOS command limit exceeded +57 Network adapter hardware error +58 Incorrect response from network +59 Unexpected network error + +60 Incompatible remote adapter +61 Print queue full +62 Queue not full +63 Not enough space for print file +64 Network name was deleted +65 Access denied +66 Network device type incorrect +67 Network name not found +68 Network name limit exceeded +69 Net BIOS session limit exceeded + +70 Temporarily paused +71 Network request not accepted +72 Print or disk redirection is paused +73-79 Reserved + +80 File exists +81 Reserved +82 Cannot make +83 Interrupt 24 failure +84 Out of structures +85 Already assigned +86 Invalid password +87 Invalid parameter +88 Net write fault + +_ _________________________________________________________________________ + +To handle error conditions, put the following statement immediately after +calls that return errors: + +JC + + represents the label of an error-handling routine that gets the +specific error condition by checking the value in AX. This routine then + + 21 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +takes appropriate action. + +Some of the older system calls return a value in a register that specifies +whether the operation was successful. To handle such errors, check the +error code and take the appropriate action. + +Extended Error Codes + +Versions of MS-DOS after 2.0 have added new error messages. Any pro- +grams that use the older system calls cannot use these new error messages. +To avoid incompatibility, MS-DOS maps these new error codes to the old +error code that most closely matches the new one. + +Function 59H (Get Extended Error) has been added so that these new calls +can be used. It provides as much detail as possible about the most recent +error code returned by MS-DOS. The description of Function 59H lists the +new, more detailed error codes and shows how to use this function request. + +1.10.6 System Call Descriptions + +Most system calls require that you move information into one or more +registers before issuing the call that returns information in the registers. +The description of each system call in this chapter includes the following: + + o A diagram of the 8088 registers that shows their contents before + and after the system call + + o A more complete description of the register contents required + before the system call + + o A description of the processing performed + + o A more complete description of the register contents after the sys- + tem call + + o An example of how to use the system call + +The following figure is a sample illustration of the 8088 registers, showing +how the information is presented. Shaded areas indicate that the register +receives or returns information used by the call. + + _ _____________________ + + +22 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + _ _____________________ + + + Figure 1.1 Example of the 8088 Registers + + +1.10.6.1 Sample Programs + +The sample programs show only data declarations and the code that you +need to use the system calls. Unless stated otherwise, each example +assumes a common program skeleton that defines the segments and +returns control to MS-DOS. Each sample program is intended to be exe- +cuted as a .com file. Figure 1.2 shows a complete sample program. The +unshaded portion shows what appears in this chapter; the shaded portions +are the common skeleton. + +------------------------------------------------------------ +code segment + assume cs:code,ds:code,es:nothing,ss:nothing + org 100H +start: jmp begin +; +filename db "b:\textfile.asc",0 +buffer db 129 dup (?) +handle dw ? +; +begin: open_handle filename,0 ; Open the file + jc error_open ; Routine not shown + mov handle,ax ; Save handle +read_line: read_handle handle,buffer,128 ; Read 128 bytes + jc error_read ; Routine not shown + cmp ax,0 ; End of file? + je return ; Yes, go home + mov bx,ax ; No, AX bytes read + mov buffer[bx],"$" ; To terminate string + display buffer ; See Function 09H + jmp read_line ; Get next 128 bytes + +return: end_process 0 ; Return to MS-DOS +last_inst: ; To mark next byte +; +code ends + end start +------------------------------------------------------------ + + + Figure 1.2 Sample Program with Common Skeleton + +A macro has been defined for each system call to allow the examples to be +more complete programs, rather than isolated uses of the system calls. +These macros, plus some general-purpose ones, are used in the sample pro- +grams. For instance, the sample program in the preceding figure includes +four such macros: open_handle, read_handle, display, and end_process. + + 23 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +All the macro definitions are listed at the end of this chapter. + +The macros assume the environment for a .com program as described in +Chapter 4; in particular, they assume that all the segment registers con- +tain the same value. To conserve space, the macros generally leave error +checking to the main code and do not protect registers. This keeps the +macros short, yet useful. You may find that such macros are a convenient +way to include system calls in your assembly-language programs. + +1.10.6.2 Error Handling in Sample Programs + +Whenever a system call returns an error code, the sample program shows a +test for the error condition and a jump to an error routine. To conserve +space, the error routines themselves aren't shown. Some error routines +might simply display a message and continue processing. For more serious +errors, the routine might display a message and end the program (perform- +ing any required housekeeping, such as closing files). + +Tables 1.16 through 1.19 list the Interrupts and Function Requests in +numeric and alphabetic order. + +Table 1.16 + +MS-DOS Interrupts, Numeric Order + +_ _________________________________________________________________________ + +Interrupt Description + +_ _________________________________________________________________________ + +20H Program Terminate +21H Function Request +22H Terminate Process Exit Address +23H CONTROL-C Handler Address +24H Critical-Error-Handler Address +25H Absolute Disk Read +26H Absolute Disk Write +27H Terminate But Stay Resident +28H-3FH Reserved + +_ _________________________________________________________________________ + +Table 1.17 + +MS-DOS Interrupts, Alphabetic Order + +_ _________________________________________________________________________ + +Description Interrupt + +_ _________________________________________________________________________ + +Absolute Disk Read 25H +Absolute Disk Write 26H +CONTROL-C Handler Address 23H +Critical-Error-Handler Address 24H +Function Request 21H +Program Terminate 20H + +24 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +Reserved 28H-3FH +Terminate Process Exit Address 22H +Terminate But Stay Resident 27H + +_ _________________________________________________________________________ + +Table 1.18 + +MS-DOS Function Requests, Numeric Order + +_ _________________________________________________________________________ + +Function Description + +_ _________________________________________________________________________ + +00H Terminate Program + +01H Read Keyboard And Echo + +02H Display Character + +03H Auxiliary Input + +04H Auxiliary Output + +05H Print Character + +06H Direct Console I/O + +07H Direct Console Input + +08H Read Keyboard + +09H Display String + +0AH Buffered Keyboard Input + +0BH Check Keyboard Status + +0CH Flush Buffer, Read Keyboard + +0DH Reset Disk + +0EH Select Disk + +0FH Open File + +10H Close File + +11H Search For First Entry + +12H Search For Next Entry + +13H Delete File + +14H Sequential Read + +15H Sequential Write + +16H Create File + +17H Rename File + +18H Reserved + +19H Get Current Disk + +1AH Set Disk Transfer Address + +1BH Get Default Drive Data + +1CH Get Drive Data + +1DH-20H Reserved + +21H Random Read + + 25 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +22H Random Write + +23H Get File Size + +24H Set Relative Record + +25H Set Interrupt Vector + +26H Create New PSP + +27H Random Block Read + +28H Random Block Write + +29H Parse File Name + +2AH Get Date + +2BH Set Date + +2CH Get Time + +2DH Set Time + +2EH Set/Reset Verify Flag + +2FH Get Disk Transfer Address + +30H Get MS-DOS Version Number + +31H Keep Process + +32H Reserved + +33H CONTROL-C Check + +34H Reserved + +35H Get Interrupt Vector + +36H Get Disk Free Space + +37H Reserved + +38H Get/Set Country Data + +39H Create Directory + +3AH Remove Directory + +3BH Change Current Directory + +3CH Create Handle + +3DH Open Handle + +3EH Close Handle + +3FH Read Handle + +40H Write Handle + +41H Delete Directory Entry (Unlink) + +42H Move File Pointer + +43H Get/Set File Attributes (Chmod) + +4400H,4401H IOCtl Data + +4402H,4403H IOCtl Character + +4404H,4405H IOCtl Block + +4406H,4407H IOCtl Status + +4408H IOCtl Is Changeable + +4409H IOCtl Is Redirected Block + +26 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +440AH IOCtl Is Redirected Handle + +440BH IOCtl Retry + +440CH Generic IOCtl (for code page functions) + +440DH Generic IOCtl (for devices) + +440EH Get IOCtl Drive Map + +440FH Set IOCtl Drive Map + +45H Duplicate File Handle + +46H Force Duplicate File Handle + +47H Get Current Directory + +48H Allocate Memory + +49H Free Allocated Memory + +4AH Set Block + +4BH Load and Execute Program + +4B03H Load Overlay + +4CH End Process + +4DH Get Return Code of Child Process + +4EH Find First File + +4FH Find Next File + +50H-53H Reserved + +54H Get Verify State + +55H Reserved + +56H Change Directory Entry + +57H Get/Set Date/Time of File + +58H Get/Set Allocation Strategy + +59H Get Extended Error + +5AH Create Temporary File + +5BH Create New File + +5C00H Lock + +5C01H Unlock + +5DH Reserved + +5E00H Get Machine Name + +5E02H Printer Setup + +5F02H Get Assign-List Entry + +5F03H Make Assign-List Entry + +5F04H Cancel Assign-List Entry + +60H-61H Reserved + +62H Get PSP + +63H,64H Reserved + +65H Get Extended Country Information + +66H Get/Set Global Code Page + + 27 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +67H Set Handle Count + +68H Commit File + +69H-7FH Reserved + +_ _________________________________________________________________________ + +Table 1.19 + +MS-DOS Function Requests, Alphabetic Order + +_ _________________________________________________________________________ + +Description Interrupt + +_ _________________________________________________________________________ + +Allocate Memory 48H + +Auxiliary Input 03H + +Auxiliary Output 04H + +Buffered Keyboard Input 0AH + +Cancel Assign-List Entry 5F04H + +Change Current Directory 3BH + +Change Directory Entry 56H + +Check Keyboard Status 0BH + +Close File 10H + +Close Handle 3EH + +Commit FIle 68H + +CONTROL-C Check 33H + +Create Directory 39H + +Create File 16H + +Create Handle 3CH + +Create New File 5BH + +Create New PSP 26H + +Create Temporary File 5AH + +Delete Directory Entry (Unlink) 41H + +Delete File 13H + +Direct Console I/O 06H + +Direct Console Input 07H + +Display Character 02H + +Display String 09H + +Duplicate File Handle 45H + +End Process 4CH + +Find First File 4EH + +Find Next File 4FH + +Flush Buffer, Read Keyboard 0CH + +Force Duplicate File Handle 46H + + +28 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +Free Allocated Memory 49H + +Generic IOCtl (for devices) 440DH + +Generic IOCtl (for code page functions) 440CH + +Get Assign-List Entry 5F02H + +Get Current Directory 47H + +Get Current Disk 19H + +Get Date 2AH + +Get Default Drive Data 1BH + +Get Disk Free Space 36H + +Get Disk Transfer Address 2FH + +Get Drive Data 1CH + +Get Extended Country Information 65H + +Get Extended Error 59H + +Get File Size 23H + +Get Interrupt Vector 35H + +Get IOCtl Drive Map 440EH + +Get Machine Name 5E00H + +Get MS-DOS Version Number 30H + +Get PSP 62H + +Get Return Code of Child Process 4DH + +Get Time 2CH + +Get Verify State 54H + +Get/Set Allocation Strategy 58H + +Get/Set Country Data 38H + +Get/Set Date/Time Of File 57H + +Get/Set File Attributes (Chmod) 43H + +Get/Set Global Code Page 66H + +IOCtl Block 4404H,4405H + +IOCtl Character 4402H,4403H + +IOCtl Data 4400H,4401H + +IOCtl Is Changeable 4408H + +IOCtl Is Redirected Block 4409H + +IOCtl Is Redirected Handle 440AH + +IOCtl Retry 440BH + +IOCtl Status 4406H,4407H + +Keep Process 31H + +Load and Execute Program 4BH + +Load Overlay 4B03H + +Lock 5C00H + +Make Assign-List Entry 5F03H + + 29 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +Move File Pointer 42H + +Open File 0FH + +Open Handle 3DH + +Parse File Name 29H + +Print Character 05H + +Printer Setup 5E02H + +Random Block Read 27H + +Random Block Write 28H + +Random Read 21H + +Random Write 22H + +Read Handle 3FH + +Read Keyboard 08H + +Read Keyboard And Echo 01H + +Remove Directory 3AH + +Rename File 17H + +Reserved 18H + +Reserved 1DH-20H + +Reserved 32H + +Reserved 34H + +Reserved 37H + +Reserved 50H-53H + +Reserved 55H + +Reserved 5DH + +Reserved 60H-61H + +Reserved 63H, 64H + +Reserved 69H-7FH + +Reset Disk 0DH + +Search for First Entry 11H + +Search for Next Entry 12H + +Select Disk 0EH + +Sequential Read 14H + +Sequential Write 15H + +Set Block 4AH + +Set Date 2BH + +Set Disk Transfer Address 1AH + +Set Handle Count 67H + +Set Interrupt Vector 25H + +Set IOCtl Drive Map 440FH + +Set Relative Record 24H + +Set Time 2DH + +30 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +Set/Reset Verify Flag 2EH + +Terminate Program 00H + +Unlock 5C01H + +Write Handle 40H + +_ _________________________________________________________________________ + +A detailed description of each system call follows. These calls are listed in +numeric order, interrupts first, followed by function requests. + +_ ________________________________________________________________ + +Note + + Unless stated otherwise, in the system call descriptions\(emboth text and + code\(emall numbers are in hexadecimal. + +_ ________________________________________________________________ + + +1.11 Interrupts + +The following pages describe Interrupts 20H-27H. + + + 31 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + + +Program Terminate (Interrupt 20H) + + Call: + + CS + Segment address of Program Segment Prefix + + Return: + + None + + + +Comments: + +Interrupt 20H terminates the current process and returns control to its +parent process. It also closes all open file handles and clears the disk cache. +When this interrupt is issued, CS must contain the segment address of the +Program Segment Prefix. + +Interrupt 20H is provided only for compatibility with MS-DOS versions +prior to 2.0. New programs should use Function 4CH (End Process), +which permits returning a completion code to the parent process and does +not require CS to contain the segment address of the Program Segment +Prefix. + +The following exit addresses are restored from the Program Segment +Prefix: + +Offset + Exit Address +_ ________________________________________________________________ + +0AH Program terminate + +0EH CONTROL-C + +12H Critical error + +All file buffers are flushed to disk. + +_ ________________________________________________________________ + +32 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +Note + + You should close all files that have changed in length before issuing + this interrupt. If you do not close a changed file, its length may not be + recorded correctly in the directory. See Functions 10H and 3EH for a + description of the Close File system calls. If sharing is loaded, you + should remove all locks before using Interrupt 20H. See Function 5CH + (Lock) for more information. + +_ ________________________________________________________________ + + +Macro Definition: + + +terminate macro + int 20H + endm + + +Example: + +The following program displays a message and returns to MS-DOS. It uses +only the opening portion of the sample program skeleton shown in Figure +1.2: + +message db "displayed by INT20H example". 0DH, 0AH, "$" +; +begin: display message ;see Function 09H + terminate ;THIS INTERRUPT +code ends + end start + + + + 33 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + + +Function Request (Interrupt 21H) + + Call: + + AH + Function number + + Other registers + As specified in individual function + + Return: + + None. + + + +Comments: + +As specified in individual function. Interrupt 21H causes MS-DOS to carry +out the function request whose number is in AH. See Section 1.12, "Func- +tion Requests," for a description of the MS-DOS functions. + +Example: + +To call the Get Time function: + +mov ah,2CH ;Get Time is Function 2CH +int 21H ;MS-DOS function request + + + +34 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +Terminate Process Exit Address (Interrupt +22H) + +This interrupt may be issued only by MS-DOS; user programs must never +issue it. If you must write your own terminate interrupt handler, use +Function 35H (Get Interrupt Vector) to get the address of the standard +routine, save the address, then use Function 25H (Set Interrupt Vector) to +change the Interrupt 22H entry in the vector table so that it points to your +routine. + +When a program terminates, MS-DOS transfers control to the routine that +starts at the address in the Interrupt 22H entry in the vector table. When +MS-DOS creates a program segment, it copies this address into the Pro- +gram Segment Prefix, starting at offset 0AH. + + + 35 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + + +CONTROL-C Handler Address (Interrupt 23H) + +When you type CONTROL-C or CONTROL-BREAK (on IBM-compatibles), +MS-DOS transfers control as soon as possible to the routine that starts at +the address in the Interrupt 23H entry in the vector table. When MS-DOS +creates a program segment, it copies the address currently in the interrupt +table into the Program Segment Prefix, starting at offset 0EH. + +This interrupt may be issued only by MS-DOS; user programs must never +issue it. If you must write your own CONTROL-C interrupt handler, use +Function Request 35H (Get Interrupt Vector) to get the address of the +standard routine, save the address, then use Function Request 25H (Set +Interrupt Vector) to change the Interrupt 23H entry in the vector table to +point to your routine. + +If the CONTROL-C routine preserves all registers, it can end with an IRET +instruction (return from interrupt) to continue program execution. If a +user-written interrupt program returns with a long return, the program +uses the carry flag to determine whether or not the program will abort. If +the carry flag is set, it will abort; otherwise, execution will continue as +with a return by IRET. + +If a user-written CONTROL-BREAK routine interrupts function calls 09H, +0AH, or buffered I/O, and if it continues execution with an IRET, then +I/O continues from the start of the line. MS-DOS always outputs a +CONTROL-C to the screen when it issues an Interrupt 23H. There is no way +to turn this off. + +When the interrupt occurs, all registers are set to the value they had when +the original call to MS-DOS was made. There are no restrictions on what +a CONTROL-C handler can do\(emincluding calling MS-DOS functions\(emas +long as the program restores the registers. + +If a CONTROL-C interrupts Function 09H or 0AH (Display String or +Buffered Keyboard Input), the three-byte sequence 03H-0DH-0AH (usually +displayed as C followed by a carriage-return) is sent to the display and the +function resumes at the beginning of the next line. + +Suppose a program uses Function 4BH (Load and Execute Program) to +create a second Program Segment Prefix and execute a second program, +which then changes the CONTROL-C address in the vector table. MS-DOS +restores this CONTROL-C vector to its original value before returning con- +trol to the calling program. + + +36 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +Critical-Error-Handler Address (Interrupt 24H) + +If a critical error occurs during execution of an I/O function request (this +often means a fatal disk error), MS-DOS transfers control to the routine at +the address in the Interrupt 24H entry in the vector table. When MS-DOS +creates a program segment, it copies this address into the Program Seg- +ment Prefix, starting at offset 12H. + +This interrupt may be issued only by MS-DOS; user programs must never +issue it. If you must write your own critical-error interrupt handler, use +Function 35H (Get Interrupt Vector) to get the address of the standard +routine, save the address, then use Function 25H (Set Interrupt Vector) to +change the Interrupt 24H entry in the vector table to point to your rou- +tine. + +MS-DOS does not issue Interrupt 24H if a failure occurs during execution +of Interrupt 25H (Absolute Disk Read) or Interrupt 26H (Absolute Disk +Write). A command.com error routines handles these errors. This routine +retries the disk operation, then gives you the choice of aborting the opera- +tion, retrying it, allowing the system call to fail and the application pro- +cess to continue, or ignoring the error. + +The following topics describe the requirements of an Interrupt 24H rou- +tine, including the error codes, registers, and stack. + +1.11.1 Conditions upon Entry + +After retrying an I/O error five times, MS-DOS issues Interrupt 24H, +unless a File Allocation Table (FAT) or directory sector is involved. In +those cases, DOS performs three retries. The interrupt handler receives +control with interrupts disabled. AX and DI contain error codes, and BP +contains the offset (to the segment address in SI) of a Device Header con- +trol block that describes the device on which the error occurred. + +1.11.2 Requirements for an Interrupt 24H Handler + +To issue the "Abort, Retry, Fail or Ignore" prompt to a user, a user- +written critical-error handler should first push the flags and execute a FAR +call to the address of the standard Interrupt 24H handler (the user pro- +gram that changed the Interrupt 24H vector also should have saved this +address). After a user responds to the prompt, MS-DOS returns control to +the user-written routine. + +_ ________________________________________________________________ + +Note + + + 37 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + + There are source applications which will have trouble handling critical + errors, since this changes the stack frame. + +_ ________________________________________________________________ + +The error handler can then do its processing, but before it does anything +else it must preserve BX, CX, DX, DS, ES, SS, and SP. Also, the error +handler may use only function calls 01-0CH (inclusive) and 59H (if it uses +any others, the error handler destroys the MS-DOS stack and leaves +MS-DOS in an unstable state). The contents of the Device Header should +not be changed. + +It is recommended that Interrupt 24H routine fail critical errors and let +the application test for an extended error code when the Interrupt 21H +routine returns. + +User Stack + +This call uses the user stack that contains the following (starting with the +top of the stack): + +IP MS-DOS registers from issuing Interrupt 24H +CS +FLAGS + +AX User registers at time of original +BX INT 21H +CX +DX +SI +DI +BP +DS +ES + +IP From the original INT 21H +CS from the user to MS-DOS +FLAGS + +The registers are set such that if the user-written error handler issues an +IRET, MS-DOS responds according to the value in AL: + +AL + Action +_ ________________________________________________________________ + +0 Ignore the error. + +1 Retry the operation. + +2 Abort the program by issuing Interrupt 23H. + + + +38 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +3 Fail the system call that is in progress. + +Note that the ignore option may cause unexpected results, such as causing +MS-DOS to behave as if an operation had completed successfully. + +Disk Error Code in AX + +If bit 7 of AH is 0, the error occurred on a disk drive. AL contains the fail- +ing drive (0=A, 1=B, etc.). Bit 0 of AH specifies whether the error +occurred during a read or write operation (0=read, 1=write), and bits 1 +and 2 of AH identify the area of the disk where the error occurred: + +Bits 1-2 + Location of error +_ ________________________________________________________________ + +00 MS-DOS area + +01 File Allocation Table + +10 Directory + +11 Data area + +Bits 3-5 of AH specify valid responses to the error prompt: + +Bit Value Response + +_ ________________________________________________________________ + +3 0 Fail not allowed + 1 Fail allowed + +4 0 Retry not allowed + 1 Retry allowed + +5 0 Ignore not allowed + 1 Ignore allowed + +_ ________________________________________________________________ + +If you specify Retry but it isn't allowed, MS-DOS changes it to Fail. If you +specify Ignore but it isn't allowed, MS-DOS changes it to Fail. If you +specify Fail but it isn't allowed, MS-DOS changes it to Abort. The Abort +response is always allowed. + +Other Device Error Code in AX + +If bit 7 of AH is 1, either the memory image of the File Allocation Table +(FAT) is bad or an error occurred on a character device. The device header +pointed to by BP:SI contains a WORD of attribute bits that identify the +type of device and, therefore, the type of error. + + + + 39 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +The word of attribute bits is at offset 04H of the Device Header. Bit 15 +specifies the type of device (0=block, 1=character). + +If bit 15 is 0 (block device), the error was a bad memory image of the FAT. + +If bit 15 is 1 (character device), the error was on a character device. DI +contains the error code, the contents of AL are undefined, and bits 0-3 of +the attribute word have the following meaning: + +Bit + Meaning if Set +_ ________________________________________________________________ + +0 Current standard input + +1 Current standard output + +2 Current null device + +3 Current clock device + +See Chapter 2, "MS-DOS Device Drivers," for a complete description of +the Device Header control block. + +Error Code in DI + +The high byte of DI is undefined. The low byte contains the following error +codes: + +Error code + Description +_ ________________________________________________________________ + +0 Attempt to write on write-protected disk + +1 Unknown unit + +2 Drive not ready + +3 Unknown command + +4 CRC error in data + +5 Bad drive request structure length + +6 Seek error + +7 Unknown media type + +8 Sector not found + +9 Printer out of paper + +A Write fault + +B Read fault + +C General failure + +A user-written Interrupt 24H handler can use Function 59H (Get Extended + +40 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +Error) to get detailed information about the error that caused the inter- +rupt to be issued. + + + 41 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + + +Absolute Disk Read (Interrupt 25H) + + Call: + + AL + Drive number + DS:BX + Disk Transfer Address + CX + Number of sectors + DX + Beginning relative sector + + Return: + + AL + Error code if CF=1 + Flags + CF = 0 if successful + = 1 if not successful + + +Comments: + +The registers must contain the following: + +Register + Contents +_ ________________________________________________________________ + +AL Drive number (0=A, 1=B, etc.) + +BX Offset of Disk Transfer Address (from segment address in DS) + +CX Number of sectors to read + +DX Beginning relative sector + +_ ________________________________________________________________ + +Warning + + Avoid using this function unless absolutely necessary. Instead, you + should access files through normal MS-DOS function requests. There + is no guarantee of upward compatibility for the Absolute Disk I/O in + future releases of MS-DOS. + +_ ________________________________________________________________ + +Interrupt 25H transfers control to the device driver and reads from the +disk to the Disk-Transfer Address the number of sectors specified in CX. +The interrupt has the same requirements as and processes identically to + +42 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +Interrupt 26H (Absolute Disk Write), except that it reads data rather than +writes it. Also, since this interrupt does not check your input parameters +too closely, make sure they are reasonable. If you use unreasonable +parameters, you may get strange results or cause your system to crash. + +_ ________________________________________________________________ + +Note + + This call destroys all registers except the segment registers. So before + issuing the interrupt, save any registers that your program uses. + +_ ________________________________________________________________ + +The system pushes the flags at the time of the call; they are still there upon +return. To prevent uncontrolled growth, be sure to pop the stack upon +return. + +If the disk operation is successful, the Carry Flag (CF) is 0. If the disk +operation is not successful, CF is 1 and AL contains the MS-DOS error +code (see Interrupt 24H earlier in this section for the codes and their +meanings). + +Macro Definition: + + +abs_disk_read macro disk,buffer,num_sectors,first_sector + mov al,disk + mov bx,offset buffer + mov cx,num_sectors + mov dx,first_sector + int 25H + popf + endm + + +Example: + +The following program copies the contents of a single-sided disk in drive A +to the disk in drive B. + +prompt db "Source in A, target in B",0DH,0AH + db "Any key to start. $" +first dw 0 +buffer db 60 dup (512 dup (?)) ;60 sectors +; +begin: display prompt ;see Function 09H + read_kbd ;see Function 08H + mov cx,6 ;copy 6 groups of + ;60 sectors +copy: push cx ;save the loop counter + abs_disk_read 0,buffer,60,first ;THIS INTERRUPT + + 43 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + + abs_disk_write 1,buffer,60,first ;see INT 26H + add first,60 ;do the next 60 sectors + pop cx ;restore the loop counter + loop copy + + + +44 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +Absolute Disk Write (Interrupt 26H) + + Call: + + AL + Drive number + DS:BX + Disk Transfer Address + CX + Number of sectors + DX + Beginning relative sector + + Return: + + AL + Error code if CF = 1 + FLAGS + CF = 0 if successful + = 1 if not successful + + +Comments: + +_ ________________________________________________________________ + +Warning + + Avoid using this function unless absolutely necessary. Instead, you + should access files through normal MS-DOS function requests. There + is no guarantee of upward compatibility for the Absolute Disk I/O in + future releases of MS-DOS. + +_ ________________________________________________________________ + +The registers must contain the following: + +Register + Contents +_ ________________________________________________________________ + +AL Drive number (0=A, 1=B, etc.) + +BX Offset of Disk Transfer Address (from segment address in DS) + +CX Number of sectors to write + +DX Beginning relative sector + +This interrupt transfers control to MS-DOS. The number of sectors +specified in CX is written from the Disk Transfer Address to the disk. Its +requirements and processing are identical to Interrupt 25H (Absolute Disk + + 45 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +Read), except data is written to the disk rather than read from it. Also, +since Interrupt 26H does not check your input parameters too closely, +make sure they are reasonable. If you use unreasonable parameters, you +may get strange results or cause your system to crash. + +_ ________________________________________________________________ + +Note + + This call destroys all registers except the segment registers. So before + issuing the interrupt, be sure to save any registers your program uses. + +_ ________________________________________________________________ + +The system pushes the flags at the time of the call; they are still there upon +return. To prevent uncontrolled growth, be sure to pop the stack upon +return. + +If the disk operation is successful, the Carry Flag (CF) is 0. If the disk +operation is not successful, CF is 1 and AL contains the MS-DOS error +code (see Interrupt 24H for the codes and their meanings). + +Macro Definition: + + +abs_disk_write macro disk,buffer,num_sectors,first_sector + mov al,disk + mov bx,offset buffer + mov cx,num_sectors + mov dx,first_sector + int 26H + popf + endm + + +Example: + +The following program copies the contents of a single-sided disk in drive A +to the disk in drive B, verifying each write. It uses a buffer of 32K bytes. + +off equ 0 +on equ 1 +; +prompt db "Source in A, target in B",0DH,0AH + db "Any key to start. $" +first dw 0 +buffer db 60 dup (512 dup (?)) ;60 sectors +; +begin: display prompt ;see Function 09H + read_kbd ;see Function 08H + verify on ;see Function 2EH + mov cx,6 ;copy 6 groups of 60 sectors + +46 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +copy: push cx ;save the loop counter + abs_disk_read 0,buffer,60,first ;see INT 25H + abs_disk_write 1,buffer,60,first ;THIS INTERRUPT + add first,60 ;do the next 60 sectors + pop cx ;restore the loop counter + loop copy + verify off ;see Function 2EH + + + + 47 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + + +Terminate But Stay Resident (Interrupt 27H) + + Call: + + CS:DX + Pointer to first byte following + last byte of code. + + Return: + + None + + + +Comments: + +This interrupt is provided only for compatibility with MS-DOS versions +prior to 2.0. Unless your resident program must be compatible with +MS-DOS versions before 2.0, you should use Function 31H (Keep Process) +to install it. Function 31H lets programs larger than 64K remain resident +and allows return information to be passed. + +However, Interrupt 27H, which is often used to install device-specific inter- +rupt handlers, forces programs that are up to 64K to remain resident after +they terminate. + +DX must contain the offset (from the segment address in CS) of the first +byte that follows the last byte of code in the program. When Interrupt +27H is executed, the program terminates and control returns to MS-DOS, +but the program is not overlaid by other programs. Files left open are not +closed. When the interrupt is called, CS must contain the segment +address of the Program Segment Prefix (the value of DS and ES when exe- +cution started). + +.Exe programs that are loaded into high memory must not use this inter- +rupt. Similarly, since it restores the Interrupt 22H, 23H, and 24H vectors, +you should not use Interrupt 27H to install new CONTROL-C or critical- +error handlers. + + +48 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +Macro Definition: + + +stay_resident macro last_instruc + mov dx,offset last_instruc + inc dx + int 27H + endm + + +Example: + +Since the most common use of Interrupt 27H is to install a machine- +specific routine, there is no general example that applies. The macro +definition, however, shows the calling syntax. + +1.12 Function Requests + +The following pages describe function calls 00H-68H. + + + 49 + +_ _ | | _ _ + + + diff --git a/PROGREF/1B_CALLS.A b/PROGREF/1B_CALLS.A new file mode 100644 index 0000000..aa93e56 --- /dev/null +++ b/PROGREF/1B_CALLS.A @@ -0,0 +1,2688 @@ + +_ _ | | _ _ + + + + _ ______________ + + +Terminate Program (Function 00H) + + Call: + + AH = 00H + CS + Segment address of + Program Segment Prefix + + Return: + + None + + + +Comments: + +Function 00H performs the same function as Interrupt 20H. It terminates +the current process and returns control to its parent process. It also closes +all open file handles and clears the disk cache. When this interrupt is +issued, CS must contain the segment address of the Program Segment +Prefix. + +The CS register must contain the segment address of the Program Seg- +ment Prefix before you call this interrupt. + +The following exit addresses are restored from the specified offsets in the +Program Segment Prefix: + +Offset + Exit Address +_ ________________________________________________________________ + +0AH Program terminate + +0EH CONTROL-C + +12H Critical error + +All file buffers are flushed to disk. + + + 1 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +_ ________________________________________________________________ + +Warning + + Close all files that have changed in length before calling this function. + If you do not close a changed file, its length is not correctly recorded in + the directory. See Function 10H for a description of the Close File sys- + tem call. + +_ ________________________________________________________________ + + +Macro Definition: + + +terminate_program macro + xor ah,ah + int 21H + endm + + +Example: + +The following program displays a message and returns to MS-DOS. It uses +only the opening portion of the sample program skeleton shown in Figure +1.2. + +message db "Displayed by FUNC00H example", 0DH,0AH,"$" +; +begin: display message ;see Function 09H + terminate_program ;THIS FUNCTION +code ends + end start + + + +2 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Read Keyboard and Echo (Function 01H) + + Call: + + AH = 01H + + Return: + + AL + Character typed + + + +Comments: + +Function 01H waits for a character to be read from standard input, then +echoes the character to standard output and returns it in AL. If the char- +acter is CONTROL-C, it executes Interrupt 23H. + +Macro Definition: + + +read_kbd_and_echo macro + mov ah, 01H + int 21H + endm + + +Example: + +The following program displays and prints characters as you type them. If +you press the RETURN key, the program sends a linefeed/carriage-return +sequence to both the display and the printer. + +begin: read_kbd_and_echo ;THIS FUNCTION + print_char al ;see Function 05H + cmp al,0DH ;is it a CR? + jne begin ;no, print it + print_char 0AH ;see Function 05H + display_char 0AH ;see Function 02H + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + jmp begin ;get another character + + + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Display Character (Function 02H) + + Call: + + AH = 02H + DL + Character to be displayed + + Return: + + None + + + +Comments: + +Function 02H sends the character in DL to standard output. If you press +CONTROL-C, it issues Interrupt 23H. + +Macro Definition: + + +display_char macro character + mov dl,character + mov ah,02H + int 21H + endm + + +Example: + +The following program converts lowercase characters to uppercase before +displaying them. + +begin: read_kbd ;see Function 08H + cmp al,"a" + jl uppercase ;don't convert + cmp al,"z" + jg uppercase ;don't convert + sub al,20H ;convert to ASCII code + ;for uppercase + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +uppercase: display_char al ;THIS FUNCTION + jmp begin: ;get another character + + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Auxiliary Input (Function 03H) + + Call: + + AH = 03H + + Return: + + AL + Character from auxiliary device + + + +Comments: + +Function 03H waits for a character from standard auxiliary devices (AUX, +COM1, COM2, COM3, COM4), then returns the character in AL. This +system call does not return a status or error code. + +If you press CONTROL-C, it issues Interrupt 23H. + +Macro Definition: + + +aux_input macro + mov ah,03H + int 21H + endm + + +Example: + +The following program prints characters as soon as it receives them from +the auxiliary device. It stops printing when it receives an end-of-file char- +acter (ASCII 26, or CONTROL-Z). + +begin: aux_input ;THIS FUNCTION + cmp al,1AH ;end of file? + je return ;yes, all done + print_char al ;see Function 05H + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + jmp begin ;get another character + + + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Auxiliary Output (Function 04H) + + Call: + + AH = 04H + DL + Character for auxiliary device + + Return: + + None + + + +Comments: + +Function 04H sends the character in DL to standard auxiliary. This sys- +tem call does not return a status or error code. + +If you press CONTROL-C, it issues Interrupt 23H. + +Macro Definition: + + +aux_output macro character + mov dl,character + mov ah,04H + int 21H + endm + + +Example: + +The following program gets a series of strings of up to 80 bytes from the +keyboard and sends each string to the auxiliary device. It stops when you +type a null string (carriage-return only). + +string db 81 dup(?) ;see Function 0AH +; +begin: get_string 80,string ;see Function 0AH + cmp string[1],0 ;null string? + + 9 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + je return ;yes, all done + mov cx, word ptr string[1] ;get string length + mov bx,0 ;set index to 0 +send_it: aux_output string[bx+2] ;THIS FUNCTION + inc bx ;bump index + loop send_it ;send another character + jmp begin ;get another string + + + +10 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Print Character (Function 05H) + + Call: + + AH = 05H + DL + Character for printer + + Return: + + None + + + +Comments: + +Function 05H sends the character in DL to the standard printer. If you +press CONTROL-C, it issues Interrupt 23H. This function does not return a +status or error code. + +Macro Definition: + + +print_char macro character + mov dl,character + mov ah,05H + int 21H + endm + + +Example: + +The following program prints a walking test pattern on the printer. It +stops if you press CONTROL-C. + +line_num db 0 +; +begin: mov cx,60 ;print 60 lines +start_line: mov bl,33 ;first printable ASCII + ;character (!) + add bl,line_num ;to offset one character + + 11 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + push cx ;save number-of-lines counter + mov cx,80 ;loop counter for line +print_it: print_char bl ;THIS FUNCTION + inc bl ;move to next ASCII character + cmp bl,126 ;last printable ASCII + ;character (~) + jl no_reset ;not there yet + mov bl,33 ;start over with (!) +no_reset: loop print_it ;print another character + print_char 0DH ;carriage return + print_char 0AH ;linefeed + inc line_num ;to offset 1st char. of line + pop cx ;restore #-of-lines counter + loop start_line ;print another line + + + +12 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Direct Console I/O (Function 06H) + + Call: + + AH = 06H + DL + See text + + Return: + + AL + If DL = FFH before call, + then zero flag not set means AL + has character from standard input. + Zero flag set means there was not + a character to get, and AL = 0. + + + +Comments: + +The action of Function 06H depends on the value in DL when the function +is called: + +Value in DL + Action +_ ________________________________________________________________ + +FFH If a character has been read from standard input, it is + returned in AL and the zero flag is cleared (0); if a + character has not been read, the zero flag is set (1). + +Not FFH The character in DL is sent to standard output. + +This function does not check for CONTROL-C. + +Macro Definition: + + +dir_console_io macro switch + mov dl,switch + mov ah,06H + int 21H + endm + + + + 13 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program sets the system clock to 0 and displays the time +continuously. When you type any character, the display freezes; when you +type any character again, the clock is reset to 0 and the display starts +again. + +time db "00:00:00.00",0DH,0AH,"$" ;see Function 09H +; ;for explanation of $ +; +begin: set_time 0,0,0,0 ;see Function 2DH +read_clock: get_time ;see Function 2CH + CONVERT ch,time ;see end of chapter + CONVERT cl,time[3] ;see end of chapter + CONVERT dh,time[6] ;see end of chapter + CONVERT dl,time[9] ;see end of chapter + display time ;see Function 09H + dir_console_io FFH ;THIS FUNCTION + cmp al,0 ;character typed? + jne stop ;yes, stop timer + jmp read_clock ;no, keep timer + ;running +stop: read_kbd ;see Function 08H + jmp begin ;start over + + + +14 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Direct Console Input (Function 07H) + + Call: + + AH = 07H + + Return: + + AL + Character from keyboard + + + +Comments: + +Function 07H waits for a character to be read from standard input, then +returns it in AL. This function does not echo the character or check for +CONTROL-C. (For a keyboard input function that echoes or checks for +CONTROL-C, see Function 01H or 08H.) + +Macro Definition: + + +dir_console_input macro + mov ah,07H + int 21H + endm + + +Example: + +The following program prompts for a password (eight characters max- +imum) and places the characters into a string without echoing them. + +password db 8 dup(?) +prompt db "Password: $" ;see Function 09H for + ;explanation of $ +begin: display prompt ;see Function 09H + mov cx,8 ;maximum length of password + xor bx,bx ;so BL can be used as index + + 15 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +get_pass: dir_console_input ;THIS FUNCTION + cmp al,0DH ;was it a carriage return? + je return ;yes, all done + mov password[bx],al ;no, put character in string + inc bx ;bump index + loop get_pass ;get another character + + + +16 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Read Keyboard (Function 08H) + + Call: + + AH = 08H + + Return: + + AL + Character from keyboard + + + +Comments: + +Function 08H waits for a character to be read from standard input, then +returns it in AL. If you press CONTROL-C, it issues Interrupt 23H. This +function does not echo the character. (For a keyboard input function that +echoes the character or checks for CONTROL-C, see Function 01H.) + +Macro Definition: + + +read_kbd macro + mov ah,08H + int 21H + endm + + +Example: + +The following program prompts for a password (eight characters max- +imum) and places the characters into a string without echoing them. + +password db 8 dup(?) +prompt db "Password: $" ;see Function 09H + ;for explanation of $ +begin: display prompt ;see Function 09H + mov cx,8 ;maximum length of password + xor bx,bx ;BL can be an index + + 17 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +get_pass: read_kbd ;THIS FUNCTION + cmp al,0DH ;was it a carriage return? + je return ;yes, all done + mov password[bx],al ;no, put char. in string + inc bx ;bump index + loop get_pass ;get another character + + + +18 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Display String (Function 09H) + + Call: + + AH = 09H + DS:DX + Pointer to string to be displayed + + Return: + + None + + + +Comments: + +Function 09H sends to standard output a string that ends with "$" (the $ +is not displayed). + +The DX register must contain the offset (from the segment address in DS) +of the string. + +Macro Definition: + + +display macro string + mov dx,offset string + mov ah,09H + int 21H + endm + + +Example: + +The following program displays the hexadecimal code of the key that is +typed. + +table db "0123456789ABCDEF" +result db " - 00H",0DH,0AH,"$" ;see text for + ;explanation of $ +begin: read_kbd_and_echo ;see Function 01H + + 19 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + xor ah,ah ;clear upper byte + convert ax,16,result[3] ;see end of chapter + display result ;THIS FUNCTION + jmp begin ;do it again + + + +20 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Buffered Keyboard Input (Function 0AH) + + Call: + + AH = 0AH + DS:DX + Pointer to input buffer + + Return: + + None + + + +Comments: + +Function 0AH gets a string from standard input. DX must contain the +offset (from the segment address in DS) of an input buffer of the following +form: + +Byte + Contents +_ ________________________________________________________________ + +1 Maximum number of characters in buffer, including the carriage + return (you must set this value). + +2 Actual number of characters typed, not counting the carriage + return (the function sets this value). + +3-n Buffer; must be at least as long as the number in byte 1. + +Characters are read from standard input and placed in the buffer begin- +ning at the third byte until a RETURN character (ASCII 0DH) is read. If the +buffer fills to one less than the maximum, additional characters read are +ignored and ASCII 07H (Bel) is sent to standard output until a RETURN +character is read. If you type the string at the console, it can be edited as +it is being entered. If you press CONTROL-C, it issues Interrupt 23H. + +MS-DOS sets the second byte of the buffer to the number of characters +read (not counting the carriage return). + + + 21 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +get_string macro limit,string + mov dx,offset string + mov string,limit + mov ah,0AH + int 21H + endm + + +Example: + +The following program gets a 16-byte (maximum) string from the key- +board and fills a 24-line by 80-character screen with it. + +buffer label byte +max_length db ? ;maximum length +chars_entered db ? ;number of chars. +string db 17 dup (?) ;16 chars + CR +strings_per_line dw 0 ;how many strings + ;fit on line +crlf db 0DH,0AH +; +begin: get_string 17,buffer ;THIS FUNCTION + xor bx,bx ;so byte can be + ;used as index + mov bl,chars_entered ;get string length + mov buffer[bx+2],"$" ;see Function 09H + mov al,50H ;columns per line + cbw + div chars_entered ;times string fits + ;on line + xor ah,ah ;clear remainder + mov strings_per_line,ax ;save col. counter + mov cx,24 ;row counter +display_screen: push cx ;save it + mov cx,strings_per_line ;get col. counter +display_line: display string ;see Function 09H + loop display_line + display crlf ;see Function 09H + pop cx ;get line counter + loop display_screen ;display 1 more line + + + +22 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Check Keyboard Status (Function 0BH) + + Call: + + AH = 0BH + + Return: + + AL + 00H = no characters in type-ahead buffer + FFH = characters in type-ahead buffer + + + +Comments: + +Function 0BH checks whether characters are available from standard +input (if standard input has not been redirected, it checks the type-ahead +buffer). If characters are available, AL returns FFH; if not, AL returns 0. +If CONTROL-C is in the buffer, it issues Interrupt 23H. + +Macro Definition: + + +check_kbd_status macro + mov ah,0BH + int 21H + endm + + +Example: + +The following program displays the time continuously until you press any +key: + +time db "00:00:00.00",0DH,0AH,"$" + . + . +begin: get_time ;see Function 2CH + byte_to_dec ch,time ;see end of chapter + byte_to_dec cl,time[3] ;see end of chapter + + 23 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + byte_to_dec dh,time[6] ;see end of chapter + byte_to_dec dl,time[9] ;see end of chapter + display time ;see Function 09H + check_kbd_status ;THIS FUNCTION + cmp al,0FFH ;has a key been typed? + je return ;yes, go home + jmp begin ;no, keep displaying + ;time + + + +24 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Flush Buffer, Read Keyboard (Function 0CH) + + Call: + + AH = 0CH + AL + 1, 6, 7, 8, or 0AH = the + corresponding function + is called. + Any other value = no + further processing. + + Return: + + AL + 00H = Type-ahead buffer was + flushed; no other + processing performed. + + + +Comments: + +Function 0CH empties the standard input buffer (if standard input has not +been redirected, Function 0CH empties the type-ahead buffer). Further +processing depends on the value in AL when the function is called. + +AL + Action +_ ________________________________________________________________ + +1,6,7,8, or 0AH The corresponding MS-DOS function is executed. + +Any other value No further processing; AL returns 0. + + +Macro Definition: + + +flush_and_read_kbd macro switch + mov al,switch + mov ah,0CH + int 21H + endm + + + + 25 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program both displays and prints characters as you type +them. If you press the RETURN key, the program sends a carriage- +return/linefeed sequence to both the display and the printer. + +begin: flush_and_read_kbd 1 ;THIS FUNCTION + print_char al ;see Function 05H + cmp al,0DH ;is it a carriage return? + jne begin ;no, print it + print_char 0AH ;see Function 05H + display_char 0AH ;see Function 02H + jmp begin ;get another character + + + +26 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Reset Disk (Function 0DH) + + Call: + + AH = 0DH + + Return: + + None + + + +Comments: + +Function 0DH flushes all file buffers to ensure that the internal buffer +cache matches the disks in the drives. It writes out buffers that have been +modified, and marks all buffers in the internal cache as free. This function +request is normally used to force a known state of the system; CONTROL-C +interrupt handlers should call this function. + +This function does not update directory entries; you must close changed +files to update their directory entries (see Function 10H, Close File). + +Macro Definition: + + +reset_disk macro + mov ah,0DH + int 21H + endm + + + + 27 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program flushes all file buffers and selects disk A. + +begin: reset_disk + select_disk "A" + + + +28 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Select Disk (Function 0EH) + + Call: + + AH = 0EH + DL + Logical drive number + (0 = A, 1 = B, etc.) + + Return: + + AL + Number of logical drives + + + +Comments: + +Function 0EH selects the drive specified in DL (0=A, 1=B, etc.) as the +current logical drive. AL returns the number of logical drives. + +_ ________________________________________________________________ + +Note + + For future compatibility, treat the value returned in AL with care. + For example, if AL returns 5, it is not safe to assume that drives A, B, + C, D, and E are all valid drive designators. + +_ ________________________________________________________________ + + +Macro Definition: + + +select_disk macro disk + mov dl,disk[-64] + mov ah,0EH + int 21H + endm + + + + 29 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program toggles between drive A and drive B to select the +current drive (in a two-drive system). + +begin: current_disk ;see Function 19H + cmp al,00H ;drive A: selected? + je select_b ;yes, select B + select_disk "A" ;THIS FUNCTION + jmp return +select_b: select_disk "B" ;THIS FUNCTION + + + +30 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Open File (Function 0FH) + + Call: + + AH = 0FH + DS:DX + Pointer to unopened FCB + + Return: + + AL + 00H = Directory entry found + FFH = No directory entry found + + + +Comments: + +Function 0FH opens a file. DX must contain the offset (from the segment +address in DS) of an unopened File Control Block (FCB). This call +searches the disk directory for the named file. + +If the call finds a directory entry for the file, AL returns 0 and the FCB is +filled as follows: + + o If the drive code was 0 (current drive), it is changed to the actual + drive used (1=A, 2=B, etc.). This lets you change the current + drive without interfering with subsequent operations on this file. + + o Current Block (offset 0CH) is set to 0. + + o Record Size (offset 0EH) is set to the system default of 128. + + o File Size (offset 0FH), Date of Last Write (offset 13H), and Time of + Last Write (offset 15H) are set from the directory entry. + +Before performing a sequential disk operation on the file, you must set the +Current Record field (offset 1FH). Before performing a random disk opera- +tion on the file, you must set the Relative Record field (offset 20H). If the +default record size (128 bytes) is not correct, set it to the correct length. + +If the call doesn't find a directory entry for the file, or if the file has the +hidden or system attribute, AL returns 0FFH. + + + 31 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +open macro fcb + mov dx,offset fcb + mov ah,0FH + int 21H + endm + + +Example: + +The following program prints a file named textfile.asc that is on the disk in +drive B. If a partial record is in the buffer at end-of-file, the routine that +prints the partial record prints characters until it encounters an end-of-file +mark (ASCII 26, or CONTROL-Z). + +fcb db 2,"TEXTFILEASC" + db 26 dup (?) +buffer db 128 dup (?) +; +begin: set_dta buffer ;see Function 1AH + open fcb ;THIS FUNCTION +read_line: read_seq fcb ;see Function 14H + cmp al,02H ;end of file? + je all_done ;yes, go home + cmp al,00H ;more to come? + jg check_more ;no, check for partial + ;record + mov cx,80H ;yes, print the buffer + xor si,si ;set index to 0 +print_it: print_char buffer[si] ;see Function 05H + inc si ;bump index + loop print_it ;print next character + jmp read_line ;read another record +check_more: cmp al,03H ;part. record to print? + jne all_done ;no + mov cx,80H ;yes, print it + xor si,si ;set index to 0 +find_eof: cmp buffer[si],26 ;end-of-file mark? + je all_done ;yes + print_char buffer[si] ;see Function 05H + inc si ;bump index to next + ;character + loop find_eof +all_done: close fcb ;see Function 10H + + + +32 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Close File (Function 10H) + + Call: + + AH = 10H + DS:DX + Pointer to opened FCB + + Return: + + AL + 00H = Directory entry found + FFH = No directory entry found + + + +Comments: + +Function 10H closes a file. DX must contain the offset (to the segment +address in DS) of an opened FCB. This call searches the disk directory for +the file named in the FCB. If it finds a directory entry for the file, it com- +pares the location of the file with the corresponding entries in the FCB. +The call then updates the directory entry, if necessary, to match the FCB, +and AL returns 0. + +After you change a file, you must call this function to update the directory +entry. You should close any FCB (even one for a file that has not been +changed) when you no longer need access to a file. + +If this call doesn't find a directory entry for the file, AL returns FFH. + +Macro Definition: + + +close macro fcb + mov dx,offset fcb + mov ah,10H + int 21H + endm + + + + 33 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program checks the first byte of the file named mod1.bas in +drive B to see if it is FFH and, if it is, prints a message. + +message db "Not saved in ASCII format",0DH,0AH,"$" +fcb db 2,"MOD1 BAS" + db 26 dup (?) +buffer db 128 dup (?) +; +begin: set_dta buffer ;see Function 1AH + open fcb ;see Function 0FH + read_seq fcb ;see Function 14H + + cmp buffer,0FFH ;is first byte FFH? + jne all_done ;no + display message ;see Function 09H +all_done: close fcb ;THIS FUNCTION + + + +34 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Search for First Entry (Function 11H) + + Call: + + AH = 11H + DS:DX + Pointer to unopened FCB + + Return: + + AL + 00H = Directory entry found + FFH = No directory entry found + + + +Comments: + +Function 11H searches the disk directory for the first matching filename. +DX must contain the offset (from the segment address in DS) of an +unopened FCB. The filename in the FCB can include wildcard characters. +To search for hidden or system files, DX must point to the first byte of an +extended FCB prefix. + +If this call does not find a directory entry for the filename in the FCB, AL +returns FFH. + +But if the call does find a directory entry for the filename in the FCB, AL +returns 0 and the call creates an unopened FCB of the same type (normal +or extended) at the Disk Transfer Address as follows: + + 1. If the search FCB was normal, the first byte at the Disk Transfer + Address is set to the drive number used in the search (1=A, 2=B, + etc.) and the next 32 bytes contain the directory entry. + + 2. If the search FCB was extended, the first byte at the Disk Transfer + Address is set to FFH, the next 5 bytes are set to 00H, and the fol- + lowing byte is set to the value of the attribute byte in the search + FCB. The remaining 33 bytes are the same as the result of the nor- + mal FCB (drive number and 32 bytes of directory entry). + +If you use Function 12H (Search for Next Entry) to continue searching for +matching filenames, you must not alter or open the original FCB at +DS:DX. + + 35 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The attribute field is the last byte of the extended FCB fields that precede +the FCB (see earlier in this chapter). If the attribute field is zero, Function +11H searches only normal file entries. It does not search directory entries +for hidden files, system files, volume label, and subdirectories. + +If the attribute field is hidden file, system file, or subdirectory entry (02H, +04H, or 10H), or any combination of those values, this call also searches all +normal file entries. To search all directory entries except the volume label, +set the attribute byte to 16H (hidden file and system file and directory +entry). + +If the attribute field is Volume ID (08H), the call searches only the volume +label entry. + +Macro Definition: + + +search_first macro fcb + mov dx,offset fcb + mov ah,11H + int 21H + endm + + +Example: + +The following program verifies the existence of a file named report.asm on +the disk in drive B. + +yes db "FILE EXISTS.$" +no db "FILE DOES NOT EXIST.$" +crlf db 0DH,0AH,"$" +fcb db 2,"REPORT *ASM" + db 26 dup (?) +buffer db 128 dup (?) +; +begin: set_dta buffer ;see Function 1AH + search_first fcb ;THIS FUNCTION + cmp al,0FFH ;directory entry found? + je not_there ;no + display yes ;see Function 09H + jmp continue +not_there: display no ;see Function 09H +continue: display crlf ;see Function 09H + + + +36 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Search for Next Entry (Function 12H) + + Call: + + AH = 12H + DS:DX + Pointer to unopened FCB + + Return: + + AL + 00H = Directory entry found + FFH = No directory entry found + + + +Comments: + +After you use Function 11H (Search for First Entry), you can use Function +12H to find any additional directory entries that match a filename (con- +taining wildcard characters). Function 12H searches the disk directory for +the next matching name. DX must contain the offset (from the segment +address in DS) of an FCB specified in a previous call to Function 11H. To +search for hidden or system files, DX must point to the first byte of an +extended FCB prefix\(emone that includes the appropriate attribute value. + +If the call does not find a directory entry for the filename in the FCB, AL +returns FFH. + +But if the call does find a directory entry for the filename in the FCB, AL +returns 0 and the call creates an unopened FCB of the same type (normal +or extended) at the Disk Transfer Address (see Function 11H for a descrip- +tion of how the unopened FCB is formed). + +Macro Definition: + + +search_next macro fcb + mov dx,offset fcb + mov ah,12H + int 21H + endm + + + 37 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program displays the number of files on the disk in drive B. + +message db "No files",0DH,0AH,"$" +files db 0 +fcb db 2,"???????????" + db 26 dup (?) +buffer db 128 dup (?) +; +begin: set_dta buffer ;see Function 1AH + search_first fcb ;see Function 11H + cmp al,0FFH ;directory entry found? + je all_done ;no, no files on disk + inc files ;yes, increment file + ;counter +search_dir: search_next fcb ;THIS FUNCTION + cmp al,0FFH ;directory entry found? + je done ;no + inc files ;yes, increment file + ;counter + jmp search_dir ;check again +done: convert files,10,message ;see end of chapter +all_done: display message ;see Function 09H + + + +38 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Delete File (Function 13H) + + Call: + + AH = 13H + DS:DX + Pointer to unopened FCB + + Return: + + AL + 00H = Directory entry found + FFH = No directory entry found + + + +Comments: + +Function 13H deletes a file. DX must contain the offset (from the segment +address in DS) of an unopened FCB. This call searches the directory for a +matching filename. The filename in the FCB can contain wildcard charac- +ters. + +If the call does not find a matching directory entry, AL returns FFH. + +But if the call does find a matching directory entry, AL returns 0 and the +call deletes the entry from the directory. If the filename contains a wild- +card character, the call will delete all files which match. + +Do not delete open files. + +Macro Definition: + + +delete macro fcb + mov dx,offset fcb + mov ah,13H + int 21H + endm + + + + 39 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program deletes each file on the disk in drive B that was last +written before December 31, 1982. + +year dw 1982 +month db 12 +day db 31 +files db 0 +message db "No files deleted.",0DH,0AH,"$" +fcb db 2,"???????????" + db 26 dup (?) +buffer db 128 dup (?) +; +begin: set_dta buffer ;see Function 1AH + search_first fcb ;see Function 11H + cmp al,0FFH ;directory entry found? + jne compare ;yes + jmp all_done ;no, no files on disk +compare: convert_date buffer ;see end of chapter + cmp cx,year ;next several lines + jg next ;check date in directory + cmp dl,month ;entry against date + jg next ;above & check next file + cmp dh,day ;if date in directory + jge next ;entry isn't earlier. + delete buffer ;THIS FUNCTION + inc files ;bump deleted-files + ;counter +next: search_next fcb ;see Function 12H + cmp al,00H ;directory entry found? + je compare ;yes, check date + cmp files,0 ;any files deleted? + je all_done ;no, display No files + ;message. + convert files,10,message ;see end of chapter +all_done: display message ;see Function 09H + + + +40 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Sequential Read (Function 14H) + + Call: + + AH = 14H + DS:DX + Pointer to opened FCB + + Return: + + AL + 00H = Read completed successfully + 01H = EOF + 02H = DTA too small + 03H = EOF, partial record + + + +Comments: + +Function 14H reads a record from a specified file. DX must contain the +offset (from the segment address in DS) of an opened FCB. This call loads +the record pointed to by the Current Block field (offset 0CH) and Current +Record (offset 1FH) field at the Disk Transfer Address, then increments the +Current Block and Current Record fields. + +The length of the record is taken from the Record Size field (offset 0EH) of +the FCB. + +AL returns a code that describes the processing: + +Code + Meaning +_ ________________________________________________________________ + +0 Read completed successfully + +1 End-of-file; no data in the record + +2 Not enough room at the Disk Transfer Address to read one record; + read canceled + +3 End-of-file; a partial record was read and padded to the record + length with zeros + + + + 41 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +read_seq macro fcb + mov dx,offset fcb + mov ah,14H + int 21H + endm + + +Example: + +The following program displays a file named textfile.asc that is on the disk +in drive B; its function is similar to the MS-DOS type command. If a par- +tial record is in the buffer at end-of-file, the routine that displays the par- +tial record displays characters until it encounters an end-of-file mark (ASCII +26, or CONTROL-Z). + +fcb db 2,"TEXTFILEASC" + db 26 dup (?) +buffer db 128 dup (?),"$" +; +begin: set_dta buffer ;see Function 1AH + open fcb ;see Function 0FH +read_line: read_seq fcb ;THIS FUNCTION + cmp al,02H ;DTA too small? + je all_done ;yes + cmp al,00H ;end-of-file? + jg check_more ;yes + display buffer ;see Function 09H + jmp read_line ;get another record +check_more: cmp al,03H ;partial record in buffer? + jne all_done ;no, go home + xor si,si ;set index to 0 +find_eof: cmp buffer[si],26 ;is character EOF? + je all_done ;yes, no more to display + display_char buffer[si] ;see Function 02H + inc si ;bump index + jmp find_eof ;check next character +all_done: close fcb ;see Function 10H + + + +42 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Sequential Write (Function 15H) + + Call: + + AH = 15H + DS:DX + Pointer to opened FCB + + Return: + + AL + 00H = Write completed successfully + 01H = Disk full + 02H = DTA too small + + +Function 15H writes a record to a specified file. DX must contain the +offset (from the segment address in DS) of an opened FCB. This call +writes the record pointed to by the Current Block field (offset 0CH) and +Current Record field (offset 1FH) at the Disk Transfer Address, then incre- +ments the Current Block and Current Record fields. + +The record size is taken from the value of the Record Size field (offset 0EH) +of the FCB. If the record size is less than a sector, the call writes the data +at the Disk Transfer Address to an MS-DOS buffer; MS-DOS writes the +buffer to disk when it contains a full sector of data, when the file is closed, +or when Function 0DH (Reset Disk) is issued. + +AL returns a code that describes the processing: + +Code + Meaning +_ ________________________________________________________________ + +0 Write completed successfully + +1 Disk full; write canceled + +2 Not enough room at the Disk Transfer Address to write one record; + write canceled + + + + 43 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +write_seq macro fcb + mov dx,offset fcb + mov ah,15H + int 21H + endm + + +Example: + +The following program creates a file named dir.tmp on the disk in drive B, +containing the disk number (0=A, 1=B, etc.) and filename from each +directory entry on the disk. + +record_size equ 0EH ;offset of Record Size +; field in FCB +fcb1 db 2,"DIR TMP" + db 26 dup (?) +fcb2 db 2,"???????????" + db 26 dup (?) +buffer db 128 dup (?) +; +begin: set_dta buffer ;see Function 1AH + search_first fcb2 ;see Function 11H + cmp al,0FFH ;directory entry found? + je all_done ;no, no files on disk + create fcb1 ;see Function 16H + mov fcb1[record_size],12 + ;set record size to 12 +write_it: write_seq fcb1 ;THIS FUNCTION + cmp al,0 ;write successful? + jne all_done ;no, go home + search_next fcb2 ;see Function 12H + cmp al,FFH ;directory entry found? + je all_done ;no, go home + jmp write_it ;yes, write the record +all_done: close fcb1 ;see Function 10H + + + +44 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Create File (Function 16H) + + Call: + + AH = 16H + DS:DX + Pointer to unopened FCB + + Return: + + AL + 00H = Empty directory found + FFH = No empty directory available + + +Function 16H creates a file. DX must contain the offset (from the segment +address in DS) of an unopened FCB. MS-DOS searches the directory for +an entry that matches the specified filename or, if there is no matching +entry, an empty entry. + +If MS-DOS finds a matching entry, it opens the file and sets the length to +zero (in other words, if you try to create a file that already exists, MS-DOS +erases it and creates a new, empty file). If MS-DOS doesn't find a matching +entry but does find an empty directory entry, it opens the file and sets its +length to zero. In either case, the call creates the file, and AL returns 0. If +MS-DOS doesn't find a matching entry and there is no empty entry, the +call doesn't create the file, and AL returns FFH. + +You can assign an attribute to the file by using an extended FCB with the +attribute byte set to the appropriate value (see Extended FCB in Section +1.9.1). + +Macro Definition: + + +create macro fcb + mov dx,offset fcb + mov ah,16H + int 21H + endm + + + + 45 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program creates a file named dir.tmp on the disk in drive B, +containing the disk number (0 = A, 1 = B, etc.) and filename from each +directory entry on the disk. + +record_size equ 0EH ;offset of Record Size +; field of FCB +fcb1 db 2,"DIR TMP" + db 26 dup (?) +fcb2 db 2,"???????????" + db 26 dup (?) +buffer db 128 dup (?) +; +begin: set_dta buffer ;see Function 1AH + search_first fcb2 ;see Function 11H + cmp al,0FFH ;directory entry found? + je all_done ;no, no files on disk + create fcb1 ;THIS FUNCTION + mov fcb1[record_size],12 + ;set record size to 12 +write_it: write_seq fcb1 ;see Function 15H + cmp al,0 ;write successful + jne all_done ;no, go home + search_next fcb2 ;see Function 12H + cmp al,FFH ;directory entry found? + je all_done ;no, go home + jmp write_it ;yes, write the record +all_done: close fcb1 ;see Function 10H + + + +46 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Rename File (Function 17H) + + Call: + + AH = 17H + DS:DX + Pointer to modified FCB + + Return: + + AL + 00H = Directory entry found + FFH = No directory entry found + or destination already exists + + +Function 17H changes the name of an existing file. DX must contain the +offset (from the segment address in DS) of an FCB with the drive number +and filename filled in, followed by a second filename at offset 11H. DOS +searches the disk directory for an entry that matches the first filename. +This filename can contain wildcard characters. + +If MS-DOS finds a matching directory entry and there is no directory entry +that matches the second filename, it changes the filename in the directory +entry to match the second filename in the modified FCB. AL then returns +zero. If the second filename does contain a wildcard character, this call +does not change the corresponding characters in the filename of the direc- +tory entry. + +You cannot use this function request to rename a hidden file, a system file, +or a subdirectory. If MS-DOS does not find a matching directory entry or +if it finds an entry for the second filename, AL returns FFH. + +Macro Definition: + + +rename macro fcb,newname + mov dx,offset fcb + mov ah,17H + int 21H + endm + + + + 47 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program prompts for the name of a file and a new name; it +then renames the file. + +fcb db 37 dup (?) +prompt1 db "Filename: $" +prompt2 db "New name: $" +reply db 15 dup(?) +crlf db 0DH,0AH,"$" +; +begin: display prompt1 ;see Function 09H + get_string 15,reply ;see Function 0AH + display crlf ;see Function 09H + parse reply[2],fcb ;see Function 29H + display prompt2 ;see Function 09H + get_string 15,reply ;see Function 0AH + display crlf ;see Function 09H + parse reply[2],fcb[16] + ;see Function 29H + rename fcb ;THIS FUNCTION + + + +48 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Get Current Disk (Function 19H) + + Call: + + AH = 19H + + Return: + + AL + Currently selected drive + (0 = A, 1 = B, etc.) + + + +Comments: + +Function 19H returns the current drive in AL (0=A, 1=B, etc.). + +Macro Definition: + + +current_disk macro + mov ah,19H + int 21H + endm + + +Example: + +The following program displays the default drive in a two-drive system. + +message db "Current disk is $" +crlf db 0DH,OAH,"$" +; +begin: display message ;see Function 09H + current_disk ;THIS FUNCTION + cmp al,00H ;is it disk A? + jne disk_b ;no, it's disk B: + display_char "A" ;see Function 02H + jmp all_done +disk_b: display_char "B" ;see Function 02H +all_done: display crlf ;see Function 09H + + 49 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Set Disk Transfer Address (Function 1AH) + + Call: + + AH = 1AH + DS:DX + Disk Transfer Address + + Return: + + None + + + +Comments: + +Function 1AH sets the Disk Transfer Address. DX must contain the offset +(from the segment address in DS) of the Disk Transfer Address. Disk +transfers cannot wrap around from the end of the segment to the begin- +ning, nor can they overflow into another segment. + +If you do not set the Disk Transfer Address, MS-DOS defaults to offset +80H in the Program Segment Prefix. You can check the current Disk +Transfer Address with Function 2FH (Get Disk Transfer Address). + +Macro Definition: + + +set_dta macro buffer + mov dx,offset buffer + mov ah,1AH + int 21H + endm + + + +50 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program prompts for a letter, converts it to its alphabetic +sequence (A=1, B=2, etc.), then reads and displays the corresponding +record from a file named alphabet.dat that is on the disk in drive B. The +file contains 26 records, each 28 bytes long. + +record_size equ 0EH ;offset of Record Size + ;field of FCB +relative_record equ 21H ;offset of Relative Record +; field of FCB +fcb db 2,"ALPHABETDAT" + db 26 dup (?) +buffer db 28 dup(?),"$" +prompt db "Enter letter: $" +crlf db 0DH,0AH,"$" +; +begin: set_dta buffer ;THIS FUNCTION + open fcb ;see Function 0FH + mov fcb[record_size],28 ;set record size +get_char: display prompt ;see Function 09H + read_kbd_and_echo ;see Function 01H + cmp al,0DH ;just a CR? + je all_done ;yes, go home + sub al,41H ;convert ASCII + ;code to record # + mov fcb[relative_record],al + ;set relative record + display crlf ;see Function 09H + read_ran fcb ;see Function 21H + display buffer ;see Function 09H + display crlf ;see Function 09H + jmp get_char ;get another character +all_done: close fcb ;see Function 10H + + + + 51 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Default Drive Data (Function 1BH) + + Call: + + AH = 1BH + + Return: + + AL + Sectors per cluster + CX + Bytes per sector + DX + Clusters per drive + DS:BX + Pointer to FAT ID byte + + +Function 1BH retrieves data about the disk in the default drive. The data +returns in the following registers: + +Register + Contents +_ ________________________________________________________________ + +AL Number of sectors in a cluster (allocation unit) + +CX Number of bytes in a sector + +DX Number of clusters on the disk + +BX returns the offset (to the segment address in DS) of the first byte of the +File Allocation Table (FAT), which identifies the type of disk in the drive: + +Value + Type of Drive +_ ________________________________________________________________ + +FF Double-sided disk, 8 sectors per track, 40 tracks per side + +FE Single-sided disk, 8 sectors per track, 40 tracks per side + +FD Double-sided disk, 9 sectors per track, 40 tracks per side + +FC Single-sided disk, 9 sectors per track, 40 tracks per side + +F9 Double-sided disk, 15 sectors per track, 40 tracks per side + +F9 Double-sided disk, 9 sectors per track, 80 tracks per side + +F8 Fixed disk + +This call is similar to Function 36H (Get Disk Free Space), except that it + +52 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +returns the address of the FAT ID byte in BX instead of the number of +available clusters. It is also similar to Function 1CH (Get Drive Data), +except that it returns data on the disk in the default drive instead of on +the disk in a specified drive. For a description of how MS-DOS stores data +on a disk, including a description of the File Allocation Table, see Chapter +3, "MS-DOS Technical Information." + +_ ________________________________________________________________ + +Warning + + The FAT ID byte is no longer adequate to identify the type of drive + being used. See Chapter 2, "MS-DOS Device Drivers," for more + details. + +_ ________________________________________________________________ + + +Macro Definition: + + +def_drive_data macro + push ds + mov ah,1BH + int 21H + mov al,byte ptr[bx] + pop ds + endm + + +Example: + +The following program displays a message that tells whether the default +drive is a disk or a fixed disk drive. + +stdout equ 1 +; +msg db "Default drive is " +dskt db "disk." +fixed db "fixed." +crlf db ODH,OAH +; +begin: write_handle stdout,msg,17 ;display message + jc write_error ;routine not shown + def_drive_data ;THIS FUNCTION + cmp byte ptr [bx],0F8H ;check FAT ID byte + jne disk ;it's a disk + write_handle stdout,fixed,6 ;see Function 40H + jc write_error ;see Function 40H + jmp short all_done ;clean up & go home +disk: write_handle stdout,dskt,9 ;see Function 40H +all_done: write_handle stdout,crlf,2 ;see Function 40H + jc write_error ;routine not shown + + + 53 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Drive Data (Function 1CH) + + Call: + + AH = 1CH + DL + Drive (0=default, 1=A, etc.) + + + Return: + + AL + 0FFH if drive number is invalid; + otherwise, sectors per cluster + CX + Bytes per sector + DX + Clusters per drive + DS:BX + Pointer to FAT ID byte + + +Comments: + +Function 1CH retrieves data about the disk in the specified drive. DL must +contain the drive number (0=default, 1=A, etc.). The data returns in the +following registers: + +Register + Contents +_ ________________________________________________________________ + +AL Number of sectors in a cluster (allocation unit) + +CX Number of bytes in a sector + +DX Number of clusters on the disk + +BX returns the offset (to the segment address in DS) of the first byte of the +File Allocation Table (FAT), which identifies the type of disk in the drive: + +Value + Type of Drive +_ ________________________________________________________________ + +FF Double-sided disk, 8 sectors per track, 40 tracks per side + +FE Single-sided disk, 8 sectors per track, 40 tracks per side + +FD Double-sided disk, 9 sectors per track, 40 tracks per side + +FC Single-sided disk, 9 sectors per track, 40 tracks per side + + + +54 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +F9 Double-sided disk, 15 sectors per track, 40 tracks per side + +F9 Double-sided disk, 9 sectors per track, 80 tracks per side + +F8 Fixed disk + +If the drive number in DL is invalid, AL returns 0FFH. + +_ ________________________________________________________________ + +Warning + + The FAT ID byte is no longer adequate to identify the type of drive + being used. See Chapter 2, "MS-DOS Device Drivers" for more details. + +_ ________________________________________________________________ + +This call is similar to Function 36H (Get Disk Free Space), except that it +returns the address of the FAT ID byte in BX instead of the number of +available clusters. It is also similar to Function 1BH (Get Default Drive +Data), except that it returns data on the disk in the drive specified in DL +instead of the disk in the default drive. For a description of how MS-DOS +stores data on a disk, including a description of the File Allocation Table, +see Chapter 3, "MS-DOS Technical Information." + +Macro Definition: + + +drive_data macro drive + push ds + mov dl,drive + mov ah,1BH + int 21H + mov al, byte ptr[bx] + pop ds + endm + + +Example: + +The following program displays a message that tells whether drive B is a +disk or a fixed disk drive. + +stdout equ 1 +: +msg db "Drive B is " +dskt db "disk." +fixed db "fixed." +crlf db ODH,OAH +; +begin: write_handle stdout,msg,11 ;display message + jc write_error ;routine not shown + drive_data 2 ;THIS FUNCTION + + 55 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + cmp byte ptr [bx],0F8H ;check FAT ID byte + jne disk ;it's a disk + write_handle stdout,fixed,6 ;see Function 40H + jc write_error ;routine not shown + jmp all_done ;clean up & go home +disk: write_handle stdout,dskt,9 ;see Function 40H +all_done: write_handle stdout,crlf,2 ;see Function 40H + jc write_error ;routine not shown + + + +56 + +_ _ | | _ _ + + + diff --git a/PROGREF/1C_CALLS.A b/PROGREF/1C_CALLS.A new file mode 100644 index 0000000..7372f82 --- /dev/null +++ b/PROGREF/1C_CALLS.A @@ -0,0 +1,3520 @@ + +_ _ | | _ _ + + + + _ ______________ + + +Random Read (Function 21H) + + Call: + + AH = 21H + DS:DX + Pointer to opened FCB + + Return: + + AL + 0 = Read completed successfully + 1 = End of file, record empty + 2 = DTA too small + 3 = End of file, partial record + + + +Comments: + +Function 21H reads (into the Disk Transfer Address) the record pointed to +by the Relative Record field (offset 20H) of the FCB. DX must contain the +offset (from the segment address in DS) of an opened FCB. The Current +Block field (offset 0CH) and Current Record field (offset 1FH) are set to +agree with the Relative Record field (offset 20H). The record is then loaded +at the Disk Transfer Address. The record length is taken from the Record +Size field (offset 0EH) of the FCB. + +AL returns a code that describes the processing: + +Code + Meaning +_ ________________________________________________________________ + +0 Read completed successfully + +1 End-of-file; no data in the record + +2 Not enough room at the Disk Transfer Address to read one record; + read canceled + +3 End-of-file; a partial record was read and padded to the record + length with zeros + + + + 1 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +read_ran macro fcb + mov dx,offset fcb + mov ah,21H + int 21H + endm + + +Example: + +The following program prompts for a letter, converts it to its alphabetic +sequence (A = 1, B = 2, etc.), then reads and displays the corresponding +record from a file named alphabet.dat that is on the disk in drive B. The +file contains 26 records, each 28 bytes long. + +record_size equ 0EH ;offset of Record Size + ;field of FCB +relative_record equ 21H ;offset of Relative Record +; field of FCB +fcb db 2,"ALPHABETDAT" + db 26 dup (?) +buffer db 28 dup(?),"$" +prompt db "Enter letter: $" +crlf db 0DH,0AH,"$" +; +begin: set_dta buffer ;see Function 1AH + open fcb ;see Function 0FH + mov fcb[record_size],28 ;set record size +get_char: display prompt ;see Function 09H + read_kbd_and_echo ;see Function 01H + cmp al,0DH ;just a CR? + je all_done ;yes, go home + sub al,41H ;convert ASCII code + ;to record # + mov fcb[relative_record],al ;set relative + ;record + display crlf ;see Function 09H + read_ran fcb ;THIS FUNCTION + display buffer ;see Function 09H + display crlf ;see Function 09H + jmp get_char ;get another char. +all_done: close fcb ;see Function 10H + + + +2 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Random Write (Function 22H) + + Call: + + AH = 22H + DS:DX + Pointer to opened FCB + + Return: + + AL + 00H = Write completed successfully + 01H = Disk full + 02H = DTA too small + + + +Comments: + +Function 22H writes (from the Disk Transfer Address) the record pointed +to by the Relative Record field (offset 20H) of the FCB. DX must contain +the offset from the segment address in DS of an opened FCB. The Current +Block (offset 0CH) and Current Record (offset 1FH) fields are set to agree +with the Relative Record field (offset 20H). This record is then written +from the Disk Transfer Address. + +The record length is taken from the Record Size field (offset 0EH) of the +FCB. If the record size is less than a sector, the data at the Disk Transfer +Address is written to a buffer, the buffer is written to disk when it contains +a full sector of data; or when a program closes the file, or when it issues +Function 0DH (Reset Disk). + +AL returns a code that describes the processing: + +Code + Meaning +_ ________________________________________________________________ + +0 Write completed successfully + +1 Disk is full + +2 Not enough room at the Disk Transfer Address to write one record; + write canceled + + + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +write_ran macro fcb + mov dx,offset fcb + mov ah,22H + int 21H + endm + + +Example: + +The following program prompts for a letter, converts it to its alphabetic +sequence (A = 1, B = 2, etc.), then reads and displays the corresponding +record from a file named alphabet.dat that is on the disk in drive B. After +displaying the record, it prompts you to enter a changed record. If you +type a new record, it is written to the file, but if you just press the RETURN +key, the record is not replaced. The file contains 26 records, each 28 bytes +long. + +record_size equ 0EH ;offset of Record Size + ;field of FCB +relative_record equ 21H ;offset of Relative Record +; field of FCB +fcb db 2,"ALPHABETDAT" + db 26 dup (?) +buffer db 28 dup(?),0DH,0AH,"$" +prompt1 db "Enter letter: $" +prompt2 db "New record (RETURN for no change): $" +crlf db 0DH,0AH,"$" +reply db 28 dup (32) +blanks db 26 dup (32) +; +begin: set_dta buffer ;see Function 1AH + open fcb ;see Function 0FH + mov fcb[record_size],28 ;set record size +get_char: display prompt1 ;see Function 09H + read_kbd_and_echo ;see Function 01H + cmp al,0DH ;just a carriage return? + je all_done ;yes, go home + sub al,41H ;convert ASCII + ;code to record # + mov fcb[relative_record],al + ;set relative record + display crlf ;see Function 09H + read_ran fcb ;THIS FUNCTION + display buffer ;see Function 09H + display crlf ;see Function 09H + display prompt2 ;see Function 09H + get_string 27,reply ;see Function 0AH + display crlf ;see Function 09H + cmp reply[1],0 ;was anything typed + ;besides CR? + je get_char ;no + ;get another char. + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + xor bx,bx ;to load a byte + mov bl,reply[1] ;use reply length as + ;counter + move_string blanks,buffer,26 ;see chapter end + move_string reply[2],buffer,bx ;see chapter end + write_ran fcb ;THIS FUNCTION + jmp get_char ;get another character +all_done: close fcb ;see Function 10H + + + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get File Size (Function 23H) + + Call: + + AH = 23H + DS:DX + Pointer to unopened FCB + + Return: + + AL + 00H = Directory entry found + FFH = No directory entry found + + + +Comments: + +Function 23H returns the size of a specified file. DX must contain the +offset (from the segment address in DS) of an unopened FCB. + +If there is a directory entry that matches the specified file, MS-DOS divides +the File Size field (offset 1CH) of the directory entry by the Record Size +field (offset 0EH) of the FCB, puts the result in the Relative Record field +(offset 20H) of the FCB, and returns 00 in AL. + +You must set the Record Size field of the FCB to the correct value before +calling this function. If the Record Size field is not an even divisor of the +File Size field, the value set in the Relative Record field is rounded up, +yielding a value larger than the actual number of records. + +If this call does not find a matching directory, AL returns FFH. + +Macro Definition: + + +file_size macro fcb + mov dx,offset fcb + mov ah,23H + int 21H + endm + + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program prompts for the name of a file, opens the file to fill +in the Record Size field of the FCB, issues a File Size system call, and +displays the record length and number of records. + +fcb db 37 dup (?) +prompt db "File name: $" +msg1 db "Record length: ",0DH,0AH,"$" +msg2 db "Records: ",0DH,0AH,"$" +crlf db 0DH,0AH,"$" +reply db 17 dup(?) +; +begin: display prompt ;see Function 09H + get_string 17,reply ;see Function 0AH + cmp reply[1],0 ;just a CR? + jne get_length ;no, keep going + jmp all_done ;yes, go home +get_length: display crlf ;see Function 09H + parse reply[2],fcb ;see Function 29H + open fcb ;see Function 0FH + file_size fcb ;THIS FUNCTION + mov ax,word ptr fcb[33] ;get record length + convert ax,10,msg2[9] ;see end of chapter + mov ax,word ptr fcb[14] ; get record number + convert ax,10,msg1[15] ;see end of chapter + display msg1 ;see Function 09H + display msg2 ;see Function 09H +all_done: close fcb ;see Function 10H + + + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Set Relative Record (Function 24H) + + Call: + + AH = 24H + DS:DX + Pointer to opened FCB + + Return: + + None + + + +Comments: + +Function 24H sets the Relative Record field (offset 20H) to the file address +specified by the Current Block field (offset 0CH) and Current Record field +(offset 1FH). DX must contain the offset (from the segment address in DS) +of an opened FCB. You use this call to set the file pointer before a Ran- +dom Read or Write (Functions 21H, 22H, 27H, or 28H). + +Macro Definition: + + +set_relative_record macro fcb + mov dx,offset fcb + mov ah,24H + int 21H + endm + + +Example: + +The following program copies a file using the Random Block Read and +Random Block Write system calls. It speeds the copy by setting the record +length equal to the file size and the record count to 1, and by using a +buffer of 32K bytes. It positions the file pointer by setting the Current +Record field (offset 1FH) to 1 and using Function 24H (Set Relative +Record) to make the Relative Record field (offset 20H) point to the same +record that the combination of the Current Block field (offset 0CH) and + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +Current Record field (offset 1FH) points to. + +current_record equ 20H ;offset of Current Record + ;field of FCB +fil_size equ 10H ;offset of File Size +; field of FCB +fcb db 37 dup (?) +filename db 17 dup(?) +prompt1 db "File to copy: $" ;see Function 09H for +prompt2 db "Name of copy: $" ;explanation of $ +crlf db 0DH,0AH,"$" +file_length dw ? +buffer db 32767 dup(?) +; +begin: set_dta buffer ;see Function 1AH + display prompt1 ;see Function 09H + get_string 15,filename ;see Function 0AH + display crlf ;see Function 09H + parse filename[2],fcb ;see Function 29H + open fcb ;see Function 0FH + mov fcb[current_record],0 ;set Current Record + ;field + set_relative_record fcb ;THIS FUNCTION + mov ax,word ptr fcb[fil_size] ;get file size + mov file_length,ax ;save it for + ;ran_block_write + ran_block_read fcb,1,ax ;see Function 27H + display prompt2 ;see Function 09H + get_string 15,filename ;see Function 0AH + display crlf ;see Function 09H + parse filename[2],fcb ;see Function 29H + create fcb ;see Function 16H + mov fcb[current_record],0 ;set Current Record + ;field + set_relative_record fcb ;THIS FUNCTION + mov ax,file_length ;get original file + ran_block_write fcb,1,ax ;see Function 28H + close fcb ;see Function 10H + + + + 9 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Set Interrupt Vector (Function 25H) + + Call: + + AH = 25H + AL + Interrupt number + DS:DX + Pointer to interrupt-handling + routine + + Return: + + None + + + +Comments: + +Function 25H sets the address in the interrupt vector table for the +specified interrupt. + +AL must contain the number of the interrupt. DX must contain the offset +(to the segment address in DS) of the interrupt-handling routine. + +To avoid compatibility problems, programs should never set an interrupt +vector directly and should never use Interrupt 25H to read directly from +memory. To get a vector, use Function 35H (Get Interrupt Vector), and to +set a vector, use Function 25H, unless your program must be compatible +with MS-DOS versions earlier than 2.0. + +Macro Definition: + + +set_vector macro interrupt,handler_start + mov al,interrupt + mov dx,offset handler_start + mov ah,25H + endm + + + +10 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +Because interrupts tend to be machine-specific, no example is shown. + + + 11 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Create New PSP (Function 26H) + + Call: + + AH = 26H + DX + Segment address of new PSP + + Return: + + None + + + +Comments: + +This function request has been superseded. Use Function 4BH (Load and +Execute Program) to run a child process, unless your program must be +compatible with MS-DOS versions earlier than 2.0. + +Function 26H creates a new Program Segment Prefix. DX must contain the +segment address where the new PSP is to be created. + +Macro Definition: + + +create_psp macro seg_addr + mov dx,seg_addr + mov ah,26H + endm + + +Example: + +Because Function 4BH (Load and Execute Program) and 4B03H (Load +Overlay) have superseded this function request, no example is shown. + + +12 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Random Block Read (Function 27H) + + Call: + + AH = 27H + DS:DX + Pointer to opened FCB + CX + Number of blocks to read + + Return: + + AL + 0 = Read completed successfully + 1 = End of file, empty record + 2 = DTA too small + 3 = End of file, partial record + CX + Number of blocks read + + + +Comments: + +Function 27H reads one or more records from a specified file to the Disk +Transfer Address. DX must contain the offset (to the segment address in +DS) of an opened FCB. CX must contain the number of records to read. +Reading starts at the record specified by the Relative Record field (offset +20H); you must set this field with Function 24H (Set Relative Record) +before calling this function. + +DOS calculates the number of bytes to read by multiplying the value in +CX by the Record Size field (offset 0EH) of the FCB. + +CX returns the number of records read. The Current Block field (offset +0CH), Current Record field (offset 1FH), and Relative Record field (offset +20H) are set to address the next record. + +If you call this function with CX=0, no records are read. + +AL returns a code that describes the processing: + +Code + Meaning +_ ________________________________________________________________ + +0 Read completed successfully + + + + 13 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +1 End-of-file; no data in the record + +2 Not enough room at the Disk Transfer Address to read one record; + read canceled + +3 End-of-file; a partial record was read and padded to the record + length with zeros + + +Macro Definition: + + +ran_block_read macro fcb,count,rec_size + mov dx,offset fcb + mov cx,count + mov word ptr fcb[14],rec_size + mov ah,27H + int 21H + endm + + +Example: + +The following program copies a file by using Function 27H (Random Block +Read). This program speeds the copy process by specifying a record count +of 1 and a record length equal to the file size, and by using a buffer of 32K +bytes; the file is read as a single record (compare to the sample program +for Function 28H that specifies a record length of 1 and a record count +equal to the file size). + +current_record equ 20H ;offset of Current Record field +fil_size equ 10H ;offset of File Size field +; +fcb db 37 dup (?) +filename db 17 dup(?) +prompt1 db "File to copy: $" ;see Function 09H for +prompt2 db "Name of copy: $" ;explanation of $ +crlf db 0DH,0AH,"$" +file_length dw ? +buffer db 32767 dup(?) +; +begin: set_dta buffer ;see Function 1AH + display prompt1 ;see Function 09H + get_string 15,filename ;see Function 0AH + display crlf ;see Function 09H + parse filename[2],fcb ;see Function 29H + open fcb ;see Function 0FH + mov fcb[current_record],0 ;set Current + ;Record field + set_relative_record fcb ;see Function 24H + mov ax, word ptr fcb[fil_size] + ;get file size + mov file_length,ax ;save it + ran_block_read fcb,1,ax ;THIS FUNCTION + display prompt2 ;see Function 09H + +14 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + get_string 15,filename ;see Function 0AH + display crlf ;see Function 09H + parse filename[2],fcb ;see Function 29H + create fcb ;see Function 16H + mov fcb[current_record],0;set current + ;Record field + set_relative_record fcb ;see Function 24H + ran_block_write fcb,1,ax ;see Function 28H + close fcb ;see Function 10H + + + + 15 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Random Block Write (Function 28H) + + Call: + + AH = 28H + DS:DX + Pointer to opened FCB + CX + Number of blocks to write + (0 = set File Size field) + + Return: + + AL + 00H = Write completed successfully + 01H = Disk full + 02H = End of segment + CX + Number of blocks written + + + +Comments: + +Function 28H writes one or more records to a specified file from the Disk +Transfer Address. DX must contain the offset (to the segment address in +DS) of an opened FCB; CX must contain either the number of records to +write or 0. + +If CX is not 0, the specified number of records is written to the file, start- +ing at the record specified in the Relative Record field (offset 20H) of the +FCB. If CX is 0, no records are written, but MS-DOS sets the File Size +field (offset 1CH) of the directory entry to the value in the Relative Record +field (offset 20H) of the FCB. To satisfy this new file size, disk allocation +units are allocated or released, as required. + +MS-DOS calculates the number of bytes to write by multiplying the value +in CX by the Record Size field (offset 0EH) of the FCB. CX returns the +number of records written; the Current Block field (offset 0CH), Current +Record field (offset 1FH), and Relative Record (offset 20H) field are set to +address the next record. + +AL returns a code that describes the processing: + +Code + Meaning +_ ________________________________________________________________ + + + +16 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +0 Write completed successfully + +1 Disk full. No records written + +2 Not enough room at the Disk Transfer Address to write one record; + write canceled + + +Macro Definition: + + +ran_block_write macro fcb,count,rec_size + mov dx,offset fcb + mov cx,count + mov word ptr fcb[14],rec_size + mov ah,28H + int 21H + endm + + +Example: + +The following program copies a file using Function 27H (Random Block +Read) and Function 28H (Random Block Write). This program speeds the +copy process by specifying a record count equal to the file size and a record +length of 1, and by using a buffer of 32K bytes; the file is copied quickly +with one disk access each to read and write (compare to the sample pro- +gram of Function 27H, which specifies a record count of 1 and a record +length equal to file size). + +current_record equ 20H ;offset of Current Record field +fil_size equ 10H ;offset of File Size field +; +fcb db 37 dup (?) +filename db 17 dup(?) +prompt1 db "File to copy: $" ;see Function 09H for +prompt2 db "Name of copy: $" ;explanation of $ +crlf db 0DH,0AH,"$" +num_recs dw ? +buffer db 32767 dup(?) +; +begin: set_dta buffer ;see Function 1AH + display prompt1 ;see Function 09H + get_string 15,filename ;see Function 0AH + display crlf ;see Function 09H + parse filename[2],fcb ;see Function 29H + open fcb ;see Function 0FH + mov fcb[current_record],0;set Current + Record field + set_relative_record fcb ;see Function 24H + mov ax, word ptr fcb[fil_size] + ;get file size + mov num_recs,ax ;save it + ran_block_read fcb,num_recs,1 ;THIS FUNCTION + display prompt2 ;see Function 09H + + 17 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + get_string 15,filename ;see Function 0AH + display crlf ;see Function 09H + parse filename[2],fcb ;see Function 29H + create fcb ;see Function 16H + mov fcb[current_record],0 ;set Current + ;Record field + set_relative_record fcb ;see Function 24H + ran_block_write fcb,num_recs,1 ;see Function 28H + close fcb ;see Function 10H + + + +18 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Parse File Name (Function 29H) + + Call: + + AH = 29H + AL + Controls parsing (see text) + DS:SI + Pointer to string to parse + ES:DI + Pointer to buffer for unopened FCB + + Return: + + AL + 00H = No wildcard characters + 01H = Wildcard characters used + FFH = Drive letter invalid + DS:SI + Pointer to first byte past + string that was parsed + ES:DI + Pointer to unopened FCB + + +Comments: + +Function 29H parses a string for a filename of the form +drive:filename.extension. SI must contain the offset (to the segment +address in DS) of the string to parse; DI must contain the offset (to the +segment address in ES) of an area of memory large enough to hold an uno- +pened FCB. If the string contains a valid filename, this call creates a +corresponding unopened FCB at ES:DI. + +AL controls the parsing. Bits 4-7 must be 0; bits 0-3 have the following +meaning: + + +Table 0.1 + +Bit values for Function 29H + +_ _________________________________________________________________________ + +Bit Value Meaning + +_ _________________________________________________________________________ + + 0 0 Stop parsing if a file separator is encountered. + + 1 Ignore leading separators. + + 1 0 + + Set the drive number in the FCB to 0 (current drive) if the string + does not contain a drive number. + + + + 19 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + 1 + + Leave the drive number in the FCB unchanged if the string does + not contain a drive number. + + 2 0 + + Set the filename in the FCB to eight blanks if the string does not + contain a filename. + + 1 + + Leave the filename in the FCB unchanged if the string does not + contain a filename. + + 3 1 + + Leave the extension in the FCB unchanged if the string does not + contain an extension. + + 0 + + Set the extension in the FCB to three blanks if the string does not + contain an extension. + +_ _________________________________________________________________________ + +If the string contains a filename or extension that includes an asterisk (*), +all remaining characters in the name or extension are set to question +marks (?). + +Filename separators: + + : ; . , = + / " [ ] \ < > | space tab + +Filename terminators include all the filename separators, plus any control +character. A filename cannot contain a filename terminator, since if the +call encounters one, parsing stops. + +If the string contains a valid filename: + + o AL returns 1 if the filename or extension contains a wildcard char- + acter (* or ?); AL returns 0 if neither the filename nor extension + contains a wildcard character. + + o DS:SI points to the first character following the parsed string. + + o ES:DI points to the first byte of the unopened FCB. + +If the drive letter is invalid, AL returns FFH. If the string does not contain +a valid filename, ES:DI+1 points to a blank. + +Macro Definition: + + +parse macro string,fcb + mov si,offset string + mov di,offset fcb + push es + push ds + pop es + mov al,0FH ;bits 0-3 on + mov ah,29H + int 21H + +20 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + pop es + endm + + +Example: + +The following program verifies the existence of the file named in reply to +the prompt. + +fcb db 37 dup (?) +prompt db "Filename: $" +reply db 17 dup(?) +yes db "File exists",0DH,0AH,"$" +no db "File does not exist",0DH,0AH,"$" + crlf db 0DH,0AH,"$" +; +begin: display prompt ;see Function 09H + get_string 15,reply ;see Function 0AH + parse reply[2],fcb ;THIS FUNCTION + display crlf ;see Function 09H + search_first fcb ;see Function 11H + cmp al,0FFH ;dir. entry found? + je not_there ;no + display yes ;see Function 09H + jmp return +not_there: display no + + + + 21 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Date (Function 2AH) + + Call: + + AH = 2AH + + Return: + + CX + Year (1980-2099) + DH + Month (1-12) + DL + Day (1-31) + AL + Day of week (0=Sun., 6=Sat.) + + + +Comments: + +Function 2AH returns the current date set in the operating system as +binary numbers in CX and DX: + +Register + Contents +_ ________________________________________________________________ + +CX Year (1980-2099) + +DH Month (1=January, 2=February, etc.) + +DL Day of month (1-31) + +AL Day of week (0=Sunday, 1=Monday, etc.) + + +Macro Definition: + + +get_date macro + mov ah,2AH + int 21H + endm + + + +22 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program gets the date, increments the day, increments the +month or year, if necessary, and sets the new date. + +month db 31,28,31,30,31,30,31,31,30,31,30,31 +; +begin: get_date ;THIS FUNCTION + inc dl ;increment day + xor bx,bx ;so BL can be used as index + mov bl,dh ;move month to index register + dec bx ;month table starts with 0 + cmp dl,month[bx] ;past end of month? + jle month_ok ;no, set new date + mov dl,1 ;yes, set day to 1 + inc dh ;and increment month + cmp dh,12 ;past end of year? + jle month_ok ;no, set new date + mov dh,1 ;yes, set month to 1 + inc cx ;increment year +month_ok: set_date cx,dh,dl ;see Function 2AH + + + + 23 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Set Date (Function 2BH) + + Call: + + AH = 2BH + CX + Year (1980-2099) + DH + Month (1-12) + DL + Day (1-31) + + Return: + + AL + 00H = Date was valid + FFH = Date was invalid + + + +Comments: + +Function 2BH sets the date in the operating system (and in the CMOS +clock, if one exists). Registers CX and DX must contain a valid date in +binary: + +Register + Contents +_ ________________________________________________________________ + +CX Year (1980-2099) + +DH Month (1=January, 2=February, etc.) + +DL Day of month (1-31) + +If the date is valid, the call sets it and AL returns 0. If the date is not +valid, the function aborts and AL returns FFH. + +Macro Definition: + + +set_date macro year,month,day + mov cx,year + mov dh,month + mov dl,day + mov ah,2BH + int 21H + endm + + +24 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program gets the date, increments the day, increments the +month or year, if necessary, and sets the new date. + +month db 31,28,31,30,31,30,31,31,30,31,30,31 +; +begin: get_date ;see Function 2AH + inc dl ;increment day + xor bx,bx ;so BL can be used as index + mov bl,dh ;move month to index register + dec bx ;month table starts with 0 + cmp dl,month[bx] ;past end of month? + jle month_ok ;no, set the new date + mov dl,1 ;yes, set day to 1 + inc dh ;and increment month + cmp dh,12 ;past end of year? + jle month_ok ;no, set the new date + mov dh,1 ;yes, set the month to 1 + inc cx ;increment year +month_ok: set_date cx,dh,dl ;THIS FUNCTION + + + + 25 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Time (Function 2CH) + + Call: + + AH = 2CH + + Return: + + CH + Hour (0-23) + CL + Minutes (0-59) + DH + Seconds (0-59) + DL + Hundredths (0-99) + + + +Comments: + +Function 2CH returns the current time set in the operating system (and +sets the CMOS clock, if one exists) as binary numbers in CX and DX: + +Register + Contents +_ ________________________________________________________________ + +CH Hour (0-23) + +CL Minutes (0-59) + +DH Seconds (0-59) + +DL Hundredths of a second (0-99) + +Depending on how your hardware keeps time, some of these fields may be +irrelevant. As an example, many CMOS clock chips do not resolve more +than seconds. In such a case, the value in DL will probably always be 0. + +Macro Definition: + + +get_time macro + mov ah,2CH + int 21H + endm + + + +26 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program displays the time continuously until you press any +key. + +time db "00:00:00.00",0DH,"$" +; +begin: get_time ;THIS FUNCTION + byte_to_dec ch,time ;see end of chapter + byte_to_dec cl,time[3] ;see end of chapter + byte_to_dec dh,time[6] ;see end of chapter + byte_to_dec dl,time[9] ;see end of chapter + display time ;see Function 09H + check_kbd_status ;see Function 0BH + cmp al,0FFH ;has a key been pressed? + je return ;yes, terminate + jmp begin ;no, display time + + + + 27 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Set Time (Function 2DH) + + Call: + + AH = 2DH + CH + Hour (0-23) + CL + Minutes (0-59) + DH + Seconds (0-59) + DL + Hundredths (0-99) + + Return: + + AL + 00H = Time was valid + FFH = Time was invalid + + + +Comments: + +Function 2DH sets the time in the operating system. Registers CX and DX +must contain a valid time in binary: + +Register + Contents +_ ________________________________________________________________ + +CH Hour (0-23) + +CL Minutes (0-59) + +DH Seconds (0-59) + +DL Hundredths of a second (0-99) + +Depending on how your hardware keeps time, some of these fields may be +irrelevant. As an example, many CMOS clock chips do not resolve more +than seconds. In such a case, the value in DL will not be relevant. + +If the time is valid, the call sets it and AL returns 0. If the time is not +valid, the function aborts and AL returns FFH. + + +28 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +set_time macro hour,minutes,seconds,hundredths + mov ch,hour + mov cl,minutes + mov dh,seconds + mov dl,hundredths + mov ah,2DH + int 21H + endm + + +Example: + +The following program sets the system clock to 0 and displays the time +continuously. When you type a character, the display freezes; when you +type another character, the clock is reset to 0 and the display starts again. + +time db "00:00:00.00",0DH,0AH,"$" +; +begin: set_time 0,0,0,0 ;THIS FUNCTION +read_clock: get_time ;see Function 2CH + byte_to_dec ch,time ;see end of chapter + byte_to_dec cl,time[3] ;see end of chapter + byte_to_dec dh,time[6] ;see end of chapter + byte_to_dec dl,time[9] ;see end of chapter + display time ;see Function 09H + dir_console_io 0FFH ;see Function 06H + cmp al,00H ;was a char. typed? + jne stop ;yes, stop the timer + jmp read_clock ;no keep timer on +stop: read_kbd ;see Function 08H + jmp begin ;keep displaying time + + + + 29 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Set/Reset Verify Flag (Function 2EH) + + Call: + + AH = 2EH + AL + 0 = Do not verify + 1 = Verify + + Return: + + None + + + +Comments: + +Function 2EH tells MS-DOS whether to verify each disk write. If AL is 1, +verify is on; if AL is 0, verify is off. MS-DOS checks this flag each time it +writes to a disk. + +The flag is normally off; you may wish to turn it on when writing critical +data to disk. Because disk errors are rare and verification slows writing, +you will probably want to leave it off at other times. You can check the +setting with Function 54H (Get Verify State). + +Macro Definition: + + +verify macro switch + mov al,switch + mov ah,2EH + int 21H + endm + + + +30 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program copies the contents of a single-sided disk in drive A +to the disk in drive B, verifying each write. It uses a buffer of 32K bytes. + +on equ 1 +off equ 0 +; +prompt db "Source in A, target in B",0DH,0AH + db "Any key to start. $" +first dw 0 +buffer db 60 dup (512 dup(?)) ;60 sectors +; +begin: display prompt ;see Function 09H + read_kbd ;see Function 08H + verify on ;THIS FUNCTION + mov cx,6 ;copy 60 sectors + ;6 times +copy: push cx ;save counter + abs_disk_read 0,buffer,60,first ;see Int 25H + abs_disk_write 1,buffer,64,first ;see Int 26H + add first,60 ;do next 60 sectors + pop cx ;restore counter + loop copy ;do it again + verify off ;THIS FUNCTION + + + + 31 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Disk Transfer Address (Function 2FH) + + Call: + + AH = 2FH + + Return: + + ES:BX + Pointer to Disk Transfer Address + + + +Comments: + +Function 2FH returns the segment address of the current Disk Transfer +Address in ES and the offset in BX. + +Macro Definition: + + +get_dta macro + mov ah,2fH + int 21H + endm + + +Example: + +The following program displays the current Disk Transfer Address in the +form: segment:offset. + +message db "DTA -- : ",0DH,0AH,"$" +sixteen db 10H +temp db 2 dup (?) +; +begin: get_dta ;THIS FUNCTION + mov word ptr temp,ex ;To access each byte + convert temp[1],sixteen,message[07H] ;See end of + convert temp,sixteen,message[09H] ;chapter for + +32 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + convert bh,sixteen,message[0CH] ;description + convert bl,sixteen,message[0EH] ;of CONVERT + display message ;See Function 09H + + + + 33 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get MS-DOS Version Number (Function 30H) + + Call: + + AH = 30H + + Return: + + AL + Major version number + AH + Minor version number + BH + OEM serial number + BL:CX + 24-bit user (serial) number + + + +Comments: + +Function 30H returns the MS-DOS version number. AL returns the major +version number; AH returns the minor version number. (For example, +MS-DOS 3.0 returns 3 in AL and 0 in AH.) + +If AL returns 0, the MS-DOS version is earlier than 2.0. + +Macro Definition: + + +get_version macro + mov ah,30H + int 21H + endm + + +Example: + +The following program displays the MS-DOS version if it is 1.28 or +greater. + +message db "MS-DOS Version . ",0DH,0AH,"$" +ten db 0AH ;For CONVERT +; +begin: get_version ;THIS FUNCTION + cmp al,0 ;1.28 or later? + +34 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + jng return ;No, go home + convert al,ten,message[0FH] ;See end of chapter + convert ah,ten,message[12H] ;for description + display message ;See Function 9 + + + + 35 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Keep Process (Function 31H) + + Call: + + AH = 31H + AL + Return code + DX + Memory size, in paragraphs + + Return: + + None + + + +Comments: + +Function 31H makes a program remain resident after it terminates. You +can use it to install device-specific interrupt handlers. But unlike Interrupt +27H (Terminate But Stay Resident), this function request allows more +than 64K bytes to remain resident and does not require CS to contain the +segment address of the Program Segment Prefix. You should use Function +31H to install a resident program unless your program must be compatible +with MS-DOS versions earlier than 2.0. + +DX must contain the number of paragraphs of memory required by the +program (one paragraph = 16 bytes). AL contains an exit code. + +Be careful when using this function with .exe programs. The value in DX +must be the total size to remain resident, not just the size of the code seg- +ment which is to remain resident. A typical error is to forget about the +100H-byte program-header-prefix and give a value in DX that is 10H too +small. + +MS-DOS terminates the current process and tries to set the memory allo- +cation to the number of paragraphs in DX. No other allocation blocks +belonging to the process are released. + + + +36 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +By using Function 4DH (Get Return Code of Child Process), the parent +process can retrieve the process's exit code from AL. (You can test this +exit code by using the if command with errorlevel.) + +Macro Definition: + + +keep_process macro return_code,last_byte + mov al,return_code + mov dx,offset last_byte + mov cl,4 + shr dx,cl + inc dx + mov ah,31H + int 21H + endm + + +Example: + +Because the most common use of this call is to install a machine-specific +routine, an example is not shown. The macro definition, however, shows +the calling syntax. + + + 37 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +CONTROL-C Check (Function 33H) + + Call: + + AH = 33H + AL + 0 = Get state + 1 = Set state + DL (if AL=1) + 0 = Off + 1 = On + + Return: + + DL (if AL=0) + 0 = Off + 1 = On + AL + FFH = error (AL was neither 0 nor 1 + when call was made) + + +Comments: + +Function 33H gets or sets the state of CONTROL-C (or CONTROL-BREAK for +IBM compatibles) checking in MS-DOS. AL must contain a code that +specifies the requested action: + +Code + Meaning +_ ________________________________________________________________ + +0 Current state of CONTROL-C checking in DL + +1 Set state of CONTROL-C checking to the value in DL + +If AL is 0, DL returns the current state (0=off, 1=on). If AL is 1, the value +in DL specifies the state to be set (0=off, 1=on). If AL is neither 0 nor 1, +AL returns FFH and the state of CONTROL-C checking is unaffected. + +MS-DOS normally checks for CONTROL-C only when carrying out certain +function requests in the 01H through 0CH group (see the description of +specific calls for details). When CONTROL-C checking is on, MS-DOS checks +for CONTROL-C when carrying out any function request. For example, if +CONTROL-C checking is off, all disk I/O proceeds without interruption, but +if it is on, the CONTROL-C interrupt is issued at the function request that +initiates the disk operation. + +_ ________________________________________________________________ + +Note + +38 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + Programs that use Function 06H (Direct Console I/O) or 07H (Direct + Console Input) to read CONTROL-C as data must ensure that the + CONTROL-C checking is off. + +_ ________________________________________________________________ + + +Macro Definition: + + +ctrl_c_ck macro action,state + mov al,action + mov dl,state + mov ah,33H + int 21H + endm + + +Example: + +The following program displays a message that tells whether CONTROL-C +checking is on or off: + +message db "CONTROL-C checking ","$" +on db "on","$",0DH,0AH,"$" +off db "off","$",0DH,0AH,"$" +; +begin: display message ;See Function 09H + ctrl_c_ck 0 ;THIS FUNCTION + cmp dl,0 ;Is checking off? + jg ck_on ;No + display off ;See Function 09H + jmp return ;Go home +ck_on: display on ;See Function 09H + + + + 39 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Interrupt Vector (Function 35H) + + Call: + + AH = 35H + AL + Interrupt number + + Return: + + ES:BX + Pointer to interrupt routine + + + +Comments: + +Function 35H gets the address from the interrupt-vector table for the +specified interrupt. AL must contain the number of an interrupt. + +ES returns the segment address of the interrupt handler; BX returns the +offset. + +To avoid compatibility problems, programs should never read an interrupt +vector directly from memory, nor set an interrupt vector by writing it into +memory. Use this function request to get a vector and Function 25H (Set +Interrupt Vector) to set a vector, unless your program must be compatible +with MS-DOS versions earlier than 2.0. + +Macro Definition: + + +get_vector macro interrupt + mov al,interrupt + mov ah,35H + int 21H + endm + + + +40 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program displays the segment and offset (CS:IP) for the +handler for Interrupt 25H (Absolute Disk Read). + +message db "Interrupt 25H -- CS:0000 IP:0000" + db 0DH,0AH,"$" +vec_seg db 2 dup (?) +vec_off db 2 dup (?) +; +begin: push es ;save ES + get_vector 25H ;THIS FUNCTION + mov ax,es ;INT25H segment in AX + pop es ;save ES + convert ax,16,message[20] ;see end of chapter + convert bx,16,message[28] ;see end of chapter + display message ;See Function 9 + + + + 41 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Disk Free Space (Function 36H) + + Call: + + AH = 36H + DL + Drive (0=default, 1=A, etc.) + + Return: + + AX + 0FFFFH if drive number is invalid; + otherwise, sectors per cluster + BX + Available clusters + CX + Bytes per sector + DX + Clusters per drive + + + +Comments: + +Function 36H returns the number of clusters available on the disk in the +specified drive, and the information necessary to calculate the number of +bytes available on the disk. DL must contain a drive number (0=default, +1=A, etc.). If the drive number is valid, MS-DOS returns the information +in the following registers: + +Register + Contents +_ ________________________________________________________________ + +AX Sectors per cluster + +BX Available clusters + +CX Bytes per sector + +DX Total clusters + +If the drive number is invalid, AX returns 0FFFFH. + +This call supersedes Functions 1BH and 1CH in earlier MS-DOS versions. + + +42 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +get_disk_space macro drive + mov dl,drive + mov ah,36H + int 21H + endm + + +Example: + +The following program displays the space information for the disk in drive +B. + +message db " clusters on drive B.",0DH,0AH ;DX + db " clusters available.",0DH,0AH ;BX + db " sectors per cluster.",0DH,0AH ;AX + db " bytes per sector,",0DH,0AH,"$" ;CX +; +begin: get_disk_space 2 ;THIS FUNCTION + convert ax,10,message[55] ;see end of chapter + convert bx,10,message[28] ;see end of chapter + convert cx,10,message[83] ;see end of chapter + convert dx,10,message ;see end of chapter + display message ;See Function 09H + + + + 43 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Country Data (Function 38H) + + Call: + + AH = 38H + AL + 00H = Current country + 1-0FEH = Country code + 0FFH = BX contains country code + BX (if AL = 0FFH) + Country code 255 or higher + DS:DX + Pointer to 32-byte memory area + + Return: + + Carry set: + AX + 2 = Invalid country code + Carry not set: + BX + Country code + + +Comments: + +Function 38H gets the country-dependent information that MS-DOS uses +to control the keyboard and display, or it sets the currently defined coun- +try (to set the country code, see the next function request description, Set +Country Data). To get the information, DX must contain the offset (from +the segment address in DS) of a 32-byte memory area to which the country +data returns. AL specifies the country code: + +Value in AL + Meaning +_ ________________________________________________________________ + +00H Retrieve information about the country currently set. + +1 to 0FEH Retrieve information about the country identified by this + code. + +0FFH Retrieve information about the country identified by the + code in BX. + +BX must contain the country code if the code is 255 or greater. The coun- +try code is usually the international telephone-prefix code. + + + +44 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +The country-dependent information returns in the following form: + + Offset +Hex Decimal Field Name Length in bytes + +_ ________________________________________________________________ + +00H 0 Date format 2 (word) +02H 2 Currency symbol 5 (ASCIZ string) +07H 7 Thousands separator 2 (ASCIZ string) +09H 9 Decimal separator 2 (ASCIZ string) +0BH 11 Date separator 2 (ASCIZ string) +0DH 13 Time separator 2 (ASCIZ string) +0FH 15 Bit field 1 +10H 16 Currency places 1 +11H 17 Time format 1 +12H 18 Case-map call address 4 (DWORD) +16H 22 Data-list separator 2 (ASCIZ string) +18H 24 Reserved 10 + +_ ________________________________________________________________ + +Date Format: + +0 = USA (month/day/year) +1 = Europe (day/month/year) +2 = Japan (year/month/day) + + +Bit Field: + +Bit Value Meaning + +_ ________________________________________________________________ + +0 0 Currency symbol precedes amount + + 1 Currency symbol follows amount + +1 0 No space between symbol and amount + + 1 One space between symbol and amount + +_ ________________________________________________________________ + +All other bits are undefined. + +Time format: + +0 = 12-hour clock +1 = 24-hour clock + +Currency Places: + + + + 45 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +Specifies the number of places that appear after the decimal point on +currency amounts. + +Case-Mapping Call Address: + +Specifies the segment and offset of a FAR procedure that performs +country-specific lowercase-to-uppercase mapping on character values from +80H to 0FFH. You call it with the character to be mapped in AL. If there +is an uppercase code for the character, it is returned in AL; if there is not, +or if you call it with a value less than 80H in AL, AL returns unchanged. +AL and the FLAGS are the only altered registers. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +2 Invalid country code (no table for it). + + +Macro Definition: + + +get_country macro country,buffer + local gc_01 + mov dx,offset buffer + mov ax,country + cmp ax,OFFH + jl gc_01 + mov al,OFFh + mov bx,country +gc_01: mov ah,38h + int 21H + endm + + +Example: + +The following program displays the time and date in the format appropri- +ate to the current country code, and the number 999,999 and 99/100 as a +currency amount with the proper currency symbol and separators. + +time db " : : ",5 dup (20H),"$" +date db " / / ",5 dup (20H),"$" +number db "999?999?99",0DH,0AH,"$" +data_area db 32 dup (?) +; +begin: get_country 0,data_area ;THIS FUNCTION + get_time ;See Function 2CH + byte_to_dec ch,time ;See end of chapter + byte_to_dec cl,time[03H] ;for description of + byte_to_dec dh,time[06H] ;CONVERT macro + get_date ;See Function 2AH + +46 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + sub cx,1900 ;Want last 2 digits + byte_to_dec cl,date[06H] ;See end of chapter + cmp word ptr data_area,0 ;Check country code + jne not_usa ;It's not USA + byte_to_dec dh,date ;See end of chapter + byte_to_dec dl,date[03H] ;See end of chapter + jmp all_done ;Display data +not_usa: byte_to_dec dl,date ;See end of chapter + byte_to_dec dh,date[03H] ;See end of chapter +all_done: mov al,data_area[07H] ;Thousand separator + mov number[03H],al ;Put in NUMBER + mov al,data_area[09H] ;Decimal separator + mov number[07H],al ;Put in AMOUNT + display time ;See Function 09H + display date ;See Function 09H + display_char data_area[02H] ;See Function 02H + display number ;See Function 09H + + + + 47 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Set Country Data (Function 38H) + + Call: + + AH = 38H + DX = -1 (0FFFFH) + AL + Country code less than 255, or + 0FFH if the country code is in BX + BX (if AL=0FFH) + Country code 255 or higher + + Return: + + Carry set: + AX + 2 = Invalid country code + Carry not set: + No error + + + +Comments: + +Function 38H sets the country code that MS-DOS uses to control the key- +board and the display, or it retrieves the country-dependent information +(to get the country data, see the previous function request description, Get +Country Data). To set the information, DX must contain 0FFFFH. AL +must contain either the country code, if it is less than 255, or 255 to indi- +cate that the country code is in BX. If AL contains 0FFH, BX must con- +tain the country code. + +The country code is usually the international telephone prefix-code. See +"Get Country Data" for a description of the country data and how it is +used. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +2 Invalid country code (no table for it). + + + +48 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +set_country macro country + local sc_01 + mov dx,0FFFFH + mov ax,country + cmp ax,0FFH + jl sc_01 + mov bx,country + mov al,0ffh +sc_01: mov ah,38H + int 21H + endm + + +Example: + +The following program sets the country code to the United Kingdom (44). + +uk equ 44 +; +begin: set_country uk ;THIS FUNCTION + jc error ;routine not shown + + + + 49 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Create Directory (Function 39H) + + Call: + + AH = 39H + DS:DX + Pointer to pathname + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 5 = Access denied + Carry not set: + No error + + + +Comments: + +Function 39H creates a new subdirectory. DX must contain the offset +(from the segment address in DS) of an ASCIZ string that specifies the path- +name of the new subdirectory. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +2 File not found + +3 Path not found + +5 No room in the parent directory, a file with the same name exists + in the current directory, or the path specifies a device + + +Macro Definition: + + +make_dir macro path + mov dx,offset path + mov ah,39H + int 21H + endm + + +50 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program adds a subdirectory named new_dir to the root +directory on the disk in drive B and changes the current directory to +new_dir. The program then changes the current directory back to the ori- +ginal directory and then deletes new_dir. It displays the current directory +after each step to confirm the changes. + +old_path db "b: +new_path db "b:\new_dir",0 +buffer db "b: +; +begin: get_dir 2,old_path[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz old_path ;See end of chapter + make_dir new_path ;THIS FUNCTION + jc error_make ;Routine not shown + change_dir new_path ;See Function 3BH + jc error_change ;Routine not shown + get_dir 2,buffer[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz buffer ;See end of chapter + change_dir old_path ;See Function 3BH + jc error_change ;Routine not shown + rem_dir new_path ;See Function 3AH + jc error_rem ;Routine not shown + get_dir 2,buffer[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz buffer ;See end of chapter + + + + 51 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Remove Directory (Function 3AH) + + Call: + + AH = 3AH + DS:DX + Pointer to pathname + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 5 = Access denied + 16 = Current directory + Carry not set: + No error + + + +Comments: + +Function 3AH deletes a subdirectory. DX must contain the offset (from the +segment address in DS) of an ASCIZ string that specifies the pathname of +the subdirectory you want to delete. + +The subdirectory must not contain any files. You cannot erase the current +directory. If there is an error, the carry flag (CF) is set and the error code +returns in AX: + +Code + Meaning +_ ________________________________________________________________ + +2 File not found + +3 Path not found + +5 Directory not empty, or path doesn't specify a directory, or it + specifies the root directory, or it is invalid + +16 Path specifies current directory + + + +52 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +rem_dir macro path + mov dx,offset path + mov ah,3AH + int 21H + endm + + +Example: + +The following program adds a subdirectory named new_dir to the root +directory on the disk in drive B and changes the current directory to +new_dir. The program then changes the current directory back to the ori- +ginal directory and deletes new_dir. It displays the current directory after +each step to confirm the changes. + +old_path db "b: +new_path db "b:\new_dir",0 +buffer db "b: +; +begin: get_dir 2,old_path[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz old_path ;See end of chapter + make_dir new_path ;See Function 39H + jc error_make ;Routine not shown + change_dir new_path ;See Function 3BH + jc error_change ;Routine not shown + get_dir 2,buffer[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz buffer ;See end of chapter + change_dir old_path ;See Function 3BH + jc error_change ;Routine not shown + rem_dir new_path ;THIS FUNCTION + jc error_rem ;Routine not shown + get_dir 2,buffer[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz buffer ;See end of chapter + + + + 53 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Change Current Directory (Function 3BH) + + Call: + + AH = 3BH + DS:DX + Pointer to pathname + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + Carry not set: + No error + + + +Comments: + +Function 3BH changes the current directory. DX must contain the offset +(from the segment address in DS) of an ASCIZ string that specifies the path- +name of the new current directory. + +The directory string is limited to 64 characters. + +If any member of the path doesn't exist, the path is unchanged. If there is +an error, the carry flag (CF) is set and the error code returns in AX: + +Code + Meaning +_ ________________________________________________________________ + +2 File not found + +3 Path either doesn't exist or it specifies a file instead of a directory + + +Macro Definition: + + +change_dir macro path + mov dx,offset path + mov ah,3BH + int 21H + endm + + + +54 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program adds a subdirectory named new_dir to the root +directory that is on the disk in drive B and changes the current directory +to new_dir. The program then changes the current directory back to the +original directory and deletes new_dir. It displays the current directory +after each step to confirm the changes. + +old_path db "b: +new_path db "b:\new_dir",0 +buffer db "b: +; +begin: get_dir 2,old_path[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz old_path ;See end of chapter + make_dir new_path ;See Function 39H + jc error_make ;Routine not shown + change_dir new_path ;THIS FUNCTION + jc error_change ;Routine not shown + get_dir 2,buffer[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz buffer ;See end of chapter + change_dir old_path ;See Function 3BH + jc error_change ;Routine not shown + rem_dir new_path ;See Function 3AH + jc error_rem ;Routine not shown + get_dir 2,buffer[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz buffer ;See end of chapter + + + + 55 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Create Handle (Function 3CH) + + Call: + + AH = 3CH + DS:DX + Pointer to pathname + CX + File attribute + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 4 = Too many open files + 5 = Access denied + Carry not set: + AX + Handle + + +Comments: + +Function 3CH creates a file and assigns it the first available handle. DX +must contain the offset (from the segment address in DS) of an ASCIZ string +that specifies the pathname of the file to be created. CX must contain the +attribute to be assigned to the file, as described under "File Attributes" +earlier in this chapter. + +If the specified file does not exist, this function creates it. But if the file +already exists, it is truncated to a length of 0. Function 3CH then assigns +the attribute in CX to the file and opens it for read/write. AX returns the +file handle. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +2 File not found + +3 Path is invalid + +4 Too many open files (no handle available) + +5 Directory is full, a directory with the same name exists, or a file + with the same name exists with more restrictive attributes + + +56 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +create_handle macro path,attrib + mov dx,offset path + mov cx,attrib + mov ah,3CH + int 21H + endm + + +Example: + +The following program creates a file named dir.tmp, containing the name +and extension of each file in the current directory, on the disk in drive B. + +srch_file db "b:*.*",0 +tmp_file db "b:dir.tmp",0 +buffer db 43 dup (?) +handle dw ? +; +begin: set_dta buffer ;See Function 1AH + find_first_file srch_file,16H ;See Function 4EH + cmp ax,12H ;Directory empty? + je all_done ;Yes, go home + create_handle tmp_file,0 ;THIS FUNCTION + jc error ;Routine not shown + mov handle,ax ;Save handle +write_it: write_handle handle,buffer[1EH],12 ;Function 40H + find_next_file ;See Function 4FH + cmp ax,12H ;Another entry? + je all_done ;No, go home + jmp write_it ;Yes, write record +all_done: close_handle handle ;See Function 3EH + + + + 57 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Open Handle (Function 3DH) + + Call: + + AH = 3DH + AL + Access code (see text) + DS:DX + Pointer to pathname + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 4 = Too many open files + 5 = Access denied + 12 = Invalid access + Carry not set: + No error + + +Comments: + +Function 3DH opens any file, including hidden and system files, for input +or output. DX contains the offset (from the segment address in DS) of an +ASCIZ string that specifies the pathname of the file to be opened. AL con- +tains a code that specifies how the file is to be opened. This code is +described later under "Controlling Access to the File." + +If there is no error, AX returns the file handle. MS-DOS sets the read/write +pointer to the first byte of the file. + + +58 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Controlling Access to the File + +The value in AL is made up of three parts that specify whether the file is +to be opened for read, write, or both (access code); what access other +processes have to the file (sharing mode); and whether a child process +inherits the file (inherit bit). + + |---|-----------|---------------| +Bit | 7 | 6 5 4 | 3 2 1 0 | + |---|---|---|---|---|---|---|---| + + \/ \________/ \____________/ + | | | + | | |--------> Access code + | | + | |-----------------------> Sharing mode + | + |-------------------------------> Inherit bit + + +Inherit Bit The high-order bit (bit 7) specifies whether the file is inherited +by a child process created with Function 4BH (Load and Execute Pro- +gram). If the bit is 0, the child process inherits the file; if the bit is 1, it +doesn't. + + + 59 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Sharing Mode + +The sharing mode bits (bits 4-6) specify what access, if any, other +processes have to the open file. It can have the following values: + + +Table 0.2 + +Sharing Mode Bit Values + +_ _________________________________________________________________________ + +Bits 4-6 Sharing Mode Description + +_ _________________________________________________________________________ + +000 Compatibility + + On a given machine, any process can open the file + any number of times with this mode. Fails if the file + has been opened with any of the other sharing + modes. + +001 Deny both + + Fails if the file has been opened in compatibility + mode or for read or write access, even if by the + current process. + +010 Deny write + + Fails if the file has been opened in compatibility + mode or for write access by any other process. + +011 Deny read + + Fails if the file has been opened in compatibility + mode or for read access by any other process. + +100 Deny none + + Fails if the file has been opened in compatibility + mode by any other process. + +_ _________________________________________________________________________ + + + +60 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Access Code + +The access code (bits 0-3) specifies how the file is to be used. It can have +the following values: + + +Table 0.3 + +Access Code Bit Values + +_ _________________________________________________________________________ + + Access +Bits 0-3 Allowed Description + +_ _________________________________________________________________________ + +0000 Read + + Fails if the file has been opened in deny read or deny both + sharing mode. + +0001 Write + + Fails if the file has been opened in deny write or deny both + sharing mode. + +0010 Both + + Fails if the file has been opened in deny read, deny write, or + deny both sharing mode. + +_ _________________________________________________________________________ + +If there is an error, the carry flag (CF) is set and the error code is returned +in AX: + +Code + Meaning +_ ________________________________________________________________ + +2 Specified file is invalid or doesn't exist + +3 Specified path is invalid or doesn't exist + +4 No handles are available in the current process or the internal sys- + tem tables are full + +5 Program attempted to open a directory or VolumeID, or tried to + open a read-only file for writing + +12 Access code (bits 0-3 of AL) not 0, 1, or 2 + +If this system call fails because of a file-sharing error, MS-DOS issues +Interrupt 24H with error code 2 (Drive Not Ready). A subsequent Function +59H (Get Extended Error) returns the extended error code that specifies a +sharing violation. + +When opening a file, it is important to inform MS-DOS of any operations +that other processes may perform on this file (sharing mode). The default +(compatibility mode) denies all other processes access to the file, unless +they also attempt to open the file in compatibility mode. + +The following table shows the effect of opening a file with compatibility +mode set: + + + + 61 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +Type of File Opening Read-Only File Not Read-Only + +_ ________________________________________________________________ + +First open for read, write, Succeeds Succeeds +or both by machine/process +"N" + +Subsequent opens by machine Succeeds Succeeds +or process +"N" + +An open by another machine Succeeds Fails +or process + +_ ________________________________________________________________ + +Files may be read-only with the MS-DOS attrib command or by a read-only +share over the network. + +It may be all right for other processes to continue to read the file while +your process is operating on it. In this case, you should specify "Deny +Write," which inhibits other processes from writing to your files but allows +them to read from these files. + +Similarly, it is important for you to specify what operations your process +will perform ("Access" mode). If another process has the file open with +any sharing mode other than "Deny" mode, then the default mode +("Read/write") causes the open request to fail. If you only want to read +the file, your open request succeeds unless all other processes have +specified "Deny" mode or "Deny write." + +Macro Definition: + + +open_handle macro path,access + mov dx, offset path + mov al, access + mov ah, 3DH + int 21H + endm + + +Example: + +The following program prints a file named textfile.asc that is on the disk in +drive B. + +file db "b:textfile.asc",0 +buffer db ? +handle dw ? +; +begin: open_handle file,0 ;THIS FUNCTION + mov handle,ax ;Save handle +read_char: read_handle handle,buffer,1 ;Read 1 character + +62 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + jc error_read ;Routine not shown + cmp ax,0 ;End of file? + je return ;Yes, go home + print_char buffer ;See Function 05H + jmp read_char ;Read another + + + + 63 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Close Handle (Function 3EH) + + Call: + + AH = 3EH + BX + Handle + + Return: + + Carry set: + AX + 6 = Invalid handle + Carry not set: + No error + + + +Comments: + +Function 3EH closes a file opened with Function 3DH (Open Handle) or +3CH (Create Handle). BX must contain the handle of the open file that you +want to close. + +If there is no error, MS-DOS closes the file and flushes all internal buffers. +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +6 Handle not open or invalid + + +Macro Definition: + + +close_handle macro handle + mov bx,handle + mov ah,3EH + int 21H + endm + + + +64 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program creates a file named dir.tmp, containing the +filename and extension of each file in the current directory, in the current +directory on the disk in drive B. + +srch_file db "b:*.*",0 +tmp_file db "b:dir.tmp",0 +buffer db 43 dup (?) +handle dw ? +; +begin: set_dta buffer ;See Function 1AH + find_first_file srch_file,16H ;See Function 4EH + cmp ax,12H ;Directory empty? + je all_done ;Yes, go home + create_handle tmp_file,0 ;See Function 3CH + jc error_create ;Routine not shown + mov handle,ax ;Save handle +write_it: write_handle handle,buffer[1EH],12 ;See Function + jc error_write ;40H + find_next_file ;See Function 4FH + cmp ax,12H ;Another entry? + je all_done ;No, go home + jmp write_it ;Yes, write record +all_done: close_handle handle ;See Function 3EH + jc error_close ;Routine not shown + + + + 65 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Read Handle (Function 3FH) + + Call: + + AH = 3FH + BX + Handle + CX + Bytes to read + DS:DX + Pointer to buffer + + Return: + + Carry set: + AX + 5 = Access denied + 6 = Invalid handle + Carry not set: + AX + Bytes read + + +Comments: + +Function 3FH reads from the file or device associated with the specified +handle. BX must contain the handle. CX must contain the number of +bytes to be read. DX must contain the offset (to the segment address in +DS) of the buffer. + +If there is no error, AX returns the number of bytes read; if you attempt to +read starting at end of file, AX returns 0. The number of bytes specified in +CX is not necessarily transferred to the buffer; if you use this call to read +from the keyboard, for example, it reads only up to the first carriage- +return. + +If you use this function request to read from standard input, you can +redirect the input. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +5 Handle not open for reading + +6 Handle not open or invalid + + + +66 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +read_handle macro handle,buffer,bytes + mov bx,handle + mov dx,offset buffer + mov cx,bytes + mov ah,3FH + int 21H + endm + + +Example: + +The following program displays a file named textfile.asc that is on the disk +in drive B. + +filename db "b:\textfile.asc",0 +buffer db 129 dup (?) +handle dw ? +; +begin: open_handle filename,0 ;See Function 3DH + jc error_open ;Routine not shown + mov handle,ax ;Save handle +read_file: read_handle buffer,file_handle,128 + jc error_open ;Routine not shown + cmp ax,0 ;End of file? + je return ;Yes, go home + mov bx,ax ;# of bytes read + mov buffer[bx],"$" ;Make a string + display buffer ;See Function 09H + jmp read_file ;Read more + + + + 67 + +_ _ | | _ _ + + + diff --git a/PROGREF/1D_CALLS.A b/PROGREF/1D_CALLS.A new file mode 100644 index 0000000..c4eaeb9 --- /dev/null +++ b/PROGREF/1D_CALLS.A @@ -0,0 +1,3710 @@ + +_ _ | | _ _ + + + + _ ______________ + + +Write Handle (Function 40H) + + Call: + + AH = 40H + BX + Handle + CX + Bytes to write + DS:DX + Pointer to buffer + + Return: + + Carry set: + AX + 5 = Access denied + 6 = Invalid handle + Carry not set: + AX + Bytes written + + +Comments: + +Function 40H writes to the file or device associated with the specified han- +dle. BX must contain the handle. CX must contain the number of bytes to +be written. DX must contain the offset (to the segment address in DS) of +the data to be written. + +If you set CX to zero, the file will be truncated at the current position of +the file pointer. MS-DOS will not perform the write if the handle is read- +only. + +If there is no error, AX returns the number of bytes written. Be sure to +check AX after performing a write. If its value is less than the number in +CX when the call was made, it indicates an error, even though the carry +flag isn't set. If AX contains 0, and if the target is a disk file, the disk is +full. + +If you use this function request to write to standard output, you can +redirect the output. If you call this request with CX=0, the file size is set +to the value of the read/write pointer. To satisfy the new file size, alloca- +tion units are allocated or released, as required. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + + 1 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + Meaning +_ ________________________________________________________________ + +5 Handle not open for writing + +6 Handle not open or invalid + + +Macro Definition: + + +write_handle macro handle,buffer,bytes + mov bx,handle + mov dx,offset buffer + mov cx,bytes + mov ah,40H + int 21H + endm + + +Example: + +The following program creates a file named dir.tmp, containing the +filename and extension of each file in the current directory, in the current +directory on the disk in drive B. + +srch_file db "b:*.*",0 +tmp_file db "b:dir.tmp",0 +buffer db 43 dup (?) +handle dw ? +; +begin: set_dta buffer ;See Function 1AH + find_first_file srch_file,16H ;Check directory + cmp ax,12H ;Directory empty? + je return ;Yes, go home + create_handle tmp_file,0 ;See Function 3CH + jc error_create ;Routine not shown + mov handle,ax ;Save handle +write_it: write_handle handle,buffer[1EH],12 ;THIS FUNCTION + jc error_write ;Routine not shown + find_next_file ;Check directory + cmp ax,12H ;Another entry? + je all_done ;No, go home + jmp write_it ;Yes, write record +all_done: close_handle handle ;See Function 3EH + jc error_close ;Routine not shown + + + +2 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Delete Directory Entry [Unlink] (Function 41H) + + Call: + + AH = 41H + DS:DX + Pointer to pathname + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 5 = Access denied + Carry not set: + No error + + + +Comments: + +Function 41H erases a file by deleting its directory entry. DX must con- +tain the offset (from the segment address in DS) of an ASCIZ string that +specifies the pathname of the file that you want to delete. You cannot use +wildcard characters. + +If the file exists and is not read-only, the call deletes it. If there is an error, +the call sets the carry flag (CF) and the error code returns in AX: + +Code + Meaning +_ ________________________________________________________________ + +2 File doesn't exist, or specifies a directory + +3 Path is invalid + +5 File is read-only + +To delete a file with the read-only attribute, first change its attribute to 0 +with Function 43H (Get/Set File Attribute). + + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +delete_entry macro path + mov dx,offset path + mov ah,41H + int 21H + endm + + +Example: + +The following program deletes all files, dated before December 31, 1986, +from the disk in drive B. + +year db 1986 +month db 12 +day db 31 +files db ? +message db "NO FILES DELETED.",0DH,0AH,"$" +path db "b:*.*", 0 +buffer db 43 dup (?) +; +begin: set_dta buffer ;See Function 1AH + select_disk "B" ;See Function 0EH + find_first_file path,0 ;See Function 4EH + jnc compare ;got one + jmp all_done ;no match, go home +compare: convert_date buffer[-1] ;See end of chapter + cmp cx,year ;After 1986? + jg next ;Yes, don't delete + cmp dl,month ;After December? + jg next ;Yes, don't delete + cmp dh,day ;31st or after? + jge next ;Yes, don't delete + delete_entry buffer[1EH] ;THIS FUNCTION + jc error_delete ;Routine not shown + inc files ;Bump file counter +next: find_next_file ;Check directory + jnc compare ;Go home if done +how_many: cmp files,0 ;Was directory empty? + je all_done ;Yes, go home + convert files,10,message ;See end of chapter +all_done: display message ;See Function 09H + select_disk "A" ;See Function 0EH + + + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Move File Pointer (Function 42H) + + Call: + + AH = 42H + AL + Method of moving + BX + Handle + CX:DX + Distance in bytes (offset) + + Return: + + Carry set: + AX + 1 = Invalid function + 6 = Invalid handle + Carry not set: + DX:AX + New read/write pointer location + + +Comments: + +Function 42H moves the read/write pointer of the file associated with the +specified handle. BX must contain the handle. CX and DX must contain a +32-bit offset (CX contains the most significant byte). AL must contain a +code that specifies how to move the pointer: + +Code + Cursor Moved to +_ ________________________________________________________________ + +0 Beginning of file plus the offset + +1 Current pointer location plus the offset + +2 End of file plus the offset + +DX and AX return the new location of the read/write pointer (a 32-bit +integer; DX contains the most significant byte). You can determine the +length of a file by setting CX:DX to 0, AL to 2, and calling this function. +DX:AX returns the offset of the byte following the last byte in the file (size +of the file in bytes). + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +1 AL not 0, 1, or 2 + +6 Handle not open + + +Macro Definition: + + +move_ptr macro handle,high,low,method + mov bx,handle + mov cx,high + mov dx,low + mov al,method + mov ah,42H + int 21H + endm + + +Example: + +The following program prompts for a letter, converts it to its alphabetic +sequence (A=1, B=2, etc.), then reads and displays the corresponding +record from the file named alphabet.dat that is in the current directory on +the disk in drive B. The file contains 26 records, each 28 bytes long. + +file db "b:alphabet.dat",0 +buffer db 28 dup (?),"$" +prompt db "Enter letter: $" +crlf db 0DH,0AH,"$" +handle db ? +record_length dw 28 +; +begin: open_handle file,0 ;See Function 3DH + jc error_open ;Routine not shown + mov handle,ax ;Save handle +get_char: display prompt ;See Function 09H + read_kbd_and_echo ;See Function 01H + sub al,41h ;Convert to sequence + mul byte ptr record_length ;Calculate offset + move_ptr handle,0,ax,0 ;THIS FUNCTION + jc error_move ;Routine not shown + read_handle handle,buffer,record_length + jc error_read ;Routine not shown + cmp ax,0 ;End of file? + je return ;Yes, go home + display crlf ;See Function 09H + display buffer ;See Function 09H + display crlf ;See Function 09H + jmp get_char ;Get another character + + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Get/Set File Attributes (Function 43H) + + Call: + + AH = 43H + AL + 0 = Get attributes + 1 = Set attributes + CX (if AL=1) + Attributes to be set + DS:DX + Pointer to pathname + + Return: + + Carry set: + AX + 1 = Invalid function + 2 = File not found + 3 = Path not found + 5 = Access denied + Carry not set: + CX + Attribute byte (if AL=0) + + +Comments: + +Function 43H gets or sets the attributes of a file. DX must contain the +offset (from the segment address in DS) of an ASCIZ string that specifies the +pathname of a file. AL must specify whether to get or set the attribute +(0=get, 1=set). + +If AL is 0 (get the attribute), the attribute byte returns in CX. If AL is 1 +(set the attribute), CX must contain the attributes to be set. The attri- +butes are described under "File Attributes" earlier in this chapter. + +You cannot change the VolumeID bit (08H) or the Subdirectory bit (10H) +of the attribute byte with this function. + + + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 AL not 0 or 1 + +2 File doesn't exist + +3 Path invalid + +5 Attribute in CX cannot be changed (Subdirectory or VolumeID). + + +Macro Definition: + + +change_attr macro path,action,attrib + mov dx,offset path + mov al,action + mov cx,attrib + mov ah,43H + int 21H + endm + + +Example: + +The following program displays the attributes assigned to the file named +report.asm that is in the current directory on the disk in drive B. + +header db 15 dup (20h),"Read-",0DH,0AH + db "Filename Only Hidden " + db "System Volume Sub-Dir Archive" + db 0DH,0AH,0DH,0AH,"$" +path db "b:report.asm",3 dup (0),"$" +attribute dw ? +blanks db 9 dup (20h),"$" +; +begin: change_attr path,0,0 ;THIS FUNCTION + jc error_mode ;Routine not shown + mov attribute,cx ;Save attribute byte + display header ;See Function 09H + display path ;See Function 09H + mov cx,6 ;Check 6 bits (0-5) + mov bx,1 ;Start with bit 0 +chk_bit: test attribute,bx ;Is the bit set? + jz no_attr ;No + display_char "X" ;See Function 02H + jmp short next_bit ;Done with this bit +no_attr: display_char 20h ;See Function 02H +next_bit: display blanks ;See Function 09H + shl bx,1 ;Move to next bit + loop chk_bit ;Check it + + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +IOCtl Data (Function 44H, Codes 0 and 1) + + Call: + + AH = 44H + AL + 0 = Get device data + 1 = Set device data + BX + Handle + DX + Device data (see text) + + Return: + + Carry set: + AX + 1 = Invalid function + 6 = Invalid handle + Carry not set: + DX + Device data + + +Comments: + +Function 44H, Codes 0 and 1, either gets or sets the data MS-DOS uses to +control the device. AL must contain 0 to get the data or 1 to set it. BX +must contain the handle. If AL is 1, DH must contain 0. + +The device-data word is specified or returned in DX. If bit 7 of the data is +1, the handle refers to a device and the other bits have the following mean- +ings: + + + 9 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +Table 0.1 + +MS-DOS Data Bit Values + +_ _________________________________________________________________________ + +Bit Value Meaning + +_ _________________________________________________________________________ + +0 1 Console input device +1 1 Console output device +2 1 Null device +3 1 Clock device +4 1 Reserved +5 1 Don't check for control characters + 0 Check for control characters +6 0 End of file on input +8-10 Reserved +11 1 Device understands open/close +12 Reserved +13 1 Device supports output until busy +14 1 + + Device can process control strings sent with Function 44H, Codes + 2 and 3 (IOCtl character); bit can be read only, but not set +15 Reserved + +_ _________________________________________________________________________ + +You must set the reserved bits to zero. + +The control characters referred to in the description of bit 5 are +CONTROL-C, CONTROL-P, CONTROL-S, and CONTROL-Z. To read these charac- +ters as data, instead of as control characters, you must set bit 5 and use +either Function 33H, CONTROL-C Check, or the MS-DOS break command +to turn off CONTROL-C checking. + +If bit 7 of DX is 0, the handle refers to a file and the other bits have the +following meanings: + +Bit Value Meaning + +_ ________________________________________________________________ + +0-5 Drive number (0=A, 1=B, etc.) +6 0 The file has been written +8-15 Reserved + +_ ________________________________________________________________ + + + +10 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 AL not 0 or 1, or AL is 1 but DH is not 0 + +6 Handle in BX not open or is invalid + + +Macro Definition: + + +ioctl_data macro code,handle + mov bx,handle + mov al,code + mov ah,44H + int 21H + endm + + +Example: + +The following program gets the device data for standard output, sets the +bit that specifies not to check for control characters (bit 5), and then +clears the bit. + +get equ 0 +set equ 1 +stdout equ 1 +; +begin: ioctl_data get,stdout ;THIS FUNCTION + jc error ;routine not shown + mov dh,0 ;clear DH + or dl,20H ;set bit 5 + ioctl_data set,stdout ;THIS FUNCTION + jc error ;routine not shown +; +; +; + ioctl_data get,stdout ;THIS FUNCTION + jc error ;routine not shown + mov dh,0 ;clear DH + and dl,0DFH ;clear bit 5 + ioctl_data set,stdout ;THIS FUNCTION +; +; +; + + + + 11 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +IOCtl Character (Function 44H, Codes 2 and 3) + + Call: + + AH = 44H + AL + 2 = Send control data + 3 = Receive control data + BX + Handle + CX + Bytes to read or write + DS:DX + Pointer to buffer + + Return: + + Carry set: + AX + 1 = Invalid function + 6 = Invalid handle + Carry not set: + AX + Bytes transferred + + +Comments: + +Function 44H, Codes 2 and 3, sends or receives control data to or from a +character device. AL must contain 2 to send data or 3 to receive. BX must +contain the handle of a character device, such as a printer or serial port. +CX must contain the number of bytes to be read or written. DX must con- +tain the offset (to the segment address in DS) of the data buffer. + +AX returns the number of bytes transferred. The device driver must sup- +port the IOCtl interface. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 AL not 2 or 3, or device cannot perform the specified function + +6 Handle in BX not open or doesn't exist + + + +12 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +ioctl_char macro code,handle,buffer + mov bx,handle + mov dx,offset buffer + mov al,code + mov ah,44H + int 21H + endm + + +Example: + +No general example is applicable, since processing of IOCtl control data +depends on the device being used, as well as the device driver. + + + 13 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +IOCtl Block (Function 44H, Codes 4 and 5) + + Call: + + AH = 44H + AL + 4 = Send control data + 5 = Receive control data + BL + Drive number (0=default, 1=A, etc.) + CX + Bytes to read or write + DS:DX + Pointer to buffer + + Return: + + Carry set: + AX + 1 = Invalid function + 5 = Invalid drive + Carry not set: + AX + Bytes transferred + + +Comments: + +Function 44H, Codes 4 and 5, sends or receives control data to or from a +block device. AL must contain 4 to send data or 5 to receive. BL must con- +tain the drive number (0=default, 1=A, etc.). CX must contain the +number of bytes to be read or written. DX must contain the offset (to the +segment address in DS) of the data buffer. + +AX returns the number of bytes transferred. The device driver must sup- +port the IOCtl interface. To determine whether it does, use Function 44H, +Code 0, to get the device data, and test bit 14; if the bit is set, the driver +supports IOCtl. + + + +14 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 AL not 4 or 5, or device cannot perform the specified function + +5 Number in BL not a valid drive number + + +Macro Definition: + + +ioctl_status macro code,drive,buffer + mov bl,drive + mov dx,offset buffer + mov al,code + mov ah,44H + int 21H + endm + + +Example: + +No general example is applicable, since processing of IOCtl control data +depends on the device being used, as well as the device driver. + + + 15 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +IOCtl Status (Function 44H, Codes 6 and 7) + + Call: + + AH = 44H + AL + 6 = Check input status + 7 = Check output status + BX + Handle + + Return: + + Carry set: + AX + 1 = Invalid function + 5 = Access denied + 6 = Invalid handle + 13 = Invalid data + Carry not set: + AL + 00H = Not ready + 0FFH= Ready + + +Comments: + +Function 44H, Codes 6 and 7, checks whether the file or device associated +with a handle is ready. AL must contain 6 to check whether the handle is +ready for input or 7 to check whether the handle is ready for output. BX +must contain the handle. + +AL returns the status: + + Meaning for Meaning for Meaning for +Value Device Input File Output File + +_ ________________________________________________________________ + +00H Not ready Pointer is at EOF Ready +0FFH Ready Ready Ready + +_ ________________________________________________________________ + +An output file always returns ready, even if the disk is full. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + + +16 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +1 AL not 6 or 7 + +5 Access denied + +6 Number in BX not a valid, open handle + +13 Invalid data + + +Macro Definition: + + +ioctl_status macro code,handle + mov bx,handle + mov al,code + mov ah,44H + int 21H + endm + + +Example: + +The following program displays a message that tells whether the file asso- +ciated with handle 6 is ready for input or whether it is at end-of-file. + +stdout equ 1 +; +message db "File is " +ready db "ready." +at_eof db "at EOF." +crlf db ODH,OAH +; +begin: write_handle stdout,message,8 ;display message + jc write_error ;routine not shown + ioctl_status 6 ;THIS FUNCTION + jc ioctl_error ;routine not shown + cmp al,0 ;check status code + jne not_eof ;file is ready + write_handle stdout,at_eof,7 ;see Function 40H + jc write_error ;routine not shown + jmp all_done ;clean up & go home +not_eof: write_handle stdout,ready,6 ;see Function 40H +all_done: write_handle stdout,crlf,2 ;see Function 40H + jc write_error ;routine not shown + + + + 17 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +IOCtl Is Changeable (Function 44H, Code 08H) + + Call: + + AH = 44H + AL = 08H + BL + Drive number (0=default, 1=A, etc.) + + Return: + + Carry set: + AX + 1 = Invalid function + 15 = Invalid drive + Carry not set: + AX + 0 = Changeable + 1 = Not changeable + + + +Comments: + +Function 44H, Code 08H, checks whether a drive contains a removable or +nonremovable disk. BL must contain the drive number (0=default, 1=A, +etc.). AX returns 0 if the disk can be changed, 1 if it cannot. + +This call lets a program determine whether to issue a message to change +disks. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX. + +Code + Meaning +_ ________________________________________________________________ + +1 Device does not support this call + +15 Number in BL not a valid drive number + +When the call returns error 1 (because the driver doesn't support it), the +caller asssumes that the driver cannot be changed. + + +18 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +ioctl_change macro drive + mov bl, drive + mov al, 08H + mov ah, 44H + int 21H + endm + + +Example: + +The following program checks whether the current drive contains a remov- +able disk. If not, processing continues; if so, the program prompts the user +to replace the disk in the current drive. + +stdout equ 1 +; +message db "Please replace disk in drive " +drives db "ABCD" +crlf db 0DH,0AH +; +begin: ioctl_change 0 ;THIS FUNCTION + jc ioctl_error ;routine not shown + cmp ax,0 ;current drive changeable? + jne continue ;no, continue processing + write_handle stdout,message,29 ;see Function 40H + jc write_error ;routine not shown + current_disk ;see Function 19H + xor bx,bx ;clear index + mov bl,al ;get current drive + display_char drives[bx] ;see Function 02H + write_handle stdout,crlf,2 ;see Function 40H + jc write_error ;routine not shown +continue: +; (Further processing here) + + + + 19 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +IOCtl Is Redirected Block (Function 44H, Code +09H) + + Call: + + AH = 44H + AL = 09H + BL + Drive number (0=default, 1=A, etc.) + + Return: + + Carry set: + AX + 1 = Invalid function code + 15 = Invalid drive number + Carry not set: + DX + Device-attribute bits + + + +Comments: + +Function 44H, Code 09H, checks whether a drive letter refers to a drive on +a Microsoft Networks workstation (local) or is redirected to a server +(remote). BL must contain the drive number (0=default, 1=A, etc.). + +If the block device is local, DX returns the attribute word from the device +header. If the block device is remote, only bit 12 (1000H) is set; the other +bits are 0 (reserved). + +An application program should not test bit 12, because applications +should not make distinctions between local and remote files (or devices). +Programs should be written so that they will be independent of the loca- +tion of a device that has been removed. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 File sharing must be loaded to use this system call + +15 Number in BL not a valid drive number + + + +20 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +ioctl_rblock macro drive + mov bl, drive + mov al, 09H + mov ah, 44H + int 21H + endm + + +Example: + +The following program checks whether drive B is local or remote and +displays the appropriate message. + +stdout equ 1 +; +message db "Drive B: is " +loc db "local." +rem db "remote." +crlf db 0DH,0AH +; +begin: write_handle stdout,message,12 ;display message + jc write_error ;routine not shown + ioctl_rblock 2 ;THIS FUNCTION + jc ioctl_error ;routine not shown + test dx,1000h ;bit 12 set? + jnz not_loc ;yes, it's remote + write_handle stdout,loc,6 ;see Function 40H + jc write_error ;routine not shown + jmp done +not_loc: write_handle stdout,rem,7 ;see Function 40H + jc write_error ;routine not shown +done: write_handle stdout,crlf,2 ;see Function 40H + jc write_error ;routine not shown + + + + 21 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +IOCtl Is Redirected Handle (Function 44H, +Code 0AH) + + Call: + + AH = 44H + AL = 0AH + BX + Handle + + Return: + + Carry set: + AX + 1 = Invalid function code + 6 = Invalid handle + Carry not set: + DX + IOCtl bit field + + + +Comments: + +Function 44H, Code 0AH, checks whether a handle refers to a file or a dev- +ice on a Microsoft Networks workstation (local) or is redirected to a server +(remote). BX must contain the file handle. DX returns the IOCtl bit field; +bit 15 is set if the handle refers to a remote file or device. + +An application program should not test bit 15, because applications +should not make distinctions between local and remote files (or devices). +Programs should be written so that they will be independent of the loca- +tion of a device that has been removed. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 Network must be loaded to use this system call + +6 Handle in BX not a valid, open handle + + + +22 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +ioctl_rhandle macro handle + mov bx, handle + mov al, 0AH + mov ah, 44H + int 21H + endm + + +Example: + +The following program checks whether handle 5 refers to a local or remote +file or a device and displays the appropriate message. + +stdout equ 1 +; +message db "Handle 5 is " +loc db "local." +rem db "remote." +crlf db 0DH,0AH +; +begin: write_handle stdout,message,12;display message + jc write_error ;routine not shown + ioctl_rhandle 5 ;THIS FUNCTION + jc ioctl_error ;routine not shown + test dx,8000h ;bit 15 set? + jnz not_loc ;yes, it's remote + write_handle stdout,loc,6 ;see Function 40H + jc write_error ;routine not shown + jmp done +not_loc: write_handle stdout,rem,7 ;see Function 40H + jc write_error ;routine not shown +done: write_handle stdout,crlf,2 ;see Function 40H + jc write_error ;routine not shown + + + + 23 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +IOCtl Retry (Function 44H, Code 0BH) + + Call: + + AH = 44H + AL = 0BH + DX + Number of retries + CX + Wait time + + Return: + + Carry set: + AX + 1 = Invalid function code + Carry not set: + No error + + + +Comments: + +Function 44H, Code 0BH, specifies how many times MS-DOS should retry +a disk operation that fails because of a file-sharing violation. DX must +contain the number of retries. CX controls the pause between retries. + +MS-DOS retries this type of disk operation three times, unless you use this +system call to specify a different number. After the specified number of +retries, MS-DOS issues Interrupt 24H (Critical-Error-Handler Address) for +the requesting process. + +The effect of the delay parameter in CX is machine-dependent because it +specifies how many times MS-DOS should execute an empty loop. The +actual time varies, depending on the processor and clock speed. You can +determine the effect on your machine by using debug. Set the number of +retries to 1 and then time several values of CX. + + + +24 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 File sharing must be loaded to use this system call + + +Macro Definition: + + +ioctl_retry macro retries, wait + mov dx, retries + mov cx, wait + mov al, 0BH + mov ah, 44H + int 21H + endm + + +Example: + +The following program sets the number of sharing retries to 10 and +specifies a delay of 1000 between retries. + +begin: ioctl_retry 10,1000 ;THIS FUNCTION + jc error ;routine not shown + + + + 25 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Generic IOCtl (for Handles) (Function 44H, +Code 0CH) + + Call: + + AH = 44H + AL = 0CH + BX + Handle + CH = 05H + Category code (printer device) + CL + Function (minor) code + DS:DX + Pointer to data buffer + + Return: + + Carry set: + AX + 1 = Invalid function code + Carry not set: + No error + + +Comments: + +This call loads and selects code pages for devices on a per-device basis. It +also sets or gets the output iteration count for a printer that supports +"PRINT 'TIL BUSY." + +The category code may be one of the following: + +Code + Meaning +_ ________________________________________________________________ + +00 Unknown device + +01 Serial printer + +03 Console device + +05 Parallel printer + +The function code may be one of the following: + +Code + Meaning +_ ________________________________________________________________ + + + +26 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +45H Sets iteration count for printer + +4AH Select code page + +4CH Start prepare list + +4DH End prepare list + +65H Gets iteration count for printer + +6AH Query code page selected + +6BH Query code page prepare list + +_ ________________________________________________________________ + +Note + + DS:DX points to a word that contains the new value for the total + number of output iterations performed before proceeding. Thus, + DS:DX points to a word that contains the character iteration count for + the "PRINT 'TIL BUSY" loop. This is the number of times the device + driver will wait for the device to signal "ready" before acknowledging + "Device busy." + +_ ________________________________________________________________ + + +Macro Definition: + + +ioctl_handles macro handle,function,category,buffer + mov ch,05H + mov cl,function + mov dx,offset buffer + mov bx,handle + mov ah,44H + mov al,0CH + int 21H + endm + + + + 27 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Generic IOCtl (for Devices) (Function 44H, +Code 0DH) + + Call: + + AH = 44H + AL = 0DH + BL + Drive number + (0 = default, 1 = A, etc.) + CH = 08H + Category (major) code + CL + Function (minor) code + DS:DX + Pointer to parameter block -1 + + Return: + + Carry set: + AX + 1 = Invalid function code + 2 = Invalid drive + Carry not set: + No error + + +Comments: + +The function code may be one of the following: + +Code + Meaning +_ ________________________________________________________________ + +40 Set device parameters + +41 Write track on logical device + +42 Format track on logical device + +60 Get device parameters + +61 Read track on logical device + +62 Verify track on logical device + +_ ________________________________________________________________ + +Note + + You must issue "Set Device Parameters" before you can read, write, + format, or verify a logical drive. + +28 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +_ ________________________________________________________________ + +You should use the following procedure when you want to read, write, for- +mat, or verify a logical drive: + + o Save drive parameters using "Get Device Parameters;" + + o Set desired drive parameters using "Set Device Parameters;" + + o Perform the I/O operation; + + o Restore the original drive parameters using "Set Device Parame- + ters." + + +Set Device Parameters (Function 44 0DH, CL=40H) + +When CL=40H, the parameter block has the following field format: + + -------------------------------------- + | BYTE Special Functions | + |------------------------------------| + | BYTE Device Type | + |------------------------------------| + | WORD Device Attributes | + |------------------------------------| + | WORD Number of Cylinders | + |------------------------------------| + | BYTE Media Type | + |------------------------------------| + | Device BPB | + |------------------------------------| + | Track Layout | + -------------------------------------- + +These fields have the following meanings: + +Special Functions + +Bit Value Meaning + +_ ________________________________________________________________ + + 0 0 + + The Device BPB (BIOS Parameter Block) field contains + the new default BPB for this device. If a previous "Set + Parameter Device" call set this bit, Build BPB returns + the actual media BPB; otherwise, it returns the default + BPB for the device. + + 1 + + All subsequent Build BPB requests return the device + BPB. + + 1 0 Read all fields of the parameter block. + + + + 29 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + 1 + + Ignore all fields of the parameter block except for the + Track Layout field. + + 2 0 + + The sectors in the track may not all be the same size. + (You should not use this setting.) + + 1 + + The sectors in the track are all the same size and the + sector numbers range between 1 and the total number of + sectors actually in the track. You should always set this + bit. + + 3-7 0 These bits must be zero. + +_ ________________________________________________________________ + + +Device Type + +This byte describes the physical device and is set by the device. When set, +it has the following meanings: + +Value + Meaning +_ ________________________________________________________________ + +0 320/360 KB + +1 1.2 MB + +2 720 KB + +3 8-inch, single-density + +4 8-inch, double-density + +5 Hard disk + +6 Tape drive + +7 Other + + +Device Attributes + +Bit Value Meaning + +_ ________________________________________________________________ + + 0 The media is removable. + + 0 1 The media is not removable. + + 1 0 + + Disk change-line is not + supported; (no door lock + support). + + 1 + + Disk change-line is + supported; (door lock + support). + + 2-7 0 These bits must be zero. + +_ ________________________________________________________________ + + +30 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Number of Cylinders + +This field indicates the maximum number of cylinders that the physical +device can support. This information is set by the device. + +Media Type + +For drives that may contain different media, this field (which is device- +dependent) indicates which media the drive expects. + +For a 1.2 MB disk, bit zero has the following meaning: + +Bit Value Meaning + +_ ________________________________________________________________ + + 0 0 Quad-density, 1.2 MB disk + + 1 Double-density, 320/360 KB disk + +_ ________________________________________________________________ + +The default media type is a quad-density 1.2 MB disk. + +Device BPB + +If bit 0 of the Special Functions field is clear, the BPB in this field is the +new default BPB for the device. + +If bit 0 of the Special Functions field is set, the device driver returns the +BPB from this field for subsequent Build BPB requests. + +Track Layout + +This field contains a table of variable length for each logical device and +indicates the expected layout of the sectors on the media track. The field +has the following format: + + ------------------------------------------------ + | WORD Sector Count -- total # of sectors | + |----------------------------------------------| + | WORD Sector Number -- sector #1 | + |----------------------------------------------| + | WORD Sector Size -- sector #1 | + |----------------------------------------------| + | WORD Sector Number -- sector #2 | + |----------------------------------------------| + | WORD Sector Size -- sector #2 | + ------------------------------------------------ + | + | + | + + 31 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + ------------------------------------------------ + | WORD Sector Number -- sector #n | + |----------------------------------------------| + | WORD Sector Size -- sector #n | + ------------------------------------------------ + +The Sector Count field indicates the total number of sectors. Each sector +number must be unique and in the range of 1 to sector count (n). + +If bit 2 of the Special Functions field is set, all sector sizes must be the +same. + +Get Device Parameters (Function 440DH, CL=60H) + +When CL=60H, the parameter block has the same field layout as for +CL=40H. However, some of the fields have different meanings. These are +described as follows: + +Special Functions + +Bit Value Meaning + +_ ________________________________________________________________ + + 0 0 Returns the default BPB for the device. + + 1 + + Returns the BPB that Build BPB + would return. + + 1-7 0 These bits must be zero. + +_ ________________________________________________________________ + + +Track Layout + +The "Get Device Parameters" call does not use this field. + +Read/Write Track on Logical Drive +(Function 440D, CL=61H/CL=41H) + +To write to a track on a logical drive, set CL=41H. To read a track on a +logical drive, set CL=61H. + +When CL=41H or 61H, the parameter block has the following format: + + -------------------------------- + | BYTE Special Functions | + |------------------------------| + | WORD Head | + |------------------------------| + | WORD Cylinder | + |------------------------------| + +32 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + | WORD First Sector | + |------------------------------| + | WORD Number of Sectors | + |------------------------------| + | DWORD Transfer Address | + -------------------------------- + +These fields are described as follows: + +Special Functions This byte must be zero. + +Head + +This field contains the number of the head on which you perform the write +or read. + +Cylinder + +This field contains the number of the cylinder on which you perform the +write or read. + +First Sector + +This field contains the number of the first sector on which you perform the +write or read. Sectors are numbered starting with zero, so the fourth sec- +tor is numbered 3. + +Number of Sectors + +This field contains the total number of sectors. + +Transfer Address + +This field contains the address for storing the data to be written or the +data just read. + +Format/Verify Track on Logical Drive +(Function 440DH, CL=42/CL=62) + +To format and verify a track on a logical drive, set CL=42H. To verify a +track on a logical drive, set CL=62H. + + + + 33 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +When CL=42H or 62H, the parameter block has the following format: + + -------------------------------- + | BYTE Special Functions | + |------------------------------| + | WORD Head | + |------------------------------| + | WORD Cylinder | + -------------------------------- + +These fields are described as follows: + +Special Functions + +This byte must be zero. + +Head + +This field contains the number of the head on which you perform the for- +mat or verify. + +Cylinder + +This field contains the number of the cylinder on which you perform the +format or verify. + + +34 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Get/Set IOCtl Drive Map (Function 44H, +Codes 0EH and 0FH) + + Call: + + AH = 44H + AL + OEH = Get logical drive map + OFH = Set logical drive map + BX + Drive number + (0 = default, 1 = A, etc.) + + Return: + + Carry set: + AX + 1 = Invalid function code + 5 = Invalid drive + Carry not set: + AL = Logical drive mapped onto physical drive + (= 0 if only one drive is + assigned to this physical drive) + + +Comments: + +MS-DOS 3.3 supports the mapping of multiple logical drives onto a single +physical block device. Get IOCtl Drive Map lets you query the DOS about +which logical drive is currently mapped onto the corresponding physical +device. Set IOCtl Drive Map alters the device that is currently mapped +onto the physical device. These functions are only useful if there is more +than one logical block device mapped onto a single physical device. + +A possible use for these functions is with applications that want to disable +the DOS prompt in order to place the correct floppy disk in the drive when +accessing the other logical drive. + +To detect whether a logical device currently owns the physical device it is +mapped to, a program needs to check the value in AL after calling Func- +tion 440EH or 440FH (Get/Set IOCtl Drive Map). + + + 35 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Duplicate File Handle (Function 45H) + + Call: + + AH = 45H + BX + Handle + + Return: + + Carry set: + AX + 4 = Too many open files + 6 = Invalid handle + Carry not set: + AX + New handle + + + +Comments: + +Function 45H creates an additional handle for a file. BX must contain the +handle of an open file. + +MS-DOS returns the new handle in AX. The new handle refers to the same +file as the handle in BX, with the file pointer at the same position. + +After you use this function request, moving the read/write pointer of +either handle also moves the pointer for the other handle. You usually use +this function request to redirect standard input (handle 0) and standard +output (handle 1). For a description of standard input, standard output, +and the advantages and techniques of manipulating them, see Software +Tools by Brian W. Kernighan and P.J. Plauger (Addison-Wesley Publish- +ing Co., 1976). + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +4 Too many open files (no handle available) + +6 Handle not open or is invalid + + + +36 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +xdup macro handle + mov bx,handle + mov ah,45H + int 21H + endm + + +Example: + +The following program redirects standard output (handle 1) to a file +named dirfile, invokes a second copy of command.com to list the directory +(which writes the directory to dirfile), and then restores standard input to +handle 1. + +pgm_file db "command.com",0 +cmd_line db 9,"/c dir /w",0dH +parm_blk db 14 dup (0) +path db "dirfile",0 +dir_file dw ? ; For handle +sav_stdout dw ? ; For handle +; +begin: set_block last_inst ; See Function 4AH + jc error_setblk ; Routine not shown + create_handle path,0 ; See Function 3CH + jc error_create ; Routine not shown + mov dir_file,ax ; Save handle + xdup 1 ; THIS FUNCTION + jc error_xdup ; Routine not shown + mov sav_stdout,ax ; Save handle + xdup2 dir_file,1 ; See Function 46H + jc error_xdup2 ; Routine not shown + exec pgm_file,cmd_line,parm_blk ; See Function + 4BH + jc error_exec ; Routine not shown + xdup2 sav_stdout,1 ; See Function 46H + jc error_xdup2 ; Routine not shown + close_handle sav_stdout ; See Function 3EH + jc error_close ; Routine not shown + close_handle dir_file ; See Function 3EH + jc error_close ; Routine not shown + + + + 37 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Force Duplicate File Handle (Function 46H) + + Call: + + AH = 46H + BX + Handle + CX + Second handle + + Return: + + Carry set: + AX + 4 = Too many open files + 6 = Invalid handle + Carry not set: + No error + + + +Comments: + +Function 46H forces a specified handle to refer to the same file as a second +handle already associated with an open file. BX must contain the handle +of the open file; CX must contain the second handle. + +On return, the handle in CX now refers to the same file at the same posi- +tion as the handle in BX. If the file referred to by the handle in CX was +open at the time of the call, this function closes it. + +After you use this call, moving the read/write pointer of either handle also +moves the pointer for the other handle. Normally, you would use this +function request to redirect standard input (handle 0) and standard out- +put (handle 1). For a description of standard input, standard output, and +the advantages and techniques of manipulating them, see Software Tools +by Brian W. Kernighan and P.J. Plauger (Addison-Wesley Publishing Co., +1976). + + + +38 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +4 Too many open files (no handle available) + +6 Handle not open or is invalid + + +Macro Definition: + + +xdup2 macro handle1,handle2 + mov bx,handle1 + mov cx,handle2 + mov ah,46H + int 21H + endm + + +Example: + +The following program redirects standard output (handle 1) to a file +named dirfile, invokes a second copy of command.com to list the directory +(which writes the directory to dirfile), and then restores standard input to +handle 1. + +pgm_file db "command.com",0 +cmd_line db 9,"/c dir /w",0dH +parm_blk db 14 dup (0) +path db "dirfile",0 +dir_file dw ? ; For handle +sav_stdout dw ? ; For handle +; +begin: set_block last_inst ; See Function 4AH + jc error_setblk ; Routine not shown + create_handle path,0 ; See Function 3CH + jc error_create ; Routine not shown + mov dir_file,ax ; Save handle + xdup 1 ; See Function 45H + jc error_xdup ; Routine not shown + mov sav_stdout,ax ; Save handle + xdup2 dir_file,1 ; + jc error_xdup2 ; Routine not shown + exec pgm_file,cmd_line,parm_blk ; See Function + 4BH + jc error_exec ; Routine not shown + xdup2 sav_stdout,1 ; THIS FUNCTION + jc error_xdup2 ; Routine not shown + close_handle sav_stdout ; See Function 3EH + jc error_close ; Routine not shown + close_handle dir_file ; See Function 3EH + jc error_close ; Routine not shown + + 39 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Current Directory (Function 47H) + + Call: + + AH = 47H + DS:SI + Pointer to 64-byte memory area + DL + Drive number + (0 = default, 1 = A) + + Return: + + Carry set: + AX + 15 = Invalid drive number + Carry not set: + No error + + + +Comments: + +Function 47H returns the pathname of the current directory on a specified +drive. DL must contain a drive number (0=default, 1=A, etc.). SI must +contain the offset (from the segment address in DS) of a 64-byte memory +area. + +MS-DOS places an ASCIZ string in the memory area, consisting of the path +(starting from the root directory) of the current directory for the drive +specified in DL. The string does not begin with a backslash and does not +include the drive letter. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +15 Number in DL not a valid drive number + + + +40 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +get_dir macro drive,buffer + mov dl,drive + mov si,offset buffer + mov ah,47H + int 21H + endm + + +Example: + +The following program displays the current directory that is on the disk in +drive B. + +disk db "b: +buffer db 64 dup (?) +; +begin: get_dir 2,buffer ;THIS FUNCTION + jc error_dir ;Routine not shown + display disk ;See Function 09H + display_asciz buffer ;See end of chapter + + + + 41 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Allocate Memory (Function 48H) + + Call: + + AH = 48H + BX + Paragraphs of memory requested + + Return: + + Carry set: + AX + 7 = Memory-control blocks damaged + 8 = Insufficient memory + BX + Paragraphs of memory available + Carry not set: + AX + Segment address of allocated memory + + + +Comments: + +Function 48H tries to allocate the specified amount of memory to the +current process. BX must contain the number of paragraphs of memory +(one paragraph is 16 bytes). + +If sufficient memory is available to satisfy the request, AX returns the seg- +ment address of the allocated memory (the offset is 0). If sufficient memory +is not available, BX returns the number of paragraphs of memory in the +largest available block. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +7 Memory-control blocks damaged (a user program changed memory + that doesn't belong to it) + +8 Not enough free memory to satisfy the request + + + +42 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +allocate_memory macro bytes + mov bx,bytes + mov cl,4 + shr bx,cl + inc bx + mov ah,48H + int 21H + endm + + +Example: + +The following program opens the file named textfile.asc, calculates its size +with Function 42H (Move File Pointer), allocates a block of memory the +size of the file, reads the file into the allocated memory block, and then +frees the allocated memory. + +path db "textfile.asc",0 +msg1 db "File loaded into allocated memory block.", + 0DH,0AH +msg2 db "Allocated memory now being freed + (deallocated).",0DH,0AH +handle dw ? +mem_seg dw ? +file_len dw ? +; +begin: open_handle path,0 + jc error_open ;Routine not shown + mov handle,ax ;Save handle + move_ptr handle,0,0,2 ;See Function 42H + jc error_move ;Routine not shown + mov file_len,ax ;Save file length + set_block last_inst ;See Function 4AH + jc error_setblk ;Routine not shown + allocate_memory file_len ;THIS FUNCTION + jc error_alloc ;Routine not shown + mov mem_seg,ax ;Save address of new memory + move_ptr handle,0,0,0 ;See Function 42H + jc error_move ;Routine not shown + push ds ;Save DS + mov ax,mem_seg ;Get segment of new memory + mov ds,ax ;Point DS at new memory + read_handle cs:handle,0,cs:file_len ;Read file into +; new memory + pop ds ;Restore DS + jc error_read ;Routine not shown +; (CODE TO PROCESS FILE GOES HERE) + write_handle stdout,msg1,42 ;See Function 40H + jc write_error ;Routine not shown + free_memory mem_seg ;See Function 49H + jc error_freemem ;Routine not shown + write_handle stdout,msg2,49 ;See Function 40H + + 43 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + jc write_error ;Routine not shown + + + +44 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Free Allocated Memory (Function 49H) + + Call: + + AH = 49H + ES + Segment address of memory to be + freed + + Return: + + Carry set: + AX + 7 = Memory-control blocks damaged + 9 = Incorrect segment + Carry not set: + No error + + + +Comments: + +Function 49H frees (makes available) a block of memory previously allo- +cated with Function 48H (Allocate Memory). ES must contain the segment +address of the memory block to be freed. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +7 Memory-control blocks damaged (a user program changed memory + that didn't belong to it) + +9 Memory pointed to by ES was not allocated with Function 48H + + +Macro Definition: + + +free_memory macro seg_addr + mov ax,seg_addr + mov es,ax + mov ah,49H + int 21H + endm + + + + 45 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program opens a file named textfile.asc, calculates its size +with Function 42H (Move File Pointer), allocates a block of memory the +size of the file, reads the file into the allocated memory block, and then +frees the allocated memory. + +path db "textfile.asc",0 +msg1 db "File loaded into allocated memory block.", + 0DH,0AH +msg2 db "Allocated memory now being freed + (deallocated).",0DH,0AH +handle dw ? +mem_seg dw ? +file_len dw ? +; +begin: open_handle path,0 + jc error_open ;Routine not shown + mov handle,ax ;Save handle + move_ptr handle,0,0,2 ;See Function 42H + jc error_move ;Routine not shown + mov file_len,ax ;Save file length + set_block last_inst ;See Function 4AH + jc error_setblk ;Routine not shown + allocate_memory file_len ;See Function 48H + jc error_alloc ;Routine not shown + mov mem_seg,ax ;Save address of new memory + mov_ptr handle,0,0,0 ;See Function 42H + jc error_move ;Routine not shown + push ds ;Save DS + mov ax,mem_seg ;Get segment of new memory + mov ds,ax ;Point DS at new memory + read_handle handle,code,file_len ;Read file into +; new memory + pop ds ;Restore DS + jc error_read ;Routine not shown +; (CODE TO PROCESS FILE GOES HERE) + write_handle stdout,msg1,42 ;See Function 40H + jc write_error ;Routine not shown + free_memory mem_seg ;THIS FUNCTION + jc error_freemem ;Routine not shown + write_handle stdout,msg2,49 ;See Function 40H + jc write_error ;Routine not shown + + + +46 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Set Block (Function 4AH) + + Call: + + AH = 4AH + BX + Paragraphs of memory + ES + Segment address of memory area + + Return: + + Carry set: + AX + 7 = Memory-control blocks damaged + 8 = Insufficient memory + 9 = Incorrect segment + BX + Paragraphs of memory available + Carry not set: + No error + + +Comments: + +Function 4AH changes the size of a memory-allocation block. ES must +contain the segment address of the memory block. BX must contain the +new size of the memory block, in paragraphs (one paragraph is 16 bytes). + +MS-DOS attempts to change the size of the memory block. If the call fails +on a request to increase memory, BX returns the maximum size (in para- +graphs) to which the block can be increased. + +Since MS-DOS allocates all available memory to a .com program, you +would use this call most often to reduce the size of a program's initial +memory-allocation block. + + + + 47 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +7 Memory-control blocks destroyed (a user program changed memory + that didn't belong to it) + +8 Not enough free memory to satisfy the request + +9 Wrong address in ES (the memory block it points to cannot be + modified with Set Block) + +The following macro shrinks the initial memory-allocation block of a .com +program. It takes as a parameter the offset of the first byte following the +last instruction of a program (LAST_INST in the sample programs), uses +it to calculate the number of paragraphs in the program, and then adds 17 +to the result: one to round up and 16 to set aside 256 bytes for a stack. It +then sets up SP and BP to point to this stack. + +Macro Definition: + + +set_block macro last_byte + mov bx,offset last_byte + mov cl,4 + shr bx,cl + add bx,17 + mov ah,4AH + int 21H + mov ax,bx + shl ax,cl + dec ax + mov sp,ax + mov bp,sp + endm + + +Example: + +The following program invokes a second copy of command.com and exe- +cutes a dir (directory) command. + +pgm_file db "command.com",0 +cmd_line db 9,"/c dir /w",0DH +parm_blk db 14 dup (?) +reg_save db 10 dup (?) +; +begin: set_block last_inst ;THIS FUNCTION + exec pgm_file,cmd_line,parm_blk,0 ;See Function + ;4BH + + + +48 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Load and Execute Program (Function 4BH, +Code 00H) + + Call: + + AH = 4BH + AL = 00H + DS:DX + Pointer to pathname + ES:BX + Pointer to parameter block + + Return: + + Carry set: + AX + 1 = Invalid function + 2 = File not found + 3 = Path not found + 4 = Too many open files + 5 = Access denied + 8 = Insufficient memory + 10 = Bad environment + 11 = Bad format + Carry not set: + No error + + +Comments: + +Function 4BH, Code 00H, loads and executes a program. DX must contain +the offset (from the segment address in DS) of an ASCIZ string that specifies +the drive and pathname of an executable program file. BX must contain +the offset (from the segment address in ES) of a parameter block. AL must +contain 0. + +There must be enough free memory for MS-DOS to load the program file. +MS-DOS allocates all available memory to a program when it loads it, so +you must free some memory with Function 4AH (Set Block) before using +this function request to load and execute another program. Unless you or +MS-DOS needs the memory for some other purpose, you should shrink the +memory to the minimum amount required by the current process before +issuing this request. + +MS-DOS creates a Program Segment Prefix for the program being loaded +and sets the terminate and CONTROL-C addresses to the instruction that +immediately follows the call to Function 4BH in the invoking program. + + + 49 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The parameter block consists of four addresses: + +Table 0.2 + +Contents of the Parameter Block + +_ _________________________________________________________________________ + +Offset Length +(Hex) (Bytes) Description + +_ _________________________________________________________________________ + +00 2 (word) + + Segment address of the environment to be passed; 00H + means copy the parent program's environment. + +02 4 (dword) + + Segment: Offset of command line to be placed at offset 80H + of the new Program Segment Prefix. Must be a correctly- + formed command line no longer than 128 bytes. + +06 4 (dword) + + Segment: Offset of FCB to be placed at offset 5CH of the + new Program Segment Prefix (the Program Segment Prefix + is described in Chapter 4, "MS-DOS Control Blocks and + Work Areas") + +0A 4 (dword) + + Segment: Offset of FCB to be placed at offset 6CH of the + new Program Segment Prefix + +_ _________________________________________________________________________ + +All open files of a program are available to the newly loaded program, giv- +ing the parent program control over the definition of standard input, out- +put, auxiliary, and printer devices. For example, a program could write a +series of records to a file, open the file as standard input, open a second file +as standard output, and then use Function 4BH, Code 00H (Load and Exe- +cute Program) to load and execute a program that takes its input from +standard input, sorts records, and writes to standard output. + +The loaded program also receives an environment, a series of ASCIZ strings +of the form parameter=value (for example, verify= on). The environment +must begin on a paragraph boundary, be less than 32K bytes long, and +end with a byte of 00H (that is, the final entry consists of an ASCIZ string +followed by two bytes of 00H). Following the last byte of zeros is a set of +initial arguments passed to a program containing a word count followed +by an ASCIZ string. If the call finds the file in the current directory, the +ASCIZ string contains the drive and pathname of the executable program as +passed to Function 4BH. If the call finds the file in the path, it concaten- +ates the filename with the path information. (A program may use this area +to determine whence it was loaded.) If the word-environment address is 0, +the loaded program either inherits a copy of the parent program's environ- +ment or receives a new environment built for it by the parent. + +Place the segment address of the environment at offset 2CH of the new +Program Segment Prefix. To build an environment for the loaded pro- +gram, put it on a paragraph boundary and place the segment address of +the environment in the first word of the parameter block. To pass a copy +of the parent's environment to the loaded program, put 00H in the first + +50 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +word of the parameter block. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 AL not 0 or 3 + +2 Program file not found + +3 Path invalid or not found + +4 Too many open files (no handle available) + +5 Directory full, a directory with the same name exists, or a file with + the same name exists + +8 Not enough memory to load the program + +10 Environment appears longer than 32K + +11 Program file is an .exe file that contains internally inconsistent + information + + +Executing Another Copy of Command.com + +Since command.com builds pathnames, searches command paths for pro- +gram files, and relocates .exe files, the simplest way to load and execute +another program is to load and execute an additional copy of +command.com, passing it a command line that includes the /c switch, +which invokes the .com or .exe file. + +This action requires 17K bytes of available memory, so a program that +does it should be sure to shrink its initial memory-allocation block with +Function 4AH (Set Block). The format of a command line that contains +the /c switch: + +length,/c command,0DH + +Length is the length of the command line, counting the length byte but not +the ending carriage-return (0DH). + +Command is any valid MS-DOS command. + +0DH is a carriage-return character. + +If a program executes another program directly\(emnaming it as the program +file to Function 4BH instead of command.com\(emit must perform all the +processing normally done by command.com. + + + 51 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +exec macro path,command,parms + mov dx,offset path + mov bx,offset parms + mov word ptr parms[02H],offset command + mov word ptr parms[04H],cs + mov word ptr parms[06H],5CH + mov word ptr parms[08H],es + mov word ptr parms[0AH],6CH + mov word ptr parms[0CH],es + mov al,0 + mov ah,4BH + int 21H + endm + + +Example: + +The following program invokes a second copy of command.com and exe- +cutes a dir (directory) command by using the /w (wide) switch: + +pgm_file db "command.com",0 +cmd_line db 9,"/c dir /w",0DH +parm_blk db 14 dup (?) +reg_save db 10 dup (?) +; +begin: + set_block last_inst ;See Function 4AH + exec pgm_file,cmd_line,parm_blk,0 ;THIS FUNCTION + + + +52 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Load Overlay (Function 4BH, Code 03H) + + Call: + + AH = 4BH + AL = 03H + DS:DX + Pointer to pathname + ES:BX + Pointer to parameter block + + Return: + + Carry set: + AX + 1 = Invalid function + 2 = File not found + 3 = Path not found + 4 = Too many open files + 5 = Access denied + 8 = Insufficient memory + 10 = Bad environment + Carry not set: + No error + + +Comments: + +Function 4BH, Code 03H, loads a program segment (overlay). DX must +contain the offset (from the segment address in DS) of an ASCIZ string that +specifies the drive and pathname of the program file. BX must contain the +offset (from the segment address in ES) of a parameter block. AL must +contain 3. + +MS-DOS assumes that since the invoking program is loading into its own +address space, it requires no free memory. This call does not create a Pro- +gram Segment Prefix. + + + + 53 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The parameter block is four bytes long: + + +Table 0.3 + +Contents of the Parameter Block + +_ _________________________________________________________________________ + +Offset Length +(Hex) (Bytes) Description + +_ _________________________________________________________________________ + +00 2 (word) Segment address where program is to be loaded + +02 2 (word) + + Relocation factor; usually the same as the first word of the + parameter block (for a description of an .exe file and of + relocation, see Chapter 6, ".Exe File Structure and + Loading.") + +_ _________________________________________________________________________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 AL not 00H or 03H + +2 Program file not found + +3 Path invalid or not found + +4 Too many open files (no handle available) + +5 Directory is full, a directory with the same name exists, or a file + with the same name exists + +8 Not enough memory to load the program + +10 Environment appears longer than 32K + + +Macro Definition: + + +exec_ovl macro path,parms,seg_addr + mov dx,offset path + mov bx,offset parms + mov parms,seg_addr + mov parms[02H],seg_addr + mov al,3 + mov ah,4BH + int 21H + endm + + + +54 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program opens a file named textfile.asc, redirects standard +input to that file, loads more.com as an overlay, and calls an overlay +named bit.com, which reads textfile.asc as standard input. The overlay +must establish its own addressability and end with a FAR return. + +stdin equ 0 +; +file db "TEXTFILE.ASC",0 +cmd_file db "\bit.com",0 +parm_blk dw 4 dup (?) +overlay label dword + dw 0 +handle dw ? +new_mem dw ? +; +begin: set_block last_inst ;see Function 4AH + jc setblock_error ;routine not shown + allocate_memory 2000 ;see Function 48H + jc allocate_error ;routine not shown + mov new_mem,ax ;save seg of memory + open_handle file,0 ;see Function 3DH + jc open_error ;routine not shown + mov handle,ax ;save handle + xdup2 handle,stdin ;see Function 45H + jc dup2_error ;routine not shown + close_handle handle ;see Function 3EH + jc close_error ;routine not shown + mov ax,new_mem ;addr of new memory + exec_ovl cmd_file,parm_blk,ax ;THIS FUNCTION + jc exec_error ;routine not shown + call overlay ;call the overlay + free_memory new_mem ;see Function 49H + jc free_error ;routine not shown +; + + + + 55 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +End Process (Function 4CH) + + Call: + + AH = 4CH + AL + Return code + + Return: + + None + + + +Comments: + +Function 4CH terminates a process and returns to MS-DOS. AL contains a +return code that can be retrieved by the parent process with Function 4DH +(Get Return Code of Child Process) or the if command, using errorlevel. + +MS-DOS closes all open handles, ends the current process, and returns +control to the invoking process. + +This function request doesn't require CS to contain the segment address of +the Program Segment Prefix. You should use it to end a program (rather +than Interrupt 20H or a jump to location 0) unless your program must be +compatible with MS-DOS versions before 2.0. + +_ ________________________________________________________________ + +Note + + If you use file sharing, you must remove all locks issued by this process + or the DOS will be in an uncertain state. + +_ ________________________________________________________________ + + + +56 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +end_process macro return_code + mov al,return_code + mov ah,4CH + int 21H + endm + + +Example: + +The following program displays a message and returns to MS-DOS with a +return code of 8. It uses only the opening portion of the sample program +skeleton shown at the beginning of this chapter. + +message db "Displayed by FUNC_4CH example",0DH,0AH,"$" +; +begin: display message ;See Function 09H + end_process 8 ;THIS FUNCTION +code ends + end code + + + + 57 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Return Code of Child Process (Function +4DH) + + Call: + + AH = 4DH + + Return: + + AX + Return code + + + +Comments: + +Function 4DH retrieves the return code specified when a child process ter- +minates via either Function 31H (Keep Process) or Function 4CH (End +Process). The code returns in AL. AH returns a code that specifies why the +program ended: + +Code + Meaning +_ ________________________________________________________________ + +0 Normal termination + +1 Terminated by CONTROL-C + +2 Critical device error + +3 Function 31H (Keep Process) + +This call can retrieve the exit code only once. + +Macro Definition: + + +ret_code macro + mov ah,4DH + int 21H + endm + +58 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +No example is included for this function request, because the meaning of a +return code varies. + + + 59 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Find First File (Function 4EH) + + Call: + + AH = 4EH + DS:DX + Pointer to pathname + CX + Attributes to match + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 18 = No more files + Carry not set: + No error + + + +Comments: + +Function 4EH searches the current or specified directory for the first entry +that matches the specified pathname. DX must contain the offset (from the +segment address in DS) of an ASCIZ string that specifies the pathname, +which can contain wildcard characters. CX must contain the attribute to +be used in searching for the file, as described in Section 1.5.5, "File Attri- +butes," earlier in this chapter. + +If the attribute field is hidden file, system file, or subdirectory entry (02H, +04H, or 10H), or any combination of these values, all normal file entries +are also searched. To search all directory entries except the volume label, +set the attribute byte to 16H (hidden file, system file, and directory entry). + + + +60 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +If this function finds a directory entry that matches the name and attri- +bute, it fills the current DTA as follows: + + +Table 0.4 + + + +_ _________________________________________________________________________ + +Offset Length Description + +_ _________________________________________________________________________ + +00H 21 Reserved for subsequent Function 4FH (Find Next File) + +15H 1 Attribute found + +16H 2 Time file was last written + +18H 2 Date file was last written + +1AH 2 Low word of file size + +1CH 2 High word of file size + +1EH 13 + + Name and extension of the file, followed by 00H. All blanks + are removed; if there is an extension, it is preceded by a + period. (Volume labels include a period after the eighth + character.) + +_ _________________________________________________________________________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +2 Specified file invalid or doesn't exist + +3 Specified path invalid or doesn't exist + +18 No matching directory entry found + + +Macro Definition: + + +find_first_file macro path,attrib + mov dx,offset path + mov cx,attrib + mov ah,4EH + int 21H + endm + + + + 61 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program displays a message that specifies whether a file +named report.asm exists in the current directory on the disk in drive B. + +yes db "File exists.",0DH,0AH,"$" +no db "File does not exist.",0DH,0AH,"$" +path db "b:report.asm",0 +buffer db 43 dup (?) +; +begin: set_dta buffer ;See Function 1AH + find_first_file path,0 ;THIS FUNCTION + jc error_findfirst ;Routine not shown + cmp al,12H ;File found? + je not_there ;No + display yes ;See Function 09H + jmp return ;All done +not_there: display no ;See Function 09H + + + +62 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Find Next File (Function 4FH) + + Call: + + AH = 4FH + + Return: + + Carry set: + AX + 18 = No more files + Carry not set: + No error + + + +Comments: + +Function 4FH searches for the next directory entry that matches the name +and attributes specified in a previous Function 4EH (Find First File). The +current DTA must contain the information filled in by Function 4EH (Find +First File). + +If the function finds a matching entry, it fills the current DTA just as it +did for Find First File (see Function 4EH (Find First File)). + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +2 Specified path invalid or doesn't exist + +18 No matching directory entry found + + + + 63 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +find_next_file macro + mov ah,4FH + int 21H + endm + + +Example: + +The following program displays the number of files contained in the +current directory on the disk in drive B. + +message db "No files",0DH,0AH,"$" +files dw ? +path db "b:*.*",0 +buffer db 43 dup (?) +; +begin: set_dta buffer ;See Function 1AH + find_first_file path,0 ;See Function 4EH + jc error_findfirst ;Routine not shown + cmp al,12H ;Directory empty? + je all_done ;Yes, go home + inc files ;No, bump file counter +search_dir: find_next_file ;THIS FUNCTION + jc error_findnext ;Routine not shown + cmp al,12H ;Any more entries? + je done ;No, go home + inc files ;Yes, bump file counter + jmp search_dir ;And check again +done: convert files,10,message ;See end of chapter +all_done: display message ;See Function 09H + + + +64 + +_ _ | | _ _ + + + diff --git a/PROGREF/1E_CALLS.A b/PROGREF/1E_CALLS.A new file mode 100644 index 0000000..36e1cec --- /dev/null +++ b/PROGREF/1E_CALLS.A @@ -0,0 +1,3533 @@ + +_ _ | | _ _ + + + + _ ______________ + + +Get Verify State (Function 54H) + + Call: + + AH = 54H + + Return: + + AL + 0 = No verify after write + 1 = Verify after write + + + +Comments: + +Function 54H checks whether MS-DOS verifies write operations to disk +files. The status returns in AL: 0 if verify is off, 1 if verify is on. + +You can set the verify status with Function 2EH (Set/Reset Verify Flag). + +Macro Definition: + + +get_verify macro + mov ah,54H + int 21H + endm + + +Example: + +The following program displays the verify status: + +message db "Verify ","$" +on db "on.",0DH,0AH,"$" +off db "off.",0DH,0AH,"$" +; +begin: display message ;See Function 09H + get_verify ;THIS FUNCTION + cmp al,0 ;Is flag off? + + 1 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + jg ver_on ;No, it's on + display off ;See Function 09H + jmp return ;Go home +ver_on: display on ;See Function 09H + + + +2 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Change Directory Entry (Function 56H) + + Call: + + AH = 56H + DS:DX + Pointer to pathname + ES:DI + Pointer to second pathname + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 5 = Access denied + 17 = Not same device + Carry not set: + No error + + +Comments: + +Function 56H renames a file by changing its directory entry. DX must +contain the offset (from the segment address in DS) of an ASCIZ string that +contains the pathname of the entry to be changed. DI must contain the +offset (from the segment address in ES) of an ASCIZ string that contains a +second pathname to which the first is to be changed. + +If a directory entry for the first pathname exists, it is changed to the +second pathname. + +The directory paths need not be the same; in effect, you can move the file +to another directory by renaming it. You cannot use this function request +to copy a file to another drive, however; if the second pathname specifies a +drive, the first pathname must specify or default to the same drive. + +You cannot use this function request to rename an open file, a hidden file, +a system file, or a subdirectory, because it may corrupt your disk. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX. + +Code + Meaning +_ ________________________________________________________________ + +2 One of files is invalid or not open + + + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +3 One of paths is invalid or not open + +5 First pathname specifies a directory, second pathname specifies an + existing file; or second directory entry could not be opened + +17 Both files not on the same drive + + +Macro Definition: + + +rename_file macro old_path,new_path + mov dx,offset old_path + push ds + pop es + mov di,offset new_path + mov ah,56H + int 21H + endm + + +Example: + +The following program prompts for the name of a file and a new name, +then renames the file. + +prompt1 db "Filename: $" +prompt2 db "New name: $" +old_path db 15,?,15 dup (?) +new_path db 15,?,15 dup (?) +crlf db 0DH,0AH,"$" +; +begin: display prompt1 ;See Function 09H + get_string 15,old_path ;See Function 0AH + xor bx,bx ;To use BL as index + mov bl,old_path[1] ;Get string length + mov old_path[bx+2],0 ;Make an ASCIZ string + display crlf ;See Function 09H + display prompt2 ;See Function 09H + get_string 15,new_path ;See Function 0AH + xor bx,bx ;To use BL as index + mov bl,new_path[1] ;Get string length + mov new_path[bx+2],0 ;Make an ASCIZ string + display crlf ;See Function 09H + rename_file old_path[2],new_path[2];THIS FUNCTION + jc error_rename ;Routine not shown + + + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Get/Set Date/Time of File(Function 57H) + + Call: + + AH = 57H + AL = Function code + 0 = Get date and time + 1 = Set date and time + BX + Handle + CX (if AL = 1) + Time to be set + DX (if AL = 1) + Date to be set + + Return: + + Carry set: + AX + 1 = Invalid function + 6 = Invalid handle + Carry not set: + CX (if AL = 0) + Time file last written + DX (if AL = 0) + Date file last written + + +Comments: + +Function 57H gets or sets the time and date when a file was last written. +To get the time and date, AL must contain 0; the time and date return in +CX and DX. To set the time and date, AL must contain 1; CX and DX +must contain the time and date. BX must contain the file handle. The time +and date are in the form described in "Fields of the FCB" in Section 1.9.1. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 AL not 0 or 1 + +6 Handle in BX invalid or not open + + + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +get_set_date_time macro handle,action,time,date + mov bx,handle + mov al,action + mov cx,word ptr time + mov dx,word ptr date + mov ah,57H + int 21H + endm + + +Example: + +The following program gets the date of a file named report.asm in the +current directory on the disk in drive B, increments the day, increments +the month and/or year, if necessary, and sets the new date of the file. + +month db 31,28,31,30,31,30,31,31,30,31,30,31 +path db "b:report.asm",0 +handle dw ? +time db 2 dup (?) +date db 2 dup (?) +; +begin: open_handle path,0 ;See Function 3DH + mov handle,ax ;Save handle + get_set_date_time handle,0,time,date ;THIS FUNCTION + jc error_time ;Routine not shown + mov word ptr time,cx ;Save time + mov word ptr date,dx ;Save date + convert_date date[-24] ;See end of chapter + inc dh ;Increment day + xor bx,bx ;To use BL as index + mov bl,dl ;Get month + cmp dh,month[bx-1] ;Past last day? + jle month_ok ;No, go home + mov dh,1 ;Yes, set day to 1 + inc dl ;Increment month + cmp dl,12 ;Is it past December? + jle month_ok ;No, go home + mov dl,1 ;Yes, set month to 1 + inc cx ;Increment year +month_ok: pack_date date ;See end of chapter + get_set_date_time handle,1,time,date ;THIS FUNCTION + jc error_time ;Routine not shown + close_handle handle ;See Function 3EH + jc error_close ;Routine not shown + + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Get/Set Allocation Strategy (Function 58H) + + Call: + + AH = 58H + AL + 0 = Get strategy + 1 = Set strategy + BX (AL = 1) + 0 = First fit + 1 = Best fit + 2 = Last fit + + Return: + + Carry set: + AX + 1 = Invalid function code + Carry not set: + AX (AL = 0) + 0 = First fit + 1 = Best fit + 2 = Last fit + + +Comments: + +Function 58H gets or sets the strategy that MS-DOS uses to allocate +memory when a process requests it. If AL contains 0, the strategy is +returned in AX. If AL contains 1, BX must contain the strategy. The three +possible strategies are: + + + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +Table 0.1 + +Allocation Strategy + +_ _________________________________________________________________________ + +Value Name Description + +_ _________________________________________________________________________ + +0 First fit + + MS-DOS starts searching at the lowest available block and + allocates the first block it finds (the allocated memory is the + lowest available block). This is the default strategy. + +1 Best fit + + MS-DOS searches each available block and allocates the + smallest available block that satisfies the request. + +2 Last fit + + MS-DOS starts searching at the highest available block and + allocates the first block it finds (the allocated memory is the + highest available block). + +_ _________________________________________________________________________ + +You can use this function request to control how MS-DOS uses its memory +resources. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 AL doesn't contain 0 or 1, or BX doesn't contain 0, 1, or 2. + + +Macro Definition: + + +alloc_strat macro code,strategy + mov bx,strategy + mov al,code + mov ah,58H + int 21H + endm + + +Example: + +The following program displays the memory-allocation strategy in effect, +then forces subsequent memory allocations to the top of memory by set- +ting the strategy to last fit (code 2). + +get equ 0 +set equ 1 +stdout equ 1 +last_fit equ 2 +; +first db "First fit ",0DH,0AH +best db "Best fit ",0DH,0AH +last db "Last fit ",0DH,0AH + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +; +begin: alloc_strat get ;THIS FUNCTION + jc alloc_error ;routine not shown + mov cl,4 ;multiply code by 16 + shl ax,cl ;to calculate offset + mov dx,offset first ;point to first msg + add dx,ax ;add to base address + mov bx,stdout ;handle for write + mov cs,16 ;write 16 bytes + mov ah,40h ;write handle + int 21H ;system call +; jc write_error ;routine not shown + alloc_strat set,last_fit ;THIS FUNCTION +; jc alloc_error ;routine not shown + + + + 9 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Extended Error (Function 59H) + + Call: + + AH = 59H + BX = 0 + + Return: + + AX + Extended-error code + BH + Error class (see text) + BL + Suggested action (see text) + CH + Locus (see text) + + CL, DX, SI, DI, DS, ES destroyed + + + +Comments: + +Function 59H retrieves an extended-error code for the preceding system +call. Each release of MS-DOS extends the error codes to cover new capabil- +ities. These new codes are mapped to a simpler set of error codes based on +MS-DOS Version 2.0, so that existing programs can continue to operate +correctly. Note that this call destroys all registers except CS:IP and +SS:SP. + +A user-written Interrupt 24H (Critical-Error Handler Address) can use +Function 59H to get detailed information about the error that caused the +interrupt to be issued. + +The input BX is a version indicator that specifies for what level of error +handling the application was written. The current level is 0. + +The extended-error code consists of four separate codes in AX, BH, BL, +and CH that give as much detail as possible about the error and suggest +how the issuing program should respond. + + +10 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +BH\(emError Class + +BH returns a code that describes the class of error that occurred: + +Class + Description +_ ________________________________________________________________ + +1 Out of a resource, such as storage or channels + +2 Not an error, but a temporary situation (such as a locked region in + a file) that is expected to end + +3 Authorization problem + +4 Internal error in system software + +5 Hardware failure + +6 System software failure not the fault of the active process (could be + caused by missing or incorrect configuration files, for example) + +7 Application program error + +8 File or item not found + +9 File or item of invalid format or type, or that is otherwise invalid + or unsuitable + +10 Interlocked file or item + +11 Wrong disk in drive, bad spot on disk, or other problem with + storage medium + +12 Other error + + + + 11 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +BL\(emSuggested Action + +BL returns a code that suggests how the issuing program can respond to +the error: + +Action + Description +_ ________________________________________________________________ + +1 Retry, then prompt user + +2 Retry after a Pause + +3 If user entered data such as drive letter or filename, prompt for it + again + +4 Terminate with cleanup + +5 Terminate immediately; system so unhealthy that program should + exit as soon as possible without taking time to close files and + update indexes + +6 Error is informational + +7 Prompt user to perform some action, such as changing disks, then + retry operation + + +CH\(emLocus + +CH returns a code that provides additional information to help locate the +area involved in the failure. This code is particularly useful for hardware +failures (BH=5). + +Locus + Description +_ ________________________________________________________________ + +1 Unknown + +2 Related to random-access block devices, such as a disk drive + +3 Related to Network + +4 Related to serial-access character devices, such as a printer + +5 Related to random-access memory + +Your programs should handle errors by noting the error return from the +original system call and then issuing this system call to get the extended- +error code. If the program does not recognize the extended-error code, it +should respond to the original error code. + +This system call is available during Interrupt 24H and may be used to +return network-related errors. + + +12 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +get_error macro + mov ah, 59H + int 21H + endm + + +Example: + +Since this function request provides such detailed information, a general +example is not practical. User programs can interpret the various codes to +determine what sort of messages or prompts should be displayed, what +action to take, and whether to terminate the program if recovery from the +errors isn't possible. + + + 13 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Create Temporary File (Function 5AH) + + Call: + + AH = 5AH + CX + Attribute + DS:DX + Pointer to pathname, followed by a + byte of 0, and then by 13 bytes of memory + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 4 = Too many open files + 5 = Access denied + Carry not set: + AX + Handle + + +Comments: + +Function 5AH creates a file with a unique name. DX must contain the +offset (from the segment address in DS) of an ASCIZ string that specifies a +pathname and 13 bytes of memory (to hold the filename). CX must con- +tain the attribute to be assigned to the file, as described in Section 1.5.5, +"File Attributes," earlier in this chapter. + +MS-DOS creates a unique filename and appends it to the pathname +pointed to by DS:DX, creates the file and opens it in compatibility mode, +then returns the file handle in AX. A program that needs a temporary file +should use this function request to avoid name conflicts. + +When the creating process exits, MS-DOS does not automatically delete a +file created with Function 5AH. When you no longer need the file you +should delete it. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +2 File is invalid or doesn't exist + + + +14 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +3 Directory pointed to by DS:DX is invalid or doesn't exist + +4 Too many open files (no handle available) + +5 Access denied + + +Macro Definition: + + +create_temp macro pathname,attrib + mov cx,attrib + mov dx,offset pathname + mov ah,5AH + int 21H + endm + + + + 15 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program creates a temporary file in the directory named +\wp\docs, copies a file named textfile.asc that is in the current directory +into the temporary file, and then closes both files. + +stdout equ 1 +; +file db "TEXTFILE.ASC",0 +path db "\WP\DOCS",0 +temp db 13 dup (0) +open_msg db " opened.",0DH,0AH +crl_msg db " created.",0DH,0AH +rd_msg db " read into buffer.",0DH,0AH +wr_msg db "Buffer written to " +cl_msg db "Files closed.",0DH,0AH +crlf db 0DH,0AH +handle1 dw ? +handle2 dw ? +buffer db 512 dup (?) +; +begin: open_handle file,0 ;see Function 3DH + jc open_error ;routine not shown + mov handle1,ax ;save handle + write_handle stdout,file,12 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,open_msg,10 ;see Function 40H + jc write_error ;routine not shown + create_temp path,0 ;THIS FUNCTION + jc create_error ;routine not shown + mov handle2,ax ;save handle + write_handle stdout,path,8 ;see Function 40H + jc write_error ;routine not shown + display_char " + write_handle stdout,temp,12 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,crl_msg,11 ;See Function 40H + jc write_error ;routine not shown + read_handle handle1,buffer,512 ;see Function 3FH + jc read_error ;routine not shown + write_handle stdout,file,12 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,rd_msg,20 ;see Function 40H + jc write_error ;routine not shown + write_handle handle2,buffer,512 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,wr_msg,18 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,temp,12 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,crlf,2 ;see Function 40H + jc write_error ;routine not shown + close_handle handle1 ;see Function 3EH + jc close_error ;routine not shown + close_handle handle2 ;see Function 3EH + +16 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + jc close_error ;routine not shown + write_handle stdout,cl_msg,15 ;see Function 40H + jc write_error ;routine not shown + + + + 17 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Create New File (Function 5BH) + + Call: + + AH = 5BH + CX + Attribute + DS:DX + Pointer to pathname + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 4 = Too many open files + 5 = Access denied + 80 = File already exists + Carry not set: + AX + Handle + + +Comments: + +Function 5BH creates a new file. DX must contain the offset (from the seg- +ment address in DS) of an ASCIZ string that specifies a pathname. CX con- +tains the attribute to be assigned to the file, as described in Section 1.5.5, +"File Attributes." + +If there is no existing file with the same filename, MS-DOS creates the file, +opens it in compatibility mode, and returns the file handle in AX. + +This function request fails if the specified file exists, unlike Function 3CH +(Create Handle), which, under the same circumstances, truncates the file +to a length of 0. In a multitasking system, the existence of a file is used as +a semaphore; you can use this system call as a test-and-set semaphore. + + + +18 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +2 File is invalid or doesn't exist + +3 Directory pointed to by DS:DX is invalid or doesn't exist + +4 No free handles are available in the current process, or internal + system tables are full + +5 Access denied + +80 File with the same specification pointed to by DS:DX already exists + + +Macro Definition: + + +create_new macro pathname,attrib + mov cx, attrib + mov dx, offset pathname + mov ah, 5BH + int 21H + endm + + +Example: + +The following program attempts to create a new file named report.asm in +the current directory. If the file already exists, the program displays an +error message and returns to MS-DOS. If the file doesn't exist and there +are no other errors, the program saves the handle and continues process- +ing. + +err_msg db "FILE ALREADY EXISTS",0DH,0AH,"$" +path db "report.asm",0 +handle dw ? +; +begin: create_new path,0 ;THIS FUNCTION + jnc continue ;further processing + cmp ax,80 ;file already exist? + jne error ;routine not shown + display err_msg ;see Function 09H + jmp return ;return to MS-DOS +continue: mov handle,ax ;save handle +; +; (further processing here) + + + + 19 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Lock (Function 5CH, Code 00H) + + Call: + + AH = 5CH + AL = 00H + BX + Handle + CX:DX + Offset of region to be locked + SI:DI + Length of region to be locked + + Return: + + Carry set: + AX + 1 = Invalid function code + 6 = Invalid handle + 33 = Lock violation + 36 = Sharing buffer exceeded + Carry not set: + No error + + +Comments: + +Function 5CH, Code 00H, denies all access (read or write) by any other +process to the specified region of the file. BX must contain the handle of +the file that contains the region to be locked. CX:DX (a four-byte integer) +must contain the offset in the file of the beginning of the region. SI:DI (a +four-byte integer) must contain the length of the region. + +If another process attempts to use (read or write) a locked region, MS-DOS +retries three times; if the retries fail, MS-DOS issues Interrupt 24H for the +requesting process. You can change the number of retries with Function +44H, Code 0BH (IOCtl Retry). + +The locked region can be anywhere in the file. For instance, locking +beyond the end of the file is not an error. A region should be locked for +only a brief period, so if it is locked for more than ten seconds you should +consider it to be an error. + +Function 45H (Duplicate File Handle) and Function 46H (Force Duplicate +File Handle) duplicate access to any locked region. Passing an open file to +a child process with Function 4BH, Code 00H (Load and Execute Program) +does not duplicate access to locked regions. + +_ ________________________________________________________________ + +20 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +Warning + + If a program closes a file that contains a locked region or terminates + with an open file that contains a locked region, the result is undefined. + +_ ________________________________________________________________ + +Programs that might be terminated by Interrupt 23H (CONTROL-C Handler +Address) or Interrupt 24H (Critical-Error-Handler Address) should trap +these interrupts and unlock any locked regions before exiting. + +Programs should not rely on being denied access to a locked region. A +program can determine the status of a region (locked or unlocked) by +attempting to lock the region and examining the error code. + +If there is an error, the carry flag (CF) is set and the error code is returned +in AX: + +Code + Meaning +_ ________________________________________________________________ + +1 File sharing must be loaded to use this function request. + +6 The handle in BX is not a valid, open handle. + +33 All or part of the specified region is already locked. + +36 There is no more room for lock entries in the buffer. Refer to the + share command in the MS-DOS User's Reference for information + on allocating more lock entries. + + +Macro Definition: + + +lock macro handle,start,bytes + mov bx, handle + mov cx, word ptr start + mov dx, word ptr start+2 + mov si, word ptr bytes + mov di, word ptr bytes+2 + mov al, 0 + mov ah, 5CH + int 21H + endm + + + + 21 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program opens a file named finalrpt in "Deny None" mode +and locks two portions of it: the first 128 bytes and bytes 1024 through +5119. After some (unspecified) processing, it unlocks the same portions and +closes the file. + +stdout equ 1 +; +start1 dd 0 +lgth1 dd 128 +start2 dd 1023 +lgth2 dd 4096 +file db "FINALRPT",0 +op_msg db " opened.",0DH,0AH +11_msg db "First 128 bytes locked.",0DH,0AH +12_msg db "Bytes 1024-5119 locked.",0DH,0AH +u1_msg db "First 128 bytes unlocked.",0DH,0AH +u2_msg db "Bytes 1024-5119 unlocked.",0DH,0AH +cl_msg db " closed.:,0DH,0AH +handle dw ? +; +begin: open_handle file,01000010b ;see Function 3DH + jc open_error ;routine not shown + write_handle stdout,file,8 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,op_msg,10 ;see Function 40H + jc write_error ;routine not shown + mov handle,ax ;save handle + lock handle,start1,lgth1 ;THIS FUNCTION + jc lock_error ;routine not shown + write_handle stdout,11_msg,25 ;see Function 40H + jc write_error ;routine not shown + lock handle,start2,lgth2 ;THIS FUNCTION + jc lock_error ;routine not shown + write_handle stdout,12_msg,25 ;see Function 40H + jc write_error ;routine not shown +; +; ( Further processing here ) +; + unlock handle,start1,lgth1 ;See Function 5C01H + jc unlock_error ;routine not shown + write_handle stdout,ul_msg,27 ;see Function 40H + jc write_error ;routine not shown + unlock handle,start2,lgth2 ;See Function 5C01H + jc unlock_error ;routine not shown + write_handle stdout,u2_msg,27 ;See Function 40H + jc write_error ;routine not shown + close_handle handle ;See Function 3EH + jc close_error ;routine not shown + write_handle stdout,file,8 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,cl_msg,10 ;see Function 40H + jc write_error ;routine not shown + + +22 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Unlock (Function 5CH, Code 01H) + + Call: + + AH = 5CH + AL = 01H + BX + Handle + CX:DX + Offset of area to be unlocked + SI:DI + Length of area to be unlocked + + Return: + + Carry set: + AX + 1 = Invalid function code + 6 = Invalid handle + 33 = Lock violation + 36 = Sharing buffer exceeded + Carry not set: + No error + + +Comments: + +Function 5CH, Code 01H, unlocks a region previously locked by the same +process. BX must contain the handle of the file that contains the region to +be unlocked. CX:DX (a four-byte integer) must contain the offset in the file +of the beginning of the region. SI:DI (a four-byte integer) must contain the +length of the region. The offset and length must be exactly the same as the +offset and length specified in the previous Function 5CH, Code 00H (Lock). + +The description of Function 5CH, Code 00H (Lock) describes how to use +locked regions. + + + + 23 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 File sharing must be loaded to use this function request. + +6 The handle in BX is not a valid, open handle. + +33 The region specified is not identical to one that was previously + locked by the same process. + +36 There is no more room for lock entries in the buffer. Refer to the + share command in the MS-DOS User's Reference for information + on allocating more lock entries. + +You should issue Function 59H (Get Extended Error) to list the possible +errors returned by this function. + +Macro Definition: + + +unlock macro handle,start,bytes + mov bx, handle + mov cx, word ptr start + mov dx, word ptr start+2 + mov si, word ptr bytes + mov di, word ptr bytes+2 + mov al, 1 + mov ah, 5CH + int 21H + endm + + +Example: + +The following program opens a file named finalrpt in "Deny None" mode +and locks two portions of it: the first 128 bytes and bytes 1024 through +5119. After some (unspecified) processing, it unlocks the same portions and +closes the file. + +stdout equ 1 +; +start1 dd 0 +lgth1 dd 128 +start2 dd 1023 +lgth2 dd 4096 +file db "FINALRPT",0 +op_msg db " opened.",0DH,0AH +11_msg db "First 128 bytes locked.",0DH,0AH +12_msg db "Bytes 1024-5119 locked.",0DH,0AH +u1_msg db "First 128 bytes unlocked.",0DH,0AH +u2_msg db "Bytes 1024-5119 unlocked.",0DH,0AH + +24 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +cl_msg db " closed.",0DH,0AH +handle dw ? +; +begin: open_handle file,01000010b ;see Function 3DH + jc open_error ;routine not shown + write_handle stdout,file,8 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,op_msg,10 ;see Function 40H + jc write_error ;routine not shown + mov handle,ax ;save handle + lock handle,start1,lgth1 ;See Function 5C00H + jc lock_error ;routine not shown + write_handle stdout,11_msg,25 ;see Function 40H + jc write_error ;routine not shown + lock handle,start2,lgth2 ;See Function 5C00H + jc lock_error ;routine not shown + write_handle stdout,12_msg,25 ;see Function 40H + jc write_error ;routine not shown +; +; ( Further processing here ) +; + unlock handle,start1,lgth1 ;THIS FUNCTION + jc unlock_error ;routine not shown + write_handle stdout,u1_msg,27 ;see Function 40H + jc write_error ;routine not shown + unlock handle,start2,lgth2 ;THIS FUNCTION + jc unlock_error ;routine not shown + write_handle stdout,u2_msg,27 ;see Function 40H + jc write_error ;routine not shown + close_handle handle ;See Function 3EH + jc close_error ;routine not shown + write_handle stdout,file,8 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,cl_msg,10 ;see Function 40H + jc write_error ;routine not shown + + + + 25 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Machine Name (Function 5EH, Code 00H) + + Call: + + AH = 5EH + AL = 0 + DS:DX + Pointer to 16-byte buffer + + Return: + + Carry set: + AX + 1 = Invalid function code + Carry not set: + CX + Identification number of local + computer + + + +Comments: + +Function 5EH, Code 0, retrieves the net name of the local computer. DX +must contain the offset (to the segment address in DS) of a 16-byte buffer. +Microsoft Networks must be running. + +MS-DOS returns the local computer name (a 16-byte ASCIZ string, padded +with blanks) in the buffer pointed to by DS:DX. CX returns the +identification number of the local computer. If the network was never +installed, the CH register returns with zero and the value in the CL regis- +ter is invalid. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 Microsoft Networks must be running to use this function request. + + + +26 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +get_machine_name macro buffer + mov dx,offset buffer + mov al,0 + mov ah,5EH + int 21H + endm + + +Example: + +The following program displays the name of a Microsoft Networks work- +station. + +stdout equ 1 +; +msg db "Netname: " +mac_name db 16 dup (?),0DH,0AH +; +begin: get_machine_name mac_name ;THIS FUNCTION + jc name_error ;routine not shown + write_handle stdout,msg,27 ;see Function 40H + jc write_error ;routine not shown + + + + 27 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Printer Setup (Function 5EH, Code 02H) + + Call: + + AH = 5EH + AL = 02H + BX + Assign-list index + CX + Length of setup string + + DS:SI + Pointer to setup string + + Return: + + Carry set: + AX + 1 = Invalid function code + Carry not set: + No error + + +Comments: + +Function 5EH, Code 02H, defines a string of control characters that +MS-DOS adds to the beginning of each file sent to the network printer. BX +must contain the index into the assign list that identifies the printer (entry +0 is the first entry). CX must contain the length of the string. SI must con- +tain the offset (to the segment address in DS) of the string itself. Microsoft +Networks must be running. + +MS-DOS adds the setup string to the beginning of each file sent to the +printer, which is specified by the assign-list index in BX. This function +request lets each program that shares a printer have its own printer +configuration. You can use Function 5F02H (Get Assign-List Entry) to +determine which entry in the assign list refers to the printer. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 Microsoft Networks must be running to use this function request. + + + +28 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +printer_setup macro index,lgth,string + mov bx, index + mov cx, lgth + mov dx, offset string + mov al, 2 + mov ah, 5EH + int 21H + endm + + +Example: + +The following program defines a printer-setup string that consists of the +control character to print expanded type on Epson-compatible printers. +The printer cancels this mode at the first carriage return, so the effect is to +print the first line of each file sent to the network printer as a title in +expanded characters. The setup string is one character. This example +assumes that the printer is the entry number 3 (the fourth entry) in the +assign list. Use Function 5F02H (Get Assign-List Entry) to determine this +value. + +setup db 0EH +; +begin: printer_setup 3,1,setup ;THIS FUNCTION + jc error ;routine not shown + + + + 29 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Assign-List Entry (Function 5FH, Code +02H) + + Call: + + AH = 5FH + AL = 02H + BX + Assign-list index + DS:SI + Pointer to buffer for local name + ES:DI + Pointer to buffer for remote name + + Return: + + Carry set: + AX + 1 = Invalid function code + 18 = No more files + Carry not set: + BL + 3 = Printer + 4 = Drive + CX + Stored user value + + +Comments: + +Function 5FH, Code 02H, retrieves the specified entry from the network +list of assignments. BX must contain the assign-list index (entry 0 is the +first entry). SI must contain the offset (to the segment address in DS) of a +16-byte buffer for the local name. DI must contain the offset (to the seg- +ment address in ES) of a 128-byte buffer for the remote name. Microsoft +Networks must be running. + +MS-DOS puts the local name in the buffer pointed to by DS:SI and the +remote name in the buffer pointed to by ES:DI. The local name can be a +null ASCIZ string. BL returns 3 if the local device is a printer or 4 if the +local device is a drive. CX returns the stored user value set with Function +5F03H (Make Assign-List Entry). The contents of the assign list can +change between calls. + +You can use this function request to retrieve any entry, or to make a copy +of the complete list by stepping through the table. To detect the end of +the assign list, check for error code 18 (no more files), as you would when +stepping through a directory by using Functions 4EH (Find First File) and + +30 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +4FH (Find Next File). + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 Microsoft Networks must be running to use this function request. + +18 The index passed in BX is greater than the number of entries in the + assign list. + + +Macro Definition: + + +get_list macro index,local,remote + mov bx, index + mov si, offset local + mov di, offset remote + mov al,2 + mov ah, 5FH + int 21H + endm + + +Example: + +The following program displays the assign list on a Microsoft Networks +workstation, showing the local name, remote name, and device type (drive +or printer) for each entry. + +stdout equ 1 +printer equ 3 +; +local_nm db 16 dup (?),2 dup (20h) +remote_nm db 128 dup (?),2 dup (20h) +header db "Local name",8 dup (20h) + db "Remote name",7 dup (20h) + db "Device Type" +crlf db 0dh,0ah,0dh,0ah +drive_msg db "drive" +print_msg db "printer" +index dw ? +; +begin: write_handle stdout,header,51 ;see Function 40H + jc write_error ;routine not shown + mov index,0 ;assign list index +ck_list: get_list index,local_nm,remote_nm ;THIS FUNCTION + jnc got_one ;got an entry +error: cmp ax,18 + je last_one ;yes + jmp error ;routine not shown +got_one: push bx ;save device type + + 31 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + write_handle stdout,local_nm,148 ;see Function 40H + jc write_error ;routine not shown + pop bx ;get device type + cmp bl,printer ;is it a printer? + je prntr ;yes + write_handle stdout,drive_msg,5 ;see Function 40H + jc write_error ;routine not shown + jmp get_next ;finish message +prntr: write_handle stdout,print_msg,7 ;see Function 40H + jc write_error ;routine not shown +get_next: write_handle stdout,crlf,2 ;see Function 40H + jc write_error ;routine not shown + inc index ;bump index + jmp ck_list ;get next entry +last_one: write_handle stdout,crlf,4 ;see Function 40H + jc write_error ;routine not shown +; + + + +32 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Make Assign-List Entry (Function 5FH, Code +03H) + + Call: + + AH = 5FH + AL = 03H + BL + 3 = Printer + 4 = Drive + CX + User value + DS:SI + Pointer to name of source device + ES:DI + Pointer to name of destination + device + + Return: + + Carry set: + AX + 1 = Invalid function code + 5 = Access denied + 3 = Path not found + 8 = Insufficient memory + (Other errors particular to the + network may occur.) + Carry not set: + No error + + +Comments: + +Function 5FH, Code 03H, redirects a printer or disk drive (source device) +to a network directory (destination device). BL must contain 3 if the +source device is a printer or 4 if it is a disk drive. SI must contain the +offset (to the segment address in DS) of an ASCIZ string that specifies the +name of the printer, or a drive letter followed by a colon, or a null string +(one byte of 00H). DI must contain the offset (to the segment address in +ES) of an ASCIZ string that specifies the name of a network directory. CX +contains a user-specified 16-bit value that MS-DOS maintains. Microsoft +Networks must be running. + +The destination string must be an ASCIZ string of the following form: + +machine-name pathname 00H password 00H + + + 33 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +where: + +Machine-name is the net name of the server that contains the network +directory; + +Pathname is the alias of the network directory (not the directory path) to +which the source device is to be redirected; + +00H is a null byte; and + +Password is the password for access to the network directory. If no pass- +word is specified, both null bytes must immediately follow the pathname. + +If BL=3, the source string must be PRN, LPT1, LPT2, or LPT3. This +function buffers and sends all output for the named printer to the remote- +printer spooler named in the destination string. + +If BL=4, the source string can be either a drive letter followed by a colon, +or a null string. If the source string contains a valid drive letter and colon, +this call redirects all subsequent drive-letter references to the network +directory named in the destination string. If the source string is a null +string, MS-DOS attempts to grant access to the network directory with +the specified password. + +The maximum length of the destination string is 128 bytes. You can +retrieve the value in CX by using Function 5FH, Code 02H (Get Assign- +List Entry). + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 Microsoft Networks must be running to use this function request; + the value in BX is not 1 to 4, the source string is in the wrong for- + mat; the destination string is in the wrong format; or the source + device is already redirected. + +3 The network directory path is invalid or doesn't exist. + +5 The network directory/password combination is not valid. This + does not mean that the password itself was invalid; the directory + might not exist on the server. + +8 There is not enough memory for string substitutions. + + + +34 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +redir macro device,value,source,destination + mov bl, device + mov cx, value + mov si, offset source + mov es, seg destination + mov di, offset destination + mov al, 03H + mov ah, 5FH + int 21H + endm + + + + 35 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program redirects two drives and a printer from a worksta- +tion to a server named harold. It assumes the machine name, directory +names, and driver letters shown: + +Local drive Netname +or printer on server Password + +E: WORD none +F: COMM fred +PRN: PRINTER quick + +printer equ 3 +drive equ 4 +; +local_1 db "e:",0 +local_2 db "f:",0 +local_3 db "prn",0 +remote_1 db "\harold\word",0,0 +remote_2 db "\harold\comm",0,"fred",0 +remote_3 db "\harold\printer",0,"quick",0 +; +begin: redir local_1,remote_1,drive,0 ;THIS FUNCTION + jc error ;routine not shown + redir local_2,remote_2,drive,0 ;THIS FUNCTION + jc error ;routine not shown + redir local_3,remote_3,printer,0 ;THIS FUNCTION + jc error ;routine not shown + + + +36 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Cancel Assign-List Entry (Function 5FH, Code +04H) + + Call: + + AH = 5FH + AL = 04H + DS:SI + Pointer to name of source device + + Return: + + Carry set: + AX + 1 = Invalid function code + 15 = Redirection paused on server + (Other errors particular to the network + may occur.) + Carry not set: + No error + + + +Comments: + +Function 5FH, Code 04H, cancels the redirection of a printer or disk drive +(source device) to a network directory (destination device) made with +Function 5FH, Code 03H (Make Assign-List Entry). SI must contain the +offset (to the segment address in DS) of an ASCIZ string that specifies the +name of the printer or drive whose redirection is to be canceled. Microsoft +Networks must be running. + +The ASCIZ string pointed to by DS:SI can contain one of three values: + + o The letter of a redirected drive, followed by a colon. Cancels the + redirection and restores the drive to its physical meaning. + + o The name of a redirected printer (PRN, LPT1, LPT2, LPT3, or + their machine-specific equivalents). Cancels the redirection and + restores the printer name to its physical meaning. + + o A string starting with \\ (2 backslashes). Terminates the connec- + tion between the local machine and the network directory. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + + 37 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + Meaning +_ ________________________________________________________________ + +1 Microsoft Networks must be running to use this function request; + or the ASCIZ string names a nonexistent source device. + +15 Disk or printer redirection on the network server is paused. + + +Macro Definition: + + +cancel_redir macro local + mov si, offset local + mov al, 4 + mov ah, 5FH + int 21H + endm + + +Example: + +The following program cancels the redirection of drives E and F and the +printer (PRN) of a Microsoft Networks workstation. It assumes that these +local devices were redirected previously. + +local_1 db "e:",0 +local_2 db "f:",0 +local_3 db "prn",0 +; +begin: cancel_redir local_1 ;THIS FUNCTION + jc error ;routine not shown + cancel_redir local_2 ;THIS FUNCTION + jc error ;routine not shown + cancel_redir local_3 ;THIS FUNCTION + jc error ;routine not shown + + + +38 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Get PSP (Function 62H) + + Call: + + AH = 62H + + Return: + + BX + Segment address of the Program + Segment Prefix of the current process + + + +Comments: + +Function 62H retrieves the segment address of the currently active process +(the start of the Program Segment Prefix). The address returns in BX. + +Macro Definition: + + +get_psp macro + mov ah, 62H + int 21H + endm + + +Example: + +The following program displays the segment address of its Program Seg- +ment Prefix (PSP) in hexadecimal. + +msg db "PSP segment address: H",0DH,0AH,"$" +; +begin: get_psp ;THIS FUNCTION + convert bx,16,msg[21] ;see end of chapter + display msg ;see Function 09H + + + + 39 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Extended Country Information (Function +65H) + + Call: + + AH = 65H + AL + Function (minor) code + BX + Code page (-1 = active CON device) + CX + Amount of data to return + DX + Country ID for which information is to be returned + (-1=default country) + ES:DI + Address of country information buffer + + Return: + + 1 = Buffer has been filled + 2 = File not found + + +Comments: + +Function 65H retrieves standard country information. This information +includes country ID, code page, date and time format, currency symbol, +separators (for thousands, decimals, data list, date and time) currency for- +mat flags, digits in currency, and case-mapping information. + +The function code passed in AL may be one of the following: + +Code + Description +_ ________________________________________________________________ + +1 Return standard information + +2 Return pointer to uppercase table + +3 Return pointer to filename uppercase table + +4 Return pointer to collating table + +5 Reserved (no entry) + +6 Return pointer to collating sequence + + + +40 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +MS-DOS 3.3 provides more country-dependent information than previous +versions of MS-DOS. Only the information for the default country is kept +in the kernel. Country-dependent information for all other countries is +contained in the country.sys file. The MS-DOS nlsfunc command is used +to access the country-dependent information in country.sys using this call. +If the country code and code page number do not match, or if either is +invalid, error code 2 is returned to AX. If CX is less than 5, error code 1 is +returned. If the amount of information requested is greater than the value +of CX, only CX bytes are returned and no error is reported. + +If AL = 1, the buffer is filled with the following information: + +db 1 ; Information ID +dw ? ; Size (<=38) +dw ? ; Country ID +dw ? ; Code page + +If AL = 2, the buffer is filled with the following information: + +db 2 ; Information ID +dd ? ; Double-word pointer to uppercase table + +If AL = 4, the buffer is filled with the following information: + +db 4 ; Information ID +dd ? ; Double-word pointer to filename uppercase table + +Both of these tables consist of a length field (two bytes) followed by 128 +uppercase values for the upper 128 ASCII characters. The following for- +mula is used to compute the address of an uppercase equivalent in the +table: + +Address of outchar = inchar - (256-table_len) = table_start + +where: + +Parameter + Meaning +_ ________________________________________________________________ + +inchar Character to be generated + +table_len Length of list of uppercase values (two bytes) + +table_start Starting address of uppercase table + +outchar Uppercase value for inchar + +If inchar is greater than or equal to (256 - table_len), there is an uppercase +equivalent in the table; otherwise, there is not. + + + + 41 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +If AL = 6, the buffer is filled with the following information: + +db 6 ; Information ID +dd ? ; Double-word pointer to collating sequence + +The table is 258 bytes long. The first word is the length of the table. The +rest of the table is 256 ASCII values in the appropriate order. + + +42 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Get/Set Global Code Page (Function 66H) + + Call: + + AH = 66H + AL + Function (minor) code + BX + Code page to set (AL = 2) + + Return: + + Carry set: + AX + 02 = File not found + 65 = Device not selected + Carry not set: + No error + + + +Comments: + +Function 66H gets or sets the code page used by the kernel and all devices. +If no other code page has been set, this function gets the default code page +from DX. If another code page is set, this function retrieves the active +code page from BX. + +The MS-DOS nlsfunc command and country.sys must be on the system if +this function is to be used to change the global code page. + +The function code may be one of the following: + +Code + Description +_ ________________________________________________________________ + +1 Get code page + +2 Set code page + +MS-DOS gets the new code page from the country.sys file. Devices must be +prepared for code page switching before a code page can be selected. To +prepare a device, a device driver that supports code page switching must +be installed by using the device command in the config.sys file. The user + + 43 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +must also use the prepare keyword with the MS-DOS mode command to +prepare the device for code page switching. + +The code page selected must be compatible with the country code specified +in the config.sys file. If MS-DOS cannot read country.sys or other specified +country information file, error code 02 is returned to AX. + + +44 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Set Handle Count (Function 67H) + + Call: + + AH = 67H + BX + Number of allowed handles + + Return: + + Carry set: + AX + Carry not set: + No error + + + +Comments: + +Function 67H increases or decreases the number of files a program can +have open at one time. The maximum number of files handles is 64K. If +less than 20 are specified, the minimum handle number, 20, is assumed. If +this call is used to reduce the number of allowed handles, the new limit +does not take affect until any handles above the new limit are closed. + +The user should use Call 4AH (Set Block) to allocate memory for the +extended handle list if BX is greater than 255. The maximum number for +the value of the config.sys command files is 255. + + + 45 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Commit File (Function 68H) + + Call: + + AH = 68H + BX + File handle + + Return: + + Carry set: + AX = error + Carry not set + No error + + + +Comments: + +Function 68H flushes all buffered data for a file without closing it. Using +this call is more efficient than using the traditional close-open sequence, +and is more effective for network environments. This call makes sure that +the disk image of a file is current. + + +46 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +; Macro Definitions for MS-DOS System Call Examples +; +;******************* +; Interrupts +;******************* +; Interrupt 25H +ABS_DISK_READ macro disk,buffer,num_sectors,first_sector + mov al,disk + mov bx,offset buffer + mov cx,num_sectors + mov dx,first_sector + int 25H + popf + endm +; Interrupt 26H +ABS_DISK_WRITE macro disk,buffer,num_sectors,first_sector + mov al,disk + mov bx,offset buffer + mov cx,num_sectors + mov dx,first_sector + int 26H + popf + endm +; Interrupt 27H +STAY_RESIDENT macro last_instruc + mov dx,offset last_instruc + inc dx + int 27H + endm +; +; +;******************* +; Function Requests +;******************* +; Function Request 00H +TERMINATE_PROGRAM macro + xor ah,ah + int 21H + endm +; Function Request 01H +READ_KBD_AND_ECHO macro + mov ah,01H + int 21H + endm +; Function Request 02H +DISPLAY_CHAR macro character + mov dl,character + mov ah,02H + int 21H + endm +; Function Request 03H +AUX_INPUT macro + mov ah,03H + int 21H + endm +; Function Request 04H + + 47 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +AUX_OUTPUT macro + mov ah,04H + int 21H + endm +; Function Request 05H +PRINT_CHAR macro character + mov dl,character + mov ah,05H + int 21H + endm +; Function Request 06H +DIR_CONSOLE_IO macro switch + mov dl,switch + mov ah,06H + int 21H + endm +; Function Request 07H +DIR_CONSOLE_INPUT macro + mov ah,07H + int 21H + endm +; Function Request 08H +READ_KBD macro + mov ah,08H + int 21H + endm +; Function Request 09H +DISPLAY macro string + mov dx,offset string + mov ah,09H + int 21H + endm +; Function Request 0AH +GET_STRING macro limit,string + mov dx,offset string + mov string,limit + mov ah,0AH + int 21H + endm +; Function Request 0BH +CHECK_KBD_STATUS macro + mov ah,0BH + int 21H + endm +; Function Request 0CH +FLUSH_AND_READ_KBD macro switch + mov al,switch + mov ah,0CH + int 21H + endm +; Function Request 0DH +RESET_DISK macro + mov ah,0DH + int 21H + endm +; Function Request 0EH + +48 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +SELECT_DISK macro disk + mov dl,disk[-65] + mov ah,0EH + int 21H + endm +; Function Request 0FH +OPEN macro fcb + mov dx,offset fcb + mov ah,0FH + int 21H + endm +; Function Request 10H +CLOSE macro fcb + mov dx,offset fcb + mov ah,10H + int 21H + endm +; Function Request 11H +SEARCH_FIRST macro fcb + mov dx,offset fcb + mov ah,11H + int 21H + endm +; Function Request 12H +SEARCH_NEXT macro fcb + mov dx,offset fcb + mov ah,12H + int 21H + endm +; Function Request 13H +DELETE macro fcb + mov dx,offset fcb + mov ah,13H + int 21H + endm +; Function Request 14H +READ_SEQ macro fcb + mov dx,offset fcb + mov ah,14H + int 21H + endm +; Function Request 15H +WRITE_SEQ macro fcb + mov dx,offset fcb + mov ah,15H + int 21H + endm +; Function Request 16H +CREATE macro fcb + mov dx,offset fcb + mov ah,16H + int 21H + endm +; Function Request 17H +RENAME macro fcb,newname + mov dx,offset fcb + + 49 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + mov ah,17H + int 21H + endm +; Function Request 19H +CURRENT_DISK macro + mov ah,19H + int 21H + endm +; Function Request 1AH +SET_DTA macro buffer + mov dx,offset buffer + mov ah,1AH + endm +; Function Request 1BH +DEF_DRIVE_DATA macro + mov ah,1BH + int 21H + endm +; Function Request 1CH +DRIVE_DATA macro drive + mov dl,drive + mov ah,1CH + int 21H + endm +; Function Request 21H +READ_RAN macro fcb + mov dx,offset fcb + mov ah,21H + int 21H + endm +; Function Request 22H +WRITE_RAN macro fcb + mov dx,offset fcb + mov ah,22H + int 21H + endm +; Function Request 23H +FILE_SIZE macro fcb + mov dx,offset fcb + mov ah,23H + int 21H + endm +; Function Request 24H +SET_RELATIVE_RECORD macro fcb + mov dx,offset fcb + mov ah,24H + int 21H + endm +; Function Request 25H +SET_VECTOR macro interrupt,handler_start + mov al,interrupt + mov dx,offset handler_start + mov ah,25H + int 21H + endm +; Function Request 26H + +50 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +CREATE_PSP macro seg_addr + mov dx,offset seg_addr + mov ah,26H + int 21H + endm +; Function Request 27H +RAN_BLOCK_READ macro fcb,count,rec_size + mov dx,offset fcb + mov cx,count + mov word ptr fcb[14],rec_size + mov ah,27H + int 21H + endm +; Function Request 28H +RAN_BLOCK_WRITE macro fcb,count,rec_size + mov dx,offset fcb + mov cx,count + mov word ptr fcb[14],rec_size + mov ah,28H + int 21H + endm +; Function Request 29H +PARSE macro string,fcb + mov si,offset string + mov di,offset fcb + push es + push ds + pop es + mov al,0FH + mov ah,29H + int 21H + pop es + endm +; Function Request 2AH +GET_DATE macro + mov ah,2AH + int 21H + endm +; Function Request 2BH +SET_DATE macro year,month,day + mov cx,year + mov dh,month + mov dl,day + mov ah,2BH + int 21H + endm +; Function Request 2CH +GET_TIME macro + mov ah,2CH + int 21H + endm +; Function Request 2DH +SET_TIME macro hour,minutes,seconds,hundredths + mov ch,hour + mov cl,minutes + mov dh,seconds + + 51 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + mov dl,hundredths + mov ah,2DH + int 21H + endm +; Function Request 2EH +VERIFY macro switch + mov al,switch + mov ah,2EH + int 21H + endm +; Function Request 2FH +GET_DTA macro + mov ah,2FH + int 21H + endm +; Function Request 30H +GET_VERSION macro + mov ah,30H + int 21H + endm +; Function Request 31H +KEEP_PROCESS macro return_code,last_byte + mov al,return_code + mov dx,offset last_byte + mov cl,4 + shr dx,cl + inc dx + mov ah,31H + int 21H + endm +; Function Request 33H +CTRL_C_CK macro action,state + mov al,action + mov dl,state + mov ah,33H + int 21H + endm +; Function Request 35H +GET_VECTOR macro interrupt + mov al,interrupt + mov ah,35H + int 21H + endm +; Function Request 36H +GET_DISK_SPACE macro drive + mov dl,drive + mov ah,36H + int 21H + endm +; Function Request 38H +GET_COUNTRY macro country,buffer + local gc_01 + mov dx,offset buffer + mov ax,country + cmp ax,0FFH + jl gc_01 + +52 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + mov al,0ffh + mov bx,country +gc_01: mov ah,38H + int 21H + endm +; Function Request 38H +SET_COUNTRY macro country + local sc_01 + mov dx,0FFFFH + mov ax,country + cmp ax,0FFH + jl sc_01 + mov al,0ffh + mov bx,country +sc_01: mov ah,38H + int 21H + endm +; Function Request 39H +MAKE_DIR macro path + mov dx,offset path + mov ah,39H + int 21H + endm +; Function Request 3AH +REM_DIR macro path + mov dx,offset path + mov ah,3AH + int 21H + endm +; Function Request 3BH +CHANGE_DIR macro path + mov dx,offset path + mov ah,3BH + int 21H + endm +; Function Request 3CH +CREATE_HANDLE macro path,attrib + mov dx,offset path + mov cx,attrib + mov ah,3CH + int 21H + endm +; Function Request 3DH +OPEN_HANDLE macro path,access + mov dx,offset path + mov al,access + mov ah,3DH + int 21H + endm +; Function Request 3EH +CLOSE_HANDLE macro handle + mov bx,handle + mov ah,3EH + int 21H + endm +; Function Request 3FH + + 53 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +READ_HANDLE macro handle,buffer,bytes + mov bx,handle + mov dx,offset buffer + mov cx,bytes + mov ah,3FH + int 21H + endm +; Function Request 40H +WRITE_HANDLE macro handle,buffer,bytes + mov bx,handle + mov dx,offset buffer + mov cx,bytes + mov ah,40H + int 21H + endm +; Function Request 41H +DELETE_ENTRY macro path + mov dx,offset path + mov ah,41H + int 21H + endm +; Function Request 42H +MOVE_PTR macro handle,high,low,method + mov bx,handle + mov cx,high + mov dx,low + mov al,method + mov ah,42H + int 21H + endm +; Function Request 43H +CHANGE_MODE macro path,action,attrib + mov dx,offset path + mov al,action + mov cx,attrib + mov ah,43H + int 21H + endm +; Function Request 4400H,01H +IOCTL_DATA macro code,handle + mov bx,handle + mov al,code + mov ah,44H + int 21H + endm +; Function Request 4402H,03H +IOCTL_CHAR macro code,handle,buffer + mov bx,handle + mov dx,offset buffer + mov al,code + mov ah,44H + int 21H + endm +; Function Request 4404H,05H +IOCTL_STATUS macro code,drive,buffer + mov bl,drive + +54 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + mov dx,offset buffer + mov al,code + mov ah,44H + int 21H + endm +; Function Request 4406H,07H +IOCTL_STATUS macro code,handle + mov bx,handle + mov al,code + mov ah,44H + int 21H + endm +; Function Request 4408H +IOCTL_CHANGE macro drive + mov bl,drive + mov al,08H + mov ah,44H + int 21H + endm +; Function Request 4409H +IOCTL_RBLOCK macro drive + mov bl,drive + mov al,09H + mov ah,44H + int 21H + endm +; Function Request 440AH +IOCTL_RHANDLE macro handle + mov bx,handle + mov al,0AH + mov ah,44H + int 21H + endm +; Function Request 440BH +IOCTL_RETRY macro retries,wait + mov dx,retries + mov cx,wait + mov al,0BH + mov ah,44H + int 21H + endm +; Function Request 440CH +GENERIC_IOCTL_HANDLES macro handle,function,category,buffer + mov ch,05H + mov cl,function + mov dx,offset buffer + mov bx,handle + mov ah,44H + mov al,0CH + int 21H + endm +; Function Request 440DH +GENERIC_IOCTL_BLOCK macro drive_num,function,category,parm_blk + mov ch,08H + mov cl,function + mov dx,offset parm_blk - 1 + + 55 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + mov bx,drive_num + mov ah,44H + mov al,0DH + int 21H + endm +; Function Request 440EH +IOCTL_GET_DRIVE_MAP macro logical_drv + mov bx,logical_drv + mov ah,44H + mov al,0EH + int 21H + endm +; Function Request 440FH +IOCTL_SET_DRIVE_MAP macro logical_drv + mov bx,logical_drv + mov ah,44H + mov al,0FH + int 21H + endm +; Function Request 45H +XDUP macro handle + mov bx,handle + mov ah,45H + int 21H + endm +; Function Request 46H +XDUP2 macro handle1,handle2 + mov bx,handle1 + mov cx,handle2 + mov ah,46H + int 21H + endm +; Function Request 47H +GET_DIR macro drive,buffer + mov dl,drive + mov si,offset buffer + mov ah,47H + int 21H + endm +; Function Request 48H +ALLOCATE_MEMORY macro bytes + mov bx,bytes + mov cl,4 + shr bx,cl + inc bx + mov ah,48H + int 21H + endm +; Function Request 49H +FREE_MEMORY macro seg_addr + mov ax,seg_addr + mov es,ax + mov ah,49H + int 21H + endm +; Function Request 4AH + +56 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +SET_BLOCK macro last_byte + mov bx,offset last_byte + mov cl,4 + shr bx,cl + add bx,17 + mov ah,4AH + int 21H + mov ax,bx + shl ax,cl + dec ax + mov sp,ax + mov bp,sp + endm +; Function Request 4B00H +EXEC macro path,command,parms + mov dx,offset path + mov bx,offset parms + mov word ptr parms[02h],offset command + mov word ptr parms[04h],cs + mov word ptr parms[06h],5ch + mov word ptr parms[08h],es + mov word ptr parms[0ah],6ch + mov word ptr parms[0ch],es + mov al,0 + mov ah,4BH + int 21H + endm +; Function Request 4B03H +EXEC_OVL macro path,parms,seg_addr + mov dx,offset path + mov bx,offset parms + mov parms,seg_addr + mov parms[02H],seg_addr + mov al,3 + mov ah,4BH + int 21H + endm +; Function Request 4CH +END_PROCESS macro return_code + mov al,return_code + mov ah,4CH + int 21H + endm +; Function Request 4DH +RET_CODE macro + mov ah,4DH + int 21H + endm +; Function Request 4EH +FIND_FIRST_FILE macro path,attrib + mov dx,offset path + mov cx,attrib + mov ah,4EH + int 21H + endm +; Function Request 4FH + + 57 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +FIND_NEXT_FILE macro + mov ah,4FH + int 21H + endm +; Function Request 54H +GET_VERIFY macro + mov ah,54H + int 21H + endm +; Function Request 56H +RENAME_FILE macro old_path,new_path + mov dx,offset old_path + push ds + pop es + mov di,offset new_path + mov ah,56H + int 21H + endm +; Function Request 57H +GET_SET_DATE_TIME macro handle,action,time,date + mov bx,handle + mov al,action + mov cx,word ptr time + mov dx,word ptr date + mov ah,57H + int 21H + endm +; Function Request 58H +ALLOC_STRAT macro code,strategy + mov bx,strategy + mov al,code + mov ah,58H + int 21H + endm +; Function Request 59H +GET_ERROR macro + mov ah,59 + int 21H + endm +; Function Request 5AH +CREATE_TEMP macro pathname,attrib + mov cx,attrib + mov dx,offset pathname + mov ah,5AH + int 21H + endm +; Function Request 5BH +CREATE_NEW macro pathname,attrib + mov cx,attrib + mov dx,offset pathname + mov ah,5BH + int 21H + endm +; Function Request 5C00H +LOCK macro handle,start,bytes + mov bx,handle + +58 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + mov cx,word ptr start + mov dx,word ptr start+2 + mov si,word ptr bytes + mov di,word ptr bytes+2 + mov al,0 + mov ah,5CH + int 21H + endm +; Function Request 5C01H +UNLOCK macro handle,start,bytes + mov bx,handle + mov cx,word ptr start + mov dx,word ptr start+2 + mov si,word ptr bytes + mov di,word ptr bytes+2 + mov al,1 + mov ah,5CH + int 21H + endm +; Function Request 5E00H +GET_MACHINE_NAME macro buffer + mov dx,offset buffer + mov al,0 + mov ah,5EH + int 21H + endm +; Function Request 5E02H +PRINTER_SETUP macro index,lgth,string + mov bx,index + mov cx,lgth + mov dx,offset string + mov al,2 + mov ah,5EH + int 21H + endm +; Function Request 5F02H +GET_LIST macro index,local,remote + mov bx,index + mov si,offset local + mov di,offset remote + mov al,2 + mov ah,5FH + int 21H + endm +; Function Request 5F03H +REDIR macro device,value,source,destination + mov bl,device + mov cx,value + mov si,offset source + mov es,seg destination + mov di,offset destination + mov al,03H + mov ah,5FH + int 21H + endm +; Function Request 5F04H + + 59 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +CANCEL_REDIR macro local + mov si,offset local + mov al,4 + mov ah,5FH + int 21H + endm +; Function Request 62H +GET_PSP macro + mov ah,62H + int 21H + endm +; +; +;******************* +; General +;******************* +; +DISPLAY_ASCIIZ macro asciiz_string + local search,found_it + mov bx,offset asciiz_string + +search: + cmp byte ptr [bx],0 + je found_it + inc bx + jmp short search + +found_it: + mov byte ptr [bx],"$" + display asciiz_string + mov byte ptr [bx],0 + display_char 0DH + display_char 0AH + endm +; +MOVE_STRING macro source,destination,count + push es + push ds + pop es + assume es:code + mov si,offset source + mov di,offset destination + mov cx,count + rep movs es:destination,source + assume es:nothing + pop es + endm +; +CONVERT macro value,base,destination + local table,start + jmp start +table db "0123456789ABCDEF" + +start: + push ax + push bx + +60 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + push dx + mov al,value + xor ah,ah + xor bx,bx + div base + mov bl,al + mov al,cs:table[bx] + mov destination,al + mov bl,ah + mov al,cs:table[bx] + mov destination[1],al + pop dx + pop bx + pop ax + endm +; +CONVERT_TO_BINARY macro string,number,value + local ten,start,calc,mult,no_mult + jmp start +ten db 10 + +start: + mov value,0 + xor cx,cx + mov cl,number + xor si,si + +calc: + xor ax,ax + mov al,string[si] + sub al,48 + cmp cx,2 + jl no_mult + push cx + dec cx + +mult: + mul cs:ten + loop mult + pop cx + +no_mult: + add value,ax + inc si + loop calc + endm +; +CONVERT_DATE macro dir_entry + mov dx,word ptr dir_entry[24] + mov cl,5 + shr dl,cl + mov dh,dir_entry[24] + and dh,1FH + xor cx,cx + mov cl,dir_entry[25] + shr cl,1 + + 61 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + add cx,1980 + endm +; +PACK_DATE macro date + local set_bit +; +; On entry: DH=day, DL=month, CX=(year-1980) +; + sub cx,1980 + push cx + mov date,dh + mov cl,5 + shl dl,cl + pop cx + jnc set_bit + or cl,80h + +set_bit: + or date,dl + rol cl,1 + mov date[1],cl + endm +; + + + +62 + +_ _ | | _ _ + + + diff --git a/PROGREF/2_DEVDR.A b/PROGREF/2_DEVDR.A new file mode 100644 index 0000000..337f098 --- /dev/null +++ b/PROGREF/2_DEVDR.A @@ -0,0 +1,3558 @@ + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + +2.1 Introduction + +The io.sys file comprises the "resident" device drivers, which form the +MS-DOS BIOS. These drivers are called upon by MS-DOS to handle +input/output (I/O) requests initiated by application programs. + +One of the most powerful features of MS-DOS is the ability to add new +devices such as printers, plotters, and mouse input devices without rewrit- +ing the BIOS. The MS-DOS BIOS is configurable; that is, new drivers can +be added and existing drivers can be preempted. Nonresident, or install- +able, device drivers may be easily added at boot time by including a +device command line in the config.sys file. + +At boot time, a minimum of five resident device drivers must be present. +These drivers are in a linked list: the header of each one contains a +DWORD pointer to the next. The last driver in the chain has an end-of-list +marker of -1, -1 (all bits on). + +Each driver in the chain has two entry points: the strategy entry point and +the interrupt entry point. MS-DOS does not take advantage of the two +entry points: it calls the strategy routine, then immediately calls the inter- +rupt routine. + +The dual entry points will accomodate future multitasking versions of +MS-DOS and MS OS/2 operating systems. In multitasking environments, +I/O must be asynchronous; to accomplish this, the strategy routine will be +called to (internally) queue a request and return quickly. It is then the +responsibility of the interrupt routine to perform the I/O at interrupt time +by getting requests from the internal queue and processing them. When a +request is completed, it is flagged as "done" by the interrupt routine. +MS-DOS periodically scans the list of requests looking for those that are +flagged as done, and "wakes up" the process waiting for the completion of +the request. + +When requests are queued in this manner, it is no longer sufficient to pass +I/O information in registers, since many requests may be pending at any +time. Therefore, the MS-DOS device interface uses "packets" to pass +request information. These request packets are of variable size and for- +mat, and are composed of two parts: + + 1. The static request header section, which has the same format for + all requests + + 2. A section which has information specific to the type of request + +A driver is called with a pointer to a packet. In multitasking versions, this +packet will be linked into a global chain of all pending I/O requests main- +tained by MS-DOS. + + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +MS-DOS does not implement a global or local queue. Only one request is +pending at any one time. The strategy routine must store the address of +the packet at a fixed location, and the interrupt routine, which is called +immediately after the strategy routine, should process the packet by com- +pleting the request and returning. It is assumed that the request is com- +pleted when the interrupt routine returns. + +To make a device driver that sysinit can install, a .bin (core image) or .exe +format file must be created with the device driver header at the beginning +of the file. The link field should be initialized to -1 (sysinit fills it in). Dev- +ice drivers which are part of the BIOS should have their headers point to +the next device in the list and the last header should be initialized to +-1,-1. The BIOS must be a .bin (core image) format file. + +The .exe format installable device drivers may be used in non-IBM versions +of MS-DOS. On the IBM Personal Computer, the .exe loader is located in +command.com which is not present at the time that installable devices are +being loaded. + +2.2 Format of a Device Driver + +A device driver is a program segment responsible for communication +between DOS and the system hardware. It has a special header at the +beginning identifying it as a device driver, defining entry points, and +describing various attributes of the device. + +_ ________________________________________________________________ + +Note + + For device drivers, the file must not use the ORG 100H (like .com files). + Because it does not use the Program Segment Prefix (PSP), the device + driver is simply loaded; therefore, the file must have an origin of zero + (ORG 0 or no ORG statement). + +_ ________________________________________________________________ + +There are two kinds of device drivers: + + o Character device drivers + + o Block device drivers + +Character devices perform serial character I/O. Examples are the console, +communications port and printer. These devices are named (i.e., CON, +AUX, CLOCK, etc.), and programs may open channels (handles or file +control blocks) to do I/O to them. + + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +Block devices include all the disk drives on the system. They can perform +random I/O in structured pieces called blocks (usually the physical sector +size). These devices are not named as the character devices are, and there- +fore cannot be opened directly. Instead they have unit numbers and are +identified by drive letters such as A, B, and C. + +A single block device driver may be responsible for one or more logically +contiguous disk drives. For example, block device driver ALPHA may be +responsible for drives A, B, C, and D. This means that it has four units +defined (0-3), and therefore, takes up four drive letters. The position of +the driver in the list of all drivers determines which units correspond to +which driver letters. If driver ALPHA is the first block driver in the device +list, and it defines four units (0-3), then they will be A, B, C, and D. If +BETA is the second block driver and defines three units (0-2), then they +will be E, F, and G, and so on. The theoretical limit is 63, but it should be +noted that the device installation code will not allow the installation of a +device if it would result in a drive letter greater than Z (5AH). All block +device drivers present in the standard resident BIOS will be placed ahead +of installable block device drivers in the list. + +_ ________________________________________________________________ + +Note + + Because they have only one name, character devices cannot define mul- + tiple units. + +_ ________________________________________________________________ + + +2.3 How to Create a Device Driver + +To create a device driver that MS-DOS can install, you must create a +binary file (.com or .exe format) with a device header at the beginning of +the file. Note that for device drivers, the code should not be originated at +100H, but at 0. The device header contains a link field (a pointer to the +next device header) which should be -1, unless there is more than one dev- +ice driver in the file. The attribute field and entry points must be set +correctly. + +If it is a character device, the name field should be filled in with the name +of that character device. The name can be any legal eight-character +filename. If the name is less than eight characters, it should be padded out +to eight characters with spaces (20H). Note that device names do not +include colons (:). The fact that CON is the same as CON: is a property of +the default MS-DOS command interpreter (command.com) and not of the +device driver or the MS-DOS interface. All character device names are +handled in this way. + + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +MS-DOS always processes installable device drivers before handling the +default devices, so to install a new CON device, simply name the device +CON. Remember to set the standard input device and standard output +device bits in the attribute word on a new CON device. The scan of the +device list stops on the first match, so the installable device driver takes +precedence. + +It is not possible to replace the resident disk block device driver with an +installable device driver the same way you can replace the other device +drivers in the BIOS. Block drivers can be used only for devices not directly +supported by the default disk drivers in the io.sys file. + +_ ________________________________________________________________ + +Note + + Because MS-DOS can install the driver anywhere in memory, care must + be taken when making far memory references. You should not expect + that your driver will always be loaded in the same place every time. + +_ ________________________________________________________________ + + +2.3.1 Device Strategy Routine + +The device strategy routine, which is called by MS-DOS for each device +driver service request, is primarily responsible for queuing these requests in +the order in which they are to be processed by the device interrupt rou- +tine. Such queuing can be a very important performance feature in a mul- +titasking environment, or where asynchronous I/O is supported. As +MS-DOS does not currently support these facilities, only one request can +be serviced at a time, and this routine is usually very short. In the coding +examples in Section 2.12, "Two Sample Device Drivers," each request is +simply stored in a single pointer area. + +2.3.2 Device Interrupt Routine + +The device interrupt routine contains the code necessary to process the +service request. It may interface to the hardware, or it may use ROM +BIOS calls. It usually consists of a series of procedures that handle the +specific command codes to be supported as well as some exit and error- +handling routines. See the coding examples in Section 2.12, "Two Sample +Device Drivers." + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + +2.4 Installing Device Drivers + +MS-DOS allows new device drivers to be installed dynamically at boot +time. This is accomplished by initialization code in the io.sys file that +reads and processes the config.sys file. + +MS-DOS calls upon the device drivers to perform their function in the fol- +lowing manner: + + 1. MS-DOS makes a FAR call to the strategy entry. + + 2. MS-DOS passes device driver information in a request header to + the strategy routine. + + 3. MS-DOS makes a FAR call to the interrupt entry. + +This calling structure is designed to be easily upgraded to support any +future multitasking environment. + + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +2.5 Device Headers + +A device header is required at the beginning of a device driver. A device +header looks like this: + + +--------------------------------------+ + | DWORD Pointer to next device | + | (Usually set to -1 if this driver | + | is the last or only driver in the | + | file) | + +--------------------------------------+ + | WORD Attributes | + +--------------------------------------+ + | WORD Pointer to device strategy | + | entry point | + +--------------------------------------+ + | WORD Pointer to device interrupt | + | entry point | + +--------------------------------------+ + | 8-BYTE Character device name field | + | Character devices set a device name. | + | For block devices the first byte is | + | the number of units. | + +--------------------------------------+ + + + + Figure 2.1 Sample Device Header + +Note that the device entry points are words. They must be offsets from the +same segment number used to point to this table. For example, if xxx:yyy +points to the start of this table, then xxx:strategy and xxx:interrupt are the +entry points. + +The device header fields are described in the following section. + +2.5.1 Pointer to Next Device Field + +The pointer to the next device header field is a double-word field (offset +followed by segment) that is set by MS-DOS to point at the next driver in +the system list at the time the device driver is loaded. It is important that +this field be set to -1 prior to load (when it is on the disk as a file) unless +there is more than one device driver in the file. If there is more than one +driver in the file, the first word of the double-word pointer should be the +offset of the next driver's device header. + +_ ________________________________________________________________ + +Note + + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + If there is more than one device driver in the file, the last driver in the + file must have the pointer to the next device header field set to -1. + +_ ________________________________________________________________ + + +2.5.2 Attribute Field + +The attribute field is used to identify the type of device for which this +driver is responsible. In addition to distinguishing between block and +character devices, these bits are used to give selected character devices +special treatment. (Note that if a bit in the attribute word is defined only +for one type of device, a driver for the other type of device must set that +bit to 0.) + + +Table 2.1 + +For Character Devices: + +_ _________________________________________________________________________ + +Bit Value Meaning + +_ _________________________________________________________________________ + +0 1 Device is console input (sti) device +1 1 Device is console output (sto) device +2 1 Device is nul device +3 1 Device is clock device +4-5 Reserved (must be 0) +6 1 Device supports 3.2 functions +7-10 Reserved (must be 0) +11 1 Device understands Open/Close +12 Reserved (must be 0) +13 1 Device supports Output Until Busy (OUB) +14 1 Device supports IOCtl control strings +15 1 Character device + +_ _________________________________________________________________________ + +Table 2.2 + +For Block Devices: + +_ _________________________________________________________________________ + +Bit Value Meaning + +_ _________________________________________________________________________ + +0-5 Reserved (must be 0) +6 1 Device supports 3.2 functions and Generic IOCtl function calls +7-10 Reserved (must be 0) +11 1 Device understands Open/Close/Removable Media +12 Reserved (must be 0) +13 1 Device determines the media by examining the FATID byte +14 1 Device supports IOCtl control strings +15 0 Block device + +_ _________________________________________________________________________ + + + 9 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +For example, assume that you have a new device driver that you want to +use as the standard input and output. In addition to installing the driver, +you must tell MS-DOS that you want the new driver to override the +current standard input and standard output (the CON device). This is +accomplished by setting the attributes to the desired characteristics, so +you would set bits 0 and 1 to 1 (note that they are separate). Similarly, a +new CLOCK device could be installed by setting that attribute. (Refer to +Section 2.10, "The Clock Device," in this chapter for more information.) +Although there is a NUL device attribute, the NUL device cannot be reas- +signed. This attribute exists so that MS-DOS can determine if the NUL +device is being used. + +Bit 13 for block devices affects the operation of the Build BPB (BIOS +Parameter Block) device call. If set, it requires the first sector of the FAT +always to reside in the same place. This bit has a different meaning on +character devices. It indicates that the device implements the Output +Until Busy device call. + +The IOCtl bit (bit 14) has meaning on character and block devices. The +IOCtl functions allow data to be sent and received by the device for its +own use (to set baud rate, stop bits, form length, etc.) instead of passing +data over the device channel as a normal read or write does. The interpre- +tation of the passed information is up to the device but it must not be +treated as normal I/O. This bit tells MS-DOS whether the device can han- +dle control strings by using the IOCtl system call, Function 44H. + +If a driver cannot process control strings, it should initially set this bit to +0. This tells MS-DOS to return an error if an attempt is made (via Func- +tion 44H) to send or receive control strings to this device. A device which +can process control strings should initialize the IOCtl bit to 1. For drivers +of this type, MS-DOS will make calls to the IOCtl input and output device +functions to send and receive IOCtl strings. + +The IOCtl functions allow data to be sent and received by the device for +its own use (for example, to set baud rate, stop bits, and form length), +instead of passing data over the device channel as does a normal read or +write. The interpretation of the passed information is up to the device, but +it must not be treated as a normal I/O request. + +The Open/Close/Removable Media bit (bit 11) signals to MS-DOS 3.x +and later versions whether this driver supports additional MS-DOS 3.x +functionality. To support these old drivers, it is necessary to detect them. +This bit was reserved in MS-DOS 2.x, and is 0. All new devices should +support the Open, Close, and Removable Media calls and set this bit +to 1. Since MS-DOS 2.x never makes these calls, the driver will be +backward-compatible. + + + +10 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +The MS-DOS 3.2 bit (bit 6) signals whether the device supports logical +drive mapping via Function 440EH (Get Logical Drive Map) and Function +440FH (Set Logical Drive Map). This bit also supports generic IOCtl func- +tions via Function 440CH (Generic IOCtl for Handles) and Function +440DH (Generic IOCtl for Block Devices). + + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ++---------------------------------------------------------------+ +| C | I | | | O | | | | | 3 | | | C | N | S | S | +| H | O | | | P | | | | | . | | | L | U | T | T | +| R | C | | | N | | | | | 2 | | | K | L | O | I | ++---------------------------------------------------------------+ + + + Figure 2.2 Attribute Word for Character Devices + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ++---------------------------------------------------------------+ +| | I | F | | O | | | | | 3 | | | | | | | +| | O | A | | P | | | | | . | | | | | | | +| | C | T | | N | | | | | 2 | | | | | | | ++---------------------------------------------------------------+ + + + Figure 2.3 Attribute Word for Block Devices + + +2.5.3 Strategy and Interrupt Routines + +These two fields are the pointers to the entry points of the strategy and +interrupt routines. They are word values, so they must be in the same seg- +ment as the device header. + +2.5.4 Name Field + +This is an eight-byte field that contains the name of a character device or +the number of units of a block device. If the field refers to a block device, +the number of units can be put in the first byte. This is optional, because +MS-DOS will fill in this location with the value returned by the driver's +Init code. For more information, see Section 2.4, "Installing Device +Drivers." + +2.6 Request Header + +When MS-DOS calls a device driver to perform a function, it passes a +request header in ES:BX to the strategy entry point. This is a fixed length +header, followed by data pertinent to the operation being performed. +Note that it is the device driver's responsibility to preserve the machine + + 11 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +state (for example, save all registers, including flags, on entry, and restore +them on exit). There is enough room on the stack when the strategy or +interrupt routine is called to do about 20 pushes. If more room on the +stack is needed, the driver should set up its own stack. + +The following figure illustrates a request header. + +REQUEST HEADER -> + +-----------------------------+ + | BYTE Length of record | + | Length in bytes of this | + | request header | + +-----------------------------+ + | BYTE Unit code | + | The subunit the operation | + | is for (minor device) | + | (no meaning on character | + | devices) | + +-----------------------------+ + | BYTE Command code | + +-----------------------------+ + | WORD Status | + +-----------------------------+ + | 8 BYTES Reserved | + | | + |-----------------------------| + + + Figure 2.4 Request Header + +The request header fields are described below. + +2.6.1 Length of Record + +This field contains the length (in bytes) of the request header. + +2.6.2 Unit Code Field + +The unit code field identifies which unit in your device driver the request is +for. For example, if your device driver has three units defined, then the +possible values of the unit code field would be 0, 1, and 2. + +2.6.3 Command Code Field + +The command code field in the request header can have the following +values: + +Code + Function +_ ________________________________________________________________ + +12 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +0 Init + +1 Media Check (Block devices only) + +2 Build BPB (Block devices only) + +3 IOCtl Input (Only called if device has IOCtl) + +4 Input (Read) + +5 Non-destructive Read, No Wait (Character devices only) + +6 Input Status (Character devices only) + +7 Input Flush (Character devices only) + +8 Output (Write) + +9 Output (Write) with Verify + +10 Output Status (Character devices only) + +11 Output Flush (Character devices only) + +12 IOCtl Output (Only called if device has IOCtl) + +13 Device Open (Only called if Open/Close/Removable Media + bit set) + +14 Device Close (Only called if Open/Close/Removable Media + bit set) + +15 Removable Media (Only called if Open/Close/Removable + Media bit set and device is block) + +16 Output Until Busy (Only called if bit 13 is set on character dev- + ices) + +19 Generic IOCtl Request + +23 Get Logical Device + +24 Set Logical Device + + +2.6.4 Status Field + +The following figure illustrates the status field in the request header. + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ + | E | | B | D | | + | R | Reserved | U | O | Error code (bit 15 on)| + | R | | S | N | | + | | | Y | E | | + +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ + +The status word is zero on entry and is set by the driver interrupt routine +on return. + + + 13 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +Bit 8 is the done bit. When set, it means the operation has completed. The +driver sets it to 1 when it exits. + +Bit 15 is the error bit. If it is set, then the low eight bits indicate the +error. The errors are as follows: + +Error + Meaning +_ ________________________________________________________________ + +0 Write protect violation + +1 Unknown unit + +2 Drive not ready + +3 Unknown command + +4 CRC error + +5 Bad drive request structure length + +6 Seek error + +7 Unknown media + +8 Sector not found + +9 Printer out of paper + +A Write fault + +B Read fault + +C General failure + +D Reserved + +E Reserved + +F Invalid disk change + +Bit 9 is the busy bit, which is set only by Status calls and the +Removable Media call. + +2.7 Device Driver Functions + +Device drivers may perform all or some of these general functions. In some +cases, these functions break down into several command codes, for specific +cases. Each of the following general functions is described in this section. + + o Init + + o Media Check + + + +14 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + o Build BPB + + o Read, or Write, or Write Until Busy, or Write with Verify, or + Read IOCtl, or Write IOCtl + + o Non-destructive Read, No Wait + + o Open or Close (3.x) + + o Removable Media (3.x) + + o Status + + o Flush + + o Generic IOCtl + + o Get or Set Logical Device + +All strategy routines are called with ES:BX pointing to the request header. +The interrupt routines get the pointers to the request header from the +queue that the strategy routines store them in. The command code in the +request header tells the driver which function to perform and what data +follows the request header. + +_ ________________________________________________________________ + +Note + + All DWORD pointers are stored offset first, then segment. + +_ ________________________________________________________________ + + +2.7.1 The Init Function + +Command code = 0 + +INIT - ES:BX -> ++------------------------------------+ +| 13-BYTE Request header | ++------------------------------------+ +| BYTE Number of units | ++------------------------------------+ +| DWORD End Address | ++------------------------------------+ +| DWORD Pointer to BPB array | +| (Not set by character devices) | ++------------------------------------+ +| BYTE Block device number | ++------------------------------------+ + +One of the functions defined for each device driver is Init. This routine is +called only once when the device is installed. The Init routine must return +the end address, which is a DWORD pointer to the end of the portion of +the device driver to remain resident. To save space, you can use this + + 15 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +pointer method to delete initialization code that is needed only once. + +The number of units, end address, and BPB pointer are to be set by the +driver. However, on entry for installable device drivers, the DWORD that +is to be set by the driver to the BPB array (on block devices) points to the +character after the "=" on the line in config.sys that caused this device +driver to be loaded. This allows drivers to scan the config.sys invocation +line for parameters that might be passed to the driver. This line is ter- +minated by a RETURN or a linefeed character. This data is read-only and +allows the device to scan the config.sys command line for arguments. + + device=\dev\vt52.sys /l + | + |_____BPB address points here + +Also, for block devices only, the drive number assigned to the first unit +defined by this driver (A=0) as contained in the block device number field. +This is also read-only. + +_ ________________________________________________________________ + +Note + + The Init routine can issue only Functions 01H-0CH, 25H, 30H, and + 35H. + +_ ________________________________________________________________ + +For installable character devices, the end address parameter must be +returned. This is a pointer to the first available byte of memory above the +driver and may be used to throw away initialization code. + +Block devices must return the following information: + + 1. The number of units must be returned. MS-DOS uses this number + to determine logical device names. If the current maximum logical + device letter is F at the time of the install call, and the Init routine + returns 4 as the number of units, then they will have logical names + G, H, I, and J. This mapping is determined by the position of the + driver in the device list, and by the number of units on the device + (stored in the first byte of the device name field). + + 2. A DWORD pointer to an array of word offsets (pointers) to BPBs + (BIOS Parameter Blocks) must be returned. The BPBs passed by + the device driver are used by MS-DOS to create an internal struc- + ture. There must be one entry in this array for each unit defined + by the device driver. In this way, if all units are the same, all the + pointers can point to the same BPB, saving space. If the device + driver defines two units, then the DWORD pointer points to the + first of two one-word offsets which in turn point to BPBs. The for- + mat of the BPB is described later in this chapter in Section 2.7.3, + +16 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + "The Build BPB Function." + + Note that this array of word offsets must be protected (below the + free pointer set by the return), since an internal DOS structure will + be built starting at the byte pointed to by the free pointer. The + defined sector size must be less than or equal to the maximum sec- + tor size defined by the resident device drivers (BIOS) during initial- + ization. If it isn't, the installation will fail. + + 3. The last thing that the Init function of a block device must pass + back is the media descriptor byte. This byte means nothing to + MS-DOS, but is passed to devices so that they know what parame- + ters MS-DOS is currently using for a particular drive. + +_ ________________________________________________________________ + +Note + + If there are multiple device drivers in a single file, MS-DOS uses the + ending address returned by the last Init function called. All device + drivers in a single file should return the same ending address. All dev- + ices in a single file should be grouped together low in memory with the + initialization code for all devices following it in memory. + +_ ________________________________________________________________ + + +2.7.2 The Media Check Function + +Command Code = 1 + +MEDIA CHECK - ES:BX -> ++------------------------------------+ +| 13-BYTE Request header | ++------------------------------------+ +| BYTE Media descriptor from BPB | ++------------------------------------+ +| BYTE Returned | ++------------------------------------+ +| Returned DWORD pointer to previous | +| Volume ID if bit 11 set and | +| Disk Changed is returned | ++------------------------------------+ + +The Media Check function is used only with block devices. It is called +when there is a pending drive-access call other than a file read or write, +such as Open, Close, delete, and rename. Its purpose is to determine +whether the media in the drive has been changed. If the driver can assure +that the media has not been changed (through a door-lock or other inter- +lock mechanism), MS-DOS performance is enhanced, because MS-DOS +does not need to reread the FAT and invalidate in-memory buffers for each +directory access. + + + 17 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +When a disk-access call to the DOS occurs (other than a file read or write), +the following sequence of events takes place: + + 1. The DOS converts the drive letter into a unit number of a particu- + lar block device. + + 2. The device driver is then called to request a media check on that + subunit to see if the disk might have been changed. MS-DOS + passes the old media descriptor byte. The driver returns one of the + following: + + + Return + Meaning + _ _________________________________________________________ + + (1) Media not changed + + (0) Don't know if changed + + (-1) Media changed + + value Error (value is a standard error code value) + + If the media has not been changed, MS-DOS proceeds with the disk + access. + + If the value returned is -1, then if there are any disk sectors that + have been modified and not written back out to the disk for this + unit, MS-DOS assumes that the disk has not been changed and + proceeds. MS-DOS invalidates any other buffers for the unit and + does a Build BPB call (see Step 3, following). + + If the media has been changed, MS-DOS invalidates all buffers + associated with this unit including buffers with modified data that + are waiting to be written, and requests a new BIOS Parameter + Block via the Build BPB call (see Step 3). + + 3. Once the BPB has been returned, MS-DOS corrects its internal + structure for the drive from the new BPB and proceeds with the + access after reading the directory and the FAT. + +Note that the previous media ID byte is passed to the device driver. If the +old media ID byte is the same as the new one, the disk might have been +changed and a new disk may be in the drive; therefore, all FAT, directory, +and data sectors that are buffered in memory for the drive are considered +invalid. + +If the driver has bit 11 of the device attribute word set to 1, and the driver +returns -1 (Media Changed) the driver must set the DWORD pointer to +the previous Volume ID field. If the DOS determines that "Media changed" +is an error based on the state of the DOS buffer cache, the DOS will gen- +erate a 0FH error on behalf of the device. If the driver does not implement +volume ID support, but has bit 11 set, (it should set a static pointer to the +string "NO NAME" ,0.) + + + +18 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +It is not possible for a user to change a disk in less than two seconds. So +when Media Check occurs within two seconds of a disk access, the driver +reports "Media not changed (1)." This improves performance tremen- +dously. + +_ ________________________________________________________________ + +Note + + If the media ID byte in the returned BPB is the same as the previous + media ID byte, MS-DOS will assume that the format of the disk is the + same (even though the disk may have been changed) and will skip the + step of updating its internal structure. Therefore, all BPBs must have + unique media bytes regardless of FAT ID bytes. + +_ ________________________________________________________________ + + +2.7.3 The Build BPB Function + +Command code = 2 + +BUILD BPB - ES:BX -> ++------------------------------------+ +| 13-BYTE Request header | ++------------------------------------+ +| BYTE Media descriptor from BPB | ++------------------------------------+ +| DWORD Transfer address | +| (Points to one sector worth of | +| scratch space or first sector | +| of FAT depending on the value | +| of Bit 13 in the device attribute | +| word.) | ++------------------------------------+ +| DWORD Pointer to BPB | ++------------------------------------+ + +The Build BPB function is used with block devices only. As described in +the Media Check function, the Build BPB function will be called any +time that a preceding Media Check call indicates that the disk has been +or might have been changed. The device driver must return a pointer to a +BPB. This is different from the Init call where the device driver returns a +pointer to an array of word offsets to BPBs. + +The Build BPB call gets a DWORD pointer to a one-sector buffer. The +contents of this buffer are determined by the non-FAT ID bit (bit 13) in +the attribute field. If the bit is zero, then the buffer contains the first sec- +tor of the first FAT. The FAT ID byte is the first byte of this buffer. In +this case, the driver must not alter this buffer. Note that the location of +the FAT must be the same for all possible media because this first FAT +sector must be read before the actual BPB is returned. If the non-FAT ID + + 19 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +bit is set, the pointer points to one sector of scratch space (which may be +used for anything). For information on how to construct the BPB, see Sec- +tion 2.8, "The Media Descriptor Byte," and Section 2.9, "Format of a +Media Descriptor Table." + +MS-DOS 3.x includes additional support for devices that have door-locks +or some other means of telling when a disk has been changed. There is a +new error that can be returned from the device driver (error 15). The +error means "the disk has been changed when it shouldn't have been," and +the user is prompted for the correct disk using a volume ID. The driver +may generate this error on read or write. The DOS may generate the error +on Media Check calls if the driver reports media changed, and there are +buffers in the DOS buffer cache that need to be flushed to the previous +disk. + +For drivers that support this error, the Build BPB function is a trigger +that causes a new volume ID to be read off the disk. This action indicates +that the disk has been legally changed. A volume ID is placed on a disk by +the format command, and is simply an entry in the root directory of the +disk that has the Volume ID attribute. It is stored by the driver as an +ASCIZ string. + +The requirement that the driver return a volume ID does not exclude some +other volume identifier scheme as long as the scheme uses ASCIZ strings. A +NUL (nonexistent or unsupported) volume ID is by convention the follow- +ing string: + +DB "NO NAME ",0 + + +2.7.4 The Read or Write Function + +Command codes = 3,4,8,9,12, and 16 + +READ OR WRITE (Including IOCtl) or + OUTPUT UNTIL BUSY - ES:BX -> ++------------------------------------+ +| 13-BYTE Request header | ++------------------------------------+ +| BYTE Media descriptor from BPB | ++------------------------------------+ +| DWORD Transfer address | ++------------------------------------+ +| WORD Byte/sector count | ++------------------------------------+ +| WORD Starting sector number | +| (Ignored on character devices) | ++------------------------------------+ +| Returned DWORD pointer to requested| +| Volume ID if error 0FH | ++------------------------------------+ + + +20 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +Command +code + Request +_ ________________________________________________________________ + +3 IOCtl read + +4 Read (block or character device) + +8 Write (block or character device) + +9 Write with Verify + +12 IOCtl Write + +16 Output Until Busy (character device only) + +The driver must perform the Read or Write call depending on which +command code is set. Block devices read or write sectors; character devices +read or write bytes. + +When I/O completes, the device driver must set the status word and +report the number of sectors or bytes successfully transferred. This should +be done even if an error prevented the transfer from being completed. Set- +ting the error bit and error code alone is not sufficient. + +In addition to setting the status word, the driver must set the sector count +to the actual number of sectors (or bytes) transferred. No error check is +performed on an IOCtl I/O call. The device driver must always set the +return byte/sector count to the actual number of bytes/sectors success- +fully transferred. + +If the verify switch is on, the device driver will be called with command +code 9 (Write with Verify). Your device driver will be responsible for +verifying the write. + +If the driver returns error code 0FH (Invalid disk change), it must return a +DWORD pointer to an ASCIZ string (which is the correct volume ID). +Returning this error code triggers the DOS to prompt the user to re-insert +the disk. The device driver should have read the volume ID as a result of +the Build BPB function. + +Drivers may maintain a reference count of open files on the disk by moni- +toring the Open and Close functions. This allows the driver to determine +when to return error 0FH. If there are no open files (reference count = 0), +and the disk has been changed, the I/O is okay. If there are open files, +however, an 0FH error may exist. + +The Output Until Busy call is a speed optimization on character devices +only for print spoolers. The device driver is expected to output all the +characters possible until the device returns busy. Under no circumstances +should the device driver block during this function. Note that it is not an +error for the device driver to return the number of bytes output as being +less than the number of bytes requested (or = 0). + + 21 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The Output Until Busy call allows spooler programs to take advantage +of the "burst" behavior of most printers. Many printers have on-board +RAM buffers that typically hold a line or a fixed amount of characters. +These buffers fill up without the printer going busy, or going busy for a +short period (less than ten instructions) between characters. A line of +characters can be quickly output to the printer, after which the printer is +busy for a long time while the characters are being printed. This new dev- +ice call allows background spooling programs to use this burst behavior +efficiently. Rather than take the overhead of a device driver call for each +character, or risk getting stuck in the device driver outputting a block of +characters, this call allows a burst of characters to be output without the +device driver having to wait for the device to be ready. + +The Following Applies to Block Device Drivers: + +Under certain circumstances, the BIOS may be asked to perform a write +operation of 64K bytes, which seems to be a "wrap-around" of the transfer +address in the BIOS I/O packet. This request, which arises due to an +optimization added to the write code in MS-DOS, will manifest itself only +on user writes that are within a sector size of 64K bytes on files "growing" +past the current end-of-file (EOF) mark. It is allowable for the BIOS to +ignore the balance of the write that "wraps around" if it so chooses. For +example, a write of 10000H bytes worth of sectors with a transfer address +of xxx:1 could ignore the last two bytes. A user program can never request +an I/O of more than FFFFH bytes and cannot wrap around (even to 0) in +the transfer segment. Therefore, in this case, the last two bytes can be +ignored. + +MS-DOS maintains two FATs. If the DOS has problems reading the first, +it automatically tries the second before reporting the error. The BIOS is +responsible for all retries. + +Although the command.com handler does no automatic retries, there are +applications that have their own Interrupt 24H handlers that do +automatic retries on certain types of Interrupt 24H errors before reporting +them. + +2.7.5 The Non-destructive Read, No Wait Function + +Command code = 5 + +NON-DESTRUCTIVE READ NO WAIT - ES:BX -> ++------------------------------------+ +| 13-BYTE Request header | ++------------------------------------+ +| BYTE Read from device | ++------------------------------------+ + +The Non-destructive Read, No Wait function allows MS-DOS to look + +22 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +ahead one input character. The device sets the done bit in the status +word. + +If the character device returns busy bit = 0 (there are characters in the +buffer), then the next character that would be read is returned. This char- +acter is not removed from the input buffer (hence the term "Non- +destructive Read"). If the character device returns busy bit = 1, there are +no characters in the buffer. + +2.7.6 The Open or Close Function + +Command codes = 13 and 14 + +OPEN or CLOSE - ES:BX -> ++------------------------------------+ +| 13-BYTE Static request header | ++------------------------------------+ + +The Open and Close functions are called by MS-DOS 3.x only if the dev- +ice driver sets the Open/Close/Removable Media attribute bit in the +device header. They are designed to inform the device about current file +activity on the device. On block devices, they can be used to manage local +buffering. The device can keep a reference count. Every Open causes the +device to increment the count, every Close to decrement. When the count +goes to zero, it means there are no open files on the device, and the device +should flush any buffers that have been written to that may have been +used inside the device, because it is now "legal" for the user to change the +media on a removable media drive. + +There are problems with this mechanism on block devices because pro- +grams that use FCB calls can open files without closing them. It is there- +fore advisable to reset the count to zero without flushing the buffers when +the answer to "Has the media been changed?" is yes, and the Build BPB +call is made to the device. + +These calls are more useful on character devices. The Open call, for +instance, can be used to send a device initialization string. On a printer, +this could cause a string for setting font and page size characteristics to be +sent to the printer so that it would always be in a known state at the start +of an I/O stream. Using IOCtl to set these pre- and post- strings provides +a flexible mechanism of serial I/O device stream control. The reference +count mechanism can also be used to detect a simultaneous access error. It +may be desirable to disallow more than one Open on a device at any given +time. In this case, a second Open would result in an error. + +Note that since all processes have access to stdin, stdout, stderr, stdaux, +and stdprn (handles 0,1,2,3,4), the CON, AUX, and PRN devices are +always open. + + + 23 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +2.7.7 The Removable Media Function + +Command code = 15 + +REMOVABLE MEDIA - ES:BX -> ++------------------------------------+ +| 13-BYTE Static request header | ++------------------------------------+ + +The Removable Media function is called by MS-DOS 3.x only if the dev- +ice driver sets the Open/Close/Removable Media attribute bit in the +device header. This call is given only to block devices by a subfunction of +the IOCtl system call. It is sometimes desirable for a utility to know +whether it is dealing with a nonremovable media drive (such as a hard +disk), or a removable media drive (like a floppy). An example is the +format command, which prints different versions of some of the prompts. + +The information is returned in the busy bit of the status word. If the busy +bit is 1, then the media is nonremovable. If the busy bit is 0, then the +media is removable. Note that the error bit is not checked. It is assumed +that this call always succeeds. + +2.7.8 The Status Function + +Command codes = 6 and 10 + +STATUS Calls ES:BX -> ++------------------------------------+ +| 13-BYTE Request header | ++------------------------------------+ + +The Status function returns information to the DOS as to whether data is +waiting for input or output. All the driver must do is set the status word +and the busy bit as follows: + + o For output on character devices \(em if the driver sets bit 9 to 1 on + return, it informs the DOS that a write request (if made) would + wait for completion of a current request. If it is 0, there is no + current request, and a write request (if made) would start immedi- + ately. + + o For input on character devices with a buffer \(em A return of 1 implies + that no characters are buffered and that a read request (if made) + would go to the physical device. If it is 0 on return, then there are + characters in the device buffer and a read would not be blocked. A + return of 0 implies that the user has typed something. MS-DOS + assumes that all character devices have an input type-ahead buffer. + +Devices that do not have a type-ahead buffer should always return busy = +0 so that the DOS will not "hang" waiting for something to get into a + +24 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +non-existent buffer. + +2.7.9 The Flush Function + +Command codes = 7 and 11 + +FLUSH Calls - ES:BX -> ++------------------------------------+ +| 13-BYTE Request header | ++------------------------------------+ + +The Flush function tells the driver to flush (terminate) all pending +requests. This call is used to flush the input queue on character devices. + +The device driver performs the flush function, sets the status word, and +returns. + +2.7.10 The Generic IOCtl Function + +Command code = 19 + +ES:BX -> ++------------------------------------+ +| 13-BYTE Static request header | ++------------------------------------+ +| BYTE Category (Major) code | ++------------------------------------+ +| BYTE Function (Minor) code | ++------------------------------------+ +| WORD (SI) Contents | ++------------------------------------+ +| WORD (DI) Contents | ++------------------------------------+ +| DWORD Pointer to data buffer | ++------------------------------------+ + +The Generic IOCtl function provides a generic, expandable IOCtl facility +that replaces and makes the Read IOCtl and Write IOCtl device driver +functions obsolete. The MS-DOS 2.0 IOCtl functions remain to support +existing uses of the IOCtl system call (Subfunctions 2, 3, 4, and 5), but +new device drivers should use this generic MS-DOS IOCtl facility. + +The Generic IOCtl function contains both a category and function code. +The DOS examines the category field in order to intercept and obey device +commands that are actually serviced by the DOS code; all other command +categories are forwarded to the device driver for servicing. + + + + 25 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +For more information on these category and function codes, refer to Func- +tion 440CH (Generic IOCtl for Handles) and Function 440DH (Generic +IOCtl for Block Devices) in Chapter 1, "System Calls." + +2.7.11 The Get/Set Logical Drive Map Function + +Command codes = 23 (Get) or 24 (Set) + + +----------------------------------------+ + | 13-BYTE Static request header | + +----------------------------------------+ + | BYTE Input (unit code) | + +----------------------------------------+ + | BYTE Output (last device referenced)| + +----------------------------------------+ + | BYTE Command code | + +----------------------------------------+ + | WORD Status | + +----------------------------------------+ + | DWORD Reserved | + +----------------------------------------+ + +The Get/Set Logical Drive Map function is called by MS-DOS only if +the device driver sets the DOS 3.2 attribute bit in the device header. The +call is issued only to block devices by the subfunction of the IOCtl system +call. The logical drive to be mapped is passed in the Unit field of the +header to the device driver. The device driver returns the current logical +drive owner of the physical device that maps to the requested physical +drive. To detect whether a logical device currently owns the physical dev- +ice to which it is mapped, a program needs to verify that, after a call of +Function 440EH or 440FH (Get/Set Logical Drive Map), the value of +the Unit field is unchanged. + +2.8 The Media Descriptor Byte + +In MS-DOS, the media descriptor byte is used to inform the DOS that a +different type of media is present. The media descriptor byte can be any +value between 0 and FFH. It does not have to be the same as the FAT ID +byte. The FAT ID byte, which is the first byte of the FAT, was used in +MS-DOS 1.00 to distinguish between different types of disk media, and +may be used as well under 2.x and 3.x disk device drivers. However, FAT +ID bytes have significance only for block device drivers where the +non-FAT ID bit is not set (0). + + + +26 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +Values of the media descriptor byte or the FAT ID byte have no +significance to MS-DOS. They are passed to the device driver so that pro- +grams can determine the media type. + +2.9 Format of a Media Descriptor Table + +The MS-DOS file system uses a linked list of pointers (one for each cluster +or allocation unit) called the File Allocation Table (FAT). Unused clusters +are represented by zero and end-of-file by FFFH (or FFFFH on units with +16-bit FAT entries). No valid entry should ever point to a zero entry, but +if one does, the first FAT entry (which would be pointed to by a zero +entry) was reserved and set to end of chain. Eventually, several end of +chain values were defined ([F]FF8-[F]FFFH), and these were used to dis- +tinguish different types of media. + +A preferable technique is to write a complete media descriptor table in the +boot sector and use it for media identification. To ensure backward com- +patibility for systems whose drivers do not set the non-FAT ID bit +(including the IBM PC implementation), it is necessary also to write the +FAT ID bytes during the format process. + +To allow more flexibility for supporting many different disk formats in the +future, it is recommended that the information relating to the BPB for a +particular piece of media be kept in the boot sector. Figure 2.3 shows the +format of such a boot sector. + + +------------------------------------+ + | 3 BYTE Near JUMP to boot code | + +------------------------------------+ + | 8 BYTES OEM name and version | + ---+------------------------------------+--- + B | WORD Bytes per sector | + P +------------------------------------+ + B | BYTE Sectors per allocation unit | + +------------------------------------+ + | | WORD Reserved sectors | + V +------------------------------------+ + | BYTE Number of FATs | + +------------------------------------+ + | WORD Number of root dir entries | + +------------------------------------+ + | WORD Number of sectors in logical | + ^ | image | + | +------------------------------------+ + B | BYTE Media descriptor | + P +------------------------------------+ + B | WORD Number of FAT sectors | + ---+------------------------------------+--- + | WORD Sectors per track | + + 27 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +------------------------------------+ + | WORD Number of heads | + +------------------------------------+ + | WORD Number of hidden sectors | + +------------------------------------+ + | WORD High order number of hidden | + | sectors | + +------------------------------------+ + | DWORD Number of logical sectors | + +------------------------------------+ + + + Figure 2.5 Format of a Boot Sector + +Although MS-DOS does not use the five fields that follow the BPB, these +fields may be used by a device driver to help it understand the media. + +The "Sectors per track" and "Number of heads" fields are useful for sup- +porting different media which may have the same logical layout , but a +different physical layout (for example, 40-track, double-sided versus 80- +track, single-sided). "Sectors per track" tells the device driver how the log- +ical disk format is laid out on the physical disk. + +The "Number of hidden sectors" and "High order number of hidden sec- +tors" fields may be used to support drive-partitioning schemes. + +The "Number of logical sectors" field is not currently used, but will tell +the device driver how many sectors to reserve if the "Number of sectors in +logical image" field is zero. (Note that this is intended for supporting dev- +ices that access more than 32 megabytes.) + +The following procedure is recommended for media determination by NON +FAT ID format drivers: + + 1. Read the boot sector of the drive into the one-sector scratch space + pointed to by the DWORD transfer address. + + 2. Determine if the first byte of the boot sector is an E9H or EBIT + (the first byte of a 3-byte NEAR or 2-byte SHORT jump) or an + EBH (the first byte of a 2-byte jump followed by an NOP). If so, a + BPB is located beginning at offset 3. Return a pointer to it. + + 3. If the boot sector does not have a BPB table, it is probably a disk + formatted under a 1.x version of MS-DOS and probably uses a FAT + ID byte for determining media. + + The driver may optionally attempt to read the first sector of the + FAT into the one-sector scratch area and read the first byte to + determine media type based upon whatever FAT ID bytes may + have been used on disks that are expected to be read by this sys- + tem. Return a pointer to a hard-coded BPB. + + + +28 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + +2.10 The CLOCK Device + +MS-DOS assumes that some sort of clock is available in the system. This +may either be a CMOS real-time clock or an interval timer that is initial- +ized at boot time by the user. The CLOCK device defines and performs +functions like any other character device, except that it is identified by a +bit in the attribute word. The DOS uses this bit to identify it; conse- +quently, the CLOCK device may take any name. The IBM implementation +uses the name $CLOCK so as not to conflict with existing files named +clock. + +The CLOCK device is unique in that MS-DOS will read or write a 6-byte +sequence that encodes the date and time. A write to this device will set +the date and time; a read will get the date and time. + +Figure 2.6 illustrates the binary time format used by the CLOCK device: + + byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 ++--------+--------+---------+--------+--------+---------+ +| | | | | | | +|days since 1-1-80| minutes | hours | sec/100| seconds | +|low byte|hi byte | | | | | ++--------+--------+---------+--------+--------+---------+ + + + Figure 2.6 Format of a Clock Device + + +2.11 Anatomy of a Device Call + +The following steps illustrate what happens when MS-DOS calls on a block +device driver to perform a Write request: + + 1. MS-DOS writes a request packet in a reserved area of memory. + + 2. MS-DOS calls the strategy entry point of the block device driver. + + 3. The device driver saves the ES and BX registers (ES:BX points to + the request packet) and does a FAR return. + + 4. MS-DOS calls the interrupt entry point. + + 5. The device driver retrieves the pointer to the request packet and + reads the command code (offset 2) to determine that this is a + Write request. The device driver converts the command code to + an index into a dispatch table and control passes to the Write rou- + tine. + + + + 29 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + 6. The device driver reads the unit code (offset 1) to determine which + disk drive it is supposed to write to. + + 7. Since the command is a disk Write, the device driver must get the + transfer address (offset 14), the sector count (offset 18), and the + start sector (offset 20) in the request packet. + + 8. The device driver translates the first logical sector number into a + track, head, and sector number. + + 9. The device driver writes the specified number of sectors, starting at + the beginning sector on the drive defined by the unit code (the + subunit defined by this device driver), and transfers data from the + transfer address indicated in the request packet. Note that this + may involve multiple Write commands to the disk controller. + + 10. After the transfer is complete, the device driver must report the + status of the request to MS-DOS by setting the done bit in the + status word (offset 3 in the request packet). It reports the number + of sectors actually transferred in the sector count area of the + request packet. + + 11. If an error occurs, the driver sets the done bit and the error bit in + the status word and fills in the error code in the lower half of the + status word. The number of sectors actually transferred must be + written in the request header. It is not sufficient just to set the + error bit of the status word. + + 12. The device driver does a FAR return to MS-DOS. + +The device drivers should preserve the state of MS-DOS. This means that +all registers (including flags) should be preserved. The direction flag and +interrupt enable bits are critical. When the interrupt entry point in the +device driver is called, MS-DOS has room for about 40 to 50 bytes on its +internal stack. Your device driver should switch to a local stack if it uses +extensive stack operations. + +2.12 Two Sample Device Drivers + +The following two examples illustrate a block device driver and a charac- +ter device driver program. These examples are provided as guides for writ- +ing your own device drivers. However, since device drivers are hardware- +dependent, your device drivers will differ. + + +30 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + +Block Device Driver + + +;********************* A Block Device ******************* + + Title 5.25-inch Disk Driver + +;This driver is intended to drive up to four 5.25-inch +;drives hooked to a single disk controller. All standard +;IBM PC formats are supported. + + +FALSE EQU 0 +TRUE EQU NOT FALSE + +;The I/O port address of the disk controller +DISK EQU 0E0H +;DISK+0 +; 1793 Command/Status +;DISK+1 +; 1793 Track +;DISK+2 +; 1793 Sector +;DISK+3 +; 1793 Data +;DISK+4 +; Aux Command/Status +;DISK+5 +; Wait Sync + +;Back side select bit +BACKBIT EQU 04H +;5 1/4" select bit +SMALBIT EQU 10H +;Double Density bit +DDBIT EQU 08H + +;Done bit in status register +DONEBIT EQU 01H + +;Use table below to select head step speed. +;Step times for 5" drives +;are double that shown in the table. +; +;Step value 1771 1793 +; +; 0 6ms 3ms +; 1 6ms 6ms +; 2 10ms 10ms +; 3 20ms 15ms +; +STPSPD EQU 1 + +NUMERR EQU ERROUT-ERRIN + +CR EQU 0DH +LF EQU 0AH + + 31 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +CODE SEGMENT +ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING +;----------------------------------------------------- +; +; Device Header +; +DRVDEV LABEL WORD + DW -1,-1 + DW 0000 ;IBM format-compatible, Block + DW STRATEGY + DW DRV$IN +DRVMAX DB 4 + +DRVTBL LABEL WORD + DW DRV$INIT + DW MEDIA$CHK + DW GET$BPB + DW CMDERR + DW DRV$READ + DW EXIT + DW EXIT + DW EXIT + DW DRV$WRIT + DW DRV$WRIT + DW EXIT + DW EXIT + DW EXIT + +;------------------------------------ +; +; Strategy + +PTRSAV DD 0 + +STRATP PROC FAR +STRATEGY: + MOV WORD PTR [PTRSAV],BX + MOV WORD PTR [PTRSAV+2],ES + RET +STRATP ENDP + +;-------------------------------------- +; +; Main Entry + + +CMDLEN = 0 ;Length of this command +UNIT = 1 ;Subunit specified +CMDC = 2 ;Command Code +STATUS = 3 ;Status +MEDIA = 13 ;Media Descriptor +TRANS = 14 ;Transfer Address +COUNT = 18 ;Count of blocks or characters +START = 20 ;First block to transfer + +DRV$IN: + +32 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + PUSH SI + PUSH AX + PUSH CX + PUSH DX + PUSH DI + PUSH BP + PUSH DS + PUSH ES + PUSH BX + + LDS BX,[PTRSAV] ;Get pointer to I/O packet + + MOV AL,BYTE PTR [BX].UNIT ;AL = Unit Code + MOV AH,BYTE PTR [BX].MEDIA ;AH = Media Descrip + MOV CX,WORD PTR [BX].COUNT ;CX = Count + MOV DX,WORD PTR [BX].START ;DX = Start Sector + PUSH AX + MOV AL,BYTE PTR [BX].CMDC ;Command code + CMP AL,15 + JA CMDERRP ;Bad command + CBW + SHL AX,1 ;2 times command = + ;word table index + MOV SI,OFFSET DRVTBL + ADD SI,AX ;Index into table + POP AX ;Get back media + ;and unit + + LES DI,DWORD PTR [BX].TRANS ;ES:DI = Transfer + ;Address + + PUSH CS + POP DS + +ASSUME DS:CODE + + JMP WORD PTR [SI] ;GO DO COMMAND + +;---------------------------------------------------------- +; +; EXIT - All Routines return through this path +; +ASSUME DS:NOTHING +CMDERRP: + POP AX ;Clean stack +CMDERR: + MOV AL,3 ;Unknown command error + JMP SHORT ERR$EXIT + +ERR$CNT:LDS BX,[PTRSAV] + SUB WORD PTR [BX].COUNT,CX ;# OF SUCCESS. I/Os + +ERR$EXIT: +;AL has error code + MOV AH,10000001B ;Mark error return + JMP SHORT ERR1 + + 33 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +EXITP PROC FAR + +EXIT: MOV AH,00000001B +ERR1: LDS BX,[PTRSAV] + MOV WORD PTR [BX].STATUS,AX + ;Mark Operation +CompleteE + + POP BX + POP ES + POP DS + POP BP + POP DI + POP DX + POP CX + POP AX + POP SI + RET ;Restore REGS and return +EXITP ENDP + +CURDRV DB -1 + +TRKTAB DB -1,-1,-1,-1 + +SECCNT DW 0 + +DRVLIM = 8 ;Number of sectors on device +SECLIM = 13 ;Maximum Sector +HDLIM = 15 ;Maximum Head + +;WARNING - preserve order of drive and curhd! + +DRIVE DB 0 ;Physical Drive Code +CURHD DB 0 ;Current Head +CURSEC DB 0 ;Current Sector +CURTRK DW 0 ;Current Track + + +; +MEDIA$CHK: ;Always indicates Don't know +ASSUME DS:CODE + TEST AH,00000100B ;Test if Media Removable + JZ MEDIA$EXT + XOR DI,DI ;Say I Don't know +MEDIA$EXT: + LDS BX,[PTRSAV] + MOV WORD PTR [BX].TRANS,DI + JMP EXIT + +BUILD$BPB: +ASSUME DS:CODE + MOV AH,BYTE PTR ES:[DI] ;Get FAT ID Byte + CALL BUILDBP ;Translate +SETBPB: LDS BX,[PTRSAV] + MOV [BX].MEDIA,AH + MOV [BX].COUNT,DI + +34 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + MOV [BX].COUNT+2,CS + JMP EXIT + +BUILDBP: +ASSUME DS:NOTHING +;AH is media byte on entry +;DI points to correct BPB on return + PUSH AX + PUSH CX + PUSH DX + PUSH BX + MOV CL,AH ;Save Media + AND CL,0F8H ;Normalize + CMP CL,0F8H ;Compare with Good Media Byte + JZ GOODID + MOV AH,0FEH ;Default to 8-sector, + ;Single-sided +GOODID: + MOV AL,1 ;Set number of FAT sectors + MOV BX,64*256+8 ;Set Dir Entries and Sector Max + MOV CX,40*8 ;Set Size of Drive + MOV DX,01*256+1 ;Set Head Limit & Sec/All Unit + MOV DI,OFFSET DRVBPB + TEST AH,00000010B ;Test for 8 OR 9 Sectors + JNZ HAS8 ;NZ = has 8 sectors + INC AL ;Inc Number of FAT sectors + INC BL ;Inc Sector Max + ADD CX,40 ;Increase Size +HAS8: TEST AH,00000001B ;Test for 1 or 2 Heads + JZ HAS1 ;Z = 1 Head + ADD CX,CX ;Double Size of Disk + MOV BH,112 ;Increase # of Dir Entries + INC DH ;Inc Sec/All Unit + INC DL ;Inc Head Limit +HAS1: MOV BYTE PTR [DI].2,DH + MOV BYTE PTR [DI].6,BH + MOV WORD PTR [DI].8,CX + MOV BYTE PTR [DI].10,AH + MOV BYTE PTR [DI].11,AL + MOV BYTE PTR [DI].13,BL + MOV BYTE PTR [DI].15,DL + POP BX + POP DX + POP CX + POP AX + RET + + +;---------------------------------------------------------- +; +; Disk I/O Handlers +; +;ENTRY: +; AL = Drive Number (0-3) +; AH = Media Descriptor +; CX = Sector Count + + 35 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +; DX = First Sector +; DS = CS +; ES:DI = Transfer Address +;EXIT: +; IF Successful Carry Flag = 0 +; ELSE CF=1 AND AL contains (MS-DOS) Error Code, + CX # sectors NOT transferred + +DRV$READ: +ASSUME DS:CODE + JCXZ DSKOK + CALL SETUP + JC DSK$IO + CALL DISKRD + JMP SHORT DSK$IO + +DRV$WRIT: +ASSUME DS:CODE + JCXZ DSKOK + CALL SETUP + JC DSK$IO + CALL DISKWRT +ASSUME DS:NOTHING +DSK$IO: JNC DSKOK + JMP ERR$CNT +DSKOK: JMP EXIT + + +SETUP: +ASSUME DS:CODE +;Input same as above +;On output +; ES:DI = Trans addr +; DS:BX Points to BPB +; Carry set if error (AL is error code (MS-DOS)) +; else +; [DRIVE] = Drive number (0-3) +; [SECCNT] = Sectors to transfer +; [CURSEC] = Sector number of start of I/O +; [CURHD] = Head number of start of I/O ;Set +; [CURTRK] = Track # of start of I/O ;Seek performed +; All other registers destroyed + + XCHG BX,DI ;ES:BX = Transfer Address + CALL BUILDBP ;DS:DI = PTR to B.P.B + MOV SI,CX + ADD SI,DX + CMP SI,WORD PTR [DI].DRVLIM + ;Compare Against Drive Max + JBE INRANGE + MOV AL,8 + STC + RET + +INRANGE: + MOV [DRIVE],AL + +36 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + MOV [SECCNT],CX ;Save Sector Count + XCHG AX,DX ;Set Up Logical Sector + ;For Divide + XOR DX,DX + DIV WORD PTR [DI].SECLIM ;Divide by Sec per Track + INC DL + MOV [CURSEC],DL ;Save Current Sector + MOV CX,WORD PTR [DI].HDLIM ;Get Number of Heads + XOR DX,DX ;Divide Tracks by Heads per Cylinder + DIV CX + MOV [CURHD],DL ;Save Current Head + MOV [CURTRK],AX ;Save Current Track +SEEK: + PUSH BX ;Xaddr + PUSH DI ;BPB pointer + CALL CHKNEW ;Unload head if change drives + CALL DRIVESEL + MOV BL,[DRIVE] + XOR BH,BH ;BX drive index + ADD BX,OFFSET TRKTAB ;Get current track + MOV AX,[CURTRK] + MOV DL,AL ;Save desired track + XCHG AL,DS:[BX] ;Make desired track current + OUT DISK+1,AL ;Tell Controller current track + CMP AL,DL ;At correct track? + JZ SEEKRET ;Done if yes + MOV BH,2 ;Seek retry count + CMP AL,-1 ;Position Known? + JNZ NOHOME ;If not home head +TRYSK: + CALL HOME + JC SEEKERR +NOHOME: + MOV AL,DL + OUT DISK+3,AL ;Desired track + MOV AL,1CH+STPSPD ;Seek + CALL DCOM + AND AL,98H ;Accept not rdy, seek, & CRC errors + JZ SEEKRET + JS SEEKERR ;No retries if not ready + DEC BH + JNZ TRYSK +SEEKERR: + MOV BL,[DRIVE] + XOR BH,BH ;BX drive index + ADD BX,OFFSET TRKTAB ;Get current track + MOV BYTE PTR DS:[BX],-1 ;Make current track + ;unknown + CALL GETERRCD + MOV CX,[SECCNT] ;Nothing transferred + POP BX ;BPB pointer + POP DI ;Xaddr + RET + +SEEKRET: + POP BX ;BPB pointer + + 37 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + POP DI ;Xaddr + CLC + RET + +;--------------------------------------------- +; +; Read +; + +DISKRD: +ASSUME DS:CODE + MOV CX,[SECCNT] +RDLP: + CALL PRESET + PUSH BX + MOV BL,10 ;Retry count + MOV DX,DISK+3 ;Data port +RDAGN: + MOV AL,80H ;Read command + CLI ;Disable for 1793 + OUT DISK,AL ;Output read command + MOV BP,DI ;Save address for retry + JMP SHORT RLOOPENTRY +RLOOP: + STOSB +RLOOPENTRY: + IN AL,DISK+5 ;Wait for DRQ or INTRQ + SHR AL,1 + IN AL,DX ;Read data + JNC RLOOP + STI ;Ints OK now + CALL GETSTAT + AND AL,9CH + JZ RDPOP ;Ok + MOV DI,BP ;Get back transfer + DEC BL + JNZ RDAGN + CMP AL,10H ;Record not found? + JNZ GOT_CODE ;No + MOV AL,1 ;Map it +GOT_CODE: + CALL GETERRCD + POP BX + RET + +RDPOP: + POP BX + LOOP RDLP + CLC + RET + + +;--------------------------------------------- +; +; Write +; + +38 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +DISKWRT: +ASSUME DS:CODE + MOV CX,[SECCNT] + MOV SI,DI + PUSH ES + POP DS +ASSUME DS:NOTHING +WRLP: + CALL PRESET + PUSH BX + MOV BL,10 ;Retry count + MOV DX,DISK+3 ;Data port +WRAGN: + MOV AL,0A0H ;Write command + CLI ;Disable for 1793 + OUT DISK,AL ;Output write command + MOV BP,SI ;Save address for retry +WRLOOP: + IN AL,DISK+5 + SHR AL,1 + LODSB ;Get data + OUT DX,AL ;Write data + JNC WRLOOP + STI ;Ints OK now + DEC SI + CALL GETSTAT + AND AL,0FCH + JZ WRPOP ;Ok + MOV SI,BP ;Get back transfer + DEC BL + JNZ WRAGN + CALL GETERRCD + POP BX + RET + +WRPOP: + POP BX + LOOP WRLP + CLC + RET + + +PRESET: +ASSUME DS:NOTHING + MOV AL,[CURSEC] + CMP AL,CS:[BX].SECLIM + JBE GOTSEC + MOV DH,[CURHD] + INC DH + CMP DH,CS:[BX].HDLIM + JB SETHEAD ;Select new head + CALL STEP ;Go on to next track + XOR DH,DH ;Select head zero +SETHEAD: + MOV [CURHD],DH + CALL DRIVESEL + + 39 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + MOV AL,1 ;First sector + MOV [CURSEC],AL ;Reset CURSEC +GOTSEC: + OUT DISK+2,AL ;Tell controller which sector + INC [CURSEC] ;We go on to next sector + RET + +STEP: +ASSUME DS:NOTHING + MOV AL,58H+STPSPD ;Step in w/ update, no verify + CALL DCOM + PUSH BX + MOV BL,[DRIVE] + XOR BH,BH ;BX drive index + ADD BX,OFFSET TRKTAB ;Get current track + INC BYTE PTR CS:[BX] ;Next track + POP BX + RET + +HOME: +ASSUME DS:NOTHING + MOV BL,3 +TRYHOM: + MOV AL,0CH+STPSPD ;Restore with verify + CALL DCOM + AND AL,98H + JZ RET3 + JS HOMERR ;No retries if not ready + PUSH AX ;Save real error code + MOV AL,58H+STPSPD ;Step in w/ update no verify + CALL DCOM + DEC BL + POP AX ;Get back real error code + JNZ TRYHOM +HOMERR: + STC +RET3: RET + + +CHKNEW: +ASSUME DS:NOTHING + MOV AL,[DRIVE] ;Get disk drive number + MOV AH,AL + XCHG AL,[CURDRV] ;Make new drive current. + CMP AL,AH ;Changing drives? + JZ RET1 ;No +; If changing drives, unload head so the head load delay +;one-shot will fire again. Do it by seeking to the same +;track with the H bit reset. +; + IN AL,DISK+1 ;Get current track number + OUT DISK+3,AL ;Make it the track to seek + MOV AL,10H ;Seek and unload head + +DCOM: +ASSUME DS:NOTHING + +40 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + OUT DISK,AL + PUSH AX + AAM ;Delay 10 microseconds + POP AX +GETSTAT: + IN AL,DISK+4 + TEST AL,DONEBIT + JZ GETSTAT + IN AL,DISK +RET1: RET + +DRIVESEL: +ASSUME DS:NOTHING +;Select the drive based on current info +;Only AL altered + MOV AL,[DRIVE] + OR AL,SMALBIT + DDBIT ;5 1/4" IBM PC disks + CMP [CURHD],0 + JZ GOTHEAD + OR AL,BACKBIT ;Select side 1 +GOTHEAD: + OUT DISK+4,AL ;Select drive and side + RET + +GETERRCD: +ASSUME DS:NOTHING + PUSH CX + PUSH ES + PUSH DI + PUSH CS + POP ES ;Make ES the local segment + MOV CS:[LSTERR],AL ;Terminate list w/ error code + MOV CX,NUMERR ;Number of error conditions + MOV DI,OFFSET ERRIN ;Point to error conditions + REPNE SCASB + MOV AL,NUMERR-1[DI] ;Get translation + STC ;Flag error condition + POP DI + POP ES + POP CX + RET ;and return + +;********************************************************* +; BPB for an IBM floppy disk, Various parameters are +; patched by BUILDBP to reflect the type of Media +; inserted +; This is a 9-sector, single-side BPB +DRVBPB: + DW 512 ;Physical sector size in bytes + DB 1 ;Sectors/allocation unit + DW 1 ;Reserved sectors for DOS + DB 2 ;# of allocation tables + DW 64 ;Number directory entries + DW 9*40 ;Number 512-byte sectors + DB 11111100B ;Media descriptor + DW 2 ;Number of FAT sectors + + 41 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + DW 9 ;Sector limit + DW 1 ;Head limit + + +INITAB DW DRVBPB ;Up to four units + DW DRVBPB + DW DRVBPB + DW DRVBPB + +ERRIN: ;DISK ERRORS RETURNED FROM THE CONTROLLER + DB 80H ;No response + DB 40H ;Write protect + DB 20H ;Write Fault + DB 10H ;SEEK error + DB 8 ;CRC error + DB 1 ;Mapped from 10H + ;(record not found) on Read +LSTERR DB 0 ;All other errors + +ERROUT: ;RETURNED ERROR CODES CORRESPONDING TO ABOVE + DB 2 ;No response + DB 0 ;Write Attempt + ;On Write-protected disk + DB 0AH ;Write fault + DB 6 ;SEEK Failure + DB 4 ;Bad CRC + DB 8 ;Sector not found + DB 12 ;General error + + +DRV$INIT: +; +; Determine number of physical drives by reading config.sys +; +ASSUME DS:CODE + PUSH DS + LDS SI,[PTRSAV] +ASSUME DS:NOTHING + LDS SI,DWORD PTR [SI.COUNT] ;DS:SI points to + ;config.sys +SCAN_LOOP: + CALL SCAN_SWITCH + MOV AL,CL + OR AL,AL + JZ SCAN4 + CMP AL,"s" + JZ SCAN4 + +WERROR: POP DS +ASSUME DS:CODE + MOV DX,OFFSET ERRMSG2 +WERROR2: MOV AH,9 + INT 21H + XOR AX,AX + PUSH AX ;No units + JMP SHORT ABORT + +42 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +BADNDRV: + POP DS + MOV DX,OFFSET ERRMSG1 + JMP WERROR2 + +SCAN4: +ASSUME DS:NOTHING +;BX is number of floppies + OR BX,BX + JZ BADNDRV ;User error + CMP BX,4 + JA BADNDRV ;User error + POP DS +ASSUME DS:CODE + PUSH BX ;Save unit count +ABORT: LDS BX,[PTRSAV] +ASSUME DS:NOTHING + POP AX + MOV BYTE PTR [BX].MEDIA,AL ;Unit count + MOV [DRVMAX],AL + MOV WORD PTR [BX].TRANS,OFFSET DRV$INIT ;SET + ;BREAK ADDRESS + MOV [BX].TRANS+2,CS + MOV WORD PTR [BX].COUNT,OFFSET INITAB + ;SET POINTER TO BPB ARRAY + MOV [BX].ceOUNT+2,CS + JMP EXIT +; +; Put switch in CL, value in BX +; +SCAN_SWITCH: + XOR BX,BX + MOV CX,BX + LODSB + CMP AL,10 + JZ NUMRET + CMP AL,"-" + JZ GOT_SWITCH + CMP AL,"/" + JNZ SCAN_SWITCH +GOT_SWITCH: + CMP BYTE PTR [SI+1],":" + JNZ TERROR + LODSB + OR AL,20H ; Convert to lowercase + MOV CL,AL ; Get switch + LODSB ; Skip ":" +; +; Get number pointed to by [SI] +; +; Wipes out AX,DX only BX returns number +; +GETNUM1:LODSB + SUB AL,"0" + JB CHKRET + CMP AL,9 + + 43 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + JA CHKRET + CBW + XCHG AX,BX + MOV DX,10 + MUL DX + ADD BX,AX + JMP GETNUM1 + +CHKRET: ADD AL,"0" + CMP AL," " + JBE NUMRET + CMP AL,"-" + JZ NUMRET + CMP AL,"/" + JZ NUMRET +TERROR: + POP DS ; Get rid of return address + JMP WERROR +NUMRET: DEC SI + RET + +ERRMSG1 DB "SMLDRV: Bad number of drives",13,10,"$" +ERRMSG2 DB "SMLDRV: Invalid parameter",13,10,"$" +CODE ENDS + END + + + +44 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + +Character Device Driver + +The following program illustrates a character device driver program. + + +;******************** A Character Device ******************* + +Title VT52 Console for 2.0 (IBM) + +;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +; IBM Addresses for I/O +; +;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + CR=13 ;Carriage-Return + BACKSP=8 ;BACKSPACE + ESC=1BH + BRKADR=6CH ;006C Break vector address + ASNMAX=200 ;Size of key assignment buffer + +CODE SEGMENT BYTE + + ASSUME CS:CODE,DS:NOTHING,ES:NOTHING +;---------------------------------------------------------- +; +; C O N - Console Device Driver +; +CONDEV: ;Header for device "CON" + DW -1,-1 + DW 1000000000010011B ;CON IN AND CON OUT + DW STRATEGY + DW ENTRY + DB 'CON ' + +;----------------------------------------------------------- +; +; Command JUMP Tables +CONTBL: + DW CON$INIT + DW EXIT + DW EXIT + DW CMDERR + DW CON$READ + DW CON$RDND + DW EXIT + DW CON$FLSH + DW CON$WRIT + DW CON$WRIT + DW EXIT + DW EXIT + +CMDTABL DB 'A' + DW CUU ;cursor up + DB 'B' + DW CUD ;cursor down + + 45 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + DB 'C' + DW CUF ;cursor forward + DB 'D' + DW CUB ;cursor back + DB 'H' + DW CUH ;cursor position + DB 'J' + DW ED ;erase display + DB 'K' + DW EL ;erase line + DB 'Y' + DW CUP ;cursor position + DB 'j' + DW PSCP ;save cursor position + DB 'k' + DW PRCP ;restore cursor position + DB 'y' + DW RM ;reset mode + DB 'x' + DW SM ;set mode + DB 00 + +PAGE +;--------------------------------------------------- +; +; Device entry point +; +CMDLEN = 0 ;Length of this command +UNIT = 1 ;Subunit Specified +CMD = 2 ;Command Code +STATUS = 3 ;Status +MEDIA = 13 ;Media Descriptor +TRANS = 14 ;Transfer Address +COUNT = 18 ;Count of blocks or characters +START = 20 ;First block to transfer + +PTRSAV DD 0 + +STRATP PROC FAR + +STRATEGY: + MOV WORD PTR CS:[PTRSAV],BX + MOV WORD PTR CS:[PTRSAV+2],ES + RET + +STRATP ENDP + +ENTRY: + PUSH SI + PUSH AX + PUSH CX + PUSH DX + PUSH DI + PUSH BP + PUSH DS + PUSH ES + +46 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + PUSH BX + + LDS BX,CS:[PTRSAV] ;GET POINTER TO I/O PACKET + + MOV CX,WORD PTR DS:[BX].COUNT ;CX = COUNT + + MOV AL,BYTE PTR DS:[BX].CMD + CBW + MOV SI,OFFSET CONTBL + ADD SI,AX + ADD SI,AX + CMP AL,11 + JA CMDERR + + LES DI,DWORD PTR DS:[BX].TRANS + + PUSH CS + POP DS + + ASSUME DS:CODE + + JMP WORD PTR [SI] ;GO DO COMMAND + +PAGE +;===================================================== +;= +;= Subroutines Shared by Multiple Devices +;= +;===================================================== +;----------------------------------------------------- +; +; EXIT - All routines return through this path +; +BUS$EXIT: ;Device Busy Exit + MOV AH,00000011B + JMP SHORT ERR1 + +CMDERR: + MOV AL,3 ;Unknown command error + +ERR$EXIT: + MOV AH,10000001B ;Mark error Return + JMP SHORT ERR1 + +EXITP PROC FAR + +EXIT: MOV AH,00000001B +ERR1: LDS BX,CS:[PTRSAV] + MOV WORD PTR [BX].STATUS,AX ;Mark + ;Operation Complete + + POP BX + POP ES + POP DS + POP BP + POP DI + + 47 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + POP DX + POP CX + POP AX + POP SI + RET ;Restore REGS and Return +EXITP ENDP +;----------------------------------------------- +; +; BREAK Key Handling +; +BREAK: + MOV CS:ALTAH,3 ;Indicate BREAK key Set +INTRET: IRET + +PAGE +; +; WARNING - Variables are very order dependent, + so be careful when adding new ones! +; +WRAP DB 0 ; 0 = WRAP, 1 = NO WRAP +STATE DW S1 +MODE DB 3 +MAXCOL DB 79 +COL DB 0 +ROW DB 0 +SAVCR DW 0 +ALTAH DB 0 ;Special key handling + +;------------------------------------------------------- +; +; CHROUT - Write out Char in AL using current attribute +; +ATTRW LABEL WORD +ATTR DB 00000111B ;Character Attribute +BPAGE DB 0 ;Base Page +base dw 0b800h + +chrout: cmp al,13 + jnz trylf + mov [col],0 + jmp short setit + +trylf: cmp al,10 + jz lf + cmp al,7 + jnz tryback +torom: + mov bx,[attrw] + and bl,7 + mov ah,14 + int 10h +ret5: ret + +tryback: + cmp al,8 + jnz outchr + +48 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + cmp [col],0 + jz ret5 + dec [col] + jmp short setit + +outchr: + mov bx,[attrw] + mov cx,1 + mov ah,9 + int 10h + inc [col] + mov al,[col] + cmp al,[maxcol] + jbe setit + cmp [wrap],0 + jz outchr1 + dec [col] + ret +outchr1: + mov [col],0 +lf: inc [row] + cmp [row],24 + jb setit + mov [row],23 + call scroll + +setit: mov dh,row + mov dl,col + xor bh,bh + mov ah,2 + int 10h + ret + +scroll: call getmod + cmp al,2 + jz myscroll + cmp al,3 + jz myscroll + mov al,10 + jmp torom +myscroll: + mov bh,[attr] + mov bl,' ' + mov bp,80 + mov ax,[base] + mov es,ax + mov ds,ax + xor di,di + mov si,160 + mov cx,23*80 + cld + cmp ax,0b800h + jz colorcard + + rep movsw + mov ax,bx + + 49 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + mov cx,bp + rep stosw +sret: push cs + pop ds + ret + +colorcard: + mov dx,3dah +wait2: in al,dx + test al,8 + jz wait2 + mov al,25h + mov dx,3d8h + out dx,al ;turn off video + rep movsw + mov ax,bx + mov cx,bp + rep stosw + mov al,29h + mov dx,3d8h + out dx,al ;turn on video + jmp sret + +GETMOD: MOV AH,15 + INT 16 ;get column information + MOV BPAGE,BH + DEC AH + MOV WORD PTR MODE,AX + RET +;------------------------------------------------------ +; +; Console Read Routine +; +CON$READ: + JCXZ CON$EXIT +CON$LOOP: + PUSH CX ;Save Count + CALL CHRIN ;Get Char in AL + POP CX + STOSB ;Store Char at ES:DI + LOOP CON$LOOP +CON$EXIT: + JMP EXIT +;--------------------------------------------------------- +; +; Input Single Char into AL +; +CHRIN: XOR AX,AX + XCHG AL,ALTAH ;Get Character & Zero ALTAH + OR AL,AL + JNZ KEYRET + +INAGN: XOR AH,AH + INT 22 +ALT10: + OR AX,AX ;Check for non-key after BREAK + +50 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + JZ INAGN + OR AL,AL ;Special case? + JNZ KEYRET + MOV ALTAH,AH ;Store special key +KEYRET: RET +;---------------------------------------------------------- +; +; Keyboard Non-descructive Read, No Wait +; +CON$RDND: + MOV AL,[ALTAH] + OR AL,AL + JNZ RDEXIT + +RD1: MOV AH,1 + INT 22 + JZ CONBUS + OR AX,AX + JNZ RDEXIT + MOV AH,0 + INT 22 + JMP CON$RDND + +RDEXIT: LDS BX,[PTRSAV] + MOV [BX].MEDIA,AL +EXVEC: JMP EXIT +CONBUS: JMP BUS$EXIT +;---------------------------------------------------------- +; +; Keyboard Flush Routine +; +CON$FLSH: + MOV [ALTAH],0 ;Clear out holding buffer + + PUSH DS + XOR BP,BP + MOV DS,BP ;Select segment 0 + MOV DS:BYTE PTR 41AH,1EH ;Reset KB queue head + ;pointer + MOV DS:BYTE PTR 41CH,1EH ;Reset tail pointer + POP DS + JMP EXVEC +;---------------------------------------------------------- +; +; Console Write Routine +; +CON$WRIT: + JCXZ EXVEC + PUSH CX + MOV AH,3 ;Set current cursor position + XOR BX,BX + INT 16 + MOV WORD PTR [COL],DX + POP CX + +CON$LP: MOV AL,ES:[DI] ;Get Char + + 51 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + INC DI + CALL OUTC ;Output Char + LOOP CON$LP ;Repeat until all through + JMP EXVEC + +COUT: STI + PUSH DS + PUSH CS + POP DS + CALL OUTC + POP DS + IRET + +OUTC: PUSH AX + PUSH CX + PUSH DX + PUSH SI + PUSH DI + PUSH ES + PUSH BP + CALL VIDEO + POP BP + POP ES + POP DI + POP SI + POP DX + POP CX + POP AX + RET + + +;---------------------------------------------------------- +; +; Output Single Char in AL to Video Device +; +VIDEO: MOV SI,OFFSET STATE + JMP [SI] + +S1: CMP AL,ESC ;Escape sequence? + JNZ S1B + MOV WORD PTR [SI],OFFSET S2 + RET + +S1B: CALL CHROUT +S1A: MOV WORD PTR [STATE],OFFSET S1 + RET + + +S2: PUSH AX + CALL GETMOD + POP AX + MOV BX,OFFSET CMDTABL-3 +S7A: ADD BX,3 + CMP BYTE PTR [BX],0 + JZ S1A + CMP BYTE PTR [BX],AL + +52 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + JNZ S7A + JMP WORD PTR [BX+1] + + +MOVCUR: CMP BYTE PTR [BX],AH + JZ SETCUR + ADD BYTE PTR [BX],AL +SETCUR: MOV DX,WORD PTR COL + XOR BX,BX + MOV AH,2 + INT 16 + JMP S1A + + +CUP: MOV WORD PTR [SI],OFFSET CUP1 + RET +CUP1: SUB AL,32 + MOV BYTE PTR [ROW],AL + MOV WORD PTR [SI],OFFSET CUP2 + RET +CUP2: SUB AL,32 + MOV BYTE PTR [COL],AL + JMP SETCUR + +SM: MOV WORD PTR [SI],OFFSET S1A + RET + + +CUH: MOV WORD PTR COL,0 + JMP SETCUR + +CUF: MOV AH,MAXCOL + MOV AL,1 +CUF1: MOV BX,OFFSET COL + JMP MOVCUR + +CUB: MOV AX,00FFH + JMP CUF1 + +CUU: MOV AX,00FFH +CUU1: MOV BX,OFFSET ROW + JMP MOVCUR + +CUD: MOV AX,23*256+1 + JMP CUU1 + +PSCP: MOV AX,WORD PTR COL + MOV SAVCR,AX + JMP SETCUR + +PRCP: MOV AX,SAVCR + MOV WORD PTR COL,AX + JMP SETCUR + +ED: CMP BYTE PTR [ROW],24 + JAE EL1 + + 53 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + MOV CX,WORD PTR COL + MOV DH,24 + JMP ERASE + +EL1: MOV BYTE PTR [COL],0 +EL: MOV CX,WORD PTR [COL] +EL2: MOV DH,CH +ERASE: MOV DL,MAXCOL + MOV BH,ATTR + MOV AX,0600H + INT 16 +ED3: JMP SETCUR + + +RM: MOV WORD PTR [SI],OFFSET RM1 + RET +RM1: XOR CX,CX + MOV CH,24 + JMP EL2 + +CON$INIT: + int 11h + and al,00110000b + cmp al,00110000b + jnz iscolor + mov [base],0b000h ;look for bw card +iscolor: + cmp al,00010000b ;look for 40 col mode + ja setbrk + mov [mode],0 + mov [maxcol],39 + +setbrk: + XOR BX,BX + MOV DS,BX + MOV BX,BRKADR + MOV WORD PTR [BX],OFFSET BREAK + MOV WORD PTR [BX+2],CS + + MOV BX,29H*4 + MOV WORD PTR [BX],OFFSET COUT + MOV WORD PTR [BX+2],CS + + LDS BX,CS:[PTRSAV] + MOV WORD PTR [BX].TRANS,OFFSET CON$INIT + ;SET BREAK ADDRESS + MOV [BX].TRANS+2,CS + JMP EXIT + +CODE ENDS + END + + + +54 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Chapter 2 + +MS-DOS Device Drivers + +_ ________________________________________________________________ + +2.1 Introduction 3 + +2.2 Format of a Device Driver 4 + +2.3 How to Create a Device Driver 5 + +2.3.1 Device Strategy Routine 6 + +2.3.2 Device Interrupt Routine 6 + +2.4 Installing Device Drivers 7 + +2.5 Device Headers 8 + +2.5.1 Pointer to Next Device Field 8 + +2.5.2 Attribute Field 9 + +2.5.3 Strategy and Interrupt Routines 11 + +2.5.4 Name Field 11 + +2.6 Request Header 11 + +2.6.1 Length of Record 12 + +2.6.2 Unit Code Field 12 + +2.6.3 Command Code Field 12 + +2.6.4 Status Field 13 + +2.7 Device Driver Functions 14 + +2.7.1 The Init Function 15 + +2.7.2 The Media Check Function 17 + +2.7.3 The Build BPB Function 19 + +2.7.4 The Read or Write Function 20 + +2.7.5 The Non-destructive Read, No Wait Function 22 + +2.7.6 The Open or Close Function 23 + +2.7.7 The Removable Media Function 24 + +2.7.8 The Status Function 24 + +2.7.9 The Flush Function 25 + + 1 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +2.7.10 The Generic IOCtl Function 25 + +2.7.11 The Get/Set Logical Drive Map Function 26 + +2.8 The Media Descriptor Byte 26 + +2.9 Format of a Media Descriptor Table 27 + +2.10 The CLOCK Device 29 + +2.11 Anatomy of a Device Call 29 + +2.12 Two Sample Device Drivers 30 + + + +2 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +54 + +_ _ | | _ _ + + + diff --git a/PROGREF/3_TECH.A b/PROGREF/3_TECH.A new file mode 100644 index 0000000..803a2a3 --- /dev/null +++ b/PROGREF/3_TECH.A @@ -0,0 +1,623 @@ + +_ _ | | _ _ + + MS-DOS Technical Information + + _ _______________________________________ + + +3.1 Introduction + +This chapter describes how MS-DOS initializes and how it allocates disk +space for the root directory, the File Allocation Tables (FAT), and the +data area. For programmers writing installable device drivers, this +chapter explains MS-DOS disk directory entries and File Allocation +Tables. At the end of the chapter, Tables 3.1 and 3.2 describe MS-DOS +standard formats for floppy disks. + +3.2 MS-DOS Initialization + +MS-DOS initialization consists of several steps. When you reset your com- +puter or turn on its power, the ROM (Read Only Memory) BIOS is invoked +and performs hardware checks and initialization. The ROM BIOS then +examines drive A for the boot sector. If it locates a boot sector, the ROM +BIOS reads it into low memory and gives it control. If it doesn't find the +boot sector, the ROM BIOS then looks in the active partition of the hard +disk. If it still doesn't find the boot sector, the ROM BIOS then invokes +ROM BASIC. + +On a removable disk (3.5-inch, 5.25-inch, or 8-inch disk), the boot sector +sector is always located on track 0, sector 1, side 0 of the disk. On a hard +disk, the boot sector begins on the first sector of the MS-DOS partition. +The hard disk boot sector also includes a partition table. This table +identifies the active MS-DOS partition and any other partitions, such as +an extended MS-DOS partition, on the hard disk. Note that extended +MS-DOS partitions are not bootable. + +The boot sector then reads the following files, in the order listed: + +io.sys +msdos.sys + +_ ________________________________________________________________ + +Note + + Versions of MS-DOS prior to 3.3 required the io.sys file to be contigu- + ous. This is no longer a requirement. + +_ ________________________________________________________________ + +Next, the system initialization routine SYSINIT loads all of the resident +device drivers. Then, it searches for a config.sys file on the boot disk. +SYSINIT allocates memory for buffers and files, based on settings in the +config.sys file, or system default settings. If the config.sys file specifies any + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +installable device drivers, these are installed next. + +Finally, SYSINIT executes the MS-DOS command processor, +command.com. + +3.3 The Command Processor + +The command processor command.com consists of three parts: + + o A resident part resides in memory immediately following msdos.sys + and its data area. This part contains routines to process Inter- + rupts 22H (Terminate Process Exit Address), 23H (CONTROL-C Exit + Address), and 24H (Critical-Error-Handler Address), as well as a + routine to reload the transient part, if needed. All standard + MS-DOS error handling is done within this part of command.com. + This includes displaying error messages and processing the Abort, + Retry, Fail, or Ignore messages. + + o An initialization part follows the resident part. During startup, the + initialization part is given control; it contains the processor setup + routine in the autoexec.bat file. The initialization part determines + the segment address at which programs can be loaded, and because + it is no longer needed, is overlaid by the first program that + command.com loads. + + o A transient part is loaded at the high end of memory. This part + contains all the internal command processors and the batch file + processor. + + The transient part of the command processor produces the system + prompt (A>, for example), reads commands from the keyboard (or + from batch files), and causes them to be executed. For external + commands, the transient part builds a command line and issues + Function 4BH (Load and Execute Program) to load and transfer + control to the program. + + +3.4 MS-DOS Disk Allocation + +The area on a disk partitioned for use by MS-DOS is formatted as follows: + + 1. Reserved area\(emvariable size + + 2. First copy of File Allocation Table\(emvariable size + + + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Technical Information + + _ _______________________________________ + + 3. Additional copies of File Allocation Table\(emvariable size (optional) + + 4. Root directory\(emvariable size + + 5. File data area + +Space for a file in the data area is not preallocated. The space is allocated +one cluster at a time. A cluster consists of one or more consecutive sectors +(the number of sectors in a cluster must be a power of 2); the cluster size is +determined at format time. All the clusters for a file are "chained" +together in the File Allocation Table, discussed in greater detail in Section +3.5, "File Allocation Table (FAT)." MS-DOS normally keeps a second copy +of the FAT for consistency, except in the case of reliable storage such as a +virtual RAM disk. Should the disk develop a bad sector in the middle of +the first FAT, MS-DOS can use the second. This avoids loss of data due to +an unreadable FAT. + +3.5 MS-DOS Disk Directory + +The format utility builds the root directory for all disks. This directory's +location on the disk and the maximum number of entries are dependent on +the media. Specifications for standard removable-disk formats are outlined +later in this chapter. Note, however, that MS-DOS regards directories, +other than the root directory, as files, so there is no limit to the number of +files that the subdirectories under the root directory may contain. + +All directory entries are 32 bytes in length and are in the following format +(note that byte offsets are in hexadecimal): + +Byte + Function +_ ________________________________________________________________ + + +0-7 Filename. Eight characters, left-aligned and padded, if neces- + sary, with blanks. The first byte of this field indicates the file + status as follows: + _ _____________________________________________________ + + 00H The directory entry has never been used. This is used + to limit the length of directory searches, for perfor- + mance reasons. + + 05H The first character of the filename contains an E5H + character. + + 2EH The entry is for a directory. If the second byte is also + 2EH, the cluster field contains the cluster number of + this directory's parent directory (0000H if the parent + directory is the root directory). Otherwise, bytes 01H + through 0AH are all spaces, and the cluster field con- + tains the cluster number of this directory. + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + E5H The file was used, but it has since been erased. + + Any other character is the first character of a filename. + +8-0A Filename extension. + +0B File attribute. The attribute byte is mapped as follows + (values are in hexadecimal): + + + Byte + Contents + _ _____________________________________________________ + + 01H File is marked read-only. An attempt to open the file + for writing using Function 3DH (Open Handle) results + in an error code being returned. This value can be + used in programs along with the other attributes in + this list. Attempts to delete the file with Function + 13H (Delete File) or Function 41H (Delete Directory + Entry) will also fail. + + 02H Hidden file. The file is excluded from normal directory + searches. + + 04H System file. The file is excluded from normal directory + searches. + + 08H The entry contains the volume label in the first 11 + bytes. The entry contains no other usable information + (except date and time of creation), and may exist only + in the root directory. + + 10H The entry defines a subdirectory, and is excluded from + normal directory searches. + + 20H Archive bit. The bit is set to "on" whenever the file + has been written to and closed. + + Note: The system files (io.sys and msdos.sys) are + marked as read-only, hidden, and system files. Files + can be marked hidden when they are created. Also, + you may change the read-only, hidden, system, and + archive attributes through Function 43H (Get/Set File + Attributes). + +0C-15 Reserved. + +16-17 Time the file was created or last updated. The hour, minutes, + and seconds are mapped into two bytes as follows (bit 7 on + the left, 0 on the right): + + Offset 17H + | H | H | H | H | H | M | M | M | + + Offset 16H + | M | M | M | S | S | S | S | S | + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Technical Information + + _ _______________________________________ + + where: + + H is the binary number of hours (0-23). + M is the binary number of minutes (0-59). + S is the binary number of two-second increments. + + +18-19 Date the file was created or last updated. The year, month, + and day are mapped into two bytes as follows: + + Offset 19H + | Y | Y | Y | Y | Y | Y | Y | M | + + Offset 18H + | M | M | M | D | D | D | D | D | + + where: + + Y is the year, 0-119 (1980-2099). + M is the month (1-12). + D is the day of the month (1-31). + + +1A-1B Starting cluster; the number of the first cluster in the file. + + o Note that the first cluster for data space on all disks is + cluster 002. + + o The cluster number is stored with the least significant + byte first. + + o For details about converting cluster numbers to logical + sector numbers, see Sections 3.5.1 and 3.5.2. + + +1C-1F File size in bytes. The first word of this four-byte field is the + low-order part of the size. + + +3.6 File Allocation Table (FAT) + +This section explains how MS-DOS allocates disk space in the data area +for a file by using the File Allocation Table to convert the clusters of a file +to logical sector numbers. The device driver is then responsible for locat- +ing the logical sector on the disk. Programs should use the MS-DOS file +management function calls for accessing files. Programs that access the +FAT are not guaranteed to be upwardly-compatible with future releases of +MS-DOS. The following information is useful to system programmers who +wish to write installable device drivers. + +The File Allocation Table is an array of 12-bit entries (1.5 bytes) for each +cluster on the disk. For disks containing more than 4085 clusters, a 16-bit +FAT entry is used. + + + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The first two FAT entries are reserved; however, the device driver may use +the first byte as a FAT ID byte for determining media. For hard disks, the +value of this byte is F8H. See Tables 3.1 and 3.2 for the media byte +descriptors used for 8-inch, 5.25-inch, and 3.5-inch disks. + +The third FAT entry, which starts at byte offset 4, begins the mapping of +the data area (cluster 002). The operating system does not always sequen- +tially write (to the disk) files in the data area. Instead, the system allo- +cates the data area one cluster at a time, skipping over clusters it has +already allocated. The first free cluster following the last cluster allocated +for that file is the next cluster allocated, regardless of its physical location +on the disk. This permits the most efficient use of disk space, since if you +erase old files, you can free clusters, which the operating system can then +allocate for new files. + +Each FAT entry contains three or four hexadecimal characters, depending +on whether it is a 12-bit or 16-bit entry: + +_ ________________________________________________________________ + +(0)000 If the cluster is unused and available. + +(F)FF7 The cluster has a bad sector in it if it is not part of any + cluster chain. MS-DOS will not allocate such a cluster. So + for its report, the chkdsk command counts the number of + bad clusters, which are not part of any allocation chain. + +(F)FF8-FFF The last cluster of a file. + +(X)XXX Any other characters that are the cluster number of the + next cluster in the file. The number of the first cluster in + the file is in the file's directory entry. + +The File Allocation Table always begins on the first sector after the +reserved sectors. If the FAT is larger than one sector, the sectors are con- +tiguous. The operating system usually writes two copies of the FAT to +preserve data integrity. MS-DOS reads the FAT into one of its buffers, +whenever needed (open, read, write, etc.). The operating system also gives +this buffer a high priority to keep it in memory as long as possible. + +3.6.1 How to Use the FAT (12-Bit FAT Entries) + +To get the starting cluster of a file, examine its directory entry (in the +FAT). Then, to locate each subsequent cluster of the file, follow these +steps: + + 1. Multiply the cluster number just used by 1.5 (each FAT entry is + 1.5 bytes in length). + + 2. The whole part of the product is an offset into the FAT, pointing + to the entry that maps the cluster just used. That entry contains + the cluster number of the next cluster of the file. + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Technical Information + + _ _______________________________________ + + 3. Use a MOV instruction to move the word at the calculated FAT + offset into a register. + + 4. If the last cluster used was an even number, keep the low-order 12 + bits of the register by using the AND operator with 0FFFH and the + register. If the last cluster used was an odd number, keep the + high-order 12 bits by using the SHR instruction to shift the register + right four bits. + + 5. If the resultant 12 bits are 0FF8H-0FFFH, the file contains no + more clusters. Otherwise, the 12 bits contain the number of the + next cluster in the file. + +To convert the cluster to a logical sector number (relative sector, such as +that used by Interrupts 25H and 26H (Absolute Disk Read/Write) and by +debug), follow these steps: + + 1. Subtract two from the cluster number. + + 2. Multiply the result by the number of sectors per cluster. + + 3. To this result, add the logical sector number of the beginning of + the data area. + + +3.6.2 How to Use the FAT (16-Bit FAT Entries) + +To get the starting cluster of a file, examine its directory entry (in the +FAT). Then, to find the next file cluster, follow these steps: + + 1. Multiply the cluster number last used by 2 (each FAT entry is 2 + bytes). + + 2. Use a MOV WORD instruction to move the word at the calculated + FAT offset into a register. + + 3. If the resultant 16 bits are 0FFF8-0FFFH, no more clusters are in + the file. Otherwise, the 16 bits contain the number of the next + cluster in the file. + + +3.7 MS-DOS Standard Disk Formats + +MS-DOS arranges data clusters on a disk to minimize head movement. +MS-DOS then allocates all the space on one track (or cylinder) before mov- +ing to the next. It uses the sequential sectors on the lowest-numbered +head, then all the sectors on the next head, and so on, until it has used all +the sectors on all the heads of the track. + + + + 9 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The size of the MS-DOS partition on a hard disk determines the size of the +FAT and root directory. Likewise, the type of floppy disk (tracks per side, +sectors per track, etc.) determines how MS-DOS uses the disk. The remov- +able disk formats listed in Tables 3.1 and 3.2 are standard and should be +readable in the appropriate standard drive. + + +10 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Technical Information + + _ _______________________________________ + +Table 3.1 + +MS-DOS Standard Removable-Disk Formats + +_ _________________________________________________________________________ + +Disk Size in inches 5.25 8 + +_ _________________________________________________________________________ + +WORD no. heads 1 1 2 2 1 2 1 + +Tracks/side 40 40 40 40 77 77 77 + +WORD sectors/track 8 9 8 9 26 26 8 + +WORD bytes/sector 512 512 512 512 128 128 024 + +BYTE sectors/ cluster 1 1 2 2 4 4 1 + +WORD reserved sectors 1 1 1 1 1 4 1 + +Byte no. FATs 2 2 2 2 2 2 2 + +WORD root directory entries 64 64 112 112 68 68 192 + +WORD no. sectors 320 360 640 720 2002 2002 616 + +BYTE media descriptor FE FC FF FD *FE FD *FE + +WORD sectors/FAT 1 2 1 2 6 6 2 + +WORD no. hidden sectors 0 0 0 0 0 0 0 + +_ _________________________________________________________________________ + +*The two media descriptor bytes are the same for 8" disks (FEH). This is not a misprint. To +establish whether a disk is single- or double-density, try a read of a single-density address +mark. If an error occurs, the media is double-density. + +Table 3.2 + +MS-DOS Standard Removable Disk Formats (High-Density) + +_ _________________________________________________________________________ + +Disk Size in inches 3.5 or 5.25 3.5 5.25 + +_ _________________________________________________________________________ + +WORD no. heads 1 2 2 2 2 2 + +Tracks/side 80 80 80 80 80 80 + +WORD sectors/track 8 9 8 9 18 15 + +WORD bytes/sector 512 512 512 512 512 512 + +BYTE sectors/cluster 2 2 2 2 1 1 + +WORD reserved sectors 1 1 1 1 1 1 + +BYTE no. FATs 2 2 2 2 2 2 + +WORD root dir entries 112 112 112 112 224 224 + +WORD no. sectors 640 720 1280 1440 2880 2400 + +BYTE media descriptor* FA FC FB F9 F0 F9 + +WORD sectors/FAT 1 2 2 3 9 7 + +WORD no. hidden sectors 0 0 0 0 0 0 + +_ _________________________________________________________________________ + +*The value F0H in the media descriptor byte may be used to describe other media types. + + + 11 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Chapter 3 + +MS-DOS Technical Information + +_ ________________________________________________________________ + +3.1 Introduction 3 + +3.2 MS-DOS Initialization 3 + +3.3 The Command Processor 4 + +3.4 MS-DOS Disk Allocation 4 + +3.5 MS-DOS Disk Directory 5 + +3.6 File Allocation Table (FAT) 7 + +3.6.1 How to Use the FAT (12-Bit FAT Entries) 8 + +3.6.2 How to Use the FAT (16-Bit FAT Entries) 9 + +3.7 MS-DOS Standard Disk Formats 9 + + + +12 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +12 + +_ _ | | _ _ + + + diff --git a/PROGREF/4_CTRLB.A b/PROGREF/4_CTRLB.A new file mode 100644 index 0000000..863ab36 --- /dev/null +++ b/PROGREF/4_CTRLB.A @@ -0,0 +1,393 @@ + +_ _ | | _ _ + + MS-DOS Control Blocks and Work Areas + + _ ______________________________________________ + + +4.1 Introduction + +This chapter describes a typical MS-DOS memory map and explains how a +program is loaded into memory. It also describes the structure of an +MS-DOS program segment and the contents of register segments for .exe +and .com program files. + +4.2 Typical Contents of an MS-DOS Memory +Map + +A typical MS-DOS memory map contains the following information: + + + +-----------------------------------------------------+ + | ROM and Video Buffers | + +-----------------------------------------------------+ + | Transient Part of COMMAND.COM | + +-----------------------------------------------------+ + | | + | | + | | + | | + | Transient Program Area | + |- - - - - - - - - - - - - - - - - - - - - - - - - - -| + | | + | | + | | + | | + | External Commands and Utilities | + | | + +-----------------------------------------------------+ + | Resident Part of COMMAND.COM | + +-----------------------------------------------------+ + | MS-DOS buffers, control areas, & installed drivers | + +-----------------------------------------------------+ + | | + | MSDOS.SYS | + +-----------------------------------------------------+ + | IO.SYS and resident device drivers | + +-----------------------------------------------------+ + | Interrupt Vectors | + 0 +-----------------------------------------------------+ + +During system initialization, MS-DOS loads the io.sys and msdos.sys files +into low memory (Note that in MS-DOS 3.3, these files are not required to +be written contiguously to the disk). The io.sys system file is the MS-DOS +interface to hardware. The msdos.sys system file includes MS-DOS inter- +rupt handlers, service routines (Interrupt 21H functions). + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +Next, the system initialization routine loads the resident and installable +device drivers. Above the installable device drivers, MS-DOS writes the +resident part of command.com. This part includes interrupt handlers for +Interrupts 22H (Terminate Process Exit Address), 23H (CONTROL-C +Handler Address), 24H (Critical-Error-Handler Address) and code to reload +the transient part. The transient part of command.com is reloaded into +high memory. It includes the command interpreter, the internal MS-DOS +commands, and the batch processor. + +External command and utility (.com and .exe) files are loaded into the +transient program area. MS-DOS also allocates 256 bytes for user stack +used with .com files. User memory is allocated from the lowest end of +available memory that fulfills the allocation request. + +4.3 MS-DOS Program Segment + +When you type an external command or execute a program through Func- +tion 4BH (Load and Execute Program, also called EXEC), MS-DOS deter- +mines the lowest available free memory address to use as the start of the +program. The memory starting at this address is called the Program Seg- +ment. + +The EXEC system call sets up the first 256 bytes of the Program Segment +for the program being loaded into memory. The program is then loaded +following this block. An .exe file with minalloc and maxalloc both set to +zero is loaded as high as possible. + +At offset 0 within the Program Segment, MS-DOS builds the Program Seg- +ment Prefix control block. The program returns from EXEC by one of five +methods: + + o By issuing an Interrupt 21H with AH=4CH + + o By issuing an Interrupt 21H with AH=31H (Keep Process) + + o By a long jump to offset 0 in the Program Segment Prefix + + o By issuing an Interrupt 20H with CS:0 pointing at the PSP + + o By issuing an Interrupt 21H with register AH=0 and with CS:0 + pointing at the PSP + +_ ________________________________________________________________ + +Note + + The first two methods are preferred for functionality, compatibility, + and efficiency in future versions of MS-DOS. + +_ ________________________________________________________________ + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Control Blocks and Work Areas + + _ ______________________________________________ + +All five methods transfer control to the program that issued the EXEC +call. The first two methods return a completion code. They also restore +the addresses of Interrupts 22H, 23H, and 24H (Terminate Process Exit +Address, CONTROL-C Handler Address, and Critical-Error-Handler Address) +from the values saved in the Program Segment Prefix of the terminating +program. Control then passes to the terminate address. + +If a program returns to command.com, control transfers to the resident +portion. If the program is a batch file (in process), it continues. Other- +wise, command.com performs a checksum on the transient part, reloads it +if necessary, issues the system prompt, and waits for you to type another +command. + +When a program receives control, the following conditions are in effect: + +For all programs: + + o The segment address of the passed environment is at offset 2CH in + the Program Segment Prefix. + + o The environment is a series of ASCII strings (totaling less than 32K) + in the form: + + NAME=parameter + + o A byte of zeros terminates each string, and another byte of zeros + terminates the set of strings. + + Following the last byte of zeros is a set of initial arguments that + the operating system passes to a program. This set of arguments + contains a word count followed by an ASCII string. If the file is in + the current directory, the ASCII string contains the drive and path- + name of the executable program as passed to the EXEC function + call. If the file is not in the current directory, EXEC concatenates + the name of the file with the name of the path. Programs may use + this area to determine where the program was loaded. + + o The environment built by the command processor contains at least + a comspec= string (the parameters on comspec define the path + that MS-DOS uses to locate command.com on disk). The last path + and prompt commands issued are also in the environment, along + with any environment strings you have defined with the MS-DOS + set command. + + o EXEC passes a copy of the invoking process environment. If your + application uses a "keep process" concept, you should be aware + that the copy of the environment passed to you is static. That is, + it will not change even if you issue subsequent set, path, or + prompt commands. Conversely, any modification of the passed + environment by the application is not reflected in the parent pro- + cess environment. For instance, a program cannot change the + MS-DOS environment values as the set command does. + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + o The Disk Transfer Address (DTA) is set to 80H (default DTA in the + Program Segment Prefix). The Program Segment Prefix contains + file control blocks at 5CH and 6CH. MS-DOS formats these blocks + using the first two parameters that you typed when entering the + command. If either parameter contained a pathname, then the + corresponding FCB contains only the valid drive number. The + filename field is not valid. + + o An unformatted parameter area at 81H contains all the characters + typed after the command (including leading and embedded delim- + iters), with the byte at 80H set to the number of characters. If you + type <, >, or parameters on the command line, they do not + appear in this area (nor the filenames associated with them). + Redirection of standard input and output is transparent to appli- + cations. + + o Offset 6 (one word) contains the number of bytes available in the + segment. + + o Register AX indicates whether the drive specifiers (entered with the + first two parameters) are valid, as follows: + + AL=FF if the first parameter contained an invalid drive specifier + (otherwise AL=00) + + AH=FF if the second parameter contained an invalid drive + specifier (otherwise AH=00) + + o Offset 2 (one word) contains the segment address of the first byte + of unavailable memory. Programs must not modify addresses + beyond this point unless these addresses were obtained by allocat- + ing memory via Function 48H (Allocate Memory). + + +For Executable (.exe) Programs: + + o DS and ES registers point to the Program Segment Prefix. + + o CS,IP,SS, and SP registers contain the values that Microsoft link + sets in the .exe image. + + +For Executable (.com) Programs: + + o All four segment registers contain the segment address of the ini- + tial allocation block that starts with the Program Segment Prefix + control block. + + o .com programs allocate all of user memory. If the program invokes + another program through Function 4BH (EXEC), it must first free + some memory through Function 4AH (Set Block) to provide space + for the program being executed. + + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Control Blocks and Work Areas + + _ ______________________________________________ + + o The Instruction Pointer (IP) is set to 100H. + + o The Stack Pointer register is set to the end of the program's seg- + ment. The segment size at offset 6 is reduced by 100H to allow for + a stack of that size. + + o A .com program places a word of zeros on top of the stack. Then + by doing a RET instruction last, your program can exit to + command.com. This method assumes, however, that you have + maintained your stack and code segments. + +Figure 4.1 illustrates the format of the Program Segment Prefix. All +offsets are in hexadecimal. + + (Offsets in Hex) +0 ----------------------------------------------------------- + | | End of | | + | INT 20H | alloc. | Reserved | + | | block | 04H | +8 ----------------------------------------------------------- + | | Terminate address | CONTROL-C exit | + | Reserved | (IP, CS) | address (IP) | + | | | | +10----------------------------------------------------------- + |CONTROL-C | Hard error exit address | | + |exit | (IP, CS) | | + |address (CS)| | | + ---------------------------------------- | + | | + | Used by MS-DOS | + | | + | 5CH | + | | + ----------------------------------------------------------- + | | + | Formatted Parameter Area 1 formatted as standard | + | unopened FCB 6CH | + ----------------------------------------------------------- + | | + | Formatted Parameter Area 2 formatted as standard | + | unopened FCB (overlaid if FCB at 5CH is opened) | +80----------------------------------------------------------- + | Unformatted Parameter Area | + | (default Disk Transfer Area) | + | Initially contains command invocation line. | + ----------------------------------------------------------- +100 + + + Figure 4.1 Program Segment Prefix + +_ ________________________________________________________________ + +Important + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + Programs must not alter any part of the Program Segment Prefix + below offset 5CH. + +_ ________________________________________________________________ + + + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Chapter 4 + +MS-DOS Control Blocks + +and Work Areas + +_ ________________________________________________________________ + +4.1 Introduction 3 + +4.2 Typical Contents of an MS-DOS Memory Map 3 + +4.3 MS-DOS Program Segment 4 + + + + 1 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +8 + +_ _ | | _ _ + + + diff --git a/PROGREF/5_NLS.A b/PROGREF/5_NLS.A new file mode 100644 index 0000000..6ae548f --- /dev/null +++ b/PROGREF/5_NLS.A @@ -0,0 +1,360 @@ + +_ _ | | _ _ + + National Language Support + + _ ____________________________________ + + +5.1 Introduction + +National language support for this version of MS-DOS 3.3 includes these +major features: + + o Country-dependent information + + o Support for national keyboard layouts + + o Programming interfaces for national language support + + o Utility commands + +Country-dependent information is available on a per-country basis and +includes the following: + + o Time, date, and currency + + o Lowercase-to-uppercase character-conversion tables + + o Collating sequence for character sorting + + o Valid single-byte characters used in filenames + +Selectable keyboard support for different keyboard layouts is provided. + +The MS-DOS 3.3 programming interfaces for national language support +allow applications to use the country-dependent information just +described. To access this information, applications do not need to change +the current country code of the system. + +Utility commands allow the user to select the keyboard layout and system +country code. + +This version of MS-DOS does not support right-to-left national languages. + +5.2 National Language Support Calls + +The following function calls allow an application to tailor its operation to +the current country code and to accept or change the current code page. +A country code defines the country in which you live or work. MS-DOS +uses this code to prepare and assign default code pages for your system. A +code page is a table that defines the character set you are using. A +character set is a country-specific or language-specific group of characters +that are translated from the code page table and displayed on your screen +or printer. Each code page character set contains 256 characters. + + + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The following function calls are also used by MS-DOS 3.3 to support the +National Language requirements: + + o Function 44H, Code 0CH (Generic IOCtl) \(em supports code page + switching on a per-device basis. + + o Function 65H (Get Extended Country Information) \(em returns + standard country information, and points to related case-map or + collating tables. + + o Function 66H (Get/Set Global Code Page) \(em gets or sets the code + page used by the kernel and by all devices. + +These functions support access to country-dependent information, all of +which resides in one file named country.sys. + +5.3 Font Files + +Font files, also called code page information files, contain the images of +code page character sets for use by console-screen or printer devices. +These font files are identified by a filename extension of .cpi. Four font +files are included with MS-DOS 3.3: + +Font file + Supported device +_ ________________________________________________________________ + +ega.cpi Color console used with an EGA card + +lcd.cpi Liquid crystal display + +4201.cpi IBM Proprinter + +5202.cpi Quietwriter III printer + + +5.3.1 Font File Structure + +The contents of printer or console-screen font files are structured as fol- +lows: + + +--------------------------------------+ + | 22-BYTE File Header | + +--------------------------------------+ + | WORD Information Header | + +--------------------------------------+ + | 13-BYTE Code Page Entry Header | + +--------------------------------------+ + | 6-BYTE Font Data Header | + +--------------------------------------+ + | Variable size Font Header(s) | + +--------------------------------------+ + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + National Language Support + + _ ____________________________________ + + + + + Figure 5.1 Font File Structure + +The font file fields are described in the following sections. + +5.3.1.1 File Header + +Each file must begin with a file header that includes the following: + +Length + Parameter +_ ________________________________________________________________ + +8 BYTES File tag + +8 BYTES Reserved + +WORD Number of pointers + +2 WORDS Offset + +where: + +File tag begins with the byte 0FFH and is followed by a string "font " +(seven characters). + +Reserved is eight bytes of zeros. + +Number of pointers is the number of pointers in the header. For MS-DOS +3.3, the value of this word should be 1. + +Offset is the two-word offset from the beginning of the file. + +5.3.1.2 Information Header + +Following the file header is a one-word information header: + +Length + Parameter +_ ________________________________________________________________ + +WORD Number of code pages + +where: + +Number of code pages is the number of code page entries in the file. + + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +5.3.1.3 Code Page Entry Header + +For each code page entry, a header in the following format is included in +the font file: + +Length + Parameter +_ ________________________________________________________________ + +WORD Length + +WORD Pointer + +WORD Device type + +8 BYTES Device subtype + +WORD Code page ID + +WORD Reserved + +2 WORDS Offset + +where: + +Length is the size of the code page entry header. + +Pointer points to the next code page entry header (last header=0, 0). + +Device type is 1 if the device is a console screen, or 2 if the device is a +printer. + +Device subtype names the type of console screen or printer. This field also +determines the name of the font file. For example, if the subtype is +"CGA," the font file name is cga.cpi + +Code page ID defines a valid three-digit code page identification number. +Valid code page numbers are 437, 850, 860, 863, and 865. + +Reserved is eight bytes of zeros. + +Offset is a pointer to the Font Data Header. + +5.3.1.4 Font Data Header + +The Font Data Header includes the following fields: + +Length + Parameter +_ ________________________________________________________________ + +WORD Reserved + +WORD Number of fonts + + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + National Language Support + + _ ____________________________________ + +WORD Length of font data + +where: + +Reserved must be 1. + +Number of fonts is equal to the number of fonts defined in the font file. + +Length of font data is equal to the size of the font-data portion of the font +file. + +5.3.1.5 Font Header + +The font-data portion of a font file will vary for each device. The struc- +ture of the font-data portion consists of a set of data for each font type. +The following illustrates the data portion of a font file for a console-screen +device: + +font_header: + db 16, 8 ; character pixels + ; (rows, columns) + db 0, 0 ; aspect ratio (unused) + dw 256 ; number of characters in set + + +len_data equ ($ - font_header) + + + + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Chapter 5 + +National Language Support + +_ ________________________________________________________________ + +5.1 Introduction 3 + +5.2 National Language Support Calls 3 + +5.3 Font Files 4 + +5.3.1 Font File Structure 4 + +5.3.1.1 File Header 5 + +5.3.1.2 Information Header 5 + +5.3.1.3 Code Page Entry Header 6 + +5.3.1.4 Font Data Header 6 + +5.3.1.5 Font Header 7 + + + + 1 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + + 7 + +_ _ | | _ _ + + + diff --git a/PROGREF/6_EXE.A b/PROGREF/6_EXE.A new file mode 100644 index 0000000..73a4433 --- /dev/null +++ b/PROGREF/6_EXE.A @@ -0,0 +1,203 @@ + +_ _ | | _ _ + + .Exe File Structure and Loading + + _ _______________________________________ + +_ ________________________________________________________________ + +Note + + This chapter describes .exe file structure and loading procedures for + systems that use a version of MS-DOS earlier than 2.0. For MS-DOS + versions 2.0 and later, use Function 4B00H (Load and Execute a Pro- + gram) to load (or load and execute) an .exe file. + +_ ________________________________________________________________ + +The .exe files produced by link consist of two parts: + + o Control and relocation information + + o The load module + +The control and relocation information is at the beginning of the file in an +area called the header. Immediately following this header is the load +module. + +6.1 Format of a File Header + +The header is formatted as follows (note that offsets are in hexadecimal): + +Offset + Contents +_ ________________________________________________________________ + +0-1 Must contain 4DH, 5AH. + +2-3 Number of bytes contained in last page; useful for reading + overlays. + +4-5 Size of the file in 512-byte pages, including the header. + +6-7 Number of relocation entries in table. + +8-9 Size of the header in 16-byte paragraphs. Used to locate the + beginning of the load module in the file. + +AH-BH Minimum number of 16-byte paragraphs required above the + end of the loaded program. + +CH-DH Maximum number of 16-byte paragraphs required above the + end of the loaded program. If both minalloc and maxalloc + are 0, the program is loaded as high as possible. + +EH-FH Initial value to be loaded into stack segment before starting + program execution. Must be adjusted by relocation. + + + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +10-11 Value to be loaded into the SP register before starting pro- + gram execution. + +12-13 Negative sum of all the words in the file. + +14-15 Initial value to be loaded into the IP register before starting + program execution. + +16-17 Initial value to be loaded into the CS register before starting + program execution. Must be adjusted by relocation. + +18-19 Relative byte offset from beginning of run file to relocation + table. + +1AH-1BH The number of the overlay as generated by link. + + +6.2 The Relocation Table + +The relocation table that follows the formatted area above, consists of a +variable number of relocation items. Each relocation item contains two +fields: a two-byte offset value, followed by a two-byte segment value. +These two fields contain the offset into a word's load module. This item +requires modification before the module is given control. The following +steps describe this process: + + 1. The formatted part of the header is read into memory. Its size is + 1BH. + + 2. MS-DOS allocates a portion of memory depending on the size of + the load module and the allocation numbers (AH-BH and CH-DH). + MS-DOS then attempts to allocate 0FFFH paragraphs. This + attempt always fails, and returns the size of the largest free block. + If this block is smaller than minalloc and loadsize, there is no + memory error. But if this block is larger than maxalloc and + loadsize, MS-DOS allocates (maxalloc + loadsize). Otherwise, it + allocates the largest free block of memory. + + 3. A Program Segment Prefix is built in the lowest part of the allo- + cated memory. + + 4. MS-DOS calculates the load module size (using offsets 4-5 and 8-9) + by subtracting the header size from the file size. The actual size is + adjusted down based on the contents of offsets 2-3. The operating + system determines (based on the setting of the high/low load + switch) an appropriate segment, called the start segment, where it + loads the load module. + + 5. The load module is read into memory beginning with the start seg- + ment. + + + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + .Exe File Structure and Loading + + _ _______________________________________ + + 6. The items in the relocation table are read into a work area. + + 7. MS-DOS adds the segment value of each relocation table item to + the start segment value. This calculated segment, plus value, + points to the module to which the start segment value is added. + The result is then placed back into the word in the load module. + + 8. Once all relocation items have been processed, the operating sys- + tem sets the SS and SP registers, using the values in the header. + MS-DOS then adds the start segment value to SS and sets the ES + and DS registers to the segment address of the Program Segment + Prefix. The start segment value is then added to the header CS + register value. The result, along with the header IP value, is the + initial CS:IP to transfer to before starting execution of the pro- + gram. + + + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Chapter 6 + +.Exe File Structure and Loading + +_ ________________________________________________________________ + +6.1 Format of a File Header 3 + +6.2 The Relocation Table 4 + + + + 1 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + + 5 + +_ _ | | _ _ + + + diff --git a/PROGREF/7_OMF.A b/PROGREF/7_OMF.A new file mode 100644 index 0000000..cd3e50d --- /dev/null +++ b/PROGREF/7_OMF.A @@ -0,0 +1,2555 @@ + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + + +7.1 Introduction + +This chapter presents the object record formats that define the relocatable +object language for the 8086, 80186, and 80286 microprocessors. The 8086 +object language is the output of all language translators that have an 8086 +processor and that will be linked by the Microsoft linker. The 8086 object +language is used for input and output for object language processors such +as linkers and librarians, and is used in the XENIX, PC-DOS, and MS-DOS +operating systems. + +The 8086 object module formats let you specify relocatable memory +images that may be linked together. These formats also allow efficient use +of the memory mapping facilities of the 8086 family of microprocessors. + +The following table lists the record formats (each described in this +chapter) that Microsoft supports (the abbreviations appear in +parentheses): + +Table 7.1 + +Object Module Record Formats + +_ _________________________________________________________________________ + +Symbol Definition Records + +Public Names Definition Record (PUBDEF) +Communal Names Definition Record (COMDEF) +Local Symbols Record (LOCSYM) +External Names Definition Record (EXTDEF) +Line Numbers Record (LINNUM) + +Data Records + +Logical Enumerated Data Record (LEDATA) +Logical Iterated Data Record (LIDATA) + +T-Module Header Record (THEADR) +L-Module Header Record (LHEADR) +List of Names Record (LNAMES) +Segment Definition Record (SEGDEF) +Group Definition Record (GRPDEF) + +Fixup Record (FIXUPP) +Module End Record (MODEND) +Comment Record (COMENT) + +_ _________________________________________________________________________ + + + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +_ ________________________________________________________________ + +Note + + If an object module contains any undefined values, the behavior of the + Microsoft linker is undefined. All undefined values should be con- + sidered reserved by Microsoft for future use. + +_ ________________________________________________________________ + + +7.1.1 Definition of Terms + +The following terms are fundamental to 8086 relocation and linkage: + +OMF - Object Module Formats + + +MAS - Memory Address Space + +The 8086 MAS is one megabyte (1,048,576 bytes). Note that the MAS is +distinguished from actual memory, which may occupy only a portion of +the MAS. + +Module + +A module is an "inseparable" collection of object code and other informa- +tion produced by a translator. + +T-Module + +A T-module is a module created by a translator, such as Pascal or FOR- +TRAN. + +The following restrictions apply to object modules: + + o Every module should have a name. Translators provide default + names (possibly filenames or null names) for T-modules if neither + the source code nor the user specifies otherwise. + + o Every T-module in a collection of linked modules should have a + different name so that symbolic debugging systems can distinguish + the various line numbers and local symbols. The Microsoft linker + does not require or enforce this restriction. + + + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + + +Frame + +A frame is a contiguous region of 64K of memory address space (MAS), +beginning on a paragraph boundary (i.e., on a multiple of 16 bytes) or on a +selector on the 80286 processor. This concept is useful because the con- +tents of the four 8086 segment registers define four (possibly overlapping) +frames; no 16-bit address in the 8086 code can access a memory location +outside the current four frames. + +LSEG (Logical Segment) + +A logical segment (LSEG) is a contiguous region of memory whose contents +are determined at translation time (except for address-binding). Neither +the size nor the location in MAS are necessarily determined during transla- +tion: the size, although partially fixed, may not be final because the linker +may combine the LSEG when linking with other LSEGs, forming a single +LSEG. So that it can fit in a frame, an LSEG must not be larger than +64K. Thus, a 16-bit offset, from the base of a frame that covers the LSEG, +may address any byte in that LSEG. + +PSEG (Physical Segment) + +This term is equivalent to frame. Some prefer "PSEG" to "frame" because +the terms PSEG and LSEG reflect the "physical" and "logical" nature of +the underlying segments. + +Frame Number + +Every frame begins on a paragraph boundary. The "paragraphs" in MAS +can be numbered from 0 through 65,535. These numbers, each of which +defines a frame, are called frame numbers. + +Group + +A group is a collection of LSEGs defined at translation time, whose final +locations in MAS have been constrained so that at least one frame exists +that covers (contains) every LSEG in the collection. + +The notation "Gr A(X,Y,Z,)" means that LSEGs X, Y, and Z form a group +named A. That X, Y, and Z are all LSEGs in the same group does not +imply any ordering of X, Y, and Z in MAS, nor does it imply any contiguity +between X, Y, and Z. + + + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The Microsoft linker does not currently allow an LSEG to be a member of +more than one group. + +Canonic + +On the 8086 processor, any location in MAS is contained in exactly 4096 +distinct frames, but one of these frames can be distinguished because it +has a higher frame number. This frame is called the canonic frame of the +location. In other words, the canonic frame of a given byte is the frame +chosen so that the byte's offset from that frame lies in the range 0 to 15 +(decimal). + +For example, suppose FOO is a symbol defining a memory location. You +would then refer to this frame as the "canonic frame of FOO." Similarly, if +S is any set of memory locations, then a unique frame exists that has the +lowest frame number in the set of canonic frames of the locations in S. +This unique frame is called the canonic frame of the set S. You might +refer similarly to the canonic frame of an LSEG or of a group of LSEGs. + +Segment Name + +LSEGs are assigned Segment Names at translation time. These names +serve two purposes: + + o During linking they play a role in determining which LSEGs are + combined with other LSEGs. + + o They are used in assembly source code to specify membership in + groups. + + +Class Name + +The translator may optionally assign class names to LSEGs during transla- +tion. Classes define a partition on LSEGs: two LSEGs are in the same +class if they have the same class name. + +The Microsoft linker applies the following semantics to class names: the +class name "CODE", or any class name whose suffix is "CODE", implies +that all segments of that class contain only code and may be considered +read-only. Such segments may be overlaid if you specify the module con- +taining the segment as part of an overlay. + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + + +Overlay Name + +The linker may optionally assign an overlay name to LSEGs. The overlay +name of an LSEG is ignored by Microsoft language linkers for version 3.00 +and later languages, but the standard MS-DOS linker supports it. + +Complete Name + +The complete name of an LSEG consists of the segment name, class name, +and overlay name. The linker combines LSEGs from different modules if +their complete names are identical. + +7.2 Module Identification and Attributes + +A module header record, which provides a module name, is always the first +record in a module. In addition to having a name, a module may represent +a main program and may have a specified starting address. When linking +multiple modules together, you should give only one module with the main +attribute. If more than one main module appears, the first takes +precedence. + +In summary, modules may or may not be main and may or may not have a +starting address. + +7.2.1 Segment Definition + +A module is a collection of object code defined by a sequence of records +that a translator produces. The object code represents contiguous regions +of memory whose contents the linker determines during translation. +These regions are LSEGs. A module defines the attributes of each LSEG. +The segment definition record (SEGDEF) is responsible for maintaining all +LSEG information (name, length, memory alignment, etc.). The linker +requires the LSEG information when you combine multiple LSEGs and +when it establishes segment addressability. The SEGDEF records must +follow the first header record. + +7.2.2 Addressing a Segment + +The 8086 addressing mechanism provides segment base registers from +which you may address a 64K-byte region of memory (a Frame). There is +one code segment base register (CS), two data segment base registers (DS, +ES), and one stack segment base register (SS). + + + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The possible number of LSEGs that may make up a memory image far +exceeds the number of available base registers. Thus, base registers may +require frequent loading. This would be the case in a modular program +with many small data and/or code LSEGs. + +Since such frequent loading of base registers is undesirable, it is a good +strategy to collect many small LSEGs together into a single unit that will +fit in one memory frame. Then all the LSEGs may be addressed using the +same base register value. This addressable unit is a group and has been +defined earlier in Section 7.1.1, "Definition of Terms." + +To establish addressability of objects within a group, you must explicitly +define each group in the module. The group definition record (GRPDEF) +lists constituent segments by their segment names. + +The GRPDEF records within a module must follow all SEGDEF records +because GRPDEF records will reference SEGDEF records in defining a +Group. The GRPDEF records must also precede all other records except +header records, which the linker must process first. + +7.2.3 Symbol Definition + +The Microsoft linker supports three different types of records belonging to +the class of symbol definition records. The types are public names +definition records (PUBDEFs), communal names definition records (COM- +DEFs), and external names definition records (EXTDEFs). You use these +record types to define globally visible procedures and data items and to +resolve external references. + +7.2.4 Indices + +"Index" fields appear throughout this chapter. An index is an integer that +selects a particular item from a collection of items; for example: name +index, segment index, group index, external index, type index, etc. + +_ ________________________________________________________________ + +Note + + An index is normally a positive number. The index value zero is + reserved, and may carry a special meaning depending on the type of + index (for example, a segment index of zero specifies the "Unnamed" + absolute pseudo-segment; a type index of zero specifies the "Untyped + type.") + +_ ________________________________________________________________ + +In general, indices must assume values that are quite large (that is, much + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + +larger than 255). Nevertheless, a great number of object files contain no +indices with values greater than 50 or 100. Therefore, indices are encoded +in one or two bytes, as required. + +The high-order (left-most) bit of the first (and possibly the only) byte +determines whether the index occupies one byte or two. If the bit is 0, the +index is a number between 0 and 127, occupying one byte. If the bit is 1, +the index is a number between 0 and 32K-1, occupying two bytes, and is +determined as follows: the low-order eight bits are in the second byte, and +the high-order seven bits are in the first byte. + +7.3 Conceptual Framework for Fixups + +A fixup is a modification to object code that achieves address binding that +a translator requested and a linker performed. + +_ ________________________________________________________________ + +Note + + This is the linker's definition of fixup. Nevertheless, the linker can + modify object code (make a "fixup") that does not conform to this + definition. For example, binding code to either hardware or software + floating-point subroutines is a modification to an operation code, + which is treated as an address. The previous definition of fixup is not + intended to disallow or discourage modifications to the object code. + +_ ________________________________________________________________ + +8086-family translators need four kinds of data to specify a fixup: + + o The place and type of a Location to be fixed up. + + o One of two possible fixup modes. + + o A target, which is the memory address that Location must refer to. + + o A frame that defines a context in which the reference takes place. + +Location \(em There are five types of Locations: a pointer, a base, an offset, a +hibyte, and a lobyte. + +The vertical alignment of the following figure illustrates four points +(remember that the high-order byte of a word in 8086 memory is the byte +with the higher address): + + o A base is the high-order word of a pointer (the linker doesn't care + whether the low-order word of the pointer is present). + + + 9 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + o An offset is the low-order word of a pointer (the linker doesn't care + whether the high-order word follows). + + o A hibyte is the high-order half of an offset (the linker doesn't care + whether the low-order half precedes). + + o A lobyte is the low-order half of an offset (the linker doesn't care + whether the high-order half follows). + + + +----+----+----+----+ +Pointer: | | + +----+----+----+----+ + + +----+----+ +Base: | | + +----+----+ + + +----+----+ +Offset: | | + +----+----+ + + +----+ +Hibyte: | | + +----+ + + +----+ +Lobyte: | | + +----+ + + + Figure 7.1 Location Types + +A Location is specified by two kinds of data: the Location type, and where +the Location is (the location of the Location?). + +The Location type is specified by the LOC field in the FIXUPP record's +LOCAT field; where the Location is is specified by the Data Record Offset +field in the same LOCAT field. + +Mode \(em The Microsoft linker supports two kinds of fixups: self-relative +and segment-relative. + +Self-relative fixups support the 8-bit and 16-bit offsets used in CALL, +JUMP, and SHORT-JUMP instructions. Segment-relative fixups support +all other addressing modes of the 8086. + +Target \(em The target is the location in MAS that the linker references. +(More explicitly, the linker considers the target the lowest byte in the +object that it is referencing.) The linker specifies a target by one of six +methods. There are three "primary" methods and three "secondary" ones. +Each primary method of specifying a target uses two kinds of data: an +index number X, and a displacement D. + + +10 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + +_ ________________________________________________________________ + +(T0) X is a segment index. The target is the Dth byte in the LSEG that + the segment index identifies. + +(T1) X is a group index. The target is the Dth byte in the LSEG that + the group index identifies. + +(T2) X is an external index. The external index identifies the external + name that (eventually) gives the address of a byte. The Dth byte + following this byte is the target. + +Each secondary method of specifying a target uses only one item of data +\(em the index number X; this assumes an implicit displacement equal to +zero. + +_ ________________________________________________________________ + +(T4) X is a segment index. The target is the 0th (first) byte in the + LSEG that the segment index identifies. + +(T5) X is a group index. The target is the 0th (first) byte in the LSEG + in the specified group located (eventually) lowest in MAS. + +(T6) X is an external index. The target is the byte whose address is the + external name that the external index identifies. + +The following nomenclature describes a target: + +_ ________________________________________________________________ + +Target: SI(segment name), displacement [T0] + +Target: GI(group name), displacement [T1] + +Target: EI(symbol name), displacement [T2] + +Target: SI (segment name) [T4] + +Target: GI (group name) [T5] + +Target: EI (symbol name) [T6] + +The following examples illustrate how this notation is used: + +_ ________________________________________________________________ + +Target: SI(CODE), 1024 The 1025th byte in the segment + CODE. + +Target: GI(DATAAREA) The location in MAS of a group + called DATAAREA. + +Target: EI(SIN) The address of the external subrou- + tine SIN. + +Target: EI(PAYSCHEDULE), 24 The 24th byte following the location + of an external data structure called + PAYSCHEDULE. + + 11 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +Frame \(em Every 8086 memory reference is to a location contained within a +frame. This frame is designated by the content of a segment register. For +the linker to form a correct, usable memory reference, it must know what +the target is, and to which frame the reference is being made. Thus, every +fixup specifies such a frame, in one of six methods. Some methods use +data, X, which is in the index number. Other methods require no data. + +The five methods of specifying frames are as follows: + +_ ________________________________________________________________ + +(F0) X is a segment index. The frame is the canonic frame of the LSEG + that the segment index defines. + +(F1) X is a group index. The frame is the canonic frame defined by the + group (that is, the canonic frame defined by the LSEG in the group + located (eventually) lowest in MAS). + +(F2) X is an external index. The frame is determined when the linker + finds the external name's public definition. There are two cases: + + _ _________________________________________________________ + + (F2a) The linker defines the symbol relative to some LSEG, and + there is no associated group. The linker also specifies the + LSEG's canonic frame. + + (F2c) Regardless of how the linker defines the symbol, there is an + associated group. And the linker specifies the canonic + frame of the group. (The Group Index field of the PUBDEF + record specifies the group.) + +(F4) No X. The frame is the canonic frame of the LSEG that contains + Location. + +(F5) No X. The target determines the frame. There are three cases: + + _ _________________________________________________________ + + (F5a) The target specifies a segment index: in this case, the frame + is determined as in (F0). + + (F5b) The target specifies a group index: in this case, the frame is + determined as in (F1). + + (F5c) The target specifies an external index: in this case, the + frame is determined as in (F2). + + +The nomenclature that describes frames is similar to the above nomencla- +ture for targets. + +_ ________________________________________________________________ + +Frame: SI (segment name) [F0] + +Frame: GI (group name) [F1] + + + +12 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + +Frame: EI (symbol name) [F2] + +Frame: Location [F4] + +Frame: target [F5] + +Frame: None [F6] + +For an 8086 memory reference, the frame specified by a self-relative refer- +ence is usually the canonic frame of the LSEG that contains Location. +Also, the frame specified by a segment-relative reference is the canonic +frame of the LSEG that contains the target. + +7.3.1 Self-Relative Fixup + +A self-relative fixup works as follows: Location implicitly defines a +memory address\(emnamely, the address of the byte following Location +(because at the time of a self-relative reference, the 8086 IP (Instruction +Pointer) is pointing to the byte following the reference). + +For 8086 self-relative references, if either the Location or the target is out- +side the specified frame, the linker gives a warning. Otherwise, there is a +unique l6-bit displacement that, when added to the address implicitly +defined by Location, yields the relative position of the target in the frame. + + o If Location is an offset, the linker adds the displacement to Loca- + tion (modulo 65,536) and reports no errors. + + o If Location is a lobyte, the displacement must be within the range + {-128:127}; otherwise, the linker gives a warning. The linker adds + the displacement to Location (modulo 256). + + o If Location is a base, pointer, or hibyte, it is unclear what the + translator intended, so the linker's action is undefined. + + +7.3.2 Segment-Relative Fixup + +A segment-relative fixup operates as follows: a nonnegative 16-bit number, +FBVAL, is defined as the frame number of the frame or selector value that +the fixup specifies. A signed 20-bit number, FOVAL, is defined as the dis- +tance from the base of the frame to the target. If this signed 20-bit +number is less than 0 or greater than 65,535, the linker reports an error. +Otherwise, the linker uses FBVAL and FOVAL to fix up Location in the +following fashion: + + o If Location is a pointer, the linker adds FBVAL (modulo 65,536) to + the high-order word of pointer, and adds FOVAL (modulo 65,536) + to the low-order word of pointer. + + + + 13 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + o If Location is a base, the linker adds FBVAL (modulo 65,536) to + the base and ignores FOVAL. + + o If Location is an offset, the linker adds FOVAL (modulo 65,536) to + the offset and ignores FBVAL. + + o If Location is a hibyte, the linker adds (FOVAL/256) (modulo 256) + to the hibyte and ignores FBVAL. (The division indicated is + integer division; that is, the linker discards the remainder.) + + o If Location is a lobyte, the linker adds (FOVAL modulo 256) + (modulo 256) to the lobyte and ignores FBVAL. + + +7.4 Record Sequence + +A object code file must contain a sequence of (one or more) modules, or a +library containing zero or more modules. The following syntax shows the +valid record ordering necessary to form a module. In addition, the given +semantic rules provide information about how to interpret the record +sequence. + +_ ________________________________________________________________ + +Note + + The description language used in the following syntax is defined in + WIRTH: CACM, November 1977, vol. 20, no. 11, pp. 822-823. The + character strings represented by capital letters are not literals but + identifiers, and are further defined in the record format section. + +_ ________________________________________________________________ + +object file = tmodule + +tmodule = {THEADR | LHEADR} seg-grp {component} modtail + +seg_grp = {LNAMES} {SEGDEF} {EXTDEF | GRPDEF} + +component = data | debug_record + +data = content_def | thread_def | + PUBDEF | EXTDEF | COMDEF | LOCSYM + +debug_record = LINNUM + +content_def = data_record {FIXUPP} + +thread_def = FIXUPP (containing only Thread fields) + +data_record = LIDATA | LEDATA + + +14 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + +modtail = MODEND + +The following rules apply: + + o A FIXUPP record always refers to the previous data record. + + o All LNAMES, SEGDEF, GRPDEF, and EXTDEF records must pre- + cede all records that refer to them. + + o Comment records may appear anywhere in a file, except as the first + or last record in a file or module, or within a content_def. + + +7.5 Introducing the Record Formats + +The following pages present diagrams of record formats in schematic form. +Here is a sample record format that illustrates the various conventions: + +7.5.1 Sample Record Format (SAMREC) + + +-----------------------///---------||||----------- +| | | | | | +| REC | Record | Name | Number | CHK | +| TYP | Length | | | SUM | +| xxH | | | | | +| | | | | | +----------------------///----------||||----------- + | | + +----rpt-----+ + + +The Title and Official Abbreviation + +At the top of the figure is the name of the record format described, with +its official abbreviation. To promote uniformity among various programs, +including translators and debuggers, use the abbreviation in both code and +documentation. The abbreviation of the record format is always six +letters. + +The Boxes + +Each format is drawn with boxes of two sizes. The narrow boxes represent +single bytes. The wide boxes each represent two bytes. The wide boxes +with three slashes in the top and bottom represent a variable number of +bytes, one or more, depending upon content. The wide boxes with four +vertical bars in the top and bottom represent four-byte fields. + + + 15 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +RECTYP + +The first byte in each record contains a value between 0 and 255, indicat- +ing the record type. + +Record Length + +The second field in each record contains the number of bytes in the record, +exclusive of the first two fields, where a field is a 16-bit number\(ema low +byte followed by a high byte. + +Name + +Any field that indicates a name has the following internal structure: the +first byte contains a number between 0 and 127, inclusive, indicating the +number of remaining bytes in the field. The remaining bytes are inter- +preted as a byte string. + +Most translators constrain the character set to a subset of the ASCII char- +acter set. + +Number + +A four-byte number field represents a 32-bit unsigned integer, where the +first eight bits (least-significant) are stored in the first byte (lowest +address), the next eight bits are stored in the second byte, and so on. + +Repeated or Conditional Fields + +Some portions of a record format contain a field or series of fields that +may be repeated one or more times. Such portions are indicated by the +"repeated" or "rpt" brackets below the boxes. + +Similarly, some portions of a record format are present only if some given +condition is true; these fields are indicated by similar "conditional" or +"cond" brackets below the boxes. + +CHKSUM + +The last field in each record is a check sum, which contains the two's com- +plement of the sum (modulo 256) of all other bytes in the record. There- +fore, the sum (modulo 256) of all bytes in the record is zero. + + +16 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + + +Bit Fields + +Sometimes descriptions of contents of fields are at the bit level. Boxes +with vertical lines drawn through them represent bytes or words; the verti- +cal lines indicate bit boundaries. Thus, the following byte representation +has three bit fields of three, one, and four bits, respectively. + +--------------------------------- +| | | | | | | | | +| | | | +| | | | | | | | | +--------------------------------- + 3 1 4 + + +7.5.2 T-Module Header Record (THEADR) + + +-----------------------///----------- +| | | | | +| REC | Record | T- | CHK | +| TYP | Length | Module | SUM | +| 80H | | Name | | +| | | | | +----------------------///------------ + + +T-Module Name + +The T-Module Name field contains the name for the T-module. + +7.5.3 L-Module Header Record (LHEADR) + + +-----------------------///----------- +| | | | | +| REC | Record | L- | CHK | +| TYP | Length | Module | SUM | +| 82H | | Name | | +| | | | | +----------------------///------------ + + +L-Module Name + +The L-Module Name field contains the name for the L-module. + +Every module output from a translator must have a T-module or L-module +header record. The linker requires a THEADR or LHEADR record to come +first in the module and ignores any others. The LHEADR record is identi- +cal to the THEADR record, except it has a record type of 82H. + + + 17 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +7.5.4 List of Names Record (LNAMES) + + +-----------------------///----------- +| | | | | +| REC | Record | Name | CHK | +| TYP | Length | | SUM | +| 96H | | | | +| | | | | +----------------------///------------ + | | + +----rpt-----+ + +The LNAMES record contains a list of names that the following SEGDEF +and GRPDEF records may use as the names of segments, classes, and/or +groups. + +The order of LNAMES records in a module and the order of names within +each LNAMES record imply a mapping of these names to numbers: 1, 2, 3, +etc. These numbers are used as "Name Indices" in the Segment Name +Index, Class Name Index, and Group Name Index fields of the SEGDEF +and GRPDEF records. + +Name + +This repeatable field provides a name, which may have zero length. + +7.5.5 Segment Definition Record (SEGDEF) + + +-----------------///-----------------///-----///---///------ +| | | | | | | | | +|REC| Record | Segment | Segment | Segment |Class|Over |CHK| +|TYP| Length | ATTR | Length | Name |Name |Lay |SUM| +|98H| | | | Index |Index|Name | | +| | | | | | |Index| | +-----------------///-----------------///-----///---///------ + +Segment index values 1 through 32,767, which are used in other record +types to refer to specific LSEGs, are defined implicitly by the sequence in +which SEGDEF records appear in the object file. + +SEG ATTR + +The SEG ATTR field provides information on various attributes of a seg- +ment, and has the following format: + +------------------------ +| | | | +| ACB | Frame | Off- | + +18 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + +| P | Number | Set | +| | | | +| | | | +-------------r---------- + | | + +---conditional--+ + +The ACBP byte contains four numbers\(emthe A, C, B, and P attribute +specifications. This byte has the following format: + +--------------------------------- +| | | | | | | | | +| A | C | B | P | +| | | | | | | | | +--------------------------------- + +A (Alignment) is a 3-bit subfield that specifies the alignment attribute of +the LSEG. The semantics are defined as follows: + +_ ________________________________________________________________ + +A=0 SEGDEF describes an absolute LSEG. + +A=1 SEGDEF describes a relocatable, byte-aligned LSEG. + +A=2 SEGDEF describes a relocatable, word-aligned LSEG. + +A=3 SEGDEF describes a relocatable, paragraph-aligned LSEG. + +A=4 SEGDEF describes a relocatable, page(256-byte)-aligned LSEG. + +If A=0, the Frame Number and Offset fields are present. With the Micro- +soft linker, you may use absolute segments for addressing only; for exam- +ple, to define the starting address of a ROM and to define symbolic names +for addresses within the ROM. The linker ignores any data that belongs +to an absolute LSEG, and issues a warning if absolute segments are +defined for a program that runs in protected mode. + +C (Combination) is a 3-bit subfield that specifies the Combination attri- +bute of the LSEG. Absolute segments (A=0) must have combination zero +(C=0). For relocatable segments, the C field encodes a number +(0,1,2,3,4,5,6, or 7) that indicates how the segment can be combined. One +way to interpret this attribute is to consider how two LSEGs are com- +bined. + +For example, suppose that X and Y are LSEGs, and that Z is the LSEG +resulting from the combination of X and Y. Let LX and LY be the lengths +of X and Y, and let MXY denote the maximum of LX, LY. Now, to accom- +modate the alignment attribute of Y, let G be the length of any gap +required between the X and Y components of Z. Then, let LZ denote the +length of the (combined) LSEG, Z; let dx (0\(<=dx "=" hangs the system. + + Not only = in quotes but any delimitor causes problems. + + This comes from a basic lack of consistency in the treatment + of the role of the " character. In command line parsing anything + between " ----- " is not interpreted. But in forming filenames + a " is taken as a valid character. Once the '>' character is + reached the parser begins forming the filename and takes " as + the first character. The following = is taken as a delimitor and + the filename ended. When the filename is formed the processing + returns to the command line parsing main routine and sees the + next ". After this it just moves anything that comes along till + it meets the next quote and ends up destroying the stack. + + Solution: changed filename parsing code to test for quote and decrement + the number of quotes. File changed - tmisc1.asm + + + ************************************************************************ + + Problem: DOS FDISK creates partition which overlaps Xenix partition. + + Create bad track table (xenix) and then a xenix partition + which occupies whole disk. then boot dos and create partiton + asking it to use all of the space for dos. It just does that + overlapping the partition over the xenix partition. + + Problem: 3.3 fdisk was not handling the no space condition. + + Solution: + + added code to detect no space condition and report error on + such a condition. files changed fdisk.c and space.c. also + when dos tries to create primary partition with a space + requested from the user added error message when there is + no space. + + + ************************************************************************ + + Problem: + + The bug is that the routine make_partition had been checking for a free + "slot" in the Master Boot Record and aborting the menu if there was none. + This action is not desirable if the user wishes to create a Logical DOS + volume in an existing Extended DOS Partition. + + There are several circumstances where this problem becomes evident. + Probably the most common problem would be experienced on a large hard disk with several + DOS partitions defined on it (COMPAQ is not the only OEM to support + multiple DOS partitions on a hard disk...). + + Consider a disk with 4 DOS partitions defined on it and the user wants to + delete ONE of the DOS partitions so that an Extended DOS partition may be + defined. After doing this, the ext_create_partition routine allows the + user to define logical DOS volumes. + + The user decides that the Logical DOS Volumes he previously created are not + satisfactory after having left FDISK, perhaps he had previously defined + only one Logical DOS Volume and it did not use the entire Extended + Partition. + + This time FDISK will not allow the user to select the Create Logical + Volume menu option because there are no free "slots" in the Master Boot + Record although there may well be plenty of space within the Extended DOS + partition. + + NOTE: This problem also occurs with the OS/2 implementation of FDISK. + + + ************************************************************************* + + Problem: Extend file handle count is broken. + + Solution: The para calculation code in handle.asm to calculate the number + of paragraphs needed is coded wrongly. For handle values + less than a para away from the maximum this will cause a carry. + The subsequent rotate by 4 should shift the carry in. IBM 3.3 + doesn't use the appropriate rotate instruction. + + ************************************************************************** + + Problem: Disk info initialisation in extended volume wrongly done. + + The problem involves creation of Logical DOS Volumes in + an Extended DOS Partition. As you know, each Logical DOS Volume + has a "dummy" Master Boot Record which is necessary to define + the extent of its Logical Volume and to indicate the location of + the next Logical Volume (if one exists). The "dummy" Master + Boot Record for each Logical Volume (except the last one) + contains an entry with a system indicator byte with the value of + 5 - this is the pointer to the next volume. The END_HEAD number + of this type 5 record is ONE greater than the greatest physical + head number on the drive. + + + This occurs because the entries in the "max_head" array are + initialized to be one more than the greatest physical head + number in the routine "get_disk_info()" in the file INT13.C for + use in calculations. The routine "write_ext_boot_to_disk" in + the file DISKOUT.C does not subtract one from the max_head value + before placeing it into the extended boot record - which is what + results in the "End_Head" field being wrong for the type 5 + record. + + The line in "write_ext_boot_to_disk" where the subtraction + should take place is shown below... + + /* End head */ + boot_record[0x1D3] = max_head[disk]; + + Solution: As mentioned above the line given above should be + boot_record[0x1d3] = max_head[disk] - 1; diff --git a/README.DIS b/README.DIS new file mode 100644 index 0000000..707d8f6 --- /dev/null +++ b/README.DIS @@ -0,0 +1,776 @@ + SUPPLEMENT TO MS-DOS 2.XX/3.XX ADAPTATION GUIDE + + DOCUMENTATION FOR THE MS-DOS 3.30 DISTRIBUTION DISKETTES + +This documentation consists of release layout information, a diskette +directory, instructions for use, and a list of differences between the +CLONE VERSION and the MS VERSION. + +1. MS-DOS 3.30 RELEASE LAYOUT + +------------------------------------------------------------------------------ +| SOURCE CODE | +| | +| 10 96 TPI diskettes | +| readme.src | +| Not generally available to OEMS - For Customer Support/Maintenance | +------------------------------------------------------------------------------ + [] [] [] [] [] + [] [] [] [] [] + SWITCHES SET FOR SWITCHES SET FOR SWITCHES SET FOR + MS VERSION CLONE VERSION CLONE VERSION + [] [] [] [] [] + \[]/ [] \[]/ [] [] + \/ [] \/ [] BUGFIXES +------------------- [] ------------------- [] APPLIED +| | [] | | [] [] +| MS VERSION | [] | CLONE VERSION | [] [] +| SUPPLEMENTAL | [] | MESSAGE MODULES | [] [] +| MESSAGE MODULES | [] | | [] [] +| | [] | For all files | [] [] +| COMMAND.COM | [] | except for those| [] [] +| DEBUG.EXE | [] | with complete | [] [] +| MORE.COM | [] | source on the | [] [] +| RECOVER.EXE | [] | CLONE VERSION | [] [] +| SHARE.EXE | [] | DISTRIBUTION | [] [] +| MSDOS.SYS | [] | DISKETTES | [] [] +| | [] | readme.mes | [] [] +|1 96 TPI diskette| [] |1 96 TPI diskette| [] [] +|avail. on request| [] |avail. on request| [] [] +------------------- [] ------------------- [] [] + [] [] [] [] [] + \[]/ \[]/ \[]/ \[]/ \[]/ + \/ \/ \/ \/ \/ +------------------------ ------------------------- ------------------------- +| | | | | | +| MS VERSION | | CLONE VERSION | |MICROSOFT MS-DOS 3.30 | +| SUPPLEMENTAL | | DISTRIBUTION DISKETTES| | PACKAGED PRODUCT | +| DISTRIBUTION DISKETTE| | readme.dis | | | +| 1 96 TPI diskette | | 2 96 TPI diskettes | | 2 48 TPI DISKETTES | +| Available on request | | In OEM Adaptation Kit | | In OEM Adaptation Kit : +------------------------ ------------------------- ------------------------- + ------------------------- + | BUGFIX DISKETTE | + | FIXES THAT MAY BE | + |APPLIED TO MS-DOS 3.30 | + | readme.bf | + | 1 96 TPI diskette | + | In OEM Adaptation Kit | + ------------------------- + + + + Additional Materials that are part of the OEM Adaptation Kit: + + 2.XX/3.XX Adaptation Guide 1 96 TPI diskette + + Machine Readable Documentation + User's Guide/User's Reference 2 96 TPI diskette + Programmer's Reference + + Hard Copy Documentation + User's Guide + User's Reference + Programmer's Reference + + + Additional Material that is available on request through an OEM's + OEM Account Manager: + + 1. Undocumented System Calls Information + 2. Microsoft MASM 4.00 Retail Package + +(Most OEMS either already have these two items or do not have a use for them) + + +The CLONE VERSION DISTRIBUTION DISKETTES contain the files that were produced +from MS-DOS SOURCE CODE assembled with the IBMVER switch on but the +IBMCOPYRIGHT switch off. They contain full SOURCE CODE to IO.SYS, MSBOOT, +FORMAT.EXE, PRINT.EXE, SORT.EXE and partial source code to MSDOS.SYS to allow +for the customization of DOSMES.INC. MSDOS32101 is a bootable disk. + +The MS VERSION SUPPLEMENTAL DISKETTE contains files that were produced from +MS-DOS SOURCE CODE assembled with the MS-VER switch on and the IBMVER and +IBMCOPYRIGHT switch off. They contain the executables for the four files DEBUG, +MORE, RECOVER and SHARE as well as partial source for MSDOS.SYS to allow for +its customization. These are all the files with version switches in them except +for the files with complete source on the CLONE VERSION. + +The MS-DOS 3.30 PACKAGED PRODUCT contains file that were produced from MS-DOS +SOURCE CODE assembled with the IBMVER switch on but the IBMCOPYRIGHT +switch off. These two disks that are identical to the disks in the manufactured +packaged product. There is a boot disk and supplemental disk. + +The CLONE VERSION MESSAGE MODULES contain all the source code that must be +modified for translation to a language other than English. +These message source modules can be modified, then assembled and linked with the +object modules that are provided to make the executables. The object modules +in this release were made from MS-DOS SOURCE CODE assembled with IBMVER switch +on and the MSVER and IBMCOPYRIGHT switches off. Code is provided to make all +the executables on the CLONE VERSION DISTRIBUTION DISKETTES except for +the files that have complete source provided on the CLONE VERSION DISTRIBUTION +DISKETTES: IO.SYS, MSBOOT.BIN, FORMAT.EXE, PRINT.EXE, SORT.EXE, SYS.COM, and +MSDOS.SYS (partial source). + +Microsoft now offers complete translations including documentation for the +following languages: French, German, Spanish, Portuguese, Italian and Dutch. +OEMs who would like one or more of these translations added to their OEM +contract should contact their Microsoft OEM Account Manager. + +MS VERSION SUPPLEMENTAL MESSAGE MODULES contain all the source code that +must be modified for translation to a language other than English for the +six files: COMMMAND.COM, DEBUG.EXE, MORE.COM, RECOVER.EXE, SHARE.EXE and +MSDOS.SYS. They are used the same way as the CLONE VERSION MESSAGE MODULES, +except the the files they are linked to have been assembled with the +MSVER switch on. + +The MS-DOS CLONE VERSION DISTRIBUTION DISKETTES, and the PACKAGE PRODUCT +DISKETTES are provided as a part the MS-DOS 3.30 Standard OEM ADAPATION KIT. + +The CLONE VERSION MESSAGE MODULES, the MS VERSION SUPPLEMENTAL MESSAGE MODULES +and the MSVER SUPPLEMENTAL DISTRIBUTION DISKETTE, MODULES may be available to +an OEM under special conditions by request through their Microsoft OEM Account +Manager. + +The SOURCE CODE release is not generally available to OEMS, however, it is +archived for support purposes by OEM Customer Support. + +The BUGFIX DISKETTE contains code that fixes certain known problems in the +MS-DOS 3.30 Release. These fixes have been applied to the MS-DOS 3.30 +PACKAGED PRODUCT, but were not applied to the the MS-DOS 3.30 OEM Release +to maintain IBM COMPATIBILITY. An OEM can use this code to apply these +bugfixes to their product. The specific bugs are described in the release +notes and in the the README.BF file on the BUGFIX DISKETTE. + + + +2. Diskette Directories + +MS-DOS 3.20 CLONE VERSION DISTRIBUTION DISKETTES MS330DIS01 + +io.sys system file - BIOS +msdos.sys system file - DOS +command.com command interpreter + +distrib\bin + +append.com utility to set a search path for data files +assign.com utility to assign a drive letter to a different drive +attrib.exe utility to change or display a file's attribue (read/read only) +backup.com utility to backup one or more files from one disk to another +chkdsk.com utility to scan disks, check for allocation errors & repair them +debug.com utility for debugging +diskcomp.com utility to compare to contents of one disk with another +diskcopy.com utility to copy disks formatting when necessary +edlin.com line editor +exe2bin.exe utility to convert .EXE files to .COM files +fdisk.com utility to configure hard disk +find.exe filter to find text strings in files +format.com utility to format disks +graftabl.com graphic character generation driver +graphics.com utility to print a graphics display on a printer +join.exe utility to join a drive to a specific pathname +keyb.com utility to replace ROM resident english keyboard program with + non-english keyboard program +label.exe utility to change or create a disk volume ID +link.exe linker 2.40 (part of the MS-DOS 3.30) product +mode.com utility to configure parallel and serial ports +more.com utility to send output to the console one screen at a time +nlsfunc.exe utiltiy to provide support for extended country information +print.com utility to print text files on a line printer +recover.com utility to recover disk directory +replace.exe utility to update previous verison on files on a disk +restore.exe utility to restore files that were backed up with backup.exe +share.exe utility to install file sharing and locking +sort.exe utility to read standard input, sort data and write to a device +subst.exe utility to substitute a string alias for a pathname +sys.com utility to transfer msdos system files +tree.com utility to display the directory structure & contents of a drive +xcopy.exe utility to copy files, directories and lower level directories + + +dev + +ansi.sys installable console device driver +country.sys used to identify the date, time, collating sequence, + capitalization and folding format for a given country +display.sys allows use of code page switching for the display +driver.sys installable device driver to support external drives +keyboard.sys allows use of code page switch for the keyboard +printer.sys allows use of code page switching for the printer +ramdrive.sys installable RAM disk device driver +vdisk.sys installable RAM disk device driver + +src + +makefile builds all CLONE VERSION DISTRIBUTION buildables + +src\bios + +biomes.inc io.sys include file +biostruc.inc io.sys include file +clocksub.inc io.sys include file +cmosequ.inc io.sys include file +dskprm.inc io.sys include file +jumpmac.inc io.sys include file +locscr exe2bin location script +makefile io.sys link script +ms96tpi.inc io.sys include file +msaux.asm io.sys source file +msbds.inc io.sys include file +msbio.lnk msbio.link script +msbio1.asm io.sys source file +msbio2.asm io.sys source file +msclock.asm io.sys source file +mscon.asm io.sys source file +msdata.inc io.sys include file +msdisk.asm io.sys source file +msequ.inc io.sys include file +msextrn.inc io.sys include file +msgroup.inc io.sys include file +mshard.asm io.sys source file +msinit.asm io.sys source file +msioctl.inc io.sys include file +msload.asm io.sys source file +msload.inc io.sys include file +mslpt.asm io.sys source file +msmacro.inc io.sys include file +msstack.inc io.sys include file +msvolid.inc io.sys include file +pushpop.inc io.sys include file +readcloc.inc io.sys include file +stkinit.inc io.sys include file +stkmes.inc io.sys include file +sysconf.asm io.sys source file +sysimes.asm io.sys source file - message text +sysimes.inc io.sys include file +sysinit1.asm io.sys source file - system initialization +sysinit2.asm io.sys source file - system initialization + + + +src\boot + +boot.inc msboot include file +boot11.inc msboot include file +makefile msboot make file +messages.inc msboot message file +msboot.asm msboot source file +msboot.bin boot sector + + + +MS-DOS 3.20 CLONE VERSION DISTRIBUTION DISKETTES MS320DIS02 + +src\cmd\format + +bootmes.inc format include file +format.asm format generic source file +format.lnk format link script +forproc.asm format source file +make_inc.bas BASIC program to establish system size - makes filesize.inc +makefile makefile for format.com +messages.asm format message source file +messages.inc format include file +oemfor.asm format OEM specific source file + + +src\cmd\print + +makefile makefile for print.com +nprintf.asm print source file +pridefs.inc print include file +print.lnk print link script +print_r.asm print resident source code +print_rm.asm print resident message source code +print_rm.inc print resident include file +print_t.asm print transient source code +print_tm.asm print transient message source code +print_tm.inc print transient include file + + +src\cmd\sort + +makefile make file for sort.exe +messages.asm sort message file +sort.asm sort source file +sort.lnk sort link response file + + +src\cmd\sys + +build.bat batch file to build sys.exe +messages.asm sys message file +sys.asm sys source file +sys.lnk sys link response file + +src\dos + +abort.obj msdos.sys object module +alloc.obj msdos.sys object module +arena.inc msdos.sys include file +bpb.inc msdos.sys include file +buf.obj msdos.sys object module +buffer.inc msdos.sys include file +close.obj msdos.sys object module +const2.obj msdos.sys object module +cpmfcb.inc msdos.sys include file +cpmio.obj msdos.sys object module +cpmio2.obj msdos.sys object module +create.obj msdos.sys object module +crit.obj msdos.sys object module +curdir.obj msdos.sys object module +delete.obj msdos.sys object module +dev.obj msdos.sys object module +devsym.inc msdos.sys include file +dinfo.obj msdos.sys object module +dir.obj msdos.sys object module +dir2.obj msdos.sys object module +dircall.obj msdos.sys object module +dirent.inc msdos.sys include file +disk.obj msdos.sys object module +disk2.obj msdos.sys object module +disk3.obj msdos.sys object module +divmes.inc msdos.sys include file +doscntry.inc msdos.sys include file +dosmac.inc msdos.sys include file +dosseg.inc msdos.sys include file +dossym.inc msdos.sys include file +dpb.inc msdos.sys include file +dpl.inc msdos.sys include file +dup.obj msdos.sys object module +error.inc msdos.sys include file +exe.inc msdos.sys include file +fat.obj msdos.sys object module +fcb.obj msdos.sys object module +fcbio.obj msdos.sys object module +fcbio2.obj msdos.sys object module +file.obj msdos.sys object module +filemode.inc msdos.sys include file +find.inc msdos.sys include file +finfo.obj msdos.sys object module +getset.obj msdos.sys object module +handle.obj msdos.sys object module +intnat.inc msdos.sys include file +ioctl.inc msdos.sys include file +ioctl.obj msdos.sys object module +isearch.obj msdos.sys object module +lock.obj msdos.sys object module +macro.obj msdos.sys object module +macro2.obj msdos.sys object module +makefile msdos.sys makefile +mi.inc msdos.sys include file +misc.obj msdos.sys object module +misc2.obj msdos.sys object module +mknode.obj msdos.sys object module +msdos.lnk msdos.sys link script +mult.inc msdos.sys include file +nibdos.obj msdos.sys object module +open.obj msdos.sys object module +parse.obj msdos.sys object module +path.obj msdos.sys object module +pdb.inc msdos.sys include file +proc.obj msdos.sys object module +rename.obj msdos.sys object module +rom.obj msdos.sys object module +search.obj msdos.sys object module +sf.inc msdos.sys include file +share.obj msdos.sys object module +smdossym.inc msdos.sys include file +srvcall.obj msdos.sys object module +stdcode.obj msdos.sys object module +stdctrlc.obj msdos.sys object module +stddata.obj msdos.sys object module +stddisp.obj msdos.sys object module +stddosme.asm msdos.sys source file +stddosme.obj msdos.sys object module +stdsw.inc msdos.sys include file +stdtable.obj msdos.sys object module +syscall.inc msdos.sys include file +sysvar.inc msdos.sys include file +time.obj msdos.sys object module +util.obj msdos.sys object module +vector.inc msdos.sys include file + + + +src\inc + +macro.inc general msdos include file +struc.inc general msdos include file +version.inc general msdos include file +versiona.inc general msdos include file + + + +src\libc + +The files in this directory are needed when linking various msdos files. + +cds.obj +dpb.obj +errtst.obj +itoupper.obj +join.c +kstring.c +printf.asm +string.c +sysvar.c + + +tools + +The files in this directory are used to make the parts of the MSDOS product. +None of these files(except exe2bin.exe), however are part of the MS-DOS product +and they should not be supplied to an OEM's customers. + +convert.exe special file to change certain .EXE files to .COM files +dbof.exe used to insure that boot record is located proper on disk +exe2bin.exe same as exe2bin.exe in product - it is included here as + as a convenience +exefix.exe used by some makefiles to convert .EXE files to .COM files +gwbasic.exe same gwbasics as in packaged procduct. It is used by the + makefile in format - it is included here as a convenience +link.exe linker used to build msdos +masm.exe masm.exe from Retail Macro Assember 4.00 Product +masm401.exe special masm used to build IO.SYS +msmake.exe make utility - renamed msmake to distinquish it from XENIX make + +3. Instruction for use. + +The MS-DOS release installation procedure is described in Chapter 3 of +the MS-DOS 2.XX/3.XX adaptation guide. + +It is recommended that the DISTRIBUTION DISKETTES be copied over +to a hard disk with the XCOPY.EXE command. This will set up +a directory tree that the makefiles can use properly. All the +buildables on the DISTRIBUTION DISKETTES can be built by setting +the PATH to SRC\TOOLS and running the MAKEFILE in the SRC directory. +It is important that the file be built in the order that they are +by this makefile as there are some dependencies on former builds +having occurred. + +It is also recommended that MS-DOS 3.30 is installed on the build +machine and that the build occurs under MS-DOS 3.30. This will +insure that any version dependent tools will perform properly. MS-DOS +3.30 can be installed on the build machine by booting from the floppy +with the boot disk from either the DISTRIBUTION DISKETTES or the PACKAGED +PRODUCT and then using the SYS command or FORMAT /S to get the system to the +hard disk. + +System Filenames are MSDOS.SYS and IO.SYS in FORMAT and SYS. + +FORMAT.EXE and SYS.COM have the boot sector installed with INSBIN.EXE. + +The OEM NUMBER is FF. + +Build Scripts require that the files EXE2BIN.EXE and DEBUG.EXE be in the PATH. + +The 8-bit OEM Serial number may be installed with DEBUG by patching MSDOS.SYS +at location 355H (455 under DEBUG). + +The 24-bit OEM User number may be installed with DEBUG by patching MSDOS.SYS +at location 352H (452 under DEBUG). + +SYSINIT LINK REQUIREMENTS. + + SYSINIT1.obj now requires an external FAR routine called StackInit + to be linked. This routine has available to it the parameters + + STACK_ADDR: DWORD + STACK_SIZE: WORD + STACK_COUNT: WORD + + + StackInit initializes the Stack Heap and corresponding interrupt + vectors used to handle potential hardware driven stack overflows. + After completing its task, StackInit issues a RETF to return to + SYSINIT1. + To use the IBM compatible SYSINIT1, the OEM must + provide the FAR ROUTINE StackInit, whose only task is to issue a + RETF. + + +The CONVERT utility is provided in the TOOLS directory to +rename certain .EXE utilties as .COM files if desired. The CONVERT utility +is not part of the MS-DOS product and should be used only as +described as follows: + + +Documentation for CONVERT.EXE + +CONVERT is used by entering CONVERT and an .EXE file name (with the .EXE +extension). + +CONVERT FOO.EXE + + will build a FOO.COM file + + +CONVERT adds an .EXE loader onto the .EXE file image + +It should not be confused with EXE2BIN.EXE + +These are the differences: + +EXE2BIN + + - EXE2BIN is a utility for converting .EXE files to binary (.COM). + + - EXE2BIN produces a .COM file which is smaller than the .EXE file. + + - EXE2BIN may only convert files conforming to a certain documented set of + requirements. + + - EXE2BIN can only be used on a file written as .COM file (ORG 100h, not + stack segment). + + +CONVERT + + - CONVERT transforms an .EXE file into a .COM file by appending the + MS-DOS loader to the end of the file. + + - A CONVERTed file will be larger than an equivalent .EXE file. + + - CONVERT will convert ANY .EXE program. + + - CONVERT should only be used in UNUSUAL circumstances, such as when + an application program demands that a file have a .COM extension. + + + +4. Differences in the files in the MS VERSION and CLONE VERSION of MS-DOS + +This is a complete list of the differences between the MS VERSION and the +CLONE VERSION of MS-DOS at the 3.XX level. It is intended to illustrate how +few the differences actually are. These differences occur as a result of +conditional assemblies based on whether MSVER or IBMVER is TRUE at the time +of assembly. + + CLONE VERSION MS VERSION +DOS +================================================================== + +OEM_HANDLER OEM_HANDLER code OEM_HANDLER code + for call F8 NOT included for call F8 included + +DOS header IBM Text MSDOS text + +Print of DOS NO YES + version at + boot time + +INT 25,26 AH YES NO + error code + mapping + +International Large set US table only + tables + +Case map call IBM PC specific None + in internat + tables + +Function Key IBM PC Z-19 (Zenith terminal) + definition + +^N defined as NO YES + special char + equivalent + to ^P + +****************************************************************** + + CLONE VERSION MS VERSION +SHARE +================================================================== + + NOTE: The MS VERSION and CLONE VERSION do have minor + differences and will not file compare. The differences + have to do with the DOS data modules linked in with SHARE. + The CLONE VERSION SHARE, MSDOS and REDIR should be used only with + each other and the MS VERSION SHARE, MSDOS and REDIR should be + used only with each other. + +***************************************************************************** + + CLONE VERSION MS VERSION +COMMAND +================================================================== + +CLS Special IBM code to detect Assumes ANSI support, + if ANSI driver installed. outputs ANSI CLS sequence. + If no ANSI driver, CLS done + by direct calls to INT 10H + +ROM exec Special code for PC-Jr ROM No ROM exec code + cartridges. + + +***************************************************************************** + + CLONE VERSION MS VERSION +PRINT +================================================================== + INT 17,13,14,5,15 handlers No special handlers + + IBM specific timer int code No timer int code + + NOTE: SOURCE CODE FOR PRINT IS SENT SO THAT + OEMs CAN PORT THEM TO THEIR MACHINES. + + NOTE: SETTING THE IBM SWITCHES TO TRUE IN PRINT + WILL NOT YIELD A BINARY THAT IS THE SAME AS THE IBM + 3.2 . + + In PRINT's case this is due to some slight code + re-organization that was needed to get a valid + PRINT with the IBM switches set to FALSE. + + +***************************************************************************** + + CLONE VERSION MS VERSION +DEBUG +================================================================== +INT controler Contains code to twiddle No code included + one of the 8259 interrupt + controller registers to + fix the trace of the timer + int problems + +Screen Width Issues INT 10H to get Assumes screen is at + screen width. least 80 column + +***************************************************************************** + + CLONE VERSION MS VERSION +FORMAT +================================================================== + MS VERSION CLONE VERSION + ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +SYS +================================================================== + +Put Boot Contains Boot sector No put boot code + output code to put + correct boot sectors + on SYSed disks + +Check for valid Uses INT 25 to make sure Minimal checking of +destination that destination disk is MSDOS.SYS size + empty or has correct IBM + bootable disk format + +***************************************************************************** + + CLONE VERSION MS VERSION +RECOVER +================================================================== +ROM COM AREA Twiddles a byte in the ROM No code +TWIDDLE communication area on single + drive systems to indicate + drive changed. + +***************************************************************************** + + CLONE VERSION MS VERSION +EXE2BIN +================================================================== + MS VERSION CLONE VERSION + ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +CHKDSK +================================================================== + MS VERSION CLONE VERSION + ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +FIND +================================================================== + MS VERSION CLONE VERSION + ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +ASSIGN +================================================================== + MS VERSION CLONE VERSION + ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +ATTRIB +================================================================== + MS VERSION CLONE VERSION + ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +SUBST +================================================================== + MS VERSION CLONE VERSION +* ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +JOIN +================================================================== + MS VERSION CLONE VERSION + ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +EDLIN +================================================================== + MS VERSION CLONE VERSION + ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +MORE +================================================================== +Screen Width Issues INT 10H to get Assumes screen is + width of screen at least 80 column + +Non printing Assumes all chars < 20H Assumes chars < 20H +chars except for BELL (07) are are non printing and + printing characters which do not advance the + advance the cursor one cursor if output + position if output. + +***************************************************************************** + + CLONE VERSION MS VERSION +SORT +================================================================== +Internat chars Defines coalating sequence Chars > 7FH are sorted + for some chars > 7FH approp in value order + to IBM international char + sets + +***************************************************************************** + + CLONE VERSION MS VERSION +BIOS (SYSINIT) +================================================================== +MEM scan Mem scan code not included Includes memory scan + Assumes BIOS sets memory code if OEM BIOS + size variable always. does not set memory + size variable. diff --git a/SRC/BIOS/BIOMES.INC b/SRC/BIOS/BIOMES.INC new file mode 100644 index 0000000..06deb2a --- /dev/null +++ b/SRC/BIOS/BIOMES.INC @@ -0,0 +1,31 @@ + + ;;Rev 3.30 Modification +; SINGLE DRIVE MESSAGE FOR BIOS. NUL TERMINATED. +IFNDEF PATHSTART +PATHSTART MACRO INDEX,ABBR + IFDEF PATHGEN + PUBLIC ABBR&INDEX&S,ABBR&INDEX&E + ABBR&INDEX&S LABEL BYTE + ENDIF + ENDM +ENDIF + +IFNDEF PATHEND +PATHEND MACRO INDEX,ABBR + IFDEF PATHGEN + ABBR&INDEX&E LABEL BYTE + ENDIF + ENDM +ENDIF + + PATHSTART 001,BIOMS + +; +; Single drive message for msbio.com. Nul terminated. ;;End of Modification +; + +SNGMSG DB CR,LF,"Insert diskette for drive " +DRVLET DB "A: and strike",CR,LF,"any key when ready",CR,LF,LF,0 + + PATHEND 001,BIOMS + \ No newline at end of file diff --git a/SRC/BIOS/BIOSTRUC.INC b/SRC/BIOS/BIOSTRUC.INC new file mode 100644 index 0000000..25f73d2 --- /dev/null +++ b/SRC/BIOS/BIOSTRUC.INC @@ -0,0 +1,87 @@ + + + ;;Rev 3.30 Modification +; ROM BIOS CALL PACKET STRUCTURES + +;******************************* +;System Service call ( Int 15h ) +;******************************* +;Function AH = 0C0h, Return system configuration +;For PC and PCJR on return: +; (AH) = 80h +; (CY) = 1 +;For PCXT, PC PORTABLE and PCAT on return: +; (AH) = 86h +; (CY) = 1 +;For all others: +; (AH) = 0 +; (CY) = 0 +; (ES:BX) = pointer to system descriptor vector in ROS +; System descriptor : +; DW xxxx length of descriptor in bytes, +; minimum length = 8 +; DB xx model byte +; 0FFh = PC +; 0FEh = PC/XT, Portable +; 0FDh = PC/JR +; 0FCh = PC/AT +; 0F9h = Convertable +; 0F8h = Model 80 +; 0E0 thru 0EFh = reserved +; +; DB xx secondary model byte +; 000h = PC1 +; 000h = PC/XT, Portable +; 000h = PC/JR +; 000h = PC/AT +; 001h = PC/AT Model 339 +; 003h = PC/RT +; 000h = Convertable +; +; DB xx bios revision level +; 00 for first release, subsequent release +; of code with same model byte and +; secondary model byte require revison level +; to increase by one. +; +; DB xx feature information byte 1 +; X0000000 = 1, bios use DMA channel 3 +; = 0, DMA channel 3 not used +; +; 0X000000 = 1, 2nd Interrupt chip present +; = 0, 2nd Interrupt chip not present +; +; 00X00000 = 1, Real Time Clock present +; = 0, Real Time Clock not present +; +; 000X0000 = 1, Keyboard escape sequence(INT 15h) +; called in keyboard interrupt +; (Int 09h). +; = 0, Keyboard escape sequence not +; called. +; 0000XXXX reserved +; +; DB xx feature information byte 2 - reserved +; +; DB xx feature information byte 2 - reserved +; +; DB xx feature information byte 2 - reserved +; +; DB xx feature information byte 2 - reserved +; + +BIOS_SYSTEM_DESCRIPTOR struc +bios_SD_leng dw ? +bios_SD_modelbyte db ? +bios_SD_scnd_modelbyte db ? + db ? +bios_SD_featurebyte1 db ? + db 4 dup (?) +BIOS_SYSTEM_DESCRIPTOR ends + +;FeatureByte1 bit map equates +DMAchannel3 equ 10000000b +ScndIntController equ 01000000b +RealTimeClock equ 00100000b +KeyEscapeSeq equ 00010000b + ;;End of Modification diff --git a/SRC/BIOS/CLOCKSUB.INC b/SRC/BIOS/CLOCKSUB.INC new file mode 100644 index 0000000..e643d2c --- /dev/null +++ b/SRC/BIOS/CLOCKSUB.INC @@ -0,0 +1,76 @@ + +; +; date_verify loosely checks bcd date values to be in range in bin_date_time +; +date_verify: ; + cmp byte ptr bin_date_time+0,20h ; century check + ja date_error ; jmp error + jz century_20 ; jmp in 20th century + cmp byte ptr bin_date_time+0,19h ; century check + jb date_error ; jmp error + cmp byte ptr bin_date_time+1,80h ; year check + jb date_error ; jmp error +century_20: ; + cmp byte ptr bin_date_time+1,99h ; year check + ja date_error ; jmp error + cmp byte ptr bin_date_time+2,12h ; month check + ja date_error ; jmp error + cmp byte ptr bin_date_time+2,00h ; month check + jbe date_error ; jmp error + cmp byte ptr bin_date_time+3,31h ; day check + ja date_error ; jmp error + cmp byte ptr bin_date_time+3,00h ; day check + jbe date_error ; jmp error + clc ; set success flag + ret ; +date_error: ; + stc ; set error flag + ret ; + +; +; time_verify very loosely checks bcd date values to be in range in bin_date_time +; +time_verify: + cmp byte ptr bin_date_time+0,24H + ja time_error + cmp byte ptr bin_date_time+1,59H + ja time_error + cmp byte ptr bin_date_time+2,59H + ja time_error + clc + ret +time_error: + stc + ret + +; +; bcd_verify checks values in bin_date_time to be valid +; bcd numerals. carry set if any nibble out of range +; +bcd_verify: ; + mov cx,4 ; 4 bytes to check + mov bx,offset bin_date_time ; +bv_loop: ; + mov al,[bx] ; get a bcd number (0..99) + mov ah,al ; + and ax,0f00fh ; 10's place in high ah, 1's in al + cmp al,10 ; is 1's place in range? + ja bv_error ; jmp out of range + shr ah,1 ; swap nibbles + shr ah,1 ; ... + shr ah,1 ; ... + shr ah,1 ; ... + and ah,0fh ; get rid of any erroneous bits + cmp ah,10 ; is 10's place in range + ja bv_error ; jmp out of range + inc bx ; next byte + dec cx ; + jnz bv_loop ; + clc ; set success flag + ret ; +bv_error: ; + stc ; set error flag + ret ; +; +; Dos 3.30 - The real time clock structures were moved to msbio2.asm +; diff --git a/SRC/BIOS/CMOSEQU.INC b/SRC/BIOS/CMOSEQU.INC new file mode 100644 index 0000000..b52b259 --- /dev/null +++ b/SRC/BIOS/CMOSEQU.INC @@ -0,0 +1,50 @@ + ;;Rev 3.30 Modification +;Equates for CMOS. + +;---------------------------------------- +; CMOS EQUATES FOR THIS SYSTEM : +;------------------------------------------------------------------------------- +CMOS_PORT EQU 070H ; I/O ADDRESS OF CMOS ADDRESS PORT +CMOS_DATA EQU 071H ; I/O ADDRESS OF CMOS DATA PORT +NMI EQU 10000000B ; DISABLE NMI INTERRUPTS MASK - + ; HIGH BIT OF CMOS LOCATION ADDRESS + +;---------- CMOS TABLE LOCATION ADDRESS'S ## ----------------------------------- +CMOS_SECONDS EQU 000H ; SECONDS +CMOS_SEC_ALARM EQU 001H ; SECONDS ALARM ## NOTE: ALL LOCATIONS +CMOS_MINUTES EQU 002H ; MINUTES | IN THE CMOS AREA +CMOS_MIN_ALARM EQU 003H ; MINUTES ALARM | ARE IBM USE ONLY +CMOS_HOURS EQU 004H ; HOURS | AND SUBJECT TO +CMOS_HR_ALARM EQU 005H ; HOURS ALARM | CHANGE. ONLY THE +CMOS_DAY_WEEK EQU 006H ; DAY OF THE WEEK | POST & BIOS CODE +CMOS_DAY_MONTH EQU 007H ; DAY OF THE MONTH | SHOULD DIRECTLY +CMOS_MONTH EQU 008H ; MONTH | ACCESS LOCATIONS +CMOS_YEAR EQU 009H ; YEAR (TWO DIGITS) | IN CMOS STORAGE. +CMOS_REG_A EQU 00AH ; STATUS REGISTER A '----------------- +CMOS_REG_B EQU 00BH ; STATUS REGISTER B ALARM +CMOS_REG_C EQU 00CH ; STATUS REGISTER C FLAGS +CMOS_REG_D EQU 00DH ; STATUS REGISTER D BATTERY +CMOS_DIAG EQU 00EH ; POST DIAGNOSTIC STATUS RESULTS BYTE +CMOS_SHUT_DOWN EQU 00FH ; SHUTDOWN STATUS COMMAND BYTE +CMOS_DISKETTE EQU 010H ; DISKETTE DRIVE TYPE BYTE ; +; EQU 011H ; - RESERVED ;C +CMOS_DISK EQU 012H ; FIXED DISK TYPE BYTE ;H +; EQU 013H ; - RESERVED ;E +CMOS_EQUIP EQU 014H ; EQUIPMENT WORD LOW BYTE ;C +CMOS_B_M_S_LO EQU 015H ; BASE MEMORY SIZE - LOW BYTE (X1024) ;K +CMOS_B_M_S_HI EQU 016H ; BASE MEMORY SIZE - HIGH BYTE ;S +CMOS_E_M_S_LO EQU 017H ; EXPANSION MEMORY SIZE - LOW BYTE ;U +CMOS_E_M_S_HI EQU 018H ; EXPANSION MEMORY SIZE - HIGH BYTE ;M +CMOS_DISK_1 EQU 019H ; FIXED DISK TYPE - DRIVE C EXTENSION ;E +CMOS_DISK_2 EQU 01AH ; FIXED DISK TYPE - DRIVE D EXTENSION ;D +; EQU 01BH ; - 1BH THROUGH 2DH - RESERVED ; +CMOS_CKSUM_HI EQU 02EH ; CMOS CHECKSUM - HIGH BYTE ;* +CMOS_CKSUM_LO EQU 02FH ; CMOS CHECKSUM - LOW BYTE ;* +CMOS_U_M_S_LO EQU 030H ; USABLE MEMORY ABOVE 1 MEG - LOW BYTE +CMOS_U_M_S_HI EQU 031H ; USABLE MEMORY ABOVE 1 MEG - HIGH BYTE +CMOS_CENTURY EQU 032H ; DATE CENTURY BYTE (BCD) +CMOS_INFO128 EQU 033H ; 128KB INFORMATION STATUS FLAG BYTE +; EQU 034H ; - 34H THROUGH 3FH - RESERVED +; + ;;End of Modification + \ No newline at end of file diff --git a/SRC/BIOS/DSKPRM.INC b/SRC/BIOS/DSKPRM.INC new file mode 100644 index 0000000..6b24bff --- /dev/null +++ b/SRC/BIOS/DSKPRM.INC @@ -0,0 +1,22 @@ +; The following structure defines the disk parameter table +; pointed to by Interrupt vector 1EH (location 0:78H) + +DISK_PARMS STRUC +DISK_SPECIFY_1 DB ? +DISK_SPECIFY_2 DB ? +DISK_MOTOR_WAIT DB ? ; Wait till motor off +DISK_SECTOR_SIZ DB ? ; Bytes/Sector (2 = 512) +DISK_EOT DB ? ; Sectors per track (MAX) +DISK_RW_GAP DB ? ; Read Write Gap +DISK_DTL DB ? +DISK_FORMT_GAP DB ? ; Format Gap Length +DISK_FILL DB ? ; Format Fill Byte +DISK_HEAD_STTL DB ? ; Head Settle Time (MSec) +DISK_MOTOR_STRT DB ? ; Motor start delay +DISK_PARMS ENDS + +ROMStatus equ 1 +ROMRead equ 2 +ROMWrite equ 3 +ROMVerify equ 4 +ROMFormat equ 5 diff --git a/SRC/BIOS/JUMPMAC.INC b/SRC/BIOS/JUMPMAC.INC new file mode 100644 index 0000000..b13599e --- /dev/null +++ b/SRC/BIOS/JUMPMAC.INC @@ -0,0 +1,32 @@ + + ;;Rev 3.30 Modification +; +; given a label either 2 byte jump to another label _J +; if it is near enough or 3 byte jump to +; + +jump macro lbl + local a +.xcref + + ifndef lbl&_j ;; is this the first invocation +a: + JMP lbl + ELSE + IF (lbl&_J GE $) OR ($-lbl&_J GT 126) +a: + JMP lbl ;; is the jump too far away? + ELSE +a: + JMP lbl&_J ;; do the short one... + ENDIF + ENDIF +lbl&_j = a +.cref + endm +.xcref jump +;REDEFINE THE ABOVE MACRO TO ALWAYS TRY A 3 BYTE NEAR JUMP +JUMP MACRO LBL + JMP LBL + ENDM ;;End of Modification + \ No newline at end of file diff --git a/SRC/BIOS/LOCSCR b/SRC/BIOS/LOCSCR new file mode 100644 index 0000000..2bbd69c --- /dev/null +++ b/SRC/BIOS/LOCSCR @@ -0,0 +1 @@ +70 diff --git a/SRC/BIOS/MAKEFILE b/SRC/BIOS/MAKEFILE new file mode 100644 index 0000000..5d58d4a --- /dev/null +++ b/SRC/BIOS/MAKEFILE @@ -0,0 +1,107 @@ +#*** Makefile for BIOS + +DEST =io +MSG =messages +DOS =..\dos + +# Definitions for Assembler + +ASM =masm +AFLAGS =-Mx -t +AINC =-I. -I..\inc -I$(DOS) + +# Definitions for C compiler + +CC =cl +CFLAGS =-Ox -X -Zlp +CINC =-I. -I..\h + +# Definitions for Linker + +LINK =link + +# Built-in rules + +.asm.obj: + $(ASM) $(AFLAGS) $(AINC) $*.asm,$*.obj; + +.asm.lst: + $(ASM) -l $(AFLAGS) $(AINC) $*.asm; + +.c.obj: + $(CC) -c $(CFLAGS) $(CINC) -Fo$*.obj $*.c + +.c.lst: + $(CC) -c $(CFLAGS) $(CINC) -Fc$*.cod -Fo$*.obj $*.c + +.exe.com: + reloc $*.exe $*.com + +# Dependencies + +msload.obj: msload.asm msload.inc + +msload.com: msload.obj + LINK msload.obj,msload,,; + exe2bin msload.exe msload.com + del msload.exe + +msbio1.obj: msbio1.asm msdata.inc msgroup.inc jumpmac.inc pushpop.inc \ + $(DOS)\devsym.inc dskprm.inc msmacro.inc + + +mscon.obj: mscon.asm msgroup.inc jumpmac.inc msmacro.inc + +msaux.obj: msaux.asm msgroup.inc jumpmac.inc msmacro.inc + +mslpt.obj: mslpt.asm msgroup.inc msequ.inc msbds.inc msmacro.inc \ + $(dos)\devsym.inc $(dos)\ioctl.inc $(dos)\bpb.inc + +msclock.obj: msclock.asm msgroup.inc msmacro.inc + +msdisk.obj: msdisk.asm msgroup.inc msequ.inc msbds.inc pushpop.inc \ + msmacro.inc $(dos)\devsym.inc dskprm.inc msioctl.inc \ + $(dos)\ioctl.inc $(dos)\bpb.inc + +msinit.obj: msinit.asm msgroup.inc dskprm.inc msequ.inc msbds.inc \ + msmacro.inc readclock.inc clocksub.inc msextrn.inc + +sysinit1.obj: sysinit1.asm msstack.inc stkmes.inc stkinit.inc \ + $(dos)\devsym.inc $(dos)\ioctl.inc $(dos)\smdossym.inc \ + $(dos)\dosmac.inc $(dos)\bpb.inc $(dos)\buffer.inc \ + $(dos)\sysvar.inc $(dos)\vector.inc $(dos)\dirent.inc \ + $(dos)\dpb.inc $(dos)\curdir.inc $(dos)\pdb.inc $(dos)\exe.inc \ + $(dos)\sf.inc $(dos)\arena.inc $(dos)\intnat.inc $(dos)\mi.inc \ + $(dos)\syscall.inc + masm401 $(AFLAGS) $(AINC) sysinit1; + +sysconf.obj: sysconf.asm $(dos)\devsym.inc $(dos)\ioctl.inc \ + $(dos)\smdossym.inc $(dos)\dosmac.inc $(dos)\bpb.inc $(dos)\buffer.inc \ + $(dos)\sysvar.inc $(dos)\vector.inc $(dos)\dirent.inc \ + $(dos)\dpb.inc $(dos)\curdir.inc $(dos)\pdb.inc $(dos)\exe.inc \ + $(dos)\sf.inc $(dos)\arena.inc $(dos)\intnat.inc $(dos)\mi.inc \ + $(dos)\syscall.inc + +sysinit2.obj: sysinit2.asm $(dos)\devsym.inc $(dos)\ioctl.inc \ + $(dos)\smdossym.inc $(dos)\dosmac.inc $(dos)\bpb.inc $(dos)\buffer.inc \ + $(dos)\sysvar.inc $(dos)\vector.inc $(dos)\dirent.inc \ + $(dos)\dpb.inc $(dos)\curdir.inc \ + $(dos)\pdb.inc $(dos)\exe.inc $(dos)\sf.inc $(dos)\arena.inc \ + $(dos)\intnat.inc $(dos)\mi.inc $(dos)\syscall.inc + +sysimes.obj: sysimes.asm msmacro.inc sysimes.inc msequ.inc msbds.inc + +msbio2.obj: msbio2.asm msgroup.inc msequ.inc msbds.inc $(dos)\devsym.inc \ + pushpop.inc msmacro.inc biomes.inc ms96tpi.inc msvolid.inc + +mshard.obj: mshard.asm + +msbio.bin: msbio1.obj mscon.obj msaux.obj mslpt.obj msclock.obj \ + msdisk.obj msbio2.obj msinit.obj mshard.obj sysinit1.obj \ + sysconf.obj sysinit2.obj sysimes.obj + link @msbio.lnk + exe2bin msbio.exe msbio.bin < locscr + copy /b msload.com+msbio.bin io.sys + del msbio.bin + del msbio.exe + del msload.com diff --git a/SRC/BIOS/MS96TPI.INC b/SRC/BIOS/MS96TPI.INC new file mode 100644 index 0000000..c95f9f3 --- /dev/null +++ b/SRC/BIOS/MS96TPI.INC @@ -0,0 +1,494 @@ + +;------------------------------------------------------------------------ +; : +; File: ms96tpi.asm : +; : +; This file contains code to support the 96 tpi drives. The code : +; is included in the bio if the machine has at least one drive with : +; changeline support. If the machine has no changeline drives then : +; the code is not kept in the bio at system initialization time. : +; : +;------------------------------------------------------------------------ + + +;------------------------------------------------------------------------ +; : +; DISK OPEN/CLOSE ROUTINES : +; : +;------------------------------------------------------------------------ + +DSK$OPEN: + PUBLIC DSK$OPEN + Message fTestDisk,<"Disk Open "> ; print debug messages + MNUM fTestDisk,AX + Message fTestDisk, + ; AL is logical drive + call SetDrive ; Get BDS for drive + inc WORD PTR ds:[di].opcnt + jmp EXIT + +DSK$CLOSE: + PUBLIC DSK$CLOSE + Message fTestDisk,<"Disk Close "> ; print debug messages + MNUM fTestDisk,AX + Message fTestDisk, + ; AL is logical drive + call SetDrive ; Get BDS for drive + cmp WORD PTR ds:[di].opcnt,0 + jz EXITJX ; Watch out for wrap + dec WORD PTR ds:[di].opcnt +EXITJX: + jmp EXIT + +; +; ChkOpCnt checks the number of open files on drive. +; +; Input : DS:DI points to current BDS for drive. +; +; Return : zero set if no open files +; zero reset if open files +; + +ChkOpCnt: + Message fTest96,<"Check open count "> ; print debug messages + MNUM fTest96,AX + Message fTest96, + cmp WORD PTR ds:[di].opcnt,0 + ret + +; +; At media check time, we need to really get down and check what the change is. +; This is GUARANTEED to be expensive. +; +; On entry AL contains logical drive number +; + + public mediacheck +MediaCheck: + call CheckSingle ; make sure correct disk is in place + xor SI,SI + call HasChange + jz MediaRet + call CheckROMChange + jnz MediaDoVOLID + push AX + push DX + ; see if changeline has been triggered +;;Rev 3.30 Modification + mov DL, DS:[DI.drivenum] ; set logical drive number + mov AH, 16h ; get changeline status + int 13h ; call rom diskette routine +;;End of Modification + pop DX + pop AX + jc MediaDoVolid ; if changeline was triggered jmp + mov SI,1 ; else signal no change + + +; There are some drives with changeline that "lose" the changeline indication +; if a different drive is accessed after the current one. In order to avoid +; missing a media change, we return an "I don't know" to DOS if the changeline +; is not active AND we are accessing a different drive from the last one. +; If we are accessing the same drive, then we can safely rely on the changeline +; status. + + PUBLIC LOSECHNG +LOSECHNG: + mov bl,cs:[Tim_Drv] ; get last drive accessed + cmp byte ptr [di].DriveNum,bl + jz MediaRet +; Do the 2 second twiddle. If time >= 2 seconds, do a volid check. +; Otherwise return "I don't know" (Strictly speaking, we should return a +; "Not Changed" here since the 2 second test said no change.) - RS. + + SaveReg + call Check_Time_Of_Access + RestoreReg + or si,si + jz MediaDoVolid ; Check_Time says ">= 2 secs passed" + xor si,si ; return "I don't know" + Public MediaRet +MediaRet: + ret + + +; +; MediaDoVolid: if this is called somehow the media was changed. Look at +; VID to see. We do not look at FAT because this may be different since we +; only set MedByt when doing a READ or WRITE. +; + +MediaDoVolid: + call GETBP ; build a new BPB in current BDS + jc MediaRet + call Check_VID + jnc MediaRet + call MapError ; fix up AL for return to DOS + ret + +; +; Checklatchio: +; +; Simple, quick check of latched change. If no indication, then return +; otherwise do expensive check. If the expensive test fails, POP off the +; return and set AL = 15 (for invalid media change) which will be returned to +; DOS. +; + public checklatchio +CheckLatchIO: +; If returning fake BPB then assume the disk has not changed +; test word ptr ds:[di].flags, RETURN_FAKE_BPB +; jnz CheckRet +;;Rev 3.30 Modification + call HasChange ;change line supported? + jz CheckRet ;No. Just return +;;End of Modification + call ChkOpCnt + jnz CheckROM +CheckRet: + ret +; +; Check for past ROM indications. If no ROM change indicated, then return OK. +; + public checkrom +CheckROM: + call CheckROMChange + jz CheckRet ; no change +; +; We now see that a change line has been seen in the past. Let's do the +; expensive verification. +; + Message fTest96,<"CheckROMChange says yes...",CR,LF> + call GETBP ; build BPB in current BDS + jc Ret_No_Error_Map ; GETBP has already called MapError + call Check_VID + jc CheckLatchRet ; disk error trying to read in. + or SI,SI ; Is changed for sure? + jns CheckRet + call ReturnVid +CheckLatchRet: + call MapError ; fix up AL for return to DOS +Ret_No_Error_Map: + stc ; indicate an error + pop si ; pop off return address + ret + + + +; +; CheckFatVID: +; +; Check the FAT and the VID. Return in DI -1 or 0. Return with carry set +; ONLY if there was a disk error. Return that error code in AX. +; + public checkfatvid +CheckFATVID: + Message fTest96,<"Check FAT",CR,LF> + call FAT_Check + or SI,SI + js Changed_Drv +; +; The fat was the same. How about the volume ID? +; +Check_VID: + Message fTest96,<"Check VID",CR,LF> + call Read_volume_ID + jc CheckFatRet + call Check_Volume_id + or SI,SI + jnz Changed_Drv + Message fTest96,<"VID not changed",CR,LF> + call ResetChanged +CheckFatRet: + ret +Changed_Drv: + mov cs:[Tim_Drv],-1 ; Ensure that we ask ROM for media + ret ; check next time round + + + + +; +; CheckIO: At I/O time the rom-bios returned an error. We need to +; determine if the error is due to a media change. If error code is not +; change-line error (06h) we just return. We pop off the call and jmp to +; harderr if we see an error. +; +; On entry: AH contains error code returned from rom-bios. +; + + public checkio +CheckIO: + cmp AH,06 ; change line error? + jnz CheckFatRet ; no - just return + call ChkOpCnt + jz CheckFATRet ; no open files +; If returning fake BPB then ignore disk changes +; test word ptr ds:[di].flags, RETURN_FAKE_BPB +; jnz IgnoreChange + call GETBP ; build up a new BPB in current BDS + jc No_Error_Map ; GETBP has already called MapError + call CheckFATVID + jc CheckIORet ; disk error trying to read in. + or SI,SI ; Is changed for sure? + js CheckIOErr ; yes changed +IgnoreChange: + inc BP ; allow a retry + ret +CheckIOErr: + call ReturnVid +CheckIORet: + stc ; make sure carry gets passed through + jmp HardErr + +No_Error_Map: + jmp HardErr2 + + + + +; +; Return VID sets up the VID for a return to DOS. +; + + Public ReturnVID +ReturnVID: + Message fTest96,<"Return VID",cr,lf> + push DS ; save pointer to current BDS + push di + push cx + call init_vid_loop ; Sets ES:DI -> vid + lds BX,cs:[PTRSAV] + mov [BX.EXTRA],DI + mov [BX.EXTRA+2],ES + pop cx + pop di ; restore current BDS + pop DS +;; MOV AH,6 ; INVALID MEDIA CHANGE + mov AH, 0Fh ; set error as 'invalid media change' + stc ; indicate error by setting carry flag + ret + +; +; Media_Set_VID: +; +; Moves the pointer to the volid for the drive into the original request packet +; On entry, DS:BX points to the original packet. +; No attempt is made to preserve registers. +; + +MEDIA_SET_VID: + PUBLIC MEDIA_SET_VID ;;Rev 3.30 Modification + call init_vid_loop ; Sets ES:DI -> vid ;;End of Modification + lds bx,cs:[PtrSav] ; get pointer to packet + mov word ptr [BX.TRANS+1],DI + mov word ptr [BX.TRANS+3],ES + ret + + +; +; HiDensity - examine a drive/media descriptor to set the media type. If +; the media descriptor is NOT F9 (not 96tpi or 3 1/2), we return and let the +; caller do the rest. Otherwise, we pop off the return and jump to the tail +; of GETBP. For 3.5" media, we just return. +; +; Inputs: DS:DI point to correct BDS for this drive +; AH has media byte +; +; Outputs: Carry clear +; No registers modified +; Carry set +; AL = sectors/fat +; BH = number of root directory entries +; BL = sectors per track +; CX = number of sectors +; DH = sectors per allocation unit +; DL = number of heads +; +hidensity: + PUBLIC HIDENSITY ;;Rev 3.30 Modification + ;;End of Modification +; Check for correct drive +; + test word ptr ds:[di].flags,fChangeline ; is it special? + jz DoFloppy ; no, do normal floppy test +; +; We have a media byte that is pretty complex. Examine drive information +; table to see what kind it is. +; + cmp byte ptr ds:[di].FormFactor,ffSmall; Is it single-media? + jz DoFloppy ; yes, use fatid... +; +; 96 tpi drive +; + cmp AH,0F9h + jnz DoFloppy + mov al,7 ; seven sectors / fat + mov bx,224*256+0fh ; 224 root dir entries & 0f sector max + mov cx,80*15*2 ; 80 tracks, 15 sectors/track, 2 sides + mov dx,01*256+2 ; sectors/allocation unit & head max +popr: + add SP,2 ; pop off return address + jmp has1_res ; return to tail of GETBP + + +DoFloppy: + ret + + PATHSTART 001,TPI96 ;;Rev 3.30 Modification + ;;End of Modification +; +; Certain poorly designed programs avoid DOS altogether and use INT 13 directly. +; These programs even retry operations and, thus, will ignore the disk change +; logic. +; +; We hook INT 13 and note all errors. +; + assume ds:nothing,es:nothing,ss:nothing + + Public REAL13 +Real13 dd ? +OldInt dd ? +dmy dw ? + + PATHEND 001,TPI96 ;;Rev 3.30 Modification + ;;End of Modification + Public Int13 +Int13 proc FAR + pop word ptr OldInt + pop word ptr OldInt+2 + pop DMY + MESSAGE FTEST13,<"*"> ;;Rev 3.30 Modification + pushf ;;End of Modification + call REAL13 ; simulate another INT 13 + jc Err13 ; did an error occur? + jmp OldInt ; no, return and pop off flags +Err13: + MESSAGE FTEST13,<"INT 13 ERROR "> ;;Rev 3.30 Modification + MNUM FTEST13,AX + MESSAGE FTEST13, + pushf ; save state + cmp AH,06h ; is error a 'change' error? + jz GOTERR ; yes, jump down +B: popf ; no, some other error, ignore it ;;End of Modification + jmp OldInt ; return and pop off flags + + +GotErr: or DL,DL ; is this for the hard disk? + js B ; yes, ignore + mov word ptr cs:[FlagBits],fChanged + call Set_Changed_DL + jmp B +INT13 endp + + + +; +; Set_Changed_DL - Sets flag bits according to bits set in [FlagBits]. +; Essentially used to indicate Changeline, or Format. +; +; Inputs: DL contains physical drive number +; [FlagBits] contains bits to set in the flag field in the BDSs +; Outputs: None +; Registers modified: Flags +; + +Set_Changed_DL: + PUBLIC SET_CHANGED_DL ;;Rev 3.30 Modification + Message ftest96,<"Set Changed",cr,lf> ;;End of Modification + push BX + push DX + mov BL,DL +ALL_SET: + mov dx,cs:[FlagBits] ; get bits to set in flag field + xor BH,BH +; +; In the virtual drive system we *must* flag the other drives as being changed +; +; assume first BDS is in this segment + push ax + push ds ; save current BDS + push di + lds di,dword ptr cs:[Start_BDS] +Scan_BDS: + cmp di,-1 + jz SkipSet + cmp byte ptr [di].DriveNum,bl + jnz Get_Next_BDS +; +; Someone may complain, but this *always* must be done when a disk change is +; noted. There are *no* other compromising circumstances. +; +SetChanged: + or word ptr ds:[di].flags,dx ; signal change on other drive +Get_Next_BDS: + mov ax,word ptr [di].link+2 ; go to next BDS + mov di,word ptr [di].link + mov ds,ax + jmp short Scan_BDS +SkipSet: + pop di ; restore current BDS + pop ds + pop ax + pop DX + pop BX + ret + + + +; +; CheckROMChange - see if external program has diddled ROM change line. +; +; Inputs: DS:DI points to current BDS. +; Outputs: Zero set - no change +; Zero reset - change +; Registers modified: none + +CheckROMChange: + MESSAGE FTEST13,<"CHECKROM "> ;;Rev 3.30 Modification + MNUM FTEST13 + MESSAGE FTEST13, ;;End of Modification + test word ptr [di].flags,fChanged + ret + + + + +; +; ResetChanged - restore value of change line +; +; Inputs: DS:DI points to current BDS +; Outputs: none +; Registers modified: none + +ResetChanged: + MESSAGE FTEST13,<"RESETCHANGED "> ;;Rev 3.30 Modification + MNUM FTEST13 + MESSAGE FTEST13, ;;End of Modification + and word ptr ds:[di].flags,NOT fChanged + ret + + + +; +; HasChange - see if drive can supply change line +; +; Inputs: DS:DI points to current BDS +; Outputs: Zero set - no change line available +; Zero reset - change line available +; Registers modified: none + + PUBLIC HASCHANGE ;;Rev 3.30 Modification +HasChange: + MESSAGE FTEST13,<"HASCHANGE "> + MNUM FTEST13 + MESSAGE FTEST13, ;;End of Modification + test word ptr [di].flags,fChangeline + ret + + ASSUME DS:CODE + + include msvolid.inc + + Public End96tpi +End96tpi Label Byte diff --git a/SRC/BIOS/MSAUX.ASM b/SRC/BIOS/MSAUX.ASM new file mode 100644 index 0000000..5deac60 --- /dev/null +++ b/SRC/BIOS/MSAUX.ASM @@ -0,0 +1,281 @@ + TITLE MSAUX - DOS 3.3 +;---------------------------------------------------------------- +; : +; A U X - AUXILARY DEVICE DRIVER : +; : +; : +; This file contains the Auxilary Device Driver. The : +; auxilary driver handles calls to and from the RS-232 port. : +; Three devices uses this code: AUX, COM1, and COM2. AUX and : +; COM1 talk to the zero RS-232 card and COM2 talks to the : +; 'one' RS-232 card. The beginning of the interrupt entry : +; point for these devices sets the variable AUXNUM in the : +; msbio.asm module. If the value is 0 the routines in this : +; file will talk to the the 'zero' card. If the value in : +; AUXNUM is 1 the routines will talk to the 'one' card. : +; The procedure GETDX is called to put the value 0 or 1 in : +; the DX register depending on the value in AUXBUF. : +; : +; The routines in this files are: : +; : +; routine function : +; ------- -------- : +; AUX$READ Read characters from the : +; specified device. : +; AUX$RDND Non-desrucrtive read with : +; no waiting. : +; AUX$FLSH Flush specified device input : +; buffer. : +; AUX$WRIT Write characters to the : +; specified device. : +; AUX$WRST Get status of specified : +; device : +; : +; These routines are not called directly. Call are made via : +; the strategy and interrupt entry point (see Device Header). : +; : +; Data structure: : +; The Aux Device has a two byte buffer called AUXBUF. The : +; first byte is for the zero card, the second byte is for the : +; one card. A zero value in the byte indicates the buffer is : +; empty. The routines use GETBX to get the address of the : +; buffer. : +; : +;---------------------------------------------------------------- + +;;Ver 3.30 modification --------------------------- + test=0 + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + INCLUDE JUMPMAC.INC + INCLUDE MSMACRO.INC + + EXTRN ERR$CNT:NEAR ;MSBIO1 + EXTRN GETDX:NEAR ;MSBIO1 + EXTRN RDEXIT:NEAR ;MSCON + EXTRN EXIT:NEAR ;MSBIO1 + EXTRN BUS$EXIT:NEAR ;MSBIO1 + ;DATA + EXTRN AUXBUF:BYTE ;MSDATA + +; VALUES IN AH, REQUESTING FUNCTION OF INT 14H IN ROM BIOS +AUXFUNC_SEND EQU 1 ;TRANSMIT +AUXFUNC_RECEIVE EQU 2 ;READ +AUXFUNC_STATUS EQU 3 ;REQUEST STATUS + +; ERROR FLAGS, REPORTED BY INT 14H + +; THESE FLAGS REPORTED IN AH: +FLAG_DATA_READY EQU 01H ;DATA READY +FLAG_OVERRUN EQU 02H ;OVERRUN ERROR +FLAG_PARITY EQU 04H ;PARITY ERROR +FLAG_FRAME EQU 08H ;FRAMING ERROR +FLAG_BREAK EQU 10H ;BREAK DETECT +FLAG_TRANHOL_EMP EQU 20H ;TRANSMIT HOLDING REGISTER EMPTY +FLAG_TRANSHF_EMP EQU 40H ;TRANSMIT SHIFT REGISTER EMPTY +FLAG_TIMEOUT EQU 80H ;TIMEOUT + +; THESE FLAGS REPORTED IN AL: +FLAG_DELTA_CTS EQU 01H ;DELTA CLEAR TO SEND +FLAG_DELTA_DSR EQU 02H ;DELTA DATA SET READY +FLAG_TRAIL_RING EQU 04H ;TRAILING EDGE RING INDICATOR +FLAG_DELTA_SIG EQU 08H ;DELTA RECEIVE LINE SIGNAL DETECT +FLAG_CTS EQU 10H ;CLEAR TO SEND +FLAG_DSR EQU 20H ;DATA SET READY +FLAG_RING EQU 40H ;RING INDICATOR +FLAG_REC_SIG EQU 80H ;RECEIVE LINE SIGNAL DETECT +;;End of modification ------------------ + + +;---------------------------------------------------------------- +; : +; Read zero or more characters from Auxilary Device : +; : +; input:es:[di] points to area to receive aux data : +; cx has number of bytes to be read : +; "auxnum" first byte has number of aux device (rel 0): +; : +;---------------------------------------------------------------- + PUBLIC AUX$READ +AUX$READ PROC NEAR + ASSUME DS:CODE ; SET BY AUX DEVICE DRIVER ENTRY ROUTINE + jcxz EXVEC2 ; if no characters, get out + call GETBX ; put address of AUXBUF in BX + xor AX,AX ; clear AX register + xchg AL,[BX] ; Get character , if any, from + ; buffer and clear buffer + or AL,AL ; if AL is nonzero there was a + ; character in the buffer + jnz AUX2 ; if so skip AUXIN call +AUX1: ; + call AUXIN ; get character from port +AUX2: ; + stosb ; store character + loop AUX1 ; if more character, go around again +EXVEC2: ; + Jump EXIT ; all done, successful exit +AUX$READ ENDP + +; +; AUXIN: make a call on ROM BIOS to read character from +; the auxilary device, then do some error checking. +; If an error occurs then AUXIN jumps to ERR$CNT and +; does NOT return to where it was called from. +; + +AUXIN PROC NEAR + + mov ah,AUXFUNC_RECEIVE + call AUXOP + ;check for Frame, Parity, or Overrun errors + ;WARNING: these error bits are unpredictable + ; if timeout (bit 7) is set + test ah,FLAG_FRAME or FLAG_PARITY or FLAG_OVERRUN + jz AROK ;No error if all bits are clear + + ;Error getting character + add sp,+2 ;Remove rtn address (near call) + xor al,al + or al,FLAG_REC_SIG or FLAG_DSR or FLAG_CTS + + JUMP ERR$CNT +AROK: + RET ;CHAR JUST READ IS IN AL, STATUS IS IN AH +AUXIN ENDP + +;---------------------------------------------------------------- +; : +; Aux non-destructive read with no waiting : +; : +; input: es:[di] points to area to receive aux data : +; : +;---------------------------------------------------------------- +; + PUBLIC AUX$RDND +AUX$RDND PROC NEAR + ASSUME DS:CODE ; SET BY AUX DEVICE DRIVER ENTRY ROUTINE + call GETBX ; have BX point to AUXBUF + mov AL,[BX] ; copy contents of buffer to AL + or AL,AL ; if AL is non-zero (char in buffer) + jnz AUXRDX ; then return character + call AUXSTAT ; if not, get status of AUX device + TEST AH,FLAG_DATA_READY ;TEST DATA READY + jz AUXBUS ; then device is busy (not ready) + + TEST AL,FLAG_DSR ;TEST DATA SET READY + jz AUXBUS ; then device is busy (not ready) + call AUXIN ; else aux is ready, get character + call GETBX ; have bx point to AUXBUF + mov [BX],AL ; save character in buffer +AUXRDX: ; + Jump RDEXIT ; return character + +AUXBUS: ; + Jump BUS$EXIT ; jump to device busy exit +AUX$RDND ENDP + +;---------------------------------------------------------------- +; : +; Aux Output Status : +; : +;---------------------------------------------------------------- + PUBLIC AUX$WRST +AUX$WRST PROC NEAR + ASSUME DS:CODE ; SET BY AUX DEVICE DRIVER ENTRY ROUTINE + call AUXSTAT ; get status of AUX in AX + ; now test to see if device is busy + ; if this bit is not set, +;;Ver 3.30 modification ----------------------- + TEST AL,FLAG_DSR ;TEST DATA SET READY + jz AUXBUS ; then device is busy (not ready) + TEST AH,FLAG_TRANHOL_EMP ;TEST TRANSMIT HOLD REG EMPTY +;;End of modification ------------------------- + jz AUXBUS ; then device is busy (not ready) + Jump Exit + +AUX$WRST ENDP + +; +; AUXSTAT makes a call on the ROM-BIOS to determine the status +; of the auxilary device +; Outputs: +; AX is filled with status of port. +; DX is changes to specify which card - either 0, 1 (, 2, 3) ;ba +; NO other registers are modified +; + +AUXSTAT proc near + mov ah,AUXFUNC_STATUS + call AUXOP + ret +AUXSTAT endp + +AUXOP PROC NEAR + ;AH=FUNCTION CODE + ;0=INIT, 1=SEND, 2=RECEIVE, 3=STATUS + call GETDX ; have DX point to proper card + int 14h ; call rom-bios for status + ret +AUXOP ENDP + +;---------------------------------------------------------------- +; : +; Flush AUX Input buffer - set contents of AUXBUF to zero : +; : +;---------------------------------------------------------------- + PUBLIC AUX$FLSH +AUX$FLSH PROC NEAR + ASSUME DS:CODE ; SET BY AUX DEVICE DRIVER ENTRY ROUTINE + call GETBX ; get BX to point to AUXBUF + mov BYTE PTR [BX],0 ; zero out buffer + Jump Exit ; all done, successful return +AUX$FLSH ENDP + + + +;---------------------------------------------------------------- +; : +; Write to Auxilary Device : +; : +;---------------------------------------------------------------- + PUBLIC AUX$WRIT +AUX$WRIT PROC NEAR + ASSUME DS:CODE ; SET BY AUX DEVICE DRIVER ENTRY ROUTINE + jcxz EXVEC2 ; if CX is zero, no characters + ; to be written, jump to exit +AUX$LOOP: + mov AL,ES:[DI] ; get character to be written + inc DI ; move DI pointer to next character +;;Ver 3.30 modification --------------------------- + MOV AH,AUXFUNC_SEND ;VALUE=1, INDICATES A WRITE + CALL AUXOP ;SEND CHARACTER OVER AUX PORT + + TEST AH,FLAG_TIMEOUT ;CHECK FOR ERROR +;;End of modification --------------------------- + jz AWOK ; then no error + mov AL,10 ; else indicate write fault + Jump ERR$CNT ; call error routines + + ; if CX is non-zero, still more +AWOK: + loop AUX$LOOP ; more characrter to print + Jump Exit ; all done, successful return +AUX$WRIT ENDP + + +; +; GETBX puts the address of AUXBUF (the Auxilary Device buffer) +; in BX. After calling GETBX, a routine can get to AUXBUF +; with [BX]. +; +; NOTE: The getdx routine is in msbio1 and looks like: +; mov dx,word ptr cs:[auxnum] +; +GETBX PROC NEAR + call GETDX + mov BX,DX + add BX,OFFSET AUXBUF + ret +GETBX ENDP + +CODE ENDS + END diff --git a/SRC/BIOS/MSAUX.OBJ b/SRC/BIOS/MSAUX.OBJ new file mode 100644 index 0000000..2389636 Binary files /dev/null and b/SRC/BIOS/MSAUX.OBJ differ diff --git a/SRC/BIOS/MSBDS.INC b/SRC/BIOS/MSBDS.INC new file mode 100644 index 0000000..a8f8f5e --- /dev/null +++ b/SRC/BIOS/MSBDS.INC @@ -0,0 +1,118 @@ +; +; BDS is the Bios Data Structure. +; +; There is one BDS for each logical drive in the system. All the BDS's +; are linked together in a list with the pointer to the first BDS being +; found in Start_BDS. The BDS hold various values important to the disk +; drive. For example there is a field for last time accesses. As actions +; take place in the system the BDS are update to reflect the actions. +; For example is there is a read to a disk the last access field for the +; BDS for that drive is update to the current time. +; +; Values for various flags in BDS.Flags. +; + +fNon_Removable equ 01H ;For non-removable media +fChangeline equ 02H ;If changeline supported on drive +RETURN_FAKE_BPB equ 04H ; When set, don't do a build BPB + ; just return the fake one +GOOD_TRACKLAYOUT equ 08H ; The track layout has no funny sectors +fI_Am_Mult equ 10H ;If more than one logical for this physical +fI_Own_Physical equ 20H ;Signify logical owner of this physical +fChanged equ 40H ;Indicates media changed +SET_DASD_true equ 80H ; Set DASD before next format +fChanged_by_format equ 100h + +; +; Various form factors to describe media +; + +ff48tpi equ 0 +ff96tpi equ 1 +ffSmall equ 2 +ffHardFile equ 5 +ffOther equ 7 + +BDS_Type struc +Link DD ? ; Link to next BDS +DriveNum DB ? ; Physical drive number +DriveLet DB ? ; DOS drive number +BytePerSec DW ? ; number of bytes/sec +SecPerClus DB ? ; sec per allocation unit +RESSEC DW ? ; number of reserved sectors +cFAT DB ? ; number of fats +cDir DW ? ; number of directory entries +DRVLIM DW ? ; number of sectors on medium +mediad DB ? ; media descriptor byte +cSecFat DW ? ; number of sectors/fat +SECLIM DW ? ; sectors per track +HDLIM DW ? ; max number of heads +HIDSEC DW ? ; number of hidden sectors +FatSiz DB ? ; flags... +Opcnt DW ? ; Open ref. count +Volid DB 12 dup (?) ; volume ID of medium +FormFactor DB ? ; form factor index +Flags DW ? ; various flags +cCyln DW ? ; max number of cylinders +RBytePerSec DW ? ; Recommended BPB +RSecPerClus DB ? +RRESSEC DW ? +RcFAT DB ? +RcDir DW ? +RDRVLIM DW ? +Rmediad DB ? +RcSecFat DW ? +RSECLIM DW ? +RHDLIM DW ? +RHIDSEC DW ? +RHHIDSEC DW ? +RLOGSEC DD ? +Reserve DB 6 dup (?) ; Reserved for future + ; changed to word -- kcd9:85 +Track DB ? ; last track accessed on drive +Tim_Lo DW ? ; Time of last access. Keep +Tim_Hi DW ? ; these contiguous. +BDS_Type ends + +BPBSize = Track - RBytePerSec ; size in bytes of RecBPB area in the BDS + + +;;Rev 3.30 Modification +;********************************************************************* +; BDS structure for mini disk +;********************************************************************* + +BDSM_type struc +mlink DW -1 ;Link to next structure + DW ? +mdriveNum DB 80 ;Int 13 Drive Number +mdriveLet DB 3 ;Logical Drive Number +mBytePerSec DW 512 +mSecPerClus DB 1 ;Sectors/allocation unit +mRESSEC DW 1 ;Reserved sectors for DOS +mcFAT DB 2 ;No. of allocation tables +mcDIR DW 16 ;Number of directory entries +mDRVLIM DW 0 ;Number of sectors (at 512 bytes each) +mMediad DB 11111000B ;Media descriptor +mcSecFat DW 1 ;Number of FAT sectors +mSECLIM DW 0 ;Sector limit +mHDLIM DW 0 ;Head limit +mHIDSEC DW 0 ;Hidden sector count +mFatSiz DB 0 ;TRUE => bigfat +mOPCNT DW 0 ;Open Ref. Count +mVOLID DB "NO NAME " ;Volume ID for this disk + DB 0 ;ASCIZII for "NO NAME " +mFormFactor DB 3 ;Form Factor +mFLAGS DW 0020H ;Various Flags +mcCyln dw 40 ;max number of cylinders +mRecBPB db 31 dup (0) ;Recommended BPB for drive +mTrack db -1 +IsMini dw 1 ;Overlapping TIM_LOH +Hidden_Trks dw 0 ;Overlapping TIM_HIH + +;TIM_LOH DW -1 ;Keep these two contiguous (?) +;TIM_HIH DW -1 +BDSM_type ENDS +;****************************************************************************** +Max_mini_dsk_num = 23 ; Max # of mini disk bios can support +;;End of Modification diff --git a/SRC/BIOS/MSBIO.LNK b/SRC/BIOS/MSBIO.LNK new file mode 100644 index 0000000..29a65f3 --- /dev/null +++ b/SRC/BIOS/MSBIO.LNK @@ -0,0 +1,5 @@ +msbio1+mscon+msaux+mslpt+msclock+msdisk+ +msbio2+mshard+msinit+sysinit1+sysconf+sysinit2+sysimes, +msbio, +msbio/m; + \ No newline at end of file diff --git a/SRC/BIOS/MSBIO1.ASM b/SRC/BIOS/MSBIO1.ASM new file mode 100644 index 0000000..84a1f29 --- /dev/null +++ b/SRC/BIOS/MSBIO1.ASM @@ -0,0 +1,693 @@ + TITLE MSBIO MS-DOS 3.30 + +;------------------------------------------------------------------------------- +; : +; Microsoft Bio : +; : +; The file msbio.asm is the main file in the Mircosoft bio. This file : +; includes the other main files in the bio. Most of the routines are : +; in these include files. The main files included are: : +; : +; File Contains : +; : +; msdisk.inc Disk device driver routines : +; ms96tpi.inc Routines for 96tpi drives : +; msaux.inc Device driver for the rs-232 serial ports : +; msclock.inc Device driver for "clock$" device : +; mscon.inc Device driver for "con" : +; mslpt.inc Device driver for the printers : +; : +; Each of these files contain a header section documenting the code : +; in that file. : +; Msbio also includes several files for equ's, structure definition, : +; macro definitions, etc. These are: : +; : +; msbiomes.inc msmacro.inc devsym.inc : +; dskprm.inc error.inc : +; : +; Each of these file contains explanitory notes. : +; : +; The actual code in msbio can be broken down into several piece: : +; : +; macro definitions Several marco are defined in msbio. They : +; are a few odds and end that did not fit : +; anywhere else. : +; : +; Command Jump Table List of entry points in the device drivers. : +; See notation below for full explination. : +; : +; Interrupt and Strategy : +; Entry points Calls on the device driver first come to here. : +; There is common code with pushes registers and : +; the like before jumping to routines in the : +; driver files. The common exit points are also : +; in this file. : +; : +; Miscellaneous Code There are several routines and data structure : +; declarations. See below for details. : +; : +;------------------------------------------------------------------------------- + + + +; +; If the variable TEST is non-zero then code for debugging is included. +; The extra code will make the binary file nuch larger. +; The symbol is also defined in msequ.inc. Both must be changed to +; turn debugging on or off. +; +; The level of the debugging is controled by the variable fTestBits in +; this file. See the comment preceeding the variable for more information. +; The actual routines which print the messages are in msmacro.inc +; See the header comment in this file for more information. +; +;***For testing purposes, set the TEST flag to 1. Otherwise reset it. + +TEST=0 + +PATHGEN = 1 + +.SALL +; +; This is a DOSMAC macro which is used in DEVSYM which is included later. +; + +BREAK MACRO subtitle + SUBTTL subtitle + PAGE + ENDM + +; +; Some old versions of the 80286 have a bug in the chip. The popf +; instruction will enable interrupts. Therefore in a section of code with +; interrupts disabled and you need a popf instruction use the 'popff' +; macro instead. +; + +POPFF macro + jmp $+3 + iret + push cs + call $-2 + endm + +;;Rev 3.30 modification ----------------------------- + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + +SYSINITSEG SEGMENT PUBLIC 'SYSTEM_INIT' +SYSINITSEG ENDS + + + INCLUDE JUMPMAC.INC +PATHSTART MACRO INDEX,ABBR + IFDEF PATHGEN + PUBLIC ABBR&INDEX&S,ABBR&INDEX&E + ABBR&INDEX&S LABEL BYTE + ENDIF + ENDM + +PATHEND MACRO INDEX,ABBR + IFDEF PATHGEN + ABBR&INDEX&E LABEL BYTE + ENDIF + ENDM + + INCLUDE PUSHPOP.INC + INCLUDE DEVSYM.INC ;MJB001 +;; End of Modification + +; +; Revision History +; +; REV 2.1 5/1/83 ARR added timer int handler and changed order of AUX +; PRN init for HAL0 +; +; REV 2.15 7/13/83 ARR Because of IBM design issues, and that BASCOM +; is ill behaved with respect to the 1CH timer interrupt, +; the timer handler has to be backed out! The intended +; code is commented out and has an ARR 2.15 annotation. +; This means the BIOS will go back to the multiple roll +; over bug. +; +; REV 2.20 8/5/83 ARR IBM makes hardware change. Now wants to use half +; height drives for HAL0, and back fit for PC/PC XT. Problem +; with head settle time. Previous drives got by on a 0 +; settle time, 1/2 hight drives need 15 head settle when +; doing WRITEs (0 ok on READ) if the head is being stepped. +; This requires a last track value to be kept so that BIOS +; knows when head is being moved. To help out +; programs that issue INT 13H directly, the head settle will +; normally be set to 15. It will be changed to 0 on READs, +; or on WRITEs which do not require head step. +; +; REV 2.21 8/11/83 MZ IBM wants write with verify to use head settle 0. +; Use same trick as above. +; +; REV 2.25 6/20/83 mjb001 added support for 96tpi and salmon +; +; REV 2.30 6/27/83 mjb002 added real-time clock +; +; REV 2.40 7/8/83 mjb003 added volume-id checking and int 2f macro +; definitions push* and pop* +; +; REV 2.41 7/12/83 ARR more 2.X enhancements. Open/Close media change +; +; REV 2.42 11/3/83 ARR more 2.X enhancements. Disk OPEN/CLOSE, FORMAT +; code and other misc hooked out to shrink BIOS. Code for +; Disk OPEN/CLOSE, FORMAT included only with 96tpi disks. +; +; Rev 2.43 12/6/83 MZ Examine boot sectors on hard disks for 16-bit fat +; check. Examine large fat bit in BPB for walk of media for +; DOS +; +; Rev 2.44 12/9/83 ARR Change to error reporting on INT 17H +; +; Rev 2.45 12/22/83 MZ Make head settle change only when disk parm is 0. +; +; Rev 3.21 3/20/87 SP Changed OUTCHR routine to always output to page 0. + +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +; IBM ADDRESSES FOR I/O +; +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +include dskprm.inc + + SYSIZE = 100H ; number of paragraphs in sysinit module + LF = 10 ; line feed + CR = 13 ; carriage return + BACKSP = 8 ; backspace + BRKADR = 1BH * 4 ; 006C 1Bh break vector address + TIMADR = 1CH * 4 ; 0070 1Ch timer interrupt + DSKADR = 1EH * 4 ; address of ptr to disk parameters + SEC9 = 522H ; address of disk parameters + HEADSETTLE = SEC9+9 ; address of head settle time + NORMSETTLE = 15 ; Normal head settle + SPEEDSETTLE = 0 ; Speed up settle time + INITSPOT = 534H ; IBM wants 4 zeros here + AKPORT = 20H + EOI = 20H + +;;Rev 3.30 modification ----------------------------- + ASSUME CS:CODE,DS:NOTHING,ES:NOTHING + + EXTRN MEDIA$CHK:NEAR + EXTRN GET$BPB:NEAR + EXTRN DSK$INIT:NEAR + EXTRN DSK$READ:NEAR + EXTRN DSK$WRIT:NEAR + EXTRN DSK$WRITV:NEAR + EXTRN DSK$OPEN:NEAR + EXTRN DSK$CLOSE:NEAR + EXTRN DSK$REM:NEAR + EXTRN GENERIC$IOCTL:NEAR + EXTRN IOCTL$GETOWN:NEAR + EXTRN IOCTL$SETOWN:NEAR + EXTRN CON$READ:NEAR + EXTRN CON$RDND:NEAR + EXTRN CON$FLSH:NEAR + EXTRN CON$WRIT:NEAR +; EXTRN CON$GENIOCTL:NEAR + EXTRN AUX$READ:NEAR + EXTRN AUX$WRIT:NEAR + EXTRN AUX$FLSH:NEAR + EXTRN AUX$RDND:NEAR + EXTRN AUX$WRST:NEAR + EXTRN TIM$READ:NEAR + EXTRN TIM$WRIT:NEAR + EXTRN PRN$WRIT:NEAR + EXTRN PRN$STAT:NEAR + EXTRN PRN$TILBUSY:NEAR + EXTRN PRN$GENIOCTL:NEAR + EXTRN WRMSG:NEAR +;DATA AREAS + INCLUDE MSDATA.INC +;;End of modification ----------------------------- + +; +; The following variables and two routines (MSGOUT and MSGNUM) are used +; with the debug routines to print numbers and messages on the screen. +; +; The variable fTestBits controls the level of debugging in the system. +; See the comments and "equ's" in msmacro.inc for an explination of +; how to control the level of debugging. In a nutshell, setting +; fTestBits to fTestALL prints all the debugging messages. Setting +; it to fTestDisk prints all disk related messages, etc. +; + +if test +Public MSGNUM +MSGNUM: + pushf + test fTestBits,AX + jz MRet + push SI + push BX + push CX + push ES + push DI + mov DI,OFFSET NUMBUF + push CS + pop ES + mov CX,4 +NUMLOOP: + push CX + mov CL,4 + rol BX,CL + pop CX + push BX + and BX,0Fh + mov AL,Digits[BX] + stosb + pop BX + loop NumLoop + pop DI + pop ES + pop CX + pop BX + mov SI,OFFSET NUMBUF + call MSGOUT + pop SI + popf + ret + +Public MSGOUT +MSGOUT: + pushf + test fTestBits,ax + jz MRet + push DS + push AX + push BX + push CS + pop DS + call WRMSG + pop BX + pop AX + pop DS +MRet: + popf + ret +;;Rev 3.30 modification ----------------------------- + PUBLIC DUMPBYTES +;Dumpbytes will dump the bytes in memory in hex. Space will be put in +;between the bytes and CR, LF will be put at the end. - J.K. +;Input: DS:SI -> buffer to dump in Hex. +; CX -> # of bytes (Length of the buffer) +; +DUMPBYTES proc near + pushf + push ax +dumploops: + lodsb + mov ah, al + shr ah, 1 + shr ah, 1 + shr ah, 1 + shr ah, 1 + call hex_to_ascii + push ax + mov al, ah + call outchar + pop ax + call outchar + mov al, ' ' + call outchar + loop dumploops + + mov al, 0dh + call outchar + mov al, 0ah + call outchar + + pop ax + popf + ret +DUMPBYTES endp + + PUBLIC Hex_to_ascii +Hex_to_ascii proc near + and ax, 0f0fh + add ah, 30h + cmp ah, 3ah + jb hta_$1 + add ah, 7 +hta_$1: + add al, 30h + cmp al, 3ah + jb hta_$2 + add al, 7 +hta_$2: + ret +Hex_to_ascii endp + + PUBLIC outchar +Outchar proc near + PUSH AX + PUSH SI + PUSH DI + PUSH BP + PUSH BX + MOV AH, 0Eh ;SET COMMAND TO WRITE A CHAR + MOV BL, 7 ;SET FOREGROUND COLOR + mov bh,0 ; + INT 10h ;CALL ROM-BIOS + POP BX + POP BP + POP DI + POP SI + POP AX + RET +Outchar endp + + ENDIF +;;End of modification ----------------------------- + +; +; end of routines for debugging +; + INCLUDE MSMACRO.INC + + + +; +; The next nine equ's describe the offset into the request header for +; different information. For example STATUS is in byte 3 of the request +; header (starting count at zero). +; + +CMDLEN = 0 ; length of this command +UNIT = 1 ; sub unit specifier +CMD = 2 ; command code +STATUS = 3 ; status +MEDIA = 13 ; media descriptor +TRANS = 14 ; transfer address +COUNT = 18 ; count of blocks or characters +START = 20 ; first block to transfer +EXTRA = 22 ; Usually pointer to Vol Id for error 15 + +; +; Strategy is the strategy entry point for all default bio device drivers. +; All that is done is to save the pointer to the request header in the +; variable PtrSav. +; + +PUBLIC STRATEGY +STRATEGY PROC FAR + mov word ptr CS:[PTRSAV],BX + mov word ptr CS:[PTRSAV+2],ES + ret + +STRATEGY ENDP + + +;------------------------------------------------------------------------------ +; +; Device entry point +; +; The following ten pieces of code are the interrupt entry points for the +; default device drivers. These small pieces of code have two jobs. +; +; 1) Make SI point to the beginning of the proper command jump table. +; SI must first be pushed to preserve original contents. +; 2) If the call is an AUX or a printer save the number of the +; request in AL. AL is moved to AUXNUM below. +; + +; +; Con device: +; + +;;Rev 3.30 modification ----------------------------- + PUBLIC CON$IN +CON$IN PROC FAR + PUSH SI + MOV SI,OFFSET CONTBL + JMP SHORT ENTRY +CON$IN ENDP + + PUBLIC AUX0$IN +AUX0$IN PROC FAR + PUSH SI + PUSH AX + XOR AL,AL + JMP SHORT AUXENT +AUX0$IN ENDP + + PUBLIC AUX1$IN +AUX1$IN PROC FAR + PUSH SI + PUSH AX + MOV AL,1 + JMP short AUXENT +AUX1$IN ENDP + + PUBLIC AUX2$IN +AUX2$IN proc far + push si + push ax + mov al,2 + jmp short AUXENT +AUX2$IN endp + + PUBLIC AUX3$IN +AUX3$IN proc far + push si + push ax + mov al,3 + jmp short AUXENT + +AUXENT: + MOV SI,OFFSET AUXTBL + JMP SHORT ENTRY1 +AUX3$IN ENDP + +PRN0$IN PROC FAR + PUBLIC PRN0$IN + + PUSH SI + PUSH AX + XOR AX,AX + JMP SHORT PRNENT +PRN0$IN ENDP + + PUBLIC PRN1$IN +PRN1$IN PROC FAR + PUSH SI + PUSH AX + XOR AL,AL + MOV AH,1 + JMP SHORT PRNENT +PRN1$IN ENDP + + PUBLIC PRN2$IN +PRN2$IN PROC FAR + PUSH SI + PUSH AX + MOV AL,1 + MOV AH,2 + JMP SHORT PRNENT +PRN2$IN ENDP + + PUBLIC PRN3$IN +PRN3$IN PROC FAR + PUSH SI + PUSH AX + MOV AL,2 + MOV AH,3 +PRNENT: + MOV SI,OFFSET PRNTBL + MOV CS:[PRINTDEV],AH ;SAVE INDEX TO ARRAY OF RETRY CNTS + JMP SHORT ENTRY1 +PRN3$IN ENDP + + PUBLIC TIM$IN +TIM$IN PROC FAR + PUSH SI + MOV SI,OFFSET TIMTBL + JMP SHORT ENTRY +TIM$IN ENDP + + PUBLIC DSK$IN +DSK$IN PROC FAR + push SI + mov SI,OFFSET DSKTBL +;;End of modification ----------------------------- + + + +; +; This section is the prolog to all default device drivers. All registers +; are saved, the registers are filled with information fromthe request header, +; and the routine from the jump table is called. Error checking is done +; to assure command code is valid. Before calling the routine in the +; jump table the register are: +; +; AH = Media Descriptor +; AL = Unit Code +; BX = offset to PTRSAV (request header is therefore at DS:BX) +; CX = count from request header +; DX = start sector +; ES:DI = tranfer address +; SI = points to jump table +; DS = points to this segment +; +; Once the routine finishes its job it jumps back to one of the eight +; pieces of code below labeled Exit Points. +; + +ENTRY: + push AX +ENTRY1: + push CX ; save all registers + push DX + push DI + push BP + push DS + push ES + push BX + + mov CS:[AUXNUM],AL ; save choice of AUX/PRN device + + lds BX,CS:[PTRSAV] ; get pointer to I/O packet + ASSUME DS:NOTHING + + mov AL,byte ptr DS:[BX].UNIT ;AL = UNIT CODE + mov AH,byte ptr DS:[BX].MEDIA ;AH = MEDIA DESCRIP + mov CX,word ptr DS:[BX].COUNT ;CX = COUNT + mov DX,word ptr DS:[BX].START ;DX = START SECTOR + + xchg DI,AX + mov AL,BYTE PTR DS:[BX].CMD + cmp AL,CS:[SI] ; is command code a valid number? + ja CMDERR ; no, jump to handle error + + cbw ; note that AL <= 15 means OK + shl AX,1 + add SI,AX ; get SI to point to address of routine + xchg AX,DI ; put proper value back into AX + ; get ES:DI to point to transfer address + les DI,DWORD PTR DS:[BX].TRANS + push CS ; get DS equal to CS + pop DS + + ASSUME DS:CODE + + cld ; clear the direction flag + jmp WORD PTR [SI+1] ; go to the command + +DSK$IN ENDP +PAGE +;===================================================== +;= +;= SUBROUTINES SHARED BY MULTIPLE DEVICES +;= +;===================================================== + + + +;---------------------------------------------------------- +; +; Exit Points +; +; All device driver call return through one of these eight +; pieces of code. The code set error and status conditions +; and then restores the registers. +; + +PUBLIC BUS$EXIT ; device busy exit +BUS$EXIT PROC FAR + ASSUME DS:NOTHING + mov AH,00000011B ; set error code + jmp SHORT ERR1 + +PUBLIC CMDERR +CMDERR: + mov AL,3 ; unknown command error + +PUBLIC ERR$CNT +ERR$CNT: + lds BX,CS:[PTRSAV] + ASSUME DS:NOTHING + sub WORD PTR [BX].COUNT,CX ;# of successful I/O's + +PUBLIC ERR$EXIT +ERR$EXIT: + mov AH,10000001B ; mark error and return + jmp SHORT ERR1 + +BUS$EXIT ENDP +EXITP proc FAR + ASSUME DS:CODE + +EXIT$ZER: + lds BX,[PTRSAV] + ASSUME DS:NOTHING + xor AX,AX + mov WORD PTR [BX].COUNT,AX ; indicate no character read + +Public EXIT +EXIT: + ASSUME DS:NOTHING + mov AH,00000001B +ERR1: + ASSUME DS:NOTHING + lds BX,CS:[PTRSAV] + mov WORD PTR [BX].STATUS,AX ; mark operation complete + + pop BX ; restore register and return + pop ES + pop DS + pop BP + pop DI + pop DX + pop CX + pop AX + pop SI + ret +EXITP endp + + +;------------------------------------------------------------- +; +; Chrout - write out character in AL using current attribute +; +; called via int 29h +; + PUBLIC CHROUT +CHROUT = 29H + + Public OUTCHR +OUTCHR PROC FAR + push AX ; preserve affect registers + push SI + push DI + push BP + push bx ; + mov AH, 0Eh ; set command to write a character + mov bh,0 ; + mov BL, 7 ; set foreground color + int 10h ; call rom-bios + pop bx ; + pop BP ; restore registers + pop DI + pop SI + pop AX + iret +OUTCHR ENDP + + +;---------------------------------------------- +; +; Fill DX register with value in AUXNUM +; + + PUBLIC GETDX +GETDX PROC NEAR + mov DX,WORD PTR CS:[AUXNUM] + ret +GETDX ENDP + page +CODE ENDS + END diff --git a/SRC/BIOS/MSBIO1.OBJ b/SRC/BIOS/MSBIO1.OBJ new file mode 100644 index 0000000..8177a31 Binary files /dev/null and b/SRC/BIOS/MSBIO1.OBJ differ diff --git a/SRC/BIOS/MSBIO2.ASM b/SRC/BIOS/MSBIO2.ASM new file mode 100644 index 0000000..42bd7d6 --- /dev/null +++ b/SRC/BIOS/MSBIO2.ASM @@ -0,0 +1,650 @@ + TITLE MSBIO2 - DOS 3.3 + +;------------------------------------------------------------------------------- +; : +; Microsoft Bio : +; : +; The file msbio.asm is the main file in the Mircosoft bio. This file : +; includes the other main files in the bio. Most of the routines are : +; in these include files. The main files included are: : +; : +; File Contains : +; : +; msdisk.inc Disk device driver routines : +; ms96tpi.inc Routines for 96tpi drives : +; msaux.inc Device driver for the rs-232 serial ports : +; msclock.inc Device driver for "clock$" device : +; mscon.inc Device driver for "con" : +; mslpt.inc Device driver for the printers : +; : +; Each of these files contain a header section documenting the code : +; in that file. : +; Msbio also includes several files for equ's, structure definition, : +; macro definitions, etc. These are: : +; : +; msbiomes.inc msmacro.inc devsym.inc : +; dskprm.inc error.inc : +; : +; Each of these file contains explanitory notes. : +; : +; The actual code in msbio can be broken down into several piece: : +; : +; macro definitions Several marco are defined in msbio. They : +; are a few odds and end that did not fit : +; anywhere else. : +; : +; Command Jump Table List of entry points in the device drivers. : +; See notation below for full explination. : +; : +; Interrupt and Strategy : +; Entry points Calls on the device driver first come to here. : +; There is common code with pushes registers and : +; the like before jumping to routines in the : +; driver files. The common exit points are also : +; in this file. : +; : +; Miscellaneous Code There are several routines and data structure : +; declarations. See below for details. : +; : +;------------------------------------------------------------------------------- + + + +; +; If the variable TEST is non-zero then code for debugging is included. +; The extra code will make the binary file nuch larger. +; The symbol is also defined in msequ.inc. Both must be changed to +; turn debugging on or off. +; +; The level of the debugging is controled by the variable fTestBits in +; this file. See the comment preceeding the variable for more information. +; The actual routines which print the messages are in msmacro.inc +; See the header comment in this file for more information. +; + + +; +; Revision History +; +; REV 2.1 5/1/83 ARR added timer int handler and changed order of AUX +; PRN init for HAL0 +; +; REV 2.15 7/13/83 ARR Because of IBM design issues, and that BASCOM +; is ill behaved with respect to the 1CH timer interrupt, +; the timer handler has to be backed out! The intended +; code is commented out and has an ARR 2.15 annotation. +; This means the BIOS will go back to the multiple roll +; over bug. +; +; REV 2.20 8/5/83 ARR IBM makes hardware change. Now wants to use half +; height drives for HAL0, and back fit for PC/PC XT. Problem +; with head settle time. Previous drives got by on a 0 +; settle time, 1/2 hight drives need 15 head settle when +; doing WRITEs (0 ok on READ) if the head is being stepped. +; This requires a last track value to be kept so that BIOS +; knows when head is being moved. To help out +; programs that issue INT 13H directly, the head settle will +; normally be set to 15. It will be changed to 0 on READs, +; or on WRITEs which do not require head step. +; +; REV 2.21 8/11/83 MZ IBM wants write with verify to use head settle 0. +; Use same trick as above. +; +; REV 2.25 6/20/83 mjb001 added support for 96tpi and salmon +; +; REV 2.30 6/27/83 mjb002 added real-time clock +; +; REV 2.40 7/8/83 mjb003 added volume-id checking and int 2f macro +; definitions push* and pop* +; +; REV 2.41 7/12/83 ARR more 2.X enhancements. Open/Close media change +; +; REV 2.42 11/3/83 ARR more 2.X enhancements. Disk OPEN/CLOSE, FORMAT +; code and other misc hooked out to shrink BIOS. Code for +; Disk OPEN/CLOSE, FORMAT included only with 96tpi disks. +; +; Rev 2.43 12/6/83 MZ Examine boot sectors on hard disks for 16-bit fat +; check. Examine large fat bit in BPB for walk of media for +; DOS +; +; Rev 2.44 12/9/83 ARR Change to error reporting on INT 17H +; +; Rev 2.45 12/22/83 MZ Make head settle change only when disk parm is 0. + +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +; IBM ADDRESSES FOR I/O +; +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +;Below was moved from sysinit1 +ROMSEGMENT EQU 0F000H +MODELBYTE EQU DS:BYTE PTR [0FFFEH] +MODELPCJR EQU 0FDH + + test=0 +;;Rev 3.30 modification ---------------------------- + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + INCLUDE MSEQU.INC + INCLUDE DEVSYM.INC + INCLUDE PUSHPOP.INC + INCLUDE MSMACRO.INC + + ASSUME DS:NOTHING,ES:NOTHING + + EXTRN DSK$IN:NEAR + EXTRN SETPTRSAV:NEAR + EXTRN OUTCHR:NEAR + EXTRN SETDRIVE:NEAR + EXTRN FLUSH:NEAR + EXTRN HARDERR:NEAR + EXTRN HARDERR2:NEAR + EXTRN MAPERROR:NEAR + EXTRN GETBP:NEAR + EXTRN CHECKSINGLE:NEAR + EXTRN CHECK_TIME_OF_ACCESS:NEAR + EXTRN EXIT:NEAR + EXTRN HAS1:NEAR + EXTRN HAS1_res:NEAR + EXTRN READ_SECTOR:NEAR + EXTRN INT_2F_13:FAR + + EXTRN OLD13:DWORD + +;DATA + EXTRN PTRSAV:DWORD + EXTRN START_BDS:WORD + EXTRN FDRIVE1:WORD + EXTRN FDRIVE2:WORD + EXTRN FDRIVE3:WORD + EXTRN FDRIVE4:WORD + EXTRN FLAGBITS:WORD + EXTRN TIM_DRV:BYTE + EXTRN MEDBYT:BYTE + EXTRN DRVMAX:BYTE + + PATHSTART 005,DISK + EVENB + PUBLIC ORIG19 +ORIG19 DD ? + + PUBLIC INT19SEM +INT19SEM DB 0 ; INDICATE THAT ALL INT 19 + ; INITIALIZATION IS COMPLETE + + IRP AA,<02,08,09,0A,0B,0C,0D,0E,70,72,73,74,76,77> + public Int19OLD&AA +Int19OLD&AA dd -1 ;Orignal hw int. vec for INT 19h. + ENDM + + EVENB + PUBLIC DSKDRVS +DSKDRVS DW FDRIVE1 + DW FDRIVE2 + DW FDRIVE3 + DW FDRIVE4 + PUBLIC HDSKTAB +HDSKTAB DW HDRIVE + DW DRIVEX +;* Next area is reseved for mini disk BPB pointers *** 4/7/86 +;* Don't change this pos. Should be add. from DskDrvs *** 4/7/86 +MINI_DISK_BPB_PTRS DB 40 dup (?) ;4/7/86 - mem res for Mini disk. + + EVENB + PUBLIC INT_2F_NEXT +INT_2F_NEXT DD ? + +RET_ADDR DD ? + + PATHEND 005,DISK +;;End of modification ---------------------------- + +; INT19 +; +; We "hook" the INT_REBOOT vector, because contrary to IBM documentation, +; it does NOT "bootstrap" the machine. It leaves memory almost untouched. +; Since the BIOS_INIT code assumes that certain Interrupt Vectors point to +; the ROM_BIOS we must "unhook" them before issuing the actual INT_REBOOT. +; Currently the following vectors need to be unhooked: +; 02,08,09,0A,0B,0C,0D,0E,70,72,73,74,75,76,77 +; + +Public Int19 +Int19 proc FAR + xor AX,AX ; get data segment to + mov DS,AX ; point to the vector table + assume ds:nothing + assume es:nothing + les DI,Old13 ; get ES to point to this segment + mov DS:[13h*4],DI ; restore old int13 value + mov DS:[13h*4+2],ES + + cmp Byte ptr Int19Sem, 0 + jnz int19vecs + jmp doint19 + +;;Dos 3.30 Will not support the PC-Jr +;;Rev 3.30 modification ---------------------------- +; ON THE PCJR, DON'T REPLACE ANY VECTORS +; MODEL BYTE DEFINITIONS FROM MSSTACK.ASM +; MOV AX,ROMSEGMENT +; MOV DS,AX +; MOV AL,MODELPCJR +; +; CMP AL,MODELBYTE +; JNE INT19VECS +; JMP DOINT19 + + +;Stacks code has changed these hardware interrupt vectors +;STKINIT in SYSINIT1 will initialzie Int19hOLDxx values. +int19vecs: + +; +; we now need to unhook all the vector replace to prevent stack overflow +; + +;;Rev 3.30 modification ---------------------------- + XOR AX,AX + MOV DS,AX + + IRP AA,<02,08,09,0A,0B,0C,0D,0E,70,72,73,74,76,77> + + LES DI,Int19OLD&AA + + mov ax,es ; Put segment where we can compare it + cmp ax,-1 ; OPT 0ffffh is not likely + je skip_int&AA ; OPT could get away without checking + cmp di,-1 ; OPT offset here. + je skip_int&AA + + MOV DS:[AA&H*4],DI + MOV DS:[AA&H*4+2],ES +skip_int&AA: + ENDM +;;End of modification ---------------------------- + +doint19: + LES DI,Orig19 + MOV DS:[19h*4],DI + MOV DS:[19h*4+2],ES + + INT 19h +INT19 ENDP +ASSUME DS:CODE + +;***************************************************************************** +PUBLIC DSK$INIT +DSK$INIT PROC NEAR + PUSH CS + POP DS + MOV AH,BYTE PTR DRVMAX + MOV DI,OFFSET DskDrvs + JMP SetPTRSAV +DSK$INIT ENDP + + +; +; Int 2f handler for external block drivers to communicate with the internal +; block driver in msdisk. The multiplex number chosen is 8. The handler +; sets up the pointer to the request packet in [PTRSAV] and then jumps to +; DSK$IN, the entry point for all disk requests. +; On exit from this driver (at EXIT), we will return to the external driver +; that issued this Int 2F, and can then remove the flags from the stack. +; This scheme allows us to have a small external device driver, and makes +; the maintainance of the various drivers (DRIVER and msBIO) much easier, +; since we only need to make changes in one place (most of the time). +; +; AL contains the Int2F function: +; 0 - Check for installed handler - RESERVED +; 1 - Install the BDS into the linked list +; 2 - DOS request +; + +MYNUM EQU 8 + +Public Int2F_Disk +Int2F_Disk PROC FAR + cmp ah,MYNUM + je Mine + jmp cs:[Int_2F_Next] ; chain to next Int 2F handler +Mine: + cmp al,0F8H ; IRET on reserved functions + jb Do_Func + IRET +Do_Func: + or al,al ; A GET INSTALLED STATE request? + jne Disp_Func + mov al,0FFH + IRET +Disp_Func: + Message fTestInit,<"Int2F_disk",cr,lf> + cmp al,1 ; Request for installing BDS? + jne Do_DOS_Req + call Install_BDS + IRET + +Do_DOS_Req: +; Set up pointer to request packet + MOV WORD PTR CS:[PTRSAV],BX + MOV WORD PTR CS:[PTRSAV+2],ES + jmp DSK$IN + +Int2F_Disk ENDP + +; +; Install_BDS installs a BDS a location DS:DI into the current linked list of +; BDS maintained by this device driver. It places the BDS at the END of the +; list. +Public Install_BDS +INSTALL_BDS PROC NEAR + message ftestinit,<"Install BDS",cr,lf> +; ds:di point to BDS to be installed + les si,dword ptr cs:[Start_BDS] ; Start at beginning of list + push es ; Save pointer to current BDS + push si +; es:si now point to BDS in linked list +Loop_Next_BDS: + cmp si,-1 ; got to end of linked list? + jz Install_Ret +; If we have several logical drives using the same physical drive, we must +; set the I_Am_Mult flag in each of the appropriate BDSs. + mov al,byte ptr ds:[di].DriveNum + cmp byte ptr es:[si].DriveNum,al + jnz Next_BDS + message ftestinit,<"Logical Drives",cr,lf> + xor bx,bx + mov bl,fI_Am_Mult + or word ptr ds:[di].flags,bx ; set flags in both BDSs concerned + or word ptr es:[si].flags,bx + mov bl,fI_Own_Physical + xor bx,-1 + and word ptr ds:[di].flags,bx ; reset that flag for 'new' BDS +; We must also set the fChangeline bit correctly. + mov bx,word ptr es:[si].flags ; determine if changeline available + and bl,fChangeline + xor bh,bh + or word ptr ds:[di].flags,bx + +Next_BDS: +; Before moving to next BDS, preserve pointer to current one. This is needed at +; the end when the new BDS is linked into the list. + pop bx ; discard previous pointer to BDS + pop bx + push es + push si + mov bx,word ptr es:[si].link + 2 + mov si,word ptr es:[si].link + mov es,bx + jmp short Loop_Next_BDS + +Install_Ret: + pop si ; Retrieve pointer to last BDS + pop es ; in linked list. + mov ax,ds + mov word ptr es:[si].link+2,ax ; install BDS + mov word ptr es:[si].link,di + mov word ptr ds:[di].link,-1 ; set NEXT pointer to NULL + RET +INSTALL_BDS ENDP + +; +; RE_INIT installs the Int 2F vector that will handle communication between +; external block drivers and the internal driver. It also installs the +; Reset_Int_13 interface. It is called by SYSYINIT +; +PUBLIC RE_INIT +RE_INIT PROC FAR + Message ftestinit,<"REINIT",CR,LF> + PUSH AX + PUSH DS + PUSH DI + XOR DI,DI + MOV DS,DI + MOV DI,2FH*4 ; point it to Int 2F Vector + MOV AX,WORD PTR DS:[DI] + MOV WORD PTR CS:[INT_2F_NEXT],AX + MOV AX,WORD PTR DS:[DI+2] ; preserve old Int 2F vector + MOV WORD PTR CS:[INT_2F_NEXT+2],AX + +; INSTALL the Reset_Int_13 +; interface + + + CLI + MOV Word Ptr DS:[DI],Offset Int_2f_13 ; install new vectors + MOV Word Ptr DS:[DI+2],CS + STI + POP DI + POP DS + POP AX + RET + +RE_INIT ENDP + +;------------------------------------------------- +; +; Ask to swap the disk in drive A: +; Using a different drive in a one drive system so +; request the user to change disks +; +Public SWPDSK +SWPDSK PROC NEAR + mov al,byte ptr ds:[di].drivelet ; get the drive letter + add al,"A" + mov cs:DRVLET,AL + push ds ; preserve segment register + push cs + pop ds + mov SI,OFFSET SNGMSG ; ds:si -> message + push BX + call WRMSG ;Print disk change message + call FLUSH + ; wait for a keyboard character + xor AH, AH ; set command to read character + int 16h ; call rom-bios + POP BX + pop ds ; restore segment register +WRMRET: + ret +SWPDSK ENDP + +;---------------------------------------------- +; +; WrMsg writes out message pointed to by [SI] +; +Public WrMsg +WRMSG PROC NEAR + lodsb ; get the next character of the message + or AL,AL ; see fi end of message + jz WRMRET + pushf + push CS + call OUTCHR + jmp SHORT WRMSG +WRMSG ENDP + + INCLUDE BIOMES.INC + +; +; End of support for multiple floppies with no logical drives +; This is not 'special' any more because we now have the capability of +; defining logical drives in CONFIG.SYS. We therefore keep the code for +; swapping resident ALL the time. +; + +;;Rev 3.30 modification ---------------------------- +;Variables for Dynamic Relocatable modules +;These should be stay resident. + + public INT6C_RET_ADDR +INT6C_RET_ADDR DD ? ;ret add from INT 6C for P12 mach + + PATHSTART 001,CLK +; +; DATA STRUCTURES FOR REAL-TIME DATE AND TIME +; + public BIN_DATE_TIME + public MONTH_TABLE + public DAYCNT2 + public FEB29 +BIN_DATE_TIME: + DB 0 ; CENTURY (19 OR 20) OR HOURS (0-23) + DB 0 ; YEAR IN CENTURY (0-99) OR MINUTES (0-59) + DB 0 ; MONTH IN YEAR (1-12) OR SECONDS (0-59) + DB 0 ; DAY IN MONTH (1-31) +MONTH_TABLE: + DW 0 ;MJB002 JANUARY + DW 31 ;MJB002 FEBRUARY + DW 59 ;MJB002 + DW 90 ;MJB002 + DW 120 ;MJB002 + DW 151 ;MJB002 + DW 181 ;MJB002 + DW 212 ;MJB002 + DW 243 ;MJB002 + DW 273 ;MJB002 + DW 304 ;MJB002 + DW 334 ;MJB002 +DAYCNT2 DW 0000 ;MJB002 TEMP FOR CNT OF DAYS SINCE 1-1-80 +FEB29 DB 0 ;MJB002 FEBRUARY 29 IN A LEAP YEAR FLAG + PATHEND 001,CLK + +;;End of modification modification ---------------------------- + +Public EndFloppy +EndFloppy Label Byte +; +; End of code for virtual floppy drives +; +Public EndSwap +EndSwap Label Byte + + PATHSTART 004,BIO + +Public HNUM +HNUM DB 0 ; number of hardfile (hard drives) + +Public HardDrv +HARDDRV DB 80H ;Physical drive number of first hardfile + + +; +; "HDRIVE" is a hard disk with 512 byte sectors +; + + EVENB +Public BDSH +BDSH DW -1 ; Link to next structure + DW Code + DB 80h ; physical drive number + DB "C" ; Logical Drive Letter +Public HDRIVE +HDRIVE: + DW 512 + DB 1 ; Sectors/allocation unit + DW 1 ; Reserved sectors for DOS + DB 2 ; No. of allocation tables + DW 16 ; Number of directory entries + DW 0000 ; Number of sectors (at 512 bytes each) + DB 11111000B ; Media descriptor + DW 1 ; Number of FAT sectors + DW 00 ; Sector limit + DW 00 ; Head limit + DW 00 ; Hidden sector count + DB 0 ; TRUE => bigfat +OPCNTH DW 0 ; Open Ref. Count +VOLIDH DB "NO NAME ",0 ; Volume ID for this disk + DB 3 ; Form Factor +FLAGSH DW 0020H ; Various Flags + dw 40 ; number of cylinders +RecBPBH db 31 dup (?) ; Recommended BPB for drive +TRACKH DB -1 ; Last track accessed on this drive +TIM_LOH DW -1 ; Keep these two contiguous (?) +TIM_HIH DW -1 +; +; End of single hard disk section +; + + +Public EndOneHard +EndOneHard Label Byte + + + + +; +;"DRIVEX" is an extra type of drive usually reserved for an +; additional hard file +; + + EVENB +Public BDSX +BDSX DW -1 ; Link to next structure + DW Code + DB 81h ; physical drive number + DB "D" ; Logical Drive Letter +Public DRIVEX +DRIVEX: + DW 512 + DB 00 ; Sectors/allocation unit + DW 1 ; Reserved sectors for DOS + DB 2 ; No. of allocation tables + DW 0000 ; Number of directory entries + DW 0000 ; Number of sectors (at 512 bytes each) + DB 11111000B ; Media descriptor + DW 0000 ; Number of FAT sectors + DW 00 ; Sector limit + DW 00 ; Head limit + DW 00 ; Hidden sector count + DB 0 ; TRUE => bigfat +OPCNTD DW 0 ; Open Ref. Count +VOLIDD DB "NO NAME ",0 ; Volume ID for this disk + DB 3 ; Form Factor +FLAGSD DW 0020H ; Various Flags + dw 40 ; number of cylinders +RecBPBD db 31 dup (?) ; Recommended BPB for drive +TRACKD DB -1 ; Last track accessed on this drive +TIM_LOD DW -1 ; Keep these two contiguous +TIM_HID DW -1 + +; +; End of section for two hard disks +Public EndTwoHard +EndTwoHard Label Byte + + PATHEND 004,BIO + + +Public TwoHard +TWOHARD LABEL BYTE + +PAGE +include ms96tpi.inc + +;;Rev 3.30 modification ---------------------------- +;Memory allocation for BDSM table. + PUBLIC BDSMs +BDSMs BDSM_type Max_mini_dsk_num dup (<>) ;currently max. 23 + +;** End_of_BDSM defined in MSINIT.ASM will be used to set the appropriate +;** ending address of BDSM table. +;;End of modification ---------------------------- + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug005sp +; +;;3.3 BUG FIX -SUNILP ------------------------------ +;Paragraph buffer between the BDSMs and MSHARD +; +;The relocation code for MSHARD needs this. this cannot be used for +;anything. nothing can come before this or after this.....IMPORTANT!!!! +;don't get too smart and using this buffer for anything!!!!!! +; +; db 16 dup(0) +; +;end of bug fix buffer +;; +;;3.3 BUG FIX -SUNILP------------------------------ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug005sp +CODE ENDS + END diff --git a/SRC/BIOS/MSBIO2.OBJ b/SRC/BIOS/MSBIO2.OBJ new file mode 100644 index 0000000..c973327 Binary files /dev/null and b/SRC/BIOS/MSBIO2.OBJ differ diff --git a/SRC/BIOS/MSCLOCK.ASM b/SRC/BIOS/MSCLOCK.ASM new file mode 100644 index 0000000..a7bd39f --- /dev/null +++ b/SRC/BIOS/MSCLOCK.ASM @@ -0,0 +1,295 @@ + TITLE MSCLOCK - DOS 3.3 +;---------------------------------------------------------------- +; : +; CLOCK DEVICE DRIVER : +; : +; : +; This file contains the Clock Device Driver. : +; : +; The routines in this files are: : +; : +; routine function : +; ------- -------- : +; TIM$WRIT Set the current time : +; TIM$READ Read the current time : +; Time_To_Ticks Convert time to corresponding : +; number of clock ticks : +; : +; The clock ticks at the rate of: : +; : +; 1193180/65536 ticks/second (about 18.2 ticks per second): +; See each routine for information on the use. : +; : +;---------------------------------------------------------------- + + + test=0 + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + INCLUDE MSMACRO.INC + + EXTRN EXIT:NEAR +; +; DAYCNT is the number of days since 1-1-80. +; Each time the clock is read it is necessary to check if another day has +; passed. The ROM only returns the day rollover once so if it is missed +; the time will be off by a day. +; + EXTRN DAYCNT:WORD ;MSDATA + +;;Rev 3.30 Modification ------------------------------------------------ +; variables for real time clock setting + public HaveCMOSClock +HaveCMOSClock db 0 ;set by MSINIT. + public base_century +base_century db 19 + public base_year +base_year db 80 + public month_tab +month_tab db 31,28,31,30,31,30,31,31,30,31,30,31 + +; The following are indirect intra-segment call addresses. The +;procedures are defined in MSINIT for relocation. MSINIT will set these +;address when the relocation is done. + public BinToBCD +BinToBCD dw 0 ;should point to Bin_To_BCD proc in MSINIT + public DaycntToDay +DaycntToDay dw 0 ;should point to Daycnt_to_day in MSINIT + +;******************************************************************** +; Indirect call address of TIME_TO_TICKS procedure. +;This will be used by the relocatable portable suspend/resume code. + + public TimeToTicks +TimeToTicks dw Time_To_Ticks + +;;End of Modification ------------------------------------------------ + +;-------------------------------------------------------------------- +; +; Settime sets the current time +; +; On entry ES:[DI] has the current time: +; +; number of days since 1-1-80 (WORD) +; minutes (0-59) (BYTE) +; hours (0-23) (BYTE) +; hundredths of seconds (0-99) (BYTE) +; seconds (0-59) (BYTE) +; +; Each number has been checked for the correct range. +; + PUBLIC TIM$WRIT +TIM$WRIT PROC NEAR + ASSUME DS:CODE + mov AX,WORD PTR ES:[DI] + push AX ;DAYCNT. We need to set this at the very + ; end to avoid tick windows. +;;Rev 3.30 Modification + cmp HaveCMOSClock, 0 + je No_CMOS_1 + mov al,es:[di+3] ;get binary hours + call BinToBCD ;convert to BCD + mov ch,al ;CH = BCD hours + mov al,es:[di+2] ;get binary minutes + call BinToBCD ;convert to BCD + mov cl,al ;CL = BCD minutes + mov al,es:[di+5] ;get binary seconds + call BinToBCD ;convert to BCD + mov dh,al ;DH = BCD seconds + mov dl,0 ;DL = 0 (ST) or 1 (DST) + cli ;turn off timer + mov ah,03h ;set RTC time + int 1Ah ;call rom bios clock routine + sti + +;;End of Modification +No_CMOS_1: + mov CX,WORD PTR ES:[DI+2] + mov DX,WORD PTR ES:[DI+4] +;;Rev 3.30 Modification + call time_to_ticks ; convert time to ticks + ;CX:DX now has time in ticks + cli ; Turn off timer + mov AH, 1 ; command is set time in clock + int 1Ah ; call rom-bios clock routines + pop [DAYCNT] + sti +;CMOS clock ------------------------------------- + cmp HaveCMOSClock, 0 + je No_CMOS_2 + call DaycntToDay ; convert to BCD format + cli ; Turn off timer + mov AH,05h ; set RTC date + int 1Ah ; call rom-bios clock routines + sti +;------------------------------------------------ + +No_CMOS_2: + jmp EXIT +TIM$WRIT ENDP +;;End of Modification + + + +; +; convert time to ticks +; input : time in CX and DX +; ticks returned in CX:DX +; +public time_to_ticks +TIME_TO_TICKS PROC NEAR + + ; first convert from Hour,min,sec,hund. to + ; total number of 100th of seconds + mov AL,60 + mul CH ;Hours to minutes + mov CH,0 + add AX,CX ;Total minutes + mov CX,6000 ;60*100 + mov BX,DX ;Get out of the way of the multiply + mul CX ;Convert to 1/100 sec + mov CX,AX + mov AL,100 + mul BH ;Convert seconds to 1/100 sec + add CX,AX ;Combine seconds with hours and min. + adc DX,0 ;Ripple carry + mov BH,0 + add CX,BX ;Combine 1/100 sec + adc DX,0 + +;;Rev 3.30 Modification +;DX:CX IS TIME IN 1/100 SEC + XCHG AX,DX + XCHG AX,CX ;NOW TIME IS IN CX:AX + MOV BX,59659 + MUL BX ;MULTIPLY LOW HALF + XCHG DX,CX + XCHG AX,DX ;CX->AX, AX->DX, DX->CX + MUL BX ;MULTIPLY HIGH HALF + ADD AX,CX ;COMBINE OVERLAPPING PRODUCTS + ADC DX,0 + XCHG AX,DX ;AX:DX=TIME*59659 + MOV BX,5 + DIV BL ;DIVIDE HIGH HALF BY 5 + MOV CL,AL + MOV CH,0 + MOV AL,AH ;REMAINDER OF DIVIDE-BY-5 + CBW + XCHG AX,DX ;USE IT TO EXTEND LOW HALF + DIV BX ;DIVDE LOW HALF BY 5 + MOV DX,AX + ; CX:DX is now number of ticks in time + ret +TIME_TO_TICKS ENDP +;;End of Modification + + +; +; Gettime reads date and time +; and returns the following information: +; +; ES:[DI] =count of days since 1-1-80 +; ES:[DI+2]=hours +; ES:[DI+3]=minutes +; ES:[DI+4]=seconds +; ES:[DI+5]=hundredths of seconds +; + PUBLIC TIM$READ +TIM$READ PROC NEAR + ; read the clock + xor AH, AH ; set command to read clock + int 1Ah ; call rom-bios to get time + + or al,al ; check for a new day + jz noroll1 ; if al=0 then don't reset day count + INC [DAYCNT] ; CATCH ROLLOVE +noroll1: + MOV SI,[DAYCNT] + +; +; we now need to convert the time in tick to the time in 100th of +; seconds. The relation between tick and seconds is: +; +; 65536 seconds +; ---------------- +; 1,193,180 tick +; +; To get to 100th of second we need to multiply by 100. The equation is: +; +; Ticks from clock * 65536 * 100 +; --------------------------------- = time in 100th of seconds +; 1,193,180 +; +; Fortunately this fromula simplifies to: +; +; Ticks from clock * 5 * 65,536 +; --------------------------------- = time in 100th of seconds +; 59,659 +; +; The calculation is done by first multipling tick by 5. Next we divide by +; 59,659. In this division we multiply by 65,536 by shifting the dividend +; my 16 bits to the left. +; +; start with ticks in CX:DX +; multiply by 5 + MOV AX,CX + MOV BX,DX + SHL DX,1 + RCL CX,1 ;TIMES 2 + SHL DX,1 + RCL CX,1 ;TIMES 4 + ADD DX,BX + ADC AX,CX ;TIMES 5 + XCHG AX,DX + + +; now have ticks * 5 in DX:AX +; we now need to multiply by 65,536 and divide by 59659 d. + + mov CX,59659 ; get divisor + div CX + ; DX now has remainder + ; AX has high word of final quotient + mov BX,AX ; put high work if safe place + xor AX,AX ; this is the multiply by 65536 + div CX ; BX:AX now has time in 100th of seconds + +; +;Rounding based on the remainder may be added here +;The result in BX:AX is time in 1/100 second. + mov DX,BX + mov CX,200 ;Extract 1/100's +;Division by 200 is necessary to ensure no overflow--max result +;is number of seconds in a day/2 = 43200. + div CX + cmp DL,100 ;Remainder over 100? + jb NOADJ + sub DL,100 ;Keep 1/100's less than 100 +NOADJ: + cmc ;If we subtracted 100, carry is now set + mov BL,DL ;Save 1/100's +;To compensate for dividing by 200 instead of 100, we now multiply +;by two, shifting a one in if the remainder had exceeded 100. + rcl AX,1 + mov DL,0 + rcl DX,1 + mov CX,60 ;Divide out seconds + div CX + mov BH,DL ;Save the seconds + div CL ;Break into hours and minutes + xchg AL,AH + +;Time is now in AX:BX (hours, minutes, seconds, 1/100 sec) + + push AX + MOV AX,SI ; DAYCNT + stosw + pop AX + stosw + mov AX,BX + stosw + jmp EXIT + +TIM$READ ENDP +CODE ENDS + END diff --git a/SRC/BIOS/MSCLOCK.OBJ b/SRC/BIOS/MSCLOCK.OBJ new file mode 100644 index 0000000..7b0708e Binary files /dev/null and b/SRC/BIOS/MSCLOCK.OBJ differ diff --git a/SRC/BIOS/MSCON.ASM b/SRC/BIOS/MSCON.ASM new file mode 100644 index 0000000..fff22a5 --- /dev/null +++ b/SRC/BIOS/MSCON.ASM @@ -0,0 +1,216 @@ + TITLE MSCON - DOS 3.3 + +;---------------------------------------------------------------- +; : +; C O N - CONSOLE DEVICE DRIVER : +; : +; : +; This file contains the Console Device Driver. The : +; console device driver sends characters to the moniter and : +; gets characters from the keyboard. : +; : +;---------------------------------------------------------------- + +;;Rev 3.30 Modification + test=0 + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + INCLUDE JUMPMAC.INC + INCLUDE MSEQU.INC + INCLUDE MSMACRO.INC + + EXTRN EXIT:NEAR ;MSBIO1 + EXTRN BUS$EXIT:NEAR ;MSBIO1 + +;DATA + EXTRN PTRSAV:DWORD ;MSBIO1 + EXTRN FHAVEK09:BYTE ;MSDISK + EXTRN ALTAH:BYTE ;MSDATA +;;End of Modification + + +;---------------------------------------------------------------- +; : +; Console read routine : +; : +;---------------------------------------------------------------- +; + ASSUME DS:CODE ; THIS WAS SET BY THE CON DD ENTRY PT + PUBLIC CON$READ +CON$READ PROC NEAR + ; if CX is zero, no characters + jcxz CON$EXIT ; to be read -- just exit +CON$LOOP: + call CHRIN ; get char in AL + stosb ; store char at ES:DI, specified buffer + loop CON$LOOP ; if CX is non-zero more char to read +CON$EXIT: + Jump EXIT ; all done, successful return +CON$READ ENDP + + +;---------------------------------------------------------------- +; : +; Input single character into AL : +; : +;---------------------------------------------------------------- +CHRIN PROC NEAR + ; set command to read character + xor AX, AX ; and clear AL + xchg AL,ALTAH ; get character & zero ALTAH + or AL, AL ; see if buffer has a character + jnz KEYRET ; if so - return this character + ; if not - read single character + int 16h ; call ROM-Bios keyboard routine +ALT10: + or AX,AX ; Check for non-key after BREAK + jz CHRIN + cmp AX,7200h ; Check for CTRL-PRTSC + jnz ALT15 + mov AL,16 ; indicate prtsc +ALT15: + or AL,AL ; special case? + jnz KEYRET ; no, return with character + mov ALTAH, AH ; yes, store special key +KEYRET: + RET +CHRIN ENDP + +;---------------------------------------------------------------- +; : +; Keyboard non destructive read, no wait : +; : +; If bit 10 is set by the DOS in the status word of the request : +; packet, and there is no character in the input buffer, the : +; driver issues a system WAIT request to the ROM. On return : +; from the ROM, it returns a 'char-not-found' to the DOS. : +; : +;---------------------------------------------------------------- + +CONBUSJ: + ASSUME DS:NOTHING + JMP CONBUS + + ASSUME DS:CODE ; THIS WAS SET BY THE CON DD ENTRY PT + PUBLIC CON$RDND +CON$RDND: + mov AL,[ALTAH] ; first see if there is a + or AL,AL ; character in the buffer? + jz RD1 ; with debugging code it is + jmp RDEXIT ; too far for conditional jump + +RD1: + ; set command to 'see if + mov AH, 1 ; character available' + int 16h ; call ROM-BIOS keyboard routine + jz nochr ; with debugging code it is + jmp gotchr ; to far for conditional jump +nochr: + cmp fHaveK09, 0 + jz CONBUSJ + lds bx,[PTRSAV] ; get pointer to request header + ASSUME DS:NOTHING + test [bx].STATUS,0400H ; System WAIT enabled? + jz CONBUSJ ; no, get out + + message ftestcon,<"System WAIT stage",cr,lf> + + mov AX, 4100h ; set command for Wait on External + ; event and condition type to + ; any external event + xor BL,BL ; no timeout value + int 15h ; call rom-bios sleep function + message ftestcon,<"Out of wait. AX is "> + mnum ftestcon,ax + message ftestcon, + jmp CONBUS ; after wait exit to con busy + + ASSUME DS:CODE +gotchr: + or AX, AX ; check for null after break + JNZ NOTBRK ; no, skip down +; note: AH is already zero, no need to set command + int 16h ;SB ; yes, read the null + Jump CON$RDND ; and get a real status + +NOTBRK: + cmp AX, 7200H ; check for ctrl-prtsc + jnz RDEXIT ; no + mov AL, 16 ; yes, indicate ctrl-prtsc + + PUBLIC RDEXIT +RDEXIT: + lds BX, [PTRSAV] ; get pointer to request header + ASSUME DS:NOTHING + mov [BX].MEDIA, AL ; move character into req. header +EXVEC: + Jump EXIT ; all done -- successful return +CONBUS: + ASSUME DS:NOTHING + Jump BUS$EXIT ; done -- con device is busy + + +;---------------------------------------------------------------- +; : +; Keyboard flush routine : +; : +;---------------------------------------------------------------- + ASSUME DS:CODE ; THIS WAS SET BY THE CON DD ENTRY PT + PUBLIC CON$FLSH +CON$FLSH: + call FLUSH + Jump Exit + + +PUBLIC FLUSH +FLUSH: + mov [ALTAH], 0 ; clear out holding buffer + +FlLoop: +;;Rev 3.30 Modification + ; Is there a char there? + mov AH, 1 ; command code for check status + int 16h ; call rom-bios keyboard routine + ; if z flag is set then no character + jz FlDone ; is ready, buffer is empty -- get out + xor AH, AH ; if zf is nof set, get character + int 16h ; call rom-bios to get character + jmp FlLoop ; repeat until buffer is empty +FlDone: + ret +;;Rev 3.30 Modification + + +;---------------------------------------------------------------- +; : +; Console Write Routine : +; : +;---------------------------------------------------------------- + ASSUME DS:CODE ; THIS WAS SET BY THE CON DD ENTRY PT + PUBLIC CON$WRIT +CON$WRIT: + jcxz EXVEC ; if CX is zero, get out +CON$LP: + mov AL,ES:[DI] ; get character + inc DI ; point to next character + int CHROUT ; Output character + loop CON$LP ; repeat until all through + Jump Exit + + + +;----------------------------------------------- +; +; BREAK KEY HANDLING +; +Public CBREAK +CBREAK: + mov CS:ALTAH, 3 ; indicate break key set + + + +Public INTRET +INTRET: + IRET + +CODE ENDS + END diff --git a/SRC/BIOS/MSCON.OBJ b/SRC/BIOS/MSCON.OBJ new file mode 100644 index 0000000..79b498e Binary files /dev/null and b/SRC/BIOS/MSCON.OBJ differ diff --git a/SRC/BIOS/MSDATA.INC b/SRC/BIOS/MSDATA.INC new file mode 100644 index 0000000..ebe3862 --- /dev/null +++ b/SRC/BIOS/MSDATA.INC @@ -0,0 +1,882 @@ +; +; After the boot sector reads in msbio it jumps to this location. Msbio +; immediately jumps to initialization code in msinit. +; + + EXTRN INIT:NEAR + +Public START$ +START$: + JMP INIT ; START$ patch by init to point to + ; hdrive BPB + + + PATHSTART 001,BIO + + +;---------------------------------------------------------------------------- +; +; Command Jump Tables +; +; These tables hold the entry points for the various service routines +; for the different drivers. The index in the table is the command code for +; that funcion plus two. For example the command code for Read (input) is 4, +; The 6th (4 plus 2) entry in the table DSKTBL is DSK$READ - the command to +; read a disk. Commands which do not exist for a device are filled with +; exit (e.g. MediaCheck for CONTBL). The first entry in the table is the +; largest command code implemented for that device. This value is used +; for error checking. If new command codes are added then the first entry +; in the table must be incremented. +; +; BEWARE - These tables overlap somewhat! -c.p. +; + +; +; Disk: +; + + ODD +DSKTBL LABEL BYTE + DB 24 ; This is the size of the table YUK!!!! + DW DSK$INIT ; Code 0: INIT + DW MEDIA$CHK ; code 1: Media Check + DW GET$BPB ; code 2: BUILD BPB + DW CMDERR ; code 3: IOCTL input + DW DSK$READ ; code 4: INPUT + DW BUS$EXIT ; code 5: NONDESTRUCITVE INPUT, NO WAIT + DW EXIT ; code 6: INPUT STATUS + DW EXIT ; code 7: INPUT FLUSH + DW DSK$WRIT ; code 8: OUTPUT + DW DSK$WRITV ; code 9: OUTPUT with verify + DW EXIT ; code 10: OUTPUT STATUS + DW EXIT ; code 11: OUTPUT FLUSH + DW CMDERR ; code 12: IOCTL output +Public TABLE_PATCH +TABLE_PATCH LABEL WORD ;ARR 2.42 + DW DSK$OPEN ; code 13: DEVICE OPEN + DW DSK$CLOSE ; code 14: DEVICE CLOSE + DW DSK$REM ; code 15: REMOVABLE MEDIA + dw exit + dw exit + dw exit + DW GENERIC$IOCTL + dw exit + dw exit + dw exit + dw IOCTL$GETOWN + dw IOCTL$SETOWN + +; +; Console: +; + + ODD +CONTBL LABEL BYTE + DB 10 + DW EXIT + DW EXIT + DW EXIT + DW CMDERR + DW CON$READ + DW CON$RDND + DW EXIT + DW CON$FLSH + DW CON$WRIT + DW CON$WRIT + DW EXIT + +; +; Auxilary: +; + + ODD +AUXTBL LABEL BYTE + DB 10 + DW EXIT + DW EXIT + DW EXIT + DW CMDERR + DW AUX$READ + DW AUX$RDND + DW EXIT + DW AUX$FLSH + DW AUX$WRIT + DW AUX$WRIT + DW AUX$WRST + +; +; Clock: +; + + ODD +TIMTBL LABEL BYTE + DB 9 + DW EXIT + DW EXIT + DW EXIT + DW CMDERR + DW TIM$READ + DW BUS$EXIT + DW EXIT + DW EXIT + DW TIM$WRIT + DW TIM$WRIT + +; +; Printer: +; + + ODD +PRNTBL LABEL BYTE + DB 24 + DW EXIT ;INIT + DW EXIT + DW EXIT + DW CMDERR + DW EXIT$ZER ;INDICATE ZERO CHARS READ + DW BUS$EXIT + DW EXIT + DW EXIT + DW PRN$WRIT + DW PRN$WRIT + DW PRN$STAT + DW EXIT + DW EXIT + DW EXIT + DW EXIT + DW EXIT + DW PRN$TilBusy + DW EXIT + DW EXIT + DW PRN$GenIOCTL + dw exit + dw exit + dw exit + dw CMDERR + dw CMDERR + + + EVENB +Public Old13 +OLD13 label DWORD + db '5986' ;Code for 3.30 + + +Public Orig13 +ORIG13 label DWORD + db '21',0,0 ;Code for 3.30 + + +; +; PTRSAV - pointer save +; +; This variable holds the pointer to the Request Header passed by a +; program wishing to use a device driver. When the strategy routine is +; called it puts the address of the Request header in this variable and +; returns. +; + + EVENB +PUBLIC PTRSAV +PTRSAV DD 0 + + +; +; Buffer for the AUX device driver +; + +;;Rev 3.30 Modification + PUBLIC AUXBUF +AUXBUF DB 0,0,0,0 ;SET OF 1 BYTE BUFFERS FOR COM 1,2,3, AND 4 + + + EVENB + PUBLIC PREVOPER,NUMBER_OF_SEC +;;End of Modification +PrevOper DW ? ; Holds ROM DISK INT request (i.e. Register AX). +Number_Of_Sec DB ? ; Holds number of sectors to read on an ECC error + + +;;Rev 3.30 Modification + IF ($-CODE) GT 100H + %OUT VDISK BUFFER NOT CORRECTLY LOCATED + ELSE + ORG 100H + ENDIF + PUBLIC VDISK_AREA +VDISK_AREA DB 108 DUP(0) ;FOR USE BY VDISK +;;End of Modification + + +; +; AUXNUM holds the number of the printer or AUX device requested. For +; example if printer 2 was called (PRN2$IN) AUXNUM is set to be one; with +; line printer 3 AUXNUM is set to 2. With this set the printer device driver +; can tell which printer to command applies to. +; +; WARNING!!! These are addressed together in GETDX +; + + EVENB +AUXNUM DB 0 + DB 0 + + +; +; Device Header for the CON Device Driver +; + + EVENB +PUBLIC CONHeader +CONHeader LABEL WORD + DD AUXDEV2 + DW 1000000000010011B ; Con in and con out + special + DW STRATEGY ; Strategy entry point + DW CON$IN ; interrupt entry point + DB 'CON ' ; device name + + +; +; Device Header for device "AUX" +; + + EVENB + PUBLIC AUXDEV2 +AUXDEV2 LABEL WORD ;HEADER FOR DEVICE "AUX" + DD PRNDEV2 + DW 1000000000000000B ; attribute word, character device + DW STRATEGY ; device strategy routine + DW AUX0$IN ; device interrupt routine + DB 'AUX ' ; device name + + +; +; Device Header for device PRN +; + + EVENB + PUBLIC PRNDEV2 +PRNDEV2 LABEL WORD ;HEADER FOR DEVICE "PRN" + DD TIMDEV + DW CharDev + OutTilBusy + Dev320 + DW STRATEGY + DW PRN0$IN + DB 'PRN ' + + +; +; Device Header for device CLOCK$ +; + + EVENB + PUBLIC TIMDEV +TIMDEV LABEL WORD + DD DSKDEV + DW 1000000000001000B + DW STRATEGY + DW TIM$IN + DB 'CLOCK$ ' + + +; +; Device Header for disk devices +; +; Device attribute bits: +; Bit 6 - DOS 3.2 Bit +; + + EVENB +PUBLIC DSKDEV +DSKDEV LABEL WORD + DD COM1DEV + DW 0000100001000000B ; DOS 3.2 + DW STRATEGY ; strategy routine + DW DSK$IN ; Interrupt entry point + + +; +; maximum number of drives +; + +DRVMAX DB 4 +Public DRVMAX + + +; +; Last drive accessed +; + + PUBLIC STEP_DRV +STEP_DRV DB -2 ; ARR 2.20 LAST DRIVE ACCESSED + +Public Phys_Drv +Phys_Drv DB 0 ; Used by setdrvie for getting + ; BDS for logical drive, or physical + ; drive. 0 => use logical + ; 1 => use physical + +Public fHave96 +fHave96 DB 0 ; Flag to indicate presence of + ; 96tpi support + +Public Single +Single DB 0 ; Used to detect single drive systems + +Public fHaveK09 +fHaveK09 DB 0 ;Indicates if this is a K09 or not + ; used by console driver. +Public NEW_ROM +NEW_ROM DB 0 ;Set to 1 if we have a ROM that can + ; handle strange media layouts. + + PUBLIC FSETOWNER +fSetOwner db ? ;=1 if we are setting the owner of a + ;drive. (Examined by CheckSingle). + public Secrete_Code +Secrete_Code dw 'jk' ;Code for 3.30. + + +; +; Device Header for device "COM1" +; + + EVENB +Public COM1DEV +COM1DEV LABEL WORD + DD LPT1DEV + DW 1000000000000000B ; attribute word, character device + DW STRATEGY ; device strategy routine + DW AUX0$IN ; device interrupt routine + DB 'COM1 ' ; device name + + +; +; Device Header for device LPT1 +; + + EVENB +Public LPT1DEV +LPT1DEV LABEL WORD + DD LPT2DEV + DW CharDev + OutTilBusy + Dev320 + DW STRATEGY + DW PRN1$IN + DB 'LPT1 ' + + +; +; Device Header for device LPT2 +; + + EVENB +Public Lpt2Dev +LPT2DEV LABEL WORD + DD LPT3DEV + DW CharDev + OutTilBusy + Dev320 + DW STRATEGY + DW PRN2$IN + DB 'LPT2 ' + +; +; Device Header for device LPT3 +; + + EVENB +Public Lpt3Dev +LPT3DEV LABEL WORD + DD COM2DEV + DW CharDev + OutTilBusy + Dev320 + DW STRATEGY + DW PRN3$IN + DB 'LPT3 ' + + +; +; Device Header for device "COM2" +; + + EVENB +Public Com2Dev +COM2DEV LABEL WORD + dd COM3DEV + DW 1000000000000000B ; attribute word, character device + DW STRATEGY ; device strategy routine + DW AUX1$IN ; device interrupt routine + DB 'COM2 ' ; device name + +;;Rev 3.30 Modification +; +; Device header for device "COM3" +; + EVENB + PUBLIC COM3DEV +COM3DEV LABEL WORD + dd COM4DEV + dw 1000000000000000b ; character device attribute + dw STRATEGY + dw AUX2$IN ; com3 == aux2 + db 'COM3 ' + +; +; Device header for device "COM4" +; + EVENB + PUBLIC COM4DEV +COM4DEV LABEL WORD + dw -1,CODE + dw 1000000000000000b ; character device attribute + dw STRATEGY + dw AUX3$IN ; com4 == aux3 + db 'COM4 ' + +;;End of Modification + + +; Hard-wire the link to the next Int2f handler. +;;Rev 3.30 Modification + EVENB +PUBLIC Next2f_13 +NEXT2F_13 LABEL WORD + EXTRN INT2F_DISK:FAR ;MSBIO2 + DD INT2F_DISK + + +; +; Start of linked list of BDS's +; + + EVENB +Public Start_BDS +START_BDS LABEL WORD + DD BDS1 ;START OF BDS LINKED LIST. +;;End of Modification + + +; +; Some floppy drives do not have changeline support. The result is a +; large amount of inefficiency in the code. A media-check always returns +; "I don`t know". This cause DOS to reread the FAT on every access and +; always discard any cached data. +; We get around this inefficiency by implementing a "Logical Door Latch". +; The following three items are used to do this. The logical door latch is +; based on the premise that it is not physically possible to change floppy +; disks in a drive in under two seconds (most people take about 10). The +; logical door latch is implemented by saving the time of the last successful +; disk operation (in the value TIM_DRV). When a new request is made the +; current time is compared to the saved time. If less than two seconds have +; passed then the value "No Change" is returned. If more than two seconds +; have passed the value "Don't Know" is returned. +; There is one complecation to this algorithm. Some programs change the +; value of the timer. In this unfortunate case we have an invalid timer. +; This possiblity is detected by counting the number of disk operations +; which occur without any time passing. If this count exceeds the value of +; "AccessMax" we assume the counter is invalid and always return "Don't +; Know". The variable "AccessCount" is used to keep track of the number +; of disk operation which occur without the time changing. +; + + PUBLIC ACCESSCOUNT +AccessCount db 0 ; number of times media check called + + PUBLIC TIM_DRV +TIM_DRV DB -1 ; time when last disk I/O was performed + + PUBLIC FLAGBITS +FlagBits dw 0 ; Bits to set in flag field when doing + ; a Set_Changed_DL + + PUBLIC MEDBYT +MedByt DB ? ; hold media byte from floppy + + EVENB + PUBLIC WRTVERIFY +WRTVERIFY LABEL WORD + + PUBLIC RFLAG +RFLAG DB ROMRead ;2 for read, 3 for write +VERIFY DB 0 ;1 if verify after write + + PUBLIC SECCNT +SECCNT DW 0 + + +Public HARDNUM +HARDNUM DB 99 ;logical drive number of first hardfile + +; +; Some of the older versions of the IBM rom-bios always assumed a seek would +; have to be made to read the diskette. Consequently a large head settle +; time was always used in the I/O operations. To get around this problem +; we need to continually adjust the head settle time. The following +; algorithm is used: +; +; Get the current head settle value. +; If it is 1, then +; set slow = 15 +; else +; set slow = value +; ... +; if we are seeking and writing then +; use slow +; else +; use fast +; ... +; restore current head settle value +; + + PUBLIC MOTORSTARTUP,SETTLECURRENT,SETTLESLOW +MotorStartup db ? ; value from table +SettleCurrent db ? ; value from table +SettleSlow db ? ; slow settle value + +NextSpeed DB ? ; value of speed to be used + + public save_head_sttl +Save_head_sttl db ? ;used by READ_SECTOR routine + + +Public EOT +EOT DB 9 + +; +; pointer to Disk Parameter Table +; + + EVENB + PUBLIC DPT +DPT DD ? + +; +; The following two sets of variables are used to hold values for +; disk I/O operations +; Keep the next two items contiguous - see IOCTL_Block for reason + + PUBLIC CURSEC,CURHD,CURTRK,SPSAV +CURSEC DB 0 ; current sector +CURHD DB 0 ; current head +CURTRK DW 0 ; current track +SPSAV DW 0 ; save the stack pointer + +; +; The following are used for IOCTL function calls +; + + PUBLIC FORMT_EOT,HDNUM,TRKNUM,GAP_PATCH +FORMT_EOT DB 8 ; EOT used for format +HDNUM DB 0 ; Head number +TRKNUM DW 0 ; Track being manipulated +GAP_PATCH DB 50h ; Format gap patched into DPT + +; +; Disk errors returned from the IBM rom +; + +Public ERRIN +ERRIN LABEL BYTE + DB 80H ; no response + DB 40H ; seek failure + DB 10H ; bad CRC + DB 8 ; DMA overrun + DB 6 ; media change + DB 4 ; sector not found + DB 3 ; write attempt to write-protect disk + PUBLIC LSTERR +LSTERR DB 0 ; all other errors + +; +; returned error code corresponding to above errors +; + +Public ERROUT +ERROUT LABEL BYTE + DB 2 ; no response + DB 6 ; seek failure + DB 4 ; bad CRC + DB 4 ; DMA overrun + DB 15 ; invalid media change + DB 8 ; sector not found + DB 0 ; write attempt on write-protect disk + DB 12 ; general error + + PUBLIC NUMERR +NUMERR = ERROUT-ERRIN + + +;------------------------------------------------------------- +; +; DiskSector is a 512 byte sector into which the boot sector +; is read. It is also used as read sector for DMA check for +; hard disk. + + +Public DiskSector +DiskSector db 11 dup(?) ; take care of 3 jump bytes plus OEM name. + PUBLIC BPB_IN_SECTOR +BPB_In_Sector dw ? + PUBLIC SECPERCLUSINSECTOR +SECPERCLUSINSECTOR DB ? + dw ? + db ? + dw ? + dw ? + PUBLIC MEDIABYTE +mediabyte db ? + dw ? + dw ? + dw ? + dw ? + db ? + db 512-($-DiskSector) dup (?) + +;--------------------------------------------------------------------- +; +; The "BDS"'s contain information for each drive in the system. +; There is one BDS for each logical drvie in the system. The BDS's +; are all linked together in a chain. The BDS contain various values +; important to the disk drive. Various values are updated whenever actions +; are performed. For example if a drive is read from the last time +; accessed fields are updated to the current time. +; Initial values: +; * Sectors/Alloc. unit in BPB initially set to -1 to signify that +; the BPB has not been filled. +; * Link is set to -1 to signify end of list. +; * number of cylinders in MaxParms initialized to -1 to indicate +; that the parameters have not been set. +; +; Start_BDS contains a pointer to the first BDS. It is through this +; pointer that routines find particular BDS (see SetDrive to see how +; this is done). +; + + EVENB +BDS1 LABEL WORD + DD BDS2 ;LINK TO NEXT STRUCTURE + DB 0 ;ROM DISK INT Drive Number + DB 0 ;Logical Drive Letter + PUBLIC FDRIVE1 +FDRIVE1 DW 512 ;Physical sector size in bytes + DB -1 ;Sectors/allocation unit + DW 1 ;Reserved sectors for DOS + DB 2 ;No. allocation tables + DW 64 ;Number directory entries + DW 9*40 ;Number sectors (at 512 bytes ea.) + DB 00000000B ;Media descriptor, initially 00H. + DW 2 ;Number of FAT sectors + DW 9 ;Sector limit + DW 1 ;Head limit + DW 0 ;Hidden sector count + DB 0 ; TRUE => Large fats +OPCNT1 DW 0 ;Open Ref. Count +VOLID1 DB "NO NAME ",0 ;Volume ID for this disk + DB 3 ;Form Factor +FLAGS1 DW 0020H ;Various Flags +; DB 9 dup (0) ;Reserved for future use + dw 40 ; number of cylinders +RecBPB1 DW 512 ;Physical sector size in bytes + DB 1 ;Sectors/allocation unit + DW 1 ;Reserved sectors for DOS + DB 2 ;No. allocation tables + DW 0E0H ;NUMBER DIRECTORY ENTRIES + DW 9*40 ;Number sectors (at 512 bytes ea.) + DB 0F0h ;Media descriptor, initially 00H. + DW 2 ;Number of FAT sectors + DW 9 ;Sector limit + DW 2 ;HEAD LIMIT + DW 0 ;Hidden sector count + DB 12 DUP (?) +TRACK1 DB -1 ;Last track accessed on this drive +TIM_LO1 DW -1 ;Keep these two contiguous (?) +TIM_HI1 DW -1 + + EVENB +BDS2 LABEL WORD + DD BDS3 ;LINK TO NEXT STRUCTURE + DB 0 ;INT 13 DRIVE NUMBER + DB 0 ;Logical Drive Letter + PUBLIC FDRIVE2 +FDRIVE2 DW 512 ;Physical sector size in bytes + DB -1 ;Sectors/allocation unit + DW 1 ;Reserved sectors for DOS + DB 2 ;No. allocation tables + DW 64 ;Number directory entries + DW 9*40 ;Number sectors (at 512 bytes ea.) + DB 00000000B ;Media descriptor, initially 00H. + DW 2 ;Number of FAT sectors + DW 9 ;Sector limit + DW 1 ;Head limit + DW 0 ;Hidden sector count + DB 0 ; TRUE => Large fats +OPCNT2 DW 0 ;Open Ref. Count +VOLID2 DB "NO NAME ",0 ;Volume ID for this disk + DB 3 ;Form Factor +FLAGS2 DW 0020H ;Various Flags +; DB 9 dup (0) ;Reserved for future use + dw 40 ; number of cylinders +RecBPB2 DW 512 ;Physical sector size in bytes + DB 1 ;Sectors/allocation unit + DW 1 ;Reserved sectors for DOS + DB 2 ;No. allocation tables + DW 0E0H ;NUMBER DIRECTORY ENTRIES + DW 9*40 ;Number sectors (at 512 bytes ea.) + DB 0F0h ;Media descriptor, initially 00H. + DW 2 ;Number of FAT sectors + DW 9 ;Sector limit + DW 2 ;HEAD LIMIT + DW 0 ;Hidden sector count + DB 12 DUP (?) +TRACK2 DB -1 ;Last track accessed on this drive +TIM_LO2 DW -1 ;Keep these two contiguous (?) +TIM_HI2 DW -1 + + EVENB +BDS3 LABEL WORD + DD BDS4 ;LINK TO NEXT STRUCTURE + DB 0 ;INT 13 DRIVE NUMBER + DB 0 ;Logical Drive Letter + PUBLIC FDRIVE3 +FDRIVE3 DW 512 ;Physical sector size in bytes + DB -1 ;Sectors/allocation unit + DW 1 ;Reserved sectors for DOS + DB 2 ;No. allocation tables + DW 64 ;Number directory entries + DW 9*40 ;Number sectors (at 512 bytes ea.) + DB 00000000B ;Media descriptor, initially 00H. + DW 2 ;Number of FAT sectors + DW 9 ;Sector limit + DW 1 ;Head limit + DW 0 ;Hidden sector count + DB 0 ; TRUE => Large fats +OPCNT3 DW 0 ;Open Ref. Count +VOLID3 DB "NO NAME ",0 ;Volume ID for this disk + DB 3 ;Form Factor +FLAGS3 DW 0020H ;Various Flags +; DB 9 dup (0) ;Reserved for future use + dw 40 ; number of cylinders +RecBPB3 DW 512 ;Physical sector size in bytes + DB 1 ;Sectors/allocation unit + DW 1 ;Reserved sectors for DOS + DB 2 ;No. allocation tables + DW 0E0H ;NUMBER DIRECTORY ENTRIES + DW 9*40 ;Number sectors (at 512 bytes ea.) + DB 0F0h ;Media descriptor, initially 00H. + DW 2 ;Number of FAT sectors + DW 9 ;Sector limit + DW 2 ;HEAD LIMIT + DW 0 ;Hidden sector count + DB 12 DUP (?) +TRACK3 DB -1 ;Last track accessed on this drive +TIM_LO3 DW -1 ;Keep these two contiguous (?) +TIM_HI3 DW -1 + + EVENB +BDS4 LABEL WORD + DW -1 ;Link to next structure + DW Code + DB 0 ;INT 13 DRIVE NUMBER + DB 0 ;Logical Drive Letter + PUBLIC FDRIVE4 +FDRIVE4 DW 512 ;Physical sector size in bytes + DB -1 ;Sectors/allocation unit + DW 1 ;Reserved sectors for DOS + DB 2 ;No. allocation tables + DW 64 ;Number directory entries + DW 9*40 ;Number sectors (at 512 bytes ea.) + DB 00000000B ;Media descriptor, initially 00H. + DW 2 ;Number of FAT sectors + DW 9 ;Sector limit + DW 1 ;Head limit + DW 0 ;Hidden sector count + DB 0 ; TRUE => Large fats +OPCNT4 DW 0 ;Open Ref. Count +VOLID4 DB "NO NAME ",0 ;Volume ID for this disk + DB 3 ;Form Factor +FLAGS4 DW 0020H ;Various Flags +; DB 9 dup (0) ;Reserved for future use + dw 40 ; number of cylinders +;;Rev 3.30 Modification +RECBPB4 DW 512 ;BYTES PER SECTOR + DB 1 ;SECTORS/ALLOCATION UNIT + DW 1 ;RESERVED SECTORS FOR DOS + DB 2 ;NO. ALLOCATION TABLES + DW 0E0H ;NUMBER DIRECTORY ENTRIES + DW 9*40 ;NUMBER SECTORS (AT 512 BYTES EA.) + DB 0F0H ;MEDIA DESCRIPTOR, INITIALLY F0H. + DW 2 ;NUMBER OF FAT SECTORS + DW 9 ;SECTOR LIMIT + DW 2 ;HEAD LIMIT + DW 0 ;HIDDEN SECTOR COUNT + DB 12 DUP (?) +;;End of Modification +TRACK4 DB -1 ;Last track accessed on this drive +TIM_LO4 DW -1 ;Keep these two contiguous (?) +TIM_HI4 DW -1 + + +bpbType struc +spf db ? +spt db ? +cdire db ? +csec dw ? +spa db ? +chead db ? +bpbType ends + PUBLIC SM92 +sm92 bpbType <3,9,70H,2*9*80,2,2> + + +; +; ALTAH is a single character buffer used to handle special keys. +; + + PUBLIC ALTAH +ALTAH DB 0 ;Special key handling + + +; +; The following variable can be modified via IOCTL sub-function 16. In this +; way, the wait can be set to suit the speed of the particular printer being +; used. One for each printer device. +; + + PUBLIC PRINTDEV +PRINTDEV DB 0 ; Index into following array + + EVENB + PUBLIC WAIT_COUNT +WAIT_COUNT DW 4 dup (50h) ; Array of Retry counts for printer + + +; +; DAYCNT is the number of days since 1-1-80. +; Each time the clock is read it is necessary to check if another day has +; passed. The ROM only returns the day rollover once so if it is missed +; the time will be off by a day. +; + + EVENB +Public DAYCNT +DAYCNT DW 0 + + +; +; The following variables and two routines (MSGOUT and MSGNUM) are used +; with the debug routines to print numbers and messages on the screen. +; +; The variable fTestBits controls the level of debugging in the system. +; See the comments and "equ's" in msmacro.inc for an explination of +; how to control the level of debugging. In a nutshell, setting +; fTestBits to fTestALL prints all the debugging messages. Setting +; it to fTestDisk prints all disk related messages, etc. +; + +if test +Public NumBuf +NumBuf DB 5 dup (?) +Public Digits +Digits DB "0123456789ABCDEF" +Public fTestBits +FTESTBITS DW fTestDISK +endif + + + PATHEND 001,BIO diff --git a/SRC/BIOS/MSDISK.ASM b/SRC/BIOS/MSDISK.ASM new file mode 100644 index 0000000..a3d21c8 --- /dev/null +++ b/SRC/BIOS/MSDISK.ASM @@ -0,0 +1,2408 @@ + TITLE MSDISK - DOS 3.3 +;------------------------------------------------------------------------ +; : +; DISK INTERFACE ROUTINES : +; : +; : +; This file contains the Disk Device Driver. : +; : +; The routines in this files are: : +; : +; routine function : +; ------- -------- : +; : +; MEDIA$CHK Determine if media in drive has changed : +; : +; GET$BPB Build a valid BPB for drive : +; : +; DSK$REM Determine if disk has removable media : +; : +; DSK$WRTV Disk write with verify : +; : +; DSK$WRT Disk write : +; : +; DSK$READ Read disk : +; : +; : +; These routines are not called directly. Call are made via : +; the strategy and interrupt entry point (see Device Header). : +; : +; Data structures: : +; There are two main types of data structures associated with : +; the disk drives. The first is the BDS. BDS is the Bios Data : +; structure. There is one BDS for each logical drive in the system. : +; All the BDS's are linked together in a list with the pointer to the : +; first BDS being found in Start_BDS. The BDS hold various values : +; important to the disk drive. For example there is a field for last : +; time accesses. As actions take place in the system the BDS are : +; update to reflect the actions. For example if there is a read to : +; a disk the last access field for the BDS for that drive is updated : +; to the current time. : +; The second data structure associated with disk drives is the : +; BPB. A BPB is a Bios Parameter Block. The BPB contains information : +; about the media inside a disk drive. Some on the fields in the BPB : +; are Sectors per track, number of FATs, and number of tracks. This : +; information is used to tell where sectors are on the disk. For : +; example, if we need to read logical sector 52: : +; : +; Diskette Track Sector Side : +; single density : +; eight sectors per track 6 5 0 : +; : +; double density : +; nine sectors per track 2 7 1 : +; : +; The BPB for the media in the drive is stored in the BDS for the : +; drive. If the user changes the floppy in the drive a call is : +; made to GET$BPB to build a new BPB in the BDS. See this routine : +; for the algorithm. : +; : +; : +;------------------------------------------------------------------------ +;;Rev 3.30 Modification +;for testing, set test to 1. So as MSBIO1.ASM. + test=0 + EXTRN NUMERR:ABS ;MSDATA + + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + INCLUDE MSEQU.INC + INCLUDE PUSHPOP.INC + INCLUDE MSMACRO.INC + INCLUDE DEVSYM.INC + INCLUDE DSKPRM.INC + + EXTRN INT2F_DISK:FAR ;MSBIO2 + EXTRN MEDIACHECK:NEAR ;96TPI + EXTRN HASCHANGE:NEAR ;96TPI + EXTRN MEDIA_SET_VID:NEAR ;96TPI + EXTRN HIDENSITY:NEAR ;96TPI + EXTRN CHECKLATCHIO:NEAR ;96TPI + EXTRN CHECKIO:NEAR ;96TPI + EXTRN SET_CHANGED_DL:NEAR ;96TPI + EXTRN SET_VOLUME_ID:NEAR ;MSVOLID + EXTRN SWPDSK:NEAR ;MSBIO2 + EXTRN CMDERR:NEAR ;MSBIO1 + EXTRN STRATEGY:NEAR ;MSBIO1 + EXTRN ERR$CNT:NEAR ;MSBIO1 + EXTRN DSK$IN:NEAR ;MSBIO1 + EXTRN EXIT:NEAR ;MSBIO1 + EXTRN BUS$EXIT:NEAR ;MSBIO1 + EXTRN ERR$EXIT:NEAR ;MSBIO1 + +;DATA + EXTRN OLD13:DWORD ;MSBIO2 + EXTRN PTRSAV:DWORD ;MSBIO1 + EXTRN COM1DEV:WORD ;MSAUX + EXTRN DAYCNT:WORD ;MSCLOCK + EXTRN TIM_DRV:BYTE ;MSDATA + EXTRN ACCESSCOUNT:BYTE ;MSDATA + EXTRN SM92:BYTE ;MSDATA + EXTRN DISKSECTOR:BYTE ;MSDATA + EXTRN MEDIABYTE:BYTE ;MSDATA + EXTRN SECPERCLUSINSECTOR:BYTE ;MSDATA + EXTRN BPB_IN_SECTOR:WORD ;MSDATA + EXTRN DISKSECTOR:BYTE ;MSDATA + EXTRN STEP_DRV:BYTE ;MSDATA + EXTRN START_BDS:WORD ;MSDATA + EXTRN PHYS_DRV:BYTE ;MSDATA + EXTRN WRTVERIFY:WORD ;MSDATA + EXTRN FSETOWNER:BYTE ;MSDATA + EXTRN SINGLE:BYTE ;MSDATA + EXTRN RFLAG:BYTE ;MSDATA + EXTRN MEDBYT:BYTE ;MSDATA + EXTRN SPSAV:WORD ;MSDATA + EXTRN SECCNT:WORD ;MSDATA + EXTRN DPT:DWORD ;MSDATA + EXTRN CURSEC:BYTE,CURHD:BYTE ;MSDATA + EXTRN CURTRK:WORD ;MSDATA + EXTRN EOT:BYTE ;MSDATA + EXTRN MOTORSTARTUP:BYTE,SETTLECURRENT:BYTE,SETTLESLOW:BYTE ;MSDATA + EXTRN CURHD:BYTE ;MSDATA + EXTRN LSTERR:BYTE ;MSDATA + EXTRN ERRIN:BYTE,ERROUT:BYTE ;MSDATA + EXTRN PREVOPER:WORD ;MSDATA + EXTRN ORIG13:DWORD ;MSDATA + EXTRN FLAGBITS:WORD ;MSDATA + EXTRN NUMBER_OF_SEC:BYTE ;MSDATA + EXTRN FHAVE96:BYTE ;MSDATA + EXTRN NEW_ROM:BYTE ;MSDATA + EXTRN FORMT_EOT:BYTE,HDNUM:BYTE,TRKNUM:WORD,GAP_PATCH:BYTE ;MSDATA + EXTRN NEXT2F_13:WORD ;MSDATA + extrn Save_head_sttl:byte ;MSdata + extrn Secrete_Code:word ;MSdata +;;Rev 3.30 Modification + + +; +; Maximum number of retries in case of error +; + +MAXERR = 5 +LSTDRV = 504H + + +; +; Some floppy drives do not have changeline support. The result is a +; large amount of inefficiency in the code. A media-check always returns +; "I don`t know". This cause DOS to reread the FAT on every access and +; always discard any cached data. +; We get around this inefficiency by implementing a "Logical Door Latch". +; The following three items are used to do this. The logical door latch is +; based on the premise that it is not physically possible to change floppy +; disks in a drive in under two seconds (most people take about 10). The +; logical door latch is implemented by saving the time of the last successful +; disk operation (in the value TIM_DRV). When a new request is made the +; current time is compared to the saved time. If less than two seconds have +; passed then the value "No Change" is returned. If more than two seconds +; have passed the value "Don't Know" is returned. +; There is one complecation to this algorithm. Some programs change the +; value of the timer. In this unfortunate case we have an invalid timer. +; This possiblity is detected by counting the number of disk operations +; which occur without any time passing. If this count exceeds the value of +; "AccessMax" we assume the counter is invalid and always return "Don't +; Know". The variable "AccessCount" is used to keep track of the number +; of disk operation which occur without the time changing. +; + +AccessMax = 5 + + +; +; Some of the older versions of the IBM rom-bios always assumed a seek would +; have to be made to read the diskette. Consequently a large head settle +; time was always used in the I/O operations. To get around this problem +; we need to continually adjust the head settle time. The following +; algorithm is used: +; +; Get the current head settle value. +; If it is 1, then +; set slow = 15 +; else +; set slow = value +; ... +; if we are seeking and writing then +; use slow +; else +; use fast +; ... +; restore current head settle value +; +; +; flags for size of FAT +; +fTOOBIG EQU 80h +fBIG EQU 40h + +error_unknown_media equ 7 ; for use in BUILD BPB call + +BPB_TYPE STRUC +SECSIZE DW ? +SECALL DB ? +RESNUM DW ? +FATNUM DB ? +DIRNUM DW ? +SECNUM DW ? +FATID DB ? +FATSIZE DW ? +SLIM DW ? +HLIM DW ? +HIDDEN DW ? +BPB_TYPE ENDS +;------------------------------------------------------------------------ +; : +; The next 100 or so lines of code do the Media Check. Media Check : +; determines if the diskette (media) in the drive has been changed. : +; : +; SI is used to hold media check code: : +; -1 media changed : +; 0 Don't know : +; 1 media has not been changed : +; : +; The algorithm used is a follows: : +; if (hard disk) : +; if (changed by format) : +; return (not changed) : +; if not (changed by format) : +; return (changed) : +; else we have a floppy : +; if floppy has change line support go ask the floppy : +; if floppy does not have change line do the following : +; read the time : +; if more than two second have passed return don't know : +; if no time has passed then might be unreliable : +; counter (some program fool with the counter when : +; they should not). See note below for procedure with : +; unreliable counter : +; if sometime has passed but not two second return : +; media has not changed. This is based on the : +; assumption that it is not physically possilbe to : +; change a disk in less the two seconds (most people : +; take about 10 seconds). : +; : +;------------------------------------------------------------------------ + + public media$chk +MEDIA$CHK PROC NEAR + Message ftestdisk,<"Disk Media Check "> + MNUM ftestdisk,AX + Message ftestdisk, + Call SetDrive ; point DS:DI to BDS for specified drive + + cmp cs:Secrete_Code, 'jk' ; Secrete code for + jne media$done ; DOS 3.3 MSBIO. +; +; For non-removable disks only return changed if changed by format, +; otherwise return 'not changed'. +; + + mov si,1 ; assume no change + test word ptr [di].flags,fChanged_By_Format + jz WeAreNotFakingIt + ; reset flag + and word ptr [di].flags,NOT fChanged_By_Format + +; +; If media has been changed by format, must use the ROM. +; Cannot rely on the 2 second time check. +; + mov cs:[TIM_DRV],-1 ; Ensure that we ask the ROM if media + ; has changed + test word ptr [di].flags,fNon_Removable + jz WeHaveAFloppy + mov SI,-1 ; Indicate media changed + jmp short Media$Done +; +; return 'not changed' if disk is a hard file. +; + +WeAreNotFakingIt: + test word ptr [di].flags,fNon_Removable + jnz Media$Done + +; +; If this code is reached disk is a diskette drive +; + +WeHaveAFloppy: + + xor si,si ; Presume "I don't know" + +; +; If drive is a floppy with changeline support the rom is called to +; determine if the media has changed. It is not necessary to do the 2 +; second check on these drives. +; +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in MSINIT ;| + Public Media_Patch ;| +Media_Patch: ;| + CALL MediaCheck ;| + jc Err$Exitj ;| + call HasChange ;| + jnz Media$Done ;| +;----------------------------------------| +; +; If this code is reached the drive is a floppy with no changeline support +; + MOV SI,1 ; PRESUME NO CHANGE + mov al,cs:[TIM_DRV] ; last drive accessed + ;is drive of last access the same? + CMP AL,byte ptr [di].DriveNum + JNZ Media$Unk ; no, then return don't know +; +; CHECK TO SEE IF THIS DRIVE HAS BEEN ACCESSED IN THE LAST 2 SECONDS. +; + call Check_Time_of_Access + jmp short Media$Done + + +Media$Unk: + DEC SI ; RETURN "I DON'T KNOW" + +; +; SI now contains the correct value for media change. Clean up the left overs +; +Media$Done: + les bx,cs:[ptrsav] ; get original packet + mov WORD PTR es:[BX].Trans,SI + or SI,SI + js Init_Patch + jmp EXIT + +MEDIA$CHK ENDP + +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| + Public Init_Patch ;| +INIT_PATCH PROC NEAR ;| + CALL Media_Set_VID ;| +;----------------------------------------| + mov cs:[Tim_Drv],-1 ; make sure we ask ROM for media check +VOLIDOK: + jmp EXIT +INIT_PATCH ENDP + + + +ERR$EXITJ PROC NEAR + + MESSAGE FTESTCOM,<"ERR$EXITJ: "> + MNUM FTESTCOM,AX + MESSAGE FTESTCOM,<" == "> + CALL MAPERROR + MNUM FTESTCOM,AX + MESSAGE FTESTCOM, + JMP ERR$EXIT +ERR$EXITJ ENDP + +; +; PERFORM A CHECK ON THE TIME PASSED SINCE THE LAST ACCESS FOR THIS +; PHYSICAL DRIVE. +; WE ARE ACCESSING THE SAME DRIVE. IF THE TIME OF LAST SUCCESSFUL ACCESS +; WAS LESS THAN 2 SECONDS AGO, THEN WE MAY PRESUME THAT THE DISK WAS NOT +; CHANGED +; RETURNS IN SI: +; 0 - IF TIME OF LAST ACCESS WAS >= 2 SECONDS +; 1 - IF TIME WAS < 2 SECONDS (I.E NO MEDIA CHANGE ASSUMED) +; REGISTERS AFFECTED AX,CX,DX, FLAGS. +; +CHECK_TIME_OF_ACCESS PROC NEAR + PUBLIC CHECK_TIME_OF_ACCESS + mov si,1 ; Presume no change +;;Rev 3.30 Modification + xor AH, AH ; set command to read time + int 1Ah ; call rom-bios clock routine + +; +; Once time is read, must make sure the date wrap is not lost. The ROM will +; return the value only once, it must check for day wrap on each call. +; + SHR AL,1 + ADC CS:[DAYCNT],0 ; ADD IT TO OUR SAVED DAY COUNT +; +; Compute elapsed time +; + MOV AX,WORD PTR DS:[DI].TIM_LO ; GET STORED TIME + SUB DX,AX + MOV AX,WORD PTR DS:[DI].TIM_HI + SBB CX,AX +;;End of Modification +; +; CX:DX is the elapsed time +; + JNZ TimeCheck_Unk ; CX <> 0 => > 1 hour + OR DX,DX ; did some time pass? + JNZ TimePassed ; yes, examine max value +; +; No noticeable time has passed. There are two possiblities. First there +; could be two driver calls with in one clock tick (55 milliseconds). The +; second possiblity is the program has reprogramed the counter -- this is +; the unreliable counter case. To distinguish between the case a count is +; kept of the number of calls that happen without a clock tick (the variable +; is AccessCount). If this count exceeds a set limit (MaxAccess) it is +; assumed the counter is unreliable and the value don't know is returned. +; If AccessCount is less than MaxAccess we assume the time is valid and +; therefor the media has not changed. +; + inc byte ptr cs:AccessCount + ; Exceeded threshold for count? + cmp byte ptr cs:AccessCount,AccessMax + jb TimeCheck_Ret ; no, return media unchanged + dec byte ptr cs:AccessCount ; don't let the count wrap + jmp short TimeCheck_Unk ; "I don't know" if media changed + + +; +; If this code is reached some time has passed. Need to determine if +; 2 seconds have passed. Note: 18.2 ticks per second. +; +TimePassed: + CMP DX,18 * 2 ; IF ( Time_passed <= 2secs ) + JBE TimeCheck_Ret ; presume no change + + +; Everything indicates that we do not know what has happened. +; +TimeCheck_Unk: + DEC SI ; Presume I don't know +TimeCheck_Ret: + RET + +CHECK_TIME_OF_ACCESS ENDP + +ERR$EXITJ2: JMP ERR$EXITJ + + +;------------------------------------------------------------------------ +; : +; Get Bios Parameter Block : +; : +; GET$BPB is called to build a valid BPB for the media in the disk : +; drive. A BPB (Bios Parameter Block) contains information about : +; the media which is currently in the drive. The values stored is : +; information like number of fat sectors, size of drive, 8 or 9 sectors,: +; etc. : +; : +; This routine is called by the device drive code. : +; : +; On entry AL contains the logical drive number which needs : +; the BPB built. : +; ES:[di] points to a buffer; the first byte of the buffer is a : +; media decriptor byte. : +; : +;------------------------------------------------------------------------ +; +; Build a valid BPB for the disk in the drive. +; + + public GET$BPB +GET$BPB PROC NEAR + Message fTestDisk,<"Disk Build BPB "> ; print debug messages + MNUM fTestDisk,AX + Message fTestDisk, + mov AH,byte ptr ES:[DI] ; get FAT IB byte read by DOS + call SetDrive ; get the correct BDS for the drv +;;Rev 3.30 Modification + TEST WORD PTR [DI].FLAGS,FNON_REMOVABLE + JNZ ALREADY_GOTBPB ; NO NEED TO BUILD FOR FIXED DISKS +;;End of Modification + call GETBP ; build a BPB if necessary. + jc Err$exitj2 ; if error exit +GET$BPB ENDP +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| + Public SET_PATCH ;| +SET_PATCH PROC NEAR ;| + CALL set_volume_id ;| +;----------------------------------------| + ; print debug messages + message ftestdisk,<"Set Volume ID"> + mnum ftestdisk,di + message ftestdisk,<" "> + mnum ftestdisk,ds + message ftestdisk, +ALREADY_GOTBPB: + add di,BytePerSec ; return the BPB that is in the current BDS + + PUBLIC SetPTRSAV +SetPTRSAV: ; return point for DSK$INIT + les BX,cs:[PTRSAV] + mov ES:[BX].MEDIA,AH + mov ES:[BX].COUNT,DI + mov ES:[BX].COUNT+2,DS + jmp EXIT +SET_PATCH ENDP + + + + +; +; +; GETBP fills the BDS with the BPB for the media currently in the drive. +; The following steps are followed: +; If the Return_Fake_BPB flag is set then the GETBP just returns. +; If the BDS is for a hard disk (non-removable) then GETBP returns since +; the BPB cannot change on a hard disk drive. +; For all other cases GETBP reads the boot sector and looks for a BPB +; in the boot sector. (All DOS 2.X and about disks should have a valid +; BPB in the boot sector.) +; If no valid BPB is found (DOS 1.X disk) then GETBP reads the FAT +; sector and gets the FAT ID byte. With this byte a valid BPB is build. +; +; Inputs: +; DS:DI points to correct BDS +; +; Outputs: +; Fills in BPB in current BDS if valid BPB or FAT ID on disk. +; Carry set, and AL=7 if invalid disk. +; Carry set and error code in AL if other error. +; + + Public GETBP +GETBP PROC NEAR + ; if non-removable or returning + ; fake BPB then return BPB as is. + TEST WORD PTR [DI].FLAGS,RETURN_FAKE_BPB OR FNON_REMOVABLE + jz GETBP1 + JMP GETRET_EXIT + + +GETBP1: + message ftestdisk,<"Building BPB from scratch",CR,LF> + SaveReg +; +; Attempt to read in boot sector and determine BPB. +; We assume that the 2.x and greater DOS disks all have a valid boot sector. +; +Rdboot: + call ReadBootSec + jnc NoRdErr + jmp GetBP_Err_Ret ; Carry set if there was error. +NoRdErr: + cmp bx,0 ; BX is 0 if boot sector is valid. + jnz DoFatBPB ; if not go read FAT + + call MovBPB ; Move BPB into registers. + jmp Has1 + +; +; At this point the drive contains a 1.X diskette. We read the FAT byte +; and fill in the BPB from there. +; + +DoFatBPB: + call ReadFat ; puts media descriptor byte in AH + jc GetBP_Err_Ret ; if carry set, there was error, get out + +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| +Public GETBP1_PATCH ;| +GETBP1_PATCH: ;| + call hidensity ;| +;----------------------------------------| +; Test for a valid 3.5" medium + cmp [di].FormFactor, ffsmall + jnz Is_Floppy + cmp ah,0F9H ; is it a valid fat ID byte for 3.5" ? + jnz Got_Unknown_Medium + mov bx,offset sm92 ; pointer to correct BPB + push cs + pop es +ASSUME ES:CODE + mov al,[bx.spf] + mov cx,[bx.csec] + mov dx,word ptr [bx.spa] + mov bx,word ptr [bx.spt] + jmp short HAS1_res ; Need to load reserved sectors +; +; must be a 5.25" floppy if we come here +; +Is_Floppy: + mov CL,AH ; save media + and CL,0F8H ; normalize + cmp CL,0F8H ; cmopare with good media byte + jnz Got_Unknown_Medium + +GOODID: mov AL,1 ; set number of FAT sectors + mov BX,64*256+8 ; set dir entries and sector max + mov CX,40*8 ; set size of drive + mov DX,01*256+1 ; set head limit and sec/all unit + test AH,00000010B ; test for 8 or 9 sectors + jnz HAS8 ; NZ = has 8 sectors + inc AL ; inc number of FAT sectors + inc BL ; inc sector max + add CX,40 ; increase size +HAS8: test AH,00000001B ; test for 1 or 2 heads + jz HAS1_res ; Z = 1 head + add CX,CX ; double size of disk + mov BH,112 ; increase number of directory entries + inc DH ; inc sec/all unit + inc DL ; inc head limit + +PUBLIC HAS1_res +HAS1_res: + mov si,word ptr ds:[di].RESSEC +PUBLIC HAS1 ; save values in BDS +HAS1: mov byte ptr ds:[DI].SecPerClus,DH + mov byte ptr ds:[DI].cDir,BH + mov word ptr ds:[DI].Drvlim,CX + mov byte ptr ds:[DI].Mediad,AH + mov byte ptr ds:[DI].csecFat,AL + mov byte ptr ds:[DI].SecLim,BL + mov byte ptr ds:[DI].HdLim,DL + mov word ptr ds:[DI].RESSEC,SI +GETRET: pop BX + RestoreReg +ASSUME ES:NOTHING +GETRET_Exit: + RET + +GetBP_Err_Ret: + CALL MapError + JMP SHORT GETRET + +; +; We have a 3.5" diskette for which we cannot build a BPB. We do not assume any +; type of BPB for this medium. +; +Got_Unknown_Medium: + mov al,error_unknown_media + stc + jmp short GETRET + +GETBP ENDP + +bpbType struc +spf db ? +spt db ? +cdire db ? +csec dw ? +spa db ? +chead db ? +bpbType ends + +; +; end of GET$BPB code +;------------------------------------------------- + +; +; Read in the boot sector. Set carry if error in reading sector. +; BX is set to 1 if the boot sector is invalid, otherwise it is 0. +; +READBOOTSEC PROC NEAR + mov CX, 0001h ; set track and sector number + xor DH, DH ; set head number for read_sector + call read_sector + jc Err_Ret ; error - get out + xor bx,bx ; assume valid boot sector. + + ; at this point the boot sector has been + ; read in from the disk. We now need to + ; determine if the boot sector contains + ; a valid BPB. Currently there are only + ; a few simple checks. Expanding the + ; number or types of checks would not be + ; a bad idea. +;******************************************************************************* +; Put a sanity check for the boot sector in here to detect boot sectors that +; do not have valid BPBs. +; We examine the first two bytes - they must contain a long jump or a short +; jump followed by a NOP. +; If this test is passed, we further check by examining the signature at +; the end of the boot sector for the word AA55H. +; If the signature is not present, we examine the media descriptor byte to +; see if it is valid. +;****************************************************************************** + cmp byte ptr cs:[DiskSector],069H ; Is it a direct jump? + JE Check_bpb_MediaByte ; DON'T NEED TO FIND A NOP + cmp byte ptr cs:[DiskSector],0E9H ; DOS 2.0 jump? + JE Check_bpb_MediaByte ; NO NEED FOR NOP + cmp byte ptr cs:[DiskSector],0EBH ; How about a short jump. + JNE INVALIDBOOTSEC + cmp byte ptr cs:[DiskSector]+2,090H ; Is next one a NOP? + JNE INVALIDBOOTSEC + + +; Don't have to perform the following signature check since +; we need to check the media byte even with the good signatured diskette. +;CHECK_SIGNATURE: +; CMP WORD PTR CS:[DISKSECTOR+1FEH],0AA55H ; SEE IF NON-IBM +; ; DISK OR 1.X MEDIA. +; JZ CHECKSINGLESIDED ; GO SEE IF SINGLE SIDED MEDIUM. +; ; MAY NEED SOME SPECIAL HANDLING +; +; CHECK FOR NON-IBM DISKS WHICH DO NOT HAVE THE SIGNATURE AA55 AT THE +; END OF THE BOOT SECTOR, BUT STILL HAVE A VALID BOOT SECTOR. THIS IS DONE +; BY EXAMINING THE MEDIA DESCRIPTOR IN THE BOOT SECTOR. +; + +;;Rev 3.30 Modification +Check_bpb_MediaByte: + + MOV AL,BYTE PTR CS:MEDIABYTE + AND AL,0F0H + CMP AL,0F0H ; ALLOW FOR STRANGE MEDIA + JNZ INVALIDBOOTSEC +; +; THERE WERE SOME (APPARENTLY A BUNCH) DISKETTES THAT HAD BEEN FORMATTED +; UNDER DOS 3.1 AND EARLIER VERSIONS WHICH HAVE INVALID BPBS IN THEIR BOOT +; SECTORS. THESE ARE SPECIFICALLY DISKETTES THAT WERE FORMATTED IN DRIVES +; WITH ONE HEAD, OR WHOSE SIDE 0 WAS BAD. THESE CONTAIN BPBS IN THE BOOT +; SECT THAT HAVE THE SEC/CLUS FIELD SET TO 2 INSTEAD OF 1, AS IS STANDARD +; IN DOS. TO SUPPORT THEM, WE HAVE TO INTRODUCE A "HACK" THAT WILL +; HELP OUR BUILD BPB ROUTINE TO RECOGNISE THESE SPECIFIC CASES, AND TO +; SET UP OUT COPY OF THE BPB ACCORDINGLY. +; WE DO THIS BY CHECKING TO SEE IF THE BOOT SECTOR IS OFF A DISKETTE THAT +; IS SINGLE-SIDED AND IS A PRE-DOS 3.20 DISKETTE. IF IT IS, WE SET THE +; SEC/CLUS FIELD TO 1. IF NOT, WE CARRY ON AS NORMAL. +CHECKSINGLESIDED: + MOV AL,BYTE PTR CS:MEDIABYTE + TEST AL,0001H ; IS LOW BIT SET? - INDICATES DOUBLE SIDED + JNZ GOODDSK + CMP WORD PTR CS:[DISKSECTOR+8],"." SHL 8 + "3" + JNZ MUSTBEEARLIER + CMP BYTE PTR CS:[DISKSECTOR+10],"2" + JAE GOODDSK + +; WE MUST HAVE A PRE-3.20 DISKETTE. SET THE SEC/CLUS FIELD TO 1 +MUSTBEEARLIER: + MOV BYTE PTR CS:[SECPERCLUSINSECTOR],1 + JMP SHORT GOODDSK + +INVALIDBOOTSEC: + INC BX ; SET THAT BOOT SECTOR INVALID +;;End of Modification + +GoodDsk: ; carry already reset + clc + ret + +Err_Ret: ; carry is already set on entry here + message ftestdisk,<"error in readboot",cr,lf> + ret + +READBOOTSEC ENDP + +; +; MovBPB moves the BPB read from the Boot sector into registers for use by +; GETBP routine at Has1 +; +MOVBPB PROC NEAR + SaveReg + push cs + pop ds + mov di,offset BPB_In_Sector + mov dh,Byte Ptr [di].secall ;sectors per unit + mov bh,Byte Ptr [di].dirnum ;number of directory entries + mov cx,Word Ptr [di].secnum ;size of drive + mov ah,Byte Ptr [di].fatid ;media descriptor + mov al,Byte Ptr [di].fatsize ;number of FAT sectors + mov bl,Byte Ptr [di].slim ;sectors per track + mov dl,Byte Ptr [di].hlim ;number of heads + mov si,word ptr [di].resnum ;reserved sectors + RestoreReg + ret +MOVBPB ENDP + + + +; +; Read in the FAT sector and get the Media Byte from it. +; Input : AL contains logical drive. +; Output: +; Carry set if an error occurs, AX contains error code. +; Otherwise, AH contains media byte on exit. AL is preserved. + +READFAT PROC NEAR + push ax ; preserve logical drive in AL + MOV DH,0 ; HEAD 0 + mov CX,0002 ; set track and sector number + call read_sector ; CS:BX points to fat sector + jc Bad_FAT_Ret ; error, get out + pop ax ; reset logical drive + mov ah,Byte Ptr CS:[BX] ; media byte + ret + +Bad_FAT_Ret: ; carry set on entry + message ftestdisk,<"error in FAT read",cr,lf> + pop cx ; clear stack + ret +READFAT ENDP + + + +; +; Read_sector reads a single sector into the tempory buffer 'DiskSector'. +; Up to three retries are done in case of error. +; +; Inputs: +; DS:DI points to BDS for drive +; CH - track number +; CL - sector number +; DH - head number +; +; Outputs: +; If carry is clear -- successful read +; CS:BX points to buffer holding sector +; AX, BX are not preserved, CX, DX, BP, and ES are preserved +; +; If carry is set -- error on read +; AX, BX, and DX are not preserved; CX, BP, and ES are preserved +; +; + +READ_SECTOR PROC NEAR + PUBLIC READ_SECTOR + push BP ; preserve BP register + mov BP,3 ; BP is retry count, set to 3 + push ES ; preserve ES also + mov DL, byte ptr [di].DriveNum + mov BX, offset DiskSector ; Get ES:BX to point to buffer + push CS ; get the segment right + pop ES ; now ES:BX is correct + +RD_RET: + ; set command to read (AH=2) and + mov AX, 0201h ; number of sectors to 1 (AL=1) + int 13h ; call rom-bios disk routines + + jnc OKRET2 ; if no carry then no error - done +Rd_rty: + call Again ; reset disk and decrement BP + jz Err_RD_RET + test word ptr ds:[di].flags,fNon_Removable + JNZ RD_RET +;;Rev 3.30 Modification ----------------------------------------- + push ds ; For retry, set head settle + push ax ; time to 0Fh. + lds si,cs:DPT + mov al, ds:[si].disk_head_sttl + mov cs:[save_head_sttl],al + mov byte ptr ds:[si].disk_head_sttl, NormSettle + pop ax + pop ds + ; SET CMD TO READ (AH=2) AND + MOV AX, 0201h ; NUM OF SECTORS TO 1 (AL=1) + INT 13h ; CALL ROM-BIOS DISK ROUTINES + push ds + push ax + lds si,cs:DPT + mov al, cs:[save_head_sttl] + mov byte ptr ds:[si].disk_head_sttl, al + pop ax + pop ds + jnc OKRET2 + jmp Rd_rty +ERR_RD_RET: + MOV DL,-1 ; MAKE SURE WE ASK ROM IF MEDIA CHANGED + STC ; RETURN ERROR +;;End of Modification ----------------------------------------- + + ; Update information pertaining to last drive + ; accessed, time of access, last track accessed + ; in that drive. +OKRET2: + ; set up for head settle logic in DISK + mov CS:[STEP_DRV],DL ; save last drive accessed + mov CS:[TIM_DRV],DL ; save the values + mov byte ptr [di].track,CH ; + pushf ; save the flags + call SET_TIM + popf ; restore flags + pop ES ; restore registers + pop BP + ret + +READ_SECTOR ENDP + + + +;------------------------------------------------------------------------ +; : +; Disk Removable Routine : +; : +; This routine determines if a particular logical drive has : +; removable media. : +; : +; Input : +; AL contains the logical drive number which the check is being : +; done. : +;------------------------------------------------------------------------ + +DSK$REM PROC NEAR ;ARR 2.41 + PUBLIC DSK$REM + Message fTestDisk,<"Disk Removable "> ; print debug messages + MNUM fTestDisk,AX + Message fTestDisk, + ; AL is logical unit number + call SetDrive ; get BDS for this drive + test word ptr [di].flags,fNon_Removable + jnz NON_REM + jmp EXIT + +NON_REM: ; if non removable set busy bit + jmp BUS$EXIT + +DSK$REM ENDP + + + +; +; SetDrive scans through the data structure of BDSs and returns a +; pointer to the BDS that belongs to the drive specified in AL. +; Carry is set if no BDS has a logical drive number which matches the +; value in AL. +; Input: +; AL contains the logical drive number +; Output: +; DS:DI points to correct BDS if Carry is clear. +; +; All register execpt DS and DI are preserved +; + + Public SetDrive +SETDRIVE PROC NEAR + message ftestdisk,<"SetDrive",cr,lf> ; print debug messages + push bx + push cs + pop ds + ; assume first BDS is in this segment + ASSUME DS:CODE + mov di,word ptr Start_BDS +Scan_Loop: +;;Rev 3.30 Modification ----------------------------------------- + CMP BYTE PTR CS:[PHYS_DRV],1 ; DOES AL HAVE PHYS DRV? + JB USE_LOGICAL_DRV + CMP BYTE PTR [DI].DRIVENUM,AL + JE SETDRV + JMP SHORT GET_NXT_BDS +USE_LOGICAL_DRV: + CMP BYTE PTR [DI].DRIVELET,AL + JE SETDRV +GET_NXT_BDS: + MOV BX,WORD PTR [DI].LINK+2 ; GO TO NEXT BDS + MOV DI,WORD PTR [DI].LINK + mov ds,bx + ASSUME DS:NOTHING +;;End of Modification ----------------------------------------- + + cmp di,-1 ; at end of list? + jnz Scan_Loop ; no, keep looking + stc ; yes, indicate error set carry +SetDrv: + pop bx ; restore bx + ret ; return + +SETDRIVE ENDP + + + +;------------------------------------------------------------------------ +; : +; DISK I/O ROUTINES : +; : +; On entry the register contain the following values: : +; : +; AH - Media Descriptor byte : +; AL - logical drive number : +; CX - count of sectors to be read or written : +; DX - start sector : +; DI - offset of destination buffer : +; : +;------------------------------------------------------------------------ + + +;------------------------------------------------------------------------ +; : +; Disk Write with Verify : +; : +; Input : +; See about header for register contents on entry. : +; : +;------------------------------------------------------------------------ + + +DSK$WRITV PROC NEAR + PUBLIC DSK$WRITV + Message fTestDisk,<"Disk Write with verify "> + MNUM fTestDisk,AX + Message fTestDisk,<" "> + MNUM fTestDisk,DX + Message fTestDisk,<" for "> + MNUM fTestDisk,CX + Message fTestDisk, + MOV CS:[WRTVERIFY],103H + JMP SHORT DSK$CL + +;------------------------------------------------------------------------ +; : +; Disk Write : +; : +; Input : +; See about header for register contents on entry. : +; : +;------------------------------------------------------------------------ + +DSK$WRIT: + PUBLIC DSK$WRIT + Message fTestDisk,<"Disk Write "> + MNUM fTestDisk,AX + Message fTestDisk,<" "> + MNUM fTestDisk,DX + Message fTestDisk,<" for "> + MNUM fTestDisk,CX + Message fTestDisk, + MOV CS:[WRTVERIFY],ROMWrite + +DSK$CL: + CALL DISKIO +DSK$IO: + JC DSKBad + JMP EXIT +DSKBad: + JMP ERR$CNT + +DSK$WRITV ENDP + + +;------------------------------------------------------------------------ +; : +; Disk Read : +; : +; Input : +; See about header for register contents on entry. : +; : +;------------------------------------------------------------------------ + +DSK$READ PROC NEAR + PUBLIC DSK$READ + Message fTestDisk,<"Disk Read "> + MNUM fTestDisk,AX + Message fTestDisk,<" "> + MNUM fTestDisk,DX + Message fTestDisk,<" for "> + MNUM fTestDisk,CX + Message fTestDisk, + CALL DISKRD + JMP DSK$IO +DSK$READ ENDP +; +; Miscellaneous odd jump routines. Moved out of mainline for speed. +; + + +; +; CheckSingle determines if the drive specified is a virtual drive (more +; than one logical drive associated with one physical drive). If this +; is the case we need to prompt the user to place the correct disk in +; the drive. +; +; Input: +; DS:DI pints to the BDS for the drive being checked. +; +; If there is a error the carry flag is set on return +; +; All registers are preserved. +; + +CHECKSINGLE PROC NEAR + PUBLIC CHECKSINGLE + push AX ; save affected registers + push BX + mov BX,word ptr ds:[di].flags + TEST BL,FNON_REMOVABLE OR FI_OWN_PHYSICAL ;Can't change disk + jnz SingleRet ; on hard drive so return + ; is there a drive sharing this + TEST BL,FI_AM_MULT ; physical drive? + jz SingleRet ; if not, then return + + ; At this point there is more than one + ; logical drive mapped to this physical drive. + ; But the drive being accessed is not the + ; owner of the physical drive. What needs to + ; be done is find the current owner BDS and + ; turn off the owner flag and then make current + ; BDS the owner of the drive. Then prompt the + ; user to change disks. + mov al,ds:[di].DriveNum ; get physical drive number + push ds ; preserve pointer to current BDS + push di + push cs + + pop ds ; Point to start of BDS linked list + ASSUME DS:CODE + + mov di,offset Start_BDS + +Scan_List: + mov bx,word ptr [di].link+2 ; go to next BDS + mov di,word ptr [di].link + mov ds,bx + ASSUME DS:NOTHING + + cmp di,-1 ; end of list? + jz single_err_ret ; if so there must be an error + ; same physical drive? + cmp byte ptr [di].DriveNum,al + jnz Scan_List ; no, keep looking + +Check_Own: ; yes, check to see if owner + mov bx,word ptr [di].flags + test bl,fI_Own_Physical + jz Scan_List ; not owner, keep looking + xor bl,fI_Own_Physical ; yes owner reset ownership flag + mov word ptr ds:[di].flags,bx + pop di ; Restore pointer to current BDS + pop ds + xor bx,bx + or bl,fI_Own_Physical ; establish current BDS as owner + or word ptr [di].flags,bx + + + ; + ; We examine the fSetOwner flag. If it is + ; set, then we are using the code in + ; CheckSingle to just set the owner of + ; a drive. We must not issue the prompt + ; in this case. + ; + + cmp byte ptr cs:[fSetOwner],1 + jz SingleRet + ; + ; To support "backward" compatibility with + ; IBM's "single drive status byte" we now + ; check to see if we are in a single drive + ; system and the Application has "cleverly" + ; diddled the SDSB (Single Drive Status Byte) + ; + + cmp cs:[single],2 ; single drive system? + jne short Ignore_SDSB ; no, jump down + + SaveReg ; yes... + mov al,ds:[di].DriveLet ; IF (Curr_drv == Req_drv) + mov ah,al + xor di,di + mov ds,di + xchg al,ds:byte ptr LSTDRV ; THEN swap(Curr_drv,Req_drv) + cmp ah,al ; ELSE + RestoreReg ; swap(Curr_drv,Req_drv) + je SingleRet ; Issue Swap_dsk_msg + +Ignore_SDSB: + call SWPDSK ; ask user for correct disk + +SingleRet: + pop BX ; restore registers + pop ax + ret ; return + +Single_Err_Ret: + stc ; set carry flage to indicate error + pop di ; restore current BDS + pop ds + jmp short SingleRet + + +; +; BadDrive is called when sector specified is greater than last +; sector on disk. +; or when BDS is not found for drive +; + +BadDrive: + mov AL,8 ; error code 'sector not found' + stc ; indicate error +IORET: ret ; return + + + +BogusSettle: + MOV AL,NormSettle ; someone has diddled the settle + JMP GotSlowSettle + +CHECKSINGLE ENDP + + + + +;------------------------------------------------------------ +; +; DISK I/O HANDLER +; +; On entry: +; AL = Drive Number (0-6) +; AH = media Descriptor +; CX = sector count +; DX = first sector +; DS = CS +; ES:DI = transfer address +; [RFLAG] = operation (2 for read, 3 for write) +; [VERIFY] = 1 for verity after write +; +; On exit: +; if successful carry flag = 0 +; else CF=1 and AL contains error code +; + + + Public DISKRD +DISKRD PROC NEAR + mov CS:[RFLAG],ROMRead ; set command to read + +DISKIO: + mov BX,DI ; ES:BX is transfer address + Call SetDrive ; map logical and physical + jc BadDrive ; carry means BDS not found + mov al,BYTE PTR DS:[DI].Mediad + mov cs:MedByt,al ; Preserve media byte for drive for use + ; in determining media change. + jcxz IORET + mov cs:[SPSAV],SP ; save the sp value +; +; Ensure that we are trying to access valid sectors on the drive +; + mov SI,DX ; start with first sector + add SI,CX ; add in sector count + add DX,WORD PTR [DI].HIDSEC ; add in the hidden sectors + cmp SI,WORD PTR [DI].DRVLIM ; compare against drive maximum + ja BADDRIVE ; if greater than max, error + mov cs:[SECCNT],CX ; save sector count +;;Rev 3.30 Modification ----------------------------------------- +; SET UP POINTER TO DISK BASE TABLE IN [DPT]. WE CANNOT ASSUME THAT IOSETUP +; WILL DO IT BECAUSE WE WILL SKIP THE SET UP STUFF WITH HARD DISKS. + PUSH DS + XOR AX,AX + MOV DS,AX + LDS SI,DWORD PTR DS:[DSKADR]; CURRENT DISK PARM TABLE + MOV WORD PTR CS:DPT,SI + MOV WORD PTR CS:DPT+2,DS + POP DS +;;End of Modification ----------------------------------------- +; +; For hard drives do not do media check or set DPT. +; + test word ptr [di].flags,fNon_Removable + jnz Skip_Setup + CALL CHECKSINGLE +; +; Check to see if we have previously noted a change line. The routine +; returns if everything is OK. Otherwise, it pops off the stack and returns +; the proper error code. +; +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| + Public DiskIO_Patch ;| +DiskIO_PATCH: ;| + CALL CheckLatchIO ;| +;----------------------------------------| +; +; Set up tables and variables for I/O + call IOSetUp +; +; Now the settle values are correct for the following code +; +Skip_Setup: + mov AX,DX ; setup locical sector for divide + xor DX,DX + div word ptr [DI].SECLIM ; divide by sectors per track + inc DL + mov cs:[CURSEC],DL ; save current sector + mov CX,word ptr [DI].HDLIM ; get number of heads + xor DX,DX ; divide tracks by heads per cylinder + div CX + mov cs:[CURHD],DL ; save current head + mov cs:[CURTRK],AX ; save current track +; +; We are now set up for the I/O. Normally, we consider the DMA boundary +; violations here. Not true. We perform the operation as if everything is +; symmetric; let the DISK INT handler worry about the DMA violations. +; + mov AX, cs:[SECCNT] + call BLOCK + call DONE + ret + +DISKRD ENDP + + + +; +; IOSetUp: +; +; IOSetUp does the following functions: +; * Set the drive-last-accessed flag (for diskette only). No need to +; update these flags for hard disks becuase we know a hard disk will +; not be removed. +; * Set the proper last sector number in the Disk Parameter Table (DPT) +; * Set the proper motor start up time in DPT +; * Set the proper head settle time in the DPT +; +; Input: +; DS:DI -> current BDS. +; Output: +; AX,CX,SI are destroyed. +; + public IOSetUp +IOSETUP PROC NEAR + MOV AL,[DI].DRIVENUM + MOV CS:[TIM_DRV],AL ; SAVE DRIVE LETTER +; +; determine proper head settle values +; + mov CX,DS + LDS SI,DWORD PTR CS:[DPT] ; GET POINTER TO DISK BASE TABLE + MOV AL,CS:[EOT] + mov [SI].DISK_EOT,AL ; bump for us + mov AL,[si].DISK_Motor_Strt ; preserve old motor start time + mov cs:MotorStartup,AL +; +; For 3.5" drives, both external as well as on the K09, we need to set the +; Motor Start Time to 4. This checking for every I/O is going to affect +; performance across the board, but is necessary!! +; + push es + mov es,cx ; ES:DI -> to current BDS + cmp byte ptr es:[di].FormFactor,ffsmall + jnz Motor_Start_OK + mov AL,4 + xchg AL,[si].DISK_MOTOR_STRT +Motor_Start_OK: + pop ES +; +; DS:SI now points to disk parameter table. Get current settle and set fast +; settle +; + + XOR AL,AL + INC AL ; IBM WANTS FAST SETTLE = 1 - RS + xchg AL,[SI].DISK_Head_Sttl ; get settle and set up for fast + mov cs:SettleCurrent,AL + MOV AL,NORMSETTLE ; SOMEONE HAS DIDDLED THE SETTLE +GotSlowSettle: + mov DS,CX + mov cs:SettleSlow,AL + ret + + + + +; +; Set time of last access, and reset default values in the DPT. +; +DONE: + test word ptr [di].Flags,fNon_Removable + jnz RETZ ; Do not set for non-removable Media + call SET_TIM ; set time of last access for drive +; +; Restore head settle and EOT values +; +DiddleBack: + push ax ; preserve AX + mov DX,DS ; save DS in DX + mov AL,cs:SettleCurrent ; get value in registers + mov AH,cs:MotorStartup + lds SI,cs:DPT ; get pointer to DPT + mov [SI].Disk_EOT,9 ; save values in DPT + mov [SI].Disk_Head_Sttl,AL + mov [si].Disk_Sector_Siz,2 + mov [si].Disk_Motor_Strt,AH + mov DS,DX ; restore DS + pop ax ; restore AX +RETZ: + ret + + + + + +; +; Block reads or writes the number of sectors specified in AX +; handling track boundaries. For example, on an 8 sector per track +; disk there might be a request to read 6 sectors starting at the 5th +; sector. Block breaks this request into a read of sectors 5-8 on +; the first track and a read of sectors 1-2 on the next track. Disk is +; called to do the actual read. +; +; Inputs: +; AX - number of sectors to be read +; DS:DI points to BDS for disk drive +; cs:CurSec - sector on track where read should start +; cs:CurTrk - track where read should start +; cs:CurHd - head for read +; ES:BX - transfer address +; AX, CX, and BL are not preserved +; + +BLOCK: + or AX,AX ; see if any sectors to read + jz RETZ ; if not, return +;;Rev 3.30 Modification ----------------------------------------- +; Fixed disk will not be restricted to the trk-by-trk basis. + test word ptr [di].Flags, fNon_Removable + jz BLOCK_FLOPPY + call DISK + xor ax,ax + RET +BLOCK_FLOPPY: +;;End of Modification ----------------------------------------- +; +; READ AT MOST 1 TRACK WORTH. PERFORM MINIMIZATION AT SECTOR / TRACK +; + mov CL,byte ptr [DI].SecLim ; get sectors per track + inc CL + sub CL,cs:CurSec ; set CX to number of sector after current + xor CH,CH ; sector on the current track + cmp AX,CX ; is all of request on current track? + jae GotMin ; no, jump down + mov CX,AX ; yes, set number of sector on this track to AX +GotMin: + ; now + ; AX is the requested number of sectors to read + ; CX is the number that we can do on this track + push AX + push CX + mov AX,CX ; AL is number of sectors to read + call Disk + pop CX + pop AX + + ; CX is the number of sectors just transferred + sub AX,CX ; reduce sectors-remaining by last I/O + shl CL,1 + add BH,CL ; adjust transfer address + jmp Block ; jump to do any remaining sectors + +IOSETUP ENDP + + + + + +; +; DISK: +; Disk is called to read or write one or more sectors on a track. +; Retries are make if an error occurs. +; +; Input: +; AL - number of sector to be read/written (they must all be on one track) +; DS:DI points to BDS for the drive +; ES:BX is transfer address (must not cross 64k physical boundry) +; [RFLAG] is 2 for read and 3 for write +; [VERIFY] is 0 for normal, 1 for verify after write +; [CurTrk] is track (cylinder) to be read/written. +; [CurHd] is head to be used in operation. +; [CurSec] is sector to start read on. +; +; The following are overwritten: BP, +; Output: +; [SECCNT] is decrement by the number of sectors read or written + + + public disk +DISK PROC NEAR + mov BP,MAXERR ; set up retry count + MOV AH,CS:RFLAG ;GET READ/WRITE INDICATOR + +RETRY: + ; AX is overwritten in int 13 call, so + ; to do a retry we need to save the + ; value by pushing on the stack + push AX + ; the next five lines of code put the + ; sector number in bit 5-0 of CL and the + ; cylinder number in CH and bits 7-6 of + ; CL. The register must be set up in this + ; way for the bios. + mov DX,cs:[CURTRK] ;Load current cylinder +;;Rev 3.30 Modification ----------------------------------------- + test word ptr [di].FLAGS, fNon_Removable ;Fixed disk + jz DISK_NOT_MINI ;no, skip this. + cmp [di].IsMini, 1 ;Is this a mini disk? + jnz DISK_NOT_MINI ;No. continue to next. + add dx, [di].Hidden_Trks ;else add hidden trks. +DISK_NOT_MINI: +;;End of Modification ----------------------------------------- + ror DH,1 ; get high two bits of cylinder in correct place + ror DH,1 + + or DH,cs:[CURSEC] ; get sector value + mov CX,DX ; put cylinder/sector values in correct register + ; get head value + xchg CH,CL ; put bytes in correct place + mov DH,byte ptr cs:[CurHD] + ; get drive number + mov DL,byte ptr [DI].DriveNum + + CMP BYTE PTR [DI].FORMFACTOR,FFHARDFILE + JZ DO_FAST ; HARD FILES USE FAST SPEED +; +; The registers are now all set up for call on rom-bios. +; The next dozen or so line determines whether we call Do_Fast or Do_Norm +; for the actual I/O read. Do_Fast calls FastSpeed for the actual I/O. +; Do_Norm calls NormSpeed. NormSpeed changes the value for the head settle +; time in the disk parameter table to a larger value and then calls FastSpeed +; to do the I/O. So Do_Fast just has a shorter head settle time. +; + CMP CS:[STEP_DRV],-1 + jz Do_Writej + + cmp AH,ROMRead ; For read... + je Do_Fast ; ... alway use fast + + cmp AH, ROMVerify ; For verify... + je Do_Fast ; ... alway use fast + +Do_Writej: + jmp DO_Write ; Jump down for write... + + +DO_Fast: + CALL FastSpeed ; do I/O carry set if error +TestErr: + jc DSKERR ; error -- get out +; SET DRIVE AND TRACK OF LAST ACCESS + mov cs:[STEP_DRV],DL ; save the last drive accessed + mov byte ptr [di].track,CH ; save in BDS + +NO_SET: + cmp CS:WRTVERIFY,103H ; Check for write and verify + jz DoVerify ; yes -- go do verify +NOVERIFY: + pop AX ; pop command and num sec. from stack + and CL,03FH ; Eliminate cylinder bits from sector + xor AH,AH + sub cs:[SECCNT],AX ; Reduce count of sectors to go + add CL,AL ; Next sector + mov cs:[CURSEC],CL + cmp CL,BYTE PTR [DI].SECLIM ; See if sector/track limit reached + jbe Disk_Ret ; yes, return +NextTrack: + mov cs:[CURSEC],1 ; Start with first sector of next track + mov DH,CS:[CURHD] + inc DH ; go to next head + cmp DH,BYTE PTR [DI].HDLIM ; at head limit? + jb NOXOR ; no, jump down + xor DH,DH ; at head limit, reset to head zero ... + inc cs:[CURTRK] ; and go to next head +NOXOR: + mov cs:[CURHD],DH ; save new head number +Disk_Ret: + clc ; successful return so clear error flag + ret ; all done +DISK ENDP +; +; The request is for write. Determine if we are talking about the same +; track and drive. If so, use the fast speed. +; +DO_WRITE PROC NEAR + cmp DL,cs:[STEP_DRV] ; same drive? + jnz DO_Norm ; no, do normal speed + cmp CH,byte ptr [di].track ; same track on drive + jz DO_Fast ; yes, do fast speed +DO_Norm: + call NormSpeed ; use larger head settle time + jmp SHORT TestErr ; test for error + +DO_WRITE ENDP + + +; +; we have a verify request also. Get state info and go verify +; + +DOVERIFY PROC NEAR + pop AX ; get number of sectors from stack + push AX ; in non-detructive fashion + MOV AH,ROMVERIFY ; REQUEST VERIFY + CALL FastSpeed ; MZ 2.21 change settle mode + JNC NoVerify +DOVERIFY ENDP + +; +; Need to special case the change-line error AH=06h. If we get this, we +; need to return it. +; +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| + Public DSKERR ;| +DSKERR PROC NEAR ;| + CALL CheckIO ;| +;---------------------------------------;| + + Call AGAIN ; reset the disk and decrement retry cnt + jz HARDERR ; if z flag set, did all retries-give up + cmp AH,80H ; timeout? + jz HARDERR ; yes, jump to hard error +DSKERR1: + pop AX ; Restore sector count + jmp RETRY ; and try again + +HARDERR: + PUBLIC HARDERR + CALL MapError + +HARDERR2: ; for routines that call MapError themselves + PUBLIC HARDERR2 + mov cs:[Tim_Drv],-1 ;Force a media check through ROM + mov CX,cs:SECCNT ;Get count of sectors to go + mov SP,cs:[SPSAV] ;Recover entry stack pointer +; +; Since we are performing a non-local goto, restore the disk parameters +; +MedByt_OK: + call DiddleBack + ret ;and return + +DSKERR ENDP + + +; +; change settle value from SettleCurrent to whatever is appropriate +; +NORMSPEED PROC NEAR + push DS ; save two registers + push AX + mov AL,cs:SettleSlow ; change value in current disk parm tbl + lds SI,cs:DPT ; current disk parm table + mov [SI].Disk_Head_Sttl,AL + pop AX ; restore command and sector count + pop DS + call FastSpeed ; do I/0 + push DS ; restore the value in disk parm table + lds SI,cs:DPT + mov [SI].Disk_Head_Sttl,1 ; 1 is fast settle + pop DS + ret + +NORMSPEED ENDP + + +FASTSPEED PROC NEAR +; +; If the drive has been marked as too big (i.e. starting sector of the +; partition is > 16 bits, then ALWAYS return drive not ready. +; + TEST BYTE PTR [DI].FatSiz,fTOOBIG + + + IF TEST + JZ Ready ; if debugging use jmp rather + JMP NotReady ; than local jnz +Ready: + else + JNZ NotReady + endif + + Message fTestINIT,<"<"> ; print debug messages + MNUM fTestINIT,AX + Message fTestINIT,<","> + MNUM fTestINIT,ES + Message fTestINIT,<":"> + MNUM fTestINIT + Message fTestINIT,<","> + MNUM fTestINIT,CX + Message fTestINIT,<","> + MNUM fTestINIT,DX + Message fTestINIT,<">"> + + int 13h ; call rom-bios disk routines + +Death: + ret +NotReady: + stc ; set carry to indicate error + mov AH,80h ; put error code in AH + jmp Death ; jump to ret + +FASTSPEED ENDP + + +; +; Map error returned by ROM into corresponding code to be returned to +; DOS in AL. +; +MAPERROR PROC NEAR + PUBLIC MAPERROR + push CX ; save cx + push CS + pop ES ; make ES the local segment + mov AL,AH ; move error code into AL + mov cs:[LSTERR],AL ; terminate list with error code + mov CX,NUMERR ; number of possible error conditions + mov DI,OFFSET ERRIN ; point to error conditions + repne SCASB + mov AL,cs:[DI + NUMERR - 1] ; get translation + pop cx ; restore cx + stc ; flag error condition + ret +MAPERROR ENDP + +; +; Set the time of last access for this drive. This is done only for removable +; media. +; + public SET_TIM +SET_TIM PROC NEAR + push ax + xor AH, AH ; set command to get time + int 1Ah ; call rom-bios timer function + or AL,AL ; is there 24 hour rollover? + jz NOROLL3 ; no, skip down + inc cs:[DayCnt] ; yes, then increment DayCnt +NOROLL3: +; We have the new time. If we see that the time has passed, then we reset +; the threshold counter... + cmp DX,word ptr [di].TIM_LO ; Did any time pass? + jnz SetAccess ; yes, update access time + cmp CX,word ptr [di].TIM_HI ; now look at the high bits + jz Done_Set ; if equal then no time passed +SetAccess: ; we get here if some time has passed + ; zero AccessCount to show time passage + mov byte ptr cs:[AccessCount],0 + MOV WORD PTR DS:[DI].TIM_LO,DX ; save low time bits + MOV WORD PTR DS:[DI].TIM_HI,CX ; save high time bit +Done_Set: + clc ; indicate no error + pop ax ; restore AX register + ret + +SET_TIM ENDP + ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING + +; +; This is the true DISK INT handler. We parse the request to see if there is +; a DMA violation. If so, depending on the function, we: +; READ/WRITE Break the request into three pieces and move the middle one +; into our internal buffer. +; FORMAT Copy the format table into the buffer +; VERIFY Point the transfer address into the buffer +; +; This is the biggest bogosity of all. The IBM controller does NOT handle +; operations that cross physical 64K boundaries. In these cases, we copy +; the offending sector into the buffer below and do the I/O from there. +; + +INT13FRAME STRUC +oldbp dw ? +oldax dw ? +oldbx dw ? +oldcx dw ? +olddx dw ? +olddd dd ? +oldf dw ? +INT13FRAME ENDS + +;;Rev 3.30 Modification ----------------------------------------- +;To handle the INT 13h, AH = 8 Problem. +;Save Registers here. +Save_AX DW ? +Save_BX DW ? +Save_CX DW ? +Save_DX DW ? +Save_DI DW ? +Save_SI DW ? +Save_BP DW ? +Save_DS DW ? +Save_ES DW ? +Prev_DX DW ? +Save_Flag DW ? +;;End of Modification ----------------------------------------- + + +; +; Block13: +; +; Entry conditions: +; AH = function +; AL = number of sectors +; ES:BX = DMA address +; CX = packed track and sector +; DX = head and drive +; Output conditions: +; NO DMA violation. +; + Public Block13 +Block13 PROC FAR +; +; Let the opperation proceed. If there is a DMA violation, then we do things. +; + mov cs:PrevOper,AX ; save request + pushf ; preserve the flags + cmp AH,ROMFormat ; format request? + jnz Not_Format ; no, skip down + +; Set changed by format bit for all logical drives using this physical drive +;---------------------------------------------------------| +; Warning: Do Not Change the following. | +; It gets patched in at INIT time | + Public Changed_Patch +Changed_Patch: + mov word ptr cs:[FlagBits],fChanged_By_Format+fChanged + call Set_Changed_DL ; Indicate that media changed by format +; | +;---------------------------------------------------------| + +Not_Format: +;;Rev 3.30 Modification ----------------------------------------- + cmp ah, 8 ; Read Driver Parm ? + je Bus_Problem + cmp ah, 15h + je Bus_Problem + CALL ORIG13 ; SIMULATE INT 13 + JC GOTERR13_br ; ERROR? + RET 2 ; NO, RETURN AND CLEAR FLAGS + +GOTERR13_br: jmp Goterr13 + +;Some machines have a problem with Int 13h function=8 +;This function does not reset the common buses after the execution. +;To solve this problem, when we detect AH=8h, then we will save the result +;and will issue AH=1 (Read Status) call to reset the buses. + +Bus_Problem: + mov cs:Prev_DX, DX ;save orignal drive number + call Orig13 ;Do "Read drive parm" + + mov cs:Save_AX, AX ;Save registers,flag + mov cs:Save_BX, BX + mov cs:Save_CX, CX + mov cs:Save_DX, DX + mov cs:Save_DI, DI + mov cs:Save_SI, SI + mov cs:Save_BP, BP + mov cs:Save_DS, DS + mov cs:Save_ES, ES + pushf + pop cs:Save_Flag + + mov dx, cs:Prev_DX ;restore orignal drive + pushf + mov ah, 1 ;Read Status. + call Orig13 ;Reset the bus as a side effect + + mov AX, cs:Save_AX ;restore registers,flag + mov BX, cs:Save_BX + mov CX, cs:Save_CX + mov DX, cs:Save_DX + mov DI, cs:Save_DI + mov SI, cs:Save_SI + mov BP, cs:Save_BP + mov DS, cs:Save_DS + mov ES, cs:Save_ES + push cs:Save_Flag + popf + jc GotErr13 ;AH=8 had been an error? + ret 2 +; +; Some kind of error occurred. See if it is DMA violation +; +GotErr13: + pushf + cmp AH, 09h ; is error DMA error code? + JNZ CHECK_ECC + JMP GOTDMAERR +CHECK_ECC: + CMP AH,11H + JZ OK11 + POPF + RET 2 +; +; We have an error status 11h. This indicates an ECC-corrected error. Note +; that this indicates that the data is PROBABLY correct but not CERTAINLY +; correct. The ROMs on PC-1s and PC_XTs have a 'bug' in that if an ECC error +; occurs for a multi-sector read, only the sectors up to the one where the +; error occurred are read in. We have no way of knowing how many were read in +; this case, so we redo the operation, reading one sector at a time. If we +; get an ECC error on reading one sector, we ignore the error because the +; sector has been read in. +; + PUBLIC OK11 +OK11: +; popf ; restore flags +;;Rev 3.30 Modification ----------------------------------------- +; Here, it is better reset the system. So, we are going to +; call Orig13 again + mov ah, 0 + call Orig13 ;reset. Don't care about result +;;End of Modification ----------------------------------------- + + mov ax,cs:[PrevOper] ; Retrieve request +; +; This will provide a termination point. +; + cmp AL,1 ; If request for one sector, assume OK + jnz ECC_Err_Handle ; more than one sector -- jump down + xor AH,AH ; clear carry too! + ret 2 + + Public ECC_Err_Handle +ECC_Err_Handle: + SAVEREG + mov cs:[Number_Of_Sec],AL +Loop_ECC: + mov AX,CS:[PrevOper] ; set command to previos command + mov AL,1 ; but request only one sector +; +; we do reads one sector at a time. this ensures that we will eventually +; finish the request since ecc errors on 1 sector do read in that sector. +; +; we need some "intelligence" in the ecc handler to handle reads +; that attempt to read more sectors than are available on a particular +; track. +; we call check_wrap to set up the sector #, head # and cylinder # for +; this request. +; at this point, all registers are set up for the call to orig13, except +; that there maybe a starting sector number that is bigger than the number +; of sectors on a track. +; + + CALL Check_Wrap ; see if wrapping around cylinder + + pushf ; save flags + call ORIG13 ; call original rom-bios code +;;Rev 3.30 Modification ------------------------------------------------------ + JNC OK11_OP + CMP AH,11H ; ONLY ALLOW ECC ERRORS + JNZ OK11_EXIT_err ; Other error? + mov ah, 0 ; ECC error. Reset it again. + pushf + call Orig13 +OK11_Op: + dec cs:[Number_of_Sec] ; adjust number of sectors for one read + jz OK11_Exit ; all done? + inc CL ; advance sector number + inc BH ; add 200H to address + inc BH + jmp short Loop_ECC ; and around for reading another sector + +OK11_EXIT_err: + stc ; Set carry bit again. +;;End of Modification ------------------------------------------------------ + +OK11_Exit: + RESTOREREG + Ret 2 + + + +; +; we truly have a DMA violation. Restore register AX and retry the +; operation as best we can. +; +GotDMAErr: + pop AX ; clean up stack + mov AX,cs:PrevOper ; restore command + sti ; restore interrupts + cmp AH,ROMRead ; determine the command + jb IntDone + cmp AH,ROMVerify + jz IntVerify + cmp AH,ROMFormat + jz IntFormat + ja IntDone +; +; We are doing a read/write call. Check for DMA problems +; + SaveReg ; save register we overwrite + push BP + mov BP,SP + mov DX,ES ; Check for 64k boundary error + + shl DX,1 + shl DX,1 + shl DX,1 + shl DX,1 ; Segment converted to absolute address + + add DX,BX ; Combine with offset + add DX,511 ; simulate a transfer +; +; If carry is set, then we are within 512 bytes of the end of the segment. +; We skip the first transfer and perform the remaining buffering and transfer +; + JNC NO_SKIP_FIRST + mov DH,byte ptr [bp.olddx+1] ; set correct head number + jmp Buffer + +NO_SKIP_FIRST: +; +; DX is the physical 16 bits of start of transfer. Compute remaining +; sectors in segment. +; + shr DH,1 ; DH = number of sectors before address + mov AH,128 ; AH = max number of sectors in segment + sub AH,DH +; +; AH is now the number of sectors that we can successfully write in this +; segment. If this number is above or equal to the requested number, then we +; continue the operation as normal. Otherwise, we break it into pieces. +; + cmp AH,AL ; can we fit it in? + jb DoBlock ; no, perform blocking. +; +; Yes, the request fits. Let it happen +; + MOV DH,BYTE PTR [BP.OLDDX+1] ; SET UP HEAD NUMBER + call DoInt + jmp Bad13 +; +; Verify the given sectors. Place the buffer pointer into our space. +; +IntVerify: + SaveReg + push CS + pop ES +DoSimple: + mov BX,OFFSET DiskSector + pushf + call Orig13 + RestoreReg + ret 2 + +; +; Format operation. Copy the parameter table into memory +; +IntFormat: + SaveReg + SaveReg + push ES + push CS + pop ES + pop DS + mov SI,BX + mov DI,OFFSET DiskSector + call Move + RestoreReg + jmp DoSimple +; +; Inline continuation of operation +; +IntDone: + jmp Orig13 +; +; We can't fit the request into the entire block. Perform the operation on +; the first block. +; +; +; DoBlock is modified to correctly handle multi-sector disk I/O. +; Old DoBlock had added the number of sectors I/Oed (Ah in Old DoBlock) after +; the DoInt call to CL. Observing only the lower 6 bits of CL(=max. 64) can +; represent a starting sector, if AH was big, then CL would be clobbered. +; By the way, we still are going to use CL for this purpose since Checkwrap +; routine will use it as an input. To prevent CL from being clobbered, a +; safe number of sectors should be calculated like "63 - # of sectors/track". +; DoBlock will handle the first block of requested sectors within the +; boundary of this safe value. + +;Try to get the # of sectors/track from BDS via Rom drive number. +;For any mini disks installed, here we have to pray that they have the +;same # of sector/track as the main DOS partition disk drive. + +DoBlock: +;;Rev 3.30 Modification ------------------------------------------------------ + Message ftestDisk,<"!!!DMA DoBlock!!!"> + + mov dx, word ptr [bp.olddx] ;set head # + push di + push ds + push ax ;AH=# of sectors before DMA err + ;AL - User requeseted # of sectors + mov byte ptr CS:[phys_drv],1 + mov al, dl + call SetDrive ;get BDS pointer for this DISK. + pop ax + mov byte ptr CS:[phys_drv],0 + test word ptr [DI].Flags, fNon_Removable ;don't have to worry + jnz DoBlockHard ;about floppies. They are track by + ;track operatiions + mov al, ah ;set al = ah for floppies + jmp short DoBlockCont +DoBlockHard: + push cx + xor cx, cx + mov cx, [DI].SecLim ;# of sectors/track + mov ch, 63 + sub ch, cl + mov al, ch + xchg ah, al ;now ah - safe # of sectors + ;al - # of sectors before DMA err + pop cx +DoBlockCont: + pop ds + pop di +DoBlockContinue: + Message ftestDisk,<"%%DMA DoBlock Loop%%"> + cmp ah, al ;if safe_# >= #_of_sectors_to_go_before DMA, + jae DoBlocklast ;then #_of_sectors_to_go as it is for DoInt. + push ax ;save AH, AL + mov al, ah ;Otherwise, set al to ah to operate. + jmp short DoBlockDoInt ;DoInt will set AH to a proper function in [BP.Oldax] +DoBlocklast: + mov ah, al + push ax ;save AH +DoBlockDoInt: ;let AH=AL=# of sectors this shot + CALL DoInt + JC BAD13 ;something happened, bye! + pop ax + SUB BYTE PTR [BP.oldax], AH ;decrement by the successful operation + ADD CL,AH ;advance sector number. Safety gauranteed. + ADD BH,AH ;advance DMA address + ADD BH,AH ;twice for 512 byte sectors. + cmp ah, al ;check the previous value + je Buffer ;if #_of_sectors_to_go < safe_#, then we are done already. + sub al, ah ;otherwise, #_sector_to_go = #_of_sector_to_go - safe_# + call Check_Wrap ;get new CX, DH for the next operation. + jmp short DoBlockContinue ;handles next sectors left. +;;End of Modification ------------------------------------------------------ +; +Buffer: + push BX + mov AH,BYTE PTR [BP.oldax+1] + cmp AH,ROMWrite + jnz DoRead +; +; Copy the offending sector into local buffer +; + SaveReg + push CS ; exchange segment registers + push ES + pop DS + pop ES + mov DI,OFFSET DiskSector ; where to move + push DI ; save it + mov SI,BX ; source + call Move + pop BX ; new transfer address + RestoreReg + mov AL,1 + mov DL,byte ptr [BP.olddx] ; set drive number + call Check_Wrap ; check for head or cylinder wrap + +; +; AH is function +; AL is 1 for single sector transfer +; ES:BX is local transfer addres +; CX is track/sector number +; DX is head/drive number +; SI,DI unchanged +; + CALL DoInt + RestoreReg + jc Bad13 ; go clean up + jmp SHORT DoTail +; +; Reading a sector. Do INT first, then move things around +; +DoRead: + SaveReg + push CS + pop ES + mov BX,OFFSET DiskSector + mov AL,1 + mov DL,byte ptr [BP.olddx] ; set drive number + call Check_Wrap ; check for head or cylinder wrap + +; +; AH = function +; AL = 1 for single sector +; ES:BX points to local buffer +; CX, DX are track/sector, head/drive +; + CALL DoInt + RestoreReg + jc Bad13 ; error => clean up + SaveReg + push CS + pop DS + mov DI,BX + mov SI,OFFSET DiskSector + call Move + RestoreReg +; +; Note the fact that we've done 1 more sector +; +DoTail: + pop BX ; retrieve new DMA area + add BH,2 ; advance over sector + inc CX + mov AL,BYTE PTR [BP.oldAX] + clc + dec AL + jz Bad13 ; no more I/O + mov DL,byte ptr [BP.olddx] ; set drive number + call Check_Wrap ; check for head or cylinder wrap + call DoInt +; +; We are done. AX has the final code; we throw away what we got before +; +Bad13: + mov SP,BP + RestoreReg + ret 2 +Block13 ENDP + + + + + PAGE + + include msioctl.inc + + PAGE +; +; Check_Wrap is a routine that adjusts the starting sector, starting head +; and starting cylinder for an Int 13 request that requests I/O of a lot +; of sectors. It only does this for fixed disks. It is used in the sections +; of code that handle ECC errors and DMA errors. It is necessary, because +; ordinarily the ROM would take care of wraps around heads and cylinders, +; but we break down a request when we get an ECC or DMA error into several +; I/O of one or more sectors. In this case, we may already be beyond the +; number of sectors on a track on the medium, and the request would fail. +; +; Input conditions: +; ALL registers set up for an Int 13 request. +; +; Output: +; - contains starting head number for request +; - contains starting sector and cylinder numbers +; (The above may or may not have been changed, and are 0-based) +; All other registers preserved. +; + public check_wrap +Check_Wrap: + Message ftestDisk,<"Entering Check_Wrap...",cr,lf> + SaveReg + mov byte ptr cs:[Phys_drv],1;Use phys. drive in AL to get BDS + mov al,dl ; put drive number in AL for get BDS + call SetDrive ; Get pointer to BDS for drive. + mov byte ptr cs:[phys_drv],0; Restore flag to use Logical Drive + jc No_wrap ; Do nothing if wrong phys. drive + + test word ptr [di].Flags,fNon_Removable + jz No_wrap ; No wrapping for removable media + MOV BX,[DI].SECLIM + MOV AX,CX + AND AX,003FH ; EXTRACT SECTOR NUMBER + cmp ax,bx ; If Wrap + jbe No_wrap + + div bl ; AH=new sector#, AL = # of head wraps + +; We need to be careful here. If the new sector number == 0, then we are +; on the last sector on that track + or ah,ah + jnz Not_on_Bound + + mov ah,bl ; set sector = SECLIM if on Bndry + dec al ; and decrement Num. head wraps + +Not_on_Bound: + and CL,0C0H ; zero out sector # + + or CL,ah ; OR in new sector # + xor ah,ah ; AX = # of head wraps + inc ax + add al,DH ; add in starting head # + adc ah,0 ; catch any carry + CMP AX,[DI].HDLIM ; are we going to wrap around a head? + jbe No_Wrap_Head ; Do not lose new head number!! + + push DX ; preserve drive number and head number + xor dx,dx + mov bx,[DI].HDLIM + div bx ; DX=new head #, AX=# of cylinder wraps +; Careful here! If new head # is 0, then we are on the last head. + or dx,dx + jnz No_Head_Bound + + mov dx,bx ; On boundary. Set to HDLIM +; If we had some cylinder wraps, we need to reduce them by one!! + or ax,ax + jz No_Head_Bound + + dec ax ; Reduce number of cylinder wraps +No_Head_Bound: + mov bh,dl ; bh has new head number + POP DX ; restore drive number and head number + + dec bh ; get it 0-based + mov DH,bh ; set up new head number in DH + + mov bh,CL + and bh,3FH ; preserve sector number + mov bl,6 + xchg cl,bl + shr bl,cl ; get ms cylinder bits to ls end + + ADD CH,AL ; ADD IN CYLINDER WRAP + adc bl,ah ; add in high byte + shl bl,cl ; move up to ms end + xchg bl,cl ; restore cylinder bits into CL + or CL,bh ; OR in sector number + +No_Wrap: + clc ; reset carry + RestoreReg + RET + +No_Wrap_Head: + mov DH,al ; Do not lose new head number + dec DH ; get it 0-based + jmp short No_Wrap + +; +; INT_2F_13: +; This code is chained into the INT_2F interrupt during bios +; initialization. It allows the user to change the ORIG13 int_13 vector + +; INT_2F_13: +; This code is chained into the INT_2F interrupt during bios +; initialization. It allows the user to change the ORIG13 int_13 vector +; after booting. This allows testing and implementation of custom int_13 +; handlers, without giving up MS-DOS error recovery +; +; Entry Conditions +; AH == RESET_Int_13 (13h) +; DS:DX == Address of New INT_13 Handler +; ES:BX == Address of New INT_13 vector used by WARM BOOT +; (INT 19) +; +; Exit Conditions +; Orig13 == Address of new Int_13 Handler +; DS:DX == Old ORIG13 value +; ES:BX == Old OLD13 value + + ASSUME CS:CODE,DS:Nothing,ES:nothing,SS:NOTHING + + Public INT_2F_13 +INT_2F_13 Proc Far + + cmp AH,13h ; IF (interrupt_value != Reset_Int_13) + je Chg_Orig13 + jmp CS:[Next2f_13] ; THEN Continue on Int_2F chain + +Chg_Orig13: ; ELSE + push word ptr cs:[Orig13] ; Save Old value of OLD13 and + push word ptr cs:[Orig13 + 2]; ORIG13 so that we can + + Push word ptr cs:[OLD13] ; Return them to caller + Push word ptr cs:[OLD13 + 2] + + mov Word Ptr CS:[Orig13],DX ; Orig13 := Addr. Of New INT_13 + ; Vector + mov Word Ptr CS:[Orig13+2],DS + + mov Word Ptr CS:[Old13],BX ; Old13 := Addr. Of New + ; Boot_13 vector + mov Word Ptr CS:[Old13+2],ES + + pop ES ; ES:BX := Old OLD13 vector + pop BX + + pop DS ; DS:DX := Old ORIG13 vector + pop DX + + iret ; END else + +Int_2F_13 ENDP + + + + + + +Move Proc Near + push CX + mov CX,512/2 + cld + rep MOVSW + pop CX + ret +Move Endp + + + + +DoINT proc NEAR + mov DL,byte ptr [BP.olddx] + xor AH,AH + or AL,AL + jz DoIntDone + mov AH,BYTE PTR [BP.oldax+1] + push [BP.oldf] + call Orig13 + pushf + pop [BP.oldf] +DoIntDone: + ret +DoInt endp + +CODE ENDS + END diff --git a/SRC/BIOS/MSDISK.OBJ b/SRC/BIOS/MSDISK.OBJ new file mode 100644 index 0000000..78bc3dd Binary files /dev/null and b/SRC/BIOS/MSDISK.OBJ differ diff --git a/SRC/BIOS/MSEQU.INC b/SRC/BIOS/MSEQU.INC new file mode 100644 index 0000000..122c139 --- /dev/null +++ b/SRC/BIOS/MSEQU.INC @@ -0,0 +1,65 @@ + +; file: msequ.asm contains various equ's used in the bio. The values +; are explained below. +; + +;IBMCOPYRIGHT EQU 0 +fTOOBIG EQU 80h +fBIG EQU 40h +ROMStatus EQU 1 +ROMRead EQU 2 +ROMWrite EQU 3 +ROMVerify EQU 4 +ROMFormat EQU 5 +vid_size EQU 12 + +include msbds.inc ; various equates for bds +include version.inc + + +IF IBMCOPYRIGHT +SYSIZE=200H ;NUMBER OF PARAGRAPHS IN SYSINIT MODULE ;;Rev 3.30 Modification +ELSE +SYSIZE=203H +ENDIF +RSINIT=0A3H ; RS-232 initialization ;;End of Modification +LF=10 ; line feed +CR=13 ; carriage return +BACKSP=8 ; backspace +BRKADR=1BH * 4 ; 006C 1BH break vector address +TIMADR=1CH * 4 ; 0070 1CH timer interrupt +DSKADR=1EH * 4 ; address of ptr to disk parameters +SEC9=522H ; address of disk parameters +HEADSETTLE=SEC9+9 ; address of head settle time +NORMSETTLE=15 ; Normal head settle +SPEEDSETTLE=0 ; Speed up settle time +INITSPOT=534H ; IBM wants 4 zeros here +AKPORT=20H +EOI=20H +CMDLEN = 0 ; length of this command +UNIT = 1 ; sub unit specifier +CMD = 2 ; command code +STATUS = 3 ; status +MEDIA = 13 ; media descriptor +TRANS = 14 ; transfer address +COUNT = 18 ; count of blocks or characters +START = 20 ; first block to transfer +EXTRA = 22 ; usually a pointer to Vol Id for error 15 +CHROUT = 29H +MAXERR = 5 +LSTDRV = 504H + + ; location of boot sector on startup +BootBias = 200h + +NotBusyStatus = 10000000B ; not busy +AckStatus = 01000000B ; acknowledge (for what?) +NoPaperStatus = 00100000B ; No more paper +SelectedStatus = 00010000B ; The printer said it was selected +IOErrStatus = 00001000B ; Some kinda error +RESERVED = 00000110B ; NOPs +TimeOutStatus = 00000001B ; time out. + +PATHGEN = 1 + + \ No newline at end of file diff --git a/SRC/BIOS/MSEXTRN.INC b/SRC/BIOS/MSEXTRN.INC new file mode 100644 index 0000000..67e3288 --- /dev/null +++ b/SRC/BIOS/MSEXTRN.INC @@ -0,0 +1,72 @@ + +; +; file: msextrn.asm +; +; This file list the external variable used in the bio. +; + + EXTRN ORIG13:DWORD,ORIG19:DWORD + EXTRN COM2DEV:WORD,COM1DEV:WORD + EXTRN COM4DEV:WORD,COM3DEV:WORD ;3.30 + EXTRN LPT3DEV:WORD,LPT2DEV:WORD,LPT1DEV:WORD + EXTRN HARDDRV:BYTE,HARDNUM:BYTE,DRVMAX:BYTE,HDSKTAB:WORD + EXTRN DSKDRVS:WORD,HNUM:BYTE,EOT:BYTE,FHAVE96:BYTE + EXTRN REAL13:DWORD,DAYCNT:WORD,CONHeader:WORD + EXTRN TWOHARD:BYTE,INT_2F_NEXT:DWORD + EXTRN BDSH:WORD,BDSX:WORD,START_BDS:DWORD + EXTRN FHAVEK09:BYTE, NEW_ROM:BYTE + EXTRN Single:BYTE + EXTRN BDSMs:BYTE ;for Mini Disk 4/7/86 ;3.30 + EXTRN HaveCMOSClock:byte ;set by MSINIT. Used by MSCLOCK.AS;3.30 M + EXTRN BinToBCD:word ;set by MSINIT. Used by MSCLOCK.AS;3.30 M + EXTRN DaycntToDay:word ;set by MSINIT. Used by MSCLOCK.AS;3.30 M + + if test + IFNDEF NUMBUF ;3.30 + EXTRN NUMBUF:BYTE,DIGITS:BYTE,FTESTBITS:WORD + ENDIF ;3.30 + endif + + EXTRN START$:NEAR,ERROUT:NEAR,BLOCK13:FAR,INT19:FAR + EXTRN INTRET:NEAR,HDRIVE:NEAR,DRIVEX:NEAR,INT13:FAR,CBREAK:NEAR,OUTCHR:NEAR + EXTRN DISKRD:NEAR,MEDIA_PATCH:NEAR,GETBP1_PATCH:NEAR + EXTRN SET_PATCH:NEAR,DISKIO_PATCH:NEAR,DSKERR:NEAR,INIT_PATCH:NEAR + EXTRN TABLE_PATCH:NEAR,EXIT:NEAR,CHANGED_PATCH:NEAR + EXTRN ERRIN:NEAR,GETBP:NEAR,SWPDSK:NEAR ;3.30 + EXTRN OUTCHR:NEAR,WRMSG:NEAR,time_to_ticks:near + EXTRN INT2F_DISK:NEAR,INSTALL_BDS:NEAR,SETDRIVE:NEAR + + if test + IFNDEF NUMBUF ;3.30 + EXTRN MSGNUM:NEAR,MSGOUT:NEAR,dumpbytes:near,hex_to_ascii:near ;3.30 + EXTRN outchar:near ;3.30 + ENDIF ;3.30 + endif + +SYSINITSEG SEGMENT PUBLIC 'SYSTEM_INIT' + ASSUME CS:SYSINITSEG + + EXTRN CURRENT_DOS_LOCATION:WORD + EXTRN FINAL_DOS_LOCATION:WORD + EXTRN DEVICE_LIST:DWORD + EXTRN MEMORY_SIZE:WORD + EXTRN DEFAULT_DRIVE:BYTE + EXTRN BUFFERS:WORD + EXTRN SYSINIT:FAR +SYSINITSEG ENDS + + ASSUME CS:CODE ;3.30 + +; +; End of disk modules for configuration +; + EXTRN End96tpi:byte + EXTRN EndTwoHard:byte + EXTRN EndOneHard:byte + EXTRN EndSwap:byte + EXTRN EndFloppy:byte +; +; IBM fixed up AT ROM +; + EXTRN IBM_DISK_IO:FAR + diff --git a/SRC/BIOS/MSGROUP.INC b/SRC/BIOS/MSGROUP.INC new file mode 100644 index 0000000..ac6202d --- /dev/null +++ b/SRC/BIOS/MSGROUP.INC @@ -0,0 +1,46 @@ +EVBOUND = 1 ;THIS VALUE BEING 0 DOES NO BOUNDARY ALLIGNMENT, VALUE 1 ;3.30 + ; ALIGNS TO EVEN ;3.30 +; : : : : : : : : : : : : : : ;3.30 + IF EVBOUND ;;IF EVEN (WORD) ALLIGNMENT IS REQUESTED, ;3.30 +; : : : : : : : : : : : : : : ;3.30 +EVENB MACRO ;3.30 + EVEN ;;ADJUST TO EVEN BOUNDARY ;3.30 + ENDM ;3.30 + ;3.30 +ODD MACRO ;3.30 +;;GENERATE BOUNDARY PADDING TO FORCE ODD OFFSET ;3.30 + IF (($-CODE) MOD 2) EQ 0 ;3.30 + DB ? ;3.30 + ENDIF ;3.30 + ENDM ;3.30 + ;3.30 +CODE_SEGMENT MACRO ;3.30 +;;ALLIGN THE SEGMENT ON WORD BOUNDARY TO ALLOW FOR EVEN ALLIGNMENT OF DATA;3.30 +CODE SEGMENT WORD PUBLIC 'CODE' ;3.30 ;3.30 + ENDM ;3.30 + ;3.30 +; : : : : : : : : : : : : : : ;3.30 + ELSE ;;SINCE EVEN ALLIGNMENT IS NOT DESIRED, JUST USE BYTE ALLI;3.30 GNMENT +; : : : : : : : : : : : : : : ;3.30 + ;3.30 +EVENB MACRO ;3.30 +;;REQUEST FOR WORD ALLIGNMENT DOES NOTHING ;3.30 + ENDM ;3.30 + ;3.30 +ODD MACRO ;3.30 +;;REQUEST FOR ODD ALLIGNMENT DOES NOTHING ;3.30 + ENDM ;3.30 + ;3.30 +CODE_SEGMENT MACRO ;3.30 +;;SEGMENT IS ALLIGNED ON BYTE BOUNDARY FOR MINIMUM SIZE OF GENERATION ;3.30 +CODE SEGMENT BYTE PUBLIC 'CODE' ;3.30 + ENDM ;3.30 + ;3.30 +; : : : : : : : : : : : : : : ;3.30 + ENDIF ;3.30 +; : : : : : : : : : : : : : : ;3.30 + ;3.30 + CODE_SEGMENT ;3.30 + ASSUME CS:CODE ;3.30 + ;3.30 + \ No newline at end of file diff --git a/SRC/BIOS/MSHARD.ASM b/SRC/BIOS/MSHARD.ASM new file mode 100644 index 0000000..5ac9572 --- /dev/null +++ b/SRC/BIOS/MSHARD.ASM @@ -0,0 +1,418 @@ +;*** +; Title: Disk +; By: Michael Hanson +; C: Copyright (C) 1985-1987 by Microsoft corp. +; Date: 1/11/85 +; +; There is a bug in some versions of IBM's AT ROM BIOS +; interupts are not disabled during read operations. +; +; Use: This program should be chained in line with the disk +; interupt 13h, it intercepts read calls to the hard disk +; and handles them appropriately. For other functions it +; passes controll to OLD13, which should contain the +; address of the AT ROM disk routine. The entry point for +; this program is IBM_DISK_IO. +; + + + .286c ;Use 80286 non-protected mode + +BIOSEG = 040h ;Segment for ROM BIOS Data +ROMSEG = 0F000h ;Segment of ROM + + +BAD_DISK = 01 + +HF_PORT = 01F0h +HF_REG_PORT = 03F6h + +;* Offsets into Fixed disk parameter table +FDP_PRECOMP = 5 +FDP_CONTROL = 8 + +DATA SEGMENT AT BIOSEG ;ROM BIOS data segment + + ORG 42h +CMD_BLOCK DB 6 DUP (?) + +;* Offsets into CMD_BLOCK for registers +PRE_COMP = 0 ;Write Pre-compensation +SEC_CNT = 1 ;Sector count +SEC_NUM = 2 ;Sector number +CYL_LOW = 3 ;Cylinder number, low part +CYL_HIGH = 4 ;Cylinder number, high part +DRV_HEAD = 5 ;Drive/Head (Bit 7 = ECC mode, Bit 5 = 512 byte sectors, + ; Bit 4 = drive number, Bits 3-0 have head number) +CMD_REG = 6 ;Command register + + + ORG 074h + +DISK_STATUS1 DB ? +HF_NUM DB ? +CONTROL_BYTE DB ? + +DATA ENDS + + + +;*** Define where the ROM routines are actually located +ROM SEGMENT AT ROMSEG + + ORG 02E1Eh +ROMCOMMAND PROC FAR +ROMCOMMAND ENDP + + ORG 02E7Fh +ROMWAIT PROC FAR +ROMWAIT ENDP + + ORG 02EE2h +ROMWAIT_DRQ PROC FAR +ROMWAIT_DRQ ENDP + + ORG 02EF8h +ROMCHECK_STATUS PROC FAR +ROMCHECK_STATUS ENDP + + ORG 02F69h +ROMCHECK_DMA PROC FAR +ROMCHECK_DMA ENDP + + ORG 02F8Eh +ROMGET_VEC PROC FAR +ROMGET_VEC ENDP + + ORG 0FF65h +ROMFRET PROC FAR ;Far return at F000:FF65 in AT ROM. +ROMFRET ENDP + +ROM ENDS + + +CODE SEGMENT BYTE PUBLIC 'code' + +EXTRN OLD13:DWORD ;Link to AT bios int 13h + +PUBLIC IBM_DISK_IO + + + ASSUME CS:CODE + ASSUME DS:DATA + + +;*** IBM_DISK_IO - main routine, fixes AT ROM bug +; +; ENTRY: (AH) = function, 02 or 0A for read. +; (DL) = drive number (80h or 81h). +; (DH) = head number. +; (CH) = cylinder number. +; (CL) = Sector number (high 2 bits has cylinder number). +; (AL) = number of sectors. +; (ES:BX) = address of read buffer. +; For more on register contents see ROM BIOS listing. +; Stack set up for return by an IRET. +; +; EXIT: (AH) = status of current operation. +; (CY) = 1 IF failed, 0 if successful. +; For other register contents see ROM BIOS listing. +; +; USES: +; +; +; WARNING: Uses OLD13 vector for non-read calls. +; Does direct calls to the AT ROM. +; Does segment arithmatic. +; +; EFFECTS: Performs DISK I/O operation. +; +IBM_DISK_IO PROC FAR + CMP DL, 80h + JB ATD1 ;Pass through floppy disk calls. + CMP AH, 02 + JE ATD2 ;Intercept call 02 (read sectors). + CMP AH, 0Ah + JE ATD2 ;and call 0Ah (read long). +ATD1: + JMP OLD13 ;Use ROM INT 13h handler. +ATD2: + PUSH BX + PUSH CX + PUSH DX + PUSH DI + PUSH DS + PUSH ES + PUSH AX + MOV AX,BIOSEG ;Establish BIOS segment addressing. + MOV DS,AX + MOV DISK_STATUS1, 0 ;Initially no error code. + AND DL, 07fh ;Mask to hard disk number + CMP DL, HF_NUM + JB ATD3 ;Disk number in range + MOV DISK_STATUS1, BAD_DISK + JMP SHORT ATD4 ;Disk number out of range error, return + +ATD3: + PUSH BX + MOV AX, ES ;Make ES:BX to Seg:000x form. + SHR BX, 4 + ADD AX, BX + MOV ES, AX + POP BX + AND BX,000Fh + PUSH CS + CALL CHECK_DMA + JC ATD4 ;Abort if DMA across segment boundary + + POP AX ;Restore AX register for SETCMD + PUSH AX + CALL SETCMD ;Set up command block for disk op + MOV DX, HF_REG_PORT + OUT DX, AL ;Write out command modifier + CALL DOCMD ;Carry out command +ATD4: + POP AX + MOV AH,DISK_STATUS1 ;On return AH has error code + STC + OR AH,AH + JNZ ATD5 ;Carry set if error + CLC +ATD5: + POP ES + POP DS + POP DI + POP DX + POP CX + POP BX + RET 2 ;Far return, dropping flags +IBM_DISK_IO ENDP + + + +;*** SETCMD - Set up CMD_BLOCK for the disk operation +; +; ENTRY: (DS) = BIOS Data segment. +; (ES:BX) in seg:000x form. +; Other registers as in INT 13h call +; +; EXIT: CMD_BLOCK set up for disk read call. +; CONTROL_BYTE set up for disk operation. +; (AL) = Control byte modifier +; +; +; Sets the fields of CMD_BLOCK using the register contents +; and the contents of the disk parameter block for the given drive. +; +; WARNING: (AX) destroyed. +; Does direct calls to the AT ROM. +; +SETCMD PROC NEAR + MOV CMD_BLOCK[SEC_CNT], AL + MOV CMD_BLOCK[CMD_REG], 020h ;Assume function 02 + CMP AH, 2 + JE SETC1 ;CMD_REG = 20h if function 02 (read) + MOV CMD_BLOCK[CMD_REG], 022h ;CMD_REG = 22h if function 0A (" long) +SETC1: ;No longer need value in AX + MOV AL, CL + AND AL, 03fh ;Mask to sector number + MOV CMD_BLOCK[SEC_NUM], AL + MOV CMD_BLOCK[CYL_LOW], CH + MOV AL, CL + SHR AL, 6 ;Get two high bits of cylender number + MOV CMD_BLOCK[CYL_HIGH], AL + MOV AX, DX + SHL AL, 4 ;Drive number + AND AH, 0Fh + OR AL, AH ;Head number + OR AL, 0A0h ;Set ECC and 512 bytes per sector + MOV CMD_BLOCK[DRV_HEAD], AL + PUSH ES ;GET_VEC destroys ES:BX + PUSH BX + PUSH CS + CALL GET_VEC + MOV AX, ES:FDP_PRECOMP[BX] ;Write pre-comp from disk parameters + SHR AX, 2 + MOV CMD_BLOCK[PRE_COMP],AL ;Only use low part + MOV AL, ES:FDP_CONTROL[BX] ;Control byte modifier + POP BX + POP ES + MOV AH, CONTROL_BYTE + AND AH, 0C0h ;Keep disable retry bits + OR AH, AL + MOV CONTROL_BYTE, AH + RET +SETCMD ENDP + + + +;*** DOCMD - Carry out READ operation to AT hard disk +; +; ENTRY: (ES:BX) = address for read in data. +; CMD_BLOCK set up for disk read. +; +; EXIT: Buffer at (ES:BX) contains data read. +; DISK_STATUS1 set to error code (0 if success). +; +; +; +; WARNING: (AX), (BL), (CX), (DX), (DI) destroyed. +; No check is made for DMA boundary overrun. +; +; EFFECTS: Programs disk controller. +; Performs disk input. +; +DOCMD PROC NEAR + MOV DI, BX ;(ES:DI) = data buffer addr. + PUSH CS + CALL COMMAND + JNZ DOC3 +DOC1: + PUSH CS + CALL WAIT ;Wait for controller to complete read + JNZ DOC3 + MOV CX, 100h ;256 words per sector + MOV DX, HF_PORT + CLD ;String op goes up + CLI ;Disable interrupts (BUG WAS FORGETTING THIS) + REPZ INSW ;Read in sector + STI + TEST CMD_BLOCK[CMD_REG], 02 + JZ DOC2 ;No ECC bytes to read. + PUSH CS + CALL WAIT_DRQ + JC DOC3 + MOV CX, 4 ;4 bytes of ECC + MOV DX, HF_PORT + CLI + REPZ INSB ;Read in ECC + STI +DOC2: + PUSH CS + CALL CHECK_STATUS + JNZ DOC3 ;Operation failed + DEC CMD_BLOCK[SEC_CNT] + JNZ DOC1 ;Loop while more sectors to read +DOC3: + RET +DOCMD ENDP + + + +;*** GET_VEC - Get pointer to hard disk parameters. +; +; ENTRY: (DL) = Low bit has hard disk number (0 or 1). +; +; EXIT: (ES:BX) = address of disk parameters table. +; +; USES: AX for segment computation. +; +; Loads ES:BX from interrupt table in low memory, vector 46h (disk 0) +; or 70h (disk 1). +; +; WARNING: (AX) destroyed. +; This does a direct call to the AT ROM. +; +GET_VEC PROC NEAR + PUSH OFFSET ROMFRET + JMP ROMGET_VEC +GET_VEC ENDP + + + +;*** COMMAND - Send contents of CMD_BLOCK to disk controller. +; +; ENTRY: Control_byte +; CMD_BLOCK - set up with values for hard disk controller. +; +; EXIT: DISK_STATUS1 = Error code. +; NZ if error, ZR for no error. +; +; +; WARNING: (AX), (CX), (DX) destroyed. +; Does a direct call to the AT ROM. +; +; EFFECTS: Programs disk controller. +; +COMMAND PROC NEAR + PUSH OFFSET ROMFRET + JMP ROMCOMMAND +COMMAND ENDP + + + +;*** WAIT - Wait for disk interrupt +; +; ENTRY: Nothing. +; +; EXIT: DISK_STATUS1 = Error code. +; NZ if error, ZR if no error. +; +; +; WARNING: (AX), (BL), (CX) destroyed. +; Does a direct call to the AT ROM. +; +; EFFECTS: Calls int 15h, function 9000h. +; +WAIT PROC NEAR + PUSH OFFSET ROMFRET + JMP ROMWAIT +WAIT ENDP + + + +;*** WAIT_DRQ - Wait for data request. +; +; ENTRY: Nothing. +; +; EXIT: DISK_STATUS1 = Error code. +; CY if error, NC if no error. +; +; +; WARNING: (AL), (CX), (DX) destroyed. +; Does a direct call to the AT ROM. +; +WAIT_DRQ PROC NEAR + PUSH OFFSET ROMFRET + JMP ROMWAIT_DRQ +WAIT_DRQ ENDP + + + +;*** CHECK_STATUS - Check hard disk status. +; +; ENTRY: Nothing. +; +; EXIT: DISK_STATUS1 = Error code. +; NZ if error, ZR if no error. +; +; +; WARNING: (AX), (CX), (DX) destroyed. +; Does a direct call to the AT ROM. +; +CHECK_STATUS PROC NEAR + PUSH OFFSET ROMFRET + JMP ROMCHECK_STATUS +CHECK_STATUS ENDP + + + +;*** CHECK_DMA - check for DMA overrun 64k segment. +; +; ENTRY: (ES:BX) = addr. of memory buffer in seg:000x form. +; CMD_BLOCK set up for operation. +; +; EXIT: DISK_STATUS1 - Error code. +; CY if error, NC if no error. +; +; +; WARNING: Does a direct call to the AT ROM. +; +CHECK_DMA PROC NEAR + PUSH OFFSET ROMFRET + JMP ROMCHECK_DMA +CHECK_DMA ENDP + + +CODE ENDS + END diff --git a/SRC/BIOS/MSHARD.OBJ b/SRC/BIOS/MSHARD.OBJ new file mode 100644 index 0000000..4929245 Binary files /dev/null and b/SRC/BIOS/MSHARD.OBJ differ diff --git a/SRC/BIOS/MSINIT.ASM b/SRC/BIOS/MSINIT.ASM new file mode 100644 index 0000000..5e4a840 --- /dev/null +++ b/SRC/BIOS/MSINIT.ASM @@ -0,0 +1,2213 @@ + +; modification history +; +; 3.21 sp added pushf-popf fix around NoParms to fix bug + +;;Rev 3.30 Modification ----------------------------------------------- + test = 0 + include msgroup.inc ;define code segment + include dskprm.inc + include msequ.inc + include msmacro.inc + include msextrn.inc + include biostruc.inc + include cmosequ.inc + + EXTRN OLD13:DWORD + +; THE FOLLOWING LABEL DEFINES THE END OF THE AT ROM PATCH. THIS IS USED +; AT CONFIGURATION TIME. +; Warning!!! This code will be dynamically relocated by MSINIT. + + PUBLIC ENDATROM ;NOT REFERENCES EXTERNALLY, BUT + ; JUST TO CAUSE ENTRY IN LINK MAP +ENDATROM LABEL BYTE + +;CMOS Clock setting support routines used by MSCLOCK. +;Warning!!! This code will be dynamically relocated by MSINIT. + + EXTRN base_century:byte + EXTRN base_year:byte + EXTRN month_tab:byte + + public Daycnt_to_day ;for real time clock support +Daycnt_to_day proc near ;for real time clock support +;Entry: [DAYCNT] = number of days since 1-1-80 +;Return: CH=centry in BCD, CL=year in BCD, DH=month in BCD, DL=day in BCD + + push [daycnt] ;save daycnt + cmp daycnt, (365*20+(20/4)) ;# days from 1-1-1980 to 1-1-2000 + jae century20 + mov base_century, 19 + mov base_year, 80 + jmp years +century20: ;20th century + mov base_century, 20 + mov base_year, 0 + sub daycnt, (365*20+(20/4)) ;adjust daycnt +years: + xor dx, dx + mov ax, daycnt + mov bx, (366+365*3) ;# of days in a Leap year block + div bx ;AX = # of leap block, DX=daycnt + mov daycnt, dx ;save daycnt left +; or ah, ah ;ax should be less than 256 +; jz OK1 +; jmp Erroroccur +;OK1: + mov bl,4 + mul bl ;AX=# of years. Less than 100 + add base_year, al ;So, ah = 0. Adjust year + inc daycnt ;set daycnt to 1 base + cmp daycnt, 366 ;daycnt=remainder of leap year bk + jbe Leapyear ;within 366+355+355+355 days. + inc base_year ;if daycnt <= 366, then leap year + sub daycnt, 366 ;else daycnt--, base_year++; + ;And next three years are normal + mov cx, 3 +Regularyear: + cmp daycnt, 365 ;for(i=1; i>3 or daycnt <=365;i++) + jbe YearDone ;{if (daycnt > 365) + inc base_year ; { daycnt -= 365 + sub daycnt, 365 ; } + loop regularyear ;} +; jmp Erroroccur ;cannot come to here +Leapyear: + mov byte ptr month_tab+1,29 ;leap year. change month table. +Yeardone: + xor bx,bx + xor dx,dx + mov ax, daycnt + mov si, offset month_tab + mov cx, 12 +Months: + inc bl ; + mov dl, byte ptr ds:[si] ;cmp daycnt for each month til fit + cmp ax, dx ;dh=0. + jbe Month_done + inc si ;next month + sub ax, dx ;adjust daycnt + loop Months +; jmp Erroroccur +Month_done: + mov byte ptr month_tab+1, 28 ;restore month table value + mov dl, bl + mov dh, base_year + mov cl, base_century ;al=day,dl=month,dh=year,cl=cntry + call word ptr BinToBCD ;To save 15 bytes, Bin_To_BCD proc + ;was rel from Daycnt_to_Day proc. +; call Bin_to_bcd ;convert "day" to bcd + xchg dl, al ;dl = bcd day, al = month + call word ptr BinToBCD +; call Bin_to_bcd + xchg dh, al ;dh = bcd month, al = year + call word ptr BinToBCD +; call Bin_to_bcd + xchg cl, al ;cl = bcd year, al = century + call word ptr BinToBCD +; call Bin_to_bcd + mov ch, al ;ch = bcd century + pop [daycnt] ;restore original value + ret +Daycnt_to_day endp + + public EndDaycntToDay +EndDaycntToDay label byte + + public Bin_to_bcd +Bin_to_bcd proc near ; real time clock sup +;Convert a binary input in AL (less than 63h or 99 decimal) +;into a bcd value in AL. AH destroyed. + push cx + xor ah, ah + mov cl, 10 + div cl ;al=high digit bcd, ah=low digit bcd + mov cl, 4 + shl al, cl ;mov the high digit to high nibble + or al, ah + pop cx + ret +Bin_to_bcd endp + + Public EndCMOSClockset ;End of routines for CMOS clock +EndCMOSClockset label byte +; + + EXTRN INT6C_RET_ADDR:DWORD ; RETURN ADDRESS FROM INT 6C + EXTRN BIN_DATE_TIME:BYTE + EXTRN MONTH_TABLE:WORD + EXTRN DAYCNT2:WORD + EXTRN FEB29:BYTE + EXTRN TimeToTicks:Word ;indirect intra-segment call add + + EVENB +; +; THE K09 REQUIRES ROUTINES FOR READING THE CLOCK BECAUSE OF THE SUSPEND/ +; RESUME FACILITY. THE SYSTEM CLOCK NEEDS TO BE RESET AFTER RESUME. +; + ASSUME ES:NOTHING + +; THE FOLLOWING ROUTINE IS EXECUTED AT RESUME TIME WHEN THE SYSTEM +; POWERED ON AFTER SUSPENSION. IT READS THE REAL TIME CLOCK AND +; RESETS THE SYSTEM TIME AND DATE, AND THEN IRETS. +; Warning!!! This code will be dynamically relocated by MSINIT. +INT6C PROC FAR + PUSH CS + POP DS + + ASSUME DS:CODE + + POP WORD PTR INT6C_RET_ADDR ; POP OFF RETURN ADDRESS + POP WORD PTR INT6C_RET_ADDR+2 + POPF + CALL READ_REAL_DATE ; GET THE DATE FROM THE CLOCK + CLI + MOV DS:DAYCNT,SI ; UPDATE DOS COPY OF DATE + STI + CALL READ_REAL_TIME ; GET THE TIME FROM THE RTC + CLI + MOV AH, 01h ; COMMAND TO SET THE TIME + INT 1Ah ; CALL ROM-BIOS TIME ROUTINE + STI + JMP INT6C_RET_ADDR ; LONG JUMP + +INT6C ENDP + + + INCLUDE READCLOCK.INC + INCLUDE CLOCKSUB.INC + + PUBLIC ENDK09 ;NOT REFERENCES EXTERNALLY, BUT + ; JUST TO CAUSE ENTRY IN LINK MAP +ENDK09 LABEL BYTE + ASSUME DS:NOTHING,ES:NOTHING +;;End of Modification ----------------------------------------------- + +;------------------------------------------------------------------------ +; : +; System initiailzation : +; : +; The entry conditions are established by the bootstrap : +; loader and are considered unknown. The following jobs : +; will be performed by this module: : +; : +; 1. All device initialization is performed : +; 2. A local stack is set up and DS:SI are set : +; to point to an initialization table. Then : +; an inter-segment call is made to the first : +; byte of the dos : +; 3. Once the dos returns from this call the ds : +; register has been set up to point to the start : +; of free memory. The initialization will then : +; load the command program into this area : +; beginning at 100 hex and transfer control to : +; this program. : +; : +;------------------------------------------------------------------------ + +; DRVFAT must be the first location of freeable space! + EVENB +DRVFAT DW 0000 ; Drive and FAT ID of DOS +BIOS$ DW 0000 ; First sector of data +DOSCNT DW 0000 ; How many sectors to read +fBigFAT DB 0 ; Flags for drive +FatLen DW ? ; number of sectors in FAT. +FatLoc DW ? ; seg addr of fat sector + +;;Rev 3.30 Modification ----------------------------------------------- +; THE FOLLOWING TWO BYTES ARE USED TO SAVE INFO RETURNED BY INT 13, AH=8 +; CALL TO DETERMINE DRIVE PARAMETERS. +NUM_HEADS DB 2 ; NUMBER OF HEADS RETURNED BY ROM +SEC_TRK DB 9 ; SEC/TRK RETURNED BY ROM +NUM_CYLN DB 40 ; NUMBER OF CYLINDERS RET BY ROM + + public Model_Byte +MODEL_BYTE DB 0FFH ; MODEL BYTE. SET UP AT INIT TIME. + ; FF - PC-1, EXPANSION, OLD PC-2 + ; FE - NEWER PC-2 (64/256K PLANAR) + ; FD - + ; FC - + public Secondary_Model_Byte +Secondary_Model_Byte db 0 +;;End of Modification ----------------------------------------------- + +BOOTBIAS = 200H + EVENB +DiskTable DW 512, 0100h, 64, 0 + DW 2048, 0201h, 112, 0 + DW 8192, 0402h, 256, 0 + DW 32680, 0803h, 512, 0 + DW 65535, 1004h, 1024, 0 + +DiskTable2 DW 32680, 0803h, 512, 0 + DW 65535, 0402h, 512, fBIG + +;;Rev 3.30 Modification ----------------------------------------------- +;************************************************************************* +;Variables for Mini disk initialization +;************************************************************************* +End_Of_BDSM dw ? ;offset value of the ending add + ;of BDSM table. Needed to figure + ;the Final_DOS_Location. +numh db 0 ;number of hard files +mininum db 0 ;logical drive num for mini disk +num_mini_dsk db 0 ;# of mini disk installed +Rom_Minidsk_num db 80h ;physical mini disk number +Mini_HDLIM dw 0 +Mini_SECLIM dw 0 +Mini_BPB_ptr dw 0 ;temporary variable used to save + ;Mini Disk BPB pt add in DskDrvs. +;;End of Modification ----------------------------------------------- + +Bios_Date DB '01/10/84',0 + +; +; The following are the recommended BPBs for the media that we know of so +; far. + +; 48 tpi diskettes + EVENB +BPB48T DW 512 + DB 2 + DW 1 + DB 2 + DW 112 + DW 2*9*40 + DB 0FDH + DW 2 + DW 9 + DW 2 + DD 0 ;hidden sectors - sp + DD 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved + +; 96tpi diskettes + EVENB +BPB96T DW 512 + DB 1 + DW 1 + DB 2 + DW 224 + DW 2*15*80 + DB 0f9H + DW 7 + DW 15 + DW 2 + DD 0 ;hidden sectors - sp + DD 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved + +BPBSIZ = $-BPB96T + +; 3 1/2 inch diskette BPB + EVENB +BPB35 DW 512 + DB 2 + DW 1 ; Double sided with 9 sec/trk + DB 2 + DW 70h + DW 2*9*80 + DB 0f9H + DW 3 + DW 9 + DW 2 + DD 0 ;hidden sectors - sp + DD 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved + + + EVENB +BPBTable dw BPB48T ; 48tpi drives + dw BPB96T ; 96tpi drives + dw BPB35 ; 3.5" drives + ;dw BPB48T ; Not used - 8" drives + ;dw BPB48T ; Not Used - 8" drives + ;dw BPB48T ; Not Used - hard files + ;dw BPB48T ; Not Used - tape drives + ;dw BPB48T ; Not Used - Other + +PatchTable LABEL BYTE + DW 10,media_patch + DW 3,getbp1_patch + DW 3,SET_PATCH + DW 3,DiskIO_Patch + DW 3,DSKErr + DW 10,Changed_Patch + DW 3,INIT_PATCH + DW 0 + + ASSUME DS:NOTHING,ES:NOTHING + +; +; Entry from boot sector. The register contents are: +; DL = INT 13 drive number we booted from +; CH = media byte +; BX = First data sector on disk (0-based) +; +Public INIT +INIT PROC NEAR + MESSAGE FTESTINIT,<"MSBIO",CR,LF> ;3.30 + CLI + XOR AX,AX + MOV DS,AX +; +; Preserve original int 13 vector +; We need to save INT13 in two places in case we are running on an AT. +; On ATs we install the IBM supplied ROM_BIOS patch DISK.OBJ which hooks +; INT13 ahead of ORIG13. Since INT19 must unhook INT13 to point to the +; ROM INT13 routine, we must have that ROM address also stored away. +; + MOV AX,DS:[13h*4] + MOV WORD PTR Old13,AX + MOV WORD PTR Orig13,AX + MOV AX,DS:[13h*4+2] + MOV WORD PTR Old13+2,AX + MOV WORD PTR Orig13+2,AX +; +; Set up INT 13 for new action +; + MOV WORD PTR DS:[13h*4],OFFSET Block13 + MOV DS:[13h*4+2],CS +; +; Preserve original int 19 vector +; + MOV AX,DS:[19h*4] + MOV WORD PTR Orig19,AX + MOV AX,DS:[19h*4+2] + MOV WORD PTR Orig19+2,AX +; +; Set up INT 19 for new action +; + MOV WORD PTR DS:[19h*4],OFFSET int19 + MOV DS:[19h*4+2],CS + STI + + + int 11h ; rom-bios equipment determination + ROL AL,1 ;PUT BITS 6 & 7 INTO BITS 0 & 1 + ROL AL,1 + AND AX,3 ;ONLY LOOK AT BITS 0 & 1 + JNZ NOTSINGLE ;ZERO MEANS SINGLE DRIVE SYSTEM + INC AX ;PRETEND IT'S A TWO DRIVE SYSTEM + INC CS:SINGLE ;REMEMBER THIS +NOTSINGLE: + INC AX ;AX HAS NUMBER OF DRIVES, 2-4 + ;IS ALSO 0 INDEXED BOOT DRIVE IF WE + ; BOOTED OFF HARD FILE + mov CL, AL ; save number of diskette drives in CL + test DL, 80h ; booted from hard disk ? + jnz GotHrd ; yes, jump down + xor AX, AX ; no - indicate boot from drive A +GotHrd: + + ; At this point the registers contain these values: + ; AX = 0-based drive we booted from + ; BX = the logical number of the first data sector on the disk + ; CL = number of floppies including logical one + ; CH = media byte + ; + + Message fTestINIT,<"Init",CR,LF> + +; +; set up local stack +; + xor DX,DX + cli ; turn interrupts off while manupulating stack + mov SS,DX ; set stack segment register + mov SP,700h ; set stack pointer + sti ; turn interrupts on +ASSUME SS:NOTHING + + ; preserve some of the values in registers + + push CX ; save number of floppies and media byte + mov BIOS$,BX ; save first data sector + mov AH,CH ; FAT ID to AH too + push AX ; save boot drive number, and media byte +;;Rev 3.30 Modification ----------------------------------------------- +; Let Model_byte, Secondary_Model_Byte be set here!!! + mov ah,0c0h ; return system environment + int 15h ; call ROM-Bios routine + jc No_Rom_System_Conf ; just use Model_Byte + cmp ah, 0 ; double check + jne No_Rom_System_Conf + mov al, ES:[BX.bios_SD_modelbyte] ;get the model byte + mov [Model_Byte], al + mov al, ES:[BX.bios_SD_scnd_modelbyte] ;secondary model byte + mov [Secondary_Model_Byte], al + jmp short Turn_Timer_On +No_Rom_System_Conf: + MOV SI,0FFFFH ;MJB001 + MOV ES,SI ;MJB001 + MOV AL,ES:[0EH] ; GET MODEL BYTE ARR 2.41 + MOV MODEL_BYTE,AL ; SAVE MODEL BYTE ARR 2.41 +;;End of Modification ----------------------------------------------- +Turn_Timer_On: + mov AL,EOI + out AKPORT,AL ; turn on the timer + + Message fTestINIT,<"COM devices",CR,LF> + +;;Rev 3.30 Modification ----------------------------------------------- + mov si,offset COM4DEV + call AUX_INIT + mov si,offset COM3DEV + call AUX_INIT +;;End of Modification ----------------------------------------------- + mov SI,OFFSET COM2DEV + call AUX_INIT ;INIT COM2 + mov SI,OFFSET COM1DEV + call AUX_INIT ;INIT COM1 + + Message fTestINIT,<"LPT devices",CR,LF> + mov SI,OFFSET LPT3DEV + call PRINT_INIT ;INIT LPT3 + mov SI,OFFSET LPT2DEV + call PRINT_INIT ;INIT LPT2 + mov SI,OFFSET LPT1DEV + call PRINT_INIT ;INIT LPT1 + + xor DX,DX + mov DS,DX ;TO INITIALIZE PRINT SCREEN VECTOR + mov ES,DX + + xor AX,AX + mov DI,INITSPOT + stosw ;INIT four bytes to 0 + stosw + + mov AX,CS ;FETCH SEGMENT + + mov DS:WORD PTR BRKADR,OFFSET CBREAK ;BREAK ENTRY POINT + mov DS:BRKADR+2,AX ;VECTOR FOR BREAK + + mov DS:WORD PTR CHROUT*4,OFFSET WORD PTR OUTCHR + mov DS:WORD PTR CHROUT*4+2,AX + + Message fTestINIT,<"Interrupt vectors",CR,LF> + mov DI,4 + mov BX,OFFSET INTRET ;WILL INITIALIZE REST OF INTERRUPTS + xchg AX,BX + stosw ;Location 4 + xchg AX,BX + stosw ;INT 1 ;Location 6 + add DI,4 + xchg AX,BX + stosw ;Location 12 + xchg AX,BX + stosw ;INT 3 ;Location 14 + xchg AX,BX + stosw ;Location 16 + xchg AX,BX + stosw ;INT 4 ;Location 18 + + mov DS:WORD PTR 500H,DX ;SET PRINT SCREEN & BREAK =0 + mov DS:WORD PTR LSTDRV,DX ;clean out last drive spec + + Message fTestINIT,<"Disk parameter table",CR,LF> + + mov SI,WORD PTR DS:DSKADR ; ARR 2.41 + mov DS,WORD PTR DS:DSKADR+2 ; DS:SI -> current table ARR 2.41 + + mov DI,SEC9 ; ES:DI -> New Table ARR 2.41 + mov CX,SIZE DISK_PARMS ; ARR 2.41 + rep MOVSB ; Copy Table ARR 2.41 + push ES ; ARR 2.41 + pop DS ; DS = 0 ARR 2.41 + + mov WORD PTR DS:DSKADR,SEC9 ; ARR 2.41 + mov WORD PTR DS:DSKADR+2,DS ; Point disk parm vector to new table + ; ARR 2.41 + + +;----------------------------------------------- +; +; THE FOLLOWING DEPEND ON THE TYPE OF MACHINE. +; + CMP MODEL_BYTE,0FDH ; IS THIS AN OLD ROM? ARR 2.41 + JB NO_DIDDLE ; NO ARR 2.41 + MOV WORD PTR DS:(SEC9 + DISK_HEAD_STTL),0200H+NORMSETTLE + ; SET HEAD SETTLE AND MOTOR START + ; ON PC-1 PC-2 PC-XT HAL0 ARR 2.41 + MOV DS:(SEC9 + DISK_SPECIFY_1),0DFH + ; SET 1ST SPECIFY BYTE + ; ON PC-1 PC-2 PC-XT HAL0 ARR 2.41 +NO_DIDDLE: ; ARR 2.41 + int 12h ; call rom-bios for memory size + mov CL, 6 ; get ready for shift + shl AX, CL ; change from K to 16 byte blocks + pop CX ; restore CX + mov DRVFAT, CX + push AX + mov dx,ds:(7C00h + 16h) ; number of sectors/fat from boot sec + xor dh,dh + mov FatLen,DX +; +; Convert sector count to paragraph count:512 bytes / sec / 16 bytes / para +; = 32 para /sector +; +;;Rev 3.30 Modification ----------------------------------------------- + SHL DX,1 + SHL DX,1 + SHL DX,1 + SHL DX,1 + SHL DX,1 +;;End of Modification ----------------------------------------------- + SUB AX,dx ; room for FAT + MOV FatLoc,AX ; location to read fat + POP AX + + MOV DX,SYSINITSEG + MOV DS,DX + + ASSUME DS:SYSINITSEG + + MOV WORD PTR DEVICE_LIST,OFFSET CONHeader + MOV WORD PTR DEVICE_LIST+2,CS + +; Allocation of buffers has moved to SYSINIT - Aug 19/85 BAS + +;DEF_BUFF: + + MOV MEMORY_SIZE,AX + INC CL + MOV DEFAULT_DRIVE,CL ;SAVE DEFAULT DRIVE SPEC + +;DOSSEG = ((((OFFSET END$)-(OFFSET START$))+15)/16)+BIOSEG+SYSIZE + +; BAS DEBUG +;MOV CURRENT_DOS_LOCATION,((((OFFSET END$)-(OFFSET START$))+15)/16)+SYSIZE + MOV AX, OFFSET END$ + SUB AX, OFFSET START$ + ADD AX, 15 + RCR AX, 1 ; DIVIDE BY 16 + SHR AX, 1 + SHR AX, 1 + SHR AX, 1 + ADD AX, SYSIZE + ADD AX, CODE + MOV Current_DOS_Location, AX +; BAS DEBUG +; ADD Current_DOS_Location,CODE + +; +; IMPORTANT: Some old IBM hardware generates spurious INT F's due to bogus +; printer cards. We initialize this value to point to an IRET ONLY IF +; +; 1) The original segment points to storage inside valid RAM. +; +; 2) The original segment is 0F000:xxxx +; +; Theses are capricious requests from our OEM for reasons behind them, read +; the DCR's for the IBM DOS 3.2 project. +; + push ax + +ASSUME ES:SYSINITSEG, DS:NOTHING + mov ax,SYSINITSEG + mov es,ax + xor ax,ax + mov ds,ax + + mov ax,word ptr ds:(0fH*4+2) ; segment for Int 15 + + cmp ax,es:MEMORY_SIZE ; Condition 1 + jna ResetIntF + + cmp ax, 0F000h ; Condition 2 + jne KeepIntF + +ResetIntF: + mov word ptr ds:[0FH*4],offset INTRET + mov word ptr ds:[0FH*4+2],cs + +KeepIntF: + pop ax +; +; END IMPORTANT +; + +;************************************************************** +; WILL INITIALIZE THE NUMBER OF DRIVES +; AFTER THE EQUIPMENT CALL (INT 11H) BITS 6&7 WILL TELL +; THE INDICATIONS ARE AS FOLLOWS: +; +; BITS 7 6 DRIVES +; 0 0 1 +; 0 1 2 +; 1 0 3 +; 1 1 4 +;************************************************************** + PUSH CS + POP DS + PUSH CS + POP ES + + ASSUME DS:CODE,ES:CODE + + call CMOS_Clock_Read ;Before doing anything if CMOS clock, + ;then set the system time accordingly. + ;Also, reset the cmos clock rate. + + Message fTestINIT,<"Disk devices",CR,LF> + + XOR SI,SI + MOV WORD PTR [SI],OFFSET HARDDRV ;set up pointer to hdrive + + POP AX ;number of floppies and FAT ID + XOR AH,AH ; Chuck FAT ID byte + MOV HARDNUM,AL ;Remember which drive is hard disk + MOV DRVMAX,AL ;And set initial number of drives + SHL AX,1 ;Two bytes per address + MOV DI,OFFSET DSKDRVS + ADD DI,AX ;Point to hardfile location + MOV SI,OFFSET HDSKTAB + MOVSW ;Two addresses to move + MOVSW + MESSAGE FTESTINIT,<"BEFORE INT 13",CR,LF> + mov DL, 80h ; tell rom bios to look at hard drives + mov AH, 8h ; set command to get drive parameter + int 13h ; call ROM-BIOS to get number of drives + jc ENDDRV ; old, rom therefore no hard disks + mov HNUM, DL ; save number of hard drives in HNUM + +ENDDRV: + Message fTestINIT,<"Setting up BDSs",CR,LF> + +; +; Scan the list of drives to determine their type. We have three flavors of +; diskette drives: +; +; 48tpi drives We do nothing special for them +; 96tpi drives Mark the fact that they have changeline support. +; 3 1/4 drives Mark changeline support and small. +; +; The following code uses registers for certain values: +; DL - Physical Drive +; DS:DI - points to current BDS +; CX - Flag bits for BDS +; DH - Form Factor for the drive (1 - 48tpi, 2 - 96tpi, 3 - 3.5" medium) +; + XOR DL,DL ; start out with drive 0. + push cs + pop ds + ASSUME DS:CODE + MOV EOT,9 + mov di,offset Start_BDS +loop_drive: + cmp dl,drvmax + jb got_more + jmp Done_Drives +got_more: + xor cx,cx ; zero all flags + mov di,word ptr [di].link ; get next BDS + mov dh,ff48tpi ; Set Form Factor to 48 tpi + MOV NUM_CYLN,40 ; 40 TRACKS PER SIDE + + PUSH DS + PUSH DI + PUSH DX + PUSH CX + PUSH ES + + MOV AH, 8h ;GET DRIVE PARAMETERS + INT 13h ;CALL ROM-BIOS + JNC PARMSFROMROM + JMP NOPARMSFROMROM ; GOT AN OLD ROM +PARMSFROMROM: +;If CMOS is bad, it gives ES,AX,BX,CX,DH,DI=0. CY=0. +;In this case, we are going to put bogus informations to BDS table. +;We are going to set CH=39,CL=9,DH=1 to avoid divide overflow when +;they are calculated at the later time. This is just for the Diagnostic +;Diskette which need IO.SYS,MSDOS to boot up before it sets CMOS. +;This should only happen with drive B. + +;;Rev 3.30 Modification ----------------------------------------------- + CMP CH,0 ; if ch=0, then cl,dh=0 too. + JNE PFR_OK + MOV CH,39 ; ROM gave wrong info. + MOV CL,9 ; Let's default to 360K. + MOV DH,1 +PFR_OK: + INC DH ; MAKE NUMBER OF HEADS 1-BASED + INC CH ; MAKE NUMBER OF CYLINDERS 1-BASED + MOV NUM_HEADS,DH ; SAVE PARMS RETURNED BY ROM + AND CL,00111111B ; EXTRACT SECTORS/TRACK + MOV SEC_TRK,CL + MOV NUM_CYLN,CH ; ASSUME LESS THAN 256 CYLINDERS!! +; MAKE SURE THAT EOT CONTAINS THE MAX NUM OF SEC/TRK IN SYSTEM OF FLOPPIES + CMP CL,EOT ; MAY SET CARRY + JBE EOT_OK + MOV EOT,CL +EOT_OK: + POP ES + POP CX + POP DX + POP DI + POP DS + +; +; Check for presence of changeline +; + mov AH, 15h ; set command to get DASD type + int 13h ; call ROM-BIOS + JC CHANGELINE_DONE + CMP AH,02 ; CHECK FOR PRESENCE OF CHANGELINE + JNE CHANGELINE_DONE +;;End of Modification ----------------------------------------------- +; +; We have a drive with change line support. +; + Message fTestINIT,<"96tpi devices",CR,LF> + + or CL,fChangeLine ; signal type + mov fHave96,1 ; Remember that we have 96tpi disks +; ;3.30 +; WE NOW TRY TO SET UP THE FORM FACTOR FOR THE TYPES OF MEDIA THAT WE KNOW;3.30 +; AND CAN RECOGNISE. FOR THE REST, WE SET THE FORM FACTOR AS "OTHER". ;3.30 +; ;3.30 +CHANGELINE_DONE: ;3.30 +; 40 CYLINDERS AND 9 OR LESS SEC/TRK, TREAT AS 48 TPI MEDIUM. ;3.30 + CMP NUM_CYLN,40 ;3.30 + JNZ TRY_80 ;3.30 + CMP SEC_TRK,9 ;3.30 + JBE GOT_FF ;3.30 +GOTOTHER: ;3.30 + MOV DH,FFOTHER ; WE HAVE A "STRANGE" MEDIUM ;3.30 + JMP SHORT GOT_FF ;3.30 + ;3.30 +; ;3.30 +; 80 CYLINDERS AND 9 SECTORS/TRACK => 720 KB DEVICE ;3.30 +; 80 CYLINDERS AND 15 SEC/TRK => 96 TPI MEDIUM ;3.30 +; ;3.30 +TRY_80: ;3.30 + CMP NUM_CYLN,80 ;3.30 + JNZ GOTOTHER ;3.30 + CMP SEC_TRK,15 ;3.30 + JZ GOT96 ;3.30 + CMP SEC_TRK,9 ;3.30 + JNZ GOTOTHER ;3.30 + MOV DH,FFSMALL ;3.30 + JMP SHORT GOT_FF ;3.30 + ;3.30 +GOT96: ;3.30 + MOV DH,FF96TPI ;3.30 + ;3.30 +GOT_FF: ;3.30 + JMP SHORT NEXTDRIVE ;3.30 + ;3.30 +; AN OLD ROM, SO WE EITHER HAVE A 48TPI OR 96TPI DRIVE. IF THE DRIVE ;3.30 +; HAS CHANGELINE, WE ASSUME IT IS A 96TPI, OTHERWISE IT IS A 48TPI. ;3.30 + ;3.30 +NOPARMSFROMROM: ;3.30 + POP ES ;3.30 + POP CX ;3.30 + POP DX ;3.30 + POP DI ;3.30 + POP DS ;3.30 + ;3.30 + MOV AH, 15h ; SET COMMAND TO GET DASD TYPE ;3.30 + INT 13h ; CALL ROM-BIOS ;3.30 + JC NEXTDRIVE ;3.30 + CMP AH,2 ; IS THERE CHANGELINE? ;3.30 + JNZ NEXTDRIVE ;3.30 + OR CL,FCHANGELINE ;3.30 + MOV FHAVE96,1 ; REMEMBER WE HAVE 96TPI DRIVES ;3.30 + MOV NUM_CYLN,80 ;3.30 + MOV DH,FF96TPI ;3.30 + MOV AL,15 ; SET EOT IF NECESSARY ;3.30 + CMP AL, EOT ;3.30 + JBE EOT_OK2 ;3.30 + MOV EOT,AL ;3.30 +EOT_OK2: ;3.30 + +NextDrive: + or cl,fI_Own_Physical ; set this true for all drives + mov bh,dl ;save Int13 drive number +; +; We need to do special things if we have a single drive system and are setting +; up a logical drive. It needs to have the same Int13 drive number as its +; counterpart, but the next drive letter. Also reset ownership flag. +; We detect the presence of this situation by examining the flag SINGLE for the +; value 2. +; + cmp single,2 + jnz Not_Special + dec bh ; Int13 drive number same for logical drive + xor cl,fI_Own_Physical ; reset ownership flag for logical drive +Not_Special: +; The values that we put in for RHdlim and RSeclim will only remain if the +; form factor is of type "ffOther". + xor ax,ax ; fill BDS for drive + mov al,num_heads + mov word ptr [di].RHdlim,ax + mov al,sec_trk + mov word ptr [di].RSeclim,ax + mov word ptr [di].flags,cx + mov byte ptr [di].FormFactor,dh + mov byte ptr [di].DriveLet,dl + mov byte ptr [di].DriveNum,bh + MOV BL,BYTE PTR NUM_CYLN ;3.30 + mov byte ptr [di].cCyln,bl ; only the l.s. byte is set here + cmp single,1 ; Special case for single drive system + jnz No_Single + message fTestINIT,<"Single Drive System",CR,LF> + ; Don't forget we have + mov single,2 ; single drive system + or cx,fI_Am_Mult ; set that this is one of + ; several drives + or word ptr [di].flags,cx ; save flags + mov di,word ptr [di].link ; move to next BDS in list + inc dl ; add a number + jmp short NextDrive ; Use same info for BDS as previous + + + +No_Single: + inc dl + jmp loop_drive + +Done_Drives: + mov ax,-1 ; Signify end of list by + mov word ptr [di].link,ax ; setting pointer to -1 +; +; Set up all the hard drives in the system +; +DoHard: + MNUM fTestINIT+fTestHARD,AX + Message fTestINIT+fTestHARD,<" Hard disk(s) to initialize",CR,LF> + Message fTestINIT+fTestHARD,<"Hard disk 1",CR,LF> + + CMP HNUM,0 ; IF (No_Hard_files) + JLE STATIC_CONFIGURE ; THEN EXIT TO CONFIGURE ;3.30 + mov DL, 80h ; set first hard file number + mov di,offset BDSH ; Set up first hard file. + mov bl,HARDNUM + call SETHARD + jnc HardFile1_OK + + dec HNUM ; First hard file is bad. + cmp HNUM,0 ; IF (Second_Hard_File) + jg Second_Hard ; THEN Set up second hard file + JMP SHORT STATIC_CONFIGURE ;3.30 + +HardFile1_OK: + call Install_BDS ; install BDS into linked list + cmp HNUM,2 ; IF (Only_one_hardfile) + jb SetIt ; THEN SetIt "in place" + + mov bl,HARDNUM + inc BL ; next drive letter + mov di,offset BDSX + +Second_Hard: ; SETUP Second Hard FILE + + Message fTestINIT+fTestHARD,<"Hard disk 2",CR,LF> + mov DL, 81h ; set second hard file number + call SETHARD + jnc HardFile2_OK + dec HNUM + jmp short SetIt + +HardFile2_OK: + Call Install_BDS + +SETIT: + mov al,HNUM + or al,al + JZ STATIC_CONFIGURE ;3.30 + add al,HARDNUM + mov DRVMAX,al + +; End of physical drive initialization. ;3.30 +; *** Do not change the position of the following statement. +; *** DoMini routine will use [DRVMAX] value for the start of the logical ;3.30 +; *** drive number of Mini disk(s). ;3.30 + ;3.30 + call DoMini ;For setting up mini disks, if found -;3.30 + +; End of drive initialization. + +;9/24/86 We now decide, based on the configurations available so far,;3.30 +;what code or data we need to keep as a stay resident code. The following;3.30 +;table shows the configurations under consideration. They are listed in ;3.30 +;the order of their current position memory. ;3.30 +;Configuration will be done in two ways: ;3.30 +;First, we are going to set "Static configuration". Static configuration ;3.30 +;will consider from basic configuration to ENDOF96TPI configuration. ;3.30 +;The result of static configuration will be the address the Dynamic ;3.30 +;configuration will use to start with. ;3.30 +;Secondly, "Dynamic cofiguration" will be performed. Dynamic configuration;3.30 +;involves possible relocation of CODE/DATA. Dynamic configuration routine ;3.30 +;will take care of BDSM tables and AT ROM Fix module thru K09 suspend/res ;3.30 +;code individually. After these operation, FINAL_DOS_LOCATION will be set.;3.30 +;This will be the place SYSINIT routine will relocate MSDOS module. ;3.30 +; ;3.30 +; 1. BASIC CONFIGURATION FOR MSBIO (EndFloppy, EndSwap) ;3.30 +; 2. ENDONEHARD ;3.30 +; 3. ENDTWOHARD ;3.30 +; 4. END96TPI ;a system that supports "Change Line Error" ;3.30 +; 5. End of BDSM ;BDSM tables for mini disks. ;3.30 +; 6. ENDATROM ;Some of AT ROM fix module. ;3.30 +; 7. ENDCMOSCLOCKSET;Supporting program for CMOS clock write. ;3.30 +; 8. ENDK09 ;K09 CMOS Clock module to handle SUSPEND/RESUME ;3.30 +; ;3.30 +;9/24/86. ;3.30 + ;3.30 +; *** For mini disk configuration. 4/7/86 ;3.30 +; *** END_OF_BDSM will contain the ending address(off) of BDSM table for ;3.30 +; *** mini disks which is located right after the label END96TPI. ;3.30 +; *** The variable NUM_MINI_DSK will indicate the existance. 4/7/86 ;3.30 + ;3.30 + ;3.30 +STATIC_CONFIGURE: ;3.30 + ;3.30 + ;3.30 + PUSH AX ;3.30 + mov ax, offset END96TPI ;let's start with the biggest one.;3.30 + cmp fHave96, 0 ;Is change line support there? ;3.30 + jnz Config96 ;Yes. ;3.30 + ;3.30 + mov ax, offset ENDTWOHARD ;3.30 + cmp HNUM, 1 ;1 hard file? ;3.30 + jbe No_Two_HRD ;3.30 + jmp ConfigTwoHard ;3.30 +No_Two_HRD: ;3.30 + mov ax, offset ENDONEHARD ;3.30 + jnz Basic_Floppy ;3.30 + jmp ConfigOneHard ;3.30 +Basic_Floppy: ;3.30 + mov ax, offset ENDFLOPPY ;3.30 + jmp Dynamic_Configure ;static configuration is done! ;3.30 + +; +; Keep the 96tpi code +; +Config96: +; +; Save old INT 13 vector +; + PUSH AX + PUSH DS + XOR AX,AX + MOV DS,AX + ASSUME DS:NOTHING ;3.30 + MOV AX,DS:[4 * 13h] + MOV WORD PTR CS:Real13,AX + MOV AX,DS:[4 * 13h+2] + MOV WORD PTR CS:Real13+2,AX +; +; Insert new vector +; + MOV WORD PTR DS:[4 * 13h],OFFSET INT13 + MOV DS:[4 * 13h + 2],CS + POP DS + ASSUME DS:CODE ;3.30 + POP AX +; +; Keep two hard disk BPBs +; +ConfigTwoHard: +; +; Keep one hard disk BPB +; +ConfigOneHard: +; +; Adjust the number of drives to include the hard disks. +; + PUSH AX + MOV AL,HardNum + ADD AL,HNum + add al, num_mini_dsk ;4/7/86 for mini disks installed ;3.30 + ;if not installed, then num_mini_dsk = 0. ;3.30 + MOV DrvMax,AL + POP AX + +DYNAMIC_CONFIGURE: ;3.30 + call Get_Para_Offset ;For dynamic allocation, we are ;3.30 + ;going to use offset address that ;3.30 + ;is in paragraph boundary. ;3.30 + push cs ;3.30 + pop es ;es -> code ;3.30 + assume es:code ;3.30 + cld ;clear direction ;3.30 + ;3.30 + cmp [num_mini_dsk], 0 ;Mini disk(s) installed ? ;3.30 + jz CheckATROM ;No. ;3.30 + mov ax, End_Of_BDSM ;set the new ending address ;3.30 + call Get_Para_Offset ;3.30 +CheckATROM: ;3.30 + cmp Model_Byte, 0FCh ;AT ? ;3.30 + jnz CheckCMOSClock ;3.30 + cmp HNUM, 0 ;No hard file? ;3.30 + jz CheckCMOSClock ;3.30 + mov si, 0F000h ;3.30 + mov es, si ;ES -> BIOS segment ;3.30 + assume es:nothing ;3.30 + mov si, offset BIOS_DATE ;3.30 + mov di, 0FFF5H ;ROM BIOS string is at F000:FFF5 ;3.30 +Cmpbyte: ;Only patch ROM for bios 01/10/84 ;3.30 + cmpsb ;3.30 + jnz CheckCMOSClock ;3.30 + cmp byte ptr [si-1],0 ;3.30 + jnz Cmpbyte ;3.30 + ;3.30 +SetRomCode: ;Now we have to install ROM fix ;3.30 + ;AX is the address to move. ;3.30 + push cs ;3.30 + pop es ;set ES to CODE seg ;3.30 + assume es:code ;3.30 + mov word ptr ORIG13, ax ;3.30 + mov word ptr ORIG13+2, cs ;set new ROM bios int 13 vector ;3.30 + mov cx, offset ENDATROM ;3.30 + mov si, offset IBM_DISK_IO ;3.30 + sub cx, si ;size of AT ROM FIX module ;3.30 + mov di, ax ;destination ;3.30 + rep movsb ;relocate it ;3.30 + mov ax, di ;new ending address ;3.30 + call Get_Para_Offset ;in AX ;3.30 + ;3.30 +CheckCMOSClock: ;3.30 + push cs ;3.30 + pop es ;set ES to CODE seg ;3.30 + assume es:code ;3.30 + cmp HaveCMOSClock, 1 ;CMOS Clock exists? ;3.30 + jne CheckK09 ;3.30 + mov DaycntToDay, ax ;set the address for MSCLOCK ;3.30 + mov cx, offset EndDaycntToDay ;3.30 + mov si, offset Daycnt_To_Day ;3.30 + sub cx, si ;size of CMOS clock sup routine ;3.30 + mov di, ax ;3.30 + rep movsb ;3.30 + mov ax, di ;3.30 + call Get_Para_Offset ;3.30 + mov BinToBCD, ax ;set the address for MSCLOCK ;3.30 + mov cx, offset EndCMOSClockSet ;3.30 + mov si, offset Bin_To_BCD ;3.30 + sub cx, si ;3.30 + mov di, ax ;3.30 + rep movsb ;3.30 + mov ax, di ;3.30 + call Get_Para_Offset ;3.30 + ;3.30 +CheckK09: ;3.30 + push ax ;save ax ;3.30* + mov ax,4100h ;Q: is it a K09 ;3.30* + mov bl,0 ; ;3.30* + int 15h ; ;3.30* + pop ax ;3.30 + jc CONFIGDONE ;3.30 + ;3.30 + mov si, offset INT6C ;3.30 + mov cx, offset ENDK09 ;3.30 + sub cx, si ;size of K09 routine ;3.30 + mov di, ax ;3.30 + push di ;save destination ;3.30 + rep movsb ;3.30 + mov ax, di ; ;3.30 + call Get_Para_Offset ;AX = new ending address ;3.30 + pop di ;3.30 + ;3.30 + push ax ;3.30 + push ds ;3.30 + mov fHaveK09, 1 ;remember we have a K09 type ;3.30 + xor ax,ax ;3.30 + mov ds, ax ;3.30 + assume ds:nothing ;3.30 + ;3.30 + mov word ptr ds:[4 * 6Ch], di ;new INT 6Ch handler ;3.30 + mov ds:[4 * 6Ch +2], cs ;3.30 + ;3.30 + pop ds ;3.30 + assume ds:code ;3.30 + pop ax ;restore the ending address ;3.30 + +; +; Set up config stuff for SYSINIT +; +ConfigDone: + MOV DX,SYSINITSEG + MOV DS,DX + ASSUME DS:SYSINITSEG + SUB AX,OFFSET START$ ;3.30 + ADD AX,15 + RCR AX,1 + SHR AX, 1 + SHR AX, 1 + SHR AX, 1 + MOV FINAL_DOS_LOCATION, AX + POP AX + +GOINIT: + ADD Final_DOS_Location,CODE + Message fTestINIT,<"Final DOS location is "> + MNUM fTestINIT,Final_DOS_Location + Message fTestINIT, + PUSH CS + POP DS + + ASSUME DS:CODE,ES:NOTHING + + CMP BYTE PTR fHave96,0 + JNZ ReadDos + call purge_96tpi ;mjb001 eliminate calls to 96tpi hoohah + +ReadDos: + Message fTestINIT,<"Load FAT",CR,LF> + mov ax,DRVFAT ; Get drive and FAT ID + call SetDrive ; Get BDS for drive + call GetBP ; Ensure valid BPB is present + call GETFAT ; Read in the FAT sector + xor DI,DI + mov AL,ES:[DI] ; Get fat id byte + mov BYTE PTR DRVFAT+1,AL ; Save FAT byte + mov AX,DRVFAT + Message fTestINIT,<"FATID read "> + mnum ftestinit,ax + message ftestinit, + call SETDRIVE ; Get Correct BDS for this drive + mov BL,[DI].FatSiz ; get size of fat on media + mov fBigFat,BL + mov CL,[DI].SecPerClus ; get sectors/cluster + mov AX,[DI].HIDSEC ; get number of hidden sectors + sub BIOS$,AX ; subtract hidden sector offset + xor CH,CH ; CX = sectors/cluster +; +; THE BOOT PROGRAM HAS LEFT THE DIRECTORY AT 0:500 +; + PUSH DS + XOR DI,DI + MOV DS,DI ; ES:DI POINTS TO LOAD LOCATION + MOV BX,DS:WORD PTR [53AH] ; clus=*53A; + POP DS ; + Message fTestINIT,<"Load DOS",CR,LF> +; BAS DEBUG +;LOADIT: MOV AX,((((OFFSET END$)-(OFFSET START$))+15)/16)+SYSIZE +LOADIT: + MOV AX, OFFSET END$ ;3.30 + SUB AX, OFFSET START$ ;3.30 + ADD AX, 15 + RCR AX, 1 ; DIVIDE BY 16 + SHR AX, 1 + SHR AX, 1 + SHR AX, 1 + ADD AX, SYSIZE + + ADD AX,CODE + + MOV ES,AX ; + CALL GETCLUS ; clus = GetClus (clus); + +IsEof: + TEST fBigFat,fBIG ; if (fBigFAT) + JNZ EOFBig + Message fTestINIT, + CMP BX,0FF7h ; return (clus > 0ff7h); + JMP SHORT ISEOFX ;3.30 +EOFBig: + Message fTestINIT, + CMP BX,0FFF7h ; else +ISEOFX: ;3.30 + JB LOADIT ; } WHILE (!ISEOF (CLUS)); ;3.30 + ;3.30 + CALL SETDRVPARMS ;3.30 + ;3.30 + MESSAGE FTESTINIT,<"SYSINIT",CR,LF> ;3.30 + ZWAIT ;3.30 + MESSAGE FTESTINIT,<"ON TO SYSINIT...",CR,LF> ;3.30 + JMP SYSINIT ;3.30 + ;3.30 +INIT ENDP ;3.30 + ;3.30 +;**************************** ;3.30 + ;3.30 +Get_Para_Offset proc near ;3.30 +;in: AX - offset value ;3.30 +;out: AX - offset value adjusted for the next paragraph boundary. ;3.30 + add ax, 15 ;make a paragraph ;3.30 + rcr ax, 1 ;3.30 + shr ax, 1 ;3.30 + shr ax, 1 ;3.30 + shr ax, 1 ;3.30 + shl ax, 1 ;now, make it back to offset value ;3.30 + shl ax, 1 ;3.30 + shl ax, 1 ;3.30 + shl ax, 1 ;3.30 + ret ;3.30 +Get_Para_Offset endp ;3.30 + +; +; READ A FAT SECTOR INTO fat location +; +GETFAT PROC NEAR ;3.30 + XOR DI,DI ; offset + MOV DX,1 ; relative sector (1st sector of fat) + MOV CX,FatLen ; read entire fat. + MOV AX,FatLoc ; + MOV ES,AX ; location to read + MOV AX,DRVFAT ; AH FAT ID byte, AL drive + JMP DISKRD +GETFAT ENDP ;3.30 + + +; +; READ A BOOT RECORD INTO 7C0:BootBias +; GetBoot reads the boot record into 7C0:BootBias +; On Entry: +; DL contains ROM drive number (80 or 81) +; On Exit: +; if carry set error +; if carry clear: +; ES:BX piont to boot sector +; AX and CX are not preserved +; BX and ES are used to return values +; +GETBOOT PROC NEAR + mov AX, 07C0h ; prepare to load ES + mov ES, AX ; load ES segment register + mov BX, BootBias ; load BX, ES:BX is where sector goes + mov AX, 0201h ; command to read & num sec. to 1 + xor DH, DH ; head number zero + mov CX, 0001h ; cylinder zero and sector one + int 13h ; call rom bios + jc ERRET + cmp WORD PTR ES:[BootBias+1FEH],0AA55H ; DAVE LITTON MAGIC BYTE? + jz Norm_Ret + message ftesthard,<"Signature AA55 not found",cr,lf> +ERRET: + message ftesthard,<"Error in Getboot",cr,lf> + STC +Norm_Ret: + RET +GETBOOT ENDP ;3.30 +; +; SetHard - generate BPB for a variable sized hard file. IBM has a +; partitioned hard file; we must read physical sector 0 to determine where +; our own logical sectors start. We also read in our boot sector to +; determine version number +; +; Inputs: DL is ROM drive number (80 OR 81) +; DS:DI points to BDS +; Outputs: Carry clear -> BPB is filled in +; Carry set -> BPB is left uninitialized due to error +; + +SETHARD PROC NEAR ;3.30 + push di + push bx + push ds + mov byte ptr [di].DriveLet,bl + mov byte ptr [di].DriveNum,dl + xor ax,ax + or al,fNon_Removable + or word ptr [di].flags,ax + mov byte ptr [di].FormFactor,ffHardFile + MOV fBigFat,0 ; Assume 12 bit FAT + PUSH DX + + mov AH, 8 ; set command to get drive parameters + int 13h ; call rom-bios disk routine + + ; DH is number of heads-1 + ; DL is number of hard disks attached + ; Low 6 bits of CL is sectors/track + ; High 2 bits of CL with CH are max # of cylinders + INC DH ; get number of heads + MOV BYTE PTR [DI].HDLIM,DH + POP DX + JC SETRET ; carry here means no hard disk + AND CL,3FH ; extract number of sectors/track + MOV BYTE PTR [DI].SECLIM,CL + CALL GETBOOT ; if (getBoot ()) + JC SETRET ; return -1; + MOV BX,1C2H+BootBias ; p = &boot[0x1C2]; +SET1: + CMP BYTE PTR ES:[BX],1 ; while (p->PartitionType != 1 && + JZ SET2 + CMP Byte Ptr ES:[BX],4 ; p->PartitionType != 4) { + JZ Set2 + ADD BX,16 ; p += sizeof Partition; + CMP BX,202H+BootBias ; if (p == &boot[0x202h]) + JNZ SET1 ; return -1; +SETRET: + STC ; } + jmp Ret_Hard + +SET2: + PUSH DX + MOV AX,WORD PTR ES:[BX+4] + MOV DX,WORD PTR ES:[BX+6] + +;Decrement the sector count by 1 to make it zero based. Exactly 64k ;3.30 +;sectors should be allowed ;3.30 +; ;3.30 + SUB AX,1 ; PTM 901 12/12/86 MT ;3.30 + SBB DX,0 ; PTM 901 12/12/86 MT ;3.30 + + ADD AX,WORD PTR ES:[BX+8] + ADC DX,WORD PTR ES:[BX+10] + JZ OKDrive + Message fTestHard,<"Partition invalid",CR,LF> + OR fBigFat,fTOOBIG +OKDrive: + POP DX + MOV AX,WORD PTR ES:[BX+4] + MOV [DI].HIDSEC,AX ; BPB->HidSecCt = p->PartitionBegin; + MOV AX,WORD PTR ES:[BX+8] + CMP AX,64 ; if (p->PartitionLength < 64) + JB SETRET ; return -1; + + MOV WORD PTR [DI].DRVLIM,AX ; BPB->MaxSec = p->PartitionLength; + PUSH AX + + PUSH DX + MOV AX,[DI].HidSec ; boot sector number + XOR DX,DX + MOV BH,DH + MOV BL,byte ptr [DI].SecLim + DIV BX + MOV CL,DL ; CL is sector number + INC CL ; sectors are 1 based + CWD + MOV BL,byte ptr [DI].HdLim + DIV BX ; DL is head, AX is cylinder +; +; DL is head. +; AX is cylinder +; CL is sector number +; TOS is drive +; + +;*** For Mini Disks *** 4/7/86 ;3.30 + cmp word ptr [di].IsMini, 1 ;check for mini disk - 4/7/86 ;3.30 + jnz OKnotMini ;not mini disk. - 4/7/86 ;3.30 + add ax, [di].hidden_trks ;set phy track num - 4/7/86 ;3.30 +OKnotMini: ; 4/7/86 ;3.30 +;*** End of added logic for mini disk ;3.30 + + ROR AH,1 ; move high two bits of cyl to high + ROR AH,1 ; two bits of upper byte + AND AH,0C0h ; turn off remainder of bits + OR CL,AH ; move two bits to correct spot + MOV CH,AL ; CH is Cylinder +; +; CL is sector + 2 high bits of cylinder +; CH is low 8 bits of cylinder +; DL is head +; TOS is drive +; + POP AX ; AL is drive + MOV DH,DL ; DH is head + MOV DL,AL ; DL is drive +; +; CL is sector + 2 high bits of cylinder +; CH is low 8 bits of cylinder +; DH is head +; DL is drive +; + xor BX, BX ; clear BX -- ES:BX points to buffer + mov ax, 0201h ; set command to read one sector + int 13h ; call rom-bios to read sector + pop AX + +; +; ES:[0] points to the boot sector. In theory, (ha ha) the BPB in this thing +; is correct. We can, therefore, pull out all the relevant statistics on the +; media if we recognize the version number. +; + CMP WORD PTR ES:[3], "B" SHL 8 + "I" + JNZ Unknownj + CMP WORD PTR ES:[5], " " SHL 8 + "M" + JNZ Unknownj + CMP WORD PTR ES:[8], "." SHL 8 + "2" + JNZ Try5 + CMP BYTE PTR ES:[10], "0" + JNZ Try5 + Message fTestHard,<"Version 2.0 media",CR,LF> + JMP SHORT CopyBPB +unknownj: + jmp unknown +Try5: + CMP WORD PTR ES:[8],"." SHL 8 + "3" + JNZ Unknownj + cmp byte ptr es:[10],"1" ;do not trust 3.0 boot record. 4/15/86;3.30 + jb unknownj ;if version >= 3.1, then O.K. 4/15/86 ;3.30 + Message ftestHard,<"VERSION 3.1 OR ABOVE MEDIA",CR,LF> + +CopyBPB: +; We have a valid Boot sector. Use the BPB in it to build the +; BPB in BIOS. It is assumed that ONLY SecPerClus, cDIR, and +; cSecFat need to be set (all other values in already). fBigFat +; is also set. + MOV AX,WORD PTR ES:[11+DRVLIM-BytePerSec] ; Total sectors + MNUM fTestHard,AX + Message fTestHard,<" Sec "> + DEC AX ; Subtract # reserved (always 1) + MOV DX,WORD PTR ES:[11+cSecFAT-BytePerSec] ; Sectors for 1 fat + MNUM fTestHard,DX + Message fTestHard,<" Sec/Fat "> + MOV [DI+cSecFAT],DX ; Set in BIOS BPB + SHL DX,1 ; Always 2 FATs + SUB AX,DX ; Sub # FAT sectors + MOV DX,WORD PTR ES:[11+cDIR-BytePerSec] ; # root entries + MOV [DI+cDIR],DX ; Set in BIOS BPB + MNUM fTestHard,DX + Message fTestHard,<" directory entries "> + MOV CL,4 + SHR DX,CL ; Div by 16 ents/sector + SUB AX,DX ; Sub # dir sectors + ; AX now contains the # of data sectors. + MOV CL,BYTE PTR ES:[11+SecPerClus-BytePerSec] ; Sectors per cluster + MOV [DI.SecPerClus],CL ; Set in BIOS BPB + XOR DX,DX + MOV CH,DH + MNUM fTestHard,CX + Message fTestHard,<" SecPerClus",CR,LF> + DIV CX + ; AX now contains the # clusters. + CMP AX,4096-10 ; is this 16-bit fat? + JB GoodRetj ; No + OR fBigFat,fBIG ; 16 bit FAT +GoodRetj: + JMP GoodRet + +Unknown: + Message fTestHard,<"Unknown hard media. Assuming 3.0.",CR,LF> + MOV SI,OFFSET DiskTable2 +Scan: + CMP AX,[SI] + JBE GotParm + ADD SI,4 * 2 + JMP Scan +GotParm: + MOV CL,BYTE PTR [SI+6] + OR fBigFat,CL + MOV CX,[SI+2] + MOV DX,[SI+4] +; +; AX = number of sectors on disk drive +; DX = number of dir entries, +; CH = number of sectors per cluster +; CL = log base 2 of ch +; +; NOW CALCULATE SIZE OF FAT TABLE +; + MNUM fTestHard,AX + Message fTestHard,<" sectors "> + MNUM fTestHard,DX + Message fTestHard,<" directory entries "> + MNUM fTestHard,CX + Message fTestHard,<" SecPerClus|ClusShift"> + MOV WORD PTR cDir[DI],DX ;SAVE NUMBER OF DIR ENTRIES + MOV BYTE PTR SecPerClus[DI],CH ;SAVE SECTORS PER CLUSTER + TEST fBigFAT,fBIG ; if (fBigFat) + JNZ DoBig ; goto DoBig; + Message fTestHard,<" Small fat",CR,LF> + XOR BX,BX + MOV BL,CH + DEC BX + ADD BX,AX + SHR BX,CL ; BX = 1+(BPB->MaxSec+SecPerClus-1)/ + INC BX ; SecPerClus + AND BL,11111110B ; BX &= ~1; (=number of clusters) + MOV SI,BX + SHR BX,1 + ADD BX,SI + ADD BX,511 ; BX += 511 + BX/2 + SHR BH,1 ; BH >>= 1; (=BX/512) + MOV BYTE PTR [DI].cSecFat,BH ;SAVE NUMBER OF FAT SECTORS + JMP SHORT GOODRET ;3.30 +DoBig: + Message fTestHard,<" Big fat",CR,LF> + MOV CL,4 ; 16 (2^4) directory entries per sector + SHR DX,CL ; cSecDir = cDir / 16; + SUB AX,DX ; AX -= cSecDir; AX -= cSecReserved; + DEC AX ; ax = t - r - d + MOV BL,2 + MOV BH,SecPerClus[DI] ; bx = 256 * secperclus + 2 + XOR DX,DX + ADD AX,BX ; ax = t-r-d+256*spc+2 + ADC DX,0 + SUB AX,1 ; ax = t-r-d+256*spc+1 + SBB DX,0 + DIV BX ; cSecFat = ceil((total-dir-res)/ + ; (256*secperclus+2)); + MOV WORD PTR [DI].cSecFat,AX ; number of fat sectors +GoodRet: + MOV BL,fBigFat + MOV [DI].FatSiz,BL ; set size of fat on media + CLC +Ret_Hard: + pop ds + pop bx + pop di + RET +SETHARD ENDP ;3.30 + + +; +; SetDrvParms sets up the recommended BPB in each BDS in the system based on +; the form factor. It is assumed that the BPBs for the various form factors +; are present in the BPBTable. For hard files, the Recommended BPB is the same +; as the BPB on the drive. +; No attempt is made to preserve registers since we are going to jump to +; SYSINIT straight after this routine. +; +SETDRVPARMS PROC NEAR ;3.30 + message ftestinit,<"Setting Drive Parameters",cr,lf> + xor bx,bx + les di,dword ptr cs:[Start_BDS] ; get first BDS in list +Next_BDS: + cmp di,-1 + jnz Do_SetP +Done_SetParms: + RET +Do_SetP: + push es + push di ; preserve pointer to BDS + mov bl,es:[di].FormFactor + cmp bl,ffHardFile + jnz NotHardFF + mov ax,es:[di].DrvLim + push ax + mov ax,word ptr es:[di].hdlim + mul word ptr es:[di].seclim + mov cx,ax ; cx has # sectors per cylinder + pop ax + xor dx,dx ; set up for div + div cx ; div #sec by sec/cyl to get # cyl + or dx,dx + jz No_Cyl_Rnd ; came out even + inc ax ; round up +No_Cyl_Rnd: + mov es:[di].cCyln,ax + message ftestinit,<"Ccyln "> + MNUM ftestinit,AX + message ftestinit, + push es + pop ds + lea si,[di].BytePerSec ; ds:si -> BPB for hard file + jmp short Set_RecBPB +NotHardFF: + push cs + pop ds + cmp bl,ffOther ; Special case "other" type of medium + JNZ NOT_PROCESS_OTHER ;3.30 +Process_Other: + xor dx,dx + mov ax,[di].cCyln + mov bx,[di].RHdlim + mul bx + mov bx,[di].RSeclim + mul bx + mov [di].RDrvlim,ax ; Have the total number of sectors + dec ax + +; New logic to get the sectors/fat area. ;3.30 + ;Fat entry assumed to be 1.5 bytes;3.30 + mov bx, 3 ;3.30 + mul bx ;3.30 + mov bx,2 ;3.30 + div bx ;3.30 + xor dx, dx ;3.30 + mov bx, 512 ;3.30 + div bx ;3.30 + inc ax ;3.30 + +No_Round_Up: + mov [di].RcSecFat,ax + jmp short Go_To_Next_BDS + +NOT_PROCESS_OTHER: ;3.30 + shl bx,1 ; bx is word index into table of BPBs + mov si,offset BPBTable + mov si,word ptr [si+bx] ; get address of BPB +Set_RecBPB: + lea di,[di].RBytePerSec ; es:di -> RecBPB + mov cx,BPBSIZ + REP MOVSB ; MOVE BPBSIZ BYTES ;3.30 +Go_To_Next_BDS: + pop di + pop es ; restore pointer to BDS + mov bx,word ptr es:[di].link+2 + mov di,word ptr es:[di].link + mov es,bx + jmp Next_BDS +SETDRVPARMS ENDP ;3.30 + + +; +; READ CLUSTER SPECIFIED IN BX +; CX = SECTORS PER CLUSTER +; DI = LOAD LOCATION +; +GETCLUS PROC NEAR ;3.30 + PUSH CX + PUSH DI + MOV DOSCNT,CX ;SAVE NUMBER OF SECTORS TO READ + MOV AX,BX + DEC AX + DEC AX + MUL CX ;CONVERT TO LOGICAL SECTOR + ADD AX,BIOS$ ;ADD IN FIRST DATA SECTOR + MOV DX,AX ;DX = FIRST SECTOR TO READ + +GETCL1: + MNUM fTestINIT + Message fTestINIT,<" => "> + ;SI = BX, BX = NEXT ALLOCATION UNIT +; +; GET THE FAT ENTRY AT BX, WHEN FINISHED SI=ENTRY BX +; +UNPACK: + PUSH DS + PUSH BX + MOV SI,FatLoc + TEST fBigFat,fBIG ; if (!fBigFat) { + JNZ Unpack16 + MOV DS,SI + MOV SI,BX + SHR SI,1 + MOV BX,[SI+BX] ; p = fat[clus+clus/2]; + JNC HAVCLUS ; if (clus&1) + SHR BX,1 ; p >>= 4; + SHR BX,1 + SHR BX,1 + SHR BX,1 +HAVCLUS: + AND BX,0FFFH ; oldclus=clus; clus = p & 0xFFF; + JMP SHORT UNPACKX ;3.30 +Unpack16: ; else { + MOV DS,SI + SHL BX,1 ; oldclus = clus; + MOV BX,[BX] ; clus = fat[2*clus]; +UNPACKX: ;3.30 + POP SI ; return; + POP DS + ; } + MNUM fTestINIT + Message fTestINIT,<" "> + SUB SI,BX + CMP SI,-1 ;one apart? + JNZ GETCL2 + ADD DOSCNT,CX + JMP GETCL1 + +GETCL2: + PUSH BX + MOV AX,DRVFAT ;GET DRIVE AND FAT SPEC + MOV CX,DOSCNT + CALL DISKRD ;READ THE CLUSTERS + POP BX + POP DI + MOV AX,DOSCNT ;GET NUMBER OF SECTORS READ + XCHG AH,AL ;MULTIPLY BY 256 + SHL AX,1 ;TIMES 2 EQUAL 512 + ADD DI,AX ;UPDATE LOAD LOCATION + POP CX ;RESTORE SECTORS/CLUSTER + RET +GETCLUS ENDP ; RETURN; ;3.30 + +; +; SI POINTS TO DEVICE HEADER +; +; 4/22/86 - print_init, aux_init is modified to eliminate the ;3.30 +; self-modifying code. ;3.30 + ;3.30 +PRINT_INIT: ;3.30 + call Get_device_number ;3.30 + mov ah,1 ;initalize printer port ;3.30 + int 17h ;call ROM-Bios routine ;3.30 + ret ;3.30 + ;3.30 +AUX_INIT: ;3.30 + call Get_device_number ;3.30 + mov al,RSINIT ;2400,N,1,8 (MSEQU.INC) ;3.30* + mov ah,0 ;initalize AUX port ;3.30* + int 14h ;call ROM-Bios routine ;3.30* + ret ;3.30 + ;3.30 +GET_DEVICE_NUMBER: ;3.30 +;SI -> device header ;3.30 + MOV AL,CS:[SI+13] ;GET DEVICE NUMBER FROM THE NAME ;3.30 + SUB AL,"1" ;3.30 + CBW ;3.30 + MOV DX,AX ;3.30 + RET ;3.30 + +; +; purge_96tpi NOP's calls to 96tpi support. +; +PURGE_96TPI PROC NEAR ;MJB001 ;3.30 + PUSH DS + PUSH ES + + push cs ;mjb001 + pop es ;mjb001 + push cs ;mjb001 + pop ds ;mjb001 + ASSUME DS:CODE,ES:CODE ;3.30 + MOV SI,OFFSET PatchTable +PatchLoop: + LODSW + MOV CX,AX + JCXZ PatchDone + LODSW + MOV DI,AX + MOV AL,90h + REP STOSB + JMP PatchLoop + +PatchDone: + mov di,offset TABLE_PATCH ; ARR 2.42 + MOV AX,OFFSET EXIT + STOSW + STOSW + + POP ES + POP DS + ret ;mjb001 +PURGE_96TPI ENDP ;3.30 + +;Mini disk initialization routine. Called right after DoHard - 4/7/86;3.30 +; DoMini **************************************************************** ;3.30 +; **CS=DS=ES=code ;3.30 +; **DoMini will search for every extended partition in the system, and ;3.30 +; initialize it. ;3.30 +; **BDSM stands for BDS table for Mini disk and located right after the ;3.30 +; label End96Tpi. End_Of_BDSM will have the offset value of the ending ;3.30 +; address of BDSM table. ;3.30 +; **BDSM is the same as usual BDS except that TIM_LO, TIM_HI entries are ;3.30 +; overlapped and used to id mini disk and the number of Hidden_trks. ;3.30 +; Right now, they are called as IsMini, Hidden_Trks respectively. ;3.30 +; **DoMini will use the same routine in SETHARD routine after label SET1 ;3.30 +; to save coding. ;3.30 +; **DRVMAX determined in DoHard routine will be used for the next ;3.30 +; available logical mini disk drive number. ;3.30 +; ;3.30 +; Input: DRVMAX, DSKDRVS ;3.30 +; ;3.30 +; Output: MiniDisk installed. BDSM table established and installed to BDS.;3.30 +; num_mini_dsk - number of mini disks installed in the system. ;3.30 +; End_Of_BDSM - ending offset address of BDSM. ;3.30 +; ;3.30 +; ;3.30 +; Called modules: ;3.30 +; GetBoot, WRMSG, int 13h (AH=8, Rom) ;3.30 +; FIND_MINI_PARTITION (new), Install_BDSM (new), ;3.30 +; SetMini (new, it will use SET1 routine) ;3.30 +; Variables used: End_Of_BDSM, numh, mininum, num_mini_dsk, ;3.30 +; Rom_Minidsk_num, Mini_HDLIM, Mini_SECLIM ;3.30 +; BDSMs, BDSM_type (struc), Start_BDS ;3.30 +;************************************************************************ ;3.30 +; ;3.30 + ;3.30 +DoMini: ;3.30 + Message fTestHard,<"Start of DoMini...",cr,lf> ;3.30 + ;3.30 + push ax ;Do I need to do this? ;3.30 + ;3.30 + mov di, offset BDSMs ;from now on, DI points to BDSM ;3.30 + mov dl, 80h ;look at first hard drive ;3.30* + mov ah, 8h ;get drive parameters ;3.30* + int 13h ;call ROM-Bios ;3.30* + cmp dl, 0 ;3.30 + jz DoMiniRet ;no hard file? Then exit. ;3.30 + mov numh, dl ;save the number of hard files. ;3.30 + xor ax,ax ;3.30 + mov al, drvmax ;3.30 + mov mininum, al ;this will be logical drive letter;3.30 + ;for mini disk to start with. ;3.30 + ;3.30 + shl ax, 1 ;ax=number of devices. word bndry ;3.30 + push bx ;3.30 + mov bx, offset DSKDRVS ;3.30 + add bx, ax ;3.30 + mov Mini_BPB_ptr, BX ;Mini_BPB_ptr points to first avlb;3.30 + ;spot in DskDrvs for Mini disk ;3.30 + ;which points to BPB area of BDSM.;3.30 + pop bx ;3.30 + ;3.30 + mov Rom_Minidsk_num, 80h ;3.30 +DoMiniBegin: ;3.30 + inc dh ;Get # of heads (conv to 1 based) ;3.30 + xor ax, ax ;3.30 + mov al, dh ;3.30 + mov Mini_HDLIM, ax ;save it. ;3.30 + xor ax, ax ;3.30 + and cl, 3fh ;Get # of sectors/track ;3.30 + mov al, cl ;3.30 + mov Mini_SECLIM, ax ;and save it. ;3.30 + ;3.30 + mov dl, Rom_Minidsk_num ;drive number
;3.30 + call GETBOOT ;rd master boot rec 7c0:BootBias ;3.30 + jc DoMiniNext ;3.30 + call FIND_MINI_PARTITION ;3.30 +DoMiniNext: ;3.30 + dec numh ;3.30 + jz DoMiniRet ;3.30 + inc Rom_MiniDsk_Num ;Next hard file ;3.30 + mov dl, Rom_MiniDsk_Num ;look at next hard drive ;3.30* + mov ah, 8h ;get drive parameters ;3.30* + int 13h ;call ROM-Bios ;3.30* + jmp DoMiniBegin ;3.30 + ;3.30 +DoMiniRet: ;3.30 + pop ax ;3.30 + ret ;3.30 + ;3.30 + ;3.30 +;Find_Mini_Partition tries to find every Extended partition on a disk. ;3.30 +;At entry: DI -> BDSM entry ;3.30 +; ES:BX -> 07c0:BootBias - Master Boot Record ;3.30 +; Rom_MiniDsk_Num - ROM drive number ;3.30 +; MiniNum - Logical drive number ;3.30 +; Mini_HDLIM, Mini_SECLIM ;3.30 +; ;3.30 +;Called routine: SETMINI which uses SET1 (in SETHARD routine) ;3.30 +;Variables & equates used from orig BIOS - flags, fNon_Removable, fBigfat ;3.30 +; ;3.30 +; ;3.30 +FIND_MINI_PARTITION: ;3.30 + ;3.30 + add bx, 1C2h ;BX -> system id. ;3.30 + ;3.30 +FmpNext: ;3.30 + cmp byte ptr ES:[BX], 5 ; 5 = extended partition ID. ;3.30 + jz FmpGot ;3.30 + add bx, 16 ; for next entry ;3.30 + cmp bx, 202h+BootBias ;3.30 + jnz FmpNext ;3.30 + jmp FmpRet ;not found extended partition ;3.30 + ;3.30 +FmpGot: ;found my partition. ;3.30 + Message ftestHard,<"Found my partition...",cr,lf> ;3.30 + xor ax,ax ;3.30 + or al, fNon_Removable ;3.30 + or word ptr [DI].Flags, ax ;3.30 + mov byte ptr [DI].FormFactor, ffHardFile ;3.30 + mov fBigFat, 0 ;assume 12 bit Fat. ;3.30 + mov ax, Mini_HDLIM ;3.30 + mov [DI].HDLIM, ax ;3.30 + mov ax, Mini_SECLIM ;3.30 + mov [DI].SECLIM, ax ;3.30 + mov al, Rom_MiniDsk_Num ;3.30 + mov [DI].DriveNum, al ;set physical number ;3.30 + mov al, Mininum ;3.30 + mov [DI].DriveLet, al ;set logical number ;3.30 + ;3.30 + cmp word ptr ES:[BX+8], 64 ;**With current BPB, only lower word ;3.30 + ; is meaningful. ;3.30 + je FmpRet ;should be bigger than 64 sectors at least ;3.30 + sub bx, 4 ;let BX point to the start of the entry ;3.30 + mov dh, byte ptr ES:[BX+2] ;3.30 + and dh, 11000000b ;get higher bits of cyl ;3.30 + rol dh, 1 ;3.30 + rol dh, 1 ;3.30 + mov dl, byte ptr ES:[BX+3] ;cyl byte ;3.30 + mov [DI].Hidden_Trks, dx ;set hidden trks ;3.30 +;** Now, read the volume boot record into BootBias. ;3.30 + mov cx,ES:[BX+2] ;cylinder,cylinder/sector ;3.30* + mov dh,ES:[BX+1] ;head ;3.30* + mov dl,Rom_MiniDsk_Num ;drive ;3.30* + mov ax,7c0h ; ;3.30* + mov es,ax ;buffer segment ;3.30* + mov bx,BOOTBIAS ;buffer offset ;3.30* + mov ax,0201h ;read,1 sector ;3.30* + int 13h ;call ROM-Bios routine ;3.30* + jc FmpRet ;cannot continue. ;3.30 + mov bx, 1c2h+BootBias ;3.30 + ;3.30 + call SetMini ;install a mini disk. BX value saved. ;3.30 + jc FmpnextChain ;3.30 + ;3.30 + call Install_BDSM ;install the BDSM into the BDS table ;3.30 +; call Show_Installed_Mini ;show the installed message. 3/35/86 - Don't show messages. ;3.30 + inc mininum ;increase the logical drive number for next ;3.30 + inc num_mini_dsk ;increase the number of mini disk installed. ;3.30 + ;3.30 + push bx ;now, set the DskDrvs pointer to BPB info. ;3.30 + mov bx, Mini_BPB_ptr ;3.30 + lea si, [di].BytePerSec ;points to BPB of BDSM ;3.30 + mov [bx], si ;3.30 + inc Mini_BPB_ptr ;advance to the next address ;3.30 + inc Mini_BPB_ptr ;3.30 + pop bx ;3.30 + ;3.30 + add DI, type BDSM_type ;adjust to the next BDSM table entry. ;3.30 + mov End_OF_BDSM, DI ;set the ending address of BDSM table to this. ;3.30 +; Message fTestHard,<"Mini disk installed.",cr,lf> ;3.30 +FmpnextChain: jmp FmpNext ;let's find out if we have any chained partition ;3.30 +FmpRet: ;3.30 + ret ;3.30 + ;3.30 +SetMini: ;3.30 + push di ;3.30 + push bx ;3.30 + push ds ;3.30 + jmp SET1 ;will be returned to Find mini partition routine. ;3.30 + ;Some logic has been added to SET1 to ;3.30 + ;deal with Mini disks. ;3.30 + ;3.30 +; ;3.30 +;Install BDSM installs a BDSM (pointed by DS:DI) into the end of the current ;3.30 +;linked list of BDS. ;3.30 +;Also, set the current BDSM pointer segment to DS. ;3.30 +;At entry: DS:DI -> BDSM ;3.30 +; ;3.30 +Install_BDSM: ;3.30 + ;3.30 + push ax ;3.30 + push si ;3.30 + push es ;3.30 + ;3.30 + les si, dword ptr cs:Start_BDS ;start of the beginning of list ;3.30 +I_BDSM_Next: ;3.30 + cmp word ptr es:[si], -1 ;end of the list? ;3.30 + jz I_BDSM_New ;3.30 + mov si, word ptr es:[si].link ;3.30 + mov ax, word ptr es:[si].link+2 ;next pointer ;3.30 + mov es, ax ;3.30 + jmp short I_BDSM_Next ;3.30 +I_BDSM_New: ;3.30 + mov ax, ds ;3.30 + mov word ptr ds:[di].link+2, ax ;BDSM segment had not been initialized. ;3.30 + mov word ptr es:[si].link+2, ax ;3.30 + mov word ptr es:[si].link, di ;3.30 + mov word ptr ds:[di].link, -1 ;make sure it is a null ptr. ;3.30 + ;3.30 +I_BDSM_ret: ;3.30 + pop es ;3.30 + pop si ;3.30 + pop ax ;3.30 + ret ;3.30 + ;3.30 +;***The following code is not needed any more. Don't show any ;3.30 +;***messages to be compatible with the behavior of IO.SYS. ;3.30 +;;Show the message "Mini disk installed ..." ;3.30 +;;This routine uses WRMSG procedure which will call OUTCHR. ;3.30 +;Show_Installed_Mini: ;3.30 +; push ax ;3.30 +; push bx ;3.30 +; push ds ;3.30 +; ;3.30 +; mov al, Mininum ;logical drive number ;3.30 +; add al, Drv_Letter_Base ;='A' ;3.30 +; mov Mini_Drv_Let, al ;3.30 +; mov si, offset Installed_Mini ;3.30 +; call WRMSG ;3.30 +; ;3.30 +; pop ds ;3.30 +; pop bx ;3.30 +; pop ax ;3.30 +; ret ;3.30 +;**End of mini disk initialization** ; 4/7/86 ;3.30 + ;3.30 + ;3.30 +CMOS_Clock_Read proc near ;3.30 + ;3.30 +; IN ORDER TO DETERMINE IF THERE IS A CLOCK PRESENT IN THE SYSTEM, THE FOLLOWING ;3.30 +; NEEDS TO BE DONE. ;3.30 + PUSH AX ;3.30 + PUSH CX ;3.30 + PUSH DX ;3.30 + PUSH BP ;3.30 + ;3.30 + XOR BP,BP ;3.30 +LOOP_CLOCK: ;3.30 + XOR CX,CX ;3.30 + XOR DX,DX ;3.30 + MOV AH,2 ;READ REAL TIME CLOCK ;3.30 + INT 1Ah ;CALL ROM-BIOS ROUTINE ;3.30 + CMP CX,0 ;3.30 + JNZ CLOCK_PRESENT ;3.30 + ;3.30 + CMP DX,0 ;3.30 + JNZ CLOCK_PRESENT ;3.30 + ;3.30 + CMP BP,1 ; READ AGAIN AFTER A SLIGHT DELAY, IN CASE CLOCK ;3.30 + JZ NO_READDATE ; WAS AT ZERO SETTING. ;3.30 + ;3.30 + INC BP ; ONLY PERFORM DELAY ONCE. ;3.30 + MOV CX,4000H ;3.30 +DELAY: ;3.30 + LOOP DELAY ;3.30 + JMP LOOP_CLOCK ;3.30 + ;3.30 +CLOCK_PRESENT: ;3.30 + mov cs:HaveCMOSClock, 1 ; Set the flag for cmos clock ;3.30 + ;3.30 + call CMOSCK ; Reset CMOS clock rate that may be ;3.30 + ;possibly destroyed by CP DOS and POST routine did not ;3.30 + ;restore that. ;3.30 + ;3.30 + PUSH SI ;3.30 + MESSAGE FTESTINIT,<"CLOCK DEVICE",CR,LF> ;3.30 + CALL READ_REAL_DATE ;MJB002 READ REAL-TIME CLOCK FOR DATE ;3.30 + ;3.30 + CLI ;MJB002 ;3.30 + MOV DAYCNT,SI ;MJB002 SET SYSTEM DATE ;3.30 + STI ;MJB002 ;3.30 + POP SI ;MJB002 ;3.30 +NO_READDATE: ;3.30 + POP BP ;3.30 + POP DX ;3.30 + POP CX ;3.30 + POP AX ;3.30 + RET ;3.30 + ;3.30 +CMOS_Clock_Read endp ;3.30 +; ;3.30 +; 10/28/86 ;3.30 +; THE FOLLOWING CODE IS WRITTEN BY JACK GULLEY IN ENGINEERING GROUP. ;3.30 +; CP DOS IS CHANGING CMOS CLOCK RATE FOR ITS OWN PURPOSES AND IF THE ;3.30 +; USE COLD BOOT THE SYSTEM TO USE PC DOS WHILE RUNNING CP DOS, THE CMOS ;3.30 +; CLOCK RATE ARE STILL SLOW WHICH SLOW DOWN DISK OPERATIONS OF PC DOS ;3.30 +; WHICH USES CMOS CLOCK. PC DOS IS PUT THIS CODE IN MSINIT TO FIX THIS ;3.30 +; PROBLEM AT THE REQUEST OF CP DOS. ;3.30 +; THE PROGRAM IS MODIFIED TO BE RUN ON MSINIT. Equates are defined in CMOSEQU.INC. ;3.30 +; This program will be called by CMOS_Clock_Read procedure. ;3.30 +; ;3.30 +; The following code CMOSCK is used to insure that the CMOS has not ;3.30 +; had its rate controls left in an invalid state on older AT's. ;3.30 +; ;3.30 +; It checks for an AT model byte "FC" with a submodel type of ;3.30 +; 00, 01, 02, 03 or 06 and resets the periodic interrupt rate ;3.30 +; bits incase POST has not done it. This initilization routine ;3.30 +; is only needed once when DOS loads. It should be ran as soon ;3.30 +; as possible to prevent slow diskette access. ;3.30 +; ;3.30 +; This code exposes one to DOS clearing CMOS setup done by a ;3.30 +; resident program that hides and re-boots the system. ;3.30 +; ;3.30 +CMOSCK PROC NEAR ; CHECK AND RESET RTC RATE BITS ;3.30 + ;3.30 +;Model byte and Submodel byte were already determined in MSINIT. ;3.30 + push ax ;3.30 + cmp cs:Model_byte, 0FCh ;check for PC-AT model byte ;3.30 + ; EXIT IF NOT "FC" FOR A PC-AT ;3.30 + JNE CMOSCK9 ; Exit if not an AT model ;3.30 + ;3.30 + CMP cs:Secondary_Model_Byte,06H ; Is it 06 for the industral AT ;3.30 + JE CMOSCK4 ; Go reset CMOS periodic rate if 06 ;3.30 + CMP cs:Secondary_Model_Byte,04H ; Is it 00, 01, 02, or 03 ;3.30 + JNB CMOSCK9 ; EXIT if problem fixed by POST ;3.30 + ; Also,Secondary_model_byte = 0 when AH=0c0h, int 15h failed. ;3.30 +CMOSCK4: ; RESET THE CMOS PERIODIC RATE ;3.30 + ; Model=FC submodel=00,01,02,03 or 06 ;3.30 + + mov al,CMOS_REG_A or NMI ;NMI disabled on return + mov ah,00100110b ;Set divider & rate selection + call CMOS_WRITE + + + mov al,CMOS_REG_B or NMI ;NMI disabled on return + call CMOS_READ + and al,00000111b ;clear SET,PIE,AIE,UIE,SQWE + mov ah,al + mov al,CMOS_REG_B ;NMI enabled on return + call CMOS_WRITE + +CMOSCK9: ; EXIT ROUTINE ;3.30 + pop ax ;3.30 + RET ; RETurn to caller ;3.30 + ; Flags modifyied ;3.30 +CMOSCK ENDP ;3.30 +PAGE ;3.30 +;--- CMOS_READ ----------------------------------------------------------------- ;3.30 +; READ BYTE FROM CMOS SYSTEM CLOCK CONFIGURATION TABLE : ;3.30 +; : ;3.30 +; INPUT: (AL)= CMOS TABLE ADDRESS TO BE READ : ;3.30 +; BIT 7 = 0 FOR NMI ENABLED AND 1 FOR NMI DISABLED ON EXIT : ;3.30 +; BITS 6-0 = ADDRESS OF TABLE LOCATION TO READ : ;3.30 +; : ;3.30 +; OUTPUT: (AL) VALUE AT LOCATION (AL) MOVED INTO (AL). IF BIT 7 OF (AL) WAS : ;3.30 +; ON THEN NMI LEFT DISABLED. DURING THE CMOS READ BOTH NMI AND : ;3.30 +; NORMAL INTERRUPTS ARE DISABLED TO PROTECT CMOS DATA INTEGRITY. : ;3.30 +; THE CMOS ADDRESS REGISTER IS POINTED TO A DEFAULT VALUE AND : ;3.30 +; THE INTERRUPT FLAG RESTORED TO THE ENTRY STATE ON RETURN. : ;3.30 +; ONLY THE (AL) REGISTER AND THE NMI STATE IS CHANGED. : ;3.30 +;------------------------------------------------------------------------------- ;3.30 + ;3.30 +CMOS_READ PROC NEAR ; READ LOCATION (AL) INTO (AL) ;3.30 + PUSHF ; SAVE INTERRUPT ENABLE STATUS AND FLAGS ;3.30 + + cli + push bx + push ax ;save user NMI state + or al,NMI ;disable NMI for us + out CMOS_PORT,al + nop ;undocumented delay needed + in al,CMOS_DATA ;get data value + + ;set NMI state to user specified + mov bx,ax ;save data value + pop ax ;get user NMI + and al,NMI + or al,CMOS_SHUT_DOWN + out CMOS_PORT,al + nop + in al,CMOS_DATA + + mov ax,bx ;data value + pop bx + + PUSH CS ; *PLACE CODE SEGMENT IN STACK AND ;3.30 + CALL CMOS_POPF ; *HANDLE POPF FOR B- LEVEL 80286 ;3.30 + RET ; RETURN WITH FLAGS RESTORED ;3.30 + ;3.30 +CMOS_READ ENDP ;3.30 + ;3.30 +CMOS_POPF PROC NEAR ; POPF FOR LEVEL B- PARTS ;3.30 + IRET ; RETURN FAR AND RESTORE FLAGS ;3.30 + ;3.30 +CMOS_POPF ENDP ;3.30 + ;3.30 +;--- CMOS_WRITE ---------------------------------------------------------------- ;3.30 +; WRITE BYTE TO CMOS SYSTEM CLOCK CONFIGURATION TABLE : ;3.30 +; : ;3.30 +; INPUT: (AL)= CMOS TABLE ADDRESS TO BE WRITTEN TO : ;3.30 +; BIT 7 = 0 FOR NMI ENABLED AND 1 FOR NMI DISABLED ON EXIT : ;3.30 +; BITS 6-0 = ADDRESS OF TABLE LOCATION TO WRITE : ;3.30 +; (AH)= NEW VALUE TO BE PLACED IN THE ADDRESSED TABLE LOCATION : ;3.30 +; : ;3.30 +; OUTPUT: VALUE IN (AH) PLACED IN LOCATION (AL) WITH NMI LEFT DISABLED : ;3.30 +; IF BIT 7 OF (AL) IS ON. DURING THE CMOS UPDATE BOTH NMI AND : ;3.30 +; NORMAL INTERRUPTS ARE DISABLED TO PROTECT CMOS DATA INTEGRITY. : ;3.30 +; THE CMOS ADDRESS REGISTER IS POINTED TO A DEFAULT VALUE AND : ;3.30 +; THE INTERRUPT FLAG RESTORED TO THE ENTRY STATE ON RETURN. : ;3.30 +; ONLY THE CMOS LOCATION AND THE NMI STATE IS CHANGED. : ;3.30 +;------------------------------------------------------------------------------- ;3.30 + ;3.30 +CMOS_WRITE PROC NEAR ; WRITE (AH) TO LOCATION (AL) ;3.30 + PUSHF ; SAVE INTERRUPT ENABLE STATUS AND FLAGS ;3.30 + PUSH AX ; SAVE WORK REGISTER VALUES ;3.30 + + cli + push ax ;save user NMI state + or al,NMI ;disable NMI for us + out CMOS_PORT,al + nop + mov al,ah + out CMOS_DATA,al ;write data + + ;set NMI state to user specified + pop ax ;get user NMI + and al,NMI + or al,CMOS_SHUT_DOWN + out CMOS_PORT,al + nop + in al,CMOS_DATA + + POP AX ; RESTORE WORK REGISTERS ;3.30 + PUSH CS ; *PLACE CODE SEGMENT IN STACK AND ;3.30 + CALL CMOS_POPF ; *HANDLE POPF FOR B- LEVEL 80286 ;3.30 + RET ;3.30 + ;3.30 +CMOS_WRITE ENDP ;3.30 +; ;3.30 + +END$: +code ends +end diff --git a/SRC/BIOS/MSINIT.OBJ b/SRC/BIOS/MSINIT.OBJ new file mode 100644 index 0000000..62700d6 Binary files /dev/null and b/SRC/BIOS/MSINIT.OBJ differ diff --git a/SRC/BIOS/MSIOCTL.INC b/SRC/BIOS/MSIOCTL.INC new file mode 100644 index 0000000..cc1e8ba --- /dev/null +++ b/SRC/BIOS/MSIOCTL.INC @@ -0,0 +1,1036 @@ + include ioctl.inc + +; +; Generic IOCTL dispatch tables +; +IOReadJumpTable db 2 + dw offset GetDeviceParameters + dw offset ReadTrack + dw offset VerifyTrack + +IOWriteJumpTable db 2 + dw offset SetDeviceParameters + dw offset WriteTrack + dw offset FormatTrack + +MAX_SECTORS_CURR_SUP EQU 63 ; CURRENT MAXIMUM SEC/TRK THAT ;3.30 + ; WE SUPPORT (Was 40 in DOS 3.2) ;3.30 +; +; TrackTable is an area for saving information passwd by the set device +; parameter function for laster use my Read/Write/Format/Verify. +; +; Entries are 4-Tuples (C,H,R,N) where: +; C = Cylinder, H = Head, R = Sector, N = Bytes/Sector +; +; fixed for bug0016 - initialised table with values - sp +TrackTable db 0,0,1,2 + db 0,0,1,2 + db 0,0,3,2 + db 0,0,4,2 + db 0,0,5,2 + db 0,0,6,2 + db 0,0,7,2 + db 0,0,8,2 + db 0,0,9,2 + db 0,0,10,2 + db 0,0,11,2 + db 0,0,12,2 + db 0,0,13,2 + db 0,0,14,2 + db 0,0,15,2 + db MAX_SECTORS_CURR_SUP * size a_SectorTable - ($-tracktable) dup (0) + +sectorsPerTrack dw 15 + + +; This is a real ugly place to put this +; it should really go in the BDS +mediaType db 0 + +Media_Set_For_Format db 0 ; 1 if we have done an Int 13 Set Media + ; Type for Format call +; Rev 3.30 ***************************************************************** +Had_Format_Error db 0 ; 1 if the previous format operation + ; failed. +Dsk_time_out_Err equ 80h ; Time out error (No media present). +Dsk_change_line_Err equ 6h ; Change line error +Dsk_illegal_combination equ 0Ch ; Return code of ah=18h function. +; Rev 3.30 ***************************************************************** + +; +; TempDPT is a temporary place to hold a pointer to the original +; Disk Parameter Table while DPT is made to point to a table returned +; by a BIOS call. A value of -1 indicateds no value has been saved. +; + +TempDPT DD -1 + +; +; Generic$IOCTL: +; Perform Generic IOCTL request +; Input: +; al - unit number +; Output: +; if carry set then al contains error code +; + Public Generic$IOCTL +Generic$IOCTL: + Message ftestdisk,<"Generic IOCTL",cr,lf> + les bx,cs:[PTRSAV] ; es:bx points to request header. + call SetDrive ; ds:di points to BDS for drive. +; +; At this point: +; es:bx - points to the Request Header +; ds:di points to the BDS for the drive +; + cmp es:[bx].MajorFunction, RAWIO + jne IOCTL_Func_Err + mov al, es:[bx].MinorFunction + mov si, offset IOReadJumpTable + test al, GEN_IOCTL_FN_TST ; Test of req. function + jnz NotGenericIoctlWrite ; function is a Read. + mov si, offset IOWriteJumpTable +NotGenericIoctlWrite: + and al, 0fH + cmp al, cs:[si] + ja IOCTL_Func_Err + cbw + shl ax, 1 + inc si + add si,ax + les bx, es:[bx].GenericIOCTL_Packet + call cs:[si] + jc FailGeneric$IOCTL + jmp exit + +FailGeneric$IOCTL: + jmp err$exit + +IOCTL_Func_Err: + jmp CMDERR + + + + + +; +; GetDeviceParameters: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to device parameter packet +; + + PUBLIC GETDEVICEPARAMETERS ;3.30 +GetDeviceParameters proc near +; Copy info from BDS to the device parameters packet + mov al, byte ptr ds:[di].FormFactor + mov byte ptr es:[bx].DP_DeviceType, al + mov ax, word ptr ds:[di].Flags + and ax,fNon_Removable+fChangeline ; mask off other bits + mov word ptr es:[bx].DP_DeviceAttributes, ax + mov ax, word ptr ds:[di].cCyln + mov word ptr es:[bx].DP_Cylinders, ax + +; Set media type to default + xor al, al + mov byte ptr es:[bx].DP_MediaType, al + +; Copy recommended BPB + lea si, byte ptr [di].RBytePerSec + test byte ptr es:[bx].DP_SpecialFunctions, BUILD_DEVICE_BPB + jz use_BPB_present +; Get the correct disk in the drive + call CheckSingle +; Build the BPB from scratch + call GETBP + jc Get_Parm_Ret + lea si,byte ptr [di].BytePerSec +use_BPB_present: + lea di, byte ptr [bx].DP_BPB + mov cx, size BPB_Type ; for now use 'small' BPB + rep movsb + clc +Get_Parm_Ret: + ret +GetDeviceParameters endp + + + + + +; +; SetDeviceParameters: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to device parameter packet +; + + PUBLIC SETDEVICEPARAMETERS ;3.30 +SetDeviceParameters proc near + +; Make sure the fChanged_By_Format flag gets set to kick DOS into looking at +; the BPB + or word ptr ds:[di].Flags, fChanged_By_Format or fChanged + test byte ptr es:[bx].DP_SpecialFunctions, ONLY_SET_TRACKLAYOUT + jz short SetDevParm_1 + jmp SetTrackTable ; Originally TrackLayout + +SetDevParm_1: +; Copy info from the device parameters packet to BDS + mov al, byte ptr es:[bx].DP_DeviceType + mov byte ptr ds:[di].FormFactor, al + + mov ax, word ptr es:[bx].DP_Cylinders + mov word ptr ds:[di].cCyln, ax + +; If change line is not loaded then ignore changeling flag + mov ax, word ptr es:[bx].DP_DeviceAttributes + cmp cs:[fHave96],0 + jnz Have_Change + and ax,not fChangeline +Have_Change: +; ignore all bits except Non_removable and Changeline + and ax,fNon_Removable or fChangeline + mov cx, word ptr ds:[di].Flags + and cx, not (fNon_Removable or fChangeline or GOOD_TRACKLAYOUT) + or ax, cx + mov word ptr ds:[di].Flags, ax + +; Set media type + mov al, byte ptr es:[bx].DP_MediaType + mov cs:mediaType, al +; the media changed (maybe) so we will have to do a SetDASD the next time +; we format a track + or word ptr ds:[di].Flags, SET_DASD_true + + SaveReg +; Figure out what we are supposed to do with the BPB + +; Were we asked to install a fake BPB? + test byte ptr es:[bx].DP_SpecialFunctions, INSTALL_FAKE_BPB + jnz short InstallFakeBPB + +; Were we returning a fake BPB when asked to build a BPB? + test word ptr ds:[di].Flags, RETURN_FAKE_BPB + jz short InstallRecommendedBPB + +; We were returning a fake BPB but we can stop now + and word ptr ds:[di].Flags, not RETURN_FAKE_BPB + jmp DoneWithBPBstuff + +InstallRecommendedBPB: + mov cx, size a_BPB + lea di, byte ptr [di].RBytePerSec + jmp short CopyTheBPB + +InstallFakeBPB: + mov cx, size BPB_Type ; move 'smaller' BPB + lea di, byte ptr [di].BytePerSec +CopyTheBPB: + lea si, byte ptr [bx].DP_BPB +; exchange es and ds + push es + push ds + pop es + pop ds + + rep movsb + +DoneWithBPBstuff: + Call RestoreOldDPT + RestoreReg + +; Set up track table (if neccessary) +SetTrackTable: + mov cx, word ptr es:[bx].DP_TrackTableEntries + mov cs:sectorsPerTrack, cx + and word ptr ds:[di].Flags, not GOOD_TRACKLAYOUT + test byte ptr es:[bx].DP_SpecialFunctions, TRACKLAYOUT_IS_GOOD + jz UglyTrackLayout + or word ptr ds:[di].Flags, GOOD_TRACKLAYOUT + +UglyTrackLayout: + cmp cx, MAX_SECTORS_IN_TRACK + ja TooManySectorsPerTrack + jcxz SectorInfoSaved ; if no value don't copy table + ; save information in the track table + + push BX ; get ES:BX to point to sector + add BX, DP_SectorTable ; table in Device param. struct + + push DI + mov DI, offset TrackTable + 2 ; CS:DI now points to sector id + ; of the first track table entry + push AX ; preserve AX value + + ; For MAX_SECTORS_IN_TRACK +TrackLoop: ; DO: + mov AX, word ptr ES:[BX] ; get sector number + mov byte ptr CS:[DI], AL ; save in track table + + mov AX, word ptr ES:[BX]+2 ; get sector size + call SectorSizeToSectorIndex ; convert size to index number + mov byte ptr CS:[DI]+1, AL ; save size in track table + + add BX, size a_sectorTable ; advance pointers to next + add DI, size a_sectorTable ; entries + loopnz TrackLoop ; End FOR + + pop AX ; restore the saved values + pop DI + pop BX + +SectorInfoSaved: + clc + ret + +TooManySectorsPerTrack: + mov al, 0cH + stc + ret + +SetDeviceParameters endp + + +; +; FormatTrack: +; If SpecialFunction byte is 1, then this is a status call to see if there is +; ROM support for the combination of sec/trk and # of cyln, and if the +; combination is legal. If SpecialFunction byte is 0, then format the track. +; +; Input: DS:DI points to BDS for drive +; ES:BX points to format packet +; +; Output: +; For status call: +; SpecialFunction byte set to: +; 0 - ROM support + legal combination +; 1 - No ROM support +; 2 - Illegal Combination +; 3 - no media present ;Rev 3.30 +; Carry cleared. +; +; For format track: +; Carry set if error +; +; +; Flags also may be altered. All other registers preserved. +; If the call to ROM returns no error, then the current DPT is "replaced" by +; the one returned by the ROM. This is done by changing the pointer in [DPT] +; to the one returned. The original pointer to the disk base table is stored +; in TempDPT, until it is restored. +; +; This proc was changed to force a status for format call if we are on the +; new ROM. +; +; +FormatTrack proc near + test byte ptr es:[bx].DP_SpecialFunctions,Status_For_Format + jz SkipStatusOnly + +Do_Status_Only: + call FormatStatus + mov byte ptr es:[bx].DP_SpecialFunctions,al + ret + +SkipStatusOnly: ; for a hard disk only do the verify + cmp byte ptr ds:[di].FormFactor, DEV_HARDDISK + jnz SkipVerify + jmp DoVerifyTrack +SkipVerify: + SaveReg ; Format a Track + call FormatStatus ; SetDASD checks media_set_for_format + cmp al,3 ; Check for time out + je Format_Failed ; Fail if time out + call SetDASD +; +; Store Cylinder,Head in track table +; ***** ASSUMPTION ******* +; Since format requests on Fixed Media are converted to Verifies, we +; assume that we are formatting a floppy and hence have 255 or less +; tracks and heads. We therefore must change the Cylinder, Head data +; from the Request Packet Size to that of the TrackTable (see Int 13 +; interface in IBM's Tech Ref.). + +; Check to ensure correct disk is in drive + call CheckSingle + + mov ax, word ptr es:[bx].FP_Cylinder + mov word ptr cs:[TRKNUM],ax + mov cx, word ptr es:[bx].FP_Head + mov byte ptr cs:[HDNUM],cl + mov ah,cl + ; this next piece of code copies the correct head + ; and cylinder numbers to the tracktable + push di ; preserve DI + mov di, offset TrackTable + mov CX, cs:SectorsPerTrack ; get number of sectors + jcxz EndSetUpTrackTable ; if nothing to do skip down +SetUpLoop: + mov cs:[di], AX ; set head and track value + add di, 4 ; move to next entry + loopnz SetUpLoop ; loop if not done yet +EndSetUpTrackTable: + pop di ; restore DI (BDS pointer) + mov cx, MAXERR ; Set up retry count +FormatRetry: + push cx + ; set up registers for format call to TO_ROM + mov AX, word ptr CS:SectorsPerTrack ; set number of sectors + mov AH, ROMFormat + push cs ; set ES:BX to point to + pop es ; the track table + mov BX, offset TrackTable + ; don't need to set CL on format + call to_rom + jnc FormatOk + pop cx + mov cs:[Had_Format_Error],1 ; Mark the error + push ax ;3.30 + push cx ;3.30 + push dx ;3.30 + call ResetDisk + call FormatStatus ;3.30 + cmp al, 1 ;3.30 + jnz While_Err ;3.30 + call SetDASD ;3.30 +While_Err: ;3.30 + pop dx ;3.30 + pop cx ;3.30 + pop ax ;3.30 + loop FormatRetry + +; Format failed +Format_Failed: + mov cs:[Had_Format_Error],1 ; Indicate a format error + cmp ah,Dsk_Change_Line_Err ; Convert change line to + jne Map_Err ; to time out. + mov ah,Dsk_Time_Out_Err +Map_Err: + call MapError + RestoreReg + ret + +FormatOk: + mov cs:[Had_Format_Error],0 ; Reset format error flag + pop cx ; clean up stack after bailing out + ; of FormatRetry loop early + RestoreReg + +DoVerifyTrack: + call VerifyTrack ; Will reset DPT entries. + ret + +FormatTrack endp + +; +; FormatStatus: +; If SpecialFunction byte is 1, then this routine is called to see if there is +; ROM support for the combination of sec/trk and # of cyln, and if the +; combination is legal. +; +; Input: DS:DI points to BDS for drive +; ES:BX points to format packet +; +; Output: +; SpecialFunction byte set to: +; 0 - ROM support + legal combination +; 1 - No ROM support +; 2 - Illegal Combination +; 3 - No media present, ROM support exists but can't determine +; media +; Carry cleared. +; +; For format track: +; Carry set if error +; +; +; Flags also may be altered. All other registers preserved. +; If the call to ROM returns no error, then the current DPT is "replaced" by +; the one returned by the ROM. This is done by changing the pointer in [DPT] +; to the one returned. The original pointer to the disk base table is stored +; in TempDPT, until it is restored. +; +; +FormatStatus proc near + SaveReg + cmp cs:[Had_Format_Error],1 ; Are we here because of a format err + je Fstat01 + cmp byte ptr cs:[Media_Set_For_Format],1 + jnz FStat03 + jmp Stat_Ret +Fstat03: + mov byte ptr cs:[Media_Set_For_Format],0 +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; modification - sp001 +; +; remove check for new rom from here. we shall just assume the +; prescence of the new rom and go ahead and issue the int13 call +; anyway. later on if there is an error we shall check this to +; see if it is there because of lack of rom support, in which +; case the appropriate error will be indicated by setting al to 1 +; +; I would ideally like to see the new rom testing code shifted to +; msinit and this code reintroduced. however for this version we +; are aiming to stick close to the IBM variety. +; +; More changes to support this commenting out will follow. All +; will be marked as modification sp001 +; +; mov al,1 ; No ROM support available error code +; test byte ptr cs:[New_ROM],1 +; jnz FStat01 +; jmp Stat_Ret +Fstat01: + SaveReg + + xor ax,ax + mov ds,ax + lds si, dword ptr ds:[DskAdr] ; DS:SI := pDPT + + mov word ptr cs:[DPT],si ; cs:[DPT] := pDPT + mov word ptr cs:[DPT + 2],ds + + RestoreReg + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; modification sp001 +; +; the following instruction introduced for the new rom modification +; + mov cs:[New_Rom],1 ; assume new rom +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + mov ax,word ptr [di].cCyln + mov cx,word ptr [di].Seclim + ; set up registers for format status call + and AH, 03h ; 'and' out unneeded track bits + ror AH, 1 ; get track and sector values correct + ror AH, 1 + or AH, CL ; set sector number + xchg AH, AL + mov CX, AX + dec CH + mov DL, byte ptr [DI].DriveNum ; get drive number + mov AH, 18h ; set command to "sec/trk supported?" + + SaveReg + int 13h ; call rom bios to see if supported + jc Format_Stat_Err ; if carry, combination is not supported + + ; ES:DI points to new Disk Base Table + ; combination for this drive replace + ; current (DskAdr) pointer with new one, + ; saving the old one in TempDPT. + + cmp cs:[Had_Format_Error],1 ; Are we here because of a format err + jnz Fstat02 ; Then skip the disk base setup + + xor al,al ; Supported and OK + mov cs:[Had_Format_Error],al ; Clear format error + jmp Pop_Stat_Ret ; Back to work + +Fstat02: + xor ax,ax + mov ds,ax + lds si, dword ptr ds:[DskAdr] ; DS:SI := pDPT + + mov word ptr cs:[TempDPT],si + mov word ptr cs:[TempDPT + 2],ds ; Save pDPT + + mov word ptr ds:[DskAdr],DI ; Setup New DPT returned by + mov word ptr ds:[DskAdr + 2],ES ; ROM + + mov byte ptr cs:[Media_Set_For_Format],1 ; set flag + xor al,al ; Legal combination + ROM support code + jmp short Pop_Stat_Ret + +Format_Stat_Err: + mov al,3 ; Assume a time out + cmp ah,Dsk_Time_Out_Err ; Was it a time out??? + jz Pop_Stat_Ret ; Yes - then done + dec al ; Assume an illegal comb. + cmp ah,Dsk_illegal_combination ; Was it an illegal comb??? + jz Pop_Stat_Ret ; Yes - then done + dec al ; Assume No ROM Support +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; modification sp001 +; +; the following instruction was introduced for the new_rom modification +; + mov cs:[New_Rom],0 ; the old rom +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Return result of status call +Pop_Stat_Ret: + RestoreReg +Stat_Ret: + clc + RestoreReg + ret +FormatStatus endp + + + +; +; VerifyTrack: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to verify packet +; + PUBLIC VERIFYTRACK ;3.30 +VerifyTrack proc near + mov cs:RFLAG, ROMverify + mov ax, word ptr es:[bx].VP_Cylinder + mov cs:curtrk, ax + mov ax, word ptr es:[bx].VP_Head + +; ****** ASSUMPTION ****** +; we assume that we have less than 256 heads, and that the Request +; Header Data Structure is unneccessarily big + mov cs:curhd, al + xor ax, ax + mov cx, cs:sectorsPerTrack +; Use 0:0 as the transfer address for verify + xor bx, bx + mov es, bx + call TrackIO + ret +VerifyTrack endp + +; +; ReadTrack: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to read packet +; + PUBLIC READTRACK ;3.30 +ReadTrack: + mov cs:RFLAG, ROMread + jmp ReadWriteTrack + +; +; WriteTrack: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to write packet +; + PUBLIC WRITETRACK ;3.30 +WriteTrack: + mov cs:RFLAG, ROMwrite + jmp ReadWriteTrack +; +; ReadWriteTrack: +; +; Input: +; DS:DI points to BDS for drive +; ES:BX points to write packet +; RFLAG - 2 for read, 3 for write +; + PUBLIC READWRITETRACK ;3.30 +ReadWriteTrack proc near + mov ax, word ptr es:[bx].TRWP_Cylinder + mov cs:curtrk, ax + mov ax, word ptr es:[bx].TRWP_Head + +; ****** ASSUMPTION ****** +; we assume that we have less than 256 heads, and that the Request +; Header Data Structure is unneccessarily big + mov cs:curhd, al + mov ax, word ptr es:[bx].TRWP_FirstSector + mov cx, word ptr es:[bx].TRWP_SectorsToReadWrite + les bx, es:[bx].TRWP_TransferAddress + call TrackIO + ret +ReadWriteTrack endp + + +; +; TrackIO: +; Performs Track Read/Write/Verify +; +; Input: +; RFLAG - 2 = Read +; 3 = Write +; 4 = Verify +; ax - Index into track table of first sector to IO +; cx - number of sectors to IO +; es:bx - Transfer address +; ds:di - pointer to BDS +; curtrk - current cylinder +; curhd - current head +; + public trackio +TrackIO proc near +; procedure `disk' will pop stack to SPsav and return if error + mov cs:SPsav, sp +; Ensure correct disk is in drive + call CheckSingle +; +; Set up tables and variables for I/O +; + cmp byte ptr cs:[Media_Set_For_Format],1 + jz DPTAlreadySet + +; ;3.30 +; SET UP TABLES AND VARIABLES FOR I/O ;3.30 +; ;3.30 + SaveReg + call IOSetUp + RestoreReg +; +; point si at the table entry of the first sector to be IO'd +; +DPTAlreadySet: + mov si, offset trackTable + shl ax, 1 + shl ax, 1 + add si, ax +; +; we want: +; cx to be the number of times we have to loop +; dx to be the number of sectors we read on each iteration + mov dx, 1 + test word ptr ds:[di].Flags, GOOD_TRACKLAYOUT + jz IOnextSector + +; Hey! we can read all the sectors in one blow + xchg dx, cx + +IOnextSector: + push cx + push dx +; skip over the cylinder and head in the track table + inc si + inc si + +; Get sector id from track table + mov AL, byte ptr cs:[si] ; get current sector value + mov cs:[cursec], AL ; save cursec value + +;*** For a Fixed disk multi-track disk I/O - 4/14/86 ;3.30 +;Assumptions: 1). In the input CX (# of sectors to go) to TRACKIO, only CL;3.30 is +;valid. 2). Sector size should be set to 512 bytes. 3). GOODTRACKLAYOUT. ;3.30 +; ;3.30 + test word ptr [di].Flags, fNon_Removable ;Fixed disk? - J.K;3.30 . + jz IOREMOVABLE ;no - ;3.30 + mov cs:[seccnt], dx ;# of sectors to I;3.30 /O - + mov ax, dx ; ;3.30 + call disk ; ;3.30 + pop dx ; ;3.30 + pop cx ; ;3.30 + clc ; ;3.30 + ret ; ;3.30 +IOREMOVABLE: ; ;3.30 + + mov AL, byte ptr cs:[si]+1 ; get sector size index + + ; The next eight lines put sector size index in DPT + push ES ; save value while getting pointer + push SI ; to DPT + push AX + + les SI, cs:DPT ; ES:SI points to DPT + ; put size in DPT + mov byte ptr ES:[si].Disk_Sector_Siz, AL + mov AX, word ptr [di].seclim ; get number of sector/track + mov byte ptr ES:[si].Disk_EOT,AL ; patch in DPT + + pop AX ; restore register values + pop SI + pop ES + ; convert index to byte value + call SectorSizeIndexToSectorSize + push AX ; save number of bytes in sector + mov AX, DX ; get number of sector for I/0 + +DoTheIO: + mov cs:[SECCNT],ax ; set up the count of sectors to I/O + call disk + ; advance buffer pointer by adding + ; sector size + pop ax + add bx, ax + pop dx + pop cx + loop IOnextSector + call DONE ; Set time of last access, and reset + clc ; entries in DPT. + ret + +TrackIO endp +; +; The sector size in bytes needs to be converted to an index value for the IBM +; ROM. (0=>128, 1=>256,2=>512,3=>1024). It is assumed that only these values +; are permissible. +; On Input AX contains sector size in bytes +; On Output AL contains index +; + public SectorSizeToSectorIndex +SectorSizeToSectorIndex proc near + and AH, 07h ; very simple error correction + mov AL, AH ; shift left 8 bits + cmp AL, 4 ; size 1024? + jnz SecToIndexRet ; no, then we are done + sub AL, 1 ; if 1024, adjust index to 3 +SecToIndexRet: + ret +SectorSizeToSectorIndex endp + +SectorSizeIndexToSectorSize proc near +; value in AH on entry is not important + push CX ; save CX value + mov CL, AL ; use index number as shift size + mov AX, 0080h ; set AX to 128 + shl AX, CL ; shift by index to get proper value + pop CX ; restore CX value + ret +SectorSizeIndexToSectorSize endp + + + +; +; Set up the ROM for formatting. +; we have to tell the ROM BIOS what type of disk is in the drive. +; On Input - DS:DI - points to BDS +; +SetDASD proc near +; See if we have new ROM and have issues Set Media Type For Format call + test byte ptr cs:[Media_Set_For_Format],1 + jnz DasdHasBeenSet +; See if we have previously set DASD type + cmp cs:[Had_Format_Error],1 + je DoSetDasd + test word ptr ds:[di].Flags, SET_DASD_true + jz DASDhasBeenSet + and word ptr ds:[di].Flags, not SET_DASD_true + ; the next nine lines determine and put the DASD type in AL +DoSetDasd: + mov cs:[Had_Format_Error],0 + mov cs:[GAP_PATCH], 50h ; assume 48tpi or 3.5" drive + cmp [di].FormFactor, ffSmall; is 3.5" drive? + jnz not35Drive ; no, skip down + mov AL, 04h ; yes set proper DASD value + jmp short Do_Set ; jump down + +Not35Drive: + mov AL, 01h ; + cmp [di].FormFactor, ff96tpi; 96tpi disk drive? + jnz Do_Set ; no skip down to rom call + inc AL ; reflect 96tpi drive in DASD type + cmp [di].seclim, 15 ; 96tpi media in drive? + jnz Do_Set ; no, skip down to rom call + inc AL ; reflect 96tpi media in DASD type + mov cs:[GAP_PATCH], 54h ; and in the GAP_PATCH +Do_Set: + mov AH, 17h ; set command to Set DASD type + mov DL, [di].DriveNum ; set drive number + int 13h ; call rom-bios +DASDhasBeenSet: + mov ah,byte ptr [di].seclim + mov cs:[FORMT_EOT],ah + ret +SetDasd endp + + +; +; This routine is called if an error occurs while formatting or verifying. +; It resets the drive, and decrements the retry count. +; On Entry - DS:DI - points to BDS for the drive +; BP - contains retry count +; On Exit Flags indicate result of decrementing retry count +; +; +; There are some drives that "lose" the changeline indication if another +; floppy drive is accessed before the changeline is recorded by the device +; driver. In this situation, it is possible for the ROM to also not detect +; that the medium has changed. So, the end result is that we could have a +; diskette in the drive for which we can not even read the boot sector. +; We "fix" this by setting the byte at location DISK_STATE_MACHINE_DRV_0 (hex) +; for physical drive 0 (or DISK_STATE_MACHINE_DRV_1 for drive 1) to 0 (See +; IBM PC/AT "blessed" addresses Document for explanation) . This tells the ROM +; that the medium is 'unknown'. The ROM actually uses these locations for +; itself. Note that we do this only for internal drives; we do not do this for +; fixed disks or for physical drives > 1. We may end up corrupting some +; other bytes in memory that may be used for something else. +; NOTE: We do not stuff this byte if the last operation was a FORMAT because +; the ROM loses track of what it is trying to format!! +; +; This routine was changed to only stuff 61H when the drive indicated it +; supported changeline. The Phoenix ROM was taking a very long time +; to figure out what the media was which caused disk time outs to take +; forever +; +; We assume that DS:DI points to the current BDS for this drive. +; no registers should be touched +; + +AGAIN: + call ResetDisk + dec bp ; decrement retry count + RET + + PUBLIC RESETDISK +ResetDisk: + push ax + xor AH, AH ; set command to reset disk + int 13h ; call the rom-bios + pop ax + mov cs:[STEP_DRV],-1 ; zap up the speed + ret + +; +; This routine sets up the Drive Parameter Table with the values needed for +; Format, does an Int 13. Values in DPT are restored after a VERIFY is done. +; +; On Entry - DS:DI - points to BDS for the drive +; ES:BX - points to TRKBUF +; AL - number of sectors +; AH - Int 13 function code +; CL - Sector number for verify +; On Exit - DS,DI,ES,BX remain unchanged. +; ax and flags are the results of the int 13 +; + Public To_ROM +To_ROM: + SAVEREG ;3.30 + +; The below line was replaced because saving the DPT is predicated upon +; whether the functionality of the new ROM was used, not if it exists. +; test byte ptr cs:[New_ROM],1 + + test byte ptr cs:[Media_Set_For_Format],1 + jnz Got_Valid_DPT + +; Set up values in the DPT +; Set up motor start correctly for 3.5" drives. + push ax + push ds + + xor ax,ax + mov ds,ax + lds si,dword ptr ds:[DskAdr] ; DS:SI := pDPT + + mov word ptr cs:[DPT],si + mov word ptr cs:[DPT+2],ds ; Save pDPT + + pop ds + push ES ; save value in ES + LES SI, CS:DPT + + mov DX, [di].seclim ; set the sector per track in + mov es:[si].DISK_EOT, DL ; the Disk Parameter Table + cmp DX, 15 ; 96tip media? + jz To_ROM1 ; yes, skip down + ; no - set Format Gap to 320/360 media value + mov CL, cs:[Gap_Patch] + mov byte ptr ES:[si].DISK_FORMT_GAP, CL +To_ROM1: ; 3.5" floppy drive? + cmp byte ptr [di].FormFactor, ffSmall + jnz To_ROM2 ; no, skip down + ; yes - reset disk moter start value + mov byte ptr ES:[si].DISK_MOTOR_STRT, 4 +To_ROM2: + pop ES ; restore ES value + pop ax + +Got_Valid_DPT: + ; now set up the registers + mov DL, [di].DriveNum ; set drive number + mov DH, CS:[HDNUM] ; set head number + mov CX, CS:[TRKNUM] ; set track number + ror CH,1 + ror CH,1 + xchg CH, CL + int 13h ; call the rom-bios disk routines + RestoreReg + ret + + +; +; Get the owner of the physical drive represented by the logical drive in BL. +; The assumption is that we **ALWAYS** keep track of the owner of a drive!! +; If this is not the case, the system may hang, just following the linked list. +; + PUBLIC IOCTL$GETOWN +IOCTL$GETOWN: + call SetDrive + mov al,byte ptr [di].DriveNum ; Get physical drive number + push cs + pop ds + mov di,word ptr Start_BDS +Own_Loop: + cmp byte ptr [di].DriveNum,al + jne GetNextBDS + test word ptr [di].flags,fI_Own_Physical + jnz Done_GetOwn +GetNextBDS: + mov bx,word ptr [di].link+2 + mov di,word ptr [di].link + mov ds,bx + jmp short Own_Loop +Done_GetOwn: + JMP SHORT EXIT_OWN + +; +; Set the ownership of the physical drive represented by the logical drive in +; BL. +; + PUBLIC IOCTL$SETOWN +IOCTL$SETOWN: + call SetDrive + mov byte ptr cs:[fSetOwner],1 ; set flag for CheckSingle to + ; look at. + call CheckSingle ; Set ownership of drive + mov byte ptr cs:[fSetOwner],0 ; reset flag + xor bx,bx + mov es,bx + mov cl,-1 + mov byte ptr es:[LSTDRV],cl ; Set up SDSB as well + +EXIT_OWN: +; If there is only one logical drive assigned to this physical drive, return +; 0 to user to indicate this. + xor cl,cl + test word ptr [di].flags,fI_Am_Mult + jz EXIT_NO_MULT + mov cl,byte ptr [di].DriveLet ; Get logical drive number + inc cl ; get it 1-based +EXIT_NO_MULT: + LDS BX,CS:[PtrSav] + mov byte ptr [BX].UNIT,CL + jmp EXIT + + + + +; +; Moves the old DPT that had been saved in TempDPT back to DPT. This is done +; only if the first byte of TempDPT is not -1. +; All registers (including flags) are preserved. +; + Public RestoreOldDPT +RestoreOldDPT: +; If we have already restored the disk base table earlier, do not do it +; again. + push ax + xor al,al +; Reset flag and get current flag setting + mov cs:[Had_Format_Error],al + xchg byte ptr cs:[Media_Set_For_Format],al + or al,al + jz DontRestore + SaveReg + LDS SI,CS:[TempDPT] + xor ax,ax + mov es,ax ; have ES -> segment 0 + MOV WORD PTR ES:[DskAdr],SI + MOV WORD PTR ES:[DskAdr+2],DS +GotCurrentDPT: + RestoreReg +DontRestore: + pop ax + clc ; clear carry + ret ; (7/31/86) + +;end of file msioctl.asm diff --git a/SRC/BIOS/MSLOAD.ASM b/SRC/BIOS/MSLOAD.ASM new file mode 100644 index 0000000..2ccd737 --- /dev/null +++ b/SRC/BIOS/MSLOAD.ASM @@ -0,0 +1,767 @@ +title Non-Contiguous BIOS Loader (MSLOAD) + +IF1 + %OUT ASSEMBLING: Non-Contiguous BIOS Loader (MSLOAD) + %OUT +ENDIF + +bootseg segment at 0h + org 7C00h +Boot_Sector label byte + org 7D00h +Relocate_Start label byte +bootseg ends + + +dosseg segment at 70h + org 00h +BIOS_Address label byte + +dosseg ends + + +cseg segment public para 'code' + assume cs:cseg,ds:cseg,es:cseg,ss:cseg + + + +include msload.inc + +org 0h + +start: + +subttl Setup Stack +page +;*********************************************************************** +; Setup_Stack +;*********************************************************************** +; +; Input: none +; +; Output: +; +; SS:SP = 0:7C00h +; AX destroyed +;----------------------------------------------------------------------- +; First thing is to reset the stack to a better and more known place. +; +; Move the stack to just under the boot record and relocation area (0:7C00h) +; +; Preserve all other registers +;---------------------------------------------------------------------- + + CLI ;Stop interrupts till stack ok + XOR AX,AX + MOV SS,AX ;Work in stack just below this routine + MOV SP,7C00h - 30 ;Leave room for stack frame + MOV BP,7C00h - 30 ;Point BP as stack index pointer + STI + + +subttl Save Input Values +page +;*********************************************************************** +; Save_Input_Values +;*********************************************************************** +; +; Input: none +; +; DL = INT 13 drive number we booted from +; CH = media byte +; BX = First data sector on disk (0-based) +; +; Output: +; +; BX = first data sector on disk +; CL = number of floppies including fake one +; CH = media byte +; +; [bp].Media_Byte = input CH +; [bp].Drive_Number = input DL +; [bp].First_Sector = input BX +; [bp].Drive_Boot = output AX +; [bp].Number_Floppy = output CL +; [bp].Number_Sectors = Sectors/track +; [bp].Number_Heads = heads/cylinder +; +; DS = 0 +; AX,DX,SI destroyed +; +; Calls: none +;----------------------------------------------------------------------- +; Save input information +; +; Get Equipment Flag +; +; Find how many drives on system +; +; Figure out boot drive +; +;---------------------------------------------------------------------- +Save_Input_Values: + mov [bp].First_Sector,bx + mov [bp].media_Byte,ch + mov [bp].Drive_Number,dl +; INT 11h ;GET EQUIPMENT STATUS +; ROL AL,1 ;Put bits 6 & 7 into bits 0 & 1 +; ROL AL,1 +; AND AX,3 ;Only look at bits 0 & 1 +; JNZ NOTsingle ;Zero means single drive system +; INC AX ;Pretend it's a two drive system +NOTSingle: +; INC AX ;AX has number of drives, 2-4 + ;Is also 0 indexed boot drive if we + ; booted off hard file +; MOV CL,AL ;CH is FAT ID, CL # floppies +; TEST DL,80H ;BOOT FROM FLOPPY ? +; JNZ GOTHRD ;NO. +; XOR AX,AX ;INDICATE BOOT FROM DRIVE A +GotHrd: + xor ax,ax ;Segment 0 + mov ds,ax + + assume ds:Bootseg + + mov ax,Boot_Sector.SECLIM ;Get Sectors per track + mov [bp].Sectors_Per_Track,ax + mov ax,Boot_Sector.HDLIM ;Get BPB heads per cylinder + mov [bp].Number_Of_Heads,ax + mov ax,Boot_Sector.cSecFat ;Get sectors per FAT + mov [bp].Number_Of_FAT_Sectors,ax + mov ax,Boot_Sector.cSecHid ;Get hidden sectors + mov [bp].Hidden_Sectors,ax + mov ax,Boot_Sector.cSecRes ;Get Reserved Sectors + mov [bp].Reserved_Sectors,ax + + +subttl Find_Cluster_Size +page +;*********************************************************************** +; Find_Cluster_Size +;*********************************************************************** +; +; Input: BPB information in loaded boot record at 0:7C00h +; +; Output: +; +; DS = 0 +; AX = Bytes/Cluster +; BX = Sectors/Cluster +; SI destroyed +; Calls: none +;----------------------------------------------------------------------- +; +; Get Bytes/sector from BPB +; +; Get sectors/cluster from BPB +; +; Bytes/cluster = Bytes/sector * sector/cluster +;---------------------------------------------------------------------- +Find_Cluster_Size: + +;For the time being just assume the boot record is valid and the BPB +;is there. + + xor ax,ax ;Segment 0 + mov ds,ax + + assume ds:bootseg + + mov ax,Boot_Sector.ByteSec ;Get BPB bytes/sector + xor bx,bx + mov bl,Boot_Sector.cAlloc ;Get sectors/cluster + mul bx ;Bytes/cluster + mov [bp].Size_Cluster,ax ;Save it + + + +subttl Determine FAT size +page +;*********************************************************************** +; Determine_FAT_Size +;*********************************************************************** +; +; Notes: +; +; Determine if FAT is 12 or 16 bit FAT. 12 bit FAT if floppy, read MBR +; to find out what system id byte is. +; +; Input: [bp].Media_Byte = FAT ID Byte +; +; Output: +; +; [BP].Fat_Size = FAT12_bit or FAT16_bit +; ES = 0 +; All other registers destroyed +; +; Calls: READ_DISK +;----------------------------------------------------------------------- +;IF (not FAT ID of F8) +; {12 bit FAT} +;ELSE +; { +; Read in master boot record at 0:7C00h +; +; Scan system id bytes for 1 or 4 +; +; IF (Sys id = 4) +; {16 bit FAT} +; ELSE +; {IF (Sys id = 1) +; {12 bit FAT} +; ELSE +; {Error} +; ENDIF +; ENDIF +; ENDIF +; +;---------------------------------------------------------------------- +Determine_FAT_Size: + mov [bp].FAT_Size,FAT12_bit ;Assume 12 bit fat + cmp [bp].Media_Byte,0F8h ;Is it floppy + jne FAT_Size_Found ;Yep, all set + mov [bp].Logical_Sector,0 ;Got hardfile, go get MBR + xor ax,ax + mov es,ax + mov di,offset Relocate_Start + mov [bp].Sector_Count,1 + call Disk_Read + mov si,offset Relocate_Start+1C2h + mov cx,4 + xor ax,ax + mov ds,ax +Find_Sys_Id: + mov [bp].FAT_Size,FAT12_bit ;Assume 12 bit fat + cmp byte ptr [si],1 + je FAT_Size_Found + mov [bp].FAT_Size,FAT16_bit ;Assume 12 bit fat + cmp byte ptr [si],4 + je Fat_Size_Found + add si,16 + loop Find_Sys_Id + ;xxxxxxxxxxxxxxxxxxxxxxxxxx error +FAT_Size_Found: + + +subttl Determine First Cluster +page +;*********************************************************************** +; Determine_First_Cluster +;*********************************************************************** +; +; Notes: Find the last cluster that was loaded +; +; +; Input: +; +; [BP].Size_Cluster +; Total_Length is offset of end of MSLOAD +; +; Output: +; +; [BP].Last_Found_Cluster = the last cluster loaded containing MSLOAD +; code. This is also the number of clusters +; with MSLOAD code +2 +; +; Calls: none +;----------------------------------------------------------------------- +; +;Get length of loader portion of bios +; +;Divide by bytes/cluster +; +;If (Remainder = 0) +; {Last_Used_Cluster = quotient+2} +;Else +; {Last_Used_Cluster = quotient+3} +;---------------------------------------------------------------------- +Determine_First_Cluster: + mov [bp].Last_Found_Cluster,1 ;2 is the first cluster-1 + mov ax,offset Total_Length ;Get whole length + xor dx,dx + div [bp].Size_Cluster ;Div by bytes/sector + add [bp].Last_Found_Cluster,ax ;Save the result + cmp dx,0 ;Was there remainder? + je First_Cluster_Found ;No + inc [bp].Last_Found_Cluster ;Yes, round up + +First_Cluster_Found: + + +subttl Relocate +page +; +;*********************************************************************** +; RELOCATE +;*********************************************************************** +; +; Notes: +; +; Relocate the loader code to 0:7C00 - this will allow bios to be loaded +; underneath at 70:0 +; +; Input: none +; +; Output: es is set to 0 +; ds is set to cs (70h) +; ax,cx,si,di destroyed +; +; Calls: none +;----------------------------------------------------------------------- +; Copy code from Relocate_Code to Relocate_Start (7C00h) +; +; The length to copy is Relocate_Length +; +; Jump to relocated code +;----------------------------------------------------------------------- +; +Relocate: + push cs ;Set up ds segreg + pop ds + xor ax,ax ;Set up ES segreg + mov es,ax + + assume es:bootseg,ds:cseg + + mov si,offset Relocate_Code ;Source + mov di,offset Relocate_Start ;Target + mov cx,Relocate_Length ;Length + rep movsb ;Go do it + + jmp far ptr Relocate_Start + +; +;************************************************************************* +;* RELOCATED CODE ******************************************************** +;************************************************************************* +; + +Relocate_Code label byte + +subttl Read In FAT +page +;*********************************************************************** +; Read_In_FAT +;*********************************************************************** +; +; Notes: +; +; Reads in the entire FAT at 0:8000. This gives the relocated portion +; of this loader a maximum size of 1024 bytes (8000 - 7C00). The max +; size of the FAT is 64 sectors (32k) so everything will fit under the +; 64k DMA boundary, so no problems with loading. +; +; Input: none +; +; Output: +; +; ES = 0 +; All sectors destroyed +; +; Calls: READ DISK +;----------------------------------------------------------------------- +; Get number of sectors in FAT +; +; Set ES:DI to 0:8000h +; +; Read in the sectors +; +;---------------------------------------------------------------------- +Read_In_FAT: + xor ax,ax + mov ds,ax + + assume ds:bootseg + + mov ax,[bp].Number_Of_FAT_Sectors ;Get sectors/FAT + mov [bp].Sector_Count,ax ;Number of sectors to read + mov ax,[bp].Hidden_Sectors ;Hidden+Reserved = Fat + add ax,[bp].Reserved_Sectors + mov [bp].Logical_Sector,ax ;Save it, setup for read + xor ax,ax + mov es,ax + mov di,8000h ;Point to buffer + call Disk_Read + +subttl Keep Loaded BIO +page +;*********************************************************************** +; KEEP LOADED BIO +;*********************************************************************** +; +; Notes: +; +; Determine how much of bios was loaded in when the loader was loaded +; by the boot record (only the portion that is guaranteed to be +; contiguous +; +; Input: +; +; [BP].Last_Found_Cluster = number of clusters used for loader+2 +; +; Output: +; ES = DS = 70h +; DI = Next offset to load bios code +; AX,BX,CX,DX,SI destroyed +; +; [bp].Next_BIO_Location = DI on output +; [bp].Last_Cluster = last cluster loaded +; +; Calls: none +;----------------------------------------------------------------------- +;Number of clusters loaded+2 is in [BP].Last_Found_Cluster +; +;Multiply cluster * cluster size in bytes to get total loaded for MSLOAD +; +;Subtract TOTAL_LOADED - LOADBIO_SIZE to get loaded bios in last cluster +; +;Relocate this piece of bios down to 70:0 +; +;---------------------------------------------------------------------- +Keep_Loaded_BIO: + push ds + mov ax,[bp].Last_Found_Cluster ;Point to last cluster loaded + sub ax,1 ;Get number of clusters loaded + mul [bp].Size_Cluster ;Get total bytes loaded by + ;This is always < 64k, so + ;lower 16 bits ok + sub ax,LoadBio_Size ;Get portion of bios loaded + mov cx,ax ;Save length to move + mov ax,70h ;Segment at 70h + mov ds,ax + mov es,ax + mov si,offset cs:Total_Length ;Point at bios + mov di,0 ;Point at 70:0 + rep movsb ;Relocate this code + mov [bp].Next_Bio_Location,di ;Save where to load next + pop ds + +subttl Get Contiguous Clusters +page +;*********************************************************************** +; Get_Contiguous_Clusters +;*********************************************************************** +; +; Notes: Go find clusters as long as they are contiguous +; +; +; Input: +; +; [BP].Next_BIO_Location +; [BP]. +; +; +; Output: +; +; +; Calls: Get_Next_FAT_Entry +;----------------------------------------------------------------------- +; +;Set [BP].Sector_Count to Sectors per cluster +; +;Call Get_Next_FAT_Entry to get next cluster in file +; +;Call Check_for_EOF +; +;IF (NC returned) +; +; {Call Get_Next_FAT_Entry +; +; IF (New cluster is contig to old cluster) +; {Add sectors per cluster to [BP].Sector_Count +; +; Call Check_For_EOF +; +; IF (NC returned) +; +; +;---------------------------------------------------------------------- +Get_Contiguous_Cluster: + xor ah,ah + mov al,Boot_Sector.cAlloc ;Assume we will get one cluster + mov [bp].Sector_Count,ax + call Get_Next_Fat_Entry ;Go get it + mov [bp].Last_Found_Cluster,ax ;Update the last one found + cmp [bp].EOF,End_Of_File + je GOTO_bios + +Got_Contig_Clusters: + sub ax,2 ;Zero base the cluster + xor ch,ch + mov cl,Boot_Sector.cAlloc ;Get sectors per cluster + mul cx ;Get how many + add ax,[bp].First_Sector ;See where the data sector starts + mov [bp].Logical_Sector,ax ;Save it + mov di,[bp].Next_Bio_Location ;Get where to put code + push [bp].Sector_Count ;Save how many sectors + mov ax,dosseg ;Get area to load code + mov es,ax + call Disk_Read + pop ax ;Get back total sectors read in +; jc ########## + mul Boot_Sector.ByteSec ;Get number of bytes we loaded + add [bp].Next_Bio_Location,ax ;Point to where to load next + jmp short Get_Contiguous_Cluster + +subttl GOTO bios +page +;*********************************************************************** +; GOTO_bios +;*********************************************************************** +; +; Notes: +; +; Set up required registers for bios, then jump to it (70:0) +; +; Input: none +; +; [bp].Media_Byte = media byte +; [bp].Drive_Number = INT 13 drive number we booted from +; [bp].First_Sector = First data sector on disk (0-based) +; +; Output: +; +; Required by MSINIT +; DL = INT 13 drive number we booted from +; CH = media byte +; BX = First data sector on disk (0-based) +; +; Calls: none +;----------------------------------------------------------------------- +; +; Set up registers for MSINIT then do Far Jmp +; +;---------------------------------------------------------------------- +GOTO_bios: + mov ch,[bp].Media_Byte ;Restore regs required for MSINT + mov dl,[bp].Drive_Number + mov bx,[bp].First_Sector + jmp far ptr bios_Address + + + + +subttl Disk Read +page +;*********************************************************************** +; Disk_Read +;*********************************************************************** +; +; Notes: +; +; Read in the [BP].Sector_Count number of sectors at ES:DI +; +; +; Input: none +; +; DI = Offset of start of read +; ES = Segment of read +; [bp].Sector_Count = number of sectors to read +; [bp].Logical_sector = starting sector +; Following is BPB info that must be setup prior to call +; [bp].Number_Of_Heads +; [bp].Number_Of_Sectors +; [bp].Drive_Number +; [bp].Sectors_Per_Track +; +; Output: +; +; ES = 0 +; AX,BX,CX,DX,SI,DI destroyed +; +; +; Calls: none +;----------------------------------------------------------------------- +; Divide start sector by sectors per track +; The remainder is the actual sector number, 0 based +; +; Increment actual sector number to get 1 based +; +; The quotient is the number of tracks - divide by heads to get the cyl +; +; The remainder is actual head, the quotient is cylinder +; +; Figure the number of sectors in that track, set AL to this +; +; Do the read +; +; If Error, Do RESET, then redo the INT 13h +; +; If successful read, Subtract # sectors read from Sector_Count, Add to +; Logical Sector, add #sectors read * Sector_Size to BX; +; +; If Sector_Count <> 0 Do next read +;---------------------------------------------------------------------- +Disk_Read: + +; +; convert a logical sector into Track/sector/head. AX has the logical +; sector number +; +DODIV: + MOV cx,5 ;5 retries + +Try_Read: + PUSH cx ;Save it + + MOV AX,[bp].Logical_Sector ;Get starting sector + XOR DX,DX + DIV word ptr [bp].Sectors_Per_Track + MOV bx,[bp].Sectors_Per_Track ;Get number of sectors we can + sub bx,dx ;read in this track + mov si,bx + cmp [bp].Sector_Count,si ;Is possible sectors in track more + jae Got_Length ;than what we need to read? + mov si,[bp].Sector_Count ;Yes, only read what we need to + +Got_Length: + INC DL ; sector numbers are 1-based + MOV bl,dl ;Start sector in DL + XOR DX,DX + DIV word ptr [bp].Number_Of_Heads ;Start cyl in ax,head in DL + MOV DH,DL +; +; Issue one read request. ES:BX have the transfer address, AL is the number +; of sectors. +; +; +; Now convert to standard ROM call +; + mov cl,bl ;Get starting sector + ror ah,1 ;Set up high 2 bits + ror ah,1 ;Set up high 2 bits + or cl,ah ;Combine cyl/start sector + mov ch,al ;Set low order of cyl + mov bx,di ;Set offset + mov dl,[bp].Drive_Number ;Set drive + mov ax,si ;Set count + mov ah,02 ;Read Command + push ax ;Save regs + push di ; * + int 13h ;Call ROM-Bios + pop di ;Restore Regs + pop ax ; * + pop cx ;Get retry count back + jnc Read_OK + push cx + mov bx,di ; + push di ;Save Reg + mov dl,[bp].Drive_Number ;Set drive + mov ah,0 ;RESET Disk Command + int 13h ;Call ROM-Bios + pop di ;Restore Reg + pop cx + loop Try_Read + ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx error +Read_OK: + xor ah,ah ;Mask out command, just get # read + sub [bp].Sector_Count,ax ;Bump number down + jz Read_Finished + add [bp].Logical_Sector,ax ;Where to start next time + xor bx,bx ;Get number sectors read + mov bl,al + mov ax,Boot_Sector.ByteSec ;Bytes per sector + mul bx ;Get total bytes read + add di,ax ;Add it to offset + jmp short DODIV +Read_Finished: + RET + +subttl GET NEXT FAT ENTRY +page +;*********************************************************************** +; GET_NEXT_FAT_ENTRY +;*********************************************************************** +; +; Notes: +; +; Given the last cluster found, this will return the next cluster of +; bios. If the last cluster is (F)FF8 - (F)FFF, then the final cluster +; of bios has been loaded, and control is passed to GOTO_bios +; +; Input: +; +; [bp].Last_Found_Cluster +; [bp].Fat_Size +; +; Output: +; +; [bp].Last_Found_Cluster (updated) +; +; Calls: none +;----------------------------------------------------------------------- +; Get Last_Found_Cluster +; +; IF (16 bit FAT) +; {IF (Last_Found_Cluster = FFF8 - FFFF) +; {JMP GOTO_bios} +; ELSE +; {Get offset by multiply cluster by 2} +; +; ELSE +; {IF (Last_Found_Cluster = FF8 - FFF) +; {JMP GOTO_bios} +; ELSE +; {Get offset by - multiply cluster by 3 +; +; Rotate right to divide by 2 +; +; IF (CY set - means odd number) +; {SHR 4 times to keep high twelve bits} +; +; ELSE +; {AND with 0FFFh to keep low 12 bits} +; } +; } +; +; Add in 8000h to get offset of next cluster in FAT buffer +; +;---------------------------------------------------------------------- +Get_Next_FAT_Entry: + + mov [bp].EOF,End_Of_File ;Assume last cluster + mov ax,[bp].Last_Found_Cluster ;Get last cluster + cmp [bp].Fat_Size,FAT12_bit + jne Got_16_Bit + xor bx,bx + mov bl,3 ;Mult by 3 + mul bx + shr ax,1 ;Div by 2 to get 1.5 + mov si,ax ;Get the final buffer offset + mov ax,[si]+8000h ;Get new cluster + test [bp].Last_Found_Cluster,1 ;Was last cluster odd? + jnz Odd_Result ;If Carry set it was odd + and ax,0FFFh ;Keep low 12 bits + jmp short Test_EOF + +Odd_Result: + mov cl,4 ;Keep high 12 bits for odd + shr ax,cl +Test_EOF: + cmp ax,0FF8h ;Is it last cluster? + jae Got_Cluster_Done ;Yep, all done here + jmp short Not_Last_CLuster + +Got_16_Bit: + shl ax,1 ;Multiply cluster by 2 + mov si,ax ;Get the final buffer offset + mov ax,[si]+8000h ;Get new cluster + cmp ax,0FFF8h + jae Got_Cluster_Done + +Not_Last_Cluster: + mov [bp].EOF,not End_Of_File ;Assume last cluster + +Got_Cluster_Done: + ret + + + + +Relocate_Length equ $ - Read_In_FAT +Total_Length label byte +LoadBIO_Size equ $ - Start + +cseg ends +end start diff --git a/SRC/BIOS/MSLOAD.INC b/SRC/BIOS/MSLOAD.INC new file mode 100644 index 0000000..eb8deeb --- /dev/null +++ b/SRC/BIOS/MSLOAD.INC @@ -0,0 +1,52 @@ + ;3.30 +Stack_Frame STRUC ;3.30 +Number_Of_Heads dw 0 ;3.30 +Size_Cluster dw 0 ;3.30 +Logical_Sector dw 0 ;3.30 +Sector_Count dw 0 ;3.30 +Number_Of_FAT_Sectors dw 0 ;3.30 +Hidden_Sectors dw 0 ;3.30 +Sector_Size dw 0 ;3.30 +Reserved_Sectors dw 0 ;3.30 +Last_Found_Cluster dw 0 ;3.30 +Next_BIO_Location dw 0 ;3.30 +First_Sector dw 0 ;3.30 +Sectors_Per_Track dw 0 ;3.30 +Drive_Number db 0 ;3.30 +FAT_Size db 0 ;3.30 +Media_Byte db 0 ;3.30 +EOF db 0 ;3.30 + ;3.30 +Stack_Frame ENDS ;3.30 + ;3.30 + ;3.30 +BPB STRUC ;3.30 +JUMP DB 0 ;3.30 + DB 0 ;3.30 + DB 0 ;3.30 +OEM DB "IBM " ;3.30 + DB "3.3" ;3.30 +ByteSec DW 512 ; SIZE OF A PHYSICAL SECTOR ;3.30 +cAlloc DB 8 ; SECTORS PER ALLOCATION UNIT ;3.30 +cSecRes DW 1 ; NUMBER OF RESERVED SECTORS ;3.30 +cFat DB 2 ; NUMBER OF FATS ;3.30 +DirNum DW 512 ; NUMBER OF DIREC ENTRIES ;3.30 +NumSec DW 4*17*305-1 ; NUMBER OF SECTORS - NUMBER OF HI;3.30 DDEN SECTORS +MEDIA DB 0F8H ; MEDIA BYTE ;3.30 +cSecFat DW 8 ; NUMBER OF FAT SECTORS ;3.30 +SECLIM DW 17 ; SECTORS PER TRACK ;3.30 +HDLIM DW 4 ; NUMBER OF SURFACES ;3.30 +cSecHid DW 1 ; NUMBER OF HIDDEN SECTORS ;3.30 +hSecHid dw 0 ; high order word of Hidden Sector;3.30 s +BNumSec dd 0 ; 32 bit version of NUMBER OF SECT;3.30 ORS + ; (when 16 bit version is zero) ;3.30 +Other db 6 dup(?) ; reserved for later expansion ;3.30 +BPB ENDS ;3.30 + ;3.30 + ;3.30 + ;3.30 +End_Of_File equ 0FFh ;3.30 +FAT12_Bit equ 01h ;3.30 +FAT16_Bit equ 04h ;3.30 + ;3.30 + \ No newline at end of file diff --git a/SRC/BIOS/MSLOAD.OBJ b/SRC/BIOS/MSLOAD.OBJ new file mode 100644 index 0000000..9a2cc0f Binary files /dev/null and b/SRC/BIOS/MSLOAD.OBJ differ diff --git a/SRC/BIOS/MSLPT.ASM b/SRC/BIOS/MSLPT.ASM new file mode 100644 index 0000000..afa41e1 --- /dev/null +++ b/SRC/BIOS/MSLPT.ASM @@ -0,0 +1,274 @@ + TITLE MSLPT - DOS 3.3 ;3.30 +;---------------------------------------------------------------- +; : +; P R N - PRINTER DEVICE : +; : +; : +; This file contains the Printer Device Driver. The : +; printer driver handles calls to the printers. Four devices : +; use this code: PRN, LPT1, LPT2, and LPT3. The beginning : +; of the interrupt entry point for these device sets the : +; variable AUXNUM in the msbio.asm module. The number is : +; in AUXNUM dictates which device will to written to: 0 for : +; PRN and LPT1, 1 for LPT2, and 2 for LPT3. : +; : +; The routines in this files are: : +; : +; routine function : +; ------- -------- : +; PRN$WRIT Write to printer device : +; PRN$STAT Printer status routine : +; PRN$TilBusy Print spooler routine : +; Prn$GenIOCTL Generic IOCTL routine : +; : +; These routines are not called directly. Call are made via : +; the strategy and interrupt entry point (see Device Header). : +; : +;---------------------------------------------------------------- + + test=0 ;3.30 + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT ;3.30 + INCLUDE MSEQU.INC ;3.30 + INCLUDE MSMACRO.INC ;3.30 + INCLUDE DEVSYM.INC ;3.30 + INCLUDE IOCTL.INC ;3.30 + ;3.30 + EXTRN BUS$EXIT:NEAR ;MSBIO1 ;3.30 + EXTRN ERR$CNT:NEAR ;MSBIO1 ;3.30 + EXTRN CMDERR:NEAR ;MSBIO1 ;3.30 + EXTRN GETDX:NEAR ;MSBIO1 ;3.30 + EXTRN EXIT:NEAR ;MSBIO1 ;3.30 + EXTRN ERR$EXIT:NEAR ;MSBIO1 ;3.30 +;DATA ;3.30 + EXTRN PTRSAV:DWORD ;MSBIO1 ;3.30 + EXTRN TIMDEV:WORD ;MSCLOCK ;3.30 + EXTRN LPT2DEV:WORD ;MSBIO2 ;3.30 + EXTRN WAIT_COUNT:WORD ;MSDATA ;3.30 + EXTRN PRINTDEV:BYTE ;MSDATA ;3.30 + ;3.30 + + +; IBM ROM STATUS BITS (I DON'T TRUST THEM, NEITHER SHOULD YOU) ;3.30 + ;3.30 +NOTBUSYSTATUS = 10000000B ; NOT BUSY ;3.30 +ACKSTATUS = 01000000B ; ACKNOWLEDGE (FOR WHAT?) ;3.30 +NOPAPERSTATUS = 00100000B ; NO MORE PAPER ;3.30 +SELECTEDSTATUS = 00010000B ; THE PRINTER SAID IT WAS SELECTED;3.30 +IOERRSTATUS = 00001000B ; SOME KINDA ERROR ;3.30 +RESERVED = 00000110B ; NOPS ;3.30 +TIMEOUTSTATUS = 00000001B ; TIME OUT. ;3.30 + ;3.30 + ;3.30 +; WARNING!!! THE IBM ROM DOES NOT RETURN JUST ONE BIT. IT RETURNS A ;3.30 +; WHOLE SLEW OF BITS, ONLY ONE OF WHICH IS CORRECT. ;3.30 + ;3.30 + +;---------------------------------------------------------------- +; : +; WRITE TO PRINTER DEVICE : +; : +; CX has count of bytes to be printed : +; ES:DI point to source buffer contains characters : +; AuxNum (in msbio.asm) has printer number : +; : +;---------------------------------------------------------------- + PUBLIC PRN$WRIT ;3.30 +PRN$WRIT PROC NEAR ;3.30 + ASSUME DS:CODE ; SET BY PRINTER DEVICE DRIVER ENT;3.30 RY + + jcxz EXVEC3 ; no chars to output, Get out +PRN$LOOP: + mov BX,2 ; Initialize retry flag +PRN$out: + mov AL,ES:[DI] ; Get a character into AL + inc DI ; Point to next character + XOR AH,AH ; AH=0 => OUTPUT CHAR IN DL ;3.30 + call PRNOP ; print character + jnz PrRetry ; if error, try to print again + loop PRN$LOOP ; if more character, keep printing +EXVEC3: + jmp EXIT + +PrRetry: + dec DI ; undo the inc above... + dec BX ; Decrement retry count + jnz PRN$out ; See if done with retrys +PMESSG: + JMP ERR$CNT ; if so return with the error +PRN$WRIT ENDP ;3.30 + +;---------------------------------------------------------------- +; : +; PRINTER STATUS ROUTINE : +; : +;---------------------------------------------------------------- +; + PUBLIC PRN$STAT ;3.30 +PRN$STAT PROC NEAR ;3.30 + ASSUME DS:CODE ; SET BY PRINTER DEVICE DRIVER ENT;3.30 RY + ;3.30 + call PRNSTAT ; get the status + jnz PMESSG ; if error jump to error routine + MOV AL,9 ; AGAIN, ASSUME OUT OF PAPER... ;3.30 + TEST AH,NOPAPERSTATUS ;3.30 + JNZ PMESSG ;3.30 + TEST AH,NOTBUSYSTATUS ;3.30 + jnz EXVEC3 ; if not busy return via EXVEC3 + JMP BUS$EXIT ; else busy, return to busy exit ;3.30 +PRN$STAT ENDP ;3.30 + + + +; +; PRNSTAT get printer status +; PRNOP print a character +; +; PRNSTAT and PRNOP are two routines which call on the ROM-BIOS +; printer routines. The routines share code which calls on the bios and +; then determines which, if any, error occured. PRNSTAT and PRNOP differ +; only by the value put into AH before the ROM-BIOS call. +; +; INPUT if PRNOP then character in AL +; +; OUTPUT - AL holds error code +; - AH status byte from printer +; - flag NZ if error +PRNSTAT PROC NEAR ;3.30 + mov AH, 2 ; set command for get status ;3.30* +PRNOP: ;3.30* + call GETDX ; determine which printer ;3.30* + int 17h ; call ROM-BIOS printer routine ;3.30* + + TEST AH,IOERRSTATUS ; I/O ERROR? ;3.30 + JZ CHECKNOTREADY ; NO, TRY NOT READY ;3.30 + ;3.30 +; AT THIS POINT, WE KNOW WE HAVE AN ERROR. THE CONVERSE IS NOT TRUE. ;3.30 + ;3.30 + MOV AL,9 ; FIRST, ASSUME OUT OF PAPER ;3.30 + TEST AH,NOPAPERSTATUS ; OUT OF PAPER SET? ;3.30 + JNZ RET1 ; YES, ERROR IS SET ;3.30 + INC AL ; INDICATE I/O ERROR ;3.30 +RET1: ;3.30 + ;3.30 +; WE HAVE TRIAGED NOW FOR OUT OF PAPER AND IO ERR (IGNORING TIME-OUT) ;3.30 + ;3.30 + RET ; RETURN WITH ERROR ;3.30 + ;3.30 +; THE BITS SAID NO ERROR. UNFORTUNATELY, THERE MAY BE OTHER THINGS AT WOR;3.30 K +; HERE. ;3.30 + ;3.30 +CHECKNOTREADY: ;3.30 + MOV AL,2 ; ASSUME NOT-READY ;3.30 + TEST AH,TIMEOUTSTATUS ; IS TIME-OUT SET? ;3.30 + ; IF NZ THEN ERROR, ELSE OK??? ;3.30 +PRNOP2: ;3.30 + RET ;3.30 +PRNSTAT ENDP ;3.30 + + +;---------------------------------------------------------------- +; : +; Output until Busy : +; : +; Output until busy. This entry point is used EXCLUSIVELY by : +; the print spoolers. Under no curcumstances should the device : +; driver block waiting for the device to become ready. : +; : +; Inputs: CX has count of bytes to output. : +; ES:DI points to source buffer : +; Outputs: Set the number of bytes transferred : +; appropriately. : +; : +;---------------------------------------------------------------- + + PUBLIC PRN$TILBUSY ;3.30 +PRN$TILBUSY PROC NEAR ;3.30 + ASSUME DS:CODE ; SET BY PRINTER DEVICE DRIVER ENT;3.30 RY + ;3.30 + push DS ; save DS + push ES ; copy ES to DS + pop DS + ASSUME DS:NOTHING ;3.30 + + mov SI,DI ; everything is set for LODSB +PRN$TilBLoop: + push CX + push BX + xor BX,BX + mov BL,CS:[PRINTDEV] + shl BX,1 + mov CX,CS:WAIT_COUNT[BX] ; wait COUNT times to come ready + pop BX +PRN$GetStat: + call PrnStat ; get status + jnz PRN$BPERR ; if error jump to error routine + TEST AH,10000000B ; READY YET? ;3.30 + loopz PRN$GetStat ; if busy keep trying + pop CX ; get original count + jz PRN$BErr ; still not ready => done + lodsb + XOR AH,AH ;3.30 + call PrnOp ; print the character + jnz PRN$BErr ; error + loop PRN$TilBLoop ; go for more +PRN$B: + pop DS ; recover DS + lds BX,CS:[PTRSAV] ; get pointer to header + ASSUME DS:NOTHING ;3.30 + + sub WORD PTR [BX].COUNT,CX ; Determine number of succ. I/O's + jmp Exit ; all done, successful return +PRN$TILBUSY ENDP ;3.30 + +PRN$BPERR PROC NEAR ;3.30 + ASSUME DS:CODE ;3.30 + + pop CX ; recover number of char left +PRN$BErr: + pop DS ; get pointer to header + lds BX,CS:[PTRSAV] + ASSUME DS:NOTHING ;3.30 + + sub WORD PTR [BX].COUNT,CX ; Determine number of succ. I/O's + jmp err$exit ; jump to error exit +PRN$BPERR ENDP ;3.30 + + +; +; Prn$GenIOCTL: +; +; Manipulates the value in WAIT_COUNT depending on the value passed in the +; Generic IOCTL packet. +; It either sets or returns the current value for the retry count for the +; device. +; + PUBLIC PRN$GENIOCTL ;3.30 +PRN$GENIOCTL PROC NEAR ;3.30 + ASSUME DS:CODE ; SET BY PRINTER DEVICE DRIVER ENT;3.30 RY + + les di,[PTRSAV] + cmp es:[di].MajorFunction,IOC_PC + je PrnFunc_OK +PrnFuncErr: + jmp CMDERR + +PrnFunc_OK: + mov al,es:[di].MinorFunction + les di,es:[di].GenericIOCTL_Packet + xor bx,bx + mov bl,[PRINTDEV] ; get index into retry counts + shl bx,1 + mov CX,WAIT_COUNT[BX] ; pull out retry count for device + cmp al,GET_RETRY_COUNT + jz PrnGetCount + cmp al,SET_RETRY_COUNT + jnz PrnFuncErr + mov cx,es:[di].RC_Count +PrnGetCount: + mov WAIT_COUNT[BX],CX ; place "new" retry count + mov es:[di].RC_Count,cx ; return current retry count + jmp EXIT + +PRN$GENIOCTL ENDP ;3.30 +CODE ENDS ;3.30 + END ;3.30 diff --git a/SRC/BIOS/MSLPT.OBJ b/SRC/BIOS/MSLPT.OBJ new file mode 100644 index 0000000..1299fb3 Binary files /dev/null and b/SRC/BIOS/MSLPT.OBJ differ diff --git a/SRC/BIOS/MSMACRO.INC b/SRC/BIOS/MSMACRO.INC new file mode 100644 index 0000000..1ef684b --- /dev/null +++ b/SRC/BIOS/MSMACRO.INC @@ -0,0 +1,192 @@ +; +; This file contains three macros used in debugging the system. If the +; variable "test" (in msbio.asm) is nonzero code is included in the +; modules to print debugging messages. The level of debugging is controlled +; by the value of the variable fTestBits in msbio.asm. Specific bits in +; the variable determine which messages to print. The equ's below tell +; which bits control which funcitons. For example the fifth bit +; cooresponds to disk activity (see fTestDisk equ below). +; +; The macros in the file are: +; +; message Prints an ascii string on the screen. +; Example usage: +; +; message fTestDisk, <"Start Disk Write", CR, LF> +; message fTestINIT, <"Begin BDS initialization"> +; +; +; MNUM Print the value in a register or memory location on +; the screen. Value is displayed in hex. +; Usage: +; MNUM bitpattern, valueLocation +; +; valueLocation is typically a regester: +; +; mnum fTestCom, AX +; mnum fTestDisk, DX +; +; ValueLocation can also be a memory location: +; +; mnum fTestINIT, Final_Dos_Location +; +; If no valueLocation is given the macro defaults to +; the BX register. +; +; ZWAIT Stops the program until any key is pressed. +; +; +; The three macros preserve all register values. If "test" is zero +; defined during assembly then the marco produce no code. +; + + IF TEST ;3.30 + IFNDEF MSGOUT ;3.30 + EXTRN MSGOUT:NEAR,MSGNUM:NEAR ;3.30 + ENDIF ;3.30 + IFNDEF NUMBUF ;3.30 + EXTRN NUMBUF:BYTE,DIGITS:BYTE,FTESTBITS:WORD ;3.30 + ENDIF ;3.30 + IFNDEF DUMPBYTES ;3.30 + EXTRN DUMPBYTES:NEAR,OUTCHAR:NEAR,HEX_TO_ASCII:NEAR ;3.30 + ENDIF ;3.30 + + + +fTestALL equ 1111111111111111b ; watch everything +fTestHARD equ 0000000000000001b ; watch hard disk initialization +fTest96 equ 0000000000000010b ; watch 96 tpi activity +FTEST13 EQU 0000000000000100B ; WATCH INT 13 ACTIVITY ;3.30 +FTESTCOM EQU 0000000000001000B ; WATCH PACKET ACTIVITY ;3.30 +FTESTINIT EQU 0000000000010000B ; WATCH INITIALIZATION MESSAGES ;3.30 +FTESTDISK EQU 0000000000100000B ; WATCH DISK DEVICE DRIVER CALLS ;3.30 +FTESTCON EQU 0000000001000000B ; WATCH SYSTEM WAIT ACTIVITY IN CO;3.30 NSOLE +FtestClock equ 0000000010000000b ; wathc clock device 5/2/86 ;3.30 + + +; +; message macro -- see above for description +; + +MESSAGE MACRO Bits,msg + LOCAL A,B ;3.30 + jmp SHORT b +a: db msg,0 +b: push SI + push AX + mov AX,Bits + mov SI,OFFSET a + call MSGOUT + pop AX + pop SI +endm + + +; +; mnum macro -- see above for description +; + +MNum MACRO Bits,num + push AX +ifb + mov AX,Bits + call MSGNUM +else + push BX + mov BX,num + mov AX,Bits + call MSGNUM + pop BX +endif + pop AX +endm + + +; +; zwait macro -- see above for description +; + +ZWAIT MACRO + Message fTestALL,<"? "> + CALL ZWAITrtn +ENDM + +ZWAITrtn: + pushf ; save the flags + push AX ; preserve AX + xor AH, AH ; set command to get character ;3.30* + int 16h ; call rom keyboard routine ;3.30* + pop AX ; restore AX + popf ; restore the flags + ret + +;Dump_byte dumps the memory contents in hex. ;3.30 +;DUMPOFFLABEL should be a label or a variable defined in DUMPSEG. ;3.30 +DUMP_BYTE MACRO DUMPSEG, DUMPOFFLABEL, BYTELENGTH ;3.30 + push es ;3.30 + PUSH DS ;3.30 + PUSH SI ;3.30 + PUSH CX ;3.30 + ;3.30 + MOV CX, DUMPSEG ;3.30 + MOV DS, CX ;3.30 + MOV SI, OFFSET DUMPOFFLABEL ;3.30 + MOV CX, BYTELENGTH ;3.30 + call dumpbytes ;3.30 + ;3.30 + POP CX ;3.30 + POP SI ;3.30 + POP DS ;3.30 + pop es ;3.30 + ENDM ;3.30 + ;3.30 +;Dump_Byte_Reg dumps the memory contents in hex. - 4/9/86 ;3.30 +;DUMPOFFREG should be a register contains the offset value in DUMPSEG. ;3.30 +DUMP_BYTE_REG MACRO DUMPSEG, DUMPOFFREG, BYTELENGTH ;3.30 + push es ;3.30 + PUSH DS ;3.30 + PUSH SI ;3.30 + PUSH CX ;3.30 + ;3.30 + MOV CX, DUMPSEG ;3.30 + MOV DS, CX ;3.30 + MOV SI, DUMPOFFREG ;3.30 + MOV CX, BYTELENGTH ;3.30 + call dumpbytes ;3.30 + ;3.30 + POP CX ;3.30 + POP SI ;3.30 + POP DS ;3.30 + pop es ;3.30 + ENDM ;3.30 + +else + ; if test is not defined then make macro into null statements +Message macro +ENDM + +MNUM macro +ENDM + +ZWAIT macro +ENDM + +DUMP_BYTE MACRO ;3.30 + ENDM ;3.30 +DUMP_BYTE_REG MACRO ;3.30 + ENDM ;3.30 + ENDIF ;3.30 + ;3.30 +PATHSTART MACRO INDEX,ABBR ;3.30 + IFDEF PATHGEN ;3.30 + PUBLIC ABBR&INDEX&S,ABBR&INDEX&E ;3.30 + ABBR&INDEX&S LABEL BYTE ;3.30 + ENDIF ;3.30 + ENDM ;3.30 + ;3.30 +PATHEND MACRO INDEX,ABBR ;3.30 + IFDEF PATHGEN ;3.30 + ABBR&INDEX&E LABEL BYTE ;3.30 + ENDIF ;3.30 + ENDM ;3.30 + diff --git a/SRC/BIOS/MSSTACK.INC b/SRC/BIOS/MSSTACK.INC new file mode 100644 index 0000000..a6908ce --- /dev/null +++ b/SRC/BIOS/MSSTACK.INC @@ -0,0 +1,306 @@ +; MSStack.inc +; +; Interrupt level 2, 3, 4, 5, 6, 7,(10, 11, 12, 14, 15 - AT level) +; should follow the standard Interrupt Sharing Scheme which has +; a standard header structure. +; Fyi, the following shows the relations between +; the interrupt vector and interrupt level. +; VEC(Hex) 2 8 9 A B C D E 70 72 73 74 76 77 +; LVL(Deci) 9 0 1 2 3 4 5 6 8 10 11 12 14 15 +; MSSTACK module modifies the following interrupt vectors +; to meet the standard Interrupt Sharing standard; +; A, B, C, D, E, 72, 73, 74, 76, 77. +; Also, for interrupt level 7 and 15, the FirstFlag in a standard header +; should be initialized to indicat whether this interrupt handler is +; the first (= 80h) or not. The FirstFlag entry of INT77h's +; program header is initialized in STKINIT.INC module. +; FirstFlag is only meaningful for interrupt level 7 and 15. +; + +; User specifies the number of stack elements - default = 9 +; minimum = 8 +; maximum = 64 +; +; Intercepts Asynchronous Hardware Interrupts only +; +; Picks a stack from pool of stacks and switches to it +; +; Calls the previously saved interrupt vector after pushing flags +; +; On return, returns the stack to the stack pool +; + + +; This is a modification of STACKS: +; 1. To fix a bug which was causing the program to take up too much space. +; 2. To dispense stack space from hi-mem first rather than low-mem first. +; . Clobbers the stack that got too big instead of innocent stack +; . Allows system to work if the only stack that got too big was the most +; deeply nested one +; 3. Disables NMI interrupts while setting the NMI vector. +; 4. Does not intercept any interupts on a PCjr. +; 5. Double checks that a nested interrupt didn't get the same stack. +; 6. Intercepts Ints 70, 72-77 for PC-ATs and other future products + +;The following variables are for MSSTACK.inc + EVEN + dw 0 ; SPARE FIELD BUT LEAVE THESE IN ORDER +StackCount dw 0 +StackAt dw 0 +StackSize dw 0 +Stacks dw 0 + dw 0 + +FirstEntry dw Stacks +LastEntry dw Stacks+(DefaultCount*EntrySize)-EntrySize +NextEntry dw Stacks+(DefaultCount*EntrySize)-EntrySize + +;End of variables defined for MSSTACK. + +;******************************************************************* +;Macro Interrupt handler for the ordinary interrupt vectors and +;the shared interrupt vectors. +;***************************** +Stack_Main MACRO AA + ASSUME DS:NOTHING + ASSUME ES:NOTHING + ASSUME SS:NOTHING +PUBLIC Int&AA +PUBLIC Old&AA +;----------------------------- + ife IntSharingFlag ;if not IntSharingFlag +;----------------------------- + Old&AA DD 0 +Int&AA PROC FAR +;----------------------------- + else ;for shared interrupt. A Header exists. + +PUBLIC FirstFlag&AA +Int&AA PROC FAR + jmp short Entry_Int&AA&_Stk + Old&AA dd 0 ;Forward pointer + dw 424Bh ;compatible signature for Int. Sharing + FirstFlag&AA db 0 ;the firstly hooked. + jmp short Intret_&AA ;Reset routine. We don't care this. + db 7 dup (0) ;Reserved for future. +Entry_Int&AA&_Stk: +;----------------------------- + endif +;----------------------------- + +; +; Keyboard interrupt must have a three byte jump, a NOP and a zero byte +; as its first instruction for compatibility reasons + ifidn <&aa>,<09> + jmp Keyboard_lbl + nop + db 0 +Keyboard_lbl label near + endif + +; This patches INTERRUPT 75h to be "unhooked". We do this Wierdness, +; rather than never hooking INT 75h, to maintain maximum compat. with IBMs +; post production patch. + push ax + + ifidn <&aa>,<02> + +; ********************************************************************* +; +; This is special support for the P12 / NMI handler +; +; On the P12, there is a situation where an NMI can be caused by +; using the "OUT" instructions to certain ports. When this +; occurs, the P12 hardware *GUARANTEES* that **NOTHING** can stop +; the NMI or interfere with getting to the NMI handler. This +; includes other type of interrupts (hardware and software), and +; also includes other type of NMI's. When any NMI has occured, +; no other interrtupt (hardware, software or NMI) can occur until +; the software takes specific steps to allow further interrupting. +; +; For P12, the situation where the NMI is generated by the "OUT" +; to a control port requires "fixing-up" and re-attempting. In +; otherwords, it is actually a "restartable exception". In this +; case, the software handler must be able to get to the stack in +; order to figure out what instruction caused the problem, where +; it was "OUT"ing to and what value it was "OUT"ing. Therefore, +; we will not switch stacks in this situation. This situation is +; detected by interrogating port 62h, and checking for a bit value +; of 80h. If set, *****DO NOT SWITCH STACKS*****. +; +; ********************************************************************* + + push es + mov ax,0f000h + mov es,ax + cmp byte ptr es:[0fffeh],0f9h ;check if P12 + pop es + jne Normal&aa + + in al,62h + test al,80h + jz Normal&aa + +Special&aa: + pop ax + jmp dword ptr Old&aa + +Normal&aa: + +; ********************************************************************* + + endif + + push bp + push es + mov es, cs:[STACKS+2] ; Get segment of stacks + + mov bp,NextEntry ; get most likely candidate + mov al,Allocated + xchg AllocByte,al ; grab the entry + cmp al,Free ; still avail? + jne NotFree&aa + + sub NextEntry,EntrySize ; set for next interrupt + +Found&aa: + mov SavedSP,sp ; save sp value + mov SavedSS,ss ; save ss also +; mov IntLevel,aa&h ; save the int level + + mov ax,bp ; temp save of table offset + + mov bp,NewSP ; get new SP value + cmp es:[bp],ax ; check for offset into table + jne FoundBad&aa + + mov ax,es ; point ss,sp to the new stack + mov ss,ax + mov sp,bp + + pushf ; go execute the real interrupt handler + call dword ptr old&aa ; which will iret back to here + + mov bp,sp ; retrieve the table offset for us + mov bp,es:[bp] ; but leave it on the stack + mov ss,SavedSS ; get old stack back + mov sp,SavedSP + +; cmp AllocByte,Allocated ; If an error occured, +; jne NewError&aa ; do not free us + + mov AllocByte,Free ; free the entry + mov NextEntry,bp ; setup to use next time + +NewError&aa: + pop es + pop bp ; saved on entry + pop ax ; saved on entry + +INTRET_&AA: ;3.30 + iret ; done with this interrupt + +NotFree&aa: + cmp al,Allocated ; error flag + je findnext&aa ; no, continue + xchg AllocByte,al ; yes, restore error value + +FindNext&aa: + call LongPath + jmp Found&aa + +FoundBad&aa: + cmp bp,FirstEntry + jc findnext&aa + mov bp,ax ; flag this entry + mov AllocByte,Clobbered +; add bp,EntrySize ; and previous entry +; mov AllocByte,Overflowed +; sub bp,EntrySize + jmp findnext&aa ; keep looking + +int&aa endp + + + endm + +;***************************** ;3.30 +;End of Macro definition ;3.30 +;******************************************************************** ;3.30 +; THESE ARE THE INDIVIDUAL INTERRUPT HANDLERS ;3.30 + ;3.30 + IRP A,<02,08,09,70> ;3.30 + IntSharingFlag=0 ;3.30 + Stack_Main &A ;3.30 + ENDM ;3.30 + ;3.30 + IRP A,<0A,0B,0C,0D,0E,72,73,74,76,77> ;3.30 + IntSharingFlag=1 ;3.30 + Stack_Main &A ;3.30 + ENDM ;3.30 + ;3.30 +;******************************************************************** ;3.30 +;Common routines ;3.30 + +longpath: + mov bp,LastEntry ; start with last entry in table + +LPLOOPP: ;3.30 + cmp AllocByte,Free ; is entry free? + jne inuse ; no, try next one + + mov al,Allocated + xchg AllocByte,al ; allocate entry + cmp al,Free ; is it still free? + je found ; yes, go use it + + cmp al,Allocated ; is it other than Allocated or Free? + je inuse ; no, check the next one + + mov AllocByte,al ; yes, put back the error state + +inuse: + cmp bp,FirstEntry + je Fatal + sub bp,EntrySize + JMP LPLOOPP ;3.30 + +found: + ret + + page + +fatal proc near + push ds ;3.30 + mov ax, 0f000h ;loook at the model byte ;3.30 + mov ds, ax ;3.30 + cmp ds:byte ptr [0fffeh], 0f9h ;convertible ;3.30 + pop ds ;3.30 + jne Skip_NMIS ;3.30 + ;3.30 + mov al,07h ; disable p12 NMIs + out 72h,al + +Skip_NMIS: ;3.30 + cli ; disable and mask + mov al,0ffh ; all other ints + out 021h,al + out 0a1h,al + + mov si,cs + mov ds,si + mov si,offset fatal_msg + +fatal_loop: + lodsb + cmp al,'$' + je fatal_done + + mov bl,7 ;3.30* + mov ah,14 ;3.30* + int 010h ; whoops, this enables ints ;3.30* + jmp fatal_loop + +fatal_done: + jmp fatal_done +fatal endp diff --git a/SRC/BIOS/MSVOLID.INC b/SRC/BIOS/MSVOLID.INC new file mode 100644 index 0000000..d1a9588 --- /dev/null +++ b/SRC/BIOS/MSVOLID.INC @@ -0,0 +1,297 @@ +;------------------------------------------------------------------------- +; +; File: msvolid.asm +; This file contains the volume_id subroutines and data structures. +; +; Routines in this file are: +; Set_Volume_ID - main routine, calls other routines. +; read_volume_id - read the volume ID and tells if it has +; been changed. +; Transfer_volume_id - copy the volume ID from TMP to special +; drive. +; Check_Volume_ID - compare volume ID in TMP area with one +; expected for drive. +; Fat_Check - see of the fatID has changed in the +; specified drive. +; Init_Vid_loop - set up for VID scan or move +; +; +;------------------------------------------------------------------------- + +; +; length of the volume id +; + +vid_size equ 12 + + PATHSTART 001,VOLID ;3.30 + +; +; null volume id +; + +nul_vid db "NO NAME ",0 + +; +; data scratch area used to hold volume ids +; + +tmp_vid db "NO NAME ",0 + + PATHEND 001,VOLID ;3.30 + +; +; Set_Volume_ID +; If drive has changeline support, read in and set the volume_ID +; and the last FAT_ID byte. If no change line support then do nothing. +; +; On entry: +; DS:DI points to the BDS for this disk. +; AH contains media byte +; +; On Exit: +; Carry clear: +; Successful call +; Carry set +; Error and AX has error code +; + +Set_Volume_ID: + PUBLIC SET_VOLUME_ID ;3.30 + push dx ; save registers + push ax + CALL HasChange ; does drive have changeline support? + jz setvret ; no, get out + push di + call read_volume_ID ; read the volume ID + pop di + jc SetErr ; if error go to error routine + call transfer_volume_ID ; copy the volume id to special drive + call ResetChanged ; restore value of change line + +setvret: ; SET Volume RETurn + clc ; no error, clear carry flag + pop ax ; restore registers + pop dx + ret +SetErr: + pop dx ; pop stack but don't overwrite AX + pop dx ; restore DX + ret + + + +root_sec DW ? ;Root sector # + + + + +; +; read_volume_id read the volume ID and tells if it has been changed. +; +; On entry: +; DS:DI points to current BDS for drive. +; On Exit: +; Carry Clear +; SI = 1 No change +; SI = 0 ? +; SI = -1 Change +; +; Carry Set: +; Error and AX has error code. +; + +read_volume_id: + push ES ; preserve registers + push DX + push CX + push BX + push AX + push DS ; Preserve Current BDS + push DI + push cs ; get ES segment correct + pop es + push cs ; get DS segment correct + pop ds + mov di,offset tmp_vid + mov si,offset nul_vid + mov cx,vid_size + rep movsb ; initialize tmp_vid to null vi_id + + pop DI ; Restore Current BDS + pop DS + mov al,byte ptr ds:[di].cFAT ; # of fats + mov cx,word ptr ds:[di].csecfat ; sectors / fat + mul cl ; size taken by fats + add ax,word ptr ds:[di].ressec ; add on reserved sectors + ; AX is now sector # (0 based) + mov cs:[root_sec],ax ; set initial value + mov ax,[di].cDir ; # root dir entries + mov cl,4 ; 16 entries/sector + shr ax,cl ; divide by 16 + mov cx,ax ; cx is # of sectors to scan +next_sec: + push cx ; save outer loop counter + mov ax,cs:[root_sec] ; get sector # + mov cx,word ptr ds:[di].seclim ; sectors / track + xor DX,DX + div cx + ; set up registers for call to read_sector + inc DX ; dx= sectors into track, ax= track count from 0 + mov cl,dl ; sector to read + xor DX,DX + div word ptr ds:[di].hdlim ; # heads on this disc + mov dh,dl ; Head number + mov ch,al ; Track # + call read_sector ; get first sector of the root directory, + ; ES:BX -> BOOT + jc ReadVIDErr ; error on read + mov cx,16 ; # of dir entries in a block of root + mov al,08h ; volume label bit +fvid_loop: + cmp byte ptr es:[bx],0 ; End of dir? + jz no_vid ; yes, no vol id + cmp byte ptr es:[bx],0E5h ; empty entry? + jz ent_loop ; yes, skip + test es:[bx+11],al ; is volume label bit set in fcb? + jnz found_vid ; jmp yes +ent_loop: + ADD BX,32 ;MJB003 ADD LENGTH OF DIRECTORY ENTRY ;3.30 + loop fvid_loop + pop cx ; outer loop + inc cs:[root_sec] ; next sector + loop next_sec ; continue +NotFound: + XOR SI,SI + jmp short fvid_ret + +found_vid: + pop cx ; clean stack of outer loop counter + mov si,bx ; point to volume_id + push ds ; preserve currnet BDS + push di + push es ; es:si points to volume id. + pop ds ; source segment + push cs + pop es ; destination segment + mov di,offset tmp_vid ; dest of volume_id + mov cx,vid_size -1 ; length of string minus NUL + rep movsb ; mov volume label to tmp_vid + xor al,al + stosb ; Null terminate + XOR SI,SI + pop DI ; restore current BDS + pop DS +fvid_ret: + pop ax + clc +RVIDRet: + pop BX ; restore register + pop CX + pop DX + pop ES + ret +no_vid: + pop cx ; clean stack of outer loop counter + jmp NotFound ; not found +ReadVIDErr: + pop SI + pop SI + jmp RVIDRet + + + +; +; Transfer_volume_id - copy the volume ID from TMP to special drive +; +; Inputs: DS:DI nas current BDS +; Outputs: BDS for drive has volume ID from TMP +; + +transfer_volume_ID: + push DS ; preserve current BDS + push DI + push ES + push SI + push CX + call init_vid_loop + cld + rep MOVSB ; transfer + pop CX + pop SI + pop ES + pop DI ; restore current BDS + pop DS + ret + + +; +; Check_Volume_ID - compare volume ID in TMP area with one expected for +; drive +; +; Inputs: DS:DI has current BDS for drive +; Outputs: SI = 0 if compare succeeds +; SI = -1 if compare fails. + +check_volume_id: + push DS ; preserve current BDS for drive + push DI + push ES + push CX + call init_vid_loop + cld + repz cmpsb ; are the 2 volume_ids the same? + mov si,0 ; assume unknown + jz check_vid_ret ; carry clear if jump taken + mov si,-1 ; failure +check_vid_ret: + pop CX + pop ES + pop DI ; restore current BDS + pop DS + ret + +; +; Fat_Check - see of the fatID has changed in the specified drive. +; - uses the FAT ID obtained from the boot sector. +; +; Inputs: MedByt is expected FAT ID +; DS:DI points to current BDS +; Output: Carry Clear +; SI = -1 if fat ID different, +; SI = 0 otherwise +; No other registers changed. + +FAT_CHECK: + push AX + xor SI, SI ; say FAT ID's are same. + mov AL, cs:MedByt + cmp AL, byte ptr [DI].Mediad ; compare it with the BDS medbyte + jz OKRET1 ; carry clear + dec SI +OkRet1: clc + pop AX + ret + + +; +; Init_Vid_loop - set up for VID scan or move +; +; Inputs: DS:DI pionts to BDS for the drive +; Outputs: DS:SI points to tmp_vid +; ES:DI points to vid for drive +; CX has size for VID compare +; + +init_vid_loop: + push ax + push ds + pop es + push cs + pop ds + mov si,offset tmp_vid ; source + add di,volid + mov cx,vid_size + pop ax + ret + diff --git a/SRC/BIOS/PUSHPOP.INC b/SRC/BIOS/PUSHPOP.INC new file mode 100644 index 0000000..aaa76eb --- /dev/null +++ b/SRC/BIOS/PUSHPOP.INC @@ -0,0 +1,20 @@ + IF1 ;3.30 + +SaveReg MACRO reglist ;; push those registers +IRP reg, + ?stackdepth = ?stackdepth + 1 + PUSH reg +ENDM +ENDM +.xcref SaveReg + + +RestoreReg MACRO reglist ;; pop those registers +IRP reg, + ?stackdepth = ?stackdepth - 1 + POP reg +ENDM +ENDM +.xcref RestoreReg + + ENDIF ;3.30 diff --git a/SRC/BIOS/READCLOC.INC b/SRC/BIOS/READCLOC.INC new file mode 100644 index 0000000..545a22f --- /dev/null +++ b/SRC/BIOS/READCLOC.INC @@ -0,0 +1,162 @@ +; SCCSID = @(#)readclock.asm 1.2 85/07/25 +;************************************************************************ +; +; read_real_date reads real-time clock for date and returns the number +; of days elapsed since 1-1-80 in si +; +read_real_date: ;mjb002 + PUSH AX + PUSH CX + PUSH DX + XOR AH,AH ; throw away clock roll over ;3.30* + INT 1AH ;3.30* + POP DX + POP CX + POP AX + + PUSH AX + PUSH BX + PUSH CX + PUSH DX + MOV CS:DAYCNT2,1 ;MJB002 REAL TIME CLOCK ERROR FLAG (+1 DA;3.30Y) + mov ah,4 ;mjb002 read date function code ;3.30* + int 1ah ;mjb002 read real-time clock ;3.30* + jnc read_ok ;mjb002 jmp success + jmp r_d_ret ;mjb002 jmp error +read_ok: ;mjb002 ******* get bcd values in binary ***** + mov byte ptr bin_date_time+0,ch ;mjb002 store as hex value + mov byte ptr bin_date_time+1,cl ;mjb002 ... + mov byte ptr bin_date_time+2,dh ;mjb002 ... + mov byte ptr bin_date_time+3,dl ;mjb002 ... + MOV CS:DAYCNT2,2 ;MJB002 READ OF R-T CLOCK SUCCESSFUL ;3.30 + call bcd_verify ;mjb002 verify bcd values in range + jc r_d_ret ;mjb002 jmp some value out of range + MOV CS:DAYCNT2,3 ;MJB002 READ OF R-T CLOCK SUCCESSFUL ;3.30 + call date_verify ;mjb002 verify date values in range + jc r_d_ret ;mjb002 jmp some value out of range + MOV CS:DAYCNT2,0 ;MJB002 VERIFY SUCCESSFUL ;3.30;3.30 + call in_bin ;mjb002 convert date to binary + ;mjb002 ******* years since 1-1-80 ********* + mov al,byte ptr bin_date_time+1 ;mjb002 get years into century + cbw ;mjb002 + cmp byte ptr bin_date_time+0,20 ;mjb002 20th century? + jnz century_19 ;mjb002 jmp no + add ax,100 ;mjb002 add in a century +century_19: ;mjb002 + sub ax,80 ;mjb002 subtract off 1-1-80 + mov cl,4 ;mjb002 leap year every 4 + div cl ;mjb002 al= # leap year blocks, ah= remainder + mov bl,ah ;mjb002 save odd years + cbw ;mjb002 zero ah + mov cx,366+3*365 ;mjb002 # of days in leap year blocks + mul cx ;mjb002 dx:ax is result + MOV CS:DAYCNT2,AX ;MJB002 SAVE COUNT OF DAYS ;3.30 + mov al,bl ;mjb002 get odd years count + cbw ;mjb002 + or ax,ax ;mjb002 is ax= 0? + jz leap_year ;mjb002 jmp if none + mov cx,365 ;mjb002 days in year + mul cx ;mjb002 dx:ax is result + ADD CS:DAYCNT2,AX ;MJB002 ADD ON DAYS IN ODD YEARS ;3.30 + jmp short leap_adjustment ;mjb002 account for leap year +leap_year: ;mjb002 possibly account for a leap day + cmp byte ptr bin_date_time+2,2 ;mjb002 is month february + jbe no_leap_adjustment ;mjb002 jan or feb. no leap day yet. +leap_adjustment: ;mjb002 account for leap day + INC CS:DAYCNT2 ;MJB002 ... ;3.30 +no_leap_adjustment: ;mjb002 ******* get days of month ******* + mov cl,byte ptr bin_date_time+3 ;mjb002 ... + xor ch,ch ;mjb002 + dec cx ;mjb002 because of offset from day 1, not day 0 + ADD CS:DAYCNT2,CX ;MJB002 ******* GET DAYS IN MONTHS PRECEE;3.30DING ***** + mov cl,byte ptr bin_date_time+2 ;mjb002 get month + xor ch,ch ;mjb002 + dec cx ;mjb002 january starts at offset 0 + shl cx,1 ;mjb002 word offset + mov si,offset month_table ;mjb002 beginning of month_table + add si,cx ;mjb002 point into month table + mov ax,word ptr [si];mjb002 get # days in previous months + ADD CS:DAYCNT2,AX ;MJB002 ... ;3.30 +r_d_ret: ;mjb002 + MOV SI,CS:DAYCNT2 ;MJB002 RESULT IN SI ;3.30 + POP DX + POP CX + POP BX + POP AX + ret ;mjb002 + +r_t_retj: + xor cx,cx + xor dx,dx + jmp r_t_ret +; +; Read_Real_Time reads the time from the RTC. on exit, it has the number of +; ticks (at 18.2 ticks per sec.) in CX:DX. +; +Read_Real_Time: + mov ah,2 ;3.30* + int 1AH ;3.30* + jc r_t_retj +oktime: + mov byte ptr bin_date_time,ch ; hours + mov byte ptr bin_date_time+1,cl ; minutes + mov byte ptr bin_date_time+2,dh ; seconds + mov byte ptr bin_date_time+3,0 ; unused for time + call bcd_verify + jc r_t_retj + call time_verify + jc r_t_retj + call in_bin + MOV ch,byte ptr bin_date_time + MOV cl,byte ptr bin_date_time+1 + MOV dh,byte PTR bin_date_time+2 + MOV dl,byte PTR bin_date_time+3 + message ftestinit,<"Read Time "> + mnum ftestinit,cx + message ftestinit,<" "> + mnum ftestinit,dx + message ftestinit, +; get time in ticks in CX:DX + CALL word ptr cs:TimeToTicks ;3.30 + message ftestinit,<"Conv Time "> + mnum ftestinit,cx + message ftestinit,<" "> + mnum ftestinit,dx + message ftestinit, +r_t_ret: + ret + +; +; in_bin converts bin_date_time values from bcd to bin +; +in_bin: ;mjb002 + mov al,byte ptr bin_date_time+0 ; century or hours + call bcd_to_bin ; ... + mov byte ptr bin_date_time+0,al ; + mov al,byte ptr bin_date_time+1 ; years or minutes + call bcd_to_bin ; ... + mov byte ptr bin_date_time+1,al ; + mov al,byte ptr bin_date_time+2 ; months or seconds + call bcd_to_bin ; ... + mov byte ptr bin_date_time+2,al ; + mov al,byte ptr bin_date_time+3 ; days (not used for time) + call bcd_to_bin ; ... + mov byte ptr bin_date_time+3,al ; + ret ; +; +; bcd_to_bin converts two bcd nibbles in al (value <= 99.) to +; a binary representation in al +; ah is destroyed +; +bcd_to_bin: ;mjb002 + mov ah,al ;mjb002 copy bcd number to ah + and ax,0f00fh ;mjb002 clear unwanted nibbles + mov bl,al ;mjb002 save units place + xchg ah,al ;mjb002 10's place to al + xor ah,ah ;mjb002 ah not wanted + mov cl,4 ;mjb002 shift count + shr ax,cl ;mjb004 swap nibbles + mov cl,10 ;mjb002 convert al to ... + mul cl ;mjb002 ... its binary value + add al,bl ;mjb002 add in units + ret ;mjb002 diff --git a/SRC/BIOS/STKINIT.INC b/SRC/BIOS/STKINIT.INC new file mode 100644 index 0000000..4c8e20f --- /dev/null +++ b/SRC/BIOS/STKINIT.INC @@ -0,0 +1,270 @@ +; +; To follow the standard interrupt sharing scheme, MSSTACK.ASM ;3.30 +; has been modified. This initialization routine also has to ;3.30 +; be modified because for the interrupt level 7 and 15, FirstFlag ;3.30 +; should be set to signal that this interrupt handler is the ;3.30 +; first handler hooked to this interrupt vector. ;3.30 +; We determine this by looking at the instruction pointed by ;3.30 +; this vector. If it is IRET, then this handler should be the ;3.30 +; first one. In our case, only the interrupt vector 77h is the ;3.30 +; interrupt level 15. (We don't hook interrupt level 7.) ;3.30 +; 9/10/1986 ;3.30 +; The followings are mainly due to M.R.Turner; PTM fix of P886 12/3/86 ;3.30 +; Some design changes are needed to the above interrupt sharing ;3.30 +; method. The above sharing scheme assumes that 1). Interrupt ;3.30 +; sharing is NEVER done on levels that have BIOS support. 2). "Phantom" ;3.30 +; interrupts would only be generated on levels 7 and 15. ;3.30 +; These assumptions are not true any more. We have to use the FirstFlag ;3.30 +; for EVERY level of interrupt. We will set the firstFlag on the following;3.30 +; conditions: ;3.30 +; a. if the CS portion of the vector is 0000, then "first" ;3.30 +; b. else if CS:IP points to valid shared header, then NOT "first" ;3.30 +; c. else if CS:IP points to an IRET, then "first" ;3.30 +; d. else if CS:IP points to DUMMY, then "first" ;3.30 +; where DUMMY is - the CS portion must be F000, and the IP portion must ;3.30 +; be equal to the value at F000:FF01. This location is the initial value ;3.30 +; from VECTOR_TABLE for interrupt 7, one of the preserved addresses in all;3.30 +; the BIOSes for all of the machines. ;3.30 +; ;3.30 +; System design group requests BIOS to handle the phantom interrupts. ;3.30 +; ;3.30 +; The "Phantom" interrupt is an illegal interrupt such as an interrupt ;3.30 +; produced by the bogus adapter card even without interrupt request is ;3.30 +; set. More specifically, 1). The 8259 has a feature when running in ;3.30 +; edge triggered mode to latch a pulse and present the interrupt when ;3.30 +; the processor indicates interrupt acknowledge (INTA). The interrupt ;3.30 +; pulse was exist at the time of INTA to get a "phantom" interrupt. ;3.30 +; 2). or, this is caused by adapter cards placing a glitch on the ;3.30 +; interrupt line. ;3.30 +; ;3.30 +; To handle those "phantom" interrupts, the main stack code will check ;3.30 +; the own FirstFlag, and if it is not "first" (which means the forward ;3.30 +; pointer points to the legal shared interrupt handler), then pass the ;3.30 +; control. If it is the first, then the following action should be ;3.30 +; taken. We don't have to implement skack logic in this case. ;3.30 +; ;3.30 +; To implement this logic, we rather choose a simple method. ;3.30 +; If ont of the above "FirstFlag" conditions is met, we are not ;3.30 +; going to hook this interrupt vector. The reason is if the original ;3.30 +; vector points to "IRET" and do nothing, we don't need ;3.30 +; to implement the stack logic for it. This will simplify implementation;3.30 +; while maintaining compatibility with the old version of DOS. ;3.30 +; This implies that in the main stack code, there might be a stack code ;3.30 +; that will never be used, a dead code. ;3.30 +; ;3.30 +; 12/3/86 ;3.30 + ;3.30 +;In - CS, DS -> sysinitseg, ES -> relocated stack code & data. ;3.30 + ;3.30 + PAGE ;3.30 +StackInit proc near ;3.30 + ;3.30 + PUSH AX ;SAVE ALL ;3.30 + PUSH DS ;3.30 + PUSH ES ;3.30 + PUSH BX ;3.30 + PUSH CX ;3.30 + PUSH DX ;3.30 + PUSH DI ;3.30 + PUSH SI ;3.30 + PUSH BP ;3.30 + ;3.30 +;Currently ES -> stack code area ;3.30 + MOV AX, cs:[STACK_COUNT] ;defined in CS ;3.30 + MOV es:[STACKCOUNT], AX ;defined in STACK CODE AREA ;3.30 + MOV AX, [STACK_SIZE] ;in CS ;3.30 + MOV es:[STACKSIZE], AX ; ;3.30 + MOV AX, WORD PTR cs:[STACK_ADDR] ; OFFSET ;3.30 + MOV WORD PTR es:[STACKS], AX ;3.30 + MOV AX, WORD PTR cs:[STACK_ADDR+WORD] ; SEGMENT ;3.30 + MOV WORD PTR es:[STACKS+WORD], AX ;3.30 + ;3.30 +; INITIALIZE THE DATA FIELDS WITH THE PARAMETERS ;3.30 + ;3.30 +; "FIRSTENTRY" WILL ALWAYS BE AT STACKS ;3.30 + ;3.30 + MOV BP, word ptr es:STACKS ; GET OFFSET OF STACK ;3.30 + MOV es:FIRSTENTRY,BP ;3.30 + ;3.30 +; THE STACKS WILL ALWAYS IMMEDIATELY FOLLOW THE TABLE ENTRIES ;3.30 + ;3.30 + MOV AX,ENTRYSIZE ;3.30 + MOV CX,es:STACKCOUNT ;3.30 + MUL CX ;3.30 + ADD AX,BP ;3.30 + MOV es:STACKAT,AX ;3.30 + MOV BX,AX ;3.30 + SUB BX,2 ;3.30 + ;3.30 +; ZERO THE ENTIRE STACK AREA TO START WITH ;3.30 + ;3.30 + MOV DI,es:STACKAT ;3.30 + MOV AX,es:STACKSIZE ;3.30 + MUL CX ;3.30 + MOV CX,AX ;3.30 + xor ax,ax ;3.30 + push es ;3.30 + pop ds ;ds = Relocated stack code seg.;3.30 + assume ds:nothing ;3.30 +;Now, DS -> stack code area ;3.30 + MOV ES, word ptr ds:[STACKS+2] ; GET SEGMENT OF STACK AREA.;3.30 + CLD ;3.30 + REP STOSB ;3.30 + ;3.30 + MOV CX, ds:STACKCOUNT ;3.30 + ;3.30 +; LOOP FOR "COUNT" TIMES, BUILDING A TABLE ENTRY ;3.30 +; cs = sysinitseg, ds = Relocated stack code seg , es = segment of stack space;3.30 +; CX = NUMBER OF ENTRIES ;3.30 +; ES:BP => BASE OF STACKS - 2 ;3.30 +; ES:BX => FIRST TABLE ENTRY ;3.30 + ;3.30 +BUILDLOOP: ;3.30 + MOV ALLOCBYTE,FREE ;3.30 + MOV INTLEVEL,AL ;AX = 0 ;3.30 + MOV SAVEDSP,AX ;3.30 + MOV SAVEDSS,AX ;3.30 + ADD BX,ds:STACKSIZE ;3.30 + MOV NEWSP,BX ;3.30 + MOV ES:[BX],BP ;3.30 + ADD BP,ENTRYSIZE ;3.30 + ;3.30 + LOOP BUILDLOOP ;3.30 + ;3.30 + SUB BP,ENTRYSIZE ;3.30 + MOV ds:LASTENTRY,BP ;3.30 + MOV ds:NEXTENTRY,BP ;3.30 + ;3.30 + push ds ;3.30 + mov ax, 0f000h ;loook at the model byte ;3.30 + mov ds, ax ;3.30 + cmp ds:byte ptr [0fffeh], 0f9h ;convertible?(P12) ;3.30 + pop ds ;3.30 + jne Skip_disableNMIS ;3.30 + ;3.30 + MOV AL,07H ; DISABLE P12 NMIS ;3.30 + OUT 72H,AL ;3.30 + ;3.30 +Skip_disableNMIS: ;3.30 + XOR AX,AX ;3.30 + MOV es,AX ;es - SEGID OF VECTOR TABLE AT 0;3.30 + ASSUME es:NOTHING ;ds - Relocated Stack code segment;3.30 + ;3.30 + CLI ;3.30 + ;3.30 + IRP AA,<02,08,09,70> ;3.30 + ;3.30 + MOV SI,AA&H*4 ;PASS WHERE VECTOR IS TO BE ADJUSTED ;3.30 + mov di, offset Int19OLD&AA ;we have to set OLD&AA for Int19 handler too.;3.30 + MOV BX,OFFSET OLD&AA ;PASS WHERE TO SAVE ORIGINAL OWNER POINTER;3.30 + MOV DX,OFFSET INT&AA ;PASS WHERE NEW HANDLER IS ;3.30 + CALL NEW_INIT_LOOP ;ADJUST THE VECTOR TO NEW HANDLER, ;3.30 + ; SAVING POINTER TO ORIGINAL OWNER ;3.30 + ENDM ;3.30 + ;3.30 + IRP AA,<0A,0B,0C,0D,0E,72,73,74,76,77> ;shared interrupts ;3.30 + ;3.30 + MOV SI,AA&H*4 ;PASS WHERE VECTOR IS TO BE ADJUSTED ;3.30 + push ds ;save relocated stack code segment ;3.30 + lds bx, es:[si] ;ds:bx -> original interrupt handler ;3.30 + push ds ;3.30 + pop dx ;dx = segment value ;3.30 + + cmp dx,0 + jz int&AA&_first + + cmp byte ptr ds:[bx],0cfh ;Does vector point to an IRET? + jz int&AA&_first + + cmp word ptr ds:[bx.6],424Bh ;Magic offset (see INT&AA, msstack.inc) + jz int&AA&_Not_first + + cmp dx,0f000h ;ROM BIOS segment + jnz int&AA&_Not_first + + push es + push dx + mov dx,0f000h + mov es,dx + cmp bx,word ptr es:0ff01h + pop dx + pop es + jz int&AA&_first + +int&AA&_Not_first: ;Not the first. We are going to hook vector.;3.30 + pop ds ;3.30 + mov di, offset Int19OLD&AA ;we have to set OLD&AA for Int19 handler too.;3.30 + mov BX, OFFSET OLD&AA ;PASS WHERE TO SAVE ORIGINAL OWNER POINTER;3.30 + MOV DX, OFFSET INT&AA ;PASS WHERE NEW HANDLER IS ;3.30 + CALL NEW_INIT_LOOP ;ADJUST THE VECTOR TO NEW HANDLER, SAVING;3.30 + ;POINTER TO ORIGINAL OWNER. ;3.30 + jmp short int&AA&_end ;3.30 +int&AA&_first: ;the first. Don't have to hook stack code.;3.30 + pop ds ;3.30 +int&AA&_end: ;3.30 + ;3.30 + ENDM ;3.30 + ;3.30 + push ds ;3.30 + mov ax, 0f000h ;loook at the model byte ;3.30 + mov ds, ax ;3.30 + cmp ds:byte ptr [0fffeh], 0f9h ;convertible?(P12) ;3.30 + pop ds ;3.30 + jne Skip_EnableNMIS ;3.30 + ;3.30 + MOV AL,27H ; ENABLE P12 NMIS ;3.30 + OUT 72H,AL ;3.30 + ;3.30 +Skip_EnableNMIS: ;3.30 + STI ;3.30 + MOV AX,code ;3.30 + MOV DS,AX ;3.30 + ASSUME DS:CODE ;3.30 + ;3.30 +; MOV SI,OFFSET STKMSG1 ;3.30 +; CALL WRMSG ;3.30 + ;3.30 + mov [INT19SEM],1 ; INDICATE THAT INT 19 ;3.30 + ; INITIALIZATION IS COMPLETE ;3.30 + ;3.30 + POP BP ; RESTORE ALL ;3.30 + POP SI ;3.30 + POP DI ;3.30 + POP DX ;3.30 + POP CX ;3.30 + POP BX ;3.30 + ;3.30 + POP ES ;3.30 + POP DS ;3.30 + assume ds:sysinitseg ;3.30 + POP AX ;3.30 + RET ;3.30 +STACKINIT ENDP ;3.30 +; ;3.30 + ;3.30 +NEW_INIT_LOOP PROC NEAR ;3.30 +;INPUT: SI=OFSET INTO VECTOR TABLE OF THE PARTICULAR INT VECTOR BEING ADJUSTED ;3.30 +; BX=ds:OFFSET OF OLDxx, WHERE WILL BE SAVED THE POINTER TO ORIGINAL OWNER;3.30 +; DX=ds:OFFSET OF INTxx, THE NEW INTERRUPT HANDLER ;3.30 +; di=offset value of Int19OLD&AA variable in BIOS. ;3.30 +; es=ZERO, SEGID OF VECTOR TABLE ;3.30 +; ds=Relocated Stack code segment ;3.30 + ;3.30 + MOV AX,es:[SI+0] ;REMEMBER OFFSET IN VECTOR ;3.30 + MOV WORD PTR ds:[BX],AX ; TO ORIGINAL OWNER in DS ;3.30 + MOV AX,es:[SI+2] ;REMEMBER SEGID IN VECTOR ;3.30 + MOV WORD PTR ds:[BX]+2,AX ; TO ORIGINAL OWNER in DS ;3.30 + push ds ;3.30 + mov ax, code ;3.30 + mov ds, ax ;Set Int19OLDxx value in BIOS for ;3.30 + mov ax,es:[si+0] ;Int 19 handler ;3.30 + mov word ptr ds:[di],ax ;3.30 + mov ax,es:[si+2] ;3.30 + mov word ptr ds:[di]+2,ax ;3.30 + pop ds ;3.30 + ;3.30 + MOV WORD PTR es:[SI+0],DX ;SET VECTOR TO POINT TO NEW INT HANDLER ;3.30 + MOV es:[SI+2],ds ;3.30 + RET ;3.30 +NEW_INIT_LOOP ENDP ;3.30 + ;3.30 diff --git a/SRC/BIOS/STKMES.INC b/SRC/BIOS/STKMES.INC new file mode 100644 index 0000000..79225d3 --- /dev/null +++ b/SRC/BIOS/STKMES.INC @@ -0,0 +1,6 @@ + PUBLIC FATAL_MSG ;3.30 +FATAL_MSG DB 0DH,0AH ;3.30 + DB 7,0DH,0AH ;3.30 + DB "Internal stack overflow",0DH,0AH ;3.30 + DB "System halted",0DH,0AH,"$" ;3.30 +; diff --git a/SRC/BIOS/SYSCONF.ASM b/SRC/BIOS/SYSCONF.ASM new file mode 100644 index 0000000..5f404ed --- /dev/null +++ b/SRC/BIOS/SYSCONF.ASM @@ -0,0 +1,868 @@ +TITLE BIOS SYSTEM INITIALIZATION +TRUE EQU 0FFFFh +FALSE EQU 0 + +;IBMVER EQU TRUE +;IBM EQU IBMVER +STACKSW EQU TRUE ;Include Switchable Hardware Stacks +;IBMJAPVER EQU FALSE ;If TRUE set KANJI true also +;MSVER EQU FALSE +;ALTVECT EQU FALSE ;Switch to build ALTVECT version +;KANJI EQU FALSE + +INCLUDE version.inc + + IF IBMJAPVER +NOEXEC EQU TRUE + ELSE +NOEXEC EQU FALSE + ENDIF + +DOSSIZE EQU 0A000H + +.xlist + include smdossym.inc ; Reduced version of DOSSYM.INC ;3.30 + INCLUDE devsym.inc + include ioctl.inc + include BIOSTRUC.INC ;3.30 +.list + + IF NOT IBMJAPVER + EXTRN RE_INIT:FAR + ENDIF + +SYSINITSEG SEGMENT PUBLIC 'SYSTEM_INIT' + +ASSUME CS:SYSINITSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING + + EXTRN BADOPM:BYTE,CRLFM:BYTE,BADCOM:BYTE,BADMEM:BYTE,BADBLOCK:BYTE + EXTRN BADSIZ_PRE:BYTE,BADLD_PRE:BYTE + EXTRN BADSIZ_POST:BYTE,BADLD_POST:BYTE + EXTRN BADSTACK:BYTE,BADCOUNTRYCOM:BYTE ;3.30 + EXTRN SYSSIZE:BYTE,BADCOUNTRY:BYTE,INSUFMEMORY:BYTE ;3.30 + EXTRN CONDEV:BYTE,AUXDEV:BYTE,PRNDEV:BYTE,COMMND:BYTE,CONFIG:BYTE + EXTRN Cntry_Drv:BYTE,Cntry_Root:BYTE,Cntry_Path:BYTE ;3.30 + EXTRN DeviceParameters:byte ;3.30 + EXTRN MEMORY_SIZE:word ;3.30 + EXTRN BUFFERS:word ;3.30 + EXTRN FILES:byte,NUM_CDS:byte ;3.30 + EXTRN DOSINFO:dword,ENTRY_POINT:dword ;3.30 + EXTRN FCBS:byte,KEEP:byte ;3.30 + EXTRN CONFBOT:word,ALLOCLIM:word,COMMAND_LINE:byte ;3.30 + EXTRN ZERO:byte,SEPCHR:byte ;3.30 + EXTRN COUNT:word,CHRPTR:word,CNTRYFILEHANDLE:word ;3.30 + EXTRN MEMLO:word,MEMHI:word,PRMBLK:word,LDOFF:word ;3.30 + EXTRN PACKET:byte,UNITCOUNT:byte,BREAK_ADDR:dword ;3.30 + EXTRN BPB_ADDR:dword,DRIVENUMBER:byte,SYSI_COUNTRY:dword ;3.30 + ;3.30 + EXTRN MEM_ERR:NEAR,SetDOSCountryInfo:NEAR ;3.30 + EXTRN PARAROUND:NEAR,TEMPCDS:NEAR ;3.30 + EXTRN Set_Country_Path:NEAR,Move_ASCIIZ:NEAR,DELIM:NEAR ;3.30 + EXTRN BADFIL:NEAR,ROUND:NEAR ;3.30 + + IF STACKSW +; +; Internal Stack Parameters +EntrySize equ 8 + +MinCount equ 8 +DefaultCount equ 9 +MaxCount equ 64 + +MinSize equ 32 +DefaultSize equ 128 +MaxSize equ 512 + + extrn stack_count:word ;3.30 + extrn stack_size:word ;3.30 + extrn stack_addr:dword ;3.30 + + ENDIF + + PUBLIC DOCONF ;3.30 + PUBLIC GETCHR ;3.30 + +;*************************************************************************;3.30 +;Take care of Config.sys file. ;3.30 + +DOCONF: + PUSH CS + POP DS + + ASSUME DS:SYSINITSEG + + MOV AX,(CHAR_OPER SHL 8) ;GET SWITCH CHARACTER + INT 21H + MOV [COMMAND_LINE+1],DL ; Set in default command line + + MOV DX,OFFSET CONFIG ;NOW POINTING TO FILE DESCRIPTION + MOV AX,OPEN SHL 8 ;OPEN FILE "CONFIG.SYS" + STC ;IN CASE OF INT 24 + INT 21H ;FUNCTION REQUEST + JC ENDCONF ;Wasn't there, or couldn't open ;3.30 + JMP NOPROB ;PROBLEM WITH OPEN + +ENDCONF: ;3.30 + return ;3.30 + + +BADOP: MOV DX,OFFSET BADOPM ;WANT TO PRINT COMMAND ERROR + invoke PRINT + JMP COFF + +NOPROB: ;GET FILE SIZE (NOTE < 64K!!) + MOV BX,AX + XOR CX,CX + XOR DX,DX + MOV AX,(LSEEK SHL 8) OR 2 + INT 21H + MOV [COUNT],AX + XOR DX,DX + MOV AX,LSEEK SHL 8 ;Reset pointer to beginning of file + INT 21H + MOV DX,CS + MOV AX,[COUNT] + call ParaRound + SUB DX,AX + SUB DX,11H ;ROOM FOR HEADER + MOV [CONFBOT],DX ; Config starts here + CALL TEMPCDS ; Finally get CDS to "safe" location +ASSUME DS:NOTHING,ES:NOTHING + + MOV DX,[CONFBOT] + MOV DS,DX + MOV ES,DX + XOR DX,DX + MOV CX,[COUNT] + MOV AH,READ + STC ;IN CASE OF INT 24 + INT 21H ;Function request + PUSHF +; +; Find the EOF mark in the file. If present, then trim length. +; + SaveReg + MOV AL,1Ah ; eof mark + MOV DI,DX ; point ro buffer + JCXZ PutEOL ; no chars + REPNZ SCASB ; find end + JNZ PutEOL ; none found and count exahusted +; +; We found a 1A. Back up +; + DEC DI ; backup past 1A +; +; Just for the halibut, stick in an extra EOL +; +PutEOL: + MOV AL,13 + STOSB ; CR + MOV AL,10 + STOSB ; LF + SUB DI,DX ; difference moved + MOV Count,DI ; new count +; +; Restore registers +; + RestoreReg + + PUSH CS + POP DS +ASSUME DS:SYSINITSEG + PUSH AX + MOV AH,CLOSE + INT 21H + POP AX + POPF + JC CONFERR ;IF NOT WE'VE GOT A PROBLEM + CMP CX,AX + JZ GETCOM ;COULDN'T READ THE FILE +CONFERR: + MOV DX,OFFSET CONFIG ;WANT TO PRINT CONFIG ERROR + CALL BADFIL +ENDCONV:JMP ENDCONF ;3.30 + +GETCOM: + invoke ORGANIZE ;ORGANIZE THE FILE + CALL GETCHR + +CONFLP: JC ENDCONV ;3.30 + MOV AH,AL + CALL GETCHR + JNC TryB + JMP BADOP + +COFF: PUSH CS + POP DS + invoke NEWLINE + JMP CONFLP + +;------------------------------------------------------------------------------ +; Buffer command +;------------------------------------------------------------------------------ +TryB: CMP AH,'B' ;BUFFER COMMAND? + JNZ TRYC + invoke GETNUM + JZ TryBBad ; Gotta have at least one + CMP AX,100 ; check for max number + JB SaveBuf +TryBBad:JMP BadOp +SaveBuf: + MOV [BUFFERS],AX +CoffJ1: JMP COFF + +;------------------------------------------------------------------------------ +; Break command +;------------------------------------------------------------------------------ +TryC: CMP AH,'C' + JZ GOTC + JMP TRYD +GOTC: + CMP AL,'O' ;FIRST LETTER OF "ON" or "OFF" + JNZ TryCBad + CALL GETCHR + JC TryCBad + CMP AL,'N' ;SECOND LETTER OF "ON" + JNZ TryCoff + MOV AH,SET_CTRL_C_TRAPPING ;TURN ON CONTROL-C CHECK + MOV AL,1 + MOV DL,AL + INT 21H +CoffJ2: JMP Coff +TryCOff:CMP AL,'F' + JNZ TryCBad ; Check for "OFF" + CALL GetChr + JC TryCBad + CMP AL,'F' + JZ COffJ2 +TryCBad:JMP BadOp + +;------------------------------------------------------------------------------ +; Device command +;------------------------------------------------------------------------------ +TRYD: CMP AH,'D' + JZ GOTD + JMP TRYQ +GOTD: MOV BX,CS + MOV DS,BX + + MOV WORD PTR [BPB_ADDR],SI + MOV WORD PTR [BPB_ADDR+2],ES + + CALL ROUND + XOR AX,AX + MOV WORD PTR [ENTRY_POINT],AX + MOV AX,[MEMHI] + MOV WORD PTR [ENTRY_POINT+2],AX ;SET ENTRY POINT + + IF NOT NOEXEC + MOV [LDOFF],AX ;SET LOAD OFFSET + ENDIF + + PUSH ES + POP DS +ASSUME DS:NOTHING + MOV DX,SI ;DS:DX POINTS TO FILE NAME + + IF NOEXEC + LES BX,DWORD PTR CS:[MEMLO] + CALL LDFIL ;LOAD IN THE DEVICE DRIVER + ELSE +; We are going to open the cdevice driver and size it as is done +; in LDFIL. The reason we must do this is that EXEC does NO checking +; for us. We must make sure there is room to load the device without +; trashing SYSINIT. This code is not +; perfect (for instance .EXE device drivers are possible) because +; it does its sizing based on the assumption that the file being loaded +; is a .COM file. It is close enough to correctness to be usable. + MOV ES,AX ;ES:0 is LOAD addr + MOV AX,OPEN SHL 8 ;OPEN THE FILE + STC ;IN CASE OF INT 24 + INT 21H + JC BADLDRESET + MOV BX,AX ;Handle in BX + PUSH DX ; Save pointer to name + XOR CX,CX + XOR DX,DX + MOV AX,(LSEEK SHL 8) OR 2 + STC ;IN CASE OF INT 24 + INT 21H ; Get file size in DX:AX + JNC GO_AHEAD_LOAD + MOV AH,CLOSE ; Close file + INT 21H + POP DX ; Clean stack + STC ; Close may clear carry + JMP SHORT BADLDRESET + +GO_AHEAD_LOAD: + ; Convert size in DX:AX to para in AX + ADD AX,15 ; Round up size for conversion to para + ADC DX,0 + MOV CL,4 + SHR AX,CL + MOV CL,12 + SHL DX,CL ; Low nibble of DX to high nibble + OR AX,DX ; AX is now # of para for file + + MOV CX,ES ; CX:0 is xaddr + ADD CX,AX ; New device will take up to here + JC MEM_ERRJY ; WOW!!!! + CMP CX,CS:[ALLOCLIM] + JB OKLDX +MEM_ERRJY: + JMP MEM_ERR + +OKLDX: + POP DX ; Recover name pointer + MOV AH,CLOSE ; Close file + INT 21H + MOV BX,CS + MOV ES,BX + MOV BX,OFFSET PRMBLK ;ES:BX POINTS TO PARAMETERS + MOV AL,3 + MOV AH,EXEC + STC ;IN CASE OF INT 24 + INT 21H ;LOAD IN THE DEVICE DRIVER + ENDIF + +BADLDRESET: + PUSH DS + POP ES ;ES:SI BACK TO CONFIG.SYS + PUSH CS + POP DS ;DS BACK TO SYSINIT +ASSUME DS:SYSINITSEG + JNC GOODLD +BADBRK: + cmp byte ptr es:[si], 13 ;file name is CR? ;3.30 + jne BADBRK_1 ;(entered "device=" without filename);3.30 ;3.30 + jmp BADOP ;"Unrecognized command in CONFIG.SYS";3.30 +BADBRK_1: ;3.30 + invoke BADLOAD + JMP COFF + +GOODLD: SaveReg ;INITIALIZE THE DEVICE +Restore:MOV BL,ES:[SI] ; while ((c=*p) != 0) + OR BL,BL + JZ Got + INC SI ; p++; + JMP Restore +Got: MOV BYTE PTR ES:[SI],' ' ; *p = ' '; + SaveReg + PUSH CS + POP ES + MOV BX,SDEVSTRAT + invoke CALLDEV ; CallDev (SDevStrat); + MOV BX,SDEVINT + invoke CALLDEV ; CallDev (SDevInt); + RestoreReg + MOV BYTE PTR [SI],0 ; *p = 0; + + PUSH CS + POP DS + MOV AX,WORD PTR [BREAK_ADDR+2] + CMP AX,[MEMORY_SIZE] + JB BREAKOK + POP SI + POP ES + JMP BADBRK + +BREAKOK: + LDS DX,[ENTRY_POINT] ;SET DS:DX TO HEADER + MOV SI,DX + ADD SI,SDEVATT ;DS:SI POINTS TO ATTRIBUTES + LES DI,CS:[DOSINFO] ;ES:DI POINT TO DOS INFO + MOV AX,DS:[SI] ;GET ATTRIBUTES + TEST AX,DEVTYP ;TEST IF BLOCK DEV + JZ ISBLOCK + invoke SET_BREAK ; Go ahead and alloc mem for device + jc Erase_Dev ;dev driver's Init routine failed ;3.30 + TEST AX,ISCIN ;IS IT A CONSOLE IN? + JZ TRYCLK + MOV WORD PTR ES:[DI.SYSI_CON],DX + MOV WORD PTR ES:[DI.SYSI_CON+2],DS + +TRYCLK: TEST AX,ISCLOCK ;IS IT A CLOCK DEVICE? + JZ GOLINK + MOV WORD PTR ES:[DI+SYSI_CLOCK],DX + MOV WORD PTR ES:[DI+SYSI_CLOCK+2],DS +GOLINK: JMP LINKIT + +ISBLOCK: + MOV AL,CS:[UNITCOUNT] ;IF NO UNITS FOUND, erase the device + OR AL,AL + JNZ PERDRV +ERASE_DEV: + MOV AX,-1 ; No call to SET_BREAK yet, so no alloc + JMP ENDDEV + +PERDRV: + CBW ; WARNING NO DEVICE > 127 UNITS + MOV CX,AX + MOV DH,AH + MOV DL,ES:[DI.SYSI_NUMIO] ;GET NUMBER OF DEVICES + MOV AH,DL + ADD AH,AL ; Check for too many devices + CMP AH,26 ; 'A' - 'Z' is 26 devices + JBE OK_BLOCK + PUSH CS + POP DS + MOV DX,OFFSET BADBLOCK + invoke PRINT + JMP ERASE_DEV + +OK_BLOCK: + invoke SET_BREAK ; Alloc the device + ADD ES:[DI.SYSI_NUMIO],AL ;UPDATE THE AMOUNT + ADD CS:DriveNumber,AL ; remember amount for next device + LDS BX,CS:[BPB_ADDR] ;POINT TO BPB ARRAY +PERUNIT: + LES BP,CS:[DOSINFO] + LES BP,DWORD PTR ES:[BP.SYSI_DPB] ;GET FIRST DPB + +SCANDPB:CMP WORD PTR ES:[BP.DPB_NEXT_DPB],-1 + JZ FOUNDPB + LES BP,ES:[BP.DPB_NEXT_DPB] + JMP SCANDPB +FOUNDPB: + MOV AX,CS:[MEMLO] + MOV WORD PTR ES:[BP.DPB_NEXT_DPB],AX + MOV AX,CS:[MEMHI] + MOV WORD PTR ES:[BP.DPB_NEXT_DPB+2],AX + LES BP,DWORD PTR CS:[MEMLO] + ADD WORD PTR CS:[MEMLO],DPBSIZ + CALL ROUND ;Check for alloc error + MOV WORD PTR ES:[BP.DPB_NEXT_DPB],-1 + MOV ES:[BP.DPB_FIRST_ACCESS],-1 + + MOV SI,[BX] ;DS:SI POINTS TO BPB + INC BX + INC BX ;POINT TO NEXT GUY + MOV WORD PTR ES:[BP.DPB_DRIVE],DX + MOV AH,SETDPB ;HIDDEN SYSTEM CALL + INT 21H + MOV AX,ES:[BP.DPB_SECTOR_SIZE] ;3.30 + PUSH ES ;3.30 + LES DI,CS:[DOSINFO] ;ES:DI POINT TO DOS INFO ;3.30 + CMP AX,ES:[DI.SYSI_MAXSEC] ;3.30 + POP ES ;3.30 + JBE NOTMAX ;3.30 + POP SI ;3.30 + POP ES ;3.30 + MOV DX,OFFSET BADSIZ_PRE ;3.30 + MOV BX,OFFSET BADSIZ_POST ;3.30 + invoke PRNERR ;3.30 + JMP COFF ;3.30 + +NOTMAX: PUSH DS + PUSH DX + LDS DX,CS:[ENTRY_POINT] + MOV WORD PTR ES:[BP.DPB_DRIVER_ADDR],DX + MOV WORD PTR ES:[BP.DPB_DRIVER_ADDR+2],DS + POP DX + POP DS + INC DX + INC DH + LOOP PERUNIT + PUSH CS + POP DS + CALL TEMPCDS ; Set CDS for new drives + +LINKIT: + LES DI,CS:[DOSINFO] ;ES:DI = DOS TABLE + MOV CX,WORD PTR ES:[DI.SYSI_DEV] ;DX:CX = HEAD OF LIST + MOV DX,WORD PTR ES:[DI.SYSI_DEV+2] + + LDS SI,CS:[ENTRY_POINT] ;DS:SI = DEVICE LOCATION + MOV WORD PTR ES:[DI.SYSI_DEV],SI ;SET HEAD OF LIST IN DOS + MOV WORD PTR ES:[DI.SYSI_DEV+2],DS + MOV AX,DS:[SI] ;GET POINTER TO NEXT DEVICE + MOV WORD PTR CS:[ENTRY_POINT],AX ;AND SAVE IT + + MOV WORD PTR DS:[SI],CX ;LINK IN THE DRIVER + MOV WORD PTR DS:[SI+2],DX +ENDDEV: + POP SI + POP ES + INC AX ;AX = FFFF (no more devs if YES)? + JZ COFFJ3 + JMP GOODLD ;OTHERWISE PRETEND WE LOADED IT IN +COFFJ3: JMP COFF + +;------------------------------------------------------------------------------ +; Country command +; The syntax is: ;3.30 +; COUNTRY=country id {,codepage {,path}} ;3.30 +; COUNTRY=country id {,,path} :Default CODEPAGE ID in DOS ;3.30 +;------------------------------------------------------------------------------ +TRYQ: + CMP AH,'Q' ;3.30 + JZ TRYQ_CONT ;3.30 + JMP TRYF ;3.30 +TRYQ_CONT: ;3.30 + invoke GETNUM ;3.30 + JZ TryQBad ; 0 is never a valid code, or number is;3.30 + ; bad ;3.30 + MOV BX,AX ; Country code in BX ;3.30 + ;3.30 + ; 5/26/86 ;3.30 + MOV DX,0 ; assume no code page id ;3.30 + ;3.30 + invoke skip_delim ;skip the delimeters after the first nu;3.30m + jc TryQ_Def_File ;no more characters left? then use defa;3.30ult file + cmp al, 13 ; ;3.30 + je TryQ_Def_File ;3.30 + cmp al, 10 ;3.30 + jne TRYQ_YES_EXTENDED ;3.30 + inc [COUNT] ;This is for NEWLINE routine in COFF. ;3.30 + dec [CHRPTR] ;3.30 +COFFJ41: ;3.30 + JMP TryQ_Def_File ;O.K. no code page, no path specified. ;3.30Use default path. + ;3.30 +TRYQ_YES_EXTENDED: ;3.30 + cmp al, ',' ;was the second comma? ;3.30 + jne TryQ_GETNUM ;3.30 + invoke skip_delim ;Yes, skip ',' and other possible delim;3.30 + jmp short TRYQ_PATH ;and No code page id entered. ;3.30 +TRYQ_GETNUM: ;3.30 + invoke GETNUM ;3.30 + jc TryQBadCOM ;"Country=xxx,path" will not be accepte;3.30d. +; jc TRYQ_PATH ;Codepage is not specified. No code pag;3.30e. +; ;At this point, AL already contain the ;3.30 +; ;first char of the PATH. ;3.30 + jz TryQBad ;codepage=0 entered. Error ;3.30 + mov DX, AX ;save code page in DX ;3.30 + invoke skip_delim ;move CHRPTR to the path string ;3.30 + jc TryQ_Def_File ;no more char? then use default filenam;3.30e + cmp al, 13 ;3.30 + je TryQ_Def_File ;3.30 + cmp al, 10 ;3.30 + jne TryQ_PATH ;path entered. ;3.30 + inc [COUNT] ;3.30 + dec [CHRPTR] ;3.30 +TryQ_Def_File: ;3.30 + push dx ;save code page ;3.30 + mov cs:CNTRY_DRV, 0 ;flag that the default path has been us;3.30ed!!! + mov dx, offset CNTRY_ROOT ;the default path ;3.30 + jmp TRYQ_OPEN ;3.30 + ;3.30 +TryQBad: ;"Invalid country code or code page" ;3.30 + STC ;3.30 + MOV DX,OFFSET BADCOUNTRY ;3.30 + jmp TryQChkErr ;3.30 + ;3.30 +TryQBadCOM: ;Error in COUNTRY command ;3.30 + STC ;3.30 + MOV DX,OFFSET BADCOUNTRYCOM ;3.30 + jmp TryQChkErr ;3.30 + ;3.30 +TRYQ_PATH: ;DS - sysinitseg, ES - CONFBOT, ;3.30 + mov CX, [COUNT] ;AL - the first char of path ;3.30 + inc CX ;BX - country id, DX - codepage id, 0 =;3.30 No code page + mov DI, SI ;3.30 +TRYQ_PATH_LOOP: ;find the end of path to put 0 after th;3.30at. + mov AL, byte ptr ES:[DI] ;3.30 + call delim ;3.30 + jz TRYQ_PATH_END ;3.30 + cmp al, 13 ;3.30 + jz TRYQ_PATH_END ;3.30 + inc DI ;3.30 + jmp short TRYQ_PATH_LOOP ;3.30 +TryQBad_Brg:jmp short TryQBad ;3.30 +TRYQ_PATH_END: ;3.30 + mov es:byte ptr [di], 0 ;make it a ASCIIZ string. (Organize did;3.30 not handle this string) + push ds ;switch ds,es ;3.30 + push es ;3.30 + pop ds ;3.30 + pop es ;3.30 + ;3.30 + mov di, offset CNTRY_DRV ;move the user specified path to CNTRY_;3.30DRV + call Move_ASCIIZ ;3.30 + ;3.30 + push ds ;restore ds,es ;3.30 + push es ;3.30 + pop ds ;3.30 + pop es ;3.30 + ;3.30 +; call Set_Country_Path ;set CNTRY_DRV ;3.30 + ;3.30 + push dx ;save DX ;3.30 + mov dx, offset CNTRY_DRV ;Now DS:DX -> CNTRY_DRV ;3.30 +TRYQ_OPEN: ;3.30 + mov ax, 3d00h ;open a file ;3.30 + stc ;3.30 + int 21h ;3.30 + pop dx ;restore codepage id ;3.30 + jc TryQFileBad ;open failure ;3.30 + ;3.30 + mov cs:CntryFileHandle, ax ;save file handle ;3.30 + xchg ax, bx ;now, AX = country id, BX = file handle;3.30 + mov cx, cs:[MEMHI] ;3.30 + add cx, 128 ;I need 2K buffer to handle COUNTRY.SYS;3.30 + cmp cx, cs:[ALLOCLIM] ;3.30 + ja TryQMemory ;cannot allocate the buffer for country;3.30.sys + ;3.30 + mov si, offset CNTRY_DRV ;DS:SI -> CNTRY_DRV ;3.30 + cmp byte ptr [si],0 ;default path? ;3.30 + jne TRYQ_Set_for_DOS ;3.30 + inc si ;3.30 + inc si ;DS:SI -> CNTRY_ROOT ;3.30 +TRYQ_Set_for_DOS: ;3.30 + les di, cs:SYSI_Country ;ES:DI -> country info tab in DOS ;3.30 + push di ;save di ;3.30 + add di, ccPath_CountrySys ;3.30 + call MOVE_ASCIIZ ;Set the path to COUNTRY.SYS in DOS. ;3.30 + pop di ;ES:DI -> country info tab again. ;3.30 + mov cx, cs:[MEMHI] ;3.30 + mov ds, cx ;3.30 + xor si, si ;DS:SI -> 2K buffer to be used. ;3.30 + call SetDOSCountryInfo ;now do the job!!! ;3.30 + jnc TryQchkERR ;read error or could not find country,c;3.30ode page combination + cmp cx, -1 ;Could not find matching country_id,cod;3.30e page? + je TryQBad_Brg ;then "Invalid country code or code pag;3.30e" +TryQFileBad: ;3.30 + cmp cs:CNTRY_DRV,0 ;Is the default file used? ;3.30 + je TryQDefBad ;3.30 + mov si, cs:[CONFBOT] ;3.30 + mov es, si ;3.30 + mov si, cs:[CHRPTR] ;3.30 + dec si ;ES:SI -> path in CONFBOT ;3.30 + jmp short TryQBADLOAD ;3.30 +TryQDefBad: ;Default file has been used. ;3.30 + push cs ;3.30 + pop es ;3.30 + mov si, offset CNTRY_ROOT ;ES:SI -> \COUNTRY.SYS in SYSINIT_SEG ;3.30 +TryQBADLOAD: ;3.30 + call BADLOAD ;DS will be restored to SYSINIT_SEG ;3.30 + mov cx, cs:[CONFBOT] ;3.30 + mov es, cx ;Restore ES -> CONFBOT. ;3.30 + jmp short CoffJ4 ;3.30 +TryQMemory: ;3.30 + MOV DX,OFFSET INSUFMEMORY ;3.30 +TryQChkErr: ;3.30 + mov cx, cs:[CONFBOT] ;3.30 + mov es, cx ;restore ES -> CONFBOT seg ;3.30 + push cs ;3.30 + pop ds ;retore DS to SYSINIT_SEG ;3.30 + jnc CoffJ4 ;if no error, then exit ;3.30 + invoke PRINT ;else show error message ;3.30 +CoffJ4: ;3.30 + mov bx, CntryFileHandle ;3.30 + mov ah, 3eh ;3.30 + int 21h ;close a file. Don't care even if it fa;3.30ils. + JMP COFF ;3.30 + +;------------------------------------------------------------------------------ +; Files command +;------------------------------------------------------------------------------ +TRYF: + CMP AH,'F' + JNZ TRYL + invoke GETNUM + CMP AX,5 + JB TryFBad ; Gotta have at least 5 + CMP AX,256 + JAE TryFBad ; Has to be a byte + MOV [FILES],AL +CoffJ5: JMP COFF +TryFBad:JMP BadOp +;------------------------------------------------------------------------------ +; LastDrive command +;------------------------------------------------------------------------------ +TRYL: + CMP AH,'L' + JNZ TRYP + OR AL,020h + SUB AL,'a' + JB TryLBad + INC AL + CMP AL,26 ; a-z are allowed + JA TryLBad + MOV [NUM_CDS],AL +CoffJ6: JMP COFF +TryLBad:JMP BadOp +;------------------------------------------------------------------------------- +; Setting Drive Parameters +;------------------------------------------------------------------------------- +TRYP: + CMP AH,'P' + JNZ TRYK + invoke PARSELINE + JC TryLBad + invoke SETPARMS + INVOKE DIDDLEBACK + jc TryLBad + JMP COFF +;------------------------------------------------------------------------------- +; Setting Internal Stack Parameters +; STACK=M,N where +; M is the number of stacks (range 8 to 64, default 9) +; N is the stack size (range 32 to 512 bytes, default 128) +; 5/5/86: STACKS=0,0 implies no stack installation. ;3.30 +; Any combinations that are not within the specified limits will ;3.30 +; result in "Unrecognized command" error. ;3.30 +;------------------------------------------------------------------------------- +TRYK: + CMP AH,'K' + JNZ TRYW + + IF STACKSW ;3.30 + + MOV SepChr,',' + INVOKE GetNum ; Get number of stacks + MOV SepChr,0 + cmp ax, 0 ; 5/5/86 ;3.30 + je TRYK_0 ; Let's accept 0. ;3.30 + CMP AX, MinCount ; 8 <= Number of Stacks <= 64 + JB TryKBad + CMP AX, MaxCount + JA TryKBad +TRYK_0: ;3.30 + MOV [STACK_COUNT], AX +; +; Skip delimiters after the , +; + invoke Skip_delim ; ;3.30 + JC TryKBad + + INVOKE GetNum ; Get size of individual stack + JC TryKBad ; Number bad + + cmp ax, 0 ; 5/5/86 ;3.30 + je TRYK_SIZE0 ; 5/5/86. Accept 0 ;3.30 + + CMP AX, MinSize ; 32 <= Stack Size <= 512 + JB TryKBad + CMP AX, MaxSize + JA TryKBad +TRYK_SIZE0: ;3.30 + MOV [STACK_SIZE], AX + cmp ax,0 ;3.30 + je TRYK_BOTH0 ;3.30 +TRYK_OK: ;3.30 + mov word ptr [stack_addr], -1 ;set flag. user entered stacks= ;3.30 + JMP COFF +TRYK_BOTH0: ;3.30 + cmp [STACK_COUNT],0 ;stack_size=0. Stack_Count=0 too? ;3.30 + je TRYK_OK ;yes. accepted. ;3.30 +TryKBad: + MOV DX, OFFSET BADSTACK ; 5/26/86 "Invalid stack parameter";3.30 + invoke PRINT ;3.30 + JMP COFF ;3.30 + + ENDIF ;3.30 +;------------------------------------------------------------------------------ +; Switch command +;------------------------------------------------------------------------------ +TRYW: + CMP AH,'W' + JNZ TRYA + JMP BadOp ; no longer implemented +; MOV DL,AL +; MOV AX,(CHAR_OPER SHL 8) OR 1 ;SET SWITCH CHARACTER +; MOV [COMMAND_LINE+1],DL +; INT 21H +; JMP COFF + +;------------------------------------------------------------------------------ +; Availdev command +;------------------------------------------------------------------------------ +TRYA: + CMP AH,'A' + JNZ TRYS + JMP BadOp ; NO LONGER IMPLEMENTED +; CMP AL,'F' ;FIRST LETTER OF "FALSE" +; JNZ COFFJ7 +; MOV AX,(CHAR_OPER SHL 8) OR 3 ;TURN ON "/DEV" PREFIX +; XOR DL,DL +; INT 21H +;COFFJ7: JMP COFF + +;------------------------------------------------------------------------------ +; shell command +;------------------------------------------------------------------------------ +TRYS: + CMP AH,'S' + JNZ TRYX + MOV [COMMAND_LINE+1],0 + MOV DI,OFFSET COMMND + 1 + MOV [DI-1],AL +STORESHELL: + CALL GETCHR + OR AL,AL + JZ GETSHPARMS + CMP AL," " + JB ENDSH + MOV [DI],AL + INC DI + JMP STORESHELL + +ENDSH: + MOV BYTE PTR [DI],0 + CALL GETCHR + CMP AL,10 + JNZ CONV + CALL GETCHR +CONV: JMP CONFLP + +;------------------------------------------------------------------------------ +; FCBS Command +;------------------------------------------------------------------------------ +TRYX: + CMP AH,'X' + JNZ TRYZ + invoke GETNUM + JZ TryXBad ; gotta have at least one + CMP AX,256 + JAE TryXBad ; Can't be more than 8 bits worth + MOV [FCBS],AL +; +; Skip delimiters after the , +; + invoke Skip_delim ; ;3.30 + jc tryxbad + invoke GetNum + JC TryXBad ; Number bad (Zero is OK here) + CMP AX,256 + JAE TryXBad + CMP AL,FCBS + JA TryXBad + MOV Keep,AL + JMP COFF +TryXBad:JMP BadOp + +;------------------------------------------------------------------------------ +; Bogus command +;------------------------------------------------------------------------------ +TRYZ: + JMP BADOP + +GETSHPARMS: + MOV BYTE PTR [DI],0 + MOV DI,OFFSET COMMAND_LINE+1 +PARMLOOP: + CALL GETCHR + CMP AL," " + JB ENDSH + MOV [DI],AL + INC DI + JMP PARMLOOP + +GETCHR: + PUSH CX + MOV CX,COUNT + JCXZ NOCHAR + MOV SI,CHRPTR + MOV AL,ES:[SI] + DEC COUNT + INC CHRPTR + CLC +GET_RET: + POP CX + return +NOCHAR: STC + JMP SHORT GET_RET + + +SYSINITSEG ENDS + END + \ No newline at end of file diff --git a/SRC/BIOS/SYSCONF.OBJ b/SRC/BIOS/SYSCONF.OBJ new file mode 100644 index 0000000..9d863b1 Binary files /dev/null and b/SRC/BIOS/SYSCONF.OBJ differ diff --git a/SRC/BIOS/SYSIMES.ASM b/SRC/BIOS/SYSIMES.ASM new file mode 100644 index 0000000..4e96267 --- /dev/null +++ b/SRC/BIOS/SYSIMES.ASM @@ -0,0 +1,18 @@ +TEST = 0 ;3.30 +include msequ.inc ;3.30 +include msmacro.inc ;3.30 + ;3.30 +SYSINITSEG SEGMENT PUBLIC BYTE 'SYSTEM_INIT' ;3.30 + ;3.30 + PUBLIC BADOPM,CRLFM,BADSIZ_PRE,BADLD_PRE,BADCOM,SYSSIZE,BADCOUNTRY ;3.30 + PUBLIC BADLD_POST,BADSIZ_POST,BADMEM,BADBLOCK,BADSTACK ;3.30 + PUBLIC INSUFMEMORY,BADCOUNTRYCOM ;3.30 + ;3.30 +include sysimes.inc ;3.30 + ;3.30 +SYSSIZE LABEL BYTE ;3.30 + ;3.30 +PATHEND 001,SYSMES ;3.30 + ;3.30 +SYSINITSEG ENDS ;3.30 + END ;3.30 diff --git a/SRC/BIOS/SYSIMES.INC b/SRC/BIOS/SYSIMES.INC new file mode 100644 index 0000000..71e6523 --- /dev/null +++ b/SRC/BIOS/SYSIMES.INC @@ -0,0 +1,68 @@ + +; +; printed when there is a bad command in CONFIG.SYS. '$' TERMINATED, note +; that this message includes crlfm. +; + +PATHSTART 001,SYSMES ;3.30 +BADOPM DB 13,10,"Unrecognized command in CONFIG.SYS" + +BADSIZ_POST LABEL BYTE +BADLD_POST LABEL BYTE +CRLFM DB 13,10,'$' + + +; +;PRINTED when installed device specifies too large a sector size.'$' terminated. +; FORM: device name +; + +BADSIZ_PRE DB 13,10,"Sector size too large in file $" + +; +;PRINTED when installed device cannot be found. '$' terminated. +; FORM: device name +; + +BADLD_PRE DB 13,10,"Bad or missing $" + +; +;PRINTED when command interpreter is not found. NUL terminated. +; FORM: +; + +BADCOM DB "Command Interpreter",0 + +;PRINTED when country code, code page combination was not found ;3.30 +; in country.sys file. '$' terminated. ;3.30 +; FORM: ;3.30 +BADCOUNTRY DB 13,10,"Invalid country code or code page",13,10,"$" ;3.30 + ;3.30 +;PRINTED when code page id is missing or wrong syntax. - J.K. ;3.30 +; FORM: ;3.30 +BADCOUNTRYCOM DB 13,10,"Error in COUNTRY command",13,10,"$" ;3.30 + ;3.30 +;PRINTED when the memory left is not sufficient to handle COUTRY.SYS file ;3.30 +; FORM: ;3.30 +INSUFMEMORY DB 13,10, "Insufficient memory for COUNTRY.SYS file",13,10,"$" ;3.30 + ;3.30 +; +; PRINTED when there is insufficient memory. '$' TERMINATED, note +; that this message includes crlfm! +; + +BADMEM DB 13,10,"Configuration too large for memory",13,10,"$" + +; +; PRINTED when the attempt is made to install a block device which would +; have a drive letter > 'Z' +; + +BADBLOCK DB 13,10,"Too many Block Devices",13,10,"$" + + +; PRINTED when the attempt is made to install a stack with invalid ;3.30 +; combinations of # of stacks, stack size. - J.K. 5/23/86 ;3.30 +BADSTACK DB 13,10,"Invalid STACK parameters",13,10,"$" ;3.30 + ;3.30 + \ No newline at end of file diff --git a/SRC/BIOS/SYSIMES.OBJ b/SRC/BIOS/SYSIMES.OBJ new file mode 100644 index 0000000..2619536 Binary files /dev/null and b/SRC/BIOS/SYSIMES.OBJ differ diff --git a/SRC/BIOS/SYSINIT1.ASM b/SRC/BIOS/SYSINIT1.ASM new file mode 100644 index 0000000..669840b --- /dev/null +++ b/SRC/BIOS/SYSINIT1.ASM @@ -0,0 +1,1084 @@ +TITLE BIOS SYSTEM INITIALIZATION + +TRUE EQU 0FFFFh +FALSE EQU 0 + +;IBMVER EQU TRUE +;IBM EQU IBMVER +STACKSW EQU TRUE ;Include Switchable Hardware Stacks +;IBMJAPVER EQU FALSE ;If TRUE set KANJI true also +;MSVER EQU FALSE +;ALTVECT EQU FALSE ;Switch to build ALTVECT version +;KANJI EQU FALSE + +include version.inc + + IF IBMJAPVER +NOEXEC EQU TRUE + ELSE +NOEXEC EQU FALSE + ENDIF + +DOSSIZE EQU 0A000H + +.xlist + include smdossym.inc ; Reduced version of DOSSYM.INC ;3.30 + INCLUDE devsym.inc + include ioctl.inc + include BIOSTRUC.INC ;3.30 +.list + + IF NOT IBMJAPVER + EXTRN RE_INIT:FAR + ENDIF + +;--------------------------------------- ;3.30 +;Equates for Main stack and stack Initialization program ;3.30 + IF STACKSW ;3.30 +cr equ 0dh ;3.30 +lf equ 0ah ;3.30 + ;3.30 +EntrySize equ 8 ;3.30 + ;3.30 +MinCount equ 8 ;3.30 +DefaultCount equ 9 ;3.30 +MaxCount equ 64 ;3.30 + ;3.30 +MinSize equ 32 ;3.30 +DefaultSize equ 128 ;3.30 +MaxSize equ 512 ;3.30 + ;3.30 +AllocByte equ es:byte ptr [bp+0] ;3.30 +IntLevel equ es:byte ptr [bp+1] ;3.30 +SavedSP equ es:word ptr [bp+2] ;3.30 +SavedSS equ es:word ptr [bp+4] ;3.30 +NewSP equ es:word ptr [bp+6] ;3.30 +Free equ 0 ;3.30 +allocated equ 1 ;3.30 +overflowed equ 2 ;3.30 +clobbered equ 3 ;3.30 + ;3.30 + ;3.30 +;External variables in BIOS for INT19h handling rouitne. 10/23/86 ;3.30 + ;3.30 +CODE segment public 'code' ;3.30 + EXTRN Int19sem:byte ;3.30 + ;3.30 + IRP AA,<02,08,09,0A,0B,0C,0D,0E,70,72,73,74,76,77> ;3.30 + EXTRN Int19OLD&AA:dword ;3.30 + ENDM ;3.30 +CODE ends ;3.30 + ENDIF ;3.30 +;--------------------------------------- ;3.30 + ;3.30 + ;3.30 +SYSINITSEG SEGMENT PUBLIC 'SYSTEM_INIT' + +ASSUME CS:SYSINITSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING + + ;3.30 + EXTRN BADCOM:BYTE ;3.30 + EXTRN SYSSIZE:BYTE ;3.30 + EXTRN CONDEV:BYTE,AUXDEV:BYTE,PRNDEV:BYTE,COMMND:BYTE ;3.30 + extrn DeviceParameters:byte ;3.30 + ;3.30 + EXTRN INT24:NEAR,MEM_ERR:NEAR ;3.30 + EXTRN DOCONF:NEAR ;3.30 + + PUBLIC CURRENT_DOS_LOCATION + PUBLIC FINAL_DOS_LOCATION + PUBLIC DEVICE_LIST + PUBLIC SYSI_COUNTRY ;3.30 + PUBLIC MEMORY_SIZE + PUBLIC DEFAULT_DRIVE + PUBLIC BUFFERS + PUBLIC FILES + PUBLIC NUM_CDS ;3.30 + PUBLIC SYSINIT + PUBLIC CNTRYFILEHANDLE ;3.30 + PUBLIC COMMAND_LINE ;3.30 + + IF STACKSW +; Internal Stack Information + PUBLIC STACK_COUNT + PUBLIC STACK_SIZE + PUBLIC STACK_ADDR + ENDIF + + PUBLIC dosinfo,entry_point + PUBLIC fcbs,keep + PUBLIC confbot,alloclim + PUBLIC zero,sepchr,STALL + PUBLIC count,chrptr + PUBLIC bufptr,memlo,prmblk,memhi + PUBLIC ldoff,area,PACKET,UNITCOUNT + PUBLIC BREAK_ADDR,BPB_ADDR,drivenumber + +SYSINIT$: ;3.30 + IF STACKSW ;3.30 + include MSSTACK.INC ;Main stack program and data defin;3.30 itions + include STKMES.INC ;Fatal stack error message ;3.30 + public Endstackcode ;3.30 +Endstackcode label byte ;3.30 + ENDIF ;3.30 + +; +SYSINIT: + JMP GOINIT + +DOSINFO LABEL DWORD + DW 0000 +CURRENT_DOS_LOCATION DW 0000 + +MSDOS LABEL DWORD +ENTRY_POINT LABEL DWORD + DW 0000 +FINAL_DOS_LOCATION DW 0000 +DEVICE_LIST DD 00000000 + +SYSI_Country LABEL DWORD ; 5/29/86 Pointer to ;3.30 + DW 0000 ;country table in DOS ;3.30 + DW 0000 ;3.30 + + IF STACKSW +; +; Internal Stack Parameters + +STACK_COUNT DW DefaultCount +STACK_SIZE DW DefaultSize +STACK_ADDR DD 00000000 + ENDIF + +; various default values + +MEMORY_SIZE DW 0001 +DEFAULT_DRIVE DB 00 +BUFFERS DW -1 ; initialized during buffer allocation +;BUFFERS DW 2 ; two buffers +FILES DB 8 ; enough files for pipe +FCBS DB 4 ; performance for recycling +Keep DB 0 ; keep original set +NUM_CDS DB 5 ; 5 net drives +CONFBOT DW ? +ALLOCLIM DW ? +FOOSTRNG DB "A:\",0 +COMMAND_LINE DB 2,0,"P" ;Default Command.com Args + DB 29 DUP (0) +ZERO DB 0 +SepChr DB 0 + + ;3.30 +Sys_Model_Byte db 0FFh ;model byte used in SYSINIT ;3.30 +Sys_Scnd_Model_Byte db 0 ;secondary model byte used in SYSI;3.30 NIT + ;3.30 + IF NOT NOEXEC +COMEXE EXEC0 <0,COMMAND_LINE,DEFAULT_DRIVE,ZERO> + ENDIF + +COUNT DW 0000 +CHRPTR DW 0000 +CntryFilehandle DW 0000 ;3.30 + +BUFPTR LABEL DWORD ;LEAVE THIS STUFF IN ORDER! +MEMLO DW 0 +PRMBLK LABEL WORD +MEMHI DW 0 +LDOFF DW 0 +AREA DW 0 + +PACKET DB 22 + DB 0 + DB 0 ;INITIALIZE CODE + DW 0 + DB 8 DUP (?) +UNITCOUNT DB 0 +BREAK_ADDR DD 0 +BPB_ADDR DD 0 +DriveNumber DB 0 + +TempStack DB 80h DUP (?) + +GOINIT: +; before doing anything else, let's set the model byte ;3.30 + mov ah,0c0h ;get system configuration ;3.30* + int 15h ; * ;3.30* + jc No_ROM_Config ;3.30 + cmp ah, 0 ; double check ;3.30 + jne No_ROM_Config ;3.30 + mov al, ES:[BX.bios_SD_modelbyte] ;3.30 + mov cs:[Sys_Model_Byte], al ;3.30 + mov al, ES:[BX.bios_SD_scnd_modelbyte] ;3.30 + mov cs:[Sys_Scnd_Model_Byte], al ;3.30 + jmp short Move_Myself ;3.30 +No_ROM_Config: ; Old ROM ;3.30 + mov ax, 0f000h ;3.30 + mov ds, ax ;3.30 + mov al, byte ptr ds:[0fffeh] ;3.30 + mov cs:[Sys_Model_Byte], al ;set the model byte. ;3.30 + ;3.30 +Move_Myself: ;3.30 + CLD ; Set up move + XOR SI,SI + MOV DI,SI + + IF MSVER + MOV CX,cs:[MEMORY_SIZE] ;3.30 + CMP CX,1 ; 1 means do scan + JNZ NOSCAN + MOV CX,2048 ;START SCANNING AT 32K BOUNDARY + XOR BX,BX + +MEMSCAN:INC CX + JZ SETEND + MOV DS,CX + MOV AL,[BX] + NOT AL + MOV [BX],AL + CMP AL,[BX] + NOT AL + MOV [BX],AL + JZ MEMSCAN +SETEND: + MOV cs:[MEMORY_SIZE],CX + ENDIF + + IF IBMVER OR IBMJAPVER + MOV CX,cs:[MEMORY_SIZE] + ENDIF + +NOSCAN: ; CX is mem size in para + MOV AX,CS + MOV DS,AX +ASSUME DS:SYSINITSEG + + MOV AX,OFFSET SYSSIZE + Call ParaRound + SUB CX,AX ;Compute new sysinit location + MOV ES,CX + MOV CX,OFFSET SYSSIZE + 1 + SHR CX,1 ;Divide by 2 to get words + REP MOVSW ;RELOCATE SYSINIT + + ASSUME ES:SYSINITSEG + + PUSH ES + MOV AX,OFFSET SYSIN + PUSH AX + +AAA_DUMMY PROC FAR ;3.30 + RET +AAA_DUMMY ENDP ;3.30 +; +; MOVE THE DOS TO ITS PROPER LOCATION +; +SYSIN: + + ASSUME DS:NOTHING,ES:SYSINITSEG,SS:NOTHING + + MOV AX,[CURRENT_DOS_LOCATION] ; Where it is (set by BIOS) ;3.30 + MOV DS,AX + MOV AX,[FINAL_DOS_LOCATION] ; Where it is going (set by BI;3.30 OS) + MOV ES,AX + + ASSUME ES:NOTHING + + XOR SI,SI + MOV DI,SI + + MOV CX,DOSSIZE/2 + REP MOVSW + + LDS SI,[DEVICE_LIST] ; Set for call to DOSINIT + MOV DX,[MEMORY_SIZE] ; Set for call to DOSINIT + + CLI + MOV AX,CS + MOV SS,AX + MOV SP,OFFSET LOCSTACK ; Set stack + + ASSUME SS:SYSINITSEG + + IF NOT ALTVECT + STI ; Leave INTs disabled for ALTVECT + ENDIF +LOCSTACK LABEL BYTE + + CALL MSDOS ; Call DOSINIT + mov ax, word ptr es:[di.SYSI_InitVars] ; 5/29/86 ;3.30 + mov word ptr [dosinfo], ax ;3.30 + mov ax, word ptr es:[di.SYSI_InitVars+2] ;3.30 + mov word ptr [dosinfo+2],ax ;set the sysvar pointer ;3.30 + ;3.30 + mov ax, word ptr es:[di.SYSI_Country_Tab] ;3.30 + mov word ptr [SYSI_Country],ax ;3.30 + mov ax, word ptr es:[di.SYSI_Country_Tab+2] ;3.30 + mov word ptr [SYSI_Country+2],ax ;set the SYSI_Country poin;3.30 ter + ;3.30 + les di, dosinfo ;es:di -> dosinfo ;3.30 + + MOV AL,ES:[DI.SYSI_NUMIO] + MOV DriveNumber,AL ; Save start of installable block drvs + + MOV AX,CS + SUB AX,11H ; room for header we will copy shortly + MOV [CONFBOT],AX ; Temp "unsafe" location + + PUSH DS ; Save as input to RE_INIT + PUSH CS + POP DS +ASSUME DS:SYSINITSEG + CALL TEMPCDS ; Set up CDSs so RE_INIT and SYSINIT + ; can make DISK system calls + + POP DS ; Recover DS input to RE_INIT +ASSUME DS:NOTHING + + IF NOT IBMJAPVER + CALL RE_INIT ; Re-call the BIOS + ENDIF + + STI ; INTs OK + CLD ; MAKE SURE +; DOSINIT has set up a default "process" (PHP) at DS:0. We will move it out +; of the way by putting it just below SYSINIT at end of memory. + MOV BX,CS + SUB BX,10H + MOV ES,BX + XOR SI,SI + MOV DI,SI + MOV CX,80H + REP MOVSW + MOV WORD PTR ES:[PDB_JFN_Pointer + 2],ES ; Relocate + MOV AH,SET_CURRENT_PDB + INT 21H ; Tell DOS we moved it + PUSH DS + PUSH CS + POP DS +ASSUME DS:SYSINITSEG + MOV DX,OFFSET INT24 ;SET UP INT 24 HANDLER + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H + INT 21H + + MOV BX,0FFFFH + MOV AH,ALLOC + INT 21H ;FIRST TIME FAILS + MOV AH,ALLOC + INT 21H ;SECOND TIME GETS IT + MOV [AREA],AX + MOV [MEMHI],AX ; MEMHI:MEMLO now points to + ; start of free memory + IF ALTVECT + MOV DX,OFFSET BOOTMES + invoke PRINT ;Print message DOSINIT couldn't + ENDIF + + POP DS +ASSUME DS:NOTHING + + MOV DL,[DEFAULT_DRIVE] + OR DL,DL + JZ NODRVSET ; BIOS didn't say + DEC DL ;A = 0 + MOV AH,SET_DEFAULT_DRIVE + INT 21H ;SELECT THE DISK +NODRVSET: + + CALL DOCONF ;DO THE CONFIG STUFF + CALL ENDFILE ;Set the system according to Confi;3.30 g.sys file info. + + IF NOEXEC + MOV BP,DS ;SAVE COMMAND.COM SEGMENT + PUSH DS + POP ES + MOV BX,CS + SUB BX,10H ; Point to current PHP + MOV DS,BX + XOR SI,SI + MOV DI,SI + MOV CX,80H + REP MOVSW ; Copy it to new location for shell + MOV WORD PTR ES:[PDB_JFN_Pointer + 2],ES ; Relocate + MOV BX,ES + MOV AH,SET_CURRENT_PDB + INT 21H ; Tell DOS we moved it + MOV ES:[PDB_PARENT_PID],ES ;WE ARE THE ROOT + ENDIF + +; We must now close all handles and reopen STDIN,STDOUT,STDERR in order +; to get a possibly NEW device driver for CON. STDAUX and STDPRN must +; also be openned. + PUSH CS + POP DS +ASSUME DS:SYSINITSEG + MOV AL,[FILES] + XOR AH,AH ; DO NOT USE CBW INSTRUCTION!!!!! + ; IT DOES SIGN EXTEND. + MOV CX,AX + XOR BX,BX ;Close standard input + MOV AH,CLOSE + INT 21H + MOV BX,2 +RCCLLOOP: ;Close everybody but standard output + MOV AH,CLOSE ; Need output so we can print message + INT 21H ; in case we can't get new one open. + INC BX + LOOP RCCLLOOP + + MOV DX,OFFSET CONDEV + MOV AL,2 + MOV AH,OPEN ;OPEN CON FOR READ/WRITE + STC ; Set for possible INT 24 + INT 21H + JNC GOAUX + INVOKE BADFIL + JMP SHORT GOAUX2 + +GOAUX: PUSH AX + MOV BX,1 ;close standard output + MOV AH,CLOSE + INT 21H + POP AX + + MOV BX,AX ;New device handle + MOV AH,XDUP + INT 21H ;Dup to 1, STDOUT + MOV AH,XDUP + INT 21H ;Dup to 2, STDERR + +GOAUX2: MOV DX,OFFSET AUXDEV + MOV AL,2 ;READ/WRITE ACCESS + INVOKE OPEN_DEV + + MOV DX,OFFSET PRNDEV + MOV AL,1 ;WRITE ONLY + INVOKE OPEN_DEV + +;Global Rearm command for Shared Interrupt devices attached in the system; +;Shared interrupt attachment has some problem when it issues interrupt +;during a warm reboot. Once the interrupt is presented by the attachment, +;no further interrupts on that level will be presented until a global rearm +;is issued. BIOS will issue a global rearm after each device driver is loaded. +;To issue a global rearm: ;For PC1, XT, Palace +; OUT 02F2h, XX ; Interrupt level 2 +; OUT 02F3h, XX ; Interrupt level 3 +; OUT 02F4h, XX ; Interrupt level 4 +; OUT 02F5h, XX ; Interrupt level 5 +; OUT 02F6h, XX ; Interrupt level 6 +; OUT 02F7h, XX ; Interrupt level 7 +; +; ;For PC AT, in addition to the above commands, +; ;need to handle the secondary interrupt handler +; OUT 06F2h, XX ; Interrupt level 10 +; OUT 06F3h, XX ; Interrupt level 11 +; OUT 06F4h, XX ; Interrupt level 12 +; OUT 06F6h, XX ; Interrupt level 14 +; OUT 06F7h, XX ; Interrupt level 15 +; +; ;For All others machine +; None. +; where XX stands for any value. + + PUSH AX ;Save register + PUSH BX ;Save register + PUSH DX ;Save register + PUSH ES ;Save register + + MOV AL,0FFH ;Set up registers for global rearm + MOV DX,02F2H ; + OUT DX,AL ;OUT 02F2H,0FFH + INC DX ; + OUT DX,AL ;OUT 02F3H,0FFH + INC DX ; + OUT DX,AL ;OUT 02F4H,0FFH + INC DX ; + OUT DX,AL ;OUT 02F5H,0FFH + INC DX ; + OUT DX,AL ;OUT 02F6H,0FFH + INC DX ; + OUT DX,AL ;OUT 02F7H,0FFH + + MOV AX,0F000H ;Get machine type + MOV ES,AX ; + CMP BYTE PTR ES:[0FFFEH],0FCH ;Q: Is it an AT type machine? + JNE REARMDONE ; N: Skip next rearm + MOV AH,0C0H ;Get system configuration + INT 15H ;Q: Is it an old ROM? + JC REARMDONE ; Y: Skip next rearm + TEST ES:[BX.BIOS_SD_FEATUREBYTE1],SCNDINTCONTROLLER ; Q: Present? + JE REARMDONE ; N: Skip next rearm + + MOV AL,0FFH ;Set up registers for global rearm + MOV DX,06F2H ; + OUT DX,AL ;OUT 06F2H,0FFH + INC DX ; + OUT DX,AL ;OUT 06F3H,0FFH + INC DX ; + OUT DX,AL ;OUT 06F4H,0FFH + INC DX ; + INC DX ; + OUT DX,AL ;OUT 02F6H,0FFH + INC DX ; + OUT DX,AL ;OUT 02F7H,0FFH + +REARMDONE: + POP ES ;Restore register + POP DX ;Restore register + POP BX ;Restore register + POP AX ;Restore register + +;Global Rearm end ******************* + +; +; SET UP THE PARAMETERS FOR COMMAND +; +GOSET: + MOV SI,OFFSET COMMAND_LINE+1 + + IF NOEXEC + MOV DI,81H + ELSE + PUSH DS + POP ES + MOV DI,SI + ENDIF + + MOV CL,-1 +COMTRANLP: ;FIND LENGTH OF COMMAND LINE + INC CL + LODSB + STOSB ;COPY COMMAND LINE IN + OR AL,AL + JNZ COMTRANLP + DEC DI + MOV AL,0DH ; CR terminate + STOSB + + IF NOEXEC + MOV ES:[80H],CL ; Set up header + MOV AL,[DEFAULT_DRIVE] + MOV ES:[5CH],AL + ELSE + MOV [COMMAND_LINE],CL ;Count + ENDIF + + MOV DX,OFFSET COMMND ;NOW POINTING TO FILE DESCRIPTION + + IF NOEXEC + MOV ES,BP ;SET LOAD ADDRESS + MOV BX,100H + CALL LDFIL ;READ IN COMMAND + JC COMERR + MOV DS,BP + MOV DX,80H + MOV AH,SET_DMA ;SET DISK TRANFER ADDRESS + INT 21H + CLI + MOV SS,BP + MOV SP,DX + STI + XOR AX,AX ;PUSH A WORD OF ZEROS + PUSH AX + PUSH BP ;SET HIGH PART OF JUMP ADDRESS + MOV AX,100H + PUSH AX ;SET LOW PART OF JUMP ADDRESS +CCC PROC FAR + RET ;CRANK UP COMMAND! +CCC ENDP + + ELSE +; We are going to open the command interpreter and size it as is done in +; LDFIL. The reason we must do this is that SYSINIT is in free memory. If +; there is not enough room for the command interpreter, EXEC will probably +; overlay our stack and code so when it returns with an error SYSINIT won't be +; here to catch it. This code is not perfect (for instance .EXE command +; interpreters are possible) because it does its sizing based on the +; assumption that the file being loaded is a .COM file. It is close enough to +; correctness to be usable. + + PUSH DX ; Save pointer to name + +; First, find out where the command interpreter is going to go. + MOV BX,0FFFFH + MOV AH,ALLOC + INT 21H ;Get biggest piece + MOV AH,ALLOC + INT 21H ;SECOND TIME GETS IT + JC MEMERRJX ; Oooops + MOV ES,AX + MOV AH,DEALLOC + INT 21H ; Give it right back + MOV BP,BX +; ES:0 points to Block, and BP is the size of the block +; in para. + +; We will now adjust the size in BP DOWN by the size of SYSINIT. We +; need to do this because EXEC might get upset if some of the EXEC +; data in SYSINIT is overlayed during the EXEC. + MOV BX,[MEMORY_SIZE] + MOV AX,CS + SUB BX,AX ; BX is size of SYSINIT in Para + ADD BX,11H ; Add the SYSINIT PHP + SUB BP,BX ; BAIS down + JC MEMERRJX ; No Way. + + MOV AX,(OPEN SHL 8) ;OPEN THE FILE being EXECED + STC ;IN CASE OF INT 24 + INT 21H + JC COMERR ; Ooops + MOV BX,AX ;Handle in BX + XOR CX,CX + XOR DX,DX + MOV AX,(LSEEK SHL 8) OR 2 + STC ;IN CASE OF INT 24 + INT 21H ; Get file size in DX:AX + JC COMERR + ; Convert size in DX:AX to para in AX + ADD AX,15 ; Round up size for conversion to para + ADC DX,0 + MOV CL,4 + SHR AX,CL + MOV CL,12 + SHL DX,CL ; Low nibble of DX to high nibble + OR AX,DX ; AX is now # of para for file + ADD AX,10H ; 100H byte PHP + CMP AX,BP ; Will it fit? + JB OKLD ; Jump if yes. +MEMERRJX: + JMP MEM_ERR + +OKLD: + MOV AH,CLOSE + INT 21H ; Close file + POP DX ; Recover pointer to name + PUSH CS + POP ES + ASSUME ES:SYSINITSEG + MOV BX,OFFSET COMEXE ; Point to EXEC block + MOV WORD PTR [BX.EXEC0_COM_LINE+2],CS ; Set segments + MOV WORD PTR [BX.EXEC0_5C_FCB+2],CS + MOV WORD PTR [BX.EXEC0_6C_FCB+2],CS + XOR AX,AX ;Load and go + MOV AH,EXEC + STC ;IN CASE OF INT 24 + INT 21H ;GO START UP COMMAND + ENDIF +; NOTE FALL THROUGH IF EXEC RETURNS (an error) + +COMERR: + MOV DX,OFFSET BADCOM ;WANT TO PRINT COMMAND ERROR + INVOKE BADFIL +STALL: JMP STALL + + PUBLIC TEMPCDS ;3.30 +TEMPCDS: +ASSUME DS:SYSINITSEG + LES DI,[DOSINFO] + + MOV CL,BYTE PTR ES:[DI.SYSI_NUMIO] + XOR CH,CH + MOV ES:[DI.SYSI_NCDS],CL + MOV AL,CL + MOV AH,SIZE curdir_list + MUL AH + call ParaRound + MOV SI,[CONFBOT] + SUB SI,AX + MOV [ALLOCLIM],SI ; Can't alloc past here! + MOV WORD PTR ES:[DI.SYSI_CDS + 2],SI + MOV AX,SI + MOV WORD PTR ES:[DI.SYSI_CDS],0 + LDS SI,ES:[DI.SYSI_DPB] +ASSUME DS:NOTHING + MOV ES,AX + XOR DI,DI + +FOOSET: ; Init CDSs + MOV AX,WORD PTR [FOOSTRNG] + STOSW + MOV AX,WORD PTR [FOOSTRNG + 2] + STOSW + INC BYTE PTR [FOOSTRNG] + XOR AX,AX + PUSH CX + MOV CX,curdir_flags - 4 + REP STOSB + CMP SI,-1 + JNZ NORMCDS + XOR AX,AX + MOV CL,3 + REP STOSW + POP CX + JMP SHORT FINCDS + +NORMCDS: + POP CX + MOV AX,curdir_inuse + STOSW ; curdir_flags + MOV AX,SI + STOSW ; curdir_devptr + MOV AX,DS + STOSW + LDS SI,[SI.dpb_next_dpb] +FINCDS: + MOV AX,-1 + STOSW ; curdir_ID + STOSW ; curdir_ID + STOSW ; curdir_user_word + mov ax,2 + stosw ; curdir_end + LOOP FOOSET + MOV BYTE PTR [FOOSTRNG],"A" + return + + +;------------------------------------------------------------------------------ +; Allocate FILEs +;------------------------------------------------------------------------------ +ENDFILE: +; WE ARE NOW SETTING UP FINAL CDSs, BUFFERS, FILES, FCSs STRINGs etc. We no +; longer need the space taken by The TEMP stuff below CONFBOT, so set ALLOCLIM +; to CONFBOT. + MOV AX,[CONFBOT] + MOV [ALLOCLIM],AX + + PUSH CS + POP DS + INVOKE ROUND + MOV AL,[FILES] + SUB AL,5 + JBE DOFCBS + XOR AH,AH ; DO NOT USE CBW INSTRUCTION!!!!! + ; IT DOES SIGN EXTEND. + MOV BX,[MEMLO] + MOV DX,[MEMHI] + LDS DI,[DOSINFO] ;GET POINTER TO DOS DATA + LDS DI,[DI+SYSI_SFT] ;DS:BP POINTS TO SFT + MOV WORD PTR [DI+SFLINK],BX + MOV WORD PTR [DI+SFLINK+2],DX ;SET POINTER TO NEW SFT + PUSH CS + POP DS + LES DI,DWORD PTR [MEMLO] ;POINT TO NEW SFT + MOV WORD PTR ES:[DI+SFLINK],-1 + MOV ES:[DI+SFCOUNT],AX + MOV BL,SIZE SF_ENTRY + MUL BL ;AX = NUMBER OF BYTES TO CLEAR + MOV CX,AX + ADD [MEMLO],AX ;ALLOCATE MEMORY + MOV AX,6 + ADD [MEMLO],AX ;REMEMBER THE HEADER TOO + INVOKE ROUND ; Check for mem error before the STOSB + ADD DI,AX + XOR AX,AX + REP STOSB ;CLEAN OUT THE STUFF + +;------------------------------------------------------------------------------ +; Allocate FCBs +;------------------------------------------------------------------------------ +DOFCBS: + PUSH CS + POP DS + INVOKE ROUND + MOV AL,[FCBS] + XOR AH,AH ; DO NOT USE CBW INSTRUCTION!!!!! + ; IT DOES SIGN EXTEND. + MOV BX,[MEMLO] + MOV DX,[MEMHI] + LDS DI,[DOSINFO] ;GET POINTER TO DOS DATA + ASSUME DS:NOTHING + MOV WORD PTR [DI+SYSI_FCB],BX + MOV WORD PTR [DI+SYSI_FCB+2],DX ;SET POINTER TO NEW Table + MOV BL,CS:Keep + XOR BH,BH + MOV [DI+SYSI_keep],BX + PUSH CS + POP DS + ASSUME DS:SYSINITSEG + LES DI,DWORD PTR [MEMLO] ;POINT TO NEW Table + MOV WORD PTR ES:[DI+SFLINK],-1 + MOV ES:[DI+SFCOUNT],AX + MOV BL,SIZE SF_ENTRY + MOV CX,AX + MUL BL ;AX = NUMBER OF BYTES TO CLEAR + ADD [MEMLO],AX ;ALLOCATE MEMORY + MOV AX,size sf-2 + ADD [MEMLO],AX ;REMEMBER THE HEADER TOO + INVOKE ROUND ; Check for mem error before the STOSB + ADD DI,AX ;Skip over header + MOV AL,"A" +FillLoop: + PUSH CX ; save count + MOV CX,SIZE sf_entry ; number of bytes to fill + cld + REP STOSB ; filled + MOV WORD PTR ES:[DI-(SIZE sf_entry)+sf_ref_count],0 + MOV WORD PTR ES:[DI-(SIZE sf_entry)+sf_position],0 + MOV WORD PTR ES:[DI-(SIZE sf_entry)+sf_position+2],0 + POP CX + LOOP FillLoop + +;------------------------------------------------------------------------------ +; Allocate Buffers +;------------------------------------------------------------------------------ + +; Search through the list of media supported and allocate 3 buffers if the +; capacity of the drive is > 360KB + + CMP [BUFFERS], -1 ; Has buffers been already set? + je DoDefaultBuff ;3.30 + jmp DOBUFF ; the user entered the buf;3.30 fers=. + ;3.30 +DoDefaultBuff: ;3.30 + + MOV [BUFFERS], 2 ; Default to 2 buffers + PUSH AX + PUSH DS + LES BP,CS:[DOSINFO] ; Search through the DPB's + LES BP,DWORD PTR ES:[BP.SYSI_DPB] ; Get first DPB + +ASSUME DS:SYSINITSEG + PUSH CS + POP DS + +NEXTDPB: + ; Test if the drive supports removeable media + MOV BL, BYTE PTR ES:[BP.DPB_DRIVE] + INC BL + MOV AX, (IOCTL SHL 8) OR 8 + INT 21H + +; Ignore fixed disks + OR AX, AX ; AX is nonzero if disk is nonremoveable + JNZ NOSETBUF + +; Get parameters of drive + XOR BX, BX + MOV BL, BYTE PTR ES:[BP.DPB_DRIVE] + INC BL + MOV DX, OFFSET DeviceParameters + MOV AX, (IOCTL SHL 8) OR GENERIC_IOCTL + MOV CX, (RAWIO SHL 8) OR GET_DEVICE_PARAMETERS + INT 21H + JC NOSETBUF ; Get next DPB if driver doesn't support + ; Generic IOCTL + +; Determine capacity of drive +; Media Capacity = #Sectors * Bytes/Sector + MOV BX, WORD PTR DeviceParameters.DP_BPB.BPB_TotalSectors + +; To keep the magnitude of the media capacity within a word, +; scale the sector size +; (ie. 1 -> 512 bytes, 2 -> 1024 bytes, ...) + MOV AX, WORD PTR DeviceParameters.DP_BPB.BPB_BytesPerSector + XOR DX, DX + MOV CX, 512 + DIV CX ; Scale sector size in factor of + ; 512 bytes + + MUL BX ; AX = #sectors * size factor + OR DX, DX ; Just in case of LARGE floppies + JNZ SETBUF + CMP AX, 720 ; 720 Sectors * size factor of 1 + JBE NOSETBUF +SETBUF: + MOV [BUFFERS], 3 + jmp Chk_Memsize_for_Buffers ; Now check the memory siz;3.30 e for default buffer count +NOSETBUF: + CMP WORD PTR ES:[BP.DPB_NEXT_DPB],-1 + jz Chk_Memsize_for_Buffers ;3.30 + LES BP,ES:[BP.DPB_NEXT_DPB] + JMP NEXTDPB + +;From DOS 3.3, the default number of buffers will be changed according to ;3.30 the +;memory size too. ;3.30 +; Default buffers = 2 ;3.30 +; If diskette Media > 360 kb, then default buffers = 3 ;3.30 +; If memory size > 128 kb (2000H para), then default buffers = 5 ;3.30 +; If memory size > 256 kb (4000H para), then default buffers = 10 ;3.30 +; If memory size > 512 kb (8000H para), then default buffers = 15. ;3.30 + ;3.30 +Chk_Memsize_for_Buffers: ;3.30 + cmp [memory_size], 2000h ;3.30 + jbe BufSet ;3.30 + mov [buffers], 5 ;3.30 + cmp [memory_size], 4000h ;3.30 + jbe BufSet ;3.30 + mov [buffers], 10 ;3.30 + cmp [memory_size], 8000h ;3.30 + jbe BufSet ;3.30 + mov [buffers], 15 ;3.30 + ;3.30 +BUFSET: +ASSUME DS:NOTHING + POP DS + POP AX +DOBUFF: + + INVOKE ROUND + DEC [BUFFERS] ; FIRST DEC acounts for buffer already + ; in system. + JZ BUF1 ; All done + PUSH DS + LES DI,BUFPTR + LDS BX,DOSINFO + MOV AX,WORD PTR [BX.SYSI_BUF] ; Link in new buffer + MOV WORD PTR ES:[DI.buf_link],AX + MOV AX,WORD PTR [BX.SYSI_BUF+2] + MOV WORD PTR ES:[DI.buf_link+2],AX + MOV WORD PTR [BX.SYSI_BUF],DI + MOV WORD PTR [BX.SYSI_BUF+2],ES + MOV WORD PTR ES:[DI.buf_ID],00FFH ;NEW BUFFER FREE + MOV BX,[BX.SYSI_MAXSEC] + POP DS + ADD BX,BUFINSIZ + ADD [MEMLO],BX + JMP DOBUFF + +;------------------------------------------------------------------------------ +; Allocate CDSs +;------------------------------------------------------------------------------ +BUF1: + INVOKE ROUND + LES DI,[DOSINFO] + MOV CL,BYTE PTR ES:[DI.SYSI_NUMIO] + CMP CL,[NUM_CDS] + JAE GOTNCDS ; User setting must be at least NUMIO + MOV CL,[NUM_CDS] +GOTNCDS: + XOR CH,CH + MOV ES:[DI.SYSI_NCDS],CL + MOV AX,[MEMHI] + MOV WORD PTR ES:[DI.SYSI_CDS + 2],AX + MOV AX,[MEMLO] + MOV WORD PTR ES:[DI.SYSI_CDS],AX + MOV AL,CL + MOV AH,SIZE curdir_list + MUL AH + call ParaRound + ADD [MEMHI],AX + INVOKE ROUND ; Check for mem error before initializing + LDS SI,ES:[DI.SYSI_DPB] +ASSUME DS:NOTHING + LES DI,ES:[DI.SYSI_CDS] + CALL FOOSET + +;------------------------------------------------------------------------------ +; Allocate Space for Internal Stack +;------------------------------------------------------------------------------ + + IF STACKSW + + PUSH CS ;3.30 + POP DS ;3.30 + ASSUME DS:SYSINITSEG ;3.30 + + IF IBM + +;Don't install the system stack on the PCjr. Ignore STACKS=command too. ;3.30 + CMP [Sys_Model_Byte], 0FDh ; PCjr = 0FDh ;3.30 + JE SkipStack ;3.30 + ENDIF ;3.30 + ;3.30 +;If the use does not entered STACKS= command, as a default, do not install;3.30 +;sytem stacks for PC1, PC XT, PC Portable cases. ;3.30 +;Otherwise, install it to the user specified value or to the default ;3.30 +;value of 9, 128 for the rest of the system. ;3.30 + ;3.30 + cmp word ptr [stack_addr], -1 ;Has the user entered "sta;3.30 cks=" command? + je DoInstallStack ;Then install as specified;3.30 by the user + cmp [Sys_Scnd_Model_Byte], 0 ;PC1, XT has the secondary;3.30 model byte = 0 + jne DoInstallStack ;Other model should have d;3.30 efault stack of 9, 128 + cmp [Sys_Model_Byte], 0FFh ;PC1 ? ;3.30 + je SkipStack ;3.30 + cmp [Sys_Model_Byte], 0FEh ;PC/XT or PC Portable ? ;3.30 + je SkipStack ;3.30 + ;3.30 +DoInstallStack: ;3.30 + mov ax, [stack_count] ; Stack_count = 0? ;3.30 + cmp ax, 0 ;then, stack size must be ;3.30 0 too. + jz SkipStack ;Don't install stack. ;3.30 +; 10/21/86 Dynamic Relocation of Stack code. ;3.30 + call Round ;[memhi] = Seg. for stack ;3.30 code + ;[memlo] = 0 ;3.30 + mov ax, [memhi] ;3.30 + mov es, ax ;ES -> Seg. the stack code;3.30 is going to move. + assume es:nothing ;3.30 + push cs ;3.30 + pop ds ;3.30 + xor si,si ;!!We know that Stack code;3.30 is at the beginning of SYSINIT. + xor di,di ;3.30 + mov cx, offset Endstackcode ;3.30 + mov [memlo],cx ;3.30 + call Round ;Have enough space for rel;3.30 ocation? + rep movsb ;3.30 + ;3.30 + MOV AX, [MEMLO] ; Set address of stacks + MOV word ptr [STACK_ADDR],AX + MOV AX, [MEMHI] + MOV word ptr [STACK_ADDR+2],AX + +; Space for Internal Stack = STACK_COUNT(ENTRYSIZE + STACK_SIZE) + MOV AX, EntrySize + ADD AX, [STACK_SIZE] + MOV CX, [STACK_COUNT] + MUL CX + call ParaRound ; Convert size to pargraphs + ADD [MEMHI], AX + INVOKE ROUND ; Check for memory error before + ; continuing + CALL StackInit ; Initialize hardware stack + +SkipStack: + ENDIF + + PUSH CS + POP DS + ASSUME DS:SYSINITSEG +;------------------------------------------------------------------------------ +; Allocate rest of memory to system +;------------------------------------------------------------------------------ + INVOKE ROUND + MOV BX,[MEMHI] + MOV AX,[AREA] + MOV ES,AX ;CALC WHAT WE NEEDED + SUB BX,AX + MOV AH,SETBLOCK + INT 21H ;GIVE THE REST BACK + PUSH ES + MOV AX,ES + DEC AX + MOV ES,AX ;Point to arena + MOV ES:[arena_owner],8 ;Set impossible owner + POP ES + + IF NOEXEC + MOV BX,0FFFFH ;ALLOCATE THE REST OF MEM FOR COMMAND + MOV AH,ALLOC + INT 21H + MOV AH,ALLOC + INT 21H + MOV DS,AX + ENDIF + + return + +Public ParaRound +ParaRound: + ADD AX,15 + RCR AX,1 + SHR AX,1 + SHR AX,1 + SHR AX,1 + return + +;-------------------------------------------------------------------------;3.30 ----- +; 5/6/86. MSSTACK initialization routine. ;3.30 + IF STACKSW ;3.30 + ;3.30 +INCLUDE STKINIT.INC ;3.30 + ;3.30 + ENDIF ;3.30 +;-------------------------------------------------------------------------;3.30 ----- + +SYSINITSEG ENDS + END + \ No newline at end of file diff --git a/SRC/BIOS/SYSINIT1.OBJ b/SRC/BIOS/SYSINIT1.OBJ new file mode 100644 index 0000000..154a264 Binary files /dev/null and b/SRC/BIOS/SYSINIT1.OBJ differ diff --git a/SRC/BIOS/SYSINIT2.ASM b/SRC/BIOS/SYSINIT2.ASM new file mode 100644 index 0000000..f996d1f --- /dev/null +++ b/SRC/BIOS/SYSINIT2.ASM @@ -0,0 +1,1256 @@ +TITLE BIOS SYSTEM INITIALIZATION +TRUE EQU 0FFFFh +FALSE EQU 0 + +;IBMVER EQU TRUE +;IBM EQU IBMVER +STACKSW EQU TRUE ;Include Switchable Hardware Stks ;3.30 +;IBMJAPVER EQU FALSE ;If TRUE set KANJI true also +;MSVER EQU FALSE +;ALTVECT EQU FALSE ;Switch to build ALTVECT version +;KANJI EQU FALSE + +include version.inc + + IF IBMJAPVER +NOEXEC EQU TRUE + ELSE +NOEXEC EQU FALSE + ENDIF + +DOSSIZE EQU 0A000H + +.xlist + include smdossym.inc ; Reduced version of DOSSYM.INC ;3.30 + INCLUDE devsym.inc + include ioctl.inc +.list + + IF NOT IBM + IF NOT IBMJAPVER + EXTRN RE_INIT:FAR + ENDIF + ENDIF + +SYSINITSEG SEGMENT PUBLIC 'SYSTEM_INIT' BYTE + +ASSUME CS:SYSINITSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING + + EXTRN BADOPM:BYTE,CRLFM:BYTE,BADCOM:BYTE,BADMEM:BYTE,BADBLOCK:BYTE + EXTRN BADSIZ_PRE:BYTE,BADLD_PRE:BYTE + EXTRN BADSIZ_POST:BYTE,BADLD_POST:BYTE + EXTRN SYSSIZE:BYTE,BADCOUNTRY:BYTE + + EXTRN dosinfo:dword,entry_point:dword, + EXTRN MEMORY_SIZE:WORD,fcbs:byte,keep:byte + EXTRN DEFAULT_DRIVE:BYTE,confbot:word,alloclim:word + EXTRN BUFFERS:WORD,zero:byte,sepchr:byte + EXTRN FILES:BYTE,stall:near + EXTRN count:word,chrptr:word + EXTRN bufptr:byte,memlo:word,prmblk:byte,memhi:word + EXTRN ldoff:word,area:word,PACKET:BYTE,UNITCOUNT:BYTE, + EXTRN BREAK_ADDR:DWORD,BPB_ADDR:DWORD,drivenumber:byte + + PUBLIC Int24,Open_Dev,Organize,Mem_Err,Newline,CallDev,Badload + PUBLIC PrnDev,AuxDev,Config,Commnd,Condev,GetNum,BadFil,PrnErr + PUBLIC Round,Delim,Print,Set_Break + PUBLIC SetParms, ParseLine, DiddleBack + PUBLIC Skip_delim,SetDOSCountryInfo,Set_Country_Path,Move_Asciiz ;3.30 + PUBLIC Cntry_Drv,Cntry_Root,Cntry_Path ;3.30 + PUBLIC Delim ;3.30 + +ASSUME DS:SYSINITSEG +; +; The following set of routines is used to parse the DRIVPARM = command in +; the CONFIG.SYS file to change the default drive parameters. +; +SetParms: + push ds + push ax + push bx + push cx + push dx + xor bx,bx + mov bl,byte ptr drive + inc bl ; get it correct for IOCTL call (1=A,2=B...) + push cs + pop ds + mov dx,offset DeviceParameters + mov ah, IOCTL + mov al, GENERIC_IOCTL + mov ch, RAWIO + mov cl, SET_DEVICE_PARAMETERS + int 21H + pop dx + pop cx + pop bx + pop ax + pop ds + ret + +; +; Replace default values for further DRIVPARM commands +; +DiddleBack: + mov word ptr DeviceParameters.DP_Cylinders,80 + mov byte ptr DeviceParameters.DP_DeviceType, DEV_3INCH720KB + mov word ptr DeviceParameters.DP_DeviceAttributes,0 + mov word ptr switches,0 ; zero all switches + ret + +; +; Entry point is ParseLine. AL contains the first character in command line. +; +ParseLine: ; don't get character first time + push ds + push cs + pop ds +NextSwtch: + cmp al,13 ; carriage return? + jz done_line + cmp al,10 ; linefeed? + jz put_back ; put it back and done +; Anything less or equal to a space is ignored. + cmp al,' ' ; space? + jbe get_next ; skip over space + cmp al,'/' + jz getparm + stc ; mark error invalid-character-in-input + jmp short exitpl + +getparm: + call Check_Switch + mov word ptr Switches,BX ; save switches read so far + jc swterr +get_next: + invoke getchr + jc done_line + jmp NextSwtch +swterr: + jmp exitpl ; exit if error + +done_line: + test word ptr Switches,flagdrive ; see if drive specified + jnz okay + stc ; mark error no-drive-specified + jmp short exitpl + +okay: + mov ax,word ptr switches + and ax,0003H ; get flag bits for changeline and non-rem + mov word ptr DeviceParameters.DP_DeviceAttributes,ax + mov word ptr DeviceParameters.DP_TrackTableEntries, 0 + clc ; everything is fine + call SetDeviceParameters +exitpl: + pop ds + ret + +put_back: + inc count ; one more char to scan + dec chrptr ; back up over linefeed + jmp short done_line +; +; Processes a switch in the input. It ensures that the switch is valid, and +; gets the number, if any required, following the switch. The switch and the +; number *must* be separated by a colon. Carry is set if there is any kind of +; error. +; +Check_Switch: + invoke getchr + jc err_check + and al,0DFH ; convert it to upper case + cmp al,'A' + jb err_check + cmp al,'Z' + ja err_check + push es + push cs + pop es + mov cl,byte ptr switchlist ; get number of valid switches + mov ch,0 + mov di,1+offset switchlist ; point to string of valid switches + repne scasb + pop es + jnz err_check + mov ax,1 + shl ax,cl ; set bit to indicate switch + mov bx,word ptr switches ; get switches so far + or bx,ax ; save this with other switches + mov cx,ax + test ax,7cH ; test against switches that require number to follow + jz done_swtch + invoke getchr + jc err_Swtch + cmp al,':' + jnz err_swtch + invoke getchr + push bx ; preserve switches + mov byte ptr cs:sepchr,' ' ; allow space separators + call GetNum + mov byte ptr cs:sepchr,0 + pop bx ; restore switches +; Because GetNum does not consider carriage-return or line-feed as OK, we do +; not check for carry set here. If there is an error, it will be detected +; further on (hopefully). + call Process_Num + +done_swtch: + clc + ret + +err_swtch: + xor bx,cx ; remove this switch from the records +err_check: + stc + ret + +; +; This routine takes the switch just input, and the number following (if any), +; and sets the value in the appropriate variable. If the number input is zero +; then it does nothing - it assumes the default value that is present in the +; variable at the beginning. Zero is OK for form factor and drive, however. +; +Process_Num: + test word ptr Switches,cx ; if this switch has been done before, + jnz done_ret ; ignore this one. + test cx,flagdrive + jz try_f + mov byte ptr drive,al + jmp short done_ret + +try_f: + test cx,flagff + jz try_t +; Ensure that we do not get bogus form factors that are not supported + ;cmp al,Max_Dev_Type + ;ja done_ret + mov byte ptr DeviceParameters.DP_DeviceType,al + jmp short done_ret + +try_t: + or ax,ax + jz done_ret ; if number entered was 0, assume default value + test cx,flagcyln + jz try_s + mov word ptr DeviceParameters.DP_Cylinders,ax + jmp short done_ret + +try_s: + test cx,flagseclim + jz try_h + mov word ptr slim,ax + jmp short done_ret +; +; Must be for number of heads +try_h: + mov word ptr hlim,ax + +done_ret: + clc + ret + +; +; SetDeviceParameters sets up the recommended BPB in each BDS in the +; system based on the form factor. It is assumed that the BPBs for the +; various form factors are present in the BPBTable. For hard files, +; the Recommended BPB is the same as the BPB on the drive. +; No attempt is made to preserve registers since we are going to jump to +; SYSINIT straight after this routine. +; +SetDeviceParameters: + push es + push cs + pop es +ASSUME ES:SYSINITSEG + xor bx,bx + mov bl,byte ptr DeviceParameters.DP_DeviceType + cmp bl,DEV_5INCH + jnz Got_80 + mov cx,40 ; 48tpi has 40 cylinders + mov word ptr DeviceParameters.DP_Cylinders,cx +Got_80: + shl bx,1 ; get index into BPB table + mov si,offset BPBTable + mov si,word ptr [si+bx] ; get address of BPB +Set_RecBPB: + mov di,offset DeviceParameters.DP_BPB ; es:di -> BPB + mov cx,size a_BPB + cld + repe movsb + pop es +ASSUME ES:NOTHING + test word ptr switches,flagseclim + jz see_heads + mov ax,word ptr slim + mov word ptr DeviceParameters.DP_BPB.BPB_SectorsPerTrack,ax +see_heads: + test word ptr switches,flagheads + jz Set_All_Done + mov ax,word ptr hlim + mov word ptr DeviceParameters.DP_BPB.BPB_Heads,ax +; +; We need to set the media byte and the total number of sectors to reflect the +; number of heads. We do this by multiplying the number of heads by the number +; of 'sectors per head'. This is not a fool-proof scheme!! +; + mov cx,ax ; cx has number of heads + dec cl ; get it 0-based + mov ax,DeviceParameters.DP_BPB.BPB_TotalSectors ; this is OK for two heads + sar ax,1 ; ax contains # of sectors/head + sal ax,cl + jc Set_All_Done ; We have too many sectors - overflow!! + mov DeviceParameters.DP_BPB.BPB_TotalSectors,ax +; Set up correct Media Descriptor Byte + cmp cl,1 + mov bl,0F0H + mov al,2 ; AL contains sectors/cluster + ja Got_Correct_Mediad + mov bl,byte ptr DeviceParameters.DP_BPB.BPB_MediaDescriptor + je Got_Correct_Mediad +; We have one head - OK for 48tpi medium + mov al,1 ; AL contains sectors/cluster + mov ch,DeviceParameters.DP_DeviceType + cmp ch,DEV_5INCH + jz Dec_Mediad + mov bl,0F0H + jmp short Got_Correct_Mediad +Dec_Mediad: + dec bl ; adjust for one head +Got_Correct_Mediad: + mov byte ptr DeviceParameters.DP_BPB.BPB_MediaDescriptor,bl + mov byte ptr DeviceParameters.DP_BPB.BPB_SectorsPerCluster,al + clc +Set_All_Done: + RET + +ASSUME DS:NOTHING, ES:NOTHING + +NOCHAR1: STC + return + +ORGANIZE: + MOV CX,[COUNT] + JCXZ NOCHAR1 + CALL MAPCASE + XOR SI,SI + MOV DI,SI + +ORG1: CALL GET ;SKIP LEADING CONTROL CHARACTERS + CMP AL,' ' + JB ORG1 + + PUSH CX + PUSH SI + PUSH DI + MOV BP,SI + DEC BP + MOV SI,OFFSET COMTAB ;Prepare to search command table + MOV CH,0 +FINDCOM: + MOV DI,BP + MOV CL,[SI] + INC SI + JCXZ NOCOM + REPE CMPSB + LAHF + ADD SI,CX ;Bump to next position without affecting flags + SAHF + LODSB ;Get indicator letter + JNZ FINDCOM + POP DI + POP SI + POP CX + JMP SHORT GOTCOM + +NOCOM: + POP DI + POP SI + POP CX + MOV AL,'Z' +GOTCOM: STOSB ;SAVE INDICATOR CHAR IN BUFFER + +ORG2: CALL GET2 ;SKIP NAME UNTIL DELIMITER + CALL DELIM ; + JNZ ORG2 + + CALL GET ;GET CHARS TO RIGHT OF EQUALS SIGN + STOSB + +ORG4: CALL GET2 + call delim ; 5/30/86. "device=filename/p..." ;3.30 + jz ORG_EXT ; 5/30/86 ;3.30 + STOSB + CMP AL,' ' + JA ORG4 + CMP AL,10 + JZ ORG1 + + MOV BYTE PTR ES:[DI-1],0 +ORG5: CALL GET2 + STOSB + CMP AL,10 + JNZ ORG5 + JMP ORG1 + +ORG_EXT: ;3.30 + mov byte ptr es:[di], 0 ;put 0 at DI to make it an ASCIIZ ;3.30 + inc DI ; ;3.30 + stosb ;and copy the delimeter char. ;3.30 + jmp short ORG5 ;and continue as usual. ;3.30 + +GET2: + JCXZ NOGET + MOV AL,ES:[SI] + INC SI + DEC CX + return + +GET: JCXZ NOGET + MOV AL,ES:[SI] + INC SI + DEC CX + CALL DELIM + JZ GET + return + + +DELIM: CMP AL,' ' + retz + CMP AL,9 + retz + CMP AL,'=' + retz + CMP AL,',' + retz + CMP AL,';' + retz ; 5/23/86 ;3.30 + CMP AL,'/' ; 5/30/86. IBM will assume "/" delim ;3.30 + retz ;3.30 + cmp al, 0 ; 5/23/86 Special case for sysinit!!! ;3.30 + return + + +NOGET: POP CX + MOV COUNT,DI + XOR SI,SI + MOV CHRPTR,SI + return +; +; NEWLINE RETURNS WITH FIRST CHARACTER OF NEXT LINE +; +NEWLINE:invoke GETCHR ;SKIP NON-CONTROL CHARACTERS + retc + CMP AL,10 ;LOOK FOR LINE FEED + JNZ NEWLINE + invoke GETCHR + return + +MAPCASE: + PUSH CX + PUSH SI + PUSH DS + PUSH ES + POP DS + XOR SI,SI +CONVLOOP: + LODSB + + IF KANJI + CALL TESTKANJ + JZ NORMCONV + INC SI ;Skip next char + DEC CX + JCXZ CONVDONE ;Just ignore 1/2 kanji error +;Fall through, know AL is not in 'a'-'z' range +NORMCONV: + ENDIF + + CMP AL,'a' + JB NOCONV + CMP AL,'z' + JA NOCONV + SUB AL,20H + MOV [SI-1],AL +NOCONV: + LOOP CONVLOOP +CONVDONE: + POP DS + POP SI + POP CX + return + + IF KANJI +TESTKANJ: + CMP AL,81H + JB NOTLEAD + CMP AL,9FH + JBE ISLEAD + CMP AL,0E0H + JB NOTLEAD + CMP AL,0FCH + JBE ISLEAD +NOTLEAD: + PUSH AX + XOR AX,AX ;Set zero + POP AX + return + +ISLEAD: + PUSH AX + XOR AX,AX ;Set zero + INC AX ;Reset zero + POP AX + return + ENDIF + +ASSUME DS:NOTHING + +Yes_Break_Failed: ;dev drv Init failed and aborted. ;3.30 + stc ;3.30 + pop ax ;3.30 + return ;3.30 + +SET_BREAK: +; 8/14/86 For DOS 3.3, this routine is modified to take care of the ;3.30 +;Device driver's initialization error and abort. ;3.30 +;If [break_addr+2] == [memhi] && [break_addr] = 0 then assume ;3.30 +;that the device driver's initialization has an error and wanted to ;3.30 +;abort the device driver. In this case, this routine will set carry ;3.30 +;and return to the caller. ;3.30 +; ;3.30 + PUSH AX + MOV AX,WORD PTR [BREAK_ADDR+2] ;REMOVE THE INIT CODE + cmp ax, [MEMHI] ;3.30 + jne Set_Break_Continue ;if not same, then O.K. ;3.30 + ;3.30 + cmp word ptr [BREAK_ADDR],0 ;3.30 + je Yes_Break_failed ;[Break_addr+2]=[MEMHI] & [Break_addr]=0 ;3.30 + ;3.30 +Set_Break_Continue: ;3.30 + MOV [MEMHI],AX + MOV AX,WORD PTR [BREAK_ADDR] + MOV [MEMLO],AX + POP AX ; NOTE FALL THROUGH + +; +; Round the values in MEMLO and MEMHI to paragraph boundary. +; Perform bounds check. +; +ROUND: + PUSH AX + MOV AX,[MEMLO] + + invoke ParaRound ; para round up + + ADD [MEMHI],AX + MOV [MEMLO],0 + mov ax,memhi ; ax = new memhi + CMP AX,[ALLOCLIM] ; if new memhi >= alloclim, error + JAE MEM_ERR + POP AX + clc ;clear carry ;3.30 + return + +MEM_ERR: + MOV DX,OFFSET BADMEM + PUSH CS + POP DS + CALL PRINT + JMP STALL + +CALLDEV:MOV DS,WORD PTR CS:[ENTRY_POINT+2] + ADD BX,WORD PTR CS:[ENTRY_POINT] ;Do a little relocation + MOV AX,DS:[BX] + PUSH WORD PTR CS:[ENTRY_POINT] + MOV WORD PTR CS:[ENTRY_POINT],AX + MOV BX,OFFSET PACKET + CALL [ENTRY_POINT] + POP WORD PTR CS:[ENTRY_POINT] + return + +BADNUM: + MOV sepchr,0 + XOR AX,AX ; Set Zero flag, and AX = 0 + pop bx ; ;3.30 + stc ; AND carry set + return + +ToDigit: + SUB AL,'0' + JB NotDig + CMP AL,9 + JA NotDig + CLC + return +NotDig: STC + return + +; GetNum parses a decimal number. +; Returns it in AX, sets zero flag if AX = 0 (MAY BE considered an +; error), if number is BAD carry is set, zero is set, AX=0. +GETNUM: push bx ; ;3.30 + XOR BX,BX ; running count is zero +B2: CALL ToDigit ; do we have a digit + JC BadNum ; no, bomb + XCHG AX,BX ; put total in AX + PUSH BX ; save digit + MOV BX,10 ; base of arithmetic + MUL BX ; shift by one decimal di... + POP BX ; get back digit + ADD AL,BL ; get total + ADC AH,0 ; make that 16 bits + JC BADNUM ; too big a number + XCHG AX,BX ; stash total + + invoke GETCHR ;GET NEXT DIGIT + JC B1 ; no more characters + cmp al, ' ' ; 5/23/86 space? ;3.30 + jz B15 ; 5/23/86 then end of digits ;3.30 + cmp al, ',' ; 5/23/86 ',' is a seperator! ;3.30 + jz B15 ; 5/23/86 then end of digits. ;3.30 + cmp al, 9 ; 5/23/86 TAB ;3.30 + jz B15 ; ;3.30 + CMP AL,SepChr ; allow , separators + JZ b15 + cmp al,SWTCHR ; See if another switch follows + JZ b15 + cmp al,10 ; Line-feed? + jz b15 + cmp al,13 ; Carriage return? + jz b15 + OR AL,AL ; end of line separator? + JNZ B2 ; no, try as a valid char... +b15: INC COUNT ; one more character to s... + DEC CHRPTR ; back up over separator +B1: MOV AX,BX ; get proper count + OR AX,AX ; Clears carry, sets Zero accordingly + pop bx ;3.30 + return + +SKIP_DELIM proc near ; ;3.30 +;Skip the delimeters pointed by CHRPTR. AL will contain the first non delimete;3.30r +;character encountered and CHRPTR will point to the next character. ;3.30 +;This rouitne will assume the second "," found as a non delimiter character. So;3.30 +;in case if the string is " , , ", this routine will stop at the second ",". At;3.30 +;this time, Zero flag is set. ;3.30 +;If COUNT is exhausted, then carry will be set. ;3.30 +Skip_delim_char: ;3.30 + call getchr ;3.30 + jc Skip_delim_exit ;3.30 + cmp al, ',' ;the first comma? ;3.30 + je Skip_delim_next ;3.30 + call delim ;check the charater in AL. ;3.30 + jz Skip_delim_char ;3.30 + jmp short Skip_delim_exit ;found a non delim char ;3.30 +Skip_delim_next: ;3.30 + call getchr ;3.30 + jc Skip_delim_exit ;3.30 + cmp al, ',' ;the second comma? ;3.30 + je Skip_delim_exit ;done ;3.30 + call delim ;3.30 + jz Skip_delim_next ;3.30 +Skip_delim_exit: ;3.30 + return ;3.30 +SKIP_DELIM endp ;3.30 + ;3.30 +; 5/26/86 *****************************************************************;3.30 +SetDOSCountryInfo proc near ;3.30 +;Input: ES:DI -> pointer to DOS_COUNTRY_CDPG_INFO ;3.30 +; DS:0 -> buffer. ;3.30 +; SI = 0 ;3.30 +; AX = country id ;3.30 +; DX = code page id. (If 0, then use ccSysCodePage as a default.) ;3.30 +; BX = file handle ;3.30 +; This routine can handle maxium 72 COUNTRY_DATA entries. ;3.30 +;Output: DOS_country_cdpg_info set. ;3.30 +; Carry set if any file read failure or wrong information in the file. ;3.30 +; Carry set and CX = -1 if cannot find the matching COUNTRY_id, CODEPAGE;3.30 +; _id in the file. ;3.30 + ;3.30 + push di ;3.30 + push ax ;3.30 + push dx ;3.30 + ;3.30 + xor cx,cx ;3.30 + xor dx,dx ;3.30 + mov ax, 512 ;read 512 bytes ;3.30 + call ReadInControlBuffer ;Read the file header ;3.30 + jc SetDOSData_fail ;3.30 + push es ;3.30 + push si ;3.30 + push cs ;3.30 + pop es ;3.30 + mov di, offset COUNTRY_FILE_SIGNATURE ;3.30 + mov cx, 8 ;length of the signature ;3.30 + repz cmpsb ;3.30 + pop si ;3.30 + pop es ;3.30 + jnz SetDOSData_fail ;signature mismatch ;3.30 + ;3.30 + add si, 18 ;SI -> county info type ;3.30 + cmp byte ptr ds:[si], 1 ;Only accept type 1 (Currently only 1 h;3.30eader type) + jne SetDOSData_fail ;cannot proceed. error return ;3.30 + inc si ;SI -> file offset ;3.30 + mov dx, word ptr ds:[si] ;Get the INFO file offset. ;3.30 + mov cx, word ptr ds:[si+2] ;3.30 + mov ax, 1024 ;read 1024 bytes. ;3.30 + call ReadInControlBuffer ;Read INFO ;3.30 + jc SetDOSData_fail ;3.30 + mov cx, word ptr ds:[si] ;get the # of country, codepage combina;3.30tion entries + cmp cx, 72 ;cannot handle more than 72 entries. ;3.30 + ja SetDOSData_fail ;3.30 + inc si ;3.30 + inc si ;SI -> entry information packet ;3.30 + pop dx ;restore code page id ;3.30 + pop ax ;restore country id ;3.30 + pop di ;3.30 + ;3.30 +SetDOSCntry_find: ;Search for desired country_id,codepage;3.30_id. + cmp ax, word ptr ds:[si+2] ;compare country_id ;3.30 + jne SetDOSCntry_next ;3.30 + cmp dx, 0 ;No user specified code page ? ;3.30 + je SetDOSCntry_any_codepage;then no need to match code page id. ;3.30 + cmp dx, word ptr ds:[si+4] ;compare code page id ;3.30 + je SetDOSCntry_got_it ;3.30 +SetDOSCntry_next: ;3.30 + add si, word ptr ds:[si] ;next entry ;3.30 + inc si ;3.30 + inc si ;take a word for size of entry itself ;3.30 + loop SetDOSCntry_find ;3.30 + mov cx, -1 ;signals that bad country id entered. ;3.30 +SetDOSCntry_fail: ;3.30 + stc ;3.30 + ret ;3.30 + ;3.30 +SetDOSData_fail: ;3.30 + pop si ;3.30 + pop cx ;3.30 + pop di ;3.30 + jmp short SetDOSCntry_fail ;3.30 + ;3.30 +SetDOSCntry_any_CodePage: ;use the code_page_id of the country_id;3.30 found. + mov dx, word ptr ds:[si+4] ;3.30 +SetDOSCntry_got_it: ;found the matching entry ;3.30 + mov cs:CntryCodePage_Id, dx ;save code page ID for this country. ;3.30 + mov dx, word ptr ds:[si+10] ;get the file offset of country data ;3.30 + mov cx, word ptr ds:[si+12] ;3.30 + mov ax, 512 ;read 512 bytes ;3.30 + call ReadInControlBuffer ;3.30 + jc SetDOSCntry_fail ;3.30 + mov cx, word ptr ds:[si] ;get the number of entries to handle. ;3.30 + inc si ;3.30 + inc si ;SI -> first entry ;3.30 + ;3.30 +SetDOSCntry_data: ;3.30 + push di ;ES:DI -> DOS_COUNTRY_CDPG_INFO ;3.30 + push cx ;save # of entry left ;3.30 + push si ;si -> current entry in Control buffer ;3.30 + ;3.30 + mov al, byte ptr ds:[si+2] ;get data entry id ;3.30 + call GetCountryDestination ;get the address of destination in ES:D;3.30I + jc SetDOSCntry_data_next ;No matching data entry id in DOS ;3.30 + ;3.30 + ;3.30 + mov dx, word ptr ds:[si+4] ;get offset of data ;3.30 + mov cx, word ptr ds:[si+6] ;3.30 + mov ax, 4200h ;3.30 + stc ;3.30 + int 21h ;move pointer ;3.30 + jc SetDOSData_fail ;3.30 + mov dx, 512 ;start of data buffer ;3.30 + mov cx, word ptr es:[di] ;length of the corresponding data in DO;3.30S. + add cx, 10 ;Signature + A word for the length itse;3.30lf + mov ah, 3fh ;3.30 + stc ;3.30 + int 21h ;read the country.sys data ;3.30 + jc SetDOSData_fail ;read failure ;3.30 + cmp ax, cx ;3.30 + jne SetDOSData_fail ;3.30 + ;3.30 + mov al, byte ptr ds:[si+2] ;save Data id for future use. ;3.30 + mov si, (512+8) ;SI-> data buffer + id tag field ;3.30 + mov cx, word ptr ds:[si] ;get the length of the file ;3.30 + inc cx ;Take care of a word for lenght of tab ;3.30 + inc cx ;itself. ;3.30 + cmp cx, (2048 - 512 - 8) ;Fit into the buffer? ;3.30 + ja SetDOSData_fail ;3.30 + cmp al, SetCountryInfo ;is the data for SetCountryInfo table? ;3.30 + jne SetDOSCntry_Mov ;no, don't worry ;3.30 + push word ptr es:[di+24] ;Cannot destroy ccMono_ptr address. Sav;3.30e them. + push word ptr es:[di+26] ;3.30 + push di ;save DI ;3.30 + ;3.30 + push ax ;3.30 + mov ax,cs:CntryCodePage_Id ;Do not use the Code Page info in Count;3.30ry_Info + mov ds:[si+4], ax ;Use the saved one for this !!!! ;3.30 + pop ax ;3.30 + ;3.30 +SetDOSCntry_Mov: ;3.30 + rep movsb ;copy the table into DOS ;3.30 + cmp al, SetCountryInfo ;was the ccMono_ptr saved? ;3.30 + jne SetDOSCntry_data_next ;3.30 + pop di ;restore DI ;3.30 + pop word ptr es:[di+26] ;restore ccMono_ptr in DOS. ;3.30 + pop word ptr es:[di+24] ;3.30 + ;3.30 +SetDOSCntry_data_next: ;3.30 + pop si ;restore control buffer pointer ;3.30 + pop cx ;restore # of entries left ;3.30 + pop di ;restore pointer to DSO_COUNTRY_CDPG ;3.30 + add si, word ptr ds:[si] ;try to get the next entry ;3.30 + inc si ;3.30 + inc si ;take a word of entry length itself ;3.30 + loop SetDOSCntry_data ;3.30 + ret ;3.30 +SetDOSCountryInfo endp ;3.30 +; ;3.30 + ;3.30 +GetCountryDestination proc near ;3.30 +;Get the destination address in the DOS country info table. ;3.30 +;Input: AL - Data ID ;3.30 +; ES:DI -> DOS_COUNTRY_CDPG_INFO ;3.30 +;On return: ;3.30 +; ES:DI -> Destination address of the matching data id ;3.30 +; carry set if no matching data id found in DOS. ;3.30 + ;3.30 + push cx ;3.30 + add di, ccNumber_of_entries ;skip the reserved area, syscodepage et;3.30c. + mov cx, word ptr es:[di] ;get the number of entries ;3.30 + inc di ;3.30 + inc di ;SI -> the first start entry id ;3.30 +GetCntryDest: ;3.30 + cmp byte ptr es:[di], al ;3.30 + je GetCntryDest_OK ;3.30 + cmp byte ptr es:[di], SetCountryInfo ;was it SetCountryInfo entry? ;3.30 + je GetCntryDest_1 ;3.30 + add di, 5 ;next data id ;3.30 + jmp short GetCntryDest_loop ;3.30 +GetCntryDest_1: ;3.30 + add di, NEW_COUNTRY_SIZE + 3 ;next data id ;3.30 +GetCntryDest_loop: ;3.30 + loop GetCntryDest ;3.30 + stc ;3.30 + jmp short GetCntryDest_exit ;3.30 +GetCntryDest_OK: ;3.30 + cmp al, SetCountryInfo ;select country info? ;3.30 + jne GetCntryDest_OK1 ;3.30 + inc di ;now DI -> ccCountryInfoLen ;3.30 + jmp short GetCntryDest_exit ;3.30 +GetCntryDest_OK1: ;3.30 + les di, dword ptr es:[di+1] ;get the destination in ES:DI ;3.30 +GetCntryDest_Exit: ;3.30 + pop cx ;3.30 + ret ;3.30 +GetCountryDestination endp ;3.30 + ;3.30 +; ;3.30 +ReadInControlBuffer proc near ;3.30 +;Move file pointer to CX:DX ;3.30 +;Read AX bytes into the control buffer. (Should be less than 2 Kb) ;3.30 +;SI will be set to 0 hence DS:SI points to the control buffer. ;3.30 +;Entry: CX,DX offset from the start of the file where the read/write pointer ;3.30 +; be moved. ;3.30 +; AX - # of bytes to read ;3.30 +; BX - file handle ;3.30 +; DS - buffer seg. ;3.30 +;Return: The control data information is read into DS:0 - DS:0200. ;3.30 +; CX,DX value destroyed. ;3.30 +; Carry set if error in Reading file. ;3.30 +; ;3.30 + push ax ;# of bytes to read ;3.30 + mov ax, 4200h ;3.30 + stc ;3.30 + int 21h ;move pointer ;3.30 + pop cx ;# of bytes to read ;3.30 + jc RICB_exit ;3.30 + xor dx,dx ;ds:dx -> control buffer ;3.30 + xor si,si ;3.30 + mov ah,3fh ;read into the buffer ;3.30 + stc ;3.30 + int 21h ;should be less than 1024 bytes. ;3.30 +RICB_exit: ;3.30 + ret ;3.30 +ReadInControlBuffer endp ;3.30 + ;3.30 +; ;3.30 +SET_COUNTRY_PATH proc near ;3.30 +;In: DS - SYSINITSEG, ES - CONFBOT, SI -> start of the asciiz path string ;3.30 +; DOSINFO_EXT, CNTRY_DRV, CNTRY_ROOT, CNTRY_PATH ;3.30 +; Assumes current directory is the ROOT directory. ;3.30 +;Out: DS:DI -> full path (CNTRY_DRV). ;3.30 +; Set the CNTRY_DRV string from the COUNTRY=,,path command. ;3.30 +; DS, ES, SI value saved. ;3.30 + ;3.30 + push si ;3.30 + push ds ;switch ds, es ;3.30 + push es ;3.30 + pop ds ;3.30 + pop es ;now DS -> CONFBOT, ES -> SYSINITSEG ;3.30 + ;3.30 + call chk_drive_letter ;current DS:[SI] is a drive letter? ;3.30 + jc SCP_Default_drv ;no, use current default drive. ;3.30 + mov al, byte ptr DS:[SI] ;3.30 + inc si ;3.30 + inc si ;SI -> next char after ":" ;3.30 + jmp short SCP_SetDrv ;3.30 +SCP_Default_drv: ;3.30 + mov ah, 19h ;3.30 + int 21h ;3.30 + add al, "A" ;convert it to a character. ;3.30 +SCP_SetDrv: ;3.30 + mov cs:CNTRY_DRV, al ;set the drive letter. ;3.30 + mov di, offset CNTRY_PATH ;3.30 + mov al, byte ptr DS:[SI] ;3.30 + cmp al, "\" ;3.30 + je SCP_Root_Dir ;3.30 + cmp al, cs:SWTCHR ;let's accept "/" as an directory delim;3.30 + je SCP_Root_Dir ;3.30 + jmp short SCP_Path ;3.30 +SCP_Root_Dir: ;3.30 + dec di ;DI -> CNTRY_ROOT ;3.30 +SCP_Path: ;3.30 + call MOVE_ASCIIZ ;copy it ;3.30 + mov di, offset CNTRY_DRV ;3.30 +SCPath_Exit: ;3.30 + push ds ;switch ds, es ;3.30 + push es ;3.30 + pop ds ;3.30 + pop es ;DS, ES value restored ;3.30 + pop si ;3.30 + RET ;3.30 +SET_COUNTRY_PATH endp ;3.30 + ;3.30 +; ;3.30 +CHK_DRIVE_LETTER proc near ;3.30 +;Check if DS:[SI] is a drive letter followed by ":". ;3.30 +;Assume that every alpha charater is already converted to UPPER CASE. ;3.30 +;Carry set if not. ;3.30 +; ;3.30 + push ax ;3.30 + cmp byte ptr ds:[si], "A" ;3.30 + jb CDLetter_NO ;3.30 + cmp byte ptr ds:[si], "Z" ;3.30 + ja CDLetter_NO ;3.30 + cmp byte ptr ds:[si+1], ":" ;3.30 + jne CDLetter_NO ;3.30 + jmp short CDLetter_exit ;3.30 +CDLetter_NO: ;3.30 + stc ;3.30 +CDLetter_exit: ;3.30 + pop ax ;3.30 + ret ;3.30 +CHK_DRIVE_LETTER endp ;3.30 + ;3.30 +; ;3.30 +MOVE_ASCIIZ proc near ;3.30 +;In: DS:SI -> source ES:DI -> target ;3.30 +;Out: copy the string until 0. ;3.30 +;Assumes there exists a 0. ;3.30 +MASCIIZ_loop: ;3.30 + movsb ;3.30 + cmp byte ptr DS:[SI-1], 0 ;Was it 0? ;3.30 + jne MASCIIZ_loop ;3.30 + ret ;3.30 +MOVE_ASCIIZ endp ;3.30 + +; +; DS:DX POINTS TO STRING TO OUTPUT (ASCIZ) +; +; PRINTS +; +; +; +BADFIL: + PUSH CS + POP ES + MOV SI,DX +BADLOAD: + MOV DX,OFFSET BADLD_PRE ;WANT TO PRINT CONFIG ERROR + MOV BX,OFFSET BADLD_POST +PRNERR: + PUSH CS + POP DS + MOV AH,STD_CON_STRING_OUTPUT + INT 21H +PRN1: MOV DL,ES:[SI] + OR DL,DL + JZ PRN2 + MOV AH,STD_CON_OUTPUT + INT 21H + INC SI + JMP PRN1 +PRN2: MOV DX,BX +PRINT: MOV AH,STD_CON_STRING_OUTPUT + INT 21H + return + + + IF NOEXEC +; +; LOAD NON EXE FILE CALLED [DS:DX] AT MEMORY LOCATION ES:BX +; +LDFIL: + PUSH AX + PUSH BX + PUSH CX + PUSH DX + PUSH SI + PUSH DS + PUSH BX + XOR AX,AX ;OPEN THE FILE + MOV AH,OPEN + STC ;IN CASE OF INT 24 + INT 21H + POP DX ;Clean stack in case jump + JC LDRET + PUSH DX + MOV BX,AX ;Handle in BX + XOR CX,CX + XOR DX,DX + MOV AX,(LSEEK SHL 8) OR 2 + STC ;IN CASE OF INT 24 + INT 21H ; Get file size in DX:AX + JC LDCLSP + OR DX,DX + JNZ LDERRP ; File >64K + POP DX + PUSH DX + MOV CX,ES ; CX:DX is xaddr + ADD DX,AX ; Add file size to Xaddr + JNC DOSIZE + ADD CX,1000H ; ripple carry +DOSIZE: + mov ax,dx + call ParaRound + mov dx,ax + + ADD CX,DX + CMP CX,[ALLOCLIM] + JB OKLD + JMP MEM_ERR + +OKLD: + XOR CX,CX + XOR DX,DX + MOV AX,LSEEK SHL 8 ;Reset pointer to beginning of file + STC ;IN CASE OF INT 24 + INT 21H + JC LDCLSP + POP DX + PUSH ES ;READ THE FILE IN + POP DS ;Trans addr is DS:DX + MOV CX,0FF00H ; .COM files arn't any bigger than + ; 64k-100H + MOV AH,READ + STC ;IN CASE OF INT 24 + INT 21H + JC LDCLS + MOV SI,DX ;CHECK FOR EXE FILE + CMP WORD PTR [SI],"ZM" + CLC ; Assume OK + JNZ LDCLS ; Only know how to do .COM files + STC + JMP SHORT LDCLS + +LDERRP: + STC +LDCLSP: + POP DX ;Clean stack +LDCLS: + PUSHF + MOV AH,CLOSE ;CLOSE THE FILE + STC + INT 21H + POPF + +LDRET: POP DS + POP SI + POP DX + POP CX + POP BX + POP AX + return + ENDIF + +; +; OPEN DEVICE POINTED TO BY DX, AL HAS ACCESS CODE +; IF UNABLE TO OPEN DO A DEVICE OPEN NULL DEVICE INSTEAD +; +OPEN_DEV: + CALL OPEN_FILE + JNC OPEN_DEV3 +OPEN_DEV1: + MOV DX,OFFSET NULDEV + CALL OPEN_FILE + return + +OPEN_DEV3: + MOV BX,AX ; Handle from open to BX + XOR AX,AX ; GET DEVICE INFO + MOV AH,IOCTL + INT 21H + TEST DL,10000000B + retnz + MOV AH,CLOSE + INT 21H + JMP OPEN_DEV1 + +OPEN_FILE: + MOV AH,OPEN + STC + INT 21H + return + +INT24: ADD SP,6 ;RESTORE MACHINE STATE + POP AX + POP BX + POP CX + POP DX + POP SI + POP DI + POP BP + POP DS + POP ES + PUSH AX + MOV AH,GET_DEFAULT_DRIVE ;INITIALIZE DOS + INT 21H + POP AX + IRET ;BACK TO USER + + IF ALTVECT +BOOTMES DB 13,10,"MS-DOS version " + DB MAJOR_VERSION + "0" + DB "." + DB (MINOR_VERSION / 10) + "0" + DB (MINOR_VERSION MOD 10) + "0" + DB 13,10 + DB "Copyright 1981,82 Microsoft Corp.",13,10,"$" + ENDIF + +NULDEV DB "NUL",0 +CONDEV DB "CON",0 +AUXDEV DB "AUX",0 +PRNDEV DB "PRN",0 + +CONFIG DB "\CONFIG.SYS",0 + +CNTRY_DRV DB "A:" ;3.30 +CNTRY_ROOT DB "\" ;3.30 +CNTRY_PATH DB "COUNTRY.SYS",0 ;3.30 + DB 52 DUP (0) ;3.30 + ;3.30 +COUNTRY_FILE_SIGNATURE db 0FFh,'COUNTRY' ;3.30 + ;3.30 +CntryCodePage_Id DW ? ;3.30 + +COMMND DB "\COMMAND.COM",0 + DB 20 dup (0) ;3.30 + +COMTAB LABEL BYTE +;;;; DB 8,"AVAILDEV",'A' ; NO LONGER SUPPORTED + DB 7,"BUFFERS", 'B' + DB 5,"BREAK", 'C' + DB 6,"DEVICE", 'D' + DB 5,"FILES", 'F' + DB 4,"FCBS", 'X' + DB 9,"LASTDRIVE",'L' + DB 8,"DRIVPARM", 'P' ; RS for DOS 3.2 + IF STACKSW ;3.30 + DB 6,"STACKS", 'K' ; BAS for DOS 3.2 ;3.30 + ENDIF ;3.30 + DB 7,"COUNTRY", 'Q' + DB 5,"SHELL", 'S' +;;;; DB 8,"SWITCHAR",'W' ; NO LONGER SUPPORTED + DB 0 + +public DeviceParameters +DeviceParameters a_DeviceParameters <0,DEV_3INCH720KB,0,80> + +hlim dw 2 +slim dw 9 + +public drive +drive db ? + +public switches +Switches dw ? + +; +; The following are the recommended BPBs for the media that we know of so +; far. + +; 48 tpi diskettes + +BPB48T DW 512 + DB 2 + DW 1 + DB 2 + DW 112 + DW 2*9*40 + DB 0FDH + DW 2 + DW 9 + DW 2 + Dd 0 ;hidden sectors - sp + Dd 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved - sp + +; 96tpi diskettes + +BPB96T DW 512 + DB 1 + DW 1 + DB 2 + DW 224 + DW 2*15*80 + DB 0f9H + DW 7 + DW 15 + DW 2 + Dd 0 ;hidden sectors - sp + Dd 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved - sp + +; 3 1/2 inch diskette BPB + +BPB35 DW 512 + DB 2 + DW 1 ; Double sided with 9 sec/trk + DB 2 + DW 70h + DW 2*9*80 + DB 0f9H + DW 3 + DW 9 + DW 2 + Dd 0 ;hidden sectors - sp + Dd 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved - sp + + +BPBTable dw BPB48T ; 48tpi drives + dw BPB96T ; 96tpi drives + dw BPB35 ; 3.5" drives +; The following are not supported, so default to 3.5" media layout + dw BPB35 ; Not used - 8" drives + dw BPB35 ; Not Used - 8" drives + dw BPB35 ; Not Used - hard files + dw BPB35 ; Not Used - tape drives + dw BPB35 ; Not Used - Other + +switchlist db 7,"FHSTDCN" ; Preserve the positions of N and C. + +; The following depend on the positions of the various letters in SwitchList + +flagdrive equ 0004H +flagcyln equ 0008H +flagseclim equ 0010H +flagheads equ 0020H +flagff equ 0040H + +SWTCHR EQU "/" ; switch follows this character + +SYSINITSEG ENDS + END + \ No newline at end of file diff --git a/SRC/BIOS/SYSINIT2.OBJ b/SRC/BIOS/SYSINIT2.OBJ new file mode 100644 index 0000000..057e8c1 Binary files /dev/null and b/SRC/BIOS/SYSINIT2.OBJ differ diff --git a/SRC/BOOT/BOOT11.INC b/SRC/BOOT/BOOT11.INC new file mode 100644 index 0000000..03fd17e --- /dev/null +++ b/SRC/BOOT/BOOT11.INC @@ -0,0 +1,64 @@ + db 0EBH,027H,090H,008H,000H,014H,000H,000H + db 000H,000H,000H,000H,000H,000H,000H,000H + db 000H,000H,000H,000H,000H,000H,000H,000H + db 000H,000H,000H,000H,000H,000H,000H,000H + db 000H,000H,000H,000H,000H,000H,000H,0CDH + db 019H,0FAH,08CH,0C8H,08EH,0D8H,033H,0D2H + db 08EH,0D2H,0BCH,000H,07CH,0FBH,0B8H,060H + db 000H,08EH,0D8H,08EH,0C0H,033H,0D2H,08BH + db 0C2H,0CDH,013H,072H,069H,0E8H,085H,000H + db 072H,0DDH,02EH,083H,03EH,003H,07CH,008H + db 074H,006H,02EH,0C6H,006H,064H,07DH,002H + db 0BBH,000H,000H,02EH,08BH,00EH,003H,07CH + db 051H,0B0H,009H,02AH,0C1H,0B4H,000H,08BH + db 0F0H,056H,033H,0D2H,033H,0C0H,08AH,0C5H + db 02EH,0F6H,036H,064H,07DH,08AH,0E8H,08AH + db 0F4H,08BH,0C6H,0B4H,002H,0CDH,013H,072H + db 02DH,05EH,059H,02EH,029H,036H,005H,07CH + db 074H,01FH,08BH,0C6H,02EH,0F7H,026H,065H + db 07DH,003H,0D8H,0FEH,0C5H,0B1H,001H,051H + db 0BEH,008H,000H,02EH,03BH,036H,005H,07CH + db 07CH,005H,02EH,08BH,036H,005H,07CH,0EBH + db 0C0H,0EAH,000H,000H,060H,000H,0BEH,067H + db 07DH,0E8H,002H,000H,0EBH,0FEH,032H,0FFH + db 02EH,0ACH,024H,07FH,074H,00BH,056H,0B4H + db 00EH,0BBH,007H,000H,0CDH,010H,05EH,0EBH + db 0EFH,0C3H,0E9H,033H,0FFH,0BBH,000H,000H + db 0B9H,004H,000H,0B8H,001H,002H,0CDH,013H + db 01EH,072H,033H,08CH,0C8H,08EH,0D8H,0BFH + db 000H,000H,0B9H,00BH,000H,026H,080H,00DH + db 020H,026H,080H,04DH,020H,020H,047H,0E2H + db 0F4H,0BFH,000H,000H,0BEH,08BH,07DH,0B9H + db 00BH,000H,0FCH,0F3H,0A6H,075H,00FH,0BFH + db 020H,000H,0BEH,097H,07DH,0B9H,00BH,000H + db 0F3H,0A6H,075H,002H,01FH,0C3H,0BEH,01BH + db 07DH,0E8H,0A2H,0FFH,0B4H,000H,0CDH,016H + db 01FH,0F9H,0C3H,00DH,00AH,04EH,06FH,06EH + db 02DH,053H,079H,073H,074H,065H,06DH,020H + db 064H,069H,073H,06BH,020H,06FH,072H,020H + db 064H,069H,073H,06BH,020H,065H,072H,072H + db 06FH,072H,00DH,00AH,052H,065H,070H,06CH + db 061H,063H,065H,020H,061H,06EH,064H,020H + db 073H,074H,072H,069H,06BH,065H,020H,061H + db 06EH,079H,020H,06BH,065H,079H,020H,077H + db 068H,065H,06EH,020H,072H,065H,061H,064H + db 079H,00DH,00AH,000H,001H,000H,002H,00DH + db 00AH,044H,069H,073H,06BH,020H,042H,06FH + db 06FH,074H,020H,066H,061H,069H,06CH,075H + db 072H,065H,00DH,00AH,000H,04DH,069H,063H + db 072H,06FH,073H,06FH,066H,074H,02CH,049H + db 06EH,063H,020H,069H,06FH,020H,020H,020H + db 020H,020H,020H,073H,079H,073H,030H,06DH + db 073H,064H,06FH,073H,020H,020H,020H,073H + db 079H,073H,030H,005H,0C6H,006H,077H,02FH + db 0FFH,083H,07EH,0FCH,000H,075H,00BH,080H + db 07EH,0F7H,03BH,075H,005H,0C6H,006H,076H + db 02FH,0FFH,089H,0ECH,05DH,0CAH,004H,000H + db 000H,000H,000H,000H,000H,000H,000H,000H + db 000H,000H,000H,000H,000H,000H,000H,000H + db 000H,000H,000H,000H,000H,000H,000H,000H + db 000H,000H,000H,000H,000H,000H,000H,000H + db 000H,000H,000H,000H,000H,000H,000H,000H + db 000H,000H,000H,000H,000H,000H,000H,000H + db 000H,000H,000H,000H,000H,000H,000H,000H + db 000H,000H,000H,000H,000H,000H,000H,000H diff --git a/SRC/BOOT/MAKEFILE b/SRC/BOOT/MAKEFILE new file mode 100644 index 0000000..a2a46b8 --- /dev/null +++ b/SRC/BOOT/MAKEFILE @@ -0,0 +1,38 @@ +#** makefile for Boot + +DEST = msboot +MSG = messages + +# Path definitions + +BIOS = ..\..\BIOS +DOS = ..\..\DOS + +# Definitions for assembler + +ASM = masm +AFLAGS = -Mx -t +AINC = -I..\..\inc + +# Definitions for C compiler + +CC = cl +CFLAGS = -Ox -Zlp +CINC = -I..\..\h + +# Definitions for linker + +LINK = link +LIBC = ..\..\libc + + +# Rules and Dependencies follow + +msboot.obj: msboot.asm $(MSG).inc + masm $(AFLAGS) $(AINC) msboot; + +msboot.bin: msboot.obj + LINK msboot; + EXE2BIN msboot.exe msboot.bin + DEL msboot.exe + DBOF msboot.bin boot.inc 7C00 200 diff --git a/SRC/BOOT/MESSAGES.INC b/SRC/BOOT/MESSAGES.INC new file mode 100644 index 0000000..0043e12 --- /dev/null +++ b/SRC/BOOT/MESSAGES.INC @@ -0,0 +1,7 @@ +; SCCSID = @(#)messages.inc 1.1 85/05/13 +; MESSAGES FOR THE BOOT SECTOR. NUL Terminated. + +SYSMSG DB 13,10,"Non-System disk or disk error" + DB 13,10,"Replace and strike any key when ready",13,10,0 + +DMSSG DB 13,10,"Disk Boot failure",13,10,0 diff --git a/SRC/BOOT/MSBOOT.ASM b/SRC/BOOT/MSBOOT.ASM new file mode 100644 index 0000000..d7c8247 --- /dev/null +++ b/SRC/BOOT/MSBOOT.ASM @@ -0,0 +1,386 @@ +; SCCSID = @(#)ibmboot.asm 1.1 85/05/13 +TITLE BOOT SECTOR 1 OF TRACK 0 - BOOT LOADER + +; Rev 1.0 ChrisP, AaronR and others. 2.0 format boot +; +; Rev 3.0 MarkZ Salmon enhancements +; 2.50 in label +; Rev 3.1 MarkZ 3.1 in label due to vagaries of SYSing to IBM drive D's +; This resulted in the BPB being off by 1. So we now trust +; 2.0 and 3.1 boot sectors and disbelieve 3.0. +; +; Rev 3.2 LeeAc Modify layout of extended BPB for >32M support +; Move PHYDRV to 3rd byte from end of sector +; so that it won't have to be moved again +; FORMAT and SYS count on PHYDRV being in a known location +; +; Rev. 3.3 DCLove Changed Sec 9 EOT field from 15 to 18. May 29, 1986. +; +; Rev 3.31 MarkT The COUNT value has a bogus check (JBE????) to determine +; if we've loaded in all the sectors of IO.SYS. This will +; cause too big of a load if the sectors per track is high +; enough, causing either a stack overflow or the boot code +; to be overwritten. +; +; +; The ROM in the IBM PC starts the boot process by performing a hardware +; initialization and a verification of all external devices. If all goes +; well, it will then load from the boot drive the sector from track 0, head 0, +; sector 1. This sector is placed at physical address 07C00h. The initial +; registers are set up as follows: CS=DS=ES=SS=0. IP=7C00h, SP=0400H. +; +; The code in this sector is responsible for locating the MSDOS device drivers +; (IO.SYS) and for placing the directory sector with this information at +; physical address 00500h. After loading in this sector, it reads in the +; entirety of the BIOS at BIOSEG:0 and does a long jump to that point. +; +; If no BIOS/DOS pair is found an error message is displayed and the user is +; prompted to reinsert another disk. If there is a disk error during the +; process, a message is displayed and things are halted. +; +; At the beginning of the boot sector, there is a table which describes the +; MSDOS structure of the media. This is equivalent to the BPB with some +; additional information describing the physical layout of the driver (heads, +; tracks, sectors) +; + +ORIGIN EQU 7C00H ; Origin of bootstrap LOADER +BIOSEG EQU 70H ; destingation segment of BIOS +BioOff EQU 700H ; offset of bios +cbSec EQU 512 +cbDirEnt EQU 32 +DirOff EQU 500h + +; +; Define the destination segment of the BIOS, including the initialization +; label +; +SEGBIOS SEGMENT AT BIOSEG +BIOS LABEL BYTE +SEGBIOS ENDS + +CODE SEGMENT + ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING + ORG DirOff + 1Ch +BiosFS LABEL WORD + + ORG ORIGIN + +DSKADR = 1EH*4 ;POINTER TO DRIVE PARAMETERS + +Public $START +$START: + JMP START +;---------------------------------------------------------- +; +; THE FOLLOWING DATA CONFIGURES THE BOOT PROGRAM +; FOR ANY TYPE OF DRIVE OR HARDFILE +; + DB "MSDOS" + DB "3.3" +ByteSec DW cbSec ; SIZE OF A PHYSICAL SECTOR + DB 8 ; SECTORS PER ALLOCATION UNIT +cSecRes DW 1 ; NUMBER OF RESERVED SECTORS +cFat DB 2 ; NUMBER OF FATS +DirNum DW 512 ; NUMBER OF DIREC ENTRIES + DW 4*17*305-1 ; NUMBER OF SECTORS - NUMBER OF HIDDEN SECTORS +MEDIA DB 0F8H ; MEDIA BYTE +cSecFat DW 8 ; NUMBER OF FAT SECTORS +SECLIM DW 17 ; SECTORS PER TRACK +HDLIM DW 4 ; NUMBER OF SURFACES +cSecHid DW 1 ; NUMBER OF HIDDEN SECTORS + dw 0 ; high order word of Hiden Sectors + dd 0 ; 32 bit version of NUMBER OF SECTORS + ; (when 16 bit version is zero) + db 6 dup(?) ; reserved for later expansion + + +CURHD DB ? ; Unitialized + +; this is an image of the disk parameter table. Zero entries are copied +; from the rom table at boot. +; +SEC9 DB 0 ; DISK_SPECIFY_1 + DB 0 ; DISK_SPECIFY_2 + DB 0 ; DISK_MOTOR_WAIT + DB 0 ; DISK_SECTOR_SIZ + DB 12h ; DISK_EOT + DB 0 ; DISK_RW_GAP + DB 0 ; DISK_DTL + DB 0 ; DISK_FORMT_GAP + DB 0 ; DISK_FILL + DB 1 ; DISK_HEAD_STTL + DB 0 ; DISK_MOTOR_STRT + +Public UDATA +UDATA LABEL WORD +BIOS$ EQU WORD PTR UDATA+1 +CURTRK EQU WORD PTR UDATA+3 +CURSEC EQU BYTE PTR UDATA+5 +COUNT EQU BYTE PTR UDATA+6 ; NUMBER OF BIOS SECTORS +BIOSAV EQU WORD PTR UDATA+7 +DIR$ EQU WORD PTR UDATA+9 + +START: + +; +; First thing is to reset the stack to a better and more known place. The ROM +; may change, but we'd like to get the stack in the correct place. +; + CLI ;Stop interrupts till stack ok + XOR AX,AX + MOV SS,AX ;Work in stack just below this routine + ASSUME SS:CODE + MOV SP,ORIGIN + PUSH SS + POP ES + ASSUME ES:CODE +; +; We copy the disk parameter table into a local area. We scan the table above +; for non-zero parameters. Any we see get changed to their non-zero values. +; + MOV BX,DSKADR + LDS SI,DWORD PTR SS:[BX] ; get address of disk table + PUSH DS ; save original vector for possible + PUSH SI ; restore + PUSH SS + PUSH BX + MOV DI,OFFSET Sec9 + MOV CX,11 + CLD +changeloop: + LODSB + CMP BYTE PTR ES:[DI],0 ; is the template zero? + JZ Store ; yes, store what we've got + MOV AL,ES:[DI] +Store: + STOSB + MOV AL,AH + LOOP ChangeLoop +; +; Place in new disk parameter table. +; + PUSH ES + POP DS + ASSUME DS:CODE + MOV [BX+2],AX + MOV [BX],OFFSET SEC9 +; +; We may now turn interrupts back on. Before this, there is a small window +; when a reboot command may come in when the disk parameter table is garbage +; + STI ;Interrupts OK now +; +; Reset the disk system just in case any thing funny has happened. +; + INT 13H ;Reset the system + JC RERROR +; +; The system is now prepared for us to begin reading. First, determine +; logical sector numbers of the start of the directory and the start of the +; data area. +; + MOV AL,cFat ;Determine sector dir starts on + CBW + MUL cSecFat + ADD AX,cSecHid + ADD AX,cSecRes + MOV [DIR$],AX ; AX = cFat*cSecFat + cSecRes + cSecHid + MOV [BIOS$],AX +; +; Take into account size of directory (only know number of directory entries) +; + MOV AX,cbDirEnt ; bytes per directory entry + MUL DirNum ; convert to bytes in directory + MOV BX,ByteSec ; add in sector size + ADD AX,BX + DEC AX ; decrement so that we round up + DIV BX ; convert to sector number + ADD [BIOS$],AX +; +; We load in the first directory sector and examine it to make sure the the +; BIOS and DOS are the first two directory entries. If they are not found, +; the user is prompted to insert a new disk. The directory sector is loaded +; into 00500h +; + MOV BX,DirOff ; sector to go in at 00500h + MOV AX,DIR$ ; logical sector of directory + CALL DODIV ; convert to sector, track, head + MOV AX,0201H ; disk read 1 sector + CALL DOCALL ; do the disk read + JB CKERR ; if errors try to recover +; +; Now we scan for the presence of IO.SYS and MSDOS.SYS. Check the +; first directory entry. +; + MOV DI,BX + MOV CX,11 + MOV SI,OFFSET BIO ; point to "bios com" + REPZ CMPSB ; see if the same + JNZ CKERR ; if not there advise the user +; +; Found the BIOS. Check the second directory entry. +; + LEA DI,[BX+20h] + MOV SI,OFFSET DOS ; point to "86dos com" + MOV CX,11 + REPZ CMPSB + JZ DoLoad +; +; There has been some recoverable error. Display a message and wait for a +; keystroke. +; +CKERR: MOV SI,OFFSET SYSMSG ; point to no system message +ErrOut: CALL WRITE ; and write on the screen + XOR AH,AH ; wait for response + INT 16H ; get character from keyboard + POP SI ; reset disk parameter table back to + POP DS ; rom + POP [SI] + POP [SI+2] + INT 19h ; Continue in loop till good disk + +RERROR: MOV SI,OFFSET DMSSG ; DISK ERROR MESSAGE + JMP ErrOut +; +; We now begin to load the BIOS in. Compute the number of sectors needed +; +DoLoad: + MOV AX,BiosFS ; get file size + XOR DX,DX ; presume < 64K + DIV ByteSec ; convert to sectors + INC AL ; reading in one more can't hurt + MOV COUNT,AL ; Store running count + MOV AX,BIOS$ ; get logical sector of beginning of BIOS + MOV BIOSAV,AX ; store away for real bios later + MOV BX,BioOff ; Load address from BIOSSEG +; +; Main read-in loop. +; ES:BX points to area to read. +; Count is the number of sectors remaining. +; BIOS$ is the next logical sector number to read +; +LOOPRD: + MOV AX,BIOS$ ; Starting sector + CALL DODIV +; +; CurHD is the head for this next disk request +; CurTrk is the track for this next request +; CurSec is the beginning sector number for this request +; +; Compute the number of sectors that we may be able to read in a single ROM +; request. +; + MOV AX,SECLIM + SUB AL,CURSEC + INC AX +; +; AX is the number of sectors that we may read. +; + +; +;New code for Rev 3.31 +;***************************************************************************** + + CMP COUNT,AL ;Is sectors we can read more than we need? + JAE GOT_SECTORS ;No, it is okay + MOV AL,COUNT ;Yes, only read in what is left + +GOT_SECTORS: + +;***************************************************************************** +;End of change +; + + + PUSH AX + CALL DOCALL + POP AX + JB RERROR ; If errors report and go to ROM BASIC + SUB COUNT,AL ; Are we finished? +; +;Old code replaced by Rev 3.3 +;******************************************************************** +; JBE DISKOK ; Yes -- transfer control to the DOS +;******************************************************************** +;New code for Rev 3.3 +; + + JZ DISKOK ; Yes -- transfer control to the DOS + +;******************************************************************** +;End of change +; + ADD BIOS$,AX ; increment logical sector position + MUL ByteSec ; determine next offset for read + ADD BX,AX ; (BX)=(BX)+(SI)*(Bytes per sector) + JMP LOOPRD ; Get next track +; +; IBMINIT requires the following input conditions: +; +; DL = INT 13 drive number we booted from +; CH = media byte +; BX = First data sector on disk (0-based) +; +DISKOK: + MOV CH,Media + MOV DL,PhyDrv + MOV BX,[BIOSAV] ;Get bios sector in bx + JMP FAR PTR BIOS ;CRANK UP THE DOS + +WRITE: LODSB ;GET NEXT CHARACTER + OR AL,AL ;clear the high bit + JZ ENDWR ;ERROR MESSAGE UP, JUMP TO BASIC + MOV AH,14 ;WILL WRITE CHARACTER & ATTRIBUTE + MOV BX,7 ;ATTRIBUTE + INT 10H ;PRINT THE CHARACTER + JMP WRITE +; +; convert a logical sector into Track/sector/head. AX has the logical +; sector number +; +DODIV: + XOR DX,DX + DIV SECLIM + INC DL ; sector numbers are 1-based + MOV CURSEC,DL + XOR DX,DX + DIV HDLIM + MOV CURHD,DL + MOV CURTRK,AX +ENDWR: RET +; +; Issue one read request. ES:BX have the transfer address, AL is the number +; of sectors. +; +DOCALL: MOV AH,2 + MOV DX,CURTRK + MOV CL,6 + SHL DH,CL + OR DH,CURSEC + MOV CX,DX + XCHG CH,CL + MOV DL, PHYDRV + mov dh, curhd + INT 13H + RET + + include messages.inc + +BIO DB "IO SYS" +DOS DB "MSDOS SYS" + +Free EQU (cbSec - 3) - ($-$start) +if Free LT 0 + %out FATAL PROBLEM:boot sector is too large +endif + + org origin + (cbSec - 3) + +; FORMAT and SYS count on PHYDRV being right here +PHYDRV db 0 +; Boot sector signature + db 55h,0aah + +CODE ENDS + END diff --git a/SRC/BUGFIX/BIOS/MSBIO2.ASM b/SRC/BUGFIX/BIOS/MSBIO2.ASM new file mode 100644 index 0000000..e873b4c --- /dev/null +++ b/SRC/BUGFIX/BIOS/MSBIO2.ASM @@ -0,0 +1,650 @@ + TITLE MSBIO2 - DOS 3.3 + +;------------------------------------------------------------------------------- +; : +; Microsoft Bio : +; : +; The file msbio.asm is the main file in the Mircosoft bio. This file : +; includes the other main files in the bio. Most of the routines are : +; in these include files. The main files included are: : +; : +; File Contains : +; : +; msdisk.inc Disk device driver routines : +; ms96tpi.inc Routines for 96tpi drives : +; msaux.inc Device driver for the rs-232 serial ports : +; msclock.inc Device driver for "clock$" device : +; mscon.inc Device driver for "con" : +; mslpt.inc Device driver for the printers : +; : +; Each of these files contain a header section documenting the code : +; in that file. : +; Msbio also includes several files for equ's, structure definition, : +; macro definitions, etc. These are: : +; : +; msbiomes.inc msmacro.inc devsym.inc : +; dskprm.inc error.inc : +; : +; Each of these file contains explanitory notes. : +; : +; The actual code in msbio can be broken down into several piece: : +; : +; macro definitions Several marco are defined in msbio. They : +; are a few odds and end that did not fit : +; anywhere else. : +; : +; Command Jump Table List of entry points in the device drivers. : +; See notation below for full explination. : +; : +; Interrupt and Strategy : +; Entry points Calls on the device driver first come to here. : +; There is common code with pushes registers and : +; the like before jumping to routines in the : +; driver files. The common exit points are also : +; in this file. : +; : +; Miscellaneous Code There are several routines and data structure : +; declarations. See below for details. : +; : +;------------------------------------------------------------------------------- + + + +; +; If the variable TEST is non-zero then code for debugging is included. +; The extra code will make the binary file nuch larger. +; The symbol is also defined in msequ.inc. Both must be changed to +; turn debugging on or off. +; +; The level of the debugging is controled by the variable fTestBits in +; this file. See the comment preceeding the variable for more information. +; The actual routines which print the messages are in msmacro.inc +; See the header comment in this file for more information. +; + + +; +; Revision History +; +; REV 2.1 5/1/83 ARR added timer int handler and changed order of AUX +; PRN init for HAL0 +; +; REV 2.15 7/13/83 ARR Because of IBM design issues, and that BASCOM +; is ill behaved with respect to the 1CH timer interrupt, +; the timer handler has to be backed out! The intended +; code is commented out and has an ARR 2.15 annotation. +; This means the BIOS will go back to the multiple roll +; over bug. +; +; REV 2.20 8/5/83 ARR IBM makes hardware change. Now wants to use half +; height drives for HAL0, and back fit for PC/PC XT. Problem +; with head settle time. Previous drives got by on a 0 +; settle time, 1/2 hight drives need 15 head settle when +; doing WRITEs (0 ok on READ) if the head is being stepped. +; This requires a last track value to be kept so that BIOS +; knows when head is being moved. To help out +; programs that issue INT 13H directly, the head settle will +; normally be set to 15. It will be changed to 0 on READs, +; or on WRITEs which do not require head step. +; +; REV 2.21 8/11/83 MZ IBM wants write with verify to use head settle 0. +; Use same trick as above. +; +; REV 2.25 6/20/83 mjb001 added support for 96tpi and salmon +; +; REV 2.30 6/27/83 mjb002 added real-time clock +; +; REV 2.40 7/8/83 mjb003 added volume-id checking and int 2f macro +; definitions push* and pop* +; +; REV 2.41 7/12/83 ARR more 2.X enhancements. Open/Close media change +; +; REV 2.42 11/3/83 ARR more 2.X enhancements. Disk OPEN/CLOSE, FORMAT +; code and other misc hooked out to shrink BIOS. Code for +; Disk OPEN/CLOSE, FORMAT included only with 96tpi disks. +; +; Rev 2.43 12/6/83 MZ Examine boot sectors on hard disks for 16-bit fat +; check. Examine large fat bit in BPB for walk of media for +; DOS +; +; Rev 2.44 12/9/83 ARR Change to error reporting on INT 17H +; +; Rev 2.45 12/22/83 MZ Make head settle change only when disk parm is 0. + +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +; IBM ADDRESSES FOR I/O +; +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +;Below was moved from sysinit1 +ROMSEGMENT EQU 0F000H +MODELBYTE EQU DS:BYTE PTR [0FFFEH] +MODELPCJR EQU 0FDH + + test=0 +;;Rev 3.30 modification ---------------------------- + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + INCLUDE MSEQU.INC + INCLUDE DEVSYM.INC + INCLUDE PUSHPOP.INC + INCLUDE MSMACRO.INC + + ASSUME DS:NOTHING,ES:NOTHING + + EXTRN DSK$IN:NEAR + EXTRN SETPTRSAV:NEAR + EXTRN OUTCHR:NEAR + EXTRN SETDRIVE:NEAR + EXTRN FLUSH:NEAR + EXTRN HARDERR:NEAR + EXTRN HARDERR2:NEAR + EXTRN MAPERROR:NEAR + EXTRN GETBP:NEAR + EXTRN CHECKSINGLE:NEAR + EXTRN CHECK_TIME_OF_ACCESS:NEAR + EXTRN EXIT:NEAR + EXTRN HAS1:NEAR + EXTRN HAS1_res:NEAR + EXTRN READ_SECTOR:NEAR + EXTRN INT_2F_13:FAR + + EXTRN OLD13:DWORD + +;DATA + EXTRN PTRSAV:DWORD + EXTRN START_BDS:WORD + EXTRN FDRIVE1:WORD + EXTRN FDRIVE2:WORD + EXTRN FDRIVE3:WORD + EXTRN FDRIVE4:WORD + EXTRN FLAGBITS:WORD + EXTRN TIM_DRV:BYTE + EXTRN MEDBYT:BYTE + EXTRN DRVMAX:BYTE + + PATHSTART 005,DISK + EVENB + PUBLIC ORIG19 +ORIG19 DD ? + + PUBLIC INT19SEM +INT19SEM DB 0 ; INDICATE THAT ALL INT 19 + ; INITIALIZATION IS COMPLETE + + IRP AA,<02,08,09,0A,0B,0C,0D,0E,70,72,73,74,76,77> + public Int19OLD&AA +Int19OLD&AA dd -1 ;Orignal hw int. vec for INT 19h. + ENDM + + EVENB + PUBLIC DSKDRVS +DSKDRVS DW FDRIVE1 + DW FDRIVE2 + DW FDRIVE3 + DW FDRIVE4 + PUBLIC HDSKTAB +HDSKTAB DW HDRIVE + DW DRIVEX +;* Next area is reseved for mini disk BPB pointers *** 4/7/86 +;* Don't change this pos. Should be add. from DskDrvs *** 4/7/86 +MINI_DISK_BPB_PTRS DB 40 dup (?) ;4/7/86 - mem res for Mini disk. + + EVENB + PUBLIC INT_2F_NEXT +INT_2F_NEXT DD ? + +RET_ADDR DD ? + + PATHEND 005,DISK +;;End of modification ---------------------------- + +; INT19 +; +; We "hook" the INT_REBOOT vector, because contrary to IBM documentation, +; it does NOT "bootstrap" the machine. It leaves memory almost untouched. +; Since the BIOS_INIT code assumes that certain Interrupt Vectors point to +; the ROM_BIOS we must "unhook" them before issuing the actual INT_REBOOT. +; Currently the following vectors need to be unhooked: +; 02,08,09,0A,0B,0C,0D,0E,70,72,73,74,75,76,77 +; + +Public Int19 +Int19 proc FAR + xor AX,AX ; get data segment to + mov DS,AX ; point to the vector table + assume ds:nothing + assume es:nothing + les DI,Old13 ; get ES to point to this segment + mov DS:[13h*4],DI ; restore old int13 value + mov DS:[13h*4+2],ES + + cmp Byte ptr Int19Sem, 0 + jnz int19vecs + jmp doint19 + +;;Dos 3.30 Will not support the PC-Jr +;;Rev 3.30 modification ---------------------------- +; ON THE PCJR, DON'T REPLACE ANY VECTORS +; MODEL BYTE DEFINITIONS FROM MSSTACK.ASM +; MOV AX,ROMSEGMENT +; MOV DS,AX +; MOV AL,MODELPCJR +; +; CMP AL,MODELBYTE +; JNE INT19VECS +; JMP DOINT19 + + +;Stacks code has changed these hardware interrupt vectors +;STKINIT in SYSINIT1 will initialzie Int19hOLDxx values. +int19vecs: + +; +; we now need to unhook all the vector replace to prevent stack overflow +; + +;;Rev 3.30 modification ---------------------------- + XOR AX,AX + MOV DS,AX + + IRP AA,<02,08,09,0A,0B,0C,0D,0E,70,72,73,74,76,77> + + LES DI,Int19OLD&AA + + mov ax,es ; Put segment where we can compare it + cmp ax,-1 ; OPT 0ffffh is not likely + je skip_int&AA ; OPT could get away without checking + cmp di,-1 ; OPT offset here. + je skip_int&AA + + MOV DS:[AA&H*4],DI + MOV DS:[AA&H*4+2],ES +skip_int&AA: + ENDM +;;End of modification ---------------------------- + +doint19: + LES DI,Orig19 + MOV DS:[19h*4],DI + MOV DS:[19h*4+2],ES + + INT 19h +INT19 ENDP +ASSUME DS:CODE + +;***************************************************************************** +PUBLIC DSK$INIT +DSK$INIT PROC NEAR + PUSH CS + POP DS + MOV AH,BYTE PTR DRVMAX + MOV DI,OFFSET DskDrvs + JMP SetPTRSAV +DSK$INIT ENDP + + +; +; Int 2f handler for external block drivers to communicate with the internal +; block driver in msdisk. The multiplex number chosen is 8. The handler +; sets up the pointer to the request packet in [PTRSAV] and then jumps to +; DSK$IN, the entry point for all disk requests. +; On exit from this driver (at EXIT), we will return to the external driver +; that issued this Int 2F, and can then remove the flags from the stack. +; This scheme allows us to have a small external device driver, and makes +; the maintainance of the various drivers (DRIVER and msBIO) much easier, +; since we only need to make changes in one place (most of the time). +; +; AL contains the Int2F function: +; 0 - Check for installed handler - RESERVED +; 1 - Install the BDS into the linked list +; 2 - DOS request +; + +MYNUM EQU 8 + +Public Int2F_Disk +Int2F_Disk PROC FAR + cmp ah,MYNUM + je Mine + jmp cs:[Int_2F_Next] ; chain to next Int 2F handler +Mine: + cmp al,0F8H ; IRET on reserved functions + jb Do_Func + IRET +Do_Func: + or al,al ; A GET INSTALLED STATE request? + jne Disp_Func + mov al,0FFH + IRET +Disp_Func: + Message fTestInit,<"Int2F_disk",cr,lf> + cmp al,1 ; Request for installing BDS? + jne Do_DOS_Req + call Install_BDS + IRET + +Do_DOS_Req: +; Set up pointer to request packet + MOV WORD PTR CS:[PTRSAV],BX + MOV WORD PTR CS:[PTRSAV+2],ES + jmp DSK$IN + +Int2F_Disk ENDP + +; +; Install_BDS installs a BDS a location DS:DI into the current linked list of +; BDS maintained by this device driver. It places the BDS at the END of the +; list. +Public Install_BDS +INSTALL_BDS PROC NEAR + message ftestinit,<"Install BDS",cr,lf> +; ds:di point to BDS to be installed + les si,dword ptr cs:[Start_BDS] ; Start at beginning of list + push es ; Save pointer to current BDS + push si +; es:si now point to BDS in linked list +Loop_Next_BDS: + cmp si,-1 ; got to end of linked list? + jz Install_Ret +; If we have several logical drives using the same physical drive, we must +; set the I_Am_Mult flag in each of the appropriate BDSs. + mov al,byte ptr ds:[di].DriveNum + cmp byte ptr es:[si].DriveNum,al + jnz Next_BDS + message ftestinit,<"Logical Drives",cr,lf> + xor bx,bx + mov bl,fI_Am_Mult + or word ptr ds:[di].flags,bx ; set flags in both BDSs concerned + or word ptr es:[si].flags,bx + mov bl,fI_Own_Physical + xor bx,-1 + and word ptr ds:[di].flags,bx ; reset that flag for 'new' BDS +; We must also set the fChangeline bit correctly. + mov bx,word ptr es:[si].flags ; determine if changeline available + and bl,fChangeline + xor bh,bh + or word ptr ds:[di].flags,bx + +Next_BDS: +; Before moving to next BDS, preserve pointer to current one. This is needed at +; the end when the new BDS is linked into the list. + pop bx ; discard previous pointer to BDS + pop bx + push es + push si + mov bx,word ptr es:[si].link + 2 + mov si,word ptr es:[si].link + mov es,bx + jmp short Loop_Next_BDS + +Install_Ret: + pop si ; Retrieve pointer to last BDS + pop es ; in linked list. + mov ax,ds + mov word ptr es:[si].link+2,ax ; install BDS + mov word ptr es:[si].link,di + mov word ptr ds:[di].link,-1 ; set NEXT pointer to NULL + RET +INSTALL_BDS ENDP + +; +; RE_INIT installs the Int 2F vector that will handle communication between +; external block drivers and the internal driver. It also installs the +; Reset_Int_13 interface. It is called by SYSYINIT +; +PUBLIC RE_INIT +RE_INIT PROC FAR + Message ftestinit,<"REINIT",CR,LF> + PUSH AX + PUSH DS + PUSH DI + XOR DI,DI + MOV DS,DI + MOV DI,2FH*4 ; point it to Int 2F Vector + MOV AX,WORD PTR DS:[DI] + MOV WORD PTR CS:[INT_2F_NEXT],AX + MOV AX,WORD PTR DS:[DI+2] ; preserve old Int 2F vector + MOV WORD PTR CS:[INT_2F_NEXT+2],AX + +; INSTALL the Reset_Int_13 +; interface + + + CLI + MOV Word Ptr DS:[DI],Offset Int_2f_13 ; install new vectors + MOV Word Ptr DS:[DI+2],CS + STI + POP DI + POP DS + POP AX + RET + +RE_INIT ENDP + +;------------------------------------------------- +; +; Ask to swap the disk in drive A: +; Using a different drive in a one drive system so +; request the user to change disks +; +Public SWPDSK +SWPDSK PROC NEAR + mov al,byte ptr ds:[di].drivelet ; get the drive letter + add al,"A" + mov cs:DRVLET,AL + push ds ; preserve segment register + push cs + pop ds + mov SI,OFFSET SNGMSG ; ds:si -> message + push BX + call WRMSG ;Print disk change message + call FLUSH + ; wait for a keyboard character + xor AH, AH ; set command to read character + int 16h ; call rom-bios + POP BX + pop ds ; restore segment register +WRMRET: + ret +SWPDSK ENDP + +;---------------------------------------------- +; +; WrMsg writes out message pointed to by [SI] +; +Public WrMsg +WRMSG PROC NEAR + lodsb ; get the next character of the message + or AL,AL ; see fi end of message + jz WRMRET + pushf + push CS + call OUTCHR + jmp SHORT WRMSG +WRMSG ENDP + + INCLUDE BIOMES.INC + +; +; End of support for multiple floppies with no logical drives +; This is not 'special' any more because we now have the capability of +; defining logical drives in CONFIG.SYS. We therefore keep the code for +; swapping resident ALL the time. +; + +;;Rev 3.30 modification ---------------------------- +;Variables for Dynamic Relocatable modules +;These should be stay resident. + + public INT6C_RET_ADDR +INT6C_RET_ADDR DD ? ;ret add from INT 6C for P12 mach + + PATHSTART 001,CLK +; +; DATA STRUCTURES FOR REAL-TIME DATE AND TIME +; + public BIN_DATE_TIME + public MONTH_TABLE + public DAYCNT2 + public FEB29 +BIN_DATE_TIME: + DB 0 ; CENTURY (19 OR 20) OR HOURS (0-23) + DB 0 ; YEAR IN CENTURY (0-99) OR MINUTES (0-59) + DB 0 ; MONTH IN YEAR (1-12) OR SECONDS (0-59) + DB 0 ; DAY IN MONTH (1-31) +MONTH_TABLE: + DW 0 ;MJB002 JANUARY + DW 31 ;MJB002 FEBRUARY + DW 59 ;MJB002 + DW 90 ;MJB002 + DW 120 ;MJB002 + DW 151 ;MJB002 + DW 181 ;MJB002 + DW 212 ;MJB002 + DW 243 ;MJB002 + DW 273 ;MJB002 + DW 304 ;MJB002 + DW 334 ;MJB002 +DAYCNT2 DW 0000 ;MJB002 TEMP FOR CNT OF DAYS SINCE 1-1-80 +FEB29 DB 0 ;MJB002 FEBRUARY 29 IN A LEAP YEAR FLAG + PATHEND 001,CLK + +;;End of modification modification ---------------------------- + +Public EndFloppy +EndFloppy Label Byte +; +; End of code for virtual floppy drives +; +Public EndSwap +EndSwap Label Byte + + PATHSTART 004,BIO + +Public HNUM +HNUM DB 0 ; number of hardfile (hard drives) + +Public HardDrv +HARDDRV DB 80H ;Physical drive number of first hardfile + + +; +; "HDRIVE" is a hard disk with 512 byte sectors +; + + EVENB +Public BDSH +BDSH DW -1 ; Link to next structure + DW Code + DB 80h ; physical drive number + DB "C" ; Logical Drive Letter +Public HDRIVE +HDRIVE: + DW 512 + DB 1 ; Sectors/allocation unit + DW 1 ; Reserved sectors for DOS + DB 2 ; No. of allocation tables + DW 16 ; Number of directory entries + DW 0000 ; Number of sectors (at 512 bytes each) + DB 11111000B ; Media descriptor + DW 1 ; Number of FAT sectors + DW 00 ; Sector limit + DW 00 ; Head limit + DW 00 ; Hidden sector count + DB 0 ; TRUE => bigfat +OPCNTH DW 0 ; Open Ref. Count +VOLIDH DB "NO NAME ",0 ; Volume ID for this disk + DB 3 ; Form Factor +FLAGSH DW 0020H ; Various Flags + dw 40 ; number of cylinders +RecBPBH db 31 dup (?) ; Recommended BPB for drive +TRACKH DB -1 ; Last track accessed on this drive +TIM_LOH DW -1 ; Keep these two contiguous (?) +TIM_HIH DW -1 +; +; End of single hard disk section +; + + +Public EndOneHard +EndOneHard Label Byte + + + + +; +;"DRIVEX" is an extra type of drive usually reserved for an +; additional hard file +; + + EVENB +Public BDSX +BDSX DW -1 ; Link to next structure + DW Code + DB 81h ; physical drive number + DB "D" ; Logical Drive Letter +Public DRIVEX +DRIVEX: + DW 512 + DB 00 ; Sectors/allocation unit + DW 1 ; Reserved sectors for DOS + DB 2 ; No. of allocation tables + DW 0000 ; Number of directory entries + DW 0000 ; Number of sectors (at 512 bytes each) + DB 11111000B ; Media descriptor + DW 0000 ; Number of FAT sectors + DW 00 ; Sector limit + DW 00 ; Head limit + DW 00 ; Hidden sector count + DB 0 ; TRUE => bigfat +OPCNTD DW 0 ; Open Ref. Count +VOLIDD DB "NO NAME ",0 ; Volume ID for this disk + DB 3 ; Form Factor +FLAGSD DW 0020H ; Various Flags + dw 40 ; number of cylinders +RecBPBD db 31 dup (?) ; Recommended BPB for drive +TRACKD DB -1 ; Last track accessed on this drive +TIM_LOD DW -1 ; Keep these two contiguous +TIM_HID DW -1 + +; +; End of section for two hard disks +Public EndTwoHard +EndTwoHard Label Byte + + PATHEND 004,BIO + + +Public TwoHard +TWOHARD LABEL BYTE + +PAGE +include ms96tpi.inc + +;;Rev 3.30 modification ---------------------------- +;Memory allocation for BDSM table. + PUBLIC BDSMs +BDSMs BDSM_type Max_mini_dsk_num dup (<>) ;currently max. 23 + +;** End_of_BDSM defined in MSINIT.ASM will be used to set the appropriate +;** ending address of BDSM table. +;;End of modification ---------------------------- + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug005sp +; +;;3.3 BUG FIX -SUNILP ------------------------------ +;Paragraph buffer between the BDSMs and MSHARD +; +;The relocation code for MSHARD needs this. this cannot be used for +;anything. nothing can come before this or after this.....IMPORTANT!!!! +;don't get too smart and using this buffer for anything!!!!!! +; + db 16 dup(0) +; +;end of bug fix buffer +;; +;;3.3 BUG FIX -SUNILP------------------------------ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug005sp +CODE ENDS + END diff --git a/SRC/BUGFIX/CMD/COMMAND/COMMAND.COM b/SRC/BUGFIX/CMD/COMMAND/COMMAND.COM new file mode 100644 index 0000000..62d13cc Binary files /dev/null and b/SRC/BUGFIX/CMD/COMMAND/COMMAND.COM differ diff --git a/SRC/BUGFIX/CMD/FDISK/FDISK.COM b/SRC/BUGFIX/CMD/FDISK/FDISK.COM new file mode 100644 index 0000000..385fa9d Binary files /dev/null and b/SRC/BUGFIX/CMD/FDISK/FDISK.COM differ diff --git a/SRC/BUGFIX/CMD/FORMAT/FORMAT.ASM b/SRC/BUGFIX/CMD/FORMAT/FORMAT.ASM new file mode 100644 index 0000000..17d7e50 --- /dev/null +++ b/SRC/BUGFIX/CMD/FORMAT/FORMAT.ASM @@ -0,0 +1,3032 @@ +page 84,132 +; SCCSID = @(#)format.asm 1.26 85/10/20 +; SCCSID = @(#)format.asm 1.26 85/10/20 +;*************************************************************** +; +; 86-DOS FORMAT DISK UTILITY +; +; This routine formats a new disk,clears the FAT and DIRECTORY then +; optionally copies the SYSTEM and COMMAND.COM to this new disk +; +; SYNTAX: FORMAT [drive][/switch1][/switch2]...[/switch16] +; +; Regardless of the drive designator , the user will be prompted to +; insert the diskette to be formatted. +; +;*************************************************************** + +; 5/12/82 ARR Mod to ask for volume ID +; 5/19/82 ARR Fixed rounding bug in CLUSCAL: +; REV 1.5 +; Added rev number message +; Added dir attribute to DELALL FCB +; REV 2.00 +; Redone for 2.0 +; REV 2.10 +; 5/1/83 ARR Re-do to transfer system on small memory systems +; REV 2.20 +; 6/17/83 system size re-initialization bug -- mjb001 +; Rev 2.25 +; 8/31/83 16-bit fat insertion +; Rev 2.26 +; 11/2/83 MZ fix signed compare problems for bad sectors +; Rev 2.27 +; 11/8/83 EE current directories are always saved and restored +; Rev 2.28 +; 11/9/83 NP Printf and changed to an .EXE file +; Rev 2.29 +; 11/11/83 ARR Fixed ASSIGN detection to use NameTrans call to see +; if drive letter remapped. No longer IBM only +; Rev 2.30 +; 11/13/83 ARR SS does NOT = CS, so all use of BP needs CS override +; Rev 2.31 +; 12/27/83 ARR REP STOSB instruction at Clean: changed to be +; sure ES = CS. + +code segment public 'CODE' +code ends + +printf_code segment public + extrn printf:far +printf_code ends + +stack segment stack + db (362 - 80h) + 100H dup (?) ; (362-80h) is the additional IBM ROM + ; overhead recently discovered by them. +stack ends + +data segment public 'DATA' +data ends + +public end_of_memory +_end segment public para 'DATA' +end_of_memory label byte +_end ends + +code segment + + assume cs:code,ds:nothing,es:nothing,ss:stack + +;------------------------------------------------------------------------------- +; Define as public for debugging + +; procedures + public GetSize + public AddToSystemSize + public Phase1Initialisation + public SetStartSector + public SetfBigFat + public Phase2Initialisation + public DiskFormat + public BadSector + public FormatTrack + public DisplayCurrentTrack + public NextTrack + public WriteFileSystem + public Done + public CurrentLogicalSector + public PrintErrorAbort + public GetDeviceParameters + public SetDeviceParameters + + public START + public GOTBADDOS + public OKDOS + public BogusDrive + public DRVGD + public DRVSPEC + public NXTSWT + public GETPARM + public GETCHR + public INVALID + public SCANOFF + public MEMERR + public SAVSWT + public NotNet + public RE_ASSIGN + public NO_ASSIGN + public FatAllocated + public MEMERRJ + public MEM_OK + public RDFRST + public NEEDSYS + public INITCALL + public SWITCHCHK + public SYSLOOP + public FRMTPROB + public GETTRK + public TRKFND + public CLRTEST + public CMPTRKS + public PACKIT + public BadClus + public DoBig + public DoSet + public DRTFAT + public CLEARED + public LOUSE + public LOUSEP + public FATWRT + public SYSOK + public STATUS + public REPORTC + public ONCLUS + public MORE + public FEXIT + public SYSPRM + public fexitJ + public DoPrompt + public TARGPRM + public IsRemovable + public CheckRemove + public IsRemove + public NotRemove + public DSKPRM + public GOPRNIT + public crlf + public PrintString + public std_printf + public VOLID + public VRET + public DOVOL + public VOL_LOOP + public GOOD_CREATE + public VOLRET + public READDOS + public RDFILS + public FILESDONE + public CLSALL + public GOTBIOS + public GOTDOS + public CLSALLJ + public GOTCOM + public WRITEDOS + public GOTALLBIO + public BIOSDONE + public GOTNDOS + public PARTDOS + public GOTALLDOS + public DOSDONE + public PARTCOM + public GOTALLCOM + public COMDONE + public MAKEFIL + public CheckMany + public CLOSETARG + public IOLOOP + public GOTTARG + public GSYS + public TESTSYS + public GETOFFS +; public TESTSYSDISK ; dcl 8/23/86 + public SETBIOS + public BIOSCLS + public SETBIOSSIZ + public DOSOPNOK + public DOSCLS + public SETDOSSIZ + public GotComHand + public COMCLS + public SETCOMSIZ + public GETFSIZ + public READFILE + public WRITEFILE + public FILIO + public NORMIO + public IORETP + public IORET + public NORMALIZE + public GotDeviceParameters + public SmallFAT + public LoadSectorTable + public NotBigTotalSectors + public NotBig + public FormatLoop + public FormatDone + public FailDiskFormat + public FormatReallyFailed + public ContinueFormat + public ReportBadTrack + public NoMoreTracks + public ExitNextTrack + public ThatsAllFolks + public WriteFATloop + public WriteDIRloop + public CanNotWriteFAT + public CanNotWriteDirectory + public ControlC_Handler + +; bytes + public fBigFat + public formatError + public ROOTSTR + public DBLFLG + public DRIVE + public FILSTAT + public USERDIRS + public VOLFCB + public VOLNAM + public TRANSRC + public TRANDST + public INBUFF + public driveLetter + public systemDriveLetter +; words + public startSector + public fatSpace + public firstHead + public firstCylinder + public tracksLeft + public tracksPerDisk + public sectorsInRootDirectory + public directorySector + public printStringPointer + public MSTART + public MSIZE + public TempHandle + public BEGSEG + public SWITCHMAP + public SWITCHCOPY + public FAT + public CLUSSIZ + public SECSIZ + public SYSTRKS + public SECTORS + public ptr_msgHardDiskWarning + public ptr_msgInsertDisk + public ptr_msgReInsertDisk + public ptr_msgInsertDosDisk + public ptr_msgCurrentTrack + public currentHead + public currentCylinder + +; other + public deviceParameters + public formatPacket +;------------------------------------------------------------------------------- + +data segment + extrn msgAssignedDrive:byte + extrn msgBadDosVersion:byte + extrn msgDirectoryWriteError:byte + extrn msgFormatComplete:byte + extrn msgFormatNotSupported:byte + extrn msgFATwriteError:byte + extrn msgInvalidDeviceParameters:byte + extrn msgLabelPrompt:byte + extrn msgNeedDrive:byte + extrn msgNoSystemFiles:byte + extrn msgTooManyFilesOpen:byte + extrn msgNetDrive:byte + extrn msgInsertDisk:byte + extrn msgHardDiskWarning:byte + extrn msgSystemTransfered:byte + extrn msgFormatAnother?:byte + extrn msgBadCharacters:byte + extrn msgBadDrive:byte + extrn msgInvalidParameter:byte + extrn msgParametersNotSupported:byte + extrn msgReInsertDisk:byte + extrn msgInsertDosDisk:byte + extrn msgFormatFailure:byte + extrn msgNotSystemDisk:byte +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +; reintroduce following extrn + extrn msgNoRoomDestDisk:byte +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + extrn msgDiskUnusable:byte + extrn msgOutOfMemory:byte + extrn msgCurrentTrack:byte + extrn msgWriteProtected:byte + extrn msgNotReady:byte + extrn msgInterrupt:byte + extrn msgCRLF:byte + +data ends + + +debug equ 0 + .xlist + INCLUDE VERSIONA.INC + INCLUDE DOSMAC.INC + INCLUDE SYSCALL.INC + INCLUDE ERROR.INC + INCLUDE DPB.INC + INCLUDE CPMFCB.INC + INCLUDE DIRENT.INC + INCLUDE CURDIR.INC + INCLUDE PDB.INC + INCLUDE BPB.INC + .list + +;------------------------------------------------------------------------------- +; Constants + +;Limits +BIG_FAT_THRESHOLD equ 4086 + +;------------------------------------------------------------------------------- + +;FORMAT Pre-defined switches +SWITCH_S EQU 1 ; System transfer +SWITCH_V EQU 2 ; Volume ID prompt +SWITCH_H EQU 4 ; E5 dir terminator +SWITCH_C EQU 8 +SWITCH_T EQU 16 +SWITCH_N EQU 32 +SWITCH_1 EQU 64 +SWITCH_4 EQU 128 +SWITCH_8 EQU 256 +SWITCH_B EQU 512 + +NUM_SWITCHES EQU SWITCH_T or SWITCH_N + +DRNUM EQU 5CH + +RECLEN EQU fcb_RECSIZ+7 +RR EQU fcb_RR+7 + +;------------------------------------------------------------------------------- +; These are the data structures which we will need + + include ioctl.INC + +;Per system file data structure + +a_FileStructure struc +fileHandle DW ? +fileSizeInParagraphs DW ? +fileSizeInBytes DD ? +fileOffset DD ? +fileStartSegment DW ? +fileDate DW ? +fileTime DW ? +a_FileStructure ends + +;------------------------------------------------------------------------------- +; And this is the actual data + +data segment + public deviceParameters + +validSavedDeviceParameters db 0 +savedDeviceParameters a_DeviceParameters <> +deviceParameters a_DeviceParameters <> + +formatPacket a_FormatPacket <> + +startSector dw ? +fatSpace dd ? +fBigFat db FALSE + +firstHead dw ? +firstCylinder dw ? +tracksLeft dw ? +tracksPerDisk dw ? + +public NumSectors ,TrackCnt +NumSectors dw 0FFFFh +TrackCnt dw 0FFFFh + +public Old_Dir +Old_Dir db FALSE + +public fLastChance +fLastChance db FALSE ; Flags reinvocation from + ; LastChanceToSaveIt. Used by DSKPRM + +sectorsInRootDirectory dw ? + +directorySector dd 0 + +formatError db 0 + +printStringPointer dw 0 + +; Exit status defines +ExitStatus db 0 +ExitOK equ 0 +ExitCtrlC equ 3 +ExitFatal equ 4 +ExitNo equ 5 + +ROOTSTR DB ? + DB ":\",0 +DBLFLG DB 0 ;Initialize flags to zero +IOCNT DD ? +MSTART DW ? ; Start of sys file buffer (para#) +MSIZE DW ? ; Size of above in paragraphs +TempHandle DW ? +FILSTAT DB ? ; In memory status of files + ; XXXXXX00B BIOS not in + ; XXXXXX01B BIOS partly in + ; XXXXXX10B BIOS all in + ; XXXX00XXB DOS not in + ; XXXX01XXB DOS partly in + ; XXXX10XXB DOS all in + ; XX00XXXXB COMMAND not in + ; XX01XXXXB COMMAND partly in + ; XX10XXXXB COMMAND all in + +USERDIRS DB DIRSTRLEN+3 DUP(?) ; Storage for users current directory + +bios a_FileStructure <> +BiosAttributes EQU attr_hidden + attr_system + attr_read_only + +dos a_FileStructure <> +DosAttributes EQU attr_hidden + attr_system + attr_read_only + +command a_FileStructure <> +CommandAttributes EQU 0 +CommandFile DB "X:\COMMAND.COM",0 + +VOLFCB DB -1,0,0,0,0,0,8 + DB 0 +VOLNAM DB " " + DB 8 + DB 26 DUP(?) + +TRANSRC DB "A:CON",0,0 ; Device so we don't hit the drive +TRANDST DB "A:\",0,0,0,0,0,0,0,0,0,0 + +BEGSEG DW ? +SWITCHMAP DW ? +SWITCHCOPY DW ? +FAT DW ? + DW ? +CLUSSIZ DW ? +SECSIZ DW ? +SYSTRKS DW ? +SECTORS DW ? +INBUFF DB 80,0 + DB 80 DUP(?) + +ptr_msgHardDiskWarning dw msgHardDiskWarning + dw offset driveLetter + +ptr_msgInsertDisk dw msgInsertDisk + dw offset driveLetter + +ptr_msgReInsertDisk dw msgReInsertDisk + dw offset driveLetter + +ptr_msgInsertDosDisk dw offset msgInsertDosDisk + dw offset systemDriveLetter + +ptr_msgFormatNotSupported dw offset msgFormatNotSupported + dw offset driveLetter + +drive db 0 +driveLetter db "x" +systemDriveLetter db "x" + +data ends + +;For FORPROC and FORMES modules + + public secsiz,clussiz,inbuff + + PUBLIC crlf,std_printf + +;For OEM module + public switchmap,drive,driveLetter,fatSpace + public fBigFat, PrintString,currentHead,currentCylinder + extrn CheckSwitches:near,LastChanceToSaveIt:near + extrn WriteBootSector:near,OemDone:near + extrn AccessDisk:near +data segment + extrn switchlist:byte + extrn fdsksiz:word + extrn BiosFile:byte,DosFile:byte +data ends + +;For FORPROC module + + EXTRN FormatAnother?:near,Yes?:near,REPORT:NEAR,USER_STRING:NEAR +data segment + extrn badsiz:dword,syssiz:dword,biosiz:dword +data ends + +DOSVER_LOW EQU 0300H+20 +DOSVER_HIGH EQU 0300H+20 + + +START: + PUSH AX ;Save DRIVE validity info + MOV AH,GET_VERSION + INT 21H + CMP AX,EXPECTED_VERSION + JE OKDOS + +; XCHG AH,AL ;Turn it around to AH.AL +; CMP AX,DOSVER_LOW +; JB GotBadDos +; CMP AX,DOSVER_HIGH +; JBE OKDOS + + +GOTBADDOS: + MOV DX,OFFSET msgBadDosVersion + mov ax, seg data + mov ds, ax + mov ah,std_con_string_output + int 21h + push es + xor ax,ax + push ax + +foo proc far + ret ; Must use this method, version may be < 2.00 +foo endp + +OKDOS: + + mov ax, seg data + mov es, ax + assume es:data + POP AX + + CMP AL,0FFH ;See if invalid drive specified + JNZ DRVGD ;If not proceed +BogusDrive: + mov ax, seg data + mov ds, ax + lea dx, msgBadDrive + call PrintString + JMP FEXIT ;Exit + +DRVGD: + MOV AH,GET_DEFAULT_DRIVE ;Must get the default drive + INT 21H ;Default now in AL + ADD AL,"A" + MOV [BiosFile],AL + MOV [DosFile],AL + MOV [CommandFile],AL + MOV SI,DRNUM ;So we can get our parameters + LODSB ;Fetch drive designation + OR AL,AL ;See if specified + JNZ DRVSPEC ;If specfied proceed + mov ax, seg data + mov ds, ax + lea dx, msgNeedDrive + call PrintString + jmp fexit +DRVSPEC: + DEC AL ;Drive designator now correct + MOV BYTE PTR DS:[DRNUM],AL ;And updated + MOV DRIVE,AL ;Save copy + add al, 'A' + mov driveLetter, al +; Get all the switch information from the command line + MOV [BEGSEG],DS ;Save start segment + + XOR BX,BX ;Store switch information in BX + MOV SI,81H ;Point to the command line buffer +NXTSWT: + CALL SCANOFF + LODSB + CMP AL,"/" + JZ GETPARM + + CMP AL,13 + JNZ NxtS1 + JMP SavSwt +NxtS1: + MOV AH,AL + LODSB ; AX := getchar() + CMP AL,":" ; IF (AX != drive_spec) + JNZ INVALID ; THEN error + + CMP BYTE PTR DBLFLG,0 ; IF (previous drive_spec) + JNZ INVALID ; THEN error + + INC BYTE PTR DBLFLG ; Yes -- set the flag + OR AH,020h + SUB AH,'a' + CMP AH,Drive + JZ SHORT NXTSWT + JMP BogusDrive +GETPARM: + LODSB +; Convert any lower case input into upper case + CMP AL,41H + JB GETCHR ; Switch is a digit, so don't try to + ; convert it. + AND AL,0DFH +GETCHR: + MOV CL,SWITCHLIST ; CL := Number of Legal switches + OR CL,CL ; IF (Num_Legal_Switches == 0) + JZ INVALID ; THEN error + + MOV CH,0 ; FOR (i=0; i <= Max_switches; i++) + MOV DI,1+OFFSET SWITCHLIST ; IF (switch == SWITCHLIST[i]) + REPNE SCASB ; THEN set zero flag + ; END for + JNZ INVALID ; IF (zero_flag != TRUE ) THEN error + + MOV AX,1 + SHL AX,CL + OR BX,AX ;Set the appropriate bit in SWITCHMAP + + MOV CX,AX ; Current_Switch := Switch processed + Test AX,NUM_SWITCHES ; IF (Switch_processed does not require + ; numeric value) + JZ NXTSWT ; THEN parse next switch + + LODSB ; ELSE then parse :nn and save approp + cmp al,':' ; IF (getchar() != ':') + jne INVALID + + LODSB ; curr_num := MakeNum (getchar()) + SaveReg + call MakeNum + RestoreReg + jc INVALID ; IF error, THEN exit + + SaveReg + Call SaveNum ; SaveNum (curr_num) + Restorereg ; END else; + + + JMP SHORT NXTSWT ;See if there are anymore + +INVALID: + mov ax, seg data + mov ds, ax + lea dx, msgInvalidParameter + call PrintString + JMP FEXIT +MEMERR: + mov ax, seg data + mov ds, ax + lea dx, msgOutOfMemory + call PrintString + JMP FEXIT + +SAVSWT: + mov ax, seg data + mov ds, ax + assume ds:data + MOV SWITCHMAP,BX + +; Set memory requirements + mov es, begseg + mov bx, seg _end + sub bx, begseg + mov ah, setblock + int 21H + +; trap ^C + mov ax, (Set_Interrupt_Vector shl 8) or 23H + mov dx, offset ControlC_Handler + push ds + push cs + pop ds + int 21H + pop ds + +AroundControlC_Handler: + MOV BL,Drive ; x = IOCTL (getdrive, Drive+1); + INC BL + MOV AX,(IOCTL SHL 8) OR 9 + INT 21H + JC NotNet + TEST DX,1200H ; if (x & 0x1200)(redirected or shared) + JZ NotNet + lea dx, msgNetDrive ; Cann't format over net + call PrintString + JMP FEXIT + +NotNet: + TEST DX,8000h ; if local use + jnz re_assign + MOV BL,Drive + ADD BYTE PTR [TRANSRC],BL ; Make string "D:\" + MOV SI,OFFSET TRANSRC + push ds + pop es + MOV DI,OFFSET TRANDST + MOV AH,xNameTrans + INT 21H + MOV BL,BYTE PTR [TRANSRC] + CMP BL,BYTE PTR [TRANDST] ; Did drive letter change? + JZ NO_ASSIGN ; No +RE_ASSIGN: + lea dx, msgAssignedDrive + call PrintString + JMP FEXIT + +NO_ASSIGN: + + CALL Phase1Initialisation + jnc FatAllocated + + lea dx, msgFormatFailure ; IF (error_allocating_FAT) + call PrintString ; ISSUE error and abort + jmp Fexit +FatAllocated: + + TEST SWITCHMAP,SWITCH_S + JZ INITCALL + MOV BX,0FFFFH + MOV AH,ALLOC + INT 21H + OR BX,BX + JZ MEMERRJ ;No memory + MOV [MSIZE],BX + MOV AH,ALLOC + INT 21H + JNC MEM_OK +MEMERRJ: + JMP MEMERR ;No memory + +MEM_OK: + MOV [MSTART],AX + +RDFRST: + mov bios.fileSizeInParagraphs,0 ;mjb001 initialize file size + mov dos.fileSizeInParagraphs,0 ;mjb001 ... + mov command.fileSizeInParagraphs,0 ;mjb001 ... + CALL READDOS ;Read BIOS and DOS + JNC INITCALL ;OK -- read next file +NEEDSYS: + CALL SYSPRM ;Prompt for system disk + JMP RDFRST ;Try again + +INITCALL: + CALL Phase2Initialisation +; Barry S - No reason to jump on carry!!! +; JNC SWITCHCHK +; lea dx, msgFormatFailure +; call PrintString +; JMP FEXIT + +SWITCHCHK: + MOV DX,SWITCHMAP + MOV SWITCHCOPY,DX + +SYSLOOP: + MOV WORD PTR BADSIZ,0 ;Must intialize for each iteration + MOV WORD PTR BADSIZ+2,0 + MOV WORD PTR SYSSIZ,0 + MOV WORD PTR SYSSIZ+2,0 + MOV BYTE PTR DBLFLG,0 + mov ExitStatus, ExitOK + MOV DX,SWITCHCOPY + MOV SWITCHMAP,DX ;Restore original Switches +; DiskFormat will handle call for new disk +; CALL DSKPRM ;Prompt for new disk + CALL DISKFORMAT ;Format the disk + JNC GETTRK +FRMTPROB: + lea dx, msgFormatFailure + call PrintString + mov ExitStatus, ExitFatal + CALL MORE ;See if more disks to format + JMP SHORT SYSLOOP + +;Mark any bad sectors in the FATs +;And keep track of how many bytes there are in bad sectors + +GETTRK: + CALL BADSECTOR ;Do bad track fix-up + JC FRMTPROB ;Had an error in Formatting - can't recover + CMP AX,0 ;Are we finished? + JNZ TRKFND ;No - check error conditions + JMP DRTFAT ;Yes +TRKFND: + CMP BX,STARTSECTOR ;Are any sectors in the system area bad? + JAE CLRTEST ; MZ 2.26 unsigned compare + lea dx, msgDiskUnusable + call PrintString + JMP FRMTPROB ;Bad disk -- try again +CLRTEST: + MOV SECTORS,AX ;Save the number of sectors on the track + TEST SWITCHMAP,SWITCH_S ;If system requested calculate size + JZ BAD100 + CMP BYTE PTR DBLFLG,0 ;Have we already calculated System space? + JNZ CMPTRKS ;Yes -- all ready for the compare + INC BYTE PTR DBLFLG ;No -- set the flag + CALL GETBIOSIZE ; Get the size of the BIOS + MOV DX,WORD PTR SYSSIZ+2 + MOV AX,WORD PTR SYSSIZ + MOV WORD PTR BIOSIZ+2,DX + MOV WORD PTR BIOSIZ,AX + CALL GETDOSSIZE + CALL GETCMDSIZE + MOV DX,WORD PTR BIOSIZ+2 + MOV AX,WORD PTR BIOSIZ + DIV deviceParameters.DP_BPB.BPB_BytesPerSector + ADD AX,STARTSECTOR + MOV SYSTRKS,AX ;Space FAT,Dir,and system files require +CMPTRKS: + CMP BX,SYSTRKS + JA BAD100 ; MZ 2.26 unsigned compare + mov ExitStatus, ExitFatal + lea dx, msgNotSystemDisk + call PrintString + AND SWITCHMAP,NOT SWITCH_S ;Turn off system transfer switch + MOV WORD PTR SYSSIZ+2,0 ;No system to transfer + MOV WORD PTR SYSSIZ,0 ;No system to transfer +BAD100: +; BX is the first bad sector #, SECTORS is the number of bad sectors +; starting at BX. This needs to be converted to clusters. The start sector +; number may need to be rounded down to a cluster boundry, the end sector +; may need to be rounded up to a cluster boundry. Know BX >= STARTSECTOR + SUB BX,STARTSECTOR ; BX is now DATA area relative + MOV CX,BX + ADD CX,SECTORS + DEC CX ; CX is now the last bad sector # + MOV AX,BX + XOR DX,DX + xor bx,bx + mov bl, deviceParameters.DP_BPB.BPB_SectorsPerCluster + DIV bx + MOV BX,AX ; BX is rounded down and converted to + ; a cluster #. Where cluster 0 = + ; first cluster of data. First bad + ; Sector is in cluster BX. + MOV AX,CX + XOR DX,DX + push bx + xor bx,bx + mov bl, deviceParameters.DP_BPB.BPB_SectorsPerCluster + DIV bx + pop bx + MOV CX,AX ; CX is rounded up and converted to a + ; to a cluster #. Where cluster 0 = + ; first cluster of data. Last bad + ; Sector is in cluster CX. + SUB CX,BX + INC CX ; CX is number of clusters to mark bad + ADD BX,2 ; Bias start by correct amount since + ; first cluster of data is really + ; cluster 2. + xor ax,ax + MOV Al,deviceParameters.DP_BPB.BPB_SectorsPerCluster + MUL deviceParameters.DP_BPB.BPB_BytesPerSector + MOV BP,AX ; = Bytes/Cluster + +; Mark CX clusters bad starting at cluster BX +PACKIT: + CALL BadClus ;Put it in the allocation map + JZ BAD150 ;If already marked bad, don't count it + ADD WORD PTR BADSIZ,BP ;Add in number of bad bytes + JNB BAD150 + INC WORD PTR BADSIZ+2 +BAD150: + INC BX ;Next cluster + LOOP PACKIT ;Continue for # of clusters + JMP GETTRK + +; Inputs: BX = Cluster number +; Outputs: The given cluster is marked as invalid +; Zero flag is set if the cluster was already marked bad +; Registers modified: DX,SI +; No other registers affected +BadClus: + PUSH AX + PUSH BX + PUSH CX + PUSH DX + CMP fBigFat,-1 ; if (!fBigFat) { + JZ DoBig + MOV DX,0FF7h ; badval = 0xFF7; + MOV AX,0FFFh ; mask = 0xFFF; + MOV SI,BX ; p = FAT+clus+clus/2; + SHR SI,1 + ADD SI,BX + ADD SI, word ptr fatspace + TEST BX,1 ; if (clus&1) { + JZ DoSet + MOV CL,4 ; mask <<= 4; + SHL AX,CL + MOV CL,4 ; badval <<= 4; + SHL DX,CL ; } + JMP SHORT DoSet +DoBig: ; else { + MOV DX,0FFF7h ; badval = 0xFFF7; + MOV AX,0FFFFh ; mask = 0xFFFF; + MOV SI, word ptr fatSpace ; p = FAT + clus + clus; + ADD SI,BX + ADD SI,BX +DoSet: ; } + push es + mov es, word ptr fatSpace + 2 + MOV CX,es:[SI] ; op = *p & mask; + AND CX,AX + NOT AX ; *p &= ~mask; + AND es:[SI],AX + OR es:[SI],DX ; *p |= badval; + CMP DX,CX ; return op == badval; + pop es + POP DX + POP CX + POP BX + POP AX + return + +DRTFAT: + TEST SWITCHMAP,SWITCH_S ;If system requested, calculate size + JZ CLEARED + CMP BYTE PTR DBLFLG,0 ;Have we already calculated System space? + JNZ CLEARED ;Yes + INC BYTE PTR DBLFLG ;No -- set the flag + CALL GETSIZE ;Calculate the system size +CLEARED: + CALL WriteFileSystem + JNC FATWRT +LOUSE: + lea dx, msgDiskUnusable + call PrintString + JMP FRMTPROB + +LOUSEP: + POP DS + JMP LOUSE + +FATWRT: + + PUSH DS + MOV DL,DRIVE + INC DL + MOV AH,GET_DPB + INT 21H + CMP AL,-1 + JZ LOUSEP ;Something BAD has happened + MOV [BX.dpb_next_free],0 ; Reset allocation to start of disk + MOV [BX.dpb_free_cnt],-1 ; Force free space to be computed + POP DS + TEST SWITCHMAP,SWITCH_S ;System desired + JZ STATUS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +;reintroduce following section of code +; + CALL CHKSPACE ;Enough free space for system? + JNC SPACEOK ; Y: Go load system files + LEA DX, msgNoRoomDestDisk ; N: Print error message + CALL PrintString ; + MOV WORD PTR SYSSIZ+2,0 ;No system transfered + MOV WORD PTR SYSSIZ,0 ;No system transfered + JMP SHORT STATUS ; +SPACEOK: ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + mov al, drive + call AccessDisk ; note what is current logical drive + CALL WRITEDOS ;Write the BIOS & DOS + JNC SYSOK + lea dx, msgNotSystemDisk + call PrintString + MOV WORD PTR SYSSIZ+2,0 ;No system transfered + MOV WORD PTR SYSSIZ,0 ;No system transfered + JMP SHORT STATUS + +SYSOK: + lea dx, msgSystemTransfered + call PrintString +STATUS: + CALL CRLF + CALL VOLID + MOV AH,DISK_RESET + INT 21H + CALL DONE ;Final call to OEM module + JNC REPORTC + JMP FRMTPROB ;Report an error + +REPORTC: + CALL REPORT + + CALL MORE ;See if more disks to format + JMP SYSLOOP ;If we returned from MORE then continue + +;****************************************** +; Calculate the size in bytes of the system rounded up to sector and +; cluster boundries, Answer in SYSSIZ + +GetSize proc near + call GetBioSize + call GetDosSize + call GetCmdSize + return +GetSize endp + +GetBioSize proc near + MOV AX,WORD PTR bios.fileSizeInBytes + MOV DX,WORD PTR bios.fileSizeInBytes+2 + CALL AddToSystemSize + return +GetBioSize endp + +GetDosSize proc near + MOV AX,WORD PTR dos.fileSizeInBytes + MOV DX,WORD PTR dos.fileSizeInBytes+2 + CALL AddToSystemSize + return +GetDosSize endp + +GetCmdSize proc near + MOV AX,WORD PTR command.fileSizeInBytes + MOV DX,WORD PTR command.fileSizeInBytes+2 + call AddToSystemSize + return +GetCmdSize endp + +;Calculate the number of sectors used for the system +PUBLIC AddToSystemSize +AddToSystemSize proc near + push bx + DIV deviceParameters.DP_BPB.BPB_BytesPerSector + OR DX,DX + JZ FNDSIZ0 + INC AX ; Round up to next sector +FNDSIZ0: + PUSH AX + XOR DX,DX + xor bx,bx + mov bl, deviceParameters.DP_BPB.BPB_SectorsPerCluster + div bx + POP AX + OR DX,DX + JZ ONCLUS + SUB DX, bx + NEG DX + ADD AX,DX ; Round up sector count to cluster + ; boundry +ONCLUS: + MUL deviceParameters.DP_BPB.BPB_BytesPerSector + ADD WORD PTR SYSSIZ,AX + ADC WORD PTR SYSSIZ+2,DX + pop bx + return +AddToSystemSize endp + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +; reintroduce following section of code +;; Check free space to see if there is enough room to load the system +;; On Entry: DL = drive +;; On Exit: carry flag set if not enough room +;; no other registers are affected +CHKSPACE PROC NEAR + PUSH AX ;Save resisters + PUSH BX + PUSH CX + PUSH DX + + MOV AH,36H ;Get free space + INT 21h + +;;16 bit math okay here, no danger of overflow + MUL CX ;Get bytes/cluster + MOV CX,AX ; + MOV AX,WORD PTR SYSSIZ ;Get # of bytes for system + MOV DX,WORD PTR SYSSIZ+2 ; + DIV CX ;Get # of clusters for system + + CMP AX,BX ;Is there enough space? + JBE ENOUGHSPACE ; Y: Go clear carry + STC ; N: Set carry + JMP SHORT RESTOREREGS ; +; +ENOUGHSPACE: + CLC +; +RESTOREREGS: + POP DX ;Restore resisters + POP CX + POP BX + POP AX + RET +CHKSPACE ENDP +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + +MORE: CMP deviceParameters.DP_DeviceType, DEV_HARDDISK + je ExitProgram + CALL FormatAnother? ;Get yes or no response + JC ExitProgram + CALL CRLF + JMP CRLF + + +FEXIT: + mov ExitStatus,ExitFatal + +ExitProgram: + test validSavedDeviceParameters, 0ffH + jz DoNotRestoreDeviceParameters + mov savedDeviceParameters.DP_SpecialFunctions, TRACKLAYOUT_IS_GOOD + lea dx, savedDeviceParameters + call SetDeviceParameters +DoNotRestoreDeviceParameters: + mov al, ExitStatus + mov ah,exit + INT 21H + +; Prompt the user for a system diskette in the default drive +SYSPRM: + MOV AH,GET_DEFAULT_DRIVE ;Will find out the default drive + INT 21H ;Default now in AL + MOV BL,AL + INC BL ; A = 1 + ADD AL,41H ;Now in Ascii + MOV systemDriveLetter,AL ;Text now ok + CALL IsRemovable + JNC DoPrompt +; +; Media is non-removable. Switch sys disk to drive A. Check, though, to see +; if drive A is removable too. +; + MOV AL,"A" + MOV BYTE PTR [systemDriveLetter],AL + MOV [BiosFile],AL + MOV [DosFile],AL + MOV [CommandFile],AL + MOV BX,1 + CALL IsRemovable + JNC DoPrompt + lea dx, msgNoSystemFiles + call PrintString +fexitJ: + JMP FEXIT + +DoPrompt: + mov al, systemDriveLetter + sub al, 'A' + call AccessDisk + lea dx, ptr_msgInsertDosDisk + CALL std_printf ;Print first line + CALL USER_STRING ;Wait for a key + CALL CRLF + return + +TARGPRM: + mov al, drive + call AccessDisk + lea DX, ptr_msgInsertDisk + CALL std_printf ;Print first line + CALL USER_STRING ;Wait for a key + CALL CRLF + return + +; +; Determine if the drive indicated in BX is removable or not. +; +; Inputs: BX has drive (0=def, 1=A) +; Outputs: Carry clear +; Removable +; Carry set +; not removable +; Registers modified: none + +IsRemovable: + SaveReg + MOV AX,(IOCTL SHL 8) OR 8 ; Rem media check + INT 21H + JNC CheckRemove + MOV AX,(IOCTL SHL 8) + 9 ; Is it a NET drive? + INT 21h + JC NotRemove ; Yipe, say non-removable + TEST DX,1000h + JNZ NotRemove ; Is NET drive, say non-removeable + JMP IsRemove ; Is local, say removable +CheckRemove: + TEST AX,1 + JNZ NotRemove +IsRemove: + CLC + RestoreReg + return +NotRemove: + STC + RestoreReg + return + + +; DiSKPRoMpt: +; +; This routine prompts for the insertion of the correct diskette +; into the Target drive, UNLESS we are being re-entrantly invoked +; from LastChanceToSaveIt. If the target is a Hardisk we issue a +; warning message. +; +; INPUTS: +; deviceParameters.DP_DeviceType +; fLastChance +; +; OUTPUTS: +; Prompt string +; fLastChance := FALSE +; +; Registers affected: +; Flags +; +DSKPRM: + CMP fLastChance,TRUE + JE PrmptRet + + CMP deviceParameters.DP_DeviceType, DEV_HARDDISK + jne goprnit + lea dx, ptr_msgHardDiskWarning + call std_printf + CALL Yes? + jnc OkToFormatHardDisk + mov ExitStatus, ExitNo + jmp ExitProgram + +OkToFormatHardDisk: + CALL CRLF + CALL CRLF + return + +GOPRNIT: + mov al, drive + call AccessDisk + lea dx,ptr_msgInsertDisk + CALL std_printf + CALL USER_STRING ;Wait for any key + CALL CRLF + CALL CRLF + +PrmptRet: + mov fLastChance, FALSE + return + +;------------------------------------------------------------------------------- +; ScanOff +; Scan Off separator characters + +SCANOFF: + LODSB + CMP AL,' ' + JZ SCANOFF + CMP AL,9 + JZ SCANOFF + DEC SI + return + +;------------------------------------------------------------------------------- +; MakeNum +; Makenum converts digits from ASCII AlphaNumeric format to +; numeric values +; +; Entry: +; AL == Character to be converted +; DS:SI == Command line text +; +; Exit: +; AX == Value +; IF AX == 0 THEN Zero Flag == SET +; IF ERROR THEN Carry Flag == SET +; BX,CX,DX == Garbage +; DS:SI == Character after numeric value +; +; Procs used: +; ToDigit + +Public MakeNum,CalcLoop +MakeNum: + xor BX,BX ; Initialize running cnt + mov CX,10 ; and base of arithmetic +CalcLoop: ; UNTIL no more digits + call ToDigit ; AL := AL - '0' + jc BadNum ; IF error EXIT with carry set + + xchg ax,bx ; AX := running_cnt * 10 + + mul cx ; digit + add ax,bx + jc BadNum ; IF Overflow EXIT with carry + + xchg ax,bx ; BX := Running total + + LODSB ; Get Next Digit + cmp al,' ' ; IF ( ax = (' ',',',)) + je RetVal ; THEN return parsed value + cmp al,',' + je RetVal + + cmp al,'/' ; IF (ax = ('/','cr')) + je BURetVal ; THEN backup DS:SI and + cmp al,0dh ; return parsed value + je BURetVal + or al,al + jnz CalcLoop ; END until + +BURetVal: + dec SI +RetVal: + mov ax,bx + or ax,ax + return + +public Badnum +BadNum: + xor ax,ax + stc + return + +; ToDigit: +; Convert value in AX to decimal digit, range checking for valid values +; +public ToDigit +ToDigit: + sub al,'0' + jb NotDigit + cmp al,9 + ja NotDigit + clc + return + +NotDigit: + stc + return + +;------------------------------------------------------------------------------- + +ControlC_Handler: + mov ax, seg data + mov ds, ax + lea dx, msgInterrupt + call PrintString + mov ExitStatus, ExitCtrlC + jmp ExitProgram + +;------------------------------------------------------------------------------- +; SaveNum +; Save Number from switches into appropriate variable for later use +; Some switches have upper and lower bounds for legal values and +; these are checked for here +; +; ENTRY: +; cx == Switch just parsed +; ax == value parsed +; +; EXIT: +; Value stored in appropriate variable +; DS,DX == garbage +; + +public SaveNum +SaveNum: + mov dx, seg data + mov ds, dx + test word ptr data:Switchmap, CX ; IF already set THEN ignore + jnz done_ret + + test CX,SWITCH_T + jnz Store_T + + test CX,SWITCH_N + jz BadNum + +Store_N: + cmp AX,0 ; IF (value == 0) THEN ignore + je done_ret + + cmp AX, MAX_SECTORS_IN_TRACK ; IF (value > Max_sectors) + jbe short Store_N1 ; THEN issue error + jmp INVALID + +Store_N1: + mov word ptr data:NumSectors , AX + + jmp short done_ret + +Store_T: + mov word ptr data:TrackCnt, AX + +Done_ret: + ret +;------------------------------------------------------------------------------- + +crlf: + lea dx, msgCRLF + +PrintString: + mov printStringPointer, dx + lea dx, PrintStringPointer + +std_printf: + push dx + call printf + return + +;------------------------------------------------------------------------------- + +;***************************************** +; Process V switch if set + +VOLID: + TEST [SWITCHMAP],SWITCH_V + JNZ DOVOL +VRET: CLC + return + +DOVOL: + PUSH CX + PUSH SI + PUSH DI + PUSH ES + PUSH DS + POP ES +VOL_LOOP: + MOV AL,DRIVE + INC AL + MOV DS:BYTE PTR[VOLFCB+7],AL + lea dx, msgLabelPrompt + call PrintString + CALL USER_STRING + call crlf + call crlf + MOV CL,[INBUFF+1] + OR CL,CL + JZ VOLRET + XOR CH,CH + MOV SI,OFFSET INBUFF+2 + MOV DI,SI + ADD DI,CX + MOV CX,11 + MOV AL,' ' + REP STOSB + MOV CX,5 + MOV DI,OFFSET VOLNAM + REP MOVSW + MOVSB + MOV DX,OFFSET VOLFCB + MOV AH,FCB_CREATE + INT 21H + OR AL,AL + JZ GOOD_CREATE + lea dx, msgBadCharacters + call PrintString + JMP VOL_LOOP +GOOD_CREATE: + MOV DX,OFFSET VOLFCB + MOV AH,FCB_CLOSE + INT 21H + CALL CRLF +VOLRET: + POP ES + POP DI + POP SI + POP CX + return + +;**************************************** +;Copy IO.SYS, MSDOS.SYS and COMMAND.COM into data area. +; Carry set if problems + +READDOS: +; CALL TESTSYSDISK ; dcl 8/23/86 + call Get_BIOS ; dcl 8/23/86 + JNC RDFILS + return + +RDFILS: + MOV BYTE PTR [FILSTAT],0 + MOV BX,[bios.fileHandle] + MOV AX,[MSTART] + MOV DX,AX + ADD DX,[MSIZE] ; CX first bad para + MOV [bios.fileStartSegment],AX + MOV CX,[bios.fileSizeInParagraphs] + ADD AX,CX + CMP AX,DX + JBE GOTBIOS + MOV BYTE PTR [FILSTAT],00000001B ; Got part of BIOS + MOV SI,[MSIZE] + XOR DI,DI + CALL DISIX4 + push ds + MOV DS,[bios.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JC CLSALL + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR [bios.fileOffset],AX + MOV WORD PTR [bios.fileOffset+2],DX +FILESDONE: + CLC +CLSALL: + PUSHF +; CALL COMCLS ; dcl 8/23/86 + call FILE_CLS ; dcl 8/23/86 + POPF + return + +GOTBIOS: + MOV BYTE PTR [FILSTAT],00000010B ; Got all of BIOS + push es + LES SI,[bios.fileSizeInBytes] + MOV DI,ES + pop es + push ds + MOV DS,[bios.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JC CLSALL + + push ax ; dcl 8/23/86 + push dx ; dcl 8/23/86 + call File_Cls ; dcl 8/23/86 + call Get_DOS ; dcl 8/23/86 + pop dx ; dcl 8/23/86 + pop ax ; dcl 8/23/86 + + JNC Found_MSDOS ;mt 12/8/86 P894 + return ;mt 12/8/86 + +Found_MSDOS: ;mt 12/8/86 + + MOV BX,[dos.fileHandle] + MOV [dos.fileStartSegment],AX + CMP AX,DX ; No room left? + JZ CLSALL ; Yes + MOV CX,[dos.fileSizeInParagraphs] + ADD AX,CX + CMP AX,DX + JBE GOTDOS + OR BYTE PTR [FILSTAT],00000100B ; Got part of DOS + SUB DX,[dos.fileStartSegment] + MOV SI,DX + XOR DI,DI + CALL DISIX4 + push ds + MOV DS,[dos.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JC CLSALL + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR [dos.fileOffset],AX + MOV WORD PTR [dos.fileOffset+2],DX + JMP FILESDONE + +GOTDOS: + OR BYTE PTR [FILSTAT],00001000B ; Got all of DOS + LES SI,[dos.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[dos.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + +CLSALLJ: JNC NOTCLSALL ;PTM P894 mt 12/8/86 + jmp clsall ; + +NotCLSALL: + push ax ; dcl 8/23/86 + + push dx ; dcl 8/23/86 + call File_cls ; dcl 8/23/86 + call Get_COMMAND ; dcl 8/23/86 + pop dx ; dcl 8/23/86 + pop ax ; dcl 8/23/86 + + JNC Found_COMMAND ;mt 12/8/86 P894 + return ;mt 12/8/86 + +Found_COMMAND: ;mt 12/8/86 + MOV BX,[command.fileHandle] + MOV [command.fileStartSegment],AX + CMP AX,DX ; No room left? + JZ CLSALLJ ; Yes + MOV CX,[command.fileSizeInParagraphs] + ADD AX,CX + CMP AX,DX + JBE GOTCOM + OR BYTE PTR [FILSTAT],00010000B ; Got part of COMMAND + SUB DX,[command.fileStartSegment] + MOV SI,DX + XOR DI,DI + CALL DISIX4 + push ds + MOV DS,[command.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JC CLSALLJ + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR [command.fileOffset],AX + MOV WORD PTR [command.fileOffset+2],DX + JMP FILESDONE + +GOTCOM: + OR BYTE PTR [FILSTAT],00100000B ; Got all of COMMAND + LES SI,[command.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[command.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JMP CLSALL + +;************************************************** +;Write BIOS DOS COMMAND to the newly formatted disk. + +ASSUME DS:DATA +WRITEDOS: + MOV CX,BiosAttributes + MOV DX,OFFSET BiosFile + LES SI,[bios.fileSizeInBytes] + MOV DI,ES + CALL MAKEFIL + retc + + MOV [TempHandle],BX + TEST BYTE PTR FILSTAT,00000010B + JNZ GOTALLBIO + call Get_BIOS ; dcl 8/23/86 + jnc Got_WBIOS ;mt 12/8/86 P894 + ret + +Got_WBIOS: + + LES SI,[bios.fileOffset] + MOV DI,ES + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + MOV BP,OFFSET bios + CALL GOTTARG + retc + JMP SHORT BIOSDONE + +GOTALLBIO: + LES SI,[bios.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[bios.fileStartSegment] + assume ds:nothing + CALL WRITEFILE + pop ds + assume ds:data +BIOSDONE: + MOV BX,[TempHandle] + MOV CX,bios.fileTime + MOV DX,bios.fileDate + CALL CLOSETARG + MOV CX,DosAttributes + MOV DX,OFFSET DosFile + LES SI,[dos.fileSizeInBytes] + MOV DI,ES + CALL MAKEFIL + retc + +GOTNDOS: + MOV [TempHandle],BX + TEST BYTE PTR FILSTAT,00001000B + JNZ GOTALLDOS + call Get_DOS ; dcl 8/23/86 + jnc Got_WDOS ;mt 12/8/86 P894 + ret + +Got_WDOS: + MOV BP,OFFSET dos + TEST BYTE PTR FILSTAT,00000100B + JNZ PARTDOS + MOV WORD PTR [dos.fileOffset],0 + MOV WORD PTR [dos.fileOffset+2],0 + CALL GETSYS3 + retc + JMP SHORT DOSDONE + +PARTDOS: + LES SI,[dos.fileOffset] + MOV DI,ES + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + CALL GOTTARG + retc + JMP SHORT DOSDONE + +GOTALLDOS: + LES SI,[dos.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[dos.fileStartSegment] + assume ds:nothing + CALL WRITEFILE + pop ds + assume ds:data +DOSDONE: + MOV BX,[TempHandle] + MOV CX,dos.fileTime + MOV DX,dos.fileDate + CALL CLOSETARG + MOV CX,CommandAttributes + MOV DX,OFFSET CommandFile + LES SI,[command.fileSizeInBytes] + MOV DI,ES + CALL MAKEFIL + retc + + MOV [TempHandle],BX + TEST BYTE PTR FILSTAT,00100000B + JNZ GOTALLCOM + call Get_COMMAND ; dcl 8/23/86 + jnc Got_WCOM ;mt 12/8/86 P894 + ret + +Got_WCOM: + MOV BP,OFFSET command + TEST BYTE PTR FILSTAT,00010000B + JNZ PARTCOM + MOV WORD PTR [command.fileOffset],0 + MOV WORD PTR [command.fileOffset+2],0 + CALL GETSYS3 + retc + JMP SHORT COMDONE + +PARTCOM: + LES SI,[command.fileOffset] + MOV DI,ES + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + CALL GOTTARG + retc + JMP SHORT COMDONE + +GOTALLCOM: + LES SI,[command.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[command.fileStartSegment] + assume ds:nothing + CALL WRITEFILE + pop ds + assume ds:data +COMDONE: + MOV BX,[TempHandle] + MOV CX,command.fileTime + MOV DX,command.fileDate + CALL CLOSETARG +;**************************************************************** +; I don't see the need for the following code!! - RS 3.20 +; CMP BYTE PTR [FILSTAT],00101010B +; JZ NOREDOS +;RDFRST2: +; CALL READDOS ; Start back with BIOS +; JNC NOREDOS +; CALL SYSPRM ;Prompt for system disk +; JMP RDFRST2 ;Try again +;NOREDOS: +;**************************************************************** + CLC + return + +;********************************************* +; Create a file on target disk +; CX = attributes, DX points to name +; DI:SI is size file is to have +; +; There is a bug in DOS 2.00 and 2.01 having to do with writes +; from the end of memory. In order to circumvent it this routine +; must create files with the length in DI:SI +; +; On return BX is handle, carry set if problem + +MAKEFIL: + MOV BX,DX + PUSH WORD PTR [BX] + MOV AL,DriveLetter + MOV [BX],AL + MOV AH,CREAT + INT 21H + POP WORD PTR [BX] + MOV BX,AX + JC CheckMany + MOV CX,DI + MOV DX,SI + MOV AX,LSEEK SHL 8 + INT 21H ; Seek to eventual EOF + XOR CX,CX + MOV AH,WRITE + INT 21H ; Set size of file to position + XOR CX,CX + MOV DX,CX + MOV AX,LSEEK SHL 8 + INT 21H ; Seek back to start + return + +; +; Examine error code in AX to see if it is too-many-open-files. +; If it is, we abort right here. Otherwise we return. +; +CheckMany: + CMP AX,error_too_many_open_files + retnz + lea dx, msgTooManyFilesOpen + call PrintString + JMP FEXIT + +;********************************************* +; Close a file on the target disk +; CX/DX is time/date, BX is handle + +CLOSETARG: + MOV AX,(FILE_TIMES SHL 8) OR 1 + INT 21H + MOV AH,CLOSE + INT 21H + return + +;**************************************** +; Transfer system files +; BP points to data structure for file involved +; offset is set to current amount read in +; Start set to start of file in buffer +; TempHandle is handle to write to on target + +IOLOOP: + MOV AL,[systemDriveLetter] + CMP AL,[DriveLetter] + JNZ GOTTARG + MOV AH,DISK_RESET + INT 21H + CALL TARGPRM ;Get target disk + +GOTTARG: +ASSUME DS:DATA +;Enter here if some of file is already in buffer, IOCNT must be set +; to size already in buffer. + MOV BX,[TempHandle] + MOV SI,WORD PTR [IOCNT] + MOV DI,WORD PTR [IOCNT+2] + push ds + MOV DS,ds:[BP.fileStartSegment] + assume ds:nothing + CALL WRITEFILE ; Write next part + pop ds + assume ds:data + retc + + LES AX,ds:[BP.fileOffset] + CMP AX,WORD PTR ds:[BP.fileSizeInBytes] + JNZ GETSYS3 + MOV AX,ES + CMP AX,WORD PTR ds:[BP.fileSizeInBytes+2] + JNZ GETSYS3 + return ; Carry clear from CMP + +GETSYS3: +;Enter here if none of file is in buffer + MOV AH,DISK_RESET + INT 21H + MOV AX,[MSTART] ;Furthur IO done starting here + MOV ds:[BP.fileStartSegment],AX + MOV AL,[systemDriveLetter] + CMP AL,[DriveLetter] + JNZ TESTSYS +GSYS: + MOV AH,DISK_RESET + INT 21H + CALL SYSPRM ;Prompt for system disk +TESTSYS: +; CALL TESTSYSDISK ; dcl 8/23/86 + JC GSYS + MOV BX,word ptr DS:[BP.fileHandle] ; CS over ARR 2.30 + LES DX,dword ptr DS:[BP.fileOffset] ; CS over ARR 2.30 + PUSH DX + MOV CX,ES + MOV AX,LSEEK SHL 8 + INT 21H + POP DX + LES SI,dword ptr DS:[BP.fileSizeInBytes] ; CS over ARR 2.30 + MOV DI,ES + SUB SI,DX + SBB DI,CX ; DI:SI is #bytes to go + PUSH DI + PUSH SI + ADD SI,15 + ADC DI,0 + CALL DISID4 + MOV AX,SI + POP SI + POP DI + CMP AX,[MSIZE] + JBE GOTSIZ2 + MOV SI,[MSIZE] + XOR DI,DI + CALL DISIX4 +GOTSIZ2: + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + push ds + MOV DS,[MSTART] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JNC GETOFFS + CALL CLSALL + JMP GSYS +GETOFFS: + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR DS:[BP.fileOffset],AX ; CS over ARR 2.30 + MOV WORD PTR DS:[BP.fileOffset+2],DX ; CS over ARR 2.30 + CALL CLSALL + JMP IOLOOP + +;************************************************* +; Test to see if correct system disk. Open handles + +CRET12: + STC + return + +;TESTSYSDISK: ; dcl 8/23/86 +Get_BIOS: ; dcl 8/23/86 + MOV AX,OPEN SHL 8 + MOV DX,OFFSET BiosFile + INT 21H + JNC SETBIOS +; call CheckMany ; dcl 8/23/86 + jmp CheckMany ; dcl 8/23/86 + +SETBIOS: + MOV [Bios.fileHandle],AX + MOV BX,AX + CALL GETFSIZ + CMP [bios.fileSizeInParagraphs],0 + JZ SETBIOSSIZ + CMP [bios.fileSizeInParagraphs],AX + JZ SETBIOSSIZ +BIOSCLS: + MOV AH,CLOSE + MOV BX,[Bios.fileHandle] + INT 21H +; JMP CRET12 ; dcl 8/23/86 + ret + +SETBIOSSIZ: + MOV [bios.fileSizeInParagraphs],AX + MOV WORD PTR [bios.fileSizeInBytes],SI + MOV WORD PTR [bios.fileSizeInBytes+2],DI + MOV [bios.fileDate],DX + MOV [bios.fileTime],CX + clc + ret ; dcl 8/23/86 + +Get_DOS: ; dcl 8/23/86 + MOV AX,OPEN SHL 8 + MOV DX,OFFSET DosFile + INT 21H + JNC DOSOPNOK +; call CheckMany ; dcl 8/23/86 +; JMP BIOSCLS ; dcl 8/23/86 Checkmany no ret. + jmp CheckMany ; dcl 8/23/86 + +DOSOPNOK: + MOV [dos.fileHandle],AX + MOV BX,AX + CALL GETFSIZ + CMP [dos.fileSizeInParagraphs],0 + JZ SETDOSSIZ + CMP [dos.fileSizeInParagraphs],AX + JZ SETDOSSIZ + +DOSCLS: + MOV AH,CLOSE + MOV BX,[dos.fileHandle] + INT 21H +; JMP BIOSCLS ; dcl 8/23/86 + ret ; dcl 8/23/86 + +SETDOSSIZ: + MOV [dos.fileSizeInParagraphs],AX + MOV WORD PTR [dos.fileSizeInBytes],SI + MOV WORD PTR [dos.fileSizeInBytes+2],DI + MOV [dos.fileDate],DX + MOV [dos.fileTime],CX + clc + ret ; dcl 8/23/86 + +Get_COMMAND: + MOV AX,OPEN SHL 8 + MOV DX,OFFSET CommandFile + INT 21H + JNC GotComHand +; call CheckMany ; dcl 8/23/86 +; JMP DosCls ; dcl 8/23/86 + jmp Checkmany ; dcl 8/23/86 + +GotComHand: + MOV [command.fileHandle],AX + MOV BX,AX + CALL GETFSIZ + CMP [command.fileSizeInParagraphs],0 + JZ SETCOMSIZ + CMP [command.fileSizeInParagraphs],AX + JZ SETCOMSIZ +COMCLS: + MOV AH,CLOSE + MOV BX,[command.fileHandle] + INT 21H +; JMP DOSCLS ; dcl 8/23/86 + ret ; dcl 8/23/86 + +SETCOMSIZ: + MOV [command.fileSizeInParagraphs],AX + MOV WORD PTR [command.fileSizeInBytes],SI + MOV WORD PTR [command.fileSizeInBytes+2],DI + MOV [command.fileDate],DX + MOV [command.fileTime],CX + CLC + return + +FILE_CLS: ; dcl 8/23/86 + MOV AH,CLOSE ; dcl 8/23/86 + INT 21H ; dcl 8/23/86 + ret ; dcl 8/23/86 + +;******************************************* +; Handle in BX, return file size in para in AX +; File size in bytes DI:SI, file date in DX, file +; time in CX. + +GETFSIZ: + MOV AX,(LSEEK SHL 8) OR 2 + XOR CX,CX + MOV DX,CX + INT 21H + MOV SI,AX + MOV DI,DX + ADD AX,15 ; Para round up + ADC DX,0 + AND DX,0FH ; If the file is larger than this it + ; is bigger than the 8086 address + ; space! + MOV CL,12 + SHL DX,CL + MOV CL,4 + SHR AX,CL + OR AX,DX + PUSH AX + MOV AX,LSEEK SHL 8 + XOR CX,CX + MOV DX,CX + INT 21H + MOV AX,FILE_TIMES SHL 8 + INT 21H + POP AX + return + +;******************************************** +; Read/Write file +; DS:0 is Xaddr +; DI:SI is byte count to I/O +; BX is handle +; Carry set if screw up +; +; I/O SI bytes +; I/O 64K - 1 bytes DI times +; I/O DI bytes + + +READFILE: +; Must preserve AX,DX + PUSH AX + PUSH DX + PUSH BP + MOV BP,READ SHL 8 + CALL FILIO + POP BP + POP DX + POP AX + return + +WRITEFILE: + PUSH BP + MOV BP,WRITE SHL 8 + CALL FILIO + POP BP + return + +FILIO: + XOR DX,DX + MOV CX,SI + JCXZ K64IO + MOV AX,BP + INT 21H + retc + ADD DX,AX + CMP AX,CX ; If not =, AX= 4086) +; +Phase1Initialisation proc near + +; Get device parameters + lea dx, deviceParameters + mov deviceParameters.DP_SpecialFunctions, 0 + call GetDeviceParameters + jnc GotDeviceParameters + lea dx, ptr_msgFormatNotSupported + call std_printf + jmp fexit +GotDeviceParameters: + +; Save the device parameters for when we exit + lea si, deviceParameters + lea di, savedDeviceParameters + mov cx, size a_DeviceParameters + push ds + pop es + rep movsb + +; Ensure that there is a valid number of sectors in the track table + mov savedDeviceParameters.DP_TrackTableEntries, 0 + mov validSavedDeviceParameters, 1 + +; Initialise this to zero to know if CheckSwitches defined the track layout + mov deviceParameters.DP_TrackTableEntries, 0 + +; Detect whether "set media type" is supported +; test DeviceParameters.DeviceAttributes, SetMediaType +; jnz SetMTsupp + +SetMTsupp: + +; Check switches against parameters and use switches to modify device parameters + call CheckSwitches + retc + + cmp deviceParameters.DP_TrackTableEntries, 0 + jne TrackLayoutSet ; There is a good track layout + +; Store sector table info + mov cx, deviceParameters.DP_BPB.BPB_SectorsPerTrack + mov deviceParameters.DP_TrackTableEntries, cx + mov ax, 1 + mov bx, deviceParameters.DP_BPB.BPB_bytesPerSector + lea di, deviceParameters.DP_SectorTable +LoadSectorTable: + stosw + xchg ax, bx + stosw + xchg ax, bx + inc ax + loop LoadSectorTable +TrackLayoutSet: + +; +; directorySector = malloc( Bytes Per Sector ) +; + mov bx, deviceParameters.DP_BPB.BPB_BytesPerSector + add bx, 0fH + shr bx, 1 + shr bx, 1 + shr bx, 1 + shr bx, 1 + mov ah, Alloc + int 21H + retc + mov word ptr directorySector+2, ax + xor ax,ax + mov word ptr directorySector, ax + +; +; fatSpace = malloc( Bytes Per Sector * Sectors Per FAT ) +; + mov ax, deviceParameters.DP_BPB.BPB_BytesPerSector + mul deviceParameters.DP_BPB.BPB_SectorsPerFAT + add ax, 0fH + shr ax, 1 + shr ax, 1 + shr ax, 1 + shr ax, 1 + mov bx, ax + mov ah, Alloc + int 21H + retc + mov word ptr fatSpace+2, ax + xor ax, ax + mov word ptr fatSpace, ax + + call SetStartSector + call SetfBigFat + + clc + return + +Phase1Initialisation endp + +;------------------------------------------------------------------------------- + +SetStartSector proc near + +; startSector = number of reserved sectors +; + number of FAT Sectors ( Number of FATS * Sectors Per FAT ) +; + number of directory sectors ( 32* Root Entries / bytes Per Sector ) +; ( above is rounded up ) + +; Calculate the number of directory sectors + mov ax, deviceParameters.DP_BPB.BPB_RootEntries + mov bx, size dir_entry + mul bx + add ax, deviceParameters.DP_BPB.BPB_bytesPerSector + dec ax + xor dx,dx + div deviceParameters.DP_BPB.BPB_bytesPerSector + mov sectorsInRootDirectory,ax + mov startSector, ax + +; Calculate the number of FAT sectors + mov ax, deviceParameters.DP_BPB.BPB_SectorsPerFAT + mul deviceParameters.DP_BPB.BPB_numberOfFATs +; Add in the number of boot sectors + add ax, deviceParameters.DP_BPB.BPB_ReservedSectors + add startSector, ax + + return + +SetStartSector endp + +;------------------------------------------------------------------------------- + +SetfBigFat proc near +; +; fBigFat = ( ( (Total Sectors - Start Sector) / Sectors Per Cluster) >= 4086 ) +; + mov ax, deviceParameters.DP_BPB.BPB_TotalSectors + + +;************************* Fix for PTM PCDOS P51 + + ; + ; Old code + ; + ;cmp ax,20740 + ;jbe SmallFAT + ;mov fBigFat, TRUE + + ; + ; New Code + ; + + sub ax,startSector ;Get sectors in data area + xor dx,dx + xor bx,bx + mov bl,deviceParameters.DP_BPB.BPB_sectorsPerCluster + div bx ;Get total clusters + cmp ax,BIG_FAT_THRESHOLD ;Is clusters < 4086? + jb SmallFAT ;12 bit FAT if so + mov fBigFAT,TRUE ;16 bit FAT if >=4096 + +;************************* END of fix for PTM PCDOS P51 + +SmallFAT: + + return + +SetfBigFat endp + +;------------------------------------------------------------------------------- +; +; Phase2Initialisation: +; Use device parameters to build information that will be +; required for each format +; +; Algorithm: +; Calculate first head/cylinder to format +; Calculate number of tracks to format +; Calculate the total bytes on the disk and save for later printout +; First initialise the directory buffer +; +Phase2Initialisation proc near + +; Calculate first track/head to format (round up - kludge) + mov ax, deviceParameters.DP_BPB.BPB_HiddenSectors + mov dx, deviceParameters.DP_BPB.BPB_HiddenSectors + 2 + add ax, deviceParameters.DP_BPB.BPB_SectorsPerTrack + adc dx, 0 + dec ax + sbb dx, 0 + div deviceParameters.DP_BPB.BPB_SectorsPerTrack + xor dx,dx + div deviceParameters.DP_BPB.BPB_Heads + mov firstCylinder, ax + mov firstHead, dx + +; Calculate the total number of tracks to be formatted (round down - kludge) + mov ax, deviceParameters.DP_BPB.BPB_TotalSectors + xor dx,dx +; if (TotalSectors == 0) then use BigTotalSectors + or ax,ax + jnz NotBigTotalSectors + mov ax, deviceParameters.DP_BPB.BPB_BigTotalSectors + mov dx, deviceParameters.DP_BPB.BPB_BigTotalSectors + 2 + +NotBigTotalSectors: + div deviceParameters.DP_BPB.BPB_SectorsPerTrack + mov tracksPerDisk, ax + +; Initialise the directory buffer +; Clear out the Directory Sector before any information is inserted. + mov cx, deviceParameters.DP_BPB.BPB_BytesPerSector + les di, directorySector + xor ax,ax + rep stosb + + mov ax, deviceParameters.DP_BPB.BPB_BytesPerSector + xor dx, dx + mov bx, size dir_entry + div bx + mov cx, ax + + les bx, directorySector +; If Old_Dir = TRUE then put the first letter of each directory entry must be 0E5H + xor al, al + cmp old_Dir, TRUE + jne StickE5 + mov al, 0e5H +StickE5: + mov es:[bx], al + add bx, size dir_entry + loop stickE5 + +; +; fDskSiz = (Total Sectors - Start Sector) * Bytes Per Sector +; + mov ax, deviceParameters.DP_BPB.BPB_TotalSectors + sub ax, startSector + mul deviceParameters.DP_BPB.BPB_BytesPerSector + mov word ptr fDskSiz, ax + mov word ptr fDskSiz+2, dx + + return + +Phase2Initialisation endp + +;------------------------------------------------------------------------------- +; +; SetDeviceParameters: +; Set the device parameters +; +; Input: +; drive +; dx - pointer to device parameters +; +SetDeviceParameters proc near + + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + mov bl, drive + inc bl + mov cx, (RAWIO shl 8) or SET_DEVICE_PARAMETERS + int 21H + return + +SetDeviceParameters endp + +;------------------------------------------------------------------------------- +; +; GetDeviceParameters: +; Get the device parameters +; +; Input: +; drive +; dx - pointer to device parameters +; +GetDeviceParameters proc near + + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + mov bl, drive + inc bl + mov cx, (RAWIO shl 8) or GET_DEVICE_PARAMETERS + int 21H + return + +GetDeviceParameters endp + +;------------------------------------------------------------------------------- +; +; DiskFormat: +; Format the tracks on the disk +; Since we do our SetDeviceParameters here, we also need to +; detect the legality of /N /T if present and abort with errors +; if not. +; This routine stops as soon as it encounters a bad track +; Then BadSector is called to report the bad track, and it continues +; the format +; +; Algorithm: +; Initialise in memory FAT +; current track = first +; while not done +; if format track fails +; DiskFormatErrors = true +; return +; next track + +DiskFormat proc near + + +; +; Initialise fatSpace +; + push es + les di, fatSpace + mov ax, deviceParameters.DP_BPB.BPB_SectorsPerFAT + mul deviceParameters.DP_BPB.BPB_bytesPerSector + mov cx, ax + xor ax,ax + rep stosb + + mov di, word ptr fatSpace + mov al, deviceParameters.DP_BPB.BPB_MediaDescriptor + mov ah, 0ffH + stosw + mov ax, 00ffH + test fBigFat, TRUE + jz NotBig + mov ax, 0ffffH +NotBig: stosw + pop es + +; don't bother to do the formatting if /c was given + test switchmap, SWITCH_C + jz Keep_Going + jmp FormatDone ;FormatDone is to far away + +Keep_Going: +foofoo = INSTALL_FAKE_BPB or TRACKLAYOUT_IS_GOOD + mov deviceParameters.DP_SpecialFunctions, foofoo + lea dx, deviceParameters + + call SetDeviceParameters + + test switchmap, SWITCH_H ;Suppress prompt? + jnz No_Prompt + + call DSKPRM ; prompt user for disk + +No_Prompt: + test switchmap,switch_8 ; DCL 5/12/86 avoid Naples AH=18h + jnz stdBpB ; lackof support for 8 sectors/track + + ; DCL 5/12/86 + ; Always do the STATUS_FOR_FORMAT test, as we don't know if the machine + ; has this support. For 3.2 /N: & /T: were not documented & therefore + ; not fully supported thru the ROM of Aquarius & Naples & Royal Palm + + ;test SwitchMap, SWITCH_N or SWITCH_T ; IF ( /N or /T ) ;; DCL 5/12/86 + ;jz StdBPB + ; THEN check if + ; supported + mov formatPacket.FP_SpecialFunctions, STATUS_FOR_FORMAT + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + mov bl, drive + inc bl + mov cx, (RAWIO shl 8) or FORMAT_TRACK + lea dx, formatPacket + int 21H + ; switch ( FormatStatusCall) + + ;cmp FormatPacket.FP_SpecialFunctions, Format_No_ROM_Support + ;jb NTSupported ; 0 returned from IO.SYS + ;ja IllegalComb ; 2 returned - ROM Support + ; Illegal Combination! + cmp FormatPacket.FP_SpecialFunctions,0 + je NTSupported + lea dx, msgInvalidParameter + cmp FormatPacket.FP_SpecialFunctions,2 + je Abort_Prog + lea dx, msgNotReady + cmp FormatPacket.FP_SpecialFunctions,3 + je Abort_Prog + + ; DCL No ROM support is okay + ; except for /N: & /T: + test SwitchMap, SWITCH_N or SWITCH_T ; DCL 5/12/86 + jz StdBPB + lea dx, msgParametersNotSupported ; CASE: NOT SUPPORTED + +Abort_Prog: + Call PrintString + jmp Fexit +; +; We have the support to carry out the FORMAT +; +NTSupported: +StdBPB: + ;call DSKPRM ; prompt user for disk ;; DCL 5/12/86 + mov FormatPacket.FP_SpecialFunctions, 0 + mov ax, firstHead + mov formatPacket.FP_Head, ax + mov ax, firstCylinder + mov formatPacket.FP_Cylinder, ax + mov cx, tracksPerDisk + dec cx + mov tracksLeft, cx +FormatLoop: + call DisplayCurrentTrack + call FormatTrack + jc FailDiskFormat + call NextTrack + jnc FormatLoop + +; All done +FormatDone: + mov formatError, 0 + clc + return + +FailDiskFormat: + call CheckError + retc + call LastChanceToSaveIt + jc FormatReallyFailed + + call SetStartSector + call SetfBigFat + push ax + call Phase2Initialisation + clc + pop ax +; jc FormatReallyFailed + jmp DiskFormat + +FormatReallyFailed: + mov formatError, 1 + clc + return + +DiskFormat endp + + +;------------------------------------------------------------------------------- +; +; BadSector: +; Reports the bad sectors. +; Reports the track where DiskFormat stopped. +; From then on it formats until it reaches a bad track, or end, +; and reports that. +; +; Output: +; Carry: set --> fatal error +; if Carry not set +; ax - The number of consecutive bad sectors encountered +; ax == 0 --> no more bad sectors +; bx - The logical sector number of the first bad sector +; +; Algorithm: +; if DiskFormatErrors +; DiskFormatErrors = false +; return current track +; else +; next track +; while not done +; if format track fails +; return current track +; next track +; return 0 + +BadSector proc near + + +; don't bother to do the formatting if /c was given + test switchmap, SWITCH_C + jnz NoMoreTracks + + test formatError, 0ffH + jz ContinueFormat + mov formatError, 0 + jmp ReportBadTrack + +ContinueFormat: + call NextTrack + jc NoMoreTracks + + call DisplayCurrentTrack + call FormatTrack + jnc ContinueFormat + call CheckError + retc + +ReportBadTrack: + call CurrentLogicalSector + mov ax, deviceParameters.DP_BPB.BPB_SectorsPerTrack + clc + return + +NoMoreTracks: + lea dx, msgFormatComplete + call PrintString + mov ax, 0 + clc + return + +BadSector endp + + +;------------------------------------------------------------------------------- +; FormatTrack: +; format the current track +; +; Input: +; formatPacket +; +; Output: +; Carry: set if format failed +; +FormatTrack proc near + + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + mov bl, drive + inc bl + mov cx, (RAWIO shl 8) or FORMAT_TRACK + lea dx, formatPacket + int 21H + retnc + + mov ah, 59H + xor bx,bx + int 21H + stc + return + +FormatTrack endp + +;------------------------------------------------------------------------------- + +data segment + +ptr_msgCurrentTrack dw offset msgCurrentTrack +currentHead dw 0 +currentCylinder dw 0 + +data ends + +DisplayCurrentTrack proc near + + mov ax, formatPacket.FP_Cylinder + mov currentCylinder, ax + mov ax, formatPacket.FP_Head + mov currentHead, ax + lea dx, ptr_msgCurrentTrack + call std_printf + return + +DisplayCurrentTrack endp + +;------------------------------------------------------------------------------- +; NextTrack: +; Advance to the next track for formatting +; +; Input: +; formatPacket.FP_Head +; formatPacket.FP_Cylinder +; deviceParameters.DP_BPB.BPB_Heads +; tracksLeft +; +; Output: +; Carry: set --> all done +; formatPacket.FP_Head +; formatPacket.FP_cyliner +; tracksLeft +; +; Algorithm: +; if tracksLeft +; tracksLeft-- +; if ++head > highest head +; head = 0 +; cylinder++ +; +NextTrack proc near + + cmp tracksLeft, 0 + je ThatsAllFolks + dec tracksLeft + +; Bump the head + inc formatPacket.FP_Head + mov ax, formatPacket.FP_Head + cmp ax, deviceParameters.DP_BPB.BPB_Heads + jb ExitNextTrack + +; We've done all heads on this cylinder so move on to next +; (start on head 0 of the next cylinder) + mov formatPacket.FP_Head, 0 + inc formatPacket.FP_Cylinder + +ExitNextTrack: + clc + return + +ThatsAllFolks: +; Oh wow, we're all done + stc + return + +NextTrack endp + +;------------------------------------------------------------------------------- +; CheckError: +; Input: +; ax - extended error code +; Ouput: +; carry set if error is fatal +; Message printed if Not Ready or Write Protect +; +CheckError proc near + cmp ax, error_write_protect + je WriteProtectError + cmp ax, error_not_ready + je NotReadyError + cmp currentCylinder, 0 + jne CheckRealErrors + cmp currentHead, 0 + je BadTrackZero + +CheckRealErrors: + cmp ax, error_CRC + je JustABadTrack + cmp ax, error_sector_not_found + je JustABadTrack + cmp ax, error_write_fault + je JustABadTrack + cmp ax, error_read_fault + je JustABadTrack + cmp ax, error_gen_failure + je JustABadTrack + + stc + ret + +JustABadTrack: + clc + ret + +WriteProtectError: + lea dx, msgWriteProtected + call PrintString + stc + ret + +NotReadyError: + lea dx, msgNotReady + call PrintString + stc + ret + +BadTrackZero: + lea dx, msgDiskUnusable + call PrintString + stc + ret + +CheckError endp + +;------------------------------------------------------------------------------- +; WriteFileSystem: +; Write the boot sector and FATs out to disk +; Clear the directory sectors to zero +; +WriteFileSystem proc near + + + call WriteBootSector + retc + +; Write out each of the FATs + xor cx, cx + mov cl, deviceParameters.DP_BPB.BPB_numberOfFATs + mov dx, deviceParameters.DP_BPB.BPB_ReservedSectors +WriteFATloop: + push cx + push dx + mov al, drive + mov cx, deviceParameters.DP_BPB.BPB_SectorsPerFAT + push ds + lds bx, fatSpace + int 26H + pop ax + pop ds + jc CanNotWriteFAT + + pop dx + add dx, deviceParameters.DP_BPB.BPB_SectorsPerFAT + pop cx + loop WriteFATLoop + +; Clear the directory + +; Now write the initialised directory sectors out to disk + mov ax, deviceParameters.DP_BPB.BPB_SectorsPerFAT + xor dx,dx + mul deviceParameters.DP_BPB.BPB_NumberOfFATs + mov dx, deviceParameters.DP_BPB.BPB_ReservedSectors + add dx, ax + mov cx, sectorsInRootDirectory +WriteDIRloop: + push cx + push dx + mov al, drive + mov cx, 1 + push ds + lds bx, directorySector + int 26H + pop ax + pop ds + jc CanNotWriteDirectory + + pop dx + add dx, 1 + pop cx + loop WriteDIRLoop + + +; Ok, we can tell the device driver that we are finished formatting + mov savedDeviceParameters.DP_TrackTableEntries, 0 + mov savedDeviceParameters.DP_SpecialFunctions, TRACKLAYOUT_IS_GOOD + lea dx, savedDeviceParameters + call SetDeviceParameters + + MOV AH,DISK_RESET ; Flush any directories in + INT 21H ; buffers + + return + +CanNotWriteFAT: + lea dx, msgFATwriteError + jmp PrintErrorAbort + +CanNotWriteDirectory: + lea dx, msgDirectorywriteError + jmp PrintErrorAbort + +WriteFileSystem endp + +;------------------------------------------------------------------------------- +; Done: +; format is done... so clean up the disk! +; +Done proc near + + + call OemDone + return + +Done endp + +;------------------------------------------------------------------------------- +; CurrentLogicalSector: +; Get the current logical sector number +; +; Input: +; current track = tracksPerDisk - tracksLeft +; SectorsPerTrack +; +; Output: +; BX = logical sector number of the first sector in the track we +; just tried to format +; +CurrentLogicalSector proc near + mov ax, tracksPerDisk + sub ax, tracksLeft + dec ax + mul deviceParameters.DP_BPB.BPB_SectorsPerTrack + mov bx, ax + return + +CurrentLogicalSector endp + +;------------------------------------------------------------------------------- +; PrintErrorAbort: +; Print an error message and abort +; +; Input: +; dx - Pointer to error message string +; +PrintErrorAbort proc near + + push dx + call crlf + pop dx + call PrintString + + jmp fexit + +PrintErrorAbort endp + +code ends + + END START diff --git a/SRC/BUGFIX/CMD/FORMAT/MESSAGES.ASM b/SRC/BUGFIX/CMD/FORMAT/MESSAGES.ASM new file mode 100644 index 0000000..b8b9f0d --- /dev/null +++ b/SRC/BUGFIX/CMD/FORMAT/MESSAGES.ASM @@ -0,0 +1,68 @@ +; SCCSID = @(#)messages.asm 1.10 85/08/13 +TITLE FORMAT Messages + +data segment public 'DATA' + + public Yes_Byte + public No_Byte + public msgCRLF + public msgCurrentTrack + public msgSystemTransfered + public msgFormatComplete + public msgInterrupt + public msgInsertDisk + public msgHardDiskWarning + public msgFormatAnother? + public msgInsertDosDisk + public msgReInsertDisk + public msgLabelPrompt + public msgTotalDiskSpace + public msgSystemSpace + public msgBadSpace + public msgDataSpace + public msgFormatNotSupported + public msgInvalidDeviceParameters + public msgErrorInIOCTL + public msgNotBlockDevice + public msgFATwriteError + public msgDirectoryWriteError + public msgAssignedDrive + public msgNeedDrive + public msgBadDosVersion + public msgNoSystemFiles + public msgTooManyFilesOpen + public msgNetDrive + public msgBadCharacters + public msgBadDrive + public msgInvalidParameter + public msgParametersNotSupported + public msgFormatFailure + public msgNotSystemDisk +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +; reintroduce following public for fix + public msgNoRoomDestDisk +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + public msgDiskUnusable + public msgOutOfMemory + public msgWriteProtected + public msgNotReady + public msgBootWriteError + public msgDirectoryReadError + public msgBadVolumeId + public msgWhatIsVolumeId? + public msgIncompatibleParameters + public msgIncompatibleParametersForHardDisk + public msgBadPartitionTable + public msgParametersNotSupportedByDrive + public msgPartitionTableReadError + public msgPartitionTableWriteError + +CR equ 13 +LF equ 10 + +; Oem dependent messages + + include messages.inc + +data ends + END diff --git a/SRC/BUGFIX/CMD/FORMAT/MESSAGES.INC b/SRC/BUGFIX/CMD/FORMAT/MESSAGES.INC new file mode 100644 index 0000000..bf22638 --- /dev/null +++ b/SRC/BUGFIX/CMD/FORMAT/MESSAGES.INC @@ -0,0 +1,139 @@ +; SCCSID = @(#)messages.inc 1.6 85/08/02 + +DEBUG EQU 0 ; for Boot sector installation check + +IF DEBUG + public msgFormatBroken +ENDIF + +; THE FOLLOWING ONE BYTE CHARACTERS ARE THE PROMPT ANSWERS. +; THEY MUST BE LOWER CASE, AND THE UPPER TO LOWER, OR LOWER +; TO LOWER CONVERSION MUST BE DOABLE BY "OR AL,20h". +; Yes/No Answers + +Yes_Byte db "y" +No_Byte db "n" + +msgCRLF db CR, LF, 0 + +; Status messages + +msgCurrentTrack db "Head: %3d Cylinder: %4d", CR, 0 + +msgSystemTransfered db "System transferred",CR,LF,0 + +msgInterrupt db 13,10, 10, 0 + +; Note: This message must be long enough to wipe out message msgCurrentTrack +msgFormatComplete db "Format complete ",CR,LF,0 + +; Prompts + +msgInsertDisk db "Insert new diskette for drive %c:",CR,LF + db "and strike ENTER when ready",0 + +msgHardDiskWarning db CR,LF + db "WARNING, ALL DATA ON NON-REMOVABLE DISK",CR,LF + db "DRIVE %c: WILL BE LOST!",CR,LF + db "Proceed with Format (Y/N)?",0 + +msgFormatAnother? db "Format another (Y/N)?",0 + +msgInsertDosDisk db "Insert DOS disk in drive %c:", CR, LF + db "and strike ENTER when ready", CR, LF, 0 + +msgReInsertDisk db "Re-insert diskette for drive %c:",0 + +msgLabelPrompt db "Volume label (11 characters, ENTER for none)? ",0 + +; Disk usage messages + +msgTotalDiskSpace db "%l10d bytes total disk space", CR, LF, 0 + +msgSystemSpace db "%l10d bytes used by system", CR, LF, 0 + +msgBadSpace db "%l10d bytes in bad sectors", CR, LF, 0 + +msgDataSpace db "%l10d bytes available on disk",CR,LF,0 + +; Error messages + +msgFormatNotSupported db "Format not supported on drive %c:", CR,LF,0 + +msgInvalidDeviceParameters db "Invalid device parameters from device driver" + db CR, LF, 0 + +msgErrorInIOCTL db "Error in IOCTL call", CR, LF, 0 + +msgNotBlockDevice db "Not a block device", CR, LF, 0 + +msgFATwriteError db "Error writing FAT", CR, LF, 0 + +msgDirectoryWriteError db "Error writing directory", CR, LF, 0 + +msgAssignedDrive db "Cannot format an ASSIGNed or SUBSTed drive. ", CR, LF, 0 + +msgNeedDrive db "Drive letter must be specified",CR,LF,0 + +msgBadDosVersion db "Incorrect DOS version",CR,LF,"$" + +msgNoSystemFiles db "Cannot find System Files",CR,LF,0 + +msgTooManyFilesOpen db "Too many open files",CR,LF,0 + +msgNetDrive db "Cannot FORMAT a Network drive", CR, LF, 0 + +msgBadCharacters db "Invalid characters in volume label", CR, LF, 0 + +msgBadDrive db "Invalid drive specification", CR, LF, 0 + +msgInvalidParameter db "Invalid parameter", CR, LF, 0 + +msgParametersNotSupported db "Parameters not supported",CR,LF,0 + +; Note: This message must be long enough to wipe out message msgCurrentTrack +msgFormatFailure db "Format failure ",CR,LF,0 + +msgNotSystemDisk db "Disk unsuitable for system disk", CR, LF, 0 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +; reintroduce following message for fix +msgNoRoomDestDisk db "No room for system on destination disk", CR, LF, 0 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + +msgDiskUnusable db "Invalid media or Track 0 bad - disk unusable", CR, LF, 0 + +msgOutOfMemory db "Insufficient memory for system transfer", CR, LF, 0 + +; Note: This message must be long enough to wipe out message msgCurrentTrack +msgWriteProtected db "Attempted write-protect violation", CR, LF, 0 + +; Note: This message must be long enough to wipe out message msgCurrentTrack +msgNotReady db "Drive not ready ", CR, LF, 0 + + +msgBootWriteError db "Unable to write BOOT", CR, LF, 0 + +msgDirectoryReadError db "Error reading directory", CR, LF, 0 + +msgBadVolumeId db "Invalid Volume ID", CR, LF, 0 + +msgWhatIsVolumeId? db "Enter current Volume Label for drive %c: ", 0 + +msgIncompatibleParameters db "Parameters not compatible", CR,LF,0 + +msgIncompatibleParametersForHardDisk db "Parameters not compatible" + db " with fixed disk", CR,LF,0 + +msgBadPartitionTable db "Bad Partition Table", CR, LF, 0 + +msgParametersNotSupportedByDrive db "Parameters not Supported by Drive", CR, LF, 0 + +msgPartitionTableReadError db "Error reading partition table", CR, LF, 0 + +msgPartitionTableWriteError db "Error writing partition table", CR, LF, 0 + +IF DEBUG +msgFormatBroken db "Format Broken", CR, LF, 0 +ENDIF + diff --git a/SRC/BUGFIX/DOS/HANDLE.OBJ b/SRC/BUGFIX/DOS/HANDLE.OBJ new file mode 100644 index 0000000..4ce0606 Binary files /dev/null and b/SRC/BUGFIX/DOS/HANDLE.OBJ differ diff --git a/SRC/CMD/FORMAT/BOOTMES.INC b/SRC/CMD/FORMAT/BOOTMES.INC new file mode 100644 index 0000000..57d0a0f --- /dev/null +++ b/SRC/CMD/FORMAT/BOOTMES.INC @@ -0,0 +1,9 @@ +; SCCSID = @(#)bootmes.inc 1.1 85/04/18 + +; Message Include file for OEMFOR.ASM + +; THIS IS A SPECIAL MESSAGE WHICH IS INCLUDED IN THE "FAKE" IO.SYS +; FILE PLACED ON DISKS FORMATTED /B. NOTE THAT IT IS NUL TERMINATED. + +NO_SYS_MESS: + DB "Non-System disk or disk error",13,10,0 diff --git a/SRC/CMD/FORMAT/FILESIZE.INC b/SRC/CMD/FORMAT/FILESIZE.INC new file mode 100644 index 0000000..b62fb49 --- /dev/null +++ b/SRC/CMD/FORMAT/FILESIZE.INC @@ -0,0 +1,6 @@ + + %out ..filesize.inc + +BIOS_SIZE equ 22528 ; actually 22341 +DOS_SIZE equ 30208 ; actually 30128 + \ No newline at end of file diff --git a/SRC/CMD/FORMAT/FORMAT.ASM b/SRC/CMD/FORMAT/FORMAT.ASM new file mode 100644 index 0000000..3812a49 --- /dev/null +++ b/SRC/CMD/FORMAT/FORMAT.ASM @@ -0,0 +1,3032 @@ +page 84,132 +; SCCSID = @(#)format.asm 1.26 85/10/20 +; SCCSID = @(#)format.asm 1.26 85/10/20 +;*************************************************************** +; +; 86-DOS FORMAT DISK UTILITY +; +; This routine formats a new disk,clears the FAT and DIRECTORY then +; optionally copies the SYSTEM and COMMAND.COM to this new disk +; +; SYNTAX: FORMAT [drive][/switch1][/switch2]...[/switch16] +; +; Regardless of the drive designator , the user will be prompted to +; insert the diskette to be formatted. +; +;*************************************************************** + +; 5/12/82 ARR Mod to ask for volume ID +; 5/19/82 ARR Fixed rounding bug in CLUSCAL: +; REV 1.5 +; Added rev number message +; Added dir attribute to DELALL FCB +; REV 2.00 +; Redone for 2.0 +; REV 2.10 +; 5/1/83 ARR Re-do to transfer system on small memory systems +; REV 2.20 +; 6/17/83 system size re-initialization bug -- mjb001 +; Rev 2.25 +; 8/31/83 16-bit fat insertion +; Rev 2.26 +; 11/2/83 MZ fix signed compare problems for bad sectors +; Rev 2.27 +; 11/8/83 EE current directories are always saved and restored +; Rev 2.28 +; 11/9/83 NP Printf and changed to an .EXE file +; Rev 2.29 +; 11/11/83 ARR Fixed ASSIGN detection to use NameTrans call to see +; if drive letter remapped. No longer IBM only +; Rev 2.30 +; 11/13/83 ARR SS does NOT = CS, so all use of BP needs CS override +; Rev 2.31 +; 12/27/83 ARR REP STOSB instruction at Clean: changed to be +; sure ES = CS. + +code segment public 'CODE' +code ends + +printf_code segment public + extrn printf:far +printf_code ends + +stack segment stack + db (362 - 80h) + 100H dup (?) ; (362-80h) is the additional IBM ROM + ; overhead recently discovered by them. +stack ends + +data segment public 'DATA' +data ends + +public end_of_memory +_end segment public para 'DATA' +end_of_memory label byte +_end ends + +code segment + + assume cs:code,ds:nothing,es:nothing,ss:stack + +;------------------------------------------------------------------------------- +; Define as public for debugging + +; procedures + public GetSize + public AddToSystemSize + public Phase1Initialisation + public SetStartSector + public SetfBigFat + public Phase2Initialisation + public DiskFormat + public BadSector + public FormatTrack + public DisplayCurrentTrack + public NextTrack + public WriteFileSystem + public Done + public CurrentLogicalSector + public PrintErrorAbort + public GetDeviceParameters + public SetDeviceParameters + + public START + public GOTBADDOS + public OKDOS + public BogusDrive + public DRVGD + public DRVSPEC + public NXTSWT + public GETPARM + public GETCHR + public INVALID + public SCANOFF + public MEMERR + public SAVSWT + public NotNet + public RE_ASSIGN + public NO_ASSIGN + public FatAllocated + public MEMERRJ + public MEM_OK + public RDFRST + public NEEDSYS + public INITCALL + public SWITCHCHK + public SYSLOOP + public FRMTPROB + public GETTRK + public TRKFND + public CLRTEST + public CMPTRKS + public PACKIT + public BadClus + public DoBig + public DoSet + public DRTFAT + public CLEARED + public LOUSE + public LOUSEP + public FATWRT + public SYSOK + public STATUS + public REPORTC + public ONCLUS + public MORE + public FEXIT + public SYSPRM + public fexitJ + public DoPrompt + public TARGPRM + public IsRemovable + public CheckRemove + public IsRemove + public NotRemove + public DSKPRM + public GOPRNIT + public crlf + public PrintString + public std_printf + public VOLID + public VRET + public DOVOL + public VOL_LOOP + public GOOD_CREATE + public VOLRET + public READDOS + public RDFILS + public FILESDONE + public CLSALL + public GOTBIOS + public GOTDOS + public CLSALLJ + public GOTCOM + public WRITEDOS + public GOTALLBIO + public BIOSDONE + public GOTNDOS + public PARTDOS + public GOTALLDOS + public DOSDONE + public PARTCOM + public GOTALLCOM + public COMDONE + public MAKEFIL + public CheckMany + public CLOSETARG + public IOLOOP + public GOTTARG + public GSYS + public TESTSYS + public GETOFFS +; public TESTSYSDISK ; dcl 8/23/86 + public SETBIOS + public BIOSCLS + public SETBIOSSIZ + public DOSOPNOK + public DOSCLS + public SETDOSSIZ + public GotComHand + public COMCLS + public SETCOMSIZ + public GETFSIZ + public READFILE + public WRITEFILE + public FILIO + public NORMIO + public IORETP + public IORET + public NORMALIZE + public GotDeviceParameters + public SmallFAT + public LoadSectorTable + public NotBigTotalSectors + public NotBig + public FormatLoop + public FormatDone + public FailDiskFormat + public FormatReallyFailed + public ContinueFormat + public ReportBadTrack + public NoMoreTracks + public ExitNextTrack + public ThatsAllFolks + public WriteFATloop + public WriteDIRloop + public CanNotWriteFAT + public CanNotWriteDirectory + public ControlC_Handler + +; bytes + public fBigFat + public formatError + public ROOTSTR + public DBLFLG + public DRIVE + public FILSTAT + public USERDIRS + public VOLFCB + public VOLNAM + public TRANSRC + public TRANDST + public INBUFF + public driveLetter + public systemDriveLetter +; words + public startSector + public fatSpace + public firstHead + public firstCylinder + public tracksLeft + public tracksPerDisk + public sectorsInRootDirectory + public directorySector + public printStringPointer + public MSTART + public MSIZE + public TempHandle + public BEGSEG + public SWITCHMAP + public SWITCHCOPY + public FAT + public CLUSSIZ + public SECSIZ + public SYSTRKS + public SECTORS + public ptr_msgHardDiskWarning + public ptr_msgInsertDisk + public ptr_msgReInsertDisk + public ptr_msgInsertDosDisk + public ptr_msgCurrentTrack + public currentHead + public currentCylinder + +; other + public deviceParameters + public formatPacket +;------------------------------------------------------------------------------- + +data segment + extrn msgAssignedDrive:byte + extrn msgBadDosVersion:byte + extrn msgDirectoryWriteError:byte + extrn msgFormatComplete:byte + extrn msgFormatNotSupported:byte + extrn msgFATwriteError:byte + extrn msgInvalidDeviceParameters:byte + extrn msgLabelPrompt:byte + extrn msgNeedDrive:byte + extrn msgNoSystemFiles:byte + extrn msgTooManyFilesOpen:byte + extrn msgNetDrive:byte + extrn msgInsertDisk:byte + extrn msgHardDiskWarning:byte + extrn msgSystemTransfered:byte + extrn msgFormatAnother?:byte + extrn msgBadCharacters:byte + extrn msgBadDrive:byte + extrn msgInvalidParameter:byte + extrn msgParametersNotSupported:byte + extrn msgReInsertDisk:byte + extrn msgInsertDosDisk:byte + extrn msgFormatFailure:byte + extrn msgNotSystemDisk:byte +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +; reintroduce following extrn +; extrn msgNoRoomDestDisk:byte +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + extrn msgDiskUnusable:byte + extrn msgOutOfMemory:byte + extrn msgCurrentTrack:byte + extrn msgWriteProtected:byte + extrn msgNotReady:byte + extrn msgInterrupt:byte + extrn msgCRLF:byte + +data ends + + +debug equ 0 + .xlist + INCLUDE VERSIONA.INC + INCLUDE DOSMAC.INC + INCLUDE SYSCALL.INC + INCLUDE ERROR.INC + INCLUDE DPB.INC + INCLUDE CPMFCB.INC + INCLUDE DIRENT.INC + INCLUDE CURDIR.INC + INCLUDE PDB.INC + INCLUDE BPB.INC + .list + +;------------------------------------------------------------------------------- +; Constants + +;Limits +BIG_FAT_THRESHOLD equ 4086 + +;------------------------------------------------------------------------------- + +;FORMAT Pre-defined switches +SWITCH_S EQU 1 ; System transfer +SWITCH_V EQU 2 ; Volume ID prompt +SWITCH_H EQU 4 ; E5 dir terminator +SWITCH_C EQU 8 +SWITCH_T EQU 16 +SWITCH_N EQU 32 +SWITCH_1 EQU 64 +SWITCH_4 EQU 128 +SWITCH_8 EQU 256 +SWITCH_B EQU 512 + +NUM_SWITCHES EQU SWITCH_T or SWITCH_N + +DRNUM EQU 5CH + +RECLEN EQU fcb_RECSIZ+7 +RR EQU fcb_RR+7 + +;------------------------------------------------------------------------------- +; These are the data structures which we will need + + include ioctl.INC + +;Per system file data structure + +a_FileStructure struc +fileHandle DW ? +fileSizeInParagraphs DW ? +fileSizeInBytes DD ? +fileOffset DD ? +fileStartSegment DW ? +fileDate DW ? +fileTime DW ? +a_FileStructure ends + +;------------------------------------------------------------------------------- +; And this is the actual data + +data segment + public deviceParameters + +validSavedDeviceParameters db 0 +savedDeviceParameters a_DeviceParameters <> +deviceParameters a_DeviceParameters <> + +formatPacket a_FormatPacket <> + +startSector dw ? +fatSpace dd ? +fBigFat db FALSE + +firstHead dw ? +firstCylinder dw ? +tracksLeft dw ? +tracksPerDisk dw ? + +public NumSectors ,TrackCnt +NumSectors dw 0FFFFh +TrackCnt dw 0FFFFh + +public Old_Dir +Old_Dir db FALSE + +public fLastChance +fLastChance db FALSE ; Flags reinvocation from + ; LastChanceToSaveIt. Used by DSKPRM + +sectorsInRootDirectory dw ? + +directorySector dd 0 + +formatError db 0 + +printStringPointer dw 0 + +; Exit status defines +ExitStatus db 0 +ExitOK equ 0 +ExitCtrlC equ 3 +ExitFatal equ 4 +ExitNo equ 5 + +ROOTSTR DB ? + DB ":\",0 +DBLFLG DB 0 ;Initialize flags to zero +IOCNT DD ? +MSTART DW ? ; Start of sys file buffer (para#) +MSIZE DW ? ; Size of above in paragraphs +TempHandle DW ? +FILSTAT DB ? ; In memory status of files + ; XXXXXX00B BIOS not in + ; XXXXXX01B BIOS partly in + ; XXXXXX10B BIOS all in + ; XXXX00XXB DOS not in + ; XXXX01XXB DOS partly in + ; XXXX10XXB DOS all in + ; XX00XXXXB COMMAND not in + ; XX01XXXXB COMMAND partly in + ; XX10XXXXB COMMAND all in + +USERDIRS DB DIRSTRLEN+3 DUP(?) ; Storage for users current directory + +bios a_FileStructure <> +BiosAttributes EQU attr_hidden + attr_system + attr_read_only + +dos a_FileStructure <> +DosAttributes EQU attr_hidden + attr_system + attr_read_only + +command a_FileStructure <> +CommandAttributes EQU 0 +CommandFile DB "X:\COMMAND.COM",0 + +VOLFCB DB -1,0,0,0,0,0,8 + DB 0 +VOLNAM DB " " + DB 8 + DB 26 DUP(?) + +TRANSRC DB "A:CON",0,0 ; Device so we don't hit the drive +TRANDST DB "A:\",0,0,0,0,0,0,0,0,0,0 + +BEGSEG DW ? +SWITCHMAP DW ? +SWITCHCOPY DW ? +FAT DW ? + DW ? +CLUSSIZ DW ? +SECSIZ DW ? +SYSTRKS DW ? +SECTORS DW ? +INBUFF DB 80,0 + DB 80 DUP(?) + +ptr_msgHardDiskWarning dw msgHardDiskWarning + dw offset driveLetter + +ptr_msgInsertDisk dw msgInsertDisk + dw offset driveLetter + +ptr_msgReInsertDisk dw msgReInsertDisk + dw offset driveLetter + +ptr_msgInsertDosDisk dw offset msgInsertDosDisk + dw offset systemDriveLetter + +ptr_msgFormatNotSupported dw offset msgFormatNotSupported + dw offset driveLetter + +drive db 0 +driveLetter db "x" +systemDriveLetter db "x" + +data ends + +;For FORPROC and FORMES modules + + public secsiz,clussiz,inbuff + + PUBLIC crlf,std_printf + +;For OEM module + public switchmap,drive,driveLetter,fatSpace + public fBigFat, PrintString,currentHead,currentCylinder + extrn CheckSwitches:near,LastChanceToSaveIt:near + extrn WriteBootSector:near,OemDone:near + extrn AccessDisk:near +data segment + extrn switchlist:byte + extrn fdsksiz:word + extrn BiosFile:byte,DosFile:byte +data ends + +;For FORPROC module + + EXTRN FormatAnother?:near,Yes?:near,REPORT:NEAR,USER_STRING:NEAR +data segment + extrn badsiz:dword,syssiz:dword,biosiz:dword +data ends + +DOSVER_LOW EQU 0300H+20 +DOSVER_HIGH EQU 0300H+20 + + +START: + PUSH AX ;Save DRIVE validity info + MOV AH,GET_VERSION + INT 21H + CMP AX,EXPECTED_VERSION + JE OKDOS + +; XCHG AH,AL ;Turn it around to AH.AL +; CMP AX,DOSVER_LOW +; JB GotBadDos +; CMP AX,DOSVER_HIGH +; JBE OKDOS + + +GOTBADDOS: + MOV DX,OFFSET msgBadDosVersion + mov ax, seg data + mov ds, ax + mov ah,std_con_string_output + int 21h + push es + xor ax,ax + push ax + +foo proc far + ret ; Must use this method, version may be < 2.00 +foo endp + +OKDOS: + + mov ax, seg data + mov es, ax + assume es:data + POP AX + + CMP AL,0FFH ;See if invalid drive specified + JNZ DRVGD ;If not proceed +BogusDrive: + mov ax, seg data + mov ds, ax + lea dx, msgBadDrive + call PrintString + JMP FEXIT ;Exit + +DRVGD: + MOV AH,GET_DEFAULT_DRIVE ;Must get the default drive + INT 21H ;Default now in AL + ADD AL,"A" + MOV [BiosFile],AL + MOV [DosFile],AL + MOV [CommandFile],AL + MOV SI,DRNUM ;So we can get our parameters + LODSB ;Fetch drive designation + OR AL,AL ;See if specified + JNZ DRVSPEC ;If specfied proceed + mov ax, seg data + mov ds, ax + lea dx, msgNeedDrive + call PrintString + jmp fexit +DRVSPEC: + DEC AL ;Drive designator now correct + MOV BYTE PTR DS:[DRNUM],AL ;And updated + MOV DRIVE,AL ;Save copy + add al, 'A' + mov driveLetter, al +; Get all the switch information from the command line + MOV [BEGSEG],DS ;Save start segment + + XOR BX,BX ;Store switch information in BX + MOV SI,81H ;Point to the command line buffer +NXTSWT: + CALL SCANOFF + LODSB + CMP AL,"/" + JZ GETPARM + + CMP AL,13 + JNZ NxtS1 + JMP SavSwt +NxtS1: + MOV AH,AL + LODSB ; AX := getchar() + CMP AL,":" ; IF (AX != drive_spec) + JNZ INVALID ; THEN error + + CMP BYTE PTR DBLFLG,0 ; IF (previous drive_spec) + JNZ INVALID ; THEN error + + INC BYTE PTR DBLFLG ; Yes -- set the flag + OR AH,020h + SUB AH,'a' + CMP AH,Drive + JZ SHORT NXTSWT + JMP BogusDrive +GETPARM: + LODSB +; Convert any lower case input into upper case + CMP AL,41H + JB GETCHR ; Switch is a digit, so don't try to + ; convert it. + AND AL,0DFH +GETCHR: + MOV CL,SWITCHLIST ; CL := Number of Legal switches + OR CL,CL ; IF (Num_Legal_Switches == 0) + JZ INVALID ; THEN error + + MOV CH,0 ; FOR (i=0; i <= Max_switches; i++) + MOV DI,1+OFFSET SWITCHLIST ; IF (switch == SWITCHLIST[i]) + REPNE SCASB ; THEN set zero flag + ; END for + JNZ INVALID ; IF (zero_flag != TRUE ) THEN error + + MOV AX,1 + SHL AX,CL + OR BX,AX ;Set the appropriate bit in SWITCHMAP + + MOV CX,AX ; Current_Switch := Switch processed + Test AX,NUM_SWITCHES ; IF (Switch_processed does not require + ; numeric value) + JZ NXTSWT ; THEN parse next switch + + LODSB ; ELSE then parse :nn and save approp + cmp al,':' ; IF (getchar() != ':') + jne INVALID + + LODSB ; curr_num := MakeNum (getchar()) + SaveReg + call MakeNum + RestoreReg + jc INVALID ; IF error, THEN exit + + SaveReg + Call SaveNum ; SaveNum (curr_num) + Restorereg ; END else; + + + JMP SHORT NXTSWT ;See if there are anymore + +INVALID: + mov ax, seg data + mov ds, ax + lea dx, msgInvalidParameter + call PrintString + JMP FEXIT +MEMERR: + mov ax, seg data + mov ds, ax + lea dx, msgOutOfMemory + call PrintString + JMP FEXIT + +SAVSWT: + mov ax, seg data + mov ds, ax + assume ds:data + MOV SWITCHMAP,BX + +; Set memory requirements + mov es, begseg + mov bx, seg _end + sub bx, begseg + mov ah, setblock + int 21H + +; trap ^C + mov ax, (Set_Interrupt_Vector shl 8) or 23H + mov dx, offset ControlC_Handler + push ds + push cs + pop ds + int 21H + pop ds + +AroundControlC_Handler: + MOV BL,Drive ; x = IOCTL (getdrive, Drive+1); + INC BL + MOV AX,(IOCTL SHL 8) OR 9 + INT 21H + JC NotNet + TEST DX,1200H ; if (x & 0x1200)(redirected or shared) + JZ NotNet + lea dx, msgNetDrive ; Cann't format over net + call PrintString + JMP FEXIT + +NotNet: + TEST DX,8000h ; if local use + jnz re_assign + MOV BL,Drive + ADD BYTE PTR [TRANSRC],BL ; Make string "D:\" + MOV SI,OFFSET TRANSRC + push ds + pop es + MOV DI,OFFSET TRANDST + MOV AH,xNameTrans + INT 21H + MOV BL,BYTE PTR [TRANSRC] + CMP BL,BYTE PTR [TRANDST] ; Did drive letter change? + JZ NO_ASSIGN ; No +RE_ASSIGN: + lea dx, msgAssignedDrive + call PrintString + JMP FEXIT + +NO_ASSIGN: + + CALL Phase1Initialisation + jnc FatAllocated + + lea dx, msgFormatFailure ; IF (error_allocating_FAT) + call PrintString ; ISSUE error and abort + jmp Fexit +FatAllocated: + + TEST SWITCHMAP,SWITCH_S + JZ INITCALL + MOV BX,0FFFFH + MOV AH,ALLOC + INT 21H + OR BX,BX + JZ MEMERRJ ;No memory + MOV [MSIZE],BX + MOV AH,ALLOC + INT 21H + JNC MEM_OK +MEMERRJ: + JMP MEMERR ;No memory + +MEM_OK: + MOV [MSTART],AX + +RDFRST: + mov bios.fileSizeInParagraphs,0 ;mjb001 initialize file size + mov dos.fileSizeInParagraphs,0 ;mjb001 ... + mov command.fileSizeInParagraphs,0 ;mjb001 ... + CALL READDOS ;Read BIOS and DOS + JNC INITCALL ;OK -- read next file +NEEDSYS: + CALL SYSPRM ;Prompt for system disk + JMP RDFRST ;Try again + +INITCALL: + CALL Phase2Initialisation +; Barry S - No reason to jump on carry!!! +; JNC SWITCHCHK +; lea dx, msgFormatFailure +; call PrintString +; JMP FEXIT + +SWITCHCHK: + MOV DX,SWITCHMAP + MOV SWITCHCOPY,DX + +SYSLOOP: + MOV WORD PTR BADSIZ,0 ;Must intialize for each iteration + MOV WORD PTR BADSIZ+2,0 + MOV WORD PTR SYSSIZ,0 + MOV WORD PTR SYSSIZ+2,0 + MOV BYTE PTR DBLFLG,0 + mov ExitStatus, ExitOK + MOV DX,SWITCHCOPY + MOV SWITCHMAP,DX ;Restore original Switches +; DiskFormat will handle call for new disk +; CALL DSKPRM ;Prompt for new disk + CALL DISKFORMAT ;Format the disk + JNC GETTRK +FRMTPROB: + lea dx, msgFormatFailure + call PrintString + mov ExitStatus, ExitFatal + CALL MORE ;See if more disks to format + JMP SHORT SYSLOOP + +;Mark any bad sectors in the FATs +;And keep track of how many bytes there are in bad sectors + +GETTRK: + CALL BADSECTOR ;Do bad track fix-up + JC FRMTPROB ;Had an error in Formatting - can't recover + CMP AX,0 ;Are we finished? + JNZ TRKFND ;No - check error conditions + JMP DRTFAT ;Yes +TRKFND: + CMP BX,STARTSECTOR ;Are any sectors in the system area bad? + JAE CLRTEST ; MZ 2.26 unsigned compare + lea dx, msgDiskUnusable + call PrintString + JMP FRMTPROB ;Bad disk -- try again +CLRTEST: + MOV SECTORS,AX ;Save the number of sectors on the track + TEST SWITCHMAP,SWITCH_S ;If system requested calculate size + JZ BAD100 + CMP BYTE PTR DBLFLG,0 ;Have we already calculated System space? + JNZ CMPTRKS ;Yes -- all ready for the compare + INC BYTE PTR DBLFLG ;No -- set the flag + CALL GETBIOSIZE ; Get the size of the BIOS + MOV DX,WORD PTR SYSSIZ+2 + MOV AX,WORD PTR SYSSIZ + MOV WORD PTR BIOSIZ+2,DX + MOV WORD PTR BIOSIZ,AX + CALL GETDOSSIZE + CALL GETCMDSIZE + MOV DX,WORD PTR BIOSIZ+2 + MOV AX,WORD PTR BIOSIZ + DIV deviceParameters.DP_BPB.BPB_BytesPerSector + ADD AX,STARTSECTOR + MOV SYSTRKS,AX ;Space FAT,Dir,and system files require +CMPTRKS: + CMP BX,SYSTRKS + JA BAD100 ; MZ 2.26 unsigned compare + mov ExitStatus, ExitFatal + lea dx, msgNotSystemDisk + call PrintString + AND SWITCHMAP,NOT SWITCH_S ;Turn off system transfer switch + MOV WORD PTR SYSSIZ+2,0 ;No system to transfer + MOV WORD PTR SYSSIZ,0 ;No system to transfer +BAD100: +; BX is the first bad sector #, SECTORS is the number of bad sectors +; starting at BX. This needs to be converted to clusters. The start sector +; number may need to be rounded down to a cluster boundry, the end sector +; may need to be rounded up to a cluster boundry. Know BX >= STARTSECTOR + SUB BX,STARTSECTOR ; BX is now DATA area relative + MOV CX,BX + ADD CX,SECTORS + DEC CX ; CX is now the last bad sector # + MOV AX,BX + XOR DX,DX + xor bx,bx + mov bl, deviceParameters.DP_BPB.BPB_SectorsPerCluster + DIV bx + MOV BX,AX ; BX is rounded down and converted to + ; a cluster #. Where cluster 0 = + ; first cluster of data. First bad + ; Sector is in cluster BX. + MOV AX,CX + XOR DX,DX + push bx + xor bx,bx + mov bl, deviceParameters.DP_BPB.BPB_SectorsPerCluster + DIV bx + pop bx + MOV CX,AX ; CX is rounded up and converted to a + ; to a cluster #. Where cluster 0 = + ; first cluster of data. Last bad + ; Sector is in cluster CX. + SUB CX,BX + INC CX ; CX is number of clusters to mark bad + ADD BX,2 ; Bias start by correct amount since + ; first cluster of data is really + ; cluster 2. + xor ax,ax + MOV Al,deviceParameters.DP_BPB.BPB_SectorsPerCluster + MUL deviceParameters.DP_BPB.BPB_BytesPerSector + MOV BP,AX ; = Bytes/Cluster + +; Mark CX clusters bad starting at cluster BX +PACKIT: + CALL BadClus ;Put it in the allocation map + JZ BAD150 ;If already marked bad, don't count it + ADD WORD PTR BADSIZ,BP ;Add in number of bad bytes + JNB BAD150 + INC WORD PTR BADSIZ+2 +BAD150: + INC BX ;Next cluster + LOOP PACKIT ;Continue for # of clusters + JMP GETTRK + +; Inputs: BX = Cluster number +; Outputs: The given cluster is marked as invalid +; Zero flag is set if the cluster was already marked bad +; Registers modified: DX,SI +; No other registers affected +BadClus: + PUSH AX + PUSH BX + PUSH CX + PUSH DX + CMP fBigFat,-1 ; if (!fBigFat) { + JZ DoBig + MOV DX,0FF7h ; badval = 0xFF7; + MOV AX,0FFFh ; mask = 0xFFF; + MOV SI,BX ; p = FAT+clus+clus/2; + SHR SI,1 + ADD SI,BX + ADD SI, word ptr fatspace + TEST BX,1 ; if (clus&1) { + JZ DoSet + MOV CL,4 ; mask <<= 4; + SHL AX,CL + MOV CL,4 ; badval <<= 4; + SHL DX,CL ; } + JMP SHORT DoSet +DoBig: ; else { + MOV DX,0FFF7h ; badval = 0xFFF7; + MOV AX,0FFFFh ; mask = 0xFFFF; + MOV SI, word ptr fatSpace ; p = FAT + clus + clus; + ADD SI,BX + ADD SI,BX +DoSet: ; } + push es + mov es, word ptr fatSpace + 2 + MOV CX,es:[SI] ; op = *p & mask; + AND CX,AX + NOT AX ; *p &= ~mask; + AND es:[SI],AX + OR es:[SI],DX ; *p |= badval; + CMP DX,CX ; return op == badval; + pop es + POP DX + POP CX + POP BX + POP AX + return + +DRTFAT: + TEST SWITCHMAP,SWITCH_S ;If system requested, calculate size + JZ CLEARED + CMP BYTE PTR DBLFLG,0 ;Have we already calculated System space? + JNZ CLEARED ;Yes + INC BYTE PTR DBLFLG ;No -- set the flag + CALL GETSIZE ;Calculate the system size +CLEARED: + CALL WriteFileSystem + JNC FATWRT +LOUSE: + lea dx, msgDiskUnusable + call PrintString + JMP FRMTPROB + +LOUSEP: + POP DS + JMP LOUSE + +FATWRT: + + PUSH DS + MOV DL,DRIVE + INC DL + MOV AH,GET_DPB + INT 21H + CMP AL,-1 + JZ LOUSEP ;Something BAD has happened + MOV [BX.dpb_next_free],0 ; Reset allocation to start of disk + MOV [BX.dpb_free_cnt],-1 ; Force free space to be computed + POP DS + TEST SWITCHMAP,SWITCH_S ;System desired + JZ STATUS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +;reintroduce following section of code +; +; CALL CHKSPACE ;Enough free space for system? +; JNC SPACEOK ; Y: Go load system files +; LEA DX, msgNoRoomDestDisk ; N: Print error message +; CALL PrintString ; +; MOV WORD PTR SYSSIZ+2,0 ;No system transfered +; MOV WORD PTR SYSSIZ,0 ;No system transfered +; JMP SHORT STATUS ; +;SPACEOK: ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + mov al, drive + call AccessDisk ; note what is current logical drive + CALL WRITEDOS ;Write the BIOS & DOS + JNC SYSOK + lea dx, msgNotSystemDisk + call PrintString + MOV WORD PTR SYSSIZ+2,0 ;No system transfered + MOV WORD PTR SYSSIZ,0 ;No system transfered + JMP SHORT STATUS + +SYSOK: + lea dx, msgSystemTransfered + call PrintString +STATUS: + CALL CRLF + CALL VOLID + MOV AH,DISK_RESET + INT 21H + CALL DONE ;Final call to OEM module + JNC REPORTC + JMP FRMTPROB ;Report an error + +REPORTC: + CALL REPORT + + CALL MORE ;See if more disks to format + JMP SYSLOOP ;If we returned from MORE then continue + +;****************************************** +; Calculate the size in bytes of the system rounded up to sector and +; cluster boundries, Answer in SYSSIZ + +GetSize proc near + call GetBioSize + call GetDosSize + call GetCmdSize + return +GetSize endp + +GetBioSize proc near + MOV AX,WORD PTR bios.fileSizeInBytes + MOV DX,WORD PTR bios.fileSizeInBytes+2 + CALL AddToSystemSize + return +GetBioSize endp + +GetDosSize proc near + MOV AX,WORD PTR dos.fileSizeInBytes + MOV DX,WORD PTR dos.fileSizeInBytes+2 + CALL AddToSystemSize + return +GetDosSize endp + +GetCmdSize proc near + MOV AX,WORD PTR command.fileSizeInBytes + MOV DX,WORD PTR command.fileSizeInBytes+2 + call AddToSystemSize + return +GetCmdSize endp + +;Calculate the number of sectors used for the system +PUBLIC AddToSystemSize +AddToSystemSize proc near + push bx + DIV deviceParameters.DP_BPB.BPB_BytesPerSector + OR DX,DX + JZ FNDSIZ0 + INC AX ; Round up to next sector +FNDSIZ0: + PUSH AX + XOR DX,DX + xor bx,bx + mov bl, deviceParameters.DP_BPB.BPB_SectorsPerCluster + div bx + POP AX + OR DX,DX + JZ ONCLUS + SUB DX, bx + NEG DX + ADD AX,DX ; Round up sector count to cluster + ; boundry +ONCLUS: + MUL deviceParameters.DP_BPB.BPB_BytesPerSector + ADD WORD PTR SYSSIZ,AX + ADC WORD PTR SYSSIZ+2,DX + pop bx + return +AddToSystemSize endp + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +; reintroduce following section of code +;; Check free space to see if there is enough room to load the system +;; On Entry: DL = drive +;; On Exit: carry flag set if not enough room +;; no other registers are affected +;CHKSPACE PROC NEAR +; PUSH AX ;Save resisters +; PUSH BX +; PUSH CX +; PUSH DX +; +; MOV AH,36H ;Get free space +; INT 21h +; +;;16 bit math okay here, no danger of overflow +; MUL CX ;Get bytes/cluster +; MOV CX,AX ; +; MOV AX,WORD PTR SYSSIZ ;Get # of bytes for system +; MOV DX,WORD PTR SYSSIZ+2 ; +; DIV CX ;Get # of clusters for system +; +; CMP AX,BX ;Is there enough space? +; JBE ENOUGHSPACE ; Y: Go clear carry +; STC ; N: Set carry +; JMP SHORT RESTOREREGS ; +; +;ENOUGHSPACE: +; CLC +; +;RESTOREREGS: +; POP DX ;Restore resisters +; POP CX +; POP BX +; POP AX +; RET +;CHKSPACE ENDP +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + +MORE: CMP deviceParameters.DP_DeviceType, DEV_HARDDISK + je ExitProgram + CALL FormatAnother? ;Get yes or no response + JC ExitProgram + CALL CRLF + JMP CRLF + + +FEXIT: + mov ExitStatus,ExitFatal + +ExitProgram: + test validSavedDeviceParameters, 0ffH + jz DoNotRestoreDeviceParameters + mov savedDeviceParameters.DP_SpecialFunctions, TRACKLAYOUT_IS_GOOD + lea dx, savedDeviceParameters + call SetDeviceParameters +DoNotRestoreDeviceParameters: + mov al, ExitStatus + mov ah,exit + INT 21H + +; Prompt the user for a system diskette in the default drive +SYSPRM: + MOV AH,GET_DEFAULT_DRIVE ;Will find out the default drive + INT 21H ;Default now in AL + MOV BL,AL + INC BL ; A = 1 + ADD AL,41H ;Now in Ascii + MOV systemDriveLetter,AL ;Text now ok + CALL IsRemovable + JNC DoPrompt +; +; Media is non-removable. Switch sys disk to drive A. Check, though, to see +; if drive A is removable too. +; + MOV AL,"A" + MOV BYTE PTR [systemDriveLetter],AL + MOV [BiosFile],AL + MOV [DosFile],AL + MOV [CommandFile],AL + MOV BX,1 + CALL IsRemovable + JNC DoPrompt + lea dx, msgNoSystemFiles + call PrintString +fexitJ: + JMP FEXIT + +DoPrompt: + mov al, systemDriveLetter + sub al, 'A' + call AccessDisk + lea dx, ptr_msgInsertDosDisk + CALL std_printf ;Print first line + CALL USER_STRING ;Wait for a key + CALL CRLF + return + +TARGPRM: + mov al, drive + call AccessDisk + lea DX, ptr_msgInsertDisk + CALL std_printf ;Print first line + CALL USER_STRING ;Wait for a key + CALL CRLF + return + +; +; Determine if the drive indicated in BX is removable or not. +; +; Inputs: BX has drive (0=def, 1=A) +; Outputs: Carry clear +; Removable +; Carry set +; not removable +; Registers modified: none + +IsRemovable: + SaveReg + MOV AX,(IOCTL SHL 8) OR 8 ; Rem media check + INT 21H + JNC CheckRemove + MOV AX,(IOCTL SHL 8) + 9 ; Is it a NET drive? + INT 21h + JC NotRemove ; Yipe, say non-removable + TEST DX,1000h + JNZ NotRemove ; Is NET drive, say non-removeable + JMP IsRemove ; Is local, say removable +CheckRemove: + TEST AX,1 + JNZ NotRemove +IsRemove: + CLC + RestoreReg + return +NotRemove: + STC + RestoreReg + return + + +; DiSKPRoMpt: +; +; This routine prompts for the insertion of the correct diskette +; into the Target drive, UNLESS we are being re-entrantly invoked +; from LastChanceToSaveIt. If the target is a Hardisk we issue a +; warning message. +; +; INPUTS: +; deviceParameters.DP_DeviceType +; fLastChance +; +; OUTPUTS: +; Prompt string +; fLastChance := FALSE +; +; Registers affected: +; Flags +; +DSKPRM: + CMP fLastChance,TRUE + JE PrmptRet + + CMP deviceParameters.DP_DeviceType, DEV_HARDDISK + jne goprnit + lea dx, ptr_msgHardDiskWarning + call std_printf + CALL Yes? + jnc OkToFormatHardDisk + mov ExitStatus, ExitNo + jmp ExitProgram + +OkToFormatHardDisk: + CALL CRLF + CALL CRLF + return + +GOPRNIT: + mov al, drive + call AccessDisk + lea dx,ptr_msgInsertDisk + CALL std_printf + CALL USER_STRING ;Wait for any key + CALL CRLF + CALL CRLF + +PrmptRet: + mov fLastChance, FALSE + return + +;------------------------------------------------------------------------------- +; ScanOff +; Scan Off separator characters + +SCANOFF: + LODSB + CMP AL,' ' + JZ SCANOFF + CMP AL,9 + JZ SCANOFF + DEC SI + return + +;------------------------------------------------------------------------------- +; MakeNum +; Makenum converts digits from ASCII AlphaNumeric format to +; numeric values +; +; Entry: +; AL == Character to be converted +; DS:SI == Command line text +; +; Exit: +; AX == Value +; IF AX == 0 THEN Zero Flag == SET +; IF ERROR THEN Carry Flag == SET +; BX,CX,DX == Garbage +; DS:SI == Character after numeric value +; +; Procs used: +; ToDigit + +Public MakeNum,CalcLoop +MakeNum: + xor BX,BX ; Initialize running cnt + mov CX,10 ; and base of arithmetic +CalcLoop: ; UNTIL no more digits + call ToDigit ; AL := AL - '0' + jc BadNum ; IF error EXIT with carry set + + xchg ax,bx ; AX := running_cnt * 10 + + mul cx ; digit + add ax,bx + jc BadNum ; IF Overflow EXIT with carry + + xchg ax,bx ; BX := Running total + + LODSB ; Get Next Digit + cmp al,' ' ; IF ( ax = (' ',',',)) + je RetVal ; THEN return parsed value + cmp al,',' + je RetVal + + cmp al,'/' ; IF (ax = ('/','cr')) + je BURetVal ; THEN backup DS:SI and + cmp al,0dh ; return parsed value + je BURetVal + or al,al + jnz CalcLoop ; END until + +BURetVal: + dec SI +RetVal: + mov ax,bx + or ax,ax + return + +public Badnum +BadNum: + xor ax,ax + stc + return + +; ToDigit: +; Convert value in AX to decimal digit, range checking for valid values +; +public ToDigit +ToDigit: + sub al,'0' + jb NotDigit + cmp al,9 + ja NotDigit + clc + return + +NotDigit: + stc + return + +;------------------------------------------------------------------------------- + +ControlC_Handler: + mov ax, seg data + mov ds, ax + lea dx, msgInterrupt + call PrintString + mov ExitStatus, ExitCtrlC + jmp ExitProgram + +;------------------------------------------------------------------------------- +; SaveNum +; Save Number from switches into appropriate variable for later use +; Some switches have upper and lower bounds for legal values and +; these are checked for here +; +; ENTRY: +; cx == Switch just parsed +; ax == value parsed +; +; EXIT: +; Value stored in appropriate variable +; DS,DX == garbage +; + +public SaveNum +SaveNum: + mov dx, seg data + mov ds, dx + test word ptr data:Switchmap, CX ; IF already set THEN ignore + jnz done_ret + + test CX,SWITCH_T + jnz Store_T + + test CX,SWITCH_N + jz BadNum + +Store_N: + cmp AX,0 ; IF (value == 0) THEN ignore + je done_ret + + cmp AX, MAX_SECTORS_IN_TRACK ; IF (value > Max_sectors) + jbe short Store_N1 ; THEN issue error + jmp INVALID + +Store_N1: + mov word ptr data:NumSectors , AX + + jmp short done_ret + +Store_T: + mov word ptr data:TrackCnt, AX + +Done_ret: + ret +;------------------------------------------------------------------------------- + +crlf: + lea dx, msgCRLF + +PrintString: + mov printStringPointer, dx + lea dx, PrintStringPointer + +std_printf: + push dx + call printf + return + +;------------------------------------------------------------------------------- + +;***************************************** +; Process V switch if set + +VOLID: + TEST [SWITCHMAP],SWITCH_V + JNZ DOVOL +VRET: CLC + return + +DOVOL: + PUSH CX + PUSH SI + PUSH DI + PUSH ES + PUSH DS + POP ES +VOL_LOOP: + MOV AL,DRIVE + INC AL + MOV DS:BYTE PTR[VOLFCB+7],AL + lea dx, msgLabelPrompt + call PrintString + CALL USER_STRING + call crlf + call crlf + MOV CL,[INBUFF+1] + OR CL,CL + JZ VOLRET + XOR CH,CH + MOV SI,OFFSET INBUFF+2 + MOV DI,SI + ADD DI,CX + MOV CX,11 + MOV AL,' ' + REP STOSB + MOV CX,5 + MOV DI,OFFSET VOLNAM + REP MOVSW + MOVSB + MOV DX,OFFSET VOLFCB + MOV AH,FCB_CREATE + INT 21H + OR AL,AL + JZ GOOD_CREATE + lea dx, msgBadCharacters + call PrintString + JMP VOL_LOOP +GOOD_CREATE: + MOV DX,OFFSET VOLFCB + MOV AH,FCB_CLOSE + INT 21H + CALL CRLF +VOLRET: + POP ES + POP DI + POP SI + POP CX + return + +;**************************************** +;Copy IO.SYS, MSDOS.SYS and COMMAND.COM into data area. +; Carry set if problems + +READDOS: +; CALL TESTSYSDISK ; dcl 8/23/86 + call Get_BIOS ; dcl 8/23/86 + JNC RDFILS + return + +RDFILS: + MOV BYTE PTR [FILSTAT],0 + MOV BX,[bios.fileHandle] + MOV AX,[MSTART] + MOV DX,AX + ADD DX,[MSIZE] ; CX first bad para + MOV [bios.fileStartSegment],AX + MOV CX,[bios.fileSizeInParagraphs] + ADD AX,CX + CMP AX,DX + JBE GOTBIOS + MOV BYTE PTR [FILSTAT],00000001B ; Got part of BIOS + MOV SI,[MSIZE] + XOR DI,DI + CALL DISIX4 + push ds + MOV DS,[bios.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JC CLSALL + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR [bios.fileOffset],AX + MOV WORD PTR [bios.fileOffset+2],DX +FILESDONE: + CLC +CLSALL: + PUSHF +; CALL COMCLS ; dcl 8/23/86 + call FILE_CLS ; dcl 8/23/86 + POPF + return + +GOTBIOS: + MOV BYTE PTR [FILSTAT],00000010B ; Got all of BIOS + push es + LES SI,[bios.fileSizeInBytes] + MOV DI,ES + pop es + push ds + MOV DS,[bios.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JC CLSALL + + push ax ; dcl 8/23/86 + push dx ; dcl 8/23/86 + call File_Cls ; dcl 8/23/86 + call Get_DOS ; dcl 8/23/86 + pop dx ; dcl 8/23/86 + pop ax ; dcl 8/23/86 + + JNC Found_MSDOS ;mt 12/8/86 P894 + return ;mt 12/8/86 + +Found_MSDOS: ;mt 12/8/86 + + MOV BX,[dos.fileHandle] + MOV [dos.fileStartSegment],AX + CMP AX,DX ; No room left? + JZ CLSALL ; Yes + MOV CX,[dos.fileSizeInParagraphs] + ADD AX,CX + CMP AX,DX + JBE GOTDOS + OR BYTE PTR [FILSTAT],00000100B ; Got part of DOS + SUB DX,[dos.fileStartSegment] + MOV SI,DX + XOR DI,DI + CALL DISIX4 + push ds + MOV DS,[dos.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JC CLSALL + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR [dos.fileOffset],AX + MOV WORD PTR [dos.fileOffset+2],DX + JMP FILESDONE + +GOTDOS: + OR BYTE PTR [FILSTAT],00001000B ; Got all of DOS + LES SI,[dos.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[dos.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + +CLSALLJ: JNC NOTCLSALL ;PTM P894 mt 12/8/86 + jmp clsall ; + +NotCLSALL: + push ax ; dcl 8/23/86 + + push dx ; dcl 8/23/86 + call File_cls ; dcl 8/23/86 + call Get_COMMAND ; dcl 8/23/86 + pop dx ; dcl 8/23/86 + pop ax ; dcl 8/23/86 + + JNC Found_COMMAND ;mt 12/8/86 P894 + return ;mt 12/8/86 + +Found_COMMAND: ;mt 12/8/86 + MOV BX,[command.fileHandle] + MOV [command.fileStartSegment],AX + CMP AX,DX ; No room left? + JZ CLSALLJ ; Yes + MOV CX,[command.fileSizeInParagraphs] + ADD AX,CX + CMP AX,DX + JBE GOTCOM + OR BYTE PTR [FILSTAT],00010000B ; Got part of COMMAND + SUB DX,[command.fileStartSegment] + MOV SI,DX + XOR DI,DI + CALL DISIX4 + push ds + MOV DS,[command.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JC CLSALLJ + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR [command.fileOffset],AX + MOV WORD PTR [command.fileOffset+2],DX + JMP FILESDONE + +GOTCOM: + OR BYTE PTR [FILSTAT],00100000B ; Got all of COMMAND + LES SI,[command.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[command.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JMP CLSALL + +;************************************************** +;Write BIOS DOS COMMAND to the newly formatted disk. + +ASSUME DS:DATA +WRITEDOS: + MOV CX,BiosAttributes + MOV DX,OFFSET BiosFile + LES SI,[bios.fileSizeInBytes] + MOV DI,ES + CALL MAKEFIL + retc + + MOV [TempHandle],BX + TEST BYTE PTR FILSTAT,00000010B + JNZ GOTALLBIO + call Get_BIOS ; dcl 8/23/86 + jnc Got_WBIOS ;mt 12/8/86 P894 + ret + +Got_WBIOS: + + LES SI,[bios.fileOffset] + MOV DI,ES + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + MOV BP,OFFSET bios + CALL GOTTARG + retc + JMP SHORT BIOSDONE + +GOTALLBIO: + LES SI,[bios.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[bios.fileStartSegment] + assume ds:nothing + CALL WRITEFILE + pop ds + assume ds:data +BIOSDONE: + MOV BX,[TempHandle] + MOV CX,bios.fileTime + MOV DX,bios.fileDate + CALL CLOSETARG + MOV CX,DosAttributes + MOV DX,OFFSET DosFile + LES SI,[dos.fileSizeInBytes] + MOV DI,ES + CALL MAKEFIL + retc + +GOTNDOS: + MOV [TempHandle],BX + TEST BYTE PTR FILSTAT,00001000B + JNZ GOTALLDOS + call Get_DOS ; dcl 8/23/86 + jnc Got_WDOS ;mt 12/8/86 P894 + ret + +Got_WDOS: + MOV BP,OFFSET dos + TEST BYTE PTR FILSTAT,00000100B + JNZ PARTDOS + MOV WORD PTR [dos.fileOffset],0 + MOV WORD PTR [dos.fileOffset+2],0 + CALL GETSYS3 + retc + JMP SHORT DOSDONE + +PARTDOS: + LES SI,[dos.fileOffset] + MOV DI,ES + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + CALL GOTTARG + retc + JMP SHORT DOSDONE + +GOTALLDOS: + LES SI,[dos.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[dos.fileStartSegment] + assume ds:nothing + CALL WRITEFILE + pop ds + assume ds:data +DOSDONE: + MOV BX,[TempHandle] + MOV CX,dos.fileTime + MOV DX,dos.fileDate + CALL CLOSETARG + MOV CX,CommandAttributes + MOV DX,OFFSET CommandFile + LES SI,[command.fileSizeInBytes] + MOV DI,ES + CALL MAKEFIL + retc + + MOV [TempHandle],BX + TEST BYTE PTR FILSTAT,00100000B + JNZ GOTALLCOM + call Get_COMMAND ; dcl 8/23/86 + jnc Got_WCOM ;mt 12/8/86 P894 + ret + +Got_WCOM: + MOV BP,OFFSET command + TEST BYTE PTR FILSTAT,00010000B + JNZ PARTCOM + MOV WORD PTR [command.fileOffset],0 + MOV WORD PTR [command.fileOffset+2],0 + CALL GETSYS3 + retc + JMP SHORT COMDONE + +PARTCOM: + LES SI,[command.fileOffset] + MOV DI,ES + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + CALL GOTTARG + retc + JMP SHORT COMDONE + +GOTALLCOM: + LES SI,[command.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[command.fileStartSegment] + assume ds:nothing + CALL WRITEFILE + pop ds + assume ds:data +COMDONE: + MOV BX,[TempHandle] + MOV CX,command.fileTime + MOV DX,command.fileDate + CALL CLOSETARG +;**************************************************************** +; I don't see the need for the following code!! - RS 3.20 +; CMP BYTE PTR [FILSTAT],00101010B +; JZ NOREDOS +;RDFRST2: +; CALL READDOS ; Start back with BIOS +; JNC NOREDOS +; CALL SYSPRM ;Prompt for system disk +; JMP RDFRST2 ;Try again +;NOREDOS: +;**************************************************************** + CLC + return + +;********************************************* +; Create a file on target disk +; CX = attributes, DX points to name +; DI:SI is size file is to have +; +; There is a bug in DOS 2.00 and 2.01 having to do with writes +; from the end of memory. In order to circumvent it this routine +; must create files with the length in DI:SI +; +; On return BX is handle, carry set if problem + +MAKEFIL: + MOV BX,DX + PUSH WORD PTR [BX] + MOV AL,DriveLetter + MOV [BX],AL + MOV AH,CREAT + INT 21H + POP WORD PTR [BX] + MOV BX,AX + JC CheckMany + MOV CX,DI + MOV DX,SI + MOV AX,LSEEK SHL 8 + INT 21H ; Seek to eventual EOF + XOR CX,CX + MOV AH,WRITE + INT 21H ; Set size of file to position + XOR CX,CX + MOV DX,CX + MOV AX,LSEEK SHL 8 + INT 21H ; Seek back to start + return + +; +; Examine error code in AX to see if it is too-many-open-files. +; If it is, we abort right here. Otherwise we return. +; +CheckMany: + CMP AX,error_too_many_open_files + retnz + lea dx, msgTooManyFilesOpen + call PrintString + JMP FEXIT + +;********************************************* +; Close a file on the target disk +; CX/DX is time/date, BX is handle + +CLOSETARG: + MOV AX,(FILE_TIMES SHL 8) OR 1 + INT 21H + MOV AH,CLOSE + INT 21H + return + +;**************************************** +; Transfer system files +; BP points to data structure for file involved +; offset is set to current amount read in +; Start set to start of file in buffer +; TempHandle is handle to write to on target + +IOLOOP: + MOV AL,[systemDriveLetter] + CMP AL,[DriveLetter] + JNZ GOTTARG + MOV AH,DISK_RESET + INT 21H + CALL TARGPRM ;Get target disk + +GOTTARG: +ASSUME DS:DATA +;Enter here if some of file is already in buffer, IOCNT must be set +; to size already in buffer. + MOV BX,[TempHandle] + MOV SI,WORD PTR [IOCNT] + MOV DI,WORD PTR [IOCNT+2] + push ds + MOV DS,ds:[BP.fileStartSegment] + assume ds:nothing + CALL WRITEFILE ; Write next part + pop ds + assume ds:data + retc + + LES AX,ds:[BP.fileOffset] + CMP AX,WORD PTR ds:[BP.fileSizeInBytes] + JNZ GETSYS3 + MOV AX,ES + CMP AX,WORD PTR ds:[BP.fileSizeInBytes+2] + JNZ GETSYS3 + return ; Carry clear from CMP + +GETSYS3: +;Enter here if none of file is in buffer + MOV AH,DISK_RESET + INT 21H + MOV AX,[MSTART] ;Furthur IO done starting here + MOV ds:[BP.fileStartSegment],AX + MOV AL,[systemDriveLetter] + CMP AL,[DriveLetter] + JNZ TESTSYS +GSYS: + MOV AH,DISK_RESET + INT 21H + CALL SYSPRM ;Prompt for system disk +TESTSYS: +; CALL TESTSYSDISK ; dcl 8/23/86 + JC GSYS + MOV BX,word ptr DS:[BP.fileHandle] ; CS over ARR 2.30 + LES DX,dword ptr DS:[BP.fileOffset] ; CS over ARR 2.30 + PUSH DX + MOV CX,ES + MOV AX,LSEEK SHL 8 + INT 21H + POP DX + LES SI,dword ptr DS:[BP.fileSizeInBytes] ; CS over ARR 2.30 + MOV DI,ES + SUB SI,DX + SBB DI,CX ; DI:SI is #bytes to go + PUSH DI + PUSH SI + ADD SI,15 + ADC DI,0 + CALL DISID4 + MOV AX,SI + POP SI + POP DI + CMP AX,[MSIZE] + JBE GOTSIZ2 + MOV SI,[MSIZE] + XOR DI,DI + CALL DISIX4 +GOTSIZ2: + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + push ds + MOV DS,[MSTART] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JNC GETOFFS + CALL CLSALL + JMP GSYS +GETOFFS: + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR DS:[BP.fileOffset],AX ; CS over ARR 2.30 + MOV WORD PTR DS:[BP.fileOffset+2],DX ; CS over ARR 2.30 + CALL CLSALL + JMP IOLOOP + +;************************************************* +; Test to see if correct system disk. Open handles + +CRET12: + STC + return + +;TESTSYSDISK: ; dcl 8/23/86 +Get_BIOS: ; dcl 8/23/86 + MOV AX,OPEN SHL 8 + MOV DX,OFFSET BiosFile + INT 21H + JNC SETBIOS +; call CheckMany ; dcl 8/23/86 + jmp CheckMany ; dcl 8/23/86 + +SETBIOS: + MOV [Bios.fileHandle],AX + MOV BX,AX + CALL GETFSIZ + CMP [bios.fileSizeInParagraphs],0 + JZ SETBIOSSIZ + CMP [bios.fileSizeInParagraphs],AX + JZ SETBIOSSIZ +BIOSCLS: + MOV AH,CLOSE + MOV BX,[Bios.fileHandle] + INT 21H +; JMP CRET12 ; dcl 8/23/86 + ret + +SETBIOSSIZ: + MOV [bios.fileSizeInParagraphs],AX + MOV WORD PTR [bios.fileSizeInBytes],SI + MOV WORD PTR [bios.fileSizeInBytes+2],DI + MOV [bios.fileDate],DX + MOV [bios.fileTime],CX + clc + ret ; dcl 8/23/86 + +Get_DOS: ; dcl 8/23/86 + MOV AX,OPEN SHL 8 + MOV DX,OFFSET DosFile + INT 21H + JNC DOSOPNOK +; call CheckMany ; dcl 8/23/86 +; JMP BIOSCLS ; dcl 8/23/86 Checkmany no ret. + jmp CheckMany ; dcl 8/23/86 + +DOSOPNOK: + MOV [dos.fileHandle],AX + MOV BX,AX + CALL GETFSIZ + CMP [dos.fileSizeInParagraphs],0 + JZ SETDOSSIZ + CMP [dos.fileSizeInParagraphs],AX + JZ SETDOSSIZ + +DOSCLS: + MOV AH,CLOSE + MOV BX,[dos.fileHandle] + INT 21H +; JMP BIOSCLS ; dcl 8/23/86 + ret ; dcl 8/23/86 + +SETDOSSIZ: + MOV [dos.fileSizeInParagraphs],AX + MOV WORD PTR [dos.fileSizeInBytes],SI + MOV WORD PTR [dos.fileSizeInBytes+2],DI + MOV [dos.fileDate],DX + MOV [dos.fileTime],CX + clc + ret ; dcl 8/23/86 + +Get_COMMAND: + MOV AX,OPEN SHL 8 + MOV DX,OFFSET CommandFile + INT 21H + JNC GotComHand +; call CheckMany ; dcl 8/23/86 +; JMP DosCls ; dcl 8/23/86 + jmp Checkmany ; dcl 8/23/86 + +GotComHand: + MOV [command.fileHandle],AX + MOV BX,AX + CALL GETFSIZ + CMP [command.fileSizeInParagraphs],0 + JZ SETCOMSIZ + CMP [command.fileSizeInParagraphs],AX + JZ SETCOMSIZ +COMCLS: + MOV AH,CLOSE + MOV BX,[command.fileHandle] + INT 21H +; JMP DOSCLS ; dcl 8/23/86 + ret ; dcl 8/23/86 + +SETCOMSIZ: + MOV [command.fileSizeInParagraphs],AX + MOV WORD PTR [command.fileSizeInBytes],SI + MOV WORD PTR [command.fileSizeInBytes+2],DI + MOV [command.fileDate],DX + MOV [command.fileTime],CX + CLC + return + +FILE_CLS: ; dcl 8/23/86 + MOV AH,CLOSE ; dcl 8/23/86 + INT 21H ; dcl 8/23/86 + ret ; dcl 8/23/86 + +;******************************************* +; Handle in BX, return file size in para in AX +; File size in bytes DI:SI, file date in DX, file +; time in CX. + +GETFSIZ: + MOV AX,(LSEEK SHL 8) OR 2 + XOR CX,CX + MOV DX,CX + INT 21H + MOV SI,AX + MOV DI,DX + ADD AX,15 ; Para round up + ADC DX,0 + AND DX,0FH ; If the file is larger than this it + ; is bigger than the 8086 address + ; space! + MOV CL,12 + SHL DX,CL + MOV CL,4 + SHR AX,CL + OR AX,DX + PUSH AX + MOV AX,LSEEK SHL 8 + XOR CX,CX + MOV DX,CX + INT 21H + MOV AX,FILE_TIMES SHL 8 + INT 21H + POP AX + return + +;******************************************** +; Read/Write file +; DS:0 is Xaddr +; DI:SI is byte count to I/O +; BX is handle +; Carry set if screw up +; +; I/O SI bytes +; I/O 64K - 1 bytes DI times +; I/O DI bytes + + +READFILE: +; Must preserve AX,DX + PUSH AX + PUSH DX + PUSH BP + MOV BP,READ SHL 8 + CALL FILIO + POP BP + POP DX + POP AX + return + +WRITEFILE: + PUSH BP + MOV BP,WRITE SHL 8 + CALL FILIO + POP BP + return + +FILIO: + XOR DX,DX + MOV CX,SI + JCXZ K64IO + MOV AX,BP + INT 21H + retc + ADD DX,AX + CMP AX,CX ; If not =, AX= 4086) +; +Phase1Initialisation proc near + +; Get device parameters + lea dx, deviceParameters + mov deviceParameters.DP_SpecialFunctions, 0 + call GetDeviceParameters + jnc GotDeviceParameters + lea dx, ptr_msgFormatNotSupported + call std_printf + jmp fexit +GotDeviceParameters: + +; Save the device parameters for when we exit + lea si, deviceParameters + lea di, savedDeviceParameters + mov cx, size a_DeviceParameters + push ds + pop es + rep movsb + +; Ensure that there is a valid number of sectors in the track table + mov savedDeviceParameters.DP_TrackTableEntries, 0 + mov validSavedDeviceParameters, 1 + +; Initialise this to zero to know if CheckSwitches defined the track layout + mov deviceParameters.DP_TrackTableEntries, 0 + +; Detect whether "set media type" is supported +; test DeviceParameters.DeviceAttributes, SetMediaType +; jnz SetMTsupp + +SetMTsupp: + +; Check switches against parameters and use switches to modify device parameters + call CheckSwitches + retc + + cmp deviceParameters.DP_TrackTableEntries, 0 + jne TrackLayoutSet ; There is a good track layout + +; Store sector table info + mov cx, deviceParameters.DP_BPB.BPB_SectorsPerTrack + mov deviceParameters.DP_TrackTableEntries, cx + mov ax, 1 + mov bx, deviceParameters.DP_BPB.BPB_bytesPerSector + lea di, deviceParameters.DP_SectorTable +LoadSectorTable: + stosw + xchg ax, bx + stosw + xchg ax, bx + inc ax + loop LoadSectorTable +TrackLayoutSet: + +; +; directorySector = malloc( Bytes Per Sector ) +; + mov bx, deviceParameters.DP_BPB.BPB_BytesPerSector + add bx, 0fH + shr bx, 1 + shr bx, 1 + shr bx, 1 + shr bx, 1 + mov ah, Alloc + int 21H + retc + mov word ptr directorySector+2, ax + xor ax,ax + mov word ptr directorySector, ax + +; +; fatSpace = malloc( Bytes Per Sector * Sectors Per FAT ) +; + mov ax, deviceParameters.DP_BPB.BPB_BytesPerSector + mul deviceParameters.DP_BPB.BPB_SectorsPerFAT + add ax, 0fH + shr ax, 1 + shr ax, 1 + shr ax, 1 + shr ax, 1 + mov bx, ax + mov ah, Alloc + int 21H + retc + mov word ptr fatSpace+2, ax + xor ax, ax + mov word ptr fatSpace, ax + + call SetStartSector + call SetfBigFat + + clc + return + +Phase1Initialisation endp + +;------------------------------------------------------------------------------- + +SetStartSector proc near + +; startSector = number of reserved sectors +; + number of FAT Sectors ( Number of FATS * Sectors Per FAT ) +; + number of directory sectors ( 32* Root Entries / bytes Per Sector ) +; ( above is rounded up ) + +; Calculate the number of directory sectors + mov ax, deviceParameters.DP_BPB.BPB_RootEntries + mov bx, size dir_entry + mul bx + add ax, deviceParameters.DP_BPB.BPB_bytesPerSector + dec ax + xor dx,dx + div deviceParameters.DP_BPB.BPB_bytesPerSector + mov sectorsInRootDirectory,ax + mov startSector, ax + +; Calculate the number of FAT sectors + mov ax, deviceParameters.DP_BPB.BPB_SectorsPerFAT + mul deviceParameters.DP_BPB.BPB_numberOfFATs +; Add in the number of boot sectors + add ax, deviceParameters.DP_BPB.BPB_ReservedSectors + add startSector, ax + + return + +SetStartSector endp + +;------------------------------------------------------------------------------- + +SetfBigFat proc near +; +; fBigFat = ( ( (Total Sectors - Start Sector) / Sectors Per Cluster) >= 4086 ) +; + mov ax, deviceParameters.DP_BPB.BPB_TotalSectors + + +;************************* Fix for PTM PCDOS P51 + + ; + ; Old code + ; + ;cmp ax,20740 + ;jbe SmallFAT + ;mov fBigFat, TRUE + + ; + ; New Code + ; + + sub ax,startSector ;Get sectors in data area + xor dx,dx + xor bx,bx + mov bl,deviceParameters.DP_BPB.BPB_sectorsPerCluster + div bx ;Get total clusters + cmp ax,BIG_FAT_THRESHOLD ;Is clusters < 4086? + jb SmallFAT ;12 bit FAT if so + mov fBigFAT,TRUE ;16 bit FAT if >=4096 + +;************************* END of fix for PTM PCDOS P51 + +SmallFAT: + + return + +SetfBigFat endp + +;------------------------------------------------------------------------------- +; +; Phase2Initialisation: +; Use device parameters to build information that will be +; required for each format +; +; Algorithm: +; Calculate first head/cylinder to format +; Calculate number of tracks to format +; Calculate the total bytes on the disk and save for later printout +; First initialise the directory buffer +; +Phase2Initialisation proc near + +; Calculate first track/head to format (round up - kludge) + mov ax, deviceParameters.DP_BPB.BPB_HiddenSectors + mov dx, deviceParameters.DP_BPB.BPB_HiddenSectors + 2 + add ax, deviceParameters.DP_BPB.BPB_SectorsPerTrack + adc dx, 0 + dec ax + sbb dx, 0 + div deviceParameters.DP_BPB.BPB_SectorsPerTrack + xor dx,dx + div deviceParameters.DP_BPB.BPB_Heads + mov firstCylinder, ax + mov firstHead, dx + +; Calculate the total number of tracks to be formatted (round down - kludge) + mov ax, deviceParameters.DP_BPB.BPB_TotalSectors + xor dx,dx +; if (TotalSectors == 0) then use BigTotalSectors + or ax,ax + jnz NotBigTotalSectors + mov ax, deviceParameters.DP_BPB.BPB_BigTotalSectors + mov dx, deviceParameters.DP_BPB.BPB_BigTotalSectors + 2 + +NotBigTotalSectors: + div deviceParameters.DP_BPB.BPB_SectorsPerTrack + mov tracksPerDisk, ax + +; Initialise the directory buffer +; Clear out the Directory Sector before any information is inserted. + mov cx, deviceParameters.DP_BPB.BPB_BytesPerSector + les di, directorySector + xor ax,ax + rep stosb + + mov ax, deviceParameters.DP_BPB.BPB_BytesPerSector + xor dx, dx + mov bx, size dir_entry + div bx + mov cx, ax + + les bx, directorySector +; If Old_Dir = TRUE then put the first letter of each directory entry must be 0E5H + xor al, al + cmp old_Dir, TRUE + jne StickE5 + mov al, 0e5H +StickE5: + mov es:[bx], al + add bx, size dir_entry + loop stickE5 + +; +; fDskSiz = (Total Sectors - Start Sector) * Bytes Per Sector +; + mov ax, deviceParameters.DP_BPB.BPB_TotalSectors + sub ax, startSector + mul deviceParameters.DP_BPB.BPB_BytesPerSector + mov word ptr fDskSiz, ax + mov word ptr fDskSiz+2, dx + + return + +Phase2Initialisation endp + +;------------------------------------------------------------------------------- +; +; SetDeviceParameters: +; Set the device parameters +; +; Input: +; drive +; dx - pointer to device parameters +; +SetDeviceParameters proc near + + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + mov bl, drive + inc bl + mov cx, (RAWIO shl 8) or SET_DEVICE_PARAMETERS + int 21H + return + +SetDeviceParameters endp + +;------------------------------------------------------------------------------- +; +; GetDeviceParameters: +; Get the device parameters +; +; Input: +; drive +; dx - pointer to device parameters +; +GetDeviceParameters proc near + + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + mov bl, drive + inc bl + mov cx, (RAWIO shl 8) or GET_DEVICE_PARAMETERS + int 21H + return + +GetDeviceParameters endp + +;------------------------------------------------------------------------------- +; +; DiskFormat: +; Format the tracks on the disk +; Since we do our SetDeviceParameters here, we also need to +; detect the legality of /N /T if present and abort with errors +; if not. +; This routine stops as soon as it encounters a bad track +; Then BadSector is called to report the bad track, and it continues +; the format +; +; Algorithm: +; Initialise in memory FAT +; current track = first +; while not done +; if format track fails +; DiskFormatErrors = true +; return +; next track + +DiskFormat proc near + + +; +; Initialise fatSpace +; + push es + les di, fatSpace + mov ax, deviceParameters.DP_BPB.BPB_SectorsPerFAT + mul deviceParameters.DP_BPB.BPB_bytesPerSector + mov cx, ax + xor ax,ax + rep stosb + + mov di, word ptr fatSpace + mov al, deviceParameters.DP_BPB.BPB_MediaDescriptor + mov ah, 0ffH + stosw + mov ax, 00ffH + test fBigFat, TRUE + jz NotBig + mov ax, 0ffffH +NotBig: stosw + pop es + +; don't bother to do the formatting if /c was given + test switchmap, SWITCH_C + jz Keep_Going + jmp FormatDone ;FormatDone is to far away + +Keep_Going: +foofoo = INSTALL_FAKE_BPB or TRACKLAYOUT_IS_GOOD + mov deviceParameters.DP_SpecialFunctions, foofoo + lea dx, deviceParameters + + call SetDeviceParameters + + test switchmap, SWITCH_H ;Suppress prompt? + jnz No_Prompt + + call DSKPRM ; prompt user for disk + +No_Prompt: + test switchmap,switch_8 ; DCL 5/12/86 avoid Naples AH=18h + jnz stdBpB ; lackof support for 8 sectors/track + + ; DCL 5/12/86 + ; Always do the STATUS_FOR_FORMAT test, as we don't know if the machine + ; has this support. For 3.2 /N: & /T: were not documented & therefore + ; not fully supported thru the ROM of Aquarius & Naples & Royal Palm + + ;test SwitchMap, SWITCH_N or SWITCH_T ; IF ( /N or /T ) ;; DCL 5/12/86 + ;jz StdBPB + ; THEN check if + ; supported + mov formatPacket.FP_SpecialFunctions, STATUS_FOR_FORMAT + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + mov bl, drive + inc bl + mov cx, (RAWIO shl 8) or FORMAT_TRACK + lea dx, formatPacket + int 21H + ; switch ( FormatStatusCall) + + ;cmp FormatPacket.FP_SpecialFunctions, Format_No_ROM_Support + ;jb NTSupported ; 0 returned from IO.SYS + ;ja IllegalComb ; 2 returned - ROM Support + ; Illegal Combination! + cmp FormatPacket.FP_SpecialFunctions,0 + je NTSupported + lea dx, msgInvalidParameter + cmp FormatPacket.FP_SpecialFunctions,2 + je Abort_Prog + lea dx, msgNotReady + cmp FormatPacket.FP_SpecialFunctions,3 + je Abort_Prog + + ; DCL No ROM support is okay + ; except for /N: & /T: + test SwitchMap, SWITCH_N or SWITCH_T ; DCL 5/12/86 + jz StdBPB + lea dx, msgParametersNotSupported ; CASE: NOT SUPPORTED + +Abort_Prog: + Call PrintString + jmp Fexit +; +; We have the support to carry out the FORMAT +; +NTSupported: +StdBPB: + ;call DSKPRM ; prompt user for disk ;; DCL 5/12/86 + mov FormatPacket.FP_SpecialFunctions, 0 + mov ax, firstHead + mov formatPacket.FP_Head, ax + mov ax, firstCylinder + mov formatPacket.FP_Cylinder, ax + mov cx, tracksPerDisk + dec cx + mov tracksLeft, cx +FormatLoop: + call DisplayCurrentTrack + call FormatTrack + jc FailDiskFormat + call NextTrack + jnc FormatLoop + +; All done +FormatDone: + mov formatError, 0 + clc + return + +FailDiskFormat: + call CheckError + retc + call LastChanceToSaveIt + jc FormatReallyFailed + + call SetStartSector + call SetfBigFat + push ax + call Phase2Initialisation + clc + pop ax +; jc FormatReallyFailed + jmp DiskFormat + +FormatReallyFailed: + mov formatError, 1 + clc + return + +DiskFormat endp + + +;------------------------------------------------------------------------------- +; +; BadSector: +; Reports the bad sectors. +; Reports the track where DiskFormat stopped. +; From then on it formats until it reaches a bad track, or end, +; and reports that. +; +; Output: +; Carry: set --> fatal error +; if Carry not set +; ax - The number of consecutive bad sectors encountered +; ax == 0 --> no more bad sectors +; bx - The logical sector number of the first bad sector +; +; Algorithm: +; if DiskFormatErrors +; DiskFormatErrors = false +; return current track +; else +; next track +; while not done +; if format track fails +; return current track +; next track +; return 0 + +BadSector proc near + + +; don't bother to do the formatting if /c was given + test switchmap, SWITCH_C + jnz NoMoreTracks + + test formatError, 0ffH + jz ContinueFormat + mov formatError, 0 + jmp ReportBadTrack + +ContinueFormat: + call NextTrack + jc NoMoreTracks + + call DisplayCurrentTrack + call FormatTrack + jnc ContinueFormat + call CheckError + retc + +ReportBadTrack: + call CurrentLogicalSector + mov ax, deviceParameters.DP_BPB.BPB_SectorsPerTrack + clc + return + +NoMoreTracks: + lea dx, msgFormatComplete + call PrintString + mov ax, 0 + clc + return + +BadSector endp + + +;------------------------------------------------------------------------------- +; FormatTrack: +; format the current track +; +; Input: +; formatPacket +; +; Output: +; Carry: set if format failed +; +FormatTrack proc near + + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + mov bl, drive + inc bl + mov cx, (RAWIO shl 8) or FORMAT_TRACK + lea dx, formatPacket + int 21H + retnc + + mov ah, 59H + xor bx,bx + int 21H + stc + return + +FormatTrack endp + +;------------------------------------------------------------------------------- + +data segment + +ptr_msgCurrentTrack dw offset msgCurrentTrack +currentHead dw 0 +currentCylinder dw 0 + +data ends + +DisplayCurrentTrack proc near + + mov ax, formatPacket.FP_Cylinder + mov currentCylinder, ax + mov ax, formatPacket.FP_Head + mov currentHead, ax + lea dx, ptr_msgCurrentTrack + call std_printf + return + +DisplayCurrentTrack endp + +;------------------------------------------------------------------------------- +; NextTrack: +; Advance to the next track for formatting +; +; Input: +; formatPacket.FP_Head +; formatPacket.FP_Cylinder +; deviceParameters.DP_BPB.BPB_Heads +; tracksLeft +; +; Output: +; Carry: set --> all done +; formatPacket.FP_Head +; formatPacket.FP_cyliner +; tracksLeft +; +; Algorithm: +; if tracksLeft +; tracksLeft-- +; if ++head > highest head +; head = 0 +; cylinder++ +; +NextTrack proc near + + cmp tracksLeft, 0 + je ThatsAllFolks + dec tracksLeft + +; Bump the head + inc formatPacket.FP_Head + mov ax, formatPacket.FP_Head + cmp ax, deviceParameters.DP_BPB.BPB_Heads + jb ExitNextTrack + +; We've done all heads on this cylinder so move on to next +; (start on head 0 of the next cylinder) + mov formatPacket.FP_Head, 0 + inc formatPacket.FP_Cylinder + +ExitNextTrack: + clc + return + +ThatsAllFolks: +; Oh wow, we're all done + stc + return + +NextTrack endp + +;------------------------------------------------------------------------------- +; CheckError: +; Input: +; ax - extended error code +; Ouput: +; carry set if error is fatal +; Message printed if Not Ready or Write Protect +; +CheckError proc near + cmp ax, error_write_protect + je WriteProtectError + cmp ax, error_not_ready + je NotReadyError + cmp currentCylinder, 0 + jne CheckRealErrors + cmp currentHead, 0 + je BadTrackZero + +CheckRealErrors: + cmp ax, error_CRC + je JustABadTrack + cmp ax, error_sector_not_found + je JustABadTrack + cmp ax, error_write_fault + je JustABadTrack + cmp ax, error_read_fault + je JustABadTrack + cmp ax, error_gen_failure + je JustABadTrack + + stc + ret + +JustABadTrack: + clc + ret + +WriteProtectError: + lea dx, msgWriteProtected + call PrintString + stc + ret + +NotReadyError: + lea dx, msgNotReady + call PrintString + stc + ret + +BadTrackZero: + lea dx, msgDiskUnusable + call PrintString + stc + ret + +CheckError endp + +;------------------------------------------------------------------------------- +; WriteFileSystem: +; Write the boot sector and FATs out to disk +; Clear the directory sectors to zero +; +WriteFileSystem proc near + + + call WriteBootSector + retc + +; Write out each of the FATs + xor cx, cx + mov cl, deviceParameters.DP_BPB.BPB_numberOfFATs + mov dx, deviceParameters.DP_BPB.BPB_ReservedSectors +WriteFATloop: + push cx + push dx + mov al, drive + mov cx, deviceParameters.DP_BPB.BPB_SectorsPerFAT + push ds + lds bx, fatSpace + int 26H + pop ax + pop ds + jc CanNotWriteFAT + + pop dx + add dx, deviceParameters.DP_BPB.BPB_SectorsPerFAT + pop cx + loop WriteFATLoop + +; Clear the directory + +; Now write the initialised directory sectors out to disk + mov ax, deviceParameters.DP_BPB.BPB_SectorsPerFAT + xor dx,dx + mul deviceParameters.DP_BPB.BPB_NumberOfFATs + mov dx, deviceParameters.DP_BPB.BPB_ReservedSectors + add dx, ax + mov cx, sectorsInRootDirectory +WriteDIRloop: + push cx + push dx + mov al, drive + mov cx, 1 + push ds + lds bx, directorySector + int 26H + pop ax + pop ds + jc CanNotWriteDirectory + + pop dx + add dx, 1 + pop cx + loop WriteDIRLoop + + +; Ok, we can tell the device driver that we are finished formatting + mov savedDeviceParameters.DP_TrackTableEntries, 0 + mov savedDeviceParameters.DP_SpecialFunctions, TRACKLAYOUT_IS_GOOD + lea dx, savedDeviceParameters + call SetDeviceParameters + + MOV AH,DISK_RESET ; Flush any directories in + INT 21H ; buffers + + return + +CanNotWriteFAT: + lea dx, msgFATwriteError + jmp PrintErrorAbort + +CanNotWriteDirectory: + lea dx, msgDirectorywriteError + jmp PrintErrorAbort + +WriteFileSystem endp + +;------------------------------------------------------------------------------- +; Done: +; format is done... so clean up the disk! +; +Done proc near + + + call OemDone + return + +Done endp + +;------------------------------------------------------------------------------- +; CurrentLogicalSector: +; Get the current logical sector number +; +; Input: +; current track = tracksPerDisk - tracksLeft +; SectorsPerTrack +; +; Output: +; BX = logical sector number of the first sector in the track we +; just tried to format +; +CurrentLogicalSector proc near + mov ax, tracksPerDisk + sub ax, tracksLeft + dec ax + mul deviceParameters.DP_BPB.BPB_SectorsPerTrack + mov bx, ax + return + +CurrentLogicalSector endp + +;------------------------------------------------------------------------------- +; PrintErrorAbort: +; Print an error message and abort +; +; Input: +; dx - Pointer to error message string +; +PrintErrorAbort proc near + + push dx + call crlf + pop dx + call PrintString + + jmp fexit + +PrintErrorAbort endp + +code ends + + END START diff --git a/SRC/CMD/FORMAT/FORMAT.LNK b/SRC/CMD/FORMAT/FORMAT.LNK new file mode 100644 index 0000000..6b68295 --- /dev/null +++ b/SRC/CMD/FORMAT/FORMAT.LNK @@ -0,0 +1,2 @@ +format.obj forproc.obj messages.obj oemfor.obj ..\..\libc\printf.obj +format.exe /m; diff --git a/SRC/CMD/FORMAT/FORPROC.ASM b/SRC/CMD/FORMAT/FORPROC.ASM new file mode 100644 index 0000000..88c12f4 --- /dev/null +++ b/SRC/CMD/FORMAT/FORPROC.ASM @@ -0,0 +1,141 @@ +; SCCSID = @(#)forproc.asm 1.2 85/07/25 +.xlist +.xcref +BREAK MACRO subtitle + SUBTTL subtitle + PAGE +ENDM + + INCLUDE SYSCALL.INC +.cref +.list +data segment public 'DATA' +data ends + +code segment public 'CODE' + assume cs:code,ds:data + + PUBLIC FormatAnother?,Yes?,REPORT,USER_STRING + public fdsksiz,badsiz,syssiz,datasiz,biosiz + + extrn std_printf:near,crlf:near,PrintString:near + +data segment + extrn driveLetter:byte + +; In formes.asm + extrn msgInsertDisk:byte + extrn msgFormatAnother?:byte + extrn msgTotalDiskSpace:byte + extrn msgSystemSpace:byte + extrn msgBadSpace:byte + extrn msgDataSpace:byte + extrn yes_byte:byte + extrn no_byte:byte + + extrn inbuff:byte + +ptr_msgTotalDiskSpace dw offset msgTotalDiskSpace +fdsksiz dd 0 + +ptr_msgSystemSpace dw offset msgSystemSpace +syssiz dd 0 +biosiz dd 0 + +ptr_msgBadSpace dw offset msgBadSpace +badsiz dd 0 + +ptr_msgDataSpace dw offset msgDataSpace +datasiz dd 0 + +ptr_msgInsertDisk dw offset msgInsertDisk + dw offset driveLetter +data ends + +FormatAnother? proc near +; Wait for key. If yes return carry clear, else no. Insures +; explicit Y or N answer. + lea dx, msgFormatAnother? + call PrintString + CALL Yes? + JNC WAIT20 + JZ WAIT20 + CALL CRLF + JMP SHORT FormatAnother? +FormatAnother? endp + +Yes? proc near + +; Wait for key. If YES return carry clear,else carry set. +; If carry is set, Z is set if explicit NO, else key was not Yes or No. + CALL USER_STRING + JNZ GETBYT + XOR AL,AL ; So that CMP with [NO_BYTE] is NZ + JMP SHORT CHECK_NO + +GETBYT: + MOV AL,BYTE PTR [INBUFF+2] + OR AL,20H ; Convert to lower case + CMP AL,[YES_BYTE] + JZ WAIT20 ; Carry clear if jump +CHECK_NO: + CMP AL,[NO_BYTE] + STC ; Set carry (wasn't Yes) +WAIT20: RET + +Yes? endp + +USER_STRING: +; Get a string from user. Z is set if user typed no chars (imm CR) +; We need to flush a second time to get rid of incoming Kanji characters also. + MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0 ; Clean out input + INT 21H + MOV DX,OFFSET INBUFF + MOV AH,STD_CON_STRING_INPUT + INT 21H + MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0 ; Clean out input + INT 21H + CMP BYTE PTR [INBUFF+1],0 + RET + +;********************************************* +; Make a status report including the following information: +; Total disk capacity +; Total system area used +; Total bad space allocated +; Total data space available + +REPORT: + lea dx, ptr_msgTotalDiskSpace + call std_printf + cmp WORD PTR SYSSIZ,0 + JNZ SHOWSYS + cmp WORD PTR SYSSIZ+2,0 + JZ CHKBAD +SHOWSYS: + MOV dx,OFFSET ptr_msgSystemSpace + CALL std_printf ;Report space used by system +CHKBAD: + cmp WORD PTR BADSIZ,0 + JNZ SHOWBAD + cmp WORD PTR BADSIZ+2,0 + JZ SHOWDATA +SHOWBAD: + lea dx, ptr_msgBadSpace + call std_printf +SHOWDATA: + MOV CX,WORD PTR FDSKSIZ + MOV BX,WORD PTR FDSKSIZ+2 + SUB CX,WORD PTR BADSIZ + SBB BX,WORD PTR BADSIZ+2 + SUB CX,WORD PTR SYSSIZ + SBB BX,WORD PTR SYSSIZ+2 + MOV word ptr datasiz,CX + MOV word ptr datasiz+2,BX + lea dx, ptr_msgDataSpace + call std_printf + call crlf + RET + +code ends + end diff --git a/SRC/CMD/FORMAT/MAKEFILE b/SRC/CMD/FORMAT/MAKEFILE new file mode 100644 index 0000000..7d5e68d --- /dev/null +++ b/SRC/CMD/FORMAT/MAKEFILE @@ -0,0 +1,58 @@ +#** makefile for format + +DEST =format +MSG =messages + +# Path definitions + +BIOS =..\..\BIOS +BOOT =..\..\BOOT +DOS =..\..\DOS + +# Definitions for assembler + +ASM =masm +AFLAGS =-Mx -t +AINC =-I..\..\inc -I$(DOS) + +# Definitions for C compiler + +CC =cl +CFLAGS =-c -Ox -Zlp +CINC =-I..\..\h + +# Definitions for linker + +LINK =link +LIBC =..\..\libc + + +# Rules and Dependencies follow + +filesize.inc: $(DOS)\msdos.sys $(BIOS)\io.sys + GWBASIC MAKE_INC + +FORMAT.OBJ: FORMAT.ASM $(DOS)\DOSMAC.INC $(DOS)\BPB.INC \ + $(DOS)\DIRENT.INC $(DOS)\DPB.INC $(DOS)\CURDIR.INC \ + $(DOS)\CPMFCB.INC $(DOS)\PDB.INC \ + $(DOS)\ERROR.INC $(DOS)\SYSCALL.INC $(DOS)\IOCTL.INC + masm $(AFLAGS) $(AINC) FORMAT; + +$(MSG).OBJ: $(MSG).ASM $(MSG).inc + masm $(AFLAGS) $(AINC) $(MSG); + +FORPROC.OBJ: FORPROC.ASM $(DOS)\SYSCALL.INC + masm $(AFLAGS) $(AINC) FORPROC; + +OEMFOR.OBJ: OEMFOR.ASM $(DOS)\DOSMAC.INC $(DOS)\SYSCALL.INC $(DOS)\BPB.INC \ + $(DOS)\DIRENT.INC bootmes.inc $(DOS)\IOCTL.INC \ + $(BOOT)\BOOT.INC $(BOOT)\BOOT11.INC filesize.inc + masm $(AFLAGS) $(AINC) OEMFOR; + +$(LIBC)\printf.obj: $(LIBC)\printf.asm + masm $(AFLAGS) $(AINC) $(LIBC)\printf,$(LIBC)\printf; + +FORMAT.EXE: FORMAT.OBJ FORPROC.OBJ $(MSG).OBJ OEMFOR.OBJ $(LIBC)\PRINTF.OBJ + LINK @FORMAT.LNK + convert format.exe + del format.exe diff --git a/SRC/CMD/FORMAT/MAKE_INC.BAS b/SRC/CMD/FORMAT/MAKE_INC.BAS new file mode 100644 index 0000000..96fc13d Binary files /dev/null and b/SRC/CMD/FORMAT/MAKE_INC.BAS differ diff --git a/SRC/CMD/FORMAT/MESSAGES.ASM b/SRC/CMD/FORMAT/MESSAGES.ASM new file mode 100644 index 0000000..1dabff5 --- /dev/null +++ b/SRC/CMD/FORMAT/MESSAGES.ASM @@ -0,0 +1,68 @@ +; SCCSID = @(#)messages.asm 1.10 85/08/13 +TITLE FORMAT Messages + +data segment public 'DATA' + + public Yes_Byte + public No_Byte + public msgCRLF + public msgCurrentTrack + public msgSystemTransfered + public msgFormatComplete + public msgInterrupt + public msgInsertDisk + public msgHardDiskWarning + public msgFormatAnother? + public msgInsertDosDisk + public msgReInsertDisk + public msgLabelPrompt + public msgTotalDiskSpace + public msgSystemSpace + public msgBadSpace + public msgDataSpace + public msgFormatNotSupported + public msgInvalidDeviceParameters + public msgErrorInIOCTL + public msgNotBlockDevice + public msgFATwriteError + public msgDirectoryWriteError + public msgAssignedDrive + public msgNeedDrive + public msgBadDosVersion + public msgNoSystemFiles + public msgTooManyFilesOpen + public msgNetDrive + public msgBadCharacters + public msgBadDrive + public msgInvalidParameter + public msgParametersNotSupported + public msgFormatFailure + public msgNotSystemDisk +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +; reintroduce following public for fix +; public msgNoRoomDestDisk +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + public msgDiskUnusable + public msgOutOfMemory + public msgWriteProtected + public msgNotReady + public msgBootWriteError + public msgDirectoryReadError + public msgBadVolumeId + public msgWhatIsVolumeId? + public msgIncompatibleParameters + public msgIncompatibleParametersForHardDisk + public msgBadPartitionTable + public msgParametersNotSupportedByDrive + public msgPartitionTableReadError + public msgPartitionTableWriteError + +CR equ 13 +LF equ 10 + +; Oem dependent messages + + include messages.inc + +data ends + END diff --git a/SRC/CMD/FORMAT/MESSAGES.INC b/SRC/CMD/FORMAT/MESSAGES.INC new file mode 100644 index 0000000..41815d5 --- /dev/null +++ b/SRC/CMD/FORMAT/MESSAGES.INC @@ -0,0 +1,139 @@ +; SCCSID = @(#)messages.inc 1.6 85/08/02 + +DEBUG EQU 0 ; for Boot sector installation check + +IF DEBUG + public msgFormatBroken +ENDIF + +; THE FOLLOWING ONE BYTE CHARACTERS ARE THE PROMPT ANSWERS. +; THEY MUST BE LOWER CASE, AND THE UPPER TO LOWER, OR LOWER +; TO LOWER CONVERSION MUST BE DOABLE BY "OR AL,20h". +; Yes/No Answers + +Yes_Byte db "y" +No_Byte db "n" + +msgCRLF db CR, LF, 0 + +; Status messages + +msgCurrentTrack db "Head: %3d Cylinder: %4d", CR, 0 + +msgSystemTransfered db "System transferred",CR,LF,0 + +msgInterrupt db 13,10, 10, 0 + +; Note: This message must be long enough to wipe out message msgCurrentTrack +msgFormatComplete db "Format complete ",CR,LF,0 + +; Prompts + +msgInsertDisk db "Insert new diskette for drive %c:",CR,LF + db "and strike ENTER when ready",0 + +msgHardDiskWarning db CR,LF + db "WARNING, ALL DATA ON NON-REMOVABLE DISK",CR,LF + db "DRIVE %c: WILL BE LOST!",CR,LF + db "Proceed with Format (Y/N)?",0 + +msgFormatAnother? db "Format another (Y/N)?",0 + +msgInsertDosDisk db "Insert DOS disk in drive %c:", CR, LF + db "and strike ENTER when ready", CR, LF, 0 + +msgReInsertDisk db "Re-insert diskette for drive %c:",0 + +msgLabelPrompt db "Volume label (11 characters, ENTER for none)? ",0 + +; Disk usage messages + +msgTotalDiskSpace db "%l10d bytes total disk space", CR, LF, 0 + +msgSystemSpace db "%l10d bytes used by system", CR, LF, 0 + +msgBadSpace db "%l10d bytes in bad sectors", CR, LF, 0 + +msgDataSpace db "%l10d bytes available on disk",CR,LF,0 + +; Error messages + +msgFormatNotSupported db "Format not supported on drive %c:", CR,LF,0 + +msgInvalidDeviceParameters db "Invalid device parameters from device driver" + db CR, LF, 0 + +msgErrorInIOCTL db "Error in IOCTL call", CR, LF, 0 + +msgNotBlockDevice db "Not a block device", CR, LF, 0 + +msgFATwriteError db "Error writing FAT", CR, LF, 0 + +msgDirectoryWriteError db "Error writing directory", CR, LF, 0 + +msgAssignedDrive db "Cannot format an ASSIGNed or SUBSTed drive. ", CR, LF, 0 + +msgNeedDrive db "Drive letter must be specified",CR,LF,0 + +msgBadDosVersion db "Incorrect DOS version",CR,LF,"$" + +msgNoSystemFiles db "Cannot find System Files",CR,LF,0 + +msgTooManyFilesOpen db "Too many open files",CR,LF,0 + +msgNetDrive db "Cannot FORMAT a Network drive", CR, LF, 0 + +msgBadCharacters db "Invalid characters in volume label", CR, LF, 0 + +msgBadDrive db "Invalid drive specification", CR, LF, 0 + +msgInvalidParameter db "Invalid parameter", CR, LF, 0 + +msgParametersNotSupported db "Parameters not supported",CR,LF,0 + +; Note: This message must be long enough to wipe out message msgCurrentTrack +msgFormatFailure db "Format failure ",CR,LF,0 + +msgNotSystemDisk db "Disk unsuitable for system disk", CR, LF, 0 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +; reintroduce following message for fix +;msgNoRoomDestDisk db "No room for system on destination disk", CR, LF, 0 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + +msgDiskUnusable db "Invalid media or Track 0 bad - disk unusable", CR, LF, 0 + +msgOutOfMemory db "Insufficient memory for system transfer", CR, LF, 0 + +; Note: This message must be long enough to wipe out message msgCurrentTrack +msgWriteProtected db "Attempted write-protect violation", CR, LF, 0 + +; Note: This message must be long enough to wipe out message msgCurrentTrack +msgNotReady db "Drive not ready ", CR, LF, 0 + + +msgBootWriteError db "Unable to write BOOT", CR, LF, 0 + +msgDirectoryReadError db "Error reading directory", CR, LF, 0 + +msgBadVolumeId db "Invalid Volume ID", CR, LF, 0 + +msgWhatIsVolumeId? db "Enter current Volume Label for drive %c: ", 0 + +msgIncompatibleParameters db "Parameters not compatible", CR,LF,0 + +msgIncompatibleParametersForHardDisk db "Parameters not compatible" + db " with fixed disk", CR,LF,0 + +msgBadPartitionTable db "Bad Partition Table", CR, LF, 0 + +msgParametersNotSupportedByDrive db "Parameters not Supported by Drive", CR, LF, 0 + +msgPartitionTableReadError db "Error reading partition table", CR, LF, 0 + +msgPartitionTableWriteError db "Error writing partition table", CR, LF, 0 + +IF DEBUG +msgFormatBroken db "Format Broken", CR, LF, 0 +ENDIF + diff --git a/SRC/CMD/FORMAT/OEMFOR.ASM b/SRC/CMD/FORMAT/OEMFOR.ASM new file mode 100644 index 0000000..b773206 --- /dev/null +++ b/SRC/CMD/FORMAT/OEMFOR.ASM @@ -0,0 +1,1204 @@ +; SCCSID = @(#)oemfor.asm 1.28 85/10/15 + name OemFormatRoutines + +debug equ 0 +;------------------------------------------------------------------------------- +; Public for debugging only + + public CheckSwitches + public LastChanceToSaveIt + public WriteBootSector + public OemDone + public WriteBogusDos + public ConvertToOldDirectoryFormat + public SetPartitionTable + public ReadSector + public WriteSector + public SectorIO + public GetVolumeId + public CheckVolumeId + + public customBPBs + public BootSectorIsFine + public NotSlashB + public NotSingleSided + public EndSwitchCheck + public WeCanNotIgnoreThisError + public CanNotWriteBoot + public HardDisk? + public BogusDos + public sys_mess_loop + public end_sys_loop + public DirectoryRead + public wrtdir + public DirectoryWritten + public PartitionTableRead + public partitionscan + public dochange + public partitionset + public BadPartitionTable + public FCBforVolumeIdSearch + public CopyVolumeId + public CompareVolumeIds + public VolumeToUpper + public NextLetter + public BadVolumeId + + public switchlist + public boot2 + public boot + public scratchBuffer + public bootDrive + public biosFilename + public dosFilename + public oldDrive + public oldVolumeId + + public bootSignature + public ptr_msgWhatIsVolumeId? + + public trackReadWritePacket + + public BPB81 + public BPB82 + public BPB91 + public BPB92 + +;------------------------------------------------------------------------------- + +data segment public 'DATA' +data ends + +code segment public 'CODE' + assume cs:code,ds:data + + Public AccessDisk + public CheckSwitches + public LastChanceToSaveIt + public WriteBootSector + public OemDone + public BiosFile + public DosFile + +data segment + extrn AddToSystemSize:near + extrn currentCylinder:word + extrn currentHead:word + extrn deviceParameters:byte + extrn drive:byte + extrn driveLetter:byte + extrn fBigFAT:byte + extrn inbuff:byte + extrn switchmap:word + extrn Old_Dir:byte + extrn fLastChance:byte + + extrn msgBadVolumeId:byte + extrn msgBadPartitionTable:byte + extrn msgBootWriteError:byte + extrn msgDirectoryReadError:byte + extrn msgDirectoryWriteError:byte + extrn msgInvalidParameter:byte + extrn msgIncompatibleParameters:byte + extrn msgIncompatibleParametersForHardDisk:byte + extrn msgParametersNotSupportedByDrive:byte + extrn msgPartitionTableReadError:byte + extrn msgPartitionTableWriteError:byte + extrn msgWhatIsVolumeId?:byte + extrn NumSectors:word, TrackCnt:word + +IF DEBUG + extrn msgFormatBroken:byte +ENDIF + +data ends + + extrn PrintString:near + extrn std_printf:near + extrn crlf:near + extrn user_string:near + +;------------------------------------------------------------------------------- +; Support Routines + +Switches macro s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16 +;; +switchCount = 0 +switchmask = 1 + irp x,<&s1,&s2,&s3,&s4,&s5,&s6,&s7,&s8,&s9,&s10,&s11,&s12,&s13,&s14,&s15,&s16> + ifnb + switchCount = switchCount + 1 + SWITCH_&&x = switchmask + switchmask = 2 * switchmask + endif + endm +public switchlist +switchlist db switchCount + db "&s16&&s15&&s14&&s13&&s12&&s11&&s10&&s9&&s8&&s7&&s6&&s5&&s4&&s3&&s2&&s1&" + endm + +;------------------------------------------------------------------------------- +; Constants + +; Standard dos macros + INCLUDE DOSMAC.INC + +; This defines all the int 21H system calls + INCLUDE SYSCALL.INC + +; Limits + +; following were removed into FILESIZE.INC by kwc on 10/04/86 + +;BIOS_SIZE equ 5400h ; Used to set size of +;DOS_SIZE equ 7600h ; Bogus DOS for /B switch + + include filesize.inc + +; end of FILESIZE.INC change by kwc on 10/04/86 + +LOGBOOTSECT equ 1 +;MAX_SECTORS_IN_TRACK equ 20 Already defined in ioctl.INC +Set_Drv_Owner equ 0Fh ; IOCTL subfunction + +;------------------------------------------------------------------------------- +; These are the data structures which we will need + + INCLUDE DIRENT.INC + include ioctl.INC + +;------------------------------------------------------------------------------- +; And this is the actual data +data segment + +BiosFile db "x:\IO.SYS", 0 +DosFile db "x:\MSDOS.SYS", 0 + +trackReadWritePacket a_TrackReadWritePacket <> + + Switches S,V,H,C,T,N,1,4,8,B + +; BIOS parameter blocks for various media +customBPBs label byte +BPB92 a_BPB <512, 2, 1, 2, 112, 2*9*40, 0fdH, 2, 9, 2, 0, 0, 0, 0> +BPB91 a_BPB <512, 1, 1, 2, 64, 1*9*40, 0fcH, 2, 9, 1, 0, 0, 0, 0> +BPB82 a_BPB <512, 2, 1, 2, 112, 2*8*40, 0ffH, 1, 8, 2, 0, 0, 0, 0> +BPB81 a_BPB <512, 1, 1, 2, 64, 1*8*40, 0feH, 1, 8, 1, 0, 0, 0, 0> +BPB720 a_BPB <512, 2, 1, 2, 112, 2*9*80, 0F9h, 3, 9, 2, 0, 0, 0, 0> + +Custom_Media equ 0F0H ; Media byte for custom format +Dual_8_Media equ 0FFh ; Dual sided 8 sectored +Single_8_Media equ 0FEh ; Single sided 8 sectored +Dual_9_Media equ 0FDh ; Dual sided 9 sectored +Single_9_Media equ 0FCh ; Single sided 9 sectored +Dual_15_Media equ 0F9h ; Dual sided 15 sectored +Fixed_Disk equ 0F8h ; Fixed Disk + + +boot2 db 0,0,0, "Boot 1.x" + db 512 - 11 dup(?) + +REORG2 LABEL BYTE + ORG BOOT2 + INCLUDE ..\BOOT\BOOT11.INC + ORG REORG2 + +boot db 0,0,0,"Boot 2.x" +bootBPB a_BPB <> + db 512 - (size a_BPB + 11 + 3) dup(0) + +bootDrive db 0 +bootSignature dw 0 + +REORG LABEL BYTE + ORG BOOT + INCLUDE ..\BOOT\BOOT.INC + ORG REORG + +scratchBuffer db 512 dup(?) + +ptr_msgWhatIsVolumeId? dw offset msgWhatIsVolumeId? + dw offset driveLetter + +data ends +;------------------------------------------------------------------------------- +; AccessDisk: +; Called whenever a different disk is about to be accessed +; +; Input: +; al - drive letter (0=A, 1=B, ...) +; +; Output: +; none +AccessDisk proc near + + push ax ; save drive letter + mov bl,al ; Set up GENERIC IOCTL REQUEST preamble + inc bl + mov ax,(IOCTL SHL 8) + Set_Drv_Owner ; IOCTL function + int 21h + pop ax + return + +AccessDisk endp + +;------------------------------------------------------------------------------- +; CheckSwitches: +; Check switches against device parameters +; Use switches to modify device parameters +; +; Input: +; deviceParameters +; +; Output: +; deviceParameters may be modified +; Carry set if error +; +; Algorithm: +; if hard disk +; Check Boot Sector for valid Signature +; IF (valid) +; Check the volume id +; Make sure no switches other than /V, /S are specifed +; else if 96 tpi without /4 or not 5.25" disk +; Make sure no switches other than /V, /S are specifed +; else +; if 48 tpi drive and switch /4 +; turn off switch /4 +; if single sided drive and switch /1 but not switch /8 +; turn off switch /1 +; if any of interesting switches are on (/C, /O, /V, /S are not) +; set number of cylinders to 40 +; choose new BPB depending on switches /1 and /8 +; +CheckSwitches proc near + +IF DEBUG +; See if the boot sector was initialised correctly + cmp bootSignature, 0aa55H + je BootSectorIsFine + lea dx, msgFormatBroken + jmp short SwitchError +ENDIF ; DEBUG + +BootSectorIsFine: + +; Disallow /C + lea dx, msgInvalidParameter + test switchmap, SWITCH_C + jz CheckExcl + +SwitchError: + call PrintString + stc + ret + +; Only certain permutations of the switches /N /T /V /B /S and /V are legal. +; For specific cases see the file Switchmap.legal. + +CheckExcl: + lea dx, msgIncompatibleParameters ; Error message + + + test SwitchMap, SWITCH_B ; IF ( SWITCH_B) + jz SVpermitted + + test SwitchMap, SWITCH_S or SWITCH_V ; THEN exclude SWITCH_S and + jnz SwitchError ; SWITCH_V + +SVpermitted: + test SwitchMap, SWITCH_8 ; IF ( SWITCH_8 ) + jz Check_N + ; THEN + test SwitchMap, SWITCH_N or SWITCH_T ; exclude SWITCH_N and + jnz SwitchError + + + test SwitchMap, SWITCH_V ; SWITCH_V if unaccompanied + jz Check_N ; by SWITCH_S + + test SwitchMap, SWITCH_S + jz SwitchError ; ENDIF ( SWITCH_8 ) + + +Check_N: ; IF ( SWITCH_N or SWITCH_T ) + test SwitchMap, SWITCH_N or SWITCH_T + jz ExclChkDone + + test SwitchMap, SWITCH_1 or SWITCH_4 ; THEN exclude SWITCH_1 and + jnz SwitchError ; SWITCH_4 + +ExclChkDone: +; Patch the boot sector so that the boot strap loader knows what disk to +; boot from + mov bootDrive, 00H + + cmp deviceParameters.DP_DeviceType, DEV_HARDDISK + jne CheckFor5InchDrives + +; Formatting a hard disk so we must repatch the boot sector + mov bootDrive, 80H + test switchmap, not (SWITCH_S or SWITCH_V) + jz SwitchesOkForHardDisk + lea dx, msgIncompatibleParametersForHardDisk + call PrintString + stc + ret + +; Before checking the Volume Id we need to verify that a valid one exists +; We assume that unless a valid boot sector exists on the target disk, no +; valid Volume Id can exist. + +SwitchesOkForHardDisk: + SaveReg + mov al,drive + mov cx,LogBootSect + xor dx,dx + lea bx,scratchBuffer ; ScratchBuffer := Absolute_Disk_Read( + INT 25h ; Logical_sec_1 ) + pop ax ; Stupid Int 25! leaves flags + ; on the stack. We throw them away + + jnc CheckSignature + stc + RestoreReg + ret + +CheckSignature: ; IF (BootSector.BootSignature != aa55) + + mov ax, Word Ptr (ScratchBuffer + (BootSignature - boot)) + cmp ax, 0aa55h + RestoreReg + clc ; not an error, just not vol. + retnz ; THEN RETURN + + call CheckVolumeId ; ELSE CheckVolumeID + return + +OnlyVSpermitted: + test switchmap, not (SWITCH_S or SWITCH_V) + retz + lea dx, msgIncompatibleParameters + +Print_And_Return: + call PrintString + stc + return + + +CheckFor5InchDrives: + + ;If drive type is anything other than 48 or 96, then only /V/S/H/N/T allowed + cmp byte ptr deviceParameters.DP_DeviceType,DEV_5INCH96TPI + je Got96 + + cmp byte ptr deviceParameters.DP_DeviceType,DEV_5INCH + je Got48 + + test switchmap, not (SWITCH_V or SWITCH_S or SWITCH_N or SWITCH_T or SWITCH_H) + jz Goto_Got_BPB + lea dx,msgParametersNotSupportedByDrive + jmp short Print_And_Return + + ; We have a 96tpi floppy drive + ; /4 allows just about all switches however, /1 requires /4 +Got96: + test switchmap, SWITCH_4 + jnz CheckForInterestingSwitches ;If /4 check /N/T/V/S + + test switchmap, SWITCH_1 ;If /1 and /4 check others + jz Got48 + + ;If only /1 with no /4, see if /N/T + test SwitchMap,(Switch_N or Switch_T) + jnz CheckForInterestingSwitches + + lea dx, msgIncompatibleParameters ;If no /4 but /1 die + jmp short Print_And_Return + +Got48: + ;Ignore /4 for non-96tpi 5 1/4" drives + and switchmap, not SWITCH_4 + + ;Ignore /1 if drive has only one head and not /8 + cmp word ptr deviceParameters.DP_BPB.BPB_Heads, 1 + ja CheckForInterestingSwitches + test switchmap, SWITCH_8 + jz CheckForInterestingSwitches + and switchmap, not SWITCH_1 + + ;Are any interesting switches set? +CheckForInterestingSwitches: + test switchmap, not (SWITCH_V or SWITCH_S or SWITCH_H) ;Anything but /V/S/H? + jz Goto_EndSwitchCheck ;No, everything ok + + ;At this point there are switches other than /v/s/h + test SwitchMap,(SWITCH_N or SWITCH_T) + jz Use_48tpi ;Not /n/t, so must be /b/1/8/4 + + ;We've got /N/T, see if there are others + test SwitchMap, not (SWITCH_N or SWITCH_T or SWITCH_V or SWITCH_S or SWITCH_H) + jz NT_Compatible ;Nope, all is well + + ;If 96tpi drive and /1 exists with /N/T, then okay, otherwise error + cmp byte ptr deviceParameters.DP_DeviceType,DEV_5INCH96TPI + jne Bad_NT_Combo + + test SwitchMap, not (SWITCH_1 or SWITCH_N or SWITCH_T or SWITCH_V or SWITCH_S or SWITCH_H) + jz Goto_Got_BPB + +Bad_NT_Combo: + lea dx, msgIncompatibleParameters + jmp Print_And_Return + +Goto_Got_BPB: + jmp Got_BPB_Ok ;Sleazy, but je won't reach it + +Goto_EndSwitchCheck: + jmp EndSwitchCheck + ;There is a problem with /N/T in that IO.SYS will default to a BPB with the + ;media byte set to F0 (other) if the /N/T combo is used for the format. This + ;will cause problems if we are creating a media that has an assigned media + ;byte, i.e. 160,180,320,360, or 720k media using /N/T. To avoid this problem, + ;if we detect a /N/T combo that would correspond to one of these medias, then + ; we will set things up using the /4/1/8 switches instead of the /N/T + ; MT - 7/17/86 PTR 33D0110 + + ; Combo's that we look for - 96tpi drive @ /T:40, /N:9 + ; 96tpi drive @ /T:40, /N:8 + ; + ; Look for this combo after we set everything up with the /T/N routine + ; 1.44 drive @ /T:80, /N:9 + +NT_Compatible: + cmp byte ptr deviceParameters.DP_DeviceType,DEV_5INCH96TPI + jne Goto_Got_BPB + + cmp TrackCnt,40 ;Look for 40 tracks + jne Got_BPB_Ok + + cmp NumSectors,9 ;9 sectors? + je Found_48tpi_Type + + cmp NumSectors,8 ;8 sectors? + jne Goto_Got_BPB ;Nope, different type, let it go thru + + or SwitchMap,SWITCH_8 ;Yes, turn on /8 switch + +Found_48tpi_Type: + and SwitchMap,not (SWITCH_N or SWITCH_T) ;Turn off /T/N + +;******End PTR fix + +; if we have a 96 tpi drive then we will be using it in 48 tpi mode +Use_48tpi: + cmp byte ptr deviceParameters.DP_DeviceType, DEV_5INCH96TPI + jne Not96tpi + + mov byte ptr deviceParameters.DP_MediaType, 1 + mov word ptr deviceParameters.DP_Cylinders, 40 +Not96tpi: + +; Since we know we are formatting in 48 tpi mode turn on /4 switch +; (We use this info in LastChanceToSaveIt) + or switchmap, SWITCH_4 + +; At this point we know that we will require a special BPB +; It will be one of: +; 0) 9 track 2 sides - if no switches +; 1) 9 track 1 side - if only /1 specified +; 2) 8 track 2 sides - if only /8 specified +; 3) 8 track 1 side - if /8 and /1 specified +; +Get_BPBs: +; ax is used to keep track of which of the above BPB's we want + xor ax, ax + +; /B implies /8 + test switchmap, SWITCH_B + jz NotSlashB + or switchmap, SWITCH_8 +NotSlashB: + + test switchmap, SWITCH_1 + jz NotSingleSided + add ax, 1 +NotSingleSided: + + test switchmap, SWITCH_8 + jz Not8SectorsPerTrack + add ax, 2 +; /8 implies Old_Dir = TRUE + mov Old_Dir,TRUE +Not8SectorsPerTrack: + +; Ok now we know which BPB to use so lets move it to the device parameters + + mov bx, size a_BPB + mul bx + lea si, CustomBPBs + add si, ax + lea di, deviceParameters.DP_BPB + mov cx, size a_BPB + push ds + pop es + repnz movsb + +;***************************************************************** +;* /N/T DCR stuff. Possible flaw exists if we are dealing with a +;* HardDisk. If they support the "custom format" features for +;* Harddisks too, then CheckForInterestingSwitches should +;* consider /n/t UNinteresting, and instead of returning +;* after setting up the custom BPB we fall through and do our +;* Harddisk Check. +Got_BPB_OK: + test switchmap,SWITCH_N+SWITCH_T + jnz Setup_Stuff + jmp EndSwitchCheck +Setup_Stuff: +; Set up NumSectors and SectorsPerTrack entries correctly + test switchmap,SWITCH_N + jz No_Custom_Seclim + mov ax,word ptr NumSectors + mov DeviceParameters.DP_BPB.BPB_SectorsPerTrack,ax + jmp short Handle_Cyln +No_Custom_Seclim: + mov ax,deviceParameters.DP_BPB.BPB_SectorsPerTrack + mov NumSectors,ax + +Handle_Cyln: + test switchmap,SWITCH_T + jz No_Custom_Cyln +; Set up TrackCnt and Cylinders entries correctly + mov ax,TrackCnt + mov DeviceParameters.DP_Cylinders,ax + jmp short Check_720 +No_Custom_Cyln: + mov ax,DeviceParameters.DP_Cylinders + mov TrackCnt,ax + +;****PTM P868 - Always making 3 1/2 media byte 0F0h. If 720, then set to +; 0F9h and use the DOS 3.20 BPB. Should check all drives +; at this point (Make sure not 5 inch just for future +; protection) +; We will use the known BPB info for 720 3 1/2 diskettes for +; this special case. All other new diskette media will use the +; calculations that follow Calc_Total for BPB info. +; Fix MT 11/12/86 + +Check_720: + + cmp byte ptr deviceParameters.DP_DeviceType,DEV_5INCH96TPI + je Calc_Total + + cmp byte ptr deviceParameters.DP_DeviceType,DEV_5INCH + je Calc_Total + + cmp TrackCnt,80 + jne Calc_Total + + cmp NumSectors,9 + jne Calc_Total + +; At this point we know we have a 3 1/2 720kb diskette to format. Use the +; built in BPB rather than the one handed to us by DOS, because the DOS one +; will be based on the default for that drive, and it can be different from +; what we used in DOS 3.20 for the 720's. Short sighted on our part to use +; 0F9h as the media byte, should have use 0F0h (OTHER) and then we wouldn't +; have this problem. + + SaveReg + + + mov cx,seg data ;Setup seg regs, just in case they ain't! + mov ds,cx + mov es,cx + + mov si,offset BPB720 ;Copy the BPB! + mov di,offset deviceParameters.DP_BPB + mov cx,size a_BPB + rep movsb + RestoreReg + jmp EndSwitchCheck + +;End PTM P868 fix **************************************** + +Calc_Total: + mov ax,NumSectors + mov bx,DeviceParameters.DP_BPB.BPB_Heads + mul bl ; AX = # of sectors * # of heads + mul TrackCnt ; DX:AX = Total Sectors + or dx,dx + jnz Got_BigTotalSectors + mov DeviceParameters.DP_BPB.BPB_TotalSectors,ax + jmp short Set_BPB +Got_BigTotalSectors: + mov DeviceParameters.DP_BPB.BPB_BigTotalSectors,ax + mov DeviceParameters.DP_BPB.BPB_BigTotalSectors+2,dx + push dx ; preserve dx for further use + xor dx,dx + mov DeviceParameters.DP_BPB.BPB_TotalSectors,dx + pop dx + +Set_BPB: +; We calculate the number of sectors required in a FAT. This is done as: +; # of FAT Sectors = TotalSectors / SectorsPerCluster * # of bytes in FAT to +; represent one cluster (i.e. 3/2) / BytesPerSector (i.e. 512) + xor bx,bx + mov bl,DeviceParameters.DP_BPB.BPB_SectorsPerCluster + div bx ; DX:AX contains # of clusters +; now multiply by 3/2 + mov bx,3 + mul bx + mov bx,2 + div bx + xor dx,dx ; throw away modulo +; now divide by 512 + mov bx,512 + div bx +; dx:ax contains number of FAT sectors necessary + inc ax ; Go one higher + mov DeviceParameters.DP_BPB.BPB_SectorsPerFAT,ax + mov DeviceParameters.DP_MediaType,0 + mov DeviceParameters.DP_BPB.BPB_MediaDescriptor,Custom_Media + + +EndSwitchCheck: + clc + return + +CheckSwitches endp + +;------------------------------------------------------------------------------- +; LastChanceToSaveIt: +; This routine is called when an error is detected in DiskFormat. +; If it returns with carry not set then DiskFormat is restarted. +; It gives the oem one last chance to try formatting differently. +; fLastChance gets set Then to prevent multiple prompts from being +; issued for the same diskette. +; +; Algorithm: +; IF (error_loc == Track_0_Head_1) & +; ( Device_type < 96TPI ) +; THEN +; fLastChance := TRUE +; try formatting 48TPI_Single_Sided +; ELSE return ERROR +; +LastChanceToSaveIt proc near + + cmp currentCylinder, 0 + jne WeCanNotIgnoreThisError + cmp currentHead, 1 + jne WeCanNotIgnoreThisError + + cmp deviceParameters.DP_DeviceType, DEV_5INCH + ja WeCanNotIgnoreThisError + + mov fLastChance, TRUE + + or switchmap, SWITCH_1 + call CheckSwitches + clc + ret + +WeCanNotIgnoreThisError: + stc + ret + +LastChanceToSaveIt endp + +;------------------------------------------------------------------------------- + +WriteBootSector proc near + +; Copy BPB to boot sector + lea si, deviceParameters.DP_BPB + lea di, bootBPB + mov cx, size a_BPB + push ds + pop es + repnz movsb + +; Write out the boot sector + mov al, drive + mov cx, 1 + xor dx, dx + lea bx, boot + int 26H + pop ax + jc CanNotWriteBoot + return + +CanNotWriteBoot: + lea dx, msgBootWriteError + call PrintString + stc + ret + +WriteBootSector endp + +;------------------------------------------------------------------------------- +; OemDone: +; +OemDone proc near + +; if /b write out a fake dos & bios + test switchmap, SWITCH_B + jz Switch8? + call WriteBogusDos + retc + +Switch8?: + test switchmap, SWITCH_8 + jz HardDisk? + call ConvertToOldDirectoryFormat + retc + +HardDisk?: + cmp deviceParameters.DP_DeviceType, DEV_HARDDISK + clc + retnz + call SetPartitionTable + + return + +OemDone endp + +;------------------------------------------------------------------------------ + +data segment + +biosFilename db "x:\io.sys",0 +dosFilename db "x:\msdos.sys",0 + +data ends + +; simple code to stuff bogus dos in old-style diskette. + + +BogusDos: + push cs + pop ds + mov al,20h + out 20h,al ; turn on the timer so the disk motor + mov si,mesofs ; shuts off +sys_mess_loop: + lodsb +end_sys_loop: + or al,al + jz end_sys_loop + mov ah,14 + mov bx,7 + int 16 + jmp sys_mess_loop + + include bootmes.inc + +mesofs equ no_sys_mess - BogusDos + +WriteBogusDos proc near + + mov al,driveLetter + mov biosFilename,al + mov dosFilename,al + mov cx, ATTR_HIDDEN or ATTR_SYSTEM + lea dx, biosFilename + mov ah,CREAT + int 21h + mov bx,ax + mov cx, BIOS_SIZE + push ds + push cs + pop ds + assume ds:code + lea dx, BogusDos + mov ah,WRITE + int 21h + pop ds + assume ds:data + mov ah,CLOSE + int 21h + mov cx, ATTR_HIDDEN or ATTR_SYSTEM + lea dx, dosFilename + mov ah,CREAT + int 21h + mov bx,ax + mov cx, DOS_SIZE + lea dx, BogusDos + mov ah,WRITE + int 21h + mov ah,CLOSE + int 21h +; Comunicate system size to the main format program + xor dx,dx + mov ax,DOS_SIZE + call AddToSystemSize + xor dx,dx + mov ax,BIOS_SIZE + call AddToSystemSize + + clc + return + +WriteBogusDos endp + +;------------------------------------------------------------------------------- + +ConvertToOldDirectoryFormat proc near + +; +; convert to 1.1 directory +; + mov al,drive ; Get 1st sector of directory + mov cx,1 ; 1.1 directory always starts on + mov dx,3 ; sector 3 + lea bx,scratchBuffer + int 25h + pop ax ; clean up stack + jnc DirectoryRead + lea dx, msgDirectoryReadError + call PrintString + stc + ret +DirectoryRead: + +; fix attribute of io.sys and msdos.sys + lea bx,scratchBuffer + mov byte ptr [bx].dir_attr, ATTR_HIDDEN or ATTR_SYSTEM + add bx, size dir_entry + mov byte ptr [bx].dir_attr, ATTR_HIDDEN or ATTR_SYSTEM + +wrtdir: + mov al,[drive] ; write out the directory + cbw + mov cx,1 + mov dx,3 + lea bx,scratchBuffer + int 26h + pop ax ; clean up stack + jnc DirectoryWritten + lea dx, msgDirectoryWriteError + call PrintString + stc + ret +DirectoryWritten: + + test switchmap, SWITCH_S ; Was system requested? + retnz ; yes, don't write old boot sector + mov al,drive + cbw + mov bx,offset boot2 ; no, write old boot sector + cmp deviceParameters.DP_BPB.BPB_Heads, 1 + je bootset8 + mov word ptr [bx+3],0103h ; start address for double sided drives +bootset8: + mov cx,1 + xor dx,dx + int 26h ; write out that boot sector + pop ax + retnc + + lea dx, msgBootWriteError + call PrintString + stc + ret + +ConvertToOldDirectoryFormat endp + +;------------------------------------------------------------------------------- + +a_PartitionTableEntry struc +BootInd db ? +BegHead db ? +BegSector db ? +BegCylinder db ? +SysInd db ? +EndHead db ? +EndSector db ? +EndCylinder db ? +RelSec dd ? +CSec dd ? +a_PartitionTableEntry ends + +; structure of the IBM hard disk boot sector: +IBMBoot STRUC + db 512 - (4*size a_PartitionTableEntry + 2) dup(?) +PartitionTable db 4*size a_PartitionTableEntry dup(?) +Signature dw ? +IBMBoot ENDS + + +SetPartitionTable proc near + + mov ax, 0 ; Head + mov bx, 0 ; Cylinder + mov cx, 0 ; Sector + lea dx, boot2 + call ReadSector + jnc PartitionTableRead + lea dx, msgPartitionTableReadError + call PrintString + stc + ret +PartitionTableRead: + +; Check to see if there is a partition table (by looking for its signature) + cmp boot2.signature, 0aa55H + jne BadPartitionTable + +; Scan all the partitions search for the FIRST DOS partition. We then set the +; appropriate FAT size in the FIRST DOS partition and return. + + lea bx, boot2.PartitionTable +partitionscan: + +; have we scanned all partitions? + cmp bx,(offset Boot2.PartitionTable)+4*size a_PartitionTableEntry + jae BadPartitionTable + + cmp [bx].sysind,1 + jz dochange + cmp [bx].sysind,4 + jz dochange + + add bx,size a_PartitionTableEntry + jmp partitionscan + +dochange: + mov [bx].sysind,4 ; assume 16 bit fat + cmp fbigfat,0 ; test assumption + jnz partitionset ; is 16 bit fat, assumption correct + mov [bx].sysind,1 ; 12 bit fat, pre 3.0 dos can read it + +partitionset: + mov ax, 0 ; Head + mov bx, 0 ; Cylinder + mov cx, 0 ; Sector + lea dx, boot2 + call WriteSector + retnc + + lea dx, msgPartitionTableWriteError + call PrintString + stc + ret + +BadPartitionTable: + lea dx, msgBadPartitionTable + call PrintString + stc + ret + +SetPartitionTable endp + +;------------------------------------------------------------------------------- +; ReadSector: +; Read one sector +; +; Input: +; ax - head +; bx - cylinder +; cx - sector +; dx - transfer address + +ReadSector proc near + + mov TrackReadWritePacket.TRWP_FirstSector, cx + mov cx,(RAWIO shl 8) or READ_TRACK + call SectorIO + return + +ReadSector endp + +;------------------------------------------------------------------------------- +; WriteSector: +; Write one sector +; +; Input: +; ax - head +; bx - cylinder +; cx - sector +; dx - transfer address + +WriteSector proc near + + mov TrackReadWritePacket.TRWP_FirstSector, cx + mov cx,(RAWIO shl 8) or WRITE_TRACK + call SectorIO + return + +WriteSector endp + +;------------------------------------------------------------------------------- +; SectorIO: +; Read/Write one sector +; +; Input: +; ax - head +; bx - cylinder +; cx - (RAWIO shl 8) or READ_TRACK +; - (RAWIO shl 8) or WRITE_TRACK +; dx - transfer address + +SectorIO proc near + + mov TrackReadWritePacket.TRWP_Head, ax + mov TrackReadWritePacket.TRWP_Cylinder, bx + mov WORD PTR TrackReadWritePacket.TRWP_TransferAddress, dx + mov WORD PTR TrackReadWritePacket.TRWP_TransferAddress + 2, ds + mov TrackReadWritePacket.TRWP_SectorsToReadWrite, 1 + + mov bl, drive + inc bl + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + lea dx, trackReadWritePacket + int 21H + return + +SectorIO endp + +;------------------------------------------------------------------------------- + +data segment + +oldDrive db ? + +FCBforVolumeIdSearch db 0ffH + db 5 dup(0) + db 08H + db 0 + db "???????????" + db 40 DUP(0) + +data ends + +GetVolumeId proc near +; Input: +; dl = drive +; di = name buffer + +; Save current drive + mov ah,19H + int 21H + mov oldDrive, al + +; Change current drive to the drive that has the volume id we want + mov ah, 0eH + int 21H + +; Search for the volume id + mov ah, 11H + lea dx, FCBforVolumeIdSearch + int 21H + push ax + +; Restore current drive + mov ah, 0eH + mov dl,oldDrive + int 21H + +; Did the search succeed? + pop ax + or al,al + jz CopyVolumeId + stc + ret + +CopyVolumeId: +; Find out where the FCB for the located volume id was put + mov ah,2fH + int 21H + +; Copy the Volume Id + mov si, bx + add si, 8 + push es + push ds + pop es + pop ds + mov cx, 11 + rep movsb + push es + pop ds + + clc + ret + +GetVolumeId endp + +data segment +oldVolumeId db 11 dup(0) +data ends + +CheckVolumeId proc near + +; Get the volume id that's on the disk + lea di, oldVolumeId + mov dl, drive + call GetVolumeId + jnc Ask_User ;Did we find one? + clc ;No, return with no error + ret + +; Ask the user to enter the volume id that he/she thinks is on the disk +; (first blank out the input buffer) +Ask_User: + lea dx, ptr_msgWhatIsVolumeId? + call std_printf + call user_string + call crlf + +; If the user just pressed ENTER, then there must be no label + cmp inbuff+1, 0 + jne CompareVolumeIds + cmp oldVolumeId, 0 + jne BadVolumeId + ret + +CompareVolumeIds: +; pad the reponse with blanks +; The buffer is big enough so just add 11 blanks to what the user typed in + push ds + pop es + mov cx, 11 + xor bx,bx + mov bl, inbuff + 1 + lea di, inbuff + 2 + add di, bx + mov al, ' ' + rep stosb +; Make the reply all uppercase + mov cl, inbuff + 1 + xor ch,ch + lea si, inbuff + 2 +VolumeToUpper: + mov al, [si] + cmp al, 'a' + jb NextLetter + cmp al, 'z' + ja NextLetter + sub al, 'a' - 'A' + mov [si],al +NextLetter: + inc si + loop VolumeToUpper + +; Now compare what the user specified with what is really out there + mov cx, 11 + lea si, inbuff + 2 + lea di, oldVolumeId + repe cmpsb + jne BadVolumeId + ret + +BadVolumeId: + lea dx, msgBadVolumeId + call PrintString + stc + ret + +CheckVolumeId endp + +code ends + end diff --git a/SRC/CMD/MAKEFILE b/SRC/CMD/MAKEFILE new file mode 100644 index 0000000..646367a --- /dev/null +++ b/SRC/CMD/MAKEFILE @@ -0,0 +1,14 @@ +make=msmake /I makefile + +all: + cd format + $(make) + cd ..\print + $(make) + cd ..\sort + $(make) + cd ..\sys + $(make) + cd .. + + \ No newline at end of file diff --git a/SRC/CMD/PRINT/MAKEFILE b/SRC/CMD/PRINT/MAKEFILE new file mode 100644 index 0000000..725a25f --- /dev/null +++ b/SRC/CMD/PRINT/MAKEFILE @@ -0,0 +1,61 @@ +#** makefile for print + +DEST =print +MSG =messages + +# Path definitions + +BIOS =..\..\BIOS +DOS =..\..\DOS + +# Definitions for assembler + +ASM =masm +AFLAGS =-Mx -t +AINC =-I..\..\inc -I$(DOS) + +# Definitions for C compiler + +CC =cl +CFLAGS =-c -Ox -Zlp +CINC =-I..\..\h + +# Definitions for linker + +LINK =link +LIBC =..\..\libc + + +# Rules and Dependencies follow + +PRINT_RM.OBJ: PRINT_RM.ASM print_rm.inc PRIDEFS.inc \ + $(DOS)\DEVSYM.INC $(DOS)\SYSCALL.INC $(DOS)\ERROR.INC \ + $(DOS)\SYSVAR.INC $(DOS)\FIND.INC + masm $(AFLAGS) $(AINC) PRINT_RM; + +PRINT_R.OBJ: PRINT_R.ASM PRIDEFS.inc \ + $(DOS)\DEVSYM.INC $(DOS)\SYSCALL.INC $(DOS)\ERROR.INC \ + $(DOS)\SYSVAR.INC $(DOS)\FIND.INC + masm $(AFLAGS) $(AINC) PRINT_R; + +PRINT_T.OBJ: PRINT_T.ASM PRIDEFS.inc \ + $(DOS)\DEVSYM.INC $(DOS)\SYSCALL.INC $(DOS)\ERROR.INC \ + $(DOS)\SYSVAR.INC $(DOS)\FIND.INC + masm $(AFLAGS) $(AINC) PRINT_T; + +PRINT_TM.OBJ: PRINT_TM.ASM print_tm.inc PRIDEFS.inc \ + $(DOS)\DEVSYM.INC $(DOS)\SYSCALL.INC $(DOS)\ERROR.INC \ + $(DOS)\SYSVAR.INC $(DOS)\FIND.INC + masm $(AFLAGS) $(AINC) PRINT_TM; + +NPRINTF.OBJ: NPRINTF.ASM PRIDEFS.inc \ + $(DOS)\DEVSYM.INC $(DOS)\SYSCALL.INC $(DOS)\ERROR.INC \ + $(DOS)\SYSVAR.INC $(DOS)\FIND.INC + masm $(AFLAGS) $(AINC) NPRINTF; + +PRINT.EXE: PRINT_RM.OBJ PRINT_R.OBJ PRINT_T.OBJ \ + PRINT_TM.OBJ NPRINTF.OBJ + LINK @PRINT.LNK + CONVERT PRINT.EXE + DEL PRINT.EXE + \ No newline at end of file diff --git a/SRC/CMD/PRINT/NPRINTF.ASM b/SRC/CMD/PRINT/NPRINTF.ASM new file mode 100644 index 0000000..b80cef7 --- /dev/null +++ b/SRC/CMD/PRINT/NPRINTF.ASM @@ -0,0 +1,386 @@ +; SCCSID = @(#)nprintf.asm 4.1 85/07/17 + INCLUDE pridefs.inc + + +BREAK + +; +; MSDOS V3.00 PRINT +; +; Message Printing Routine +; + + +DATA SEGMENT PUBLIC BYTE + + extrn crlf_ptr:word + +Public NPR001S, NPR001E +NPR001S equ $ + +PRINTF_LEFT DB 0 +PRINTF_LONG DB 0 +PRINTF_HEX DB 0 +TABLE_INDEX DB 0 +S_FLAG DB 0 +PRINTF_WIDTH DW 0 +PRINTF_BASE DW 0 +PAD_CHAR DB " " + +PRINTF_TABLE DB "0123456789ABCDEFabcdef" + +PRINTF_STACK STRUC +OLDES DW ? +OLDDS DW ? +OLDSI DW ? +OLDDI DW ? +OLDAX DW ? +OLDBX DW ? +OLDCX DW ? +OLDBP DW ? +STRING DW ? +OLDCS DW ? +PRINTF_STACK ENDS + +PRINTF_ARGS STRUC +CONSTR DW ? +ARG DW ? +PRINTF_ARGS ENDS + +BUFSIZ EQU 20 +PRINTF_BUF DB BUFSIZ DUP (?) + db 0 ;This buffer is always nul terminated +BUFEND DW $-PRINTF_BUF + +NPR001E equ $ + +DATA ENDS + + +Code Segment public para + +ASSUME CS:DG,DS:nothing,ES:nothing,SS:Stack + + PUBLIC PRINTF,STD_PRINTF,PRINTF_CRLF + +PRINTF_CRLF: + CALL STD_PRINTF +crlf2: + mov dx,offset dg:crlf_ptr +STD_PRINTF: + PUSH DX +PRINTF: + PUSH BP ;Save the callers' registers + PUSH CX + PUSH BX + PUSH AX + PUSH DI + PUSH SI + PUSH ES + PUSH DS + MOV BP,SP + PUSH CS + POP ES ;ES points to Printf segment + CALL Clear_flags ; initialize the world + + MOV DI,DS + MOV SI,ES + CMP SI,DI + JZ S + HLT +S: + + MOV DI,OFFSET DG:PRINTF_BUF ;DI points to the output buffer + MOV BP,[BP.STRING] ;BP points to the argument list + MOV SI,DS:[BP] ;SI points to the control string + XOR BX,BX ;BX is the index into the arg list +GET_CHAR: + LODSB ;Get a character + CMP AL,"%" ;Is it a conversion specifier? + JZ CONV_CHAR ;Yes - find out which one + OR AL,AL ;Is it the end of the control string? + JZ PRINTF_DONE ;Yes - then we're done + CALL OUTCHR ;Otherwise store the character + JMP SHORT GET_CHAR ;And go get another + +PRINTF_DONE: + CALL FLUSH + POP DS + POP ES + POP SI + POP DI + POP AX + POP BX + POP CX + POP BP + POP DX + RET + +PRINTF_PERCENT: + CALL OUTCHR + JMP GET_CHAR + +CONV_CHAR: + ;Look for any format specifiers preceeding the conversion character + LODSB + CMP AL,"%" ;Just print the % + JZ PRINTF_PERCENT + CMP AL,"-" ;Right justify the field + JZ LEFT_ADJ + CMP AL,"+" ;Left justify the field + JZ NXT_CONV_CHAR + CMP AL,"L" ;Is it a long integer + JZ LONG_INT + CMP AL,"l" + JZ LONG_INT + CMP AL,"0" ;Is it a precision specification + JB LOOK_CONV_CHAR + CMP AL,"9" + JA LOOK_CONV_CHAR + CMP AL,"0" + JNZ NOT_PAD + CMP CS:[PRINTF_WIDTH],0 + JNZ NOT_PAD + MOV CS:BYTE PTR [PAD_CHAR],"0" +NOT_PAD: + PUSH AX ;Adjust decimal place on precision + MOV AX,10 + MUL CS:[PRINTF_WIDTH] + MOV CS:[PRINTF_WIDTH],AX + POP AX + XOR AH,AH + SUB AL,"0" + ADD CS:[PRINTF_WIDTH],AX ;And save the total + JMP SHORT NXT_CONV_CHAR + + ;Set the correct flags for the options in a conversion + +LEFT_ADJ: + INC CS:BYTE PTR[PRINTF_LEFT] + JMP SHORT NXT_CONV_CHAR + +LONG_INT: + INC CS:BYTE PTR[PRINTF_LONG] +NXT_CONV_CHAR: + JMP CONV_CHAR + + ;Look for a conversion character + +LOOK_CONV_CHAR: + CMP AL,"X" + JZ HEX_UP + + ;Make all other conversion characters upper case + + CMP AL,"a" + JB CAPS + CMP AL,"z" + JG CAPS + AND AL,0DFH +CAPS: + CMP AL,"X" + JZ HEX_LO + CMP AL,"D" + JZ DECIMAL + CMP AL,"C" + JZ C_PUT_CHAR + CMP AL,"S" + JZ S_PUT_STRG + + ;Didn't find any legal conversion character - IGNORE it + + call clear_flags + jmp get_char + +HEX_LO: + MOV CS:[TABLE_INDEX],6 ;Will print lower case hex digits +HEX_UP: + MOV CS:[PRINTF_BASE],16 ;Hex conversion + JMP CONV_TO_NUM + +DECIMAL: + MOV CS:[PRINTF_BASE],10 ;Decimal conversion + JMP CONV_TO_NUM + +S_PUT_STRG: + INC CS:[S_FLAG] ;It's a string specifier +C_PUT_CHAR: + PUSH SI ;Save pointer to control string + MOV SI,BX + ADD BX,2 + MOV SI,ds:[BP+SI.ARG] ;Point to the % string or character + CMP BYTE PTR CS:[S_FLAG],0 + JNZ S_PUT_1 + LODSB + cmp al,0 + jz short c_s_end + CALL OUTCHR ;Put it into our buffer + JMP SHORT C_S_END + +S_PUT_1: + mov cx,cs:[printf_width] + or cx,cx + jz s_put_2 + cmp cs:byte ptr[printf_left],0 + jnz s_put_2 + push si + call Pad_string + pop si +s_put_2: + push si +s_put_3: + LODSB ;Put them all in our buffer + CMP AL,0 + jz s_put_4 + CALL OUTCHR + jmp short S_PUT_3 +s_put_4: + pop si + cmp byte ptr[printf_left],0 + jz c_s_end + mov cx,cs:[printf_width] + or cx,cx + jz c_s_end + call Pad_string +C_S_END: + call clear_flags + POP SI ;Restore control string pointer + JMP GET_CHAR ;Go get another character + +pad_string: + xor dx,dx +count_loop: + lodsb + or al,al + jz count_done + inc dx + jmp short count_loop +count_done: + sub cx,dx + jbe count_ret + call pad +count_ret: + ret + +CONV_TO_NUM: + + PUSH SI ;Save pointer to control string + MOV SI,BX ;Get index into argument list + ADD BX,2 ;Increment the index + MOV AX,ds:[BP+SI.ARG] ;Lo word of number in SI + CMP BYTE PTR CS:[PRINTF_LONG],0 ;Is this is a short or long integer? + JZ NOT_LONG_INT + MOV SI,BX ;Copy index + ADD BX,2 ;Increment the index + MOV DX,ds:[BP+SI.ARG] ;Hi word of number in BP + JMP SHORT DO_CONV +NOT_LONG_INT: + XOR DX,DX ;Hi word is zero +DO_CONV: + PUSH BX ;Save index into arguemnt list + MOV si,CS:[PRINTF_BASE] + MOV cx,CS:[PRINTF_WIDTH] + CALL PNUM + CALL PAD +CONV_DONE: + call clear_flags + POP BX + POP SI + jmp get_char + +PNUM: + DEC CX + PUSH AX + MOV AX,DX + XOR DX,DX + DIV SI + MOV BX,AX + POP AX + DIV SI + XCHG BX,DX + PUSH AX + OR AX,DX + POP AX + JZ DO_PAD + PUSH BX + CALL PNUM + POP BX + JMP SHORT REM +DO_PAD: + CMP CS:BYTE PTR[PRINTF_LEFT],0 + JNZ REM + CALL PAD +REM: + MOV AX,BX + CMP AL,10 + JB NOT_HEX + CMP CS:BYTE PTR [PRINTF_HEX],0 + JNZ NOT_HEX + ADD AL,CS:BYTE PTR [TABLE_INDEX] +NOT_HEX: + MOV BX,OFFSET dg:PRINTF_TABLE + PUSH DS + PUSH CS + POP DS + XLAT 0 + POP DS + push cx + CALL OUTCHR + pop cx + RET + +PAD: + OR CX,CX + JLE PAD_DONE + MOV AL,CS:BYTE PTR [PAD_CHAR] +PAD_LOOP: + push cx + CALL OUTCHR + pop cx + LOOP PAD_LOOP +PAD_DONE: + RET + +OUTCHR: + STOSB + CMP DI,offset dg:bufend-1 ;Don't count the nul + jz foob2 + ret +foob2: + MOV CX,BUFSIZ +WRITE_CHARS: + push bx + MOV BX,1 + push ds + PUSH CS + POP DS + MOV DX,OFFSET dg:PRINTF_BUF + MOV AH,WRITE + INT 21H + pop ds + pop bx + MOV DI,OFFSET dg:PRINTF_BUF + RET + +FLUSH: + CMP DI,OFFSET dg:PRINTF_BUF + jnz foob1 + ret +foob1: + SUB DI,OFFSET dg:PRINTF_BUF + MOV CX,DI + call write_chars + ret + +CLEAR_FLAGS: + XOR ax,ax + MOV BYTE PTR CS:[PRINTF_LEFT],al ;Reset justifing flag + MOV BYTE PTR CS:[PRINTF_LONG],al ;Reset long flag + MOV BYTE PTR CS:[TABLE_INDEX],al ;Reset hex table index + MOV CS:[PRINTF_WIDTH],ax ;Reinitialize width to 0 + MOV BYTE PTR CS:[PAD_CHAR]," " ;Reset padding character + MOV BYTE PTR CS:[S_FLAG],al ;Clear the string flag + ret + +Code Ends + End diff --git a/SRC/CMD/PRINT/PRIDEFS.INC b/SRC/CMD/PRINT/PRIDEFS.INC new file mode 100644 index 0000000..00d5a99 --- /dev/null +++ b/SRC/CMD/PRINT/PRIDEFS.INC @@ -0,0 +1,213 @@ +; SCCSID = @(#)pridefs.asm 4.4 85/07/17 +title 3.00 Print Utility + +;MS-DOS PSPRINT/PRINT program for background printing of text files +; to the list device. +; +; IBM SERVER VERSION +; +; INT 28H is a software interrupt generated by the DOS +; in its I/O wait loops. This spooler can be assembled for +; operation using only this interrupt which is portable from +; system to system. It may also be assembled to use a hardware +; timer interrupt in addition to the software INT 28H. The +; purpose of using hardware interrupts is to allow printing to +; continue during programs which do not enter the system and +; therefore causes the INT 28H to go away. A timer interrupt is +; chosen in preference to a "printer buffer empty" interrupt +; because PRINT in the timer form is generic. It can be given +; the name of any currently installed character device as the +; "printer", this makes it portable to devices which are +; installed by the user even in the hardware case. It could be +; modified to use a buffer empty interrupt (no code is given for +; this case), if this is done the PROMPT and BADMES messages and +; their associated code should be removed as PRINT will then be +; device specific. +; +; V1.00 07/03/82 +; V2.00 07/05/83 A.Reynolds +; New INT 2FH interface, Pathnames, context switch. +; V2.50 09/14/83 M.A.Ulloa +; Turned it back to a print +; 11/21/83 M.A.Ulloa +; Repaired bug in file cancel code +; 11/28/83 M.A.Ulloa +; Added int 23 and 24 handlers to transient. +; 01/27/84 M.A.Ulloa +; Allways checks for valid drive. +; V3.00 02/03/84 M.A.Ulloa +; Partitioned so as to assemble on a PC +; By the by, it is V3.00 now. +; 05/23/85 K.G.Schulmeisters +; Chains into INT19 (bootstrap) to unhook +; INT_1C (timer) and INT_15 (AT's Wait On Event) +; + + +; Aaron's rambling: +; +; BEWARE ALL YEE WHO ENTER HERE. +; PRINT is an amazingly complex program. MS-DOS versions below 3.00 are +; NOT re-entrant, this means that this utility is basically not a +; possibility. It gets by on the fact that it is written by the same +; person who wrote the OS. Since you are not that person, you must be very +; careful about making any modification to this utility. There are a +; number of things which may seem to be unnecessary on first examination. +; BEWARE, almost every line of code is there for a very good reason. The +; order of things is very carefully chosen. PRINT is full of potential +; windows, make sure that you do not open one by careless modification. Do +; not look for a lot of help from the comments, a complete explanation +; would probably fill a book. A succesful modifier will have an in-depth +; knowledge of the internal function of MS-DOS, and of the PRINT utility +; itself through in depth study of the comments AND the code. + + +subttl General Definition +page + + +FALSE EQU 0 +TRUE EQU NOT FALSE + +;IBM EQU TRUE +;IBMVER EQU IBM +;MSVER EQU FALSE + +include version.inc + + IF MSVER +HARDINT EQU FALSE ;No hardware ints +AINT EQU FALSE ;No need to do interrupt acknowledge + ENDIF + + IF IBM +HARDINT EQU TRUE +INTLOC EQU 1CH ;Hardware interrupt location (Timer) +REBOOT EQU 19H ;ROM BIOS "Bootstrap" +AINT EQU TRUE ;Acknowledge interrupts +EOI EQU 20H ;End Of Interrupt "instruction" +AKPORT EQU 20H ;Interrupt Acknowledge port + ENDIF + +; The following values have to do with the ERRCNT variable and the CNTMES +; message. The values define levels at wich it is assumed an off-line error +; exists. ERRCNT1 defines the value of ERRCNT above which the CNTMES message +; is printed by the transient. ERRCNT2 defines the value of ERRCNT above +; which the resident will give up trying to print messages on the printer, it +; is much greater than ERRCNT1 because a much tighter loop is involved. The +; bounding event which determines the correct value is the time required to +; do a form feed. + + IF IBM +ERRCNT1 EQU 1500 +ERRCNT2 EQU 20000 + ELSE +ERRCNT1 EQU 1500 +ERRCNT2 EQU 20000 + ENDIF + + +;WARNING DANGER WARNING: +; PRINT is a systems utility. It is clearly understood that it may have +; to be entirely re-written for future versions of MS-DOS. The following +; TWO vectors are version specific, they may not exist at all in future +; versions. If they do exist, they may function differently. +; ANY PROGRAM WHICH IMITATES PRINTS USE OF THESE VECTORS IS ALSO A SYSTEMS +; UTILITY AND IS THEREFORE NOT VERSION PORTABLE IN ANY WAY SHAPE OR FORM. +; YOU HAVE BEEN WARNED, "I DID IT THE SAME WAY PRINT DID" IS NOT AN REASON +; TO EXPECT A PROGRAM TO WORK ON FUTURE VERSIONS OF MS-DOS. + +SOFTINT EQU 28H ;Software interrupt generated by DOS +ComInt EQU 2FH ;Communications interrupt used by PSPRINT + ; Multiplex number 0 and 1 + +;----- Default (and Minimal) Print queue length +DefQueueLen equ 10 ; 10 files worth +MinQueueLen equ 4 ; 4 files worth min +MaxQueueLen equ 32 ; 32 files worth max. + +;----- Maximum length of a file name (incl nul) +MaxFileLen equ 64 + +; **************** Bogosity Warning ***************** +; Below is the equate that MaxFile SHOULD be. Since the 3.0/3.1 documentation +; documents each queue entry as being 64 chars long. Yes it is known that +; that causes Print to misbehave on files deep in trees. But for +; compatibilities sake, IBM insisted that we change the code back to the +; way it was. +;MaxFileLen equ 63 + 2 + 12 ; 63 characters as Command.com's + ; max. path length + ; 2 character for the Drive ext. + ; 12 characters for the max. valid + ; DOS filename + + +.xlist +.xcref +BREAK MACRO subtitle + SUBTTL subtitle + PAGE +ENDM + +stdin EQU 0 +stdout EQU 1 +stderr EQU 2 +stdaux EQU 3 +stdprn EQU 4 + + INCLUDE DEVSYM.INC + INCLUDE SYSCALL.INC + INCLUDE ERROR.INC + INCLUDE SYSVAR.INC + INCLUDE FIND.INC + include dpl.inc + INCLUDE PDB.INC + INCLUDE SYSCALL.INC + INCLUDE MI.INC + include versiona.inc +.list +.cref + + +error_busy EQU 9 +error_queue_full EQU 8 +error_name_too_long EQU 12 + +IF1 + IF IBM + %out IBM VERSION + ELSE + %out MS-DOS VERSION + ENDIF +ENDIF + +BREAK + + +CodeR Segment public para +CodeR EndS + +Code Segment public para +Code EndS + +Data Segment public byte +Data EndS + +Stack Segment Stack +Stack Ends + +DG group Code,Data,Stack + +SaveReg MACRO reglist ;; push those registers +IRP reg, + PUSH reg +ENDM +ENDM +.xcref SaveReg + +RestoreReg MACRO reglist ;; pop those registers +IRP reg, + POP reg +ENDM +ENDM + \ No newline at end of file diff --git a/SRC/CMD/PRINT/PRINT.LNK b/SRC/CMD/PRINT/PRINT.LNK new file mode 100644 index 0000000..d93ea65 --- /dev/null +++ b/SRC/CMD/PRINT/PRINT.LNK @@ -0,0 +1,2 @@ +PRINT_RM PRINT_R PRINT_T PRINT_TM NPRINTF +PRINT.EXE /m; diff --git a/SRC/CMD/PRINT/PRINT_R.ASM b/SRC/CMD/PRINT/PRINT_R.ASM new file mode 100644 index 0000000..f220d40 --- /dev/null +++ b/SRC/CMD/PRINT/PRINT_R.ASM @@ -0,0 +1,2189 @@ +; SCCSID = @(#)print_r.asm 4.7 85/09/13 + INCLUDE pridefs.inc + + +BREAK + +; +; MSDOS V3.00 PRINT +; +; Resident Portion +; + +Code Segment public para + extrn TransRet:WORD,TransSize:WORD +Code EndS + + + +BREAK + +CodeR Segment public para + + extrn ERRMES:BYTE, ERRMEST:BYTE, BELMES:BYTE, ErrMesT2:BYTE + extrn CanMes:BYTE, CanFilNAm:BYTE, AllCan:BYTE, ERR0:BYTE + extrn ERR1:BYTE, ERR2:BYTE, ERR3:BYTE, ERR4:BYTE, ERR5:BYTE + extrn ERR6:BYTE, ERR7:BYTE, ERR8:BYTE, ERR9:BYTE, ERR10:BYTE + extrn ERR11:BYTE, ERR12:BYTE, FATMES:BYTE, BADDRVM:BYTE, + extrn BADMES:BYTE, badmeslen:WORD, GOODMES:BYTE, goodmeslen:WORD + +if hardint + public SliceCnt, BusyTick, MaxTick, TimeSlice +endif + + public EndRes, BlkSiz, QueueLen, PChar + public ListName, FileQueue, EndQueue, Buffer + public EndPtr, NxtChr, MoveTrans + +assume CS:CodeR + +public PRNR001S,PRNR001E +PRNR001S: + db "*** Microsoft/V310 ***" + + DB (362 - 80h) + 310 DUP (?) ; (362 - 80h) is IBM's New + ; recommended Stack Size - + ; Old recommended Stack Size + ; == New stack growth +ISTACK LABEL WORD ;Stack starts here and grows down the + +;Resident data + +; +; Due to flagrant bogosity by file servers, BUSY is *ALWAYS* relevant. +; +BUSY DB 0 ;Internal ME flag + + IF HARDINT +; +; WARNING!!! The *&^%(*&^ 286 chip hangs if you access a word that will wrap +; at the segment boundary. Make the initial INDOS point somewhere reasonable. +; +INDOS DD TimeSlice ;DOS buisy flag +NEXTINT DD ? ;Chain for int +NEXT_REBOOT DD ? ;Chain for ROM bootstrap + +fFake db 0 ; TRUE => do not diddle I/O ports +SOFINT DB 0 ;Internal ME flag +TICKCNT DB 0 ;Tick counter +TICKSUB DB 0 ;Tick miss counter +SLICECNT DB 8 ;Time slice counter, init to same val + ; as TIMESLICE + +TIMESLICE DB 8 ;The PRINT scheduling time slice. PRINT + ; lets this many "ticks" go by before + ; using a time slice to pump out characters. + ; Setting this to 3 for instance means PRINT + ; Will skip 3 slices, then take the fourth. + ; Thus using up 1/4 of the CPU. Setting it + ; to one gives PRINT 1/2 of the CPU. + ; The above examples assume MAXTICK is + ; 1. The actual PRINT CPU percentage is + ; (MAXTICK/(1+TIMESLICE))*100 + +MAXTICK DB 2 ;The PRINT in timeslice. PRINT will pump + ; out characters for this many clock ticks + ; and then exit. The selection of a value + ; for this is dependent on the timer rate. + +BUSYTICK DB 1 ;If PRINT sits in a wait loop waiting for + ; output device to come ready for this + ; many ticks, it gives up its time slice. + ; Setting it greater than or equal to + ; MAXTICK causes it to be ignored. + +;User gets TIMESLICE ticks and then PRINT takes MAXTICK ticks unless BUSYTICK +; ticks go by without getting a character out. + ENDIF + +QueueLen db DefQueueLen ; Actual length of print queue + even +EndQueue dw ? ; pointer to end of print queue +QueueTail dw offset CodeR:FileQueue ; pointer to next free entry + ; in the print queue +buffer dw ? ; pointer to data buffer + +I24_ERR DW ? ;Save location for INT 24H error code +Ctrlc DB ? ; saved ^C trapping state +SPNEXT DD ? ;Chain location for INT 28 +COMNEXT DD ? ;Chain location for INT 2F +SSsave DW ? ;Stack save area for INT 24 +SPsave DW ? +HERRINT DD ? ;Place to save Hard error interrupt +LISTDEV DD ? ;Pointer to Device +COLPOS DB 0 ;Column position for TAB processing +CURRFIL DB 0 +NXTCHR DW ? +CURRHAND DW -1 +PrinterNum DW -1 ; index for printer +QueueLock db 0 ; queue lock, 0=unlocked + + +PChar db ? ; path character +AmbCan db ? ; = 1 ambigous cancel +CanFlg db ? ; = 1 Current was already canceled +ACanOcrd db ? ; = 1 a file was found during an + ; ambigous cancel + +;--- Warnning: this is a FCB!! +ACBuf db ? +ACName db 8 dup(?) +ACExt db 3 dup(?) + db 4 dup(?) ; how big is an unopened fcb??? + + +CONTXTFLAG DB 0 ;0 means his context, NZ means me +HISPDB DW ? +PABORT DB 0 ;Abort flag +BLKSIZ DW 512 ;Size of the PRINT I/O block in bytes +ENDPTR DW ? + +COMDISP LABEL WORD ; Communications dispatch table + DW OFFSET CodeR:INST_REQ + DW OFFSET CodeR:ADDFIL + DW OFFSET CodeR:CANFIL + DW offset CodeR:CanAll + DW OFFSET CodeR:QSTAT + DW offset CodeR:EndStat + DW offset CodeR:QSTATDEV + +;Resident messages + +MESBAS DW OFFSET CodeR:ERR0 + DW OFFSET CodeR:ERR1 + DW OFFSET CodeR:ERR2 + DW OFFSET CodeR:ERR3 + DW OFFSET CodeR:ERR4 + DW OFFSET CodeR:ERR5 + DW OFFSET CodeR:ERR6 + DW OFFSET CodeR:ERR7 + DW OFFSET CodeR:ERR8 + DW OFFSET CodeR:ERR9 + DW OFFSET CodeR:ERR10 + DW OFFSET CodeR:ERR11 + DW OFFSET CodeR:ERR12 +ENDRES DW ? ; filled in at initialization time +PRNR001E: + +CodeR EndS + + + +BREAK + +CodeR Segment public para + +Break + +TestSetServer: +IF IBM + CLC + PUSH AX + MOV AX,8700h ; Can I run? + INT 2Ah + POP AX +ENDIF + ret + +LeaveServer: +IF IBM + PUSH AX + MOV AX,8701h + INT 2Ah + POP AX +ENDIF + ret + +;Interrupt routines +ASSUME CS:CodeR,DS:NOTHING,ES:NOTHING,SS:NOTHING +; +; PRINT is stimulated by a hardware interrupt. +; +; +; The Server may also stimulate us during timer ticks (if we handled the +; ticks ourselves, it would be disasterous. Therefore, we have a substitute +; entry here that simulates the timer stuff but does NOT muck with the ports. +; + IF HARDINT +FakeINT1C: + MOV fFake,-1 + JMP SHORT InnerHardInt + +HDSPINT: ;Hardware interrupt entry point + mov fFake,0 +InnerHardInt: + CALL TestSetServer + JNC TickTime + jmp ChainInt +TickTime: + INC [TICKCNT] ;Tick + INC [TICKSUB] ;Tick + CMP [SLICECNT],0 + JZ TIMENOW + DEC [SLICECNT] ;Count down + JMP SHORT HardIntDone ;Not time yet +TIMENOW: + CMP BUSY,0 ;See if interrupting ourself + JNZ HardIntDone + + IF IBM + push ax ; check for nested interrupts + mov al,00001011b ; select ISR in 8259 + out 20H,al + JMP x +x: + in al,20H ; get ISR register + and al,0FEH ; mask timer int + pop ax + jnz HardIntDone ; there was another int in service... + ENDIF + + PUSH DS + PUSH SI + LDS SI,[INDOS] ;Check for making DOS calls +; +; WARNING!!! Due to INT 24 clearing the INDOS flag, we must test both INDOS +; and ERRORMODE at once! These must be contiguous in MSDATA. +; + CMP WORD PTR [SI-1],0 + POP SI + POP DS + JNZ HardIntDone ;DOS is Busy + INC [BUSY] ;Exclude furthur interrupts + MOV [TICKCNT],0 ;Reset tick counter + MOV [TICKSUB],0 ;Reset tick counter + STI ;Keep things rolling + + IF AINT + TEST fFake,-1 + JNZ NoAck + PUSH AX + MOV AL,EOI ;Acknowledge interrupt + OUT AKPORT,AL + POP AX +NoAck: + ENDIF + + CALL DOINT + CLI + PUSH AX + MOV AL,[TIMESLICE] + MOV [SLICECNT],AL ;Either soft or hard int resets time slice + POP AX + DEC Busy ;Done, let others in +HardIntDone: + Call LeaveServer +CHAININT: + TEST fFake,-1 + JNZ DoIRET + JMP [NEXTINT] ;Chain to next clock routine +DoIRET: + IRET + ENDIF + + +; +; PRINT is stimulated by a spooler idle interrupt +; +SPINT: ;INT 28H entry point + CALL TestSetServer + JC NxtSp + + IF HARDINT + CMP [BUSY],0 + JNZ SpIntDone + INC [BUSY] ;Exclude hardware interrupt + INC [SOFINT] ;Indicate a software int in progress + ENDIF + + STI ;Hardware interrupts ok on INT 28H entry + CALL DOINT + + IF HARDINT + CLI + MOV [SOFINT],0 ;Indicate INT done + PUSH AX + MOV AL,[TIMESLICE] + MOV [SLICECNT],AL ;Either soft or hard int resets time slice + POP AX + DEC Busy + ENDIF +SpIntDone: + call LeaveServer + +NXTSP: JMP [SPNEXT] ;Chain to next INT 28 + +; +; Since we may be entering at arbitrary times, we need to get/set the extended +; error as we may end up blowing it away. We do not do this on spooler ints. +; + +public PRNR002S, PRNR002E +PRNR002S: + +SaveState DPL <> ; empty DPL + +PRNR002E: + +public enterprint +EnterPRINT: + IF HardInt + TEST SofInt,-1 + JNZ EnterDone + ENDIF + MOV AH,GetExtendedError + CALL DO_21 + MOV SaveState.DPL_AX,AX + MOV SaveState.DPL_BX,BX + MOV SaveState.DPL_CX,CX + MOV SaveState.DPL_DX,DX + MOV SaveState.DPL_SI,SI + MOV SaveState.DPL_DI,DI + MOV SaveState.DPL_DS,DS + MOV SaveState.DPL_ES,ES +EnterDone: + RET + +public leaveprint +LeavePRINT: + IF HardInt + TEST SofInt,-1 + JNZ LeaveDone + ENDIF + MOV AX,(ServerCall SHL 8) + 10 + PUSH CS + POP DS + MOV DX,OFFSET CodeR:SaveState + CALL Do_21 +LeaveDone: + RET + +public doint +DOINT: +ASSUME CS:CodeR,DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [CURRFIL],0 + JNZ GOAHEAD +SPRET: + ret ;Nothing to do + +GOAHEAD: + cmp [QueueLock],1 + je spret ; queue locked, do nothing... + PUSH AX ;Need a working register + MOV [SSsave],SS + MOV [SPsave],SP + MOV AX,CS + CLI +;Go to internal stack to prevent INT 24 overflowing system stack + MOV SS,AX + MOV SP,OFFSET CodeR:ISTACK + STI + PUSH ES + PUSH DS + PUSH BP + PUSH BX + PUSH CX + PUSH DX + PUSH SI + PUSH DI + PUSH CS + POP DS +ASSUME DS:CodeR + + Call EnterPRINT + + MOV BX,[NXTCHR] + CMP BX,[ENDPTR] + JB PLOOP + JMP READBUFF ;Buffer empty + +DONEJMPJP: + POPF +DONEJMPJ: + JMP DONEJMP + +FILEOFJ: +ASSUME DS:CodeR + JMP FILEOF + +PLOOP: + IF HARDINT + MOV BX,[NXTCHR] + CMP BX,[ENDPTR] + JAE DONEJMPJ ;Buffer has become empty + CMP [SOFINT],0 + JNZ STATCHK + PUSH AX + MOV AL,[MAXTICK] + CMP [TICKCNT],AL ;Check our time slice + POP AX + JAE DONEJMPJ +STATCHK: + ENDIF + + CALL PSTAT + PUSHF + CMP [CURRFIL],0 + JZ DONEJMPJP ;File got cancelled by error + POPF + + IF HARDINT + JZ DOCHAR ;Printer ready + CMP [SOFINT],0 + ENDIF + + JNZ DONEJMP ;If soft int give up + + IF HARDINT + PUSH AX + MOV AL,[BUSYTICK] + CMP [TICKSUB],AL ;Check our busy timeout + POP AX + JAE DONEJMP + JMP PLOOP + ENDIF + +DOCHAR: + MOV AL,BYTE PTR [BX] + CMP AL,1AH ;^Z? + JZ FILEOFJ ;CPM EOF + CMP AL,0DH ;CR? + JNZ NOTCR + MOV [COLPOS],0 +NOTCR: + CMP AL,9 ;TAB? + JNZ NOTABDO + MOV CL,[COLPOS] ;expand tab to # spaces + OR CL,0F8H + NEG CL + XOR CH,CH + JCXZ TABDONE ;CX contains # spaces to print +TABLP: + MOV AL," " + INC [COLPOS] + PUSH CX + CALL POUT + POP CX + DEC CX ;G + JZ TABDONE ;G We're done - get next char + JMP PLOOP ;G Keep processing tab + +;G LOOP TABLP +;G JMP TABDONE + +NOTABDO: + CMP AL,8 ;Back space? + JNZ NOTBACK + DEC [COLPOS] +NOTBACK: + CMP AL,20H ;Non Printing char? + JB NOCHAR + INC [COLPOS] ;Printing char +NOCHAR: + CALL POUT ;Print it +TABDONE: + INC [NXTCHR] ;Next char + + IF HARDINT + MOV [TICKSUB],0 ;Got a character out, Reset counter + CMP [SOFINT],0 ;Soft int does one char at a time + JNZ DONEJMP + JMP PLOOP + ENDIF + +DONEJMP: + CALL CONTEXT_BACK + Call LeavePRINT + + POP DI + POP SI + POP DX + POP CX + POP BX + POP BP + POP DS + POP ES +ASSUME DS:NOTHING,ES:NOTHING + CLI + MOV SS,[SSsave] ;Restore Entry Stack + MOV SP,[SPsave] + STI + POP AX + RET + +CONTEXT_BACK: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [CONTXTFLAG],0 + JZ CONTOK + SaveReg + MOV BX,[HISPDB] + MOV AH,SET_CURRENT_PDB + call do_21 + RestoreReg + MOV [CONTXTFLAG],0 +CONTOK: + RET + +CONTEXT_SWITCH: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [CONTXTFLAG],0 + JNZ RET45 + SaveReg + MOV AH,GET_CURRENT_PDB + call do_21 + MOV [HISPDB],BX + MOV BX,CS + sub bx,10h ; The 2.5 print is an exe program + MOV AH,SET_CURRENT_PDB + call do_21 + RestoreReg + MOV [CONTXTFLAG],1 +RET45: RET + + +;--- Refill the print buffer --- +READBUFF: +ASSUME DS:CodeR,ES:NOTHING,SS:NOTHING + + call Set24 ; switch Int24 vector + MOV [PABORT],0 ;No abort + MOV BX,[CURRHAND] + MOV CX,[BLKSIZ] + MOV DX,[BUFFER] + MOV AH,READ + call My21 + PUSHF + call Res24 ; reset Int 24 vector + CMP [PABORT],0 + JZ NOHERR + POP AX ;Flags from read + jmp FilClose ;Barf on this file, got INT 24 + + +NOHERR: + POPF + JC FILEOF + CMP AX,0 + JZ FILEOF ;Read EOF? + MOV BX,[BUFFER] ;Buffer full + MOV DI,BX + ADD DI,AX + MOV [NXTCHR],BX + MOV CX,[BLKSIZ] + SUB CX,AX + JCXZ DONEJ ; Buffer is completely full + PUSH CS + POP ES + MOV AL,1AH + cld + REP STOSB ; ^Z pad the buffer +DONEJ: + JMP DONEJMP + +FILEOF: + MOV AL,0CH ;Form feed + CALL POUT + +;--- Close file +; note: we came here from an i24 then PAbort is already = 1 +FilClose: + call Set24 + mov pAbort,-1 + MOV BX,[CURRHAND] + MOV AH,CLOSE + call My21 + call Res24 + MOV [CURRFIL],0 ; No file + MOV [CURRHAND],-1 ; Invalid handle + MOV AX,[ENDPTR] + MOV [NXTCHR],AX ; Buffer empty + +;--- Send close on output device + call Close_Dev + +;--- compact the print queue +CompQAgn: + call CompQ + +;--- Check if there are any more files to print + mov si,offset CodeR:FileQueue + cmp byte ptr [si],0 ; no more left if name starts with nul + je NoFilesLeft + call Set24 + MOV [PABORT],0 ;No abort + mov dx,si ; DS:DX points to file name + mov ax,(open shl 8) + call My21 ; try opening new file + pushf + call Res24 + cmp [PAbort],0 + je NoI24a + popf + jmp short CompQAgn ; try next file + +NoI24a: + popf + jnc GotNewFile + call PrtOpErr + jmp short CompQAgn + +GotNewFile: ; buffer was already marked as empty + mov [CurrHand],ax + mov [CurrFil],1 + +;--- Send Open on output device + call Open_Dev + +NoFilesLeft: + JMP DONEJMP + + +;--- Print open error --- +; preserves DS + +PrtOpErr: +assume ds:CodeR,es:Nothing + +; This stuff constitutes a "file" so it is bracketed by an open/close +; on the output device. + +;--- Send Open on output device + call Open_Dev + + push cs + pop es +assume es:CodeR + mov si,offset CodeR:ErrMes + call ListMes + mov si,offset CodeR:ErrMesT2 + call ListMes + mov si,offset CodeR:FileQueue + call ListMes2 + mov si,offset CodeR:BelMes + call ListMes + +;--- Send close on output device + call Close_Dev + + ret + + +;--- Compact File Queue --- +; modifies: AX,CX,SI,DI,ES + +CompQ: +assume ds:CodeR,es:nothing,ss:nothing + push cs + pop es +assume es:CodeR + mov di,offset CodeR:FileQueue ; ES:DI points to top of queue + mov si,(offset CodeR:FileQueue + MaxFileLen) ; DS:SI points to next entry + mov cx,[EndQueue] + sub cx,si ; length in bytes of the queue + cld + rep movsb ; compact the queue + mov ax,[QueueTail] ; normalize tail pointer as we + sub ax,MaxFileLen ; know have a new "next empty slot" + mov [QueueTail],ax + mov si,ax + mov byte ptr [si],0 ; nul first byte of last entry + ret + + +BREAK + +;--- Set Local Int 24 vector --- +; modifies: AX,DX + +Set24: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + push es + push bx + push dx + MOV AL,24H + MOV AH,GET_INTERRUPT_VECTOR + call do_21 + MOV WORD PTR [HERRINT+2],ES ; Save current vector + MOV WORD PTR [HERRINT],BX + MOV DX,OFFSET CodeR:DSKERR + MOV AL,24H + MOV AH,SET_INTERRUPT_VECTOR ; Install our own + call do_21 ; Spooler must catch its errors + pop dx + pop bx + pop es + ret + + +;--- Reset Old Int 24 vector --- +; modifies: none + +Res24: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + push ds + PUSH AX + push dx + LDS DX,[HERRINT] +ASSUME DS:NOTHING + MOV AL,24H + MOV AH,SET_INTERRUPT_VECTOR + call do_21 ;Restore Error INT + pop dx + POP AX + pop ds + ret + + +;--- INT 24 handler --- +DSKERR: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [PABORT],0 + JNZ IGNRET + STI + PUSH BX + PUSH CX + PUSH DX + PUSH DI + PUSH SI + PUSH BP + PUSH ES + PUSH DS + PUSH CS + POP DS + PUSH CS + POP ES +ASSUME DS:CodeR,ES:CodeR + ADD [BADDRVM],AL ;Set correct drive letter + MOV SI,OFFSET CodeR:ERRMES + CALL LISTMES + TEST AH,080H + JNZ FATERR + AND DI,0FFH + CMP DI,12 + JBE HAVCOD + MOV DI,12 +HAVCOD: + MOV [I24_ERR],DI + SHL DI,1 + MOV DI,WORD PTR [DI+MESBAS] ; Get pointer to error message + MOV SI,DI + CALL LISTMES ; Print error type + MOV SI,OFFSET CodeR:ERRMEST + CALL LISTMES + mov si,offset CodeR:FileQueue ; print filename + call ListMes2 ; print name + mov si,offset CodeR:BelMes + call ListMes +SETABORT: + INC [PABORT] ;Indicate abort + POP DS + POP ES + POP BP + POP SI + POP DI + POP DX + POP CX + POP BX +IGNRET: + XOR AL,AL ;Ignore + IRET + +FATERR: + MOV [I24_ERR],0FFH + MOV SI,OFFSET CodeR:FATMES + CALL LISTMES + JMP SHORT SETABORT + + +BREAK + +;--- Communications interrupt --- +SPCOMINT proc far +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP AH,1 + JBE MINE + JMP [COMNEXT] + +MINE: + CMP AL,0F8H + JAE RESERVED_RET +IF HardInt + CMP AX,0080h + JNZ CheckPSP + JMP FakeINT1C +ENDIF +CheckPSP: + OR AH,AH + JNE PSPDO + MOV AL,1 ; Tell PSPRINT to go away (AH = 1) +RESERVED_RET: + IRET + +PSPDO: + OR AL,AL + JNE PSPDISP +INST_REQ: + MOV AL,0FFH + IRET + +PSPDISP: + CMP [BUSY],0 + JZ SETCBUSY +ErrBusy: + MOV AX,error_busy +setcret: + push bp + mov bp,sp + or word ptr [bp+6],f_Carry + pop bp + iret + +SETCBUSY: + XOR AH,AH + CMP AX,6 ; check function within valid range + Jbe GoForIt + mov ax,error_invalid_function + jmp setcret +GoForIt: + INC [BUSY] ;Exclude + STI ;Turn ints back on + PUSH DI ;G + PUSH ES + PUSH DS + PUSH CS + POP DS +ASSUME DS:CodeR + mov [QueueLock],0 ; unlock the print queue + SHL AX,1 ;Turn into word index + mov di,ax + call ComDisp[DI] + assume ds:nothing + jc ErrRet +ASSUME DS:CodeR,ES:NOTHING + push ds + push cs + pop ds +ASSUME DS:CodeR,ES:NOTHING + CALL PSTAT ; Tweek error counter + pop ds + assume ds:nothing +ErrRet: + pushf + call Context_Back + popf + CLI + DEC BUSY ; leaves carry alone! + POP DS +ASSUME DS:NOTHING + POP ES + POP DI ;G + jc setcret + push bp + mov bp,sp + and word ptr [bp+6],NOT f_Carry + pop bp + iret +SpComInt Endp + +BREAK + +;--- Return pointer to file queue --- +QSTAT: +ASSUME DS:CodeR,ES:NOTHING + + mov [QueueLock],1 ; lock the print queue + CALL PSTAT ; Tweek error counter + push bp + mov bp,sp ; 0 2 4 + MOV [bp+ 2 + 2],cs ; + POP BP + mov si,offset CodeR:FileQueue + mov dx,[ErrCnt] ; return error count + clc + ret + +;--- Return pointer to device driver if active --- +QSTATDEV: +ASSUME DS:CodeR,ES:NOTHING + + xor ax,ax ;g assume not busy + mov [QueueLock],1 ;g lock the print queue + CALL PSTAT ;g Tweek error counter + cmp byte ptr FileQueue,0 ;g is there anything in the queue? + clc ;g + jz qstatdev_end ;g no - just exit + mov ax,error_queue_full ;g yes - set error queue full + mov si,word ptr [listdev+2] ;g get segment of list device + push bp ;g + mov bp,sp ;g 0 2 4 + MOV [bp+2+2],si ;g seg of device to DS + pop bp ;g + mov si,word ptr [listdev] ;g offset of device to SI + stc ;g + +qstatdev_end: ;g + mov [QueueLock],0 ;g unlock the print queue + ret ;g + +BREAK + +;--- Unlock the print queue --- +EndStat: +assume ds:CodeR,es:nothing + mov [QueueLock],0 + clc + ret + +BREAK + +; +; Note that we need to spin until the background is free +; +CanAll: +assume ds:CodeR,es:nothing + + cmp [CurrFil],0 ; are we currently printing? + jnz DoCanAll ; yes, go and cancel + ret ; carry is clear + +DoCanAll: + +;--- Cancel active file + mov bx,[CurrHand] ; close the current file + call Set24 + mov [PAbort],1 ; no Int24's + mov ah,Close + call My21 + call Res24 + mov [CurrFil],0 ; no files to print + mov [CurrHand],-1 ; invalidate handle + mov ax,[EndPtr] ; buffer empty + mov [NxtChr],ax + +;--- Cancel rest of files + mov si,offset CodeR:FileQueue + mov [QueueTail],si ; next free entry is the first + mov byte ptr [si],0 ; nul first byte of firts entry + mov si,offset CodeR:AllCan + call ListMes ; print cancelation message + mov si,offset CodeR:BelMes + call ListMes ; ring!! + +;--- Send close on output device + call Close_Dev + clc + ret + +BREAK + +CANFIL: +ASSUME DS:CodeR,ES:NOTHING + + CMP [CURRFIL],0 + JNZ DOCAN + ret ; carry is clear + +DOCAN: + +;--- find which file to cancel + push bp + mov bp,sp ; 0 2 4 + MOV ds,[bp+ 2 + 2] ; + POP BP + +assume ds:nothing + push cs + pop es +assume es:CodeR + mov CS:[CanFlg],0 ; reset message flag + mov CS:[ACanOcrd],0 ; no cancelation has ocured yet + mov bx,offset CodeR:FileQueue ; ES:BX points to 1st entry in queue + call AmbChk + +AnotherTry: + mov di,bx ; ES:DI points to 1st entry in queue + mov si,dx ; DS:SI points to filename to cancel +MatchLoop: + lodsb + cmp al,byte ptr es:[di] ; names in queue are all in upper case + je CharMatch + call UpConv ; did not match, try upper case + cmp al,byte ptr es:[di] + jne AnotherName ; a mismatch, try another name +CharMatch: + cmp es:byte ptr es:[di],0 ; was this the terminating nul? + je NameFound ; yes we got our file... + inc di + jmp MatchLoop + +AnotherName: + cmp CS:[AmbCan],1 ; ambigous file name specified? + jne AnName ; if not then no more work to do + cmp al,"?" + jne AnName + cmp byte ptr es:[di],"." + je FindPeriod + cmp byte ptr es:[di],0 ; if nul then file names match + jne CharMatch ; only if only ?'s are left... +FindNul: + lodsb + cmp al,"?" + je FindNul + cmp al,"." + je FindNul + or al,al + jne AnName ; found something else, no match + jmp short NameFound + +FindPeriod: ; ambigous files always have 8 chars + lodsb ; in name so we can not look for the + or al,al ; period twice (smart uh?) + je AnName ; no period found, files do not match + cmp al,"." + jne FindPeriod + jmp short CharMatch + +AnName: + add bx,MaxFileLen + cmp byte ptr es:[bx],0 ; end of queue? + jne AnotherTry ; no, continue... + cmp CS:[ACanOcrd],1 ; yes, was there a file found? + jne sk2 + push cs + pop ds +assume ds:CodeR ; StartAnFil likes it this way... + jmp StartAnFil ; restart printing + +sk2: +assume ds:nothing + + mov ax,error_file_not_found + stc + ret + + +;--- Name found, check if current file +NameFound: + push cs + pop ds +assume ds:CodeR + mov [ACanOcrd],1 ; remember we found a file + cmp bx,offset CodeR:FileQueue ; is the file being printed? + jne NotCurrent ; no, just compact the queue + cmp [CanFlg],0 + jne NotCurrent ; only cance current once + +;--- Cancel current file + mov [CanFlg],1 ; remeber we already canceled current + push bx + mov bx,[CurrHand] ; close the current file + call Set24 + mov [PAbort],1 ; no Int24's + mov ah,Close + call My21 + call Res24 + mov [CurrFil],0 ; no files to print + mov [CurrHand],-1 ; invalidate handle + mov ax,[EndPtr] ; buffer empty + mov [NxtChr],ax + pop bx + +;--- print cancelation message + push bx + mov si,offset CodeR:CanMes + call ListMes ; print cancelation message + mov si,bx ; points to filename + call ListMes2 ; print filename + mov si,offset CodeR:CanFilNam + call ListMes + mov si,offset CodeR:BelMes + call ListMes ; ring!! + pop bx + +;--- Send close on output device + call Close_Dev + +NotCurrent: + mov di,bx ; DI points to entry to cancel + mov si,bx + add si,MaxFileLen ; SI points to next entry + cmp si,[QueueTail] ; is the entry being canceled the last? + jne DoCompact ; no, do compaction + mov byte ptr [di],0 ; yes, just nul the first byte + jmp short CompactDone +DoCompact: + mov cx,[EndQueue] ; CX points to the end of the queue + sub cx,si ; length of the remainning of the queue + cld + rep movsb ; compact the queue +CompactDone: + mov ax,[QueueTail] ; remember new end of queue + sub ax,MaxFileLen + mov [QueueTail],ax + mov si,ax + mov byte ptr [si],0 ; nul first byte of last entry + + cmp byte ptr [bx],0 ; is there another file to consider? + je StartAnFil + push bp + mov bp,sp ; 0 2 4 + MOV ds,[bp+ 2 + 2] ; + POP BP +assume ds:nothing + jmp AnotherTry ; yes do it again... + + +;--- Start new file... +StartAnFil: +assume ds:CodeR + cmp [CurrHand],-1 ; was the canceled name the current? + jne NoneLeft ; no, just quit +StartAnFil2: + mov si,offset CodeR:FileQueue ; points to new current file + cmp byte ptr[si],0 ; is there one there? + je NoneLeft ; no, we canceled current and are none left + call Set24 + mov [PAbort],0 + mov dx,si + mov ax,(open shl 8) + call My21 + pushf + call Res24 + cmp [PAbort],0 + je NoI24b + popf + call CompQ ; compact file queue + jmp short StartAnFil2 + +NoI24b: + popf + jnc GoodNewCurr + call PrtOpErr ; print open error + call CompQ ; compact file queue + jmp short StartAnFil2 + +GoodNewCurr: + mov [CurrHand],ax ; save handle + mov [CurrFil],1 ; signal active (buffer is already empty) + +;--- Send Open on output device + call Open_Dev +NoneLeft: + clc + ret + +;--- Upper case conversion --- +UpConv: + CMP AL,'a' + JB NOCONV + CMP AL,'z' + JA NOCONV + SUB AL,20H +NOCONV: + RET + + +;--- Ambigous file name check --- +; entry: ds:dx points to filename +; preserves ds:dx and es +; +assume ds:nothing,es:CodeR +AmbChk: + mov CS:[AmbCan],0 ; assume not ambigous + mov si,dx + cld +AmbLoop: + lodsb + or al,al ; the nul? + jne AmbLoop + dec si ; points to nul + std ; scan backwards +ScanBack: + lodsb + cmp al,"*" + jne NotAStar + mov CS:[AmbCan],1 +NotAStar: + cmp al,"?" + jne NotAQues + mov CS:[AmbCan],1 +NotAQues: + cmp al,CS:[PChar] + jne ScanBack + cld ; be safe + cmp CS:[AmbCan],1 ; an ambigous cancel? + je AmbCanFnd ; no, just proceed + ret + +;--- transform * to ?'s +AmbCanFnd: + inc si + inc si ; points to actual name (past path char) + mov di,offset CodeR:ACBuf + push di + mov cx,12 + mov al,20h + cld + rep stosb ; fill fcb with blanks + pop di + push si + mov ax,(Parse_file_descriptor shl 8) and 0FF00h + call My21 + pop si + +;--- Copy name to expanded name + push ds + pop es +assume ds:nothing + push cs + pop ds +assume ds:CodeR + push es + mov di,si + mov si,offset CodeR:ACName + mov cx,8 +ACMovNam: + lodsb ; move name + cmp al,20h + je ACMovDn1 + stosb + loop ACMovNam + +ACMovDn1: + mov si,offset CodeR:ACExt + cmp byte ptr [si],20h ; if extension starts with blank + je ACMovDn2 ; then do not put period + mov al,"." + stosb + mov cx,3 + +ACMovExt: + lodsb ; move name + cmp al,20h + je ACMovDn2 + stosb + loop ACMovExt + +ACMovDn2: + mov byte ptr es:[di],0 ; nul terminate + pop ds +assume ds:nothing + push cs + pop es +assume es:CodeR + ret + + + +BREAK + +ADDFIL: +ASSUME DS:CodeR,ES:NOTHING + +;--- Check that queue is not full + mov di,[QueueTail] ; load pointer to next empty entry + cmp di,[EndQueue] ; queue full? + jb OkToQueue ; no, place in queue... + mov ax,error_queue_full + stc + ret + +;--- Copy name to empty slot in queue +OkToQueue: +; +; Retrieve old DS +; + push bp + mov bp,sp ; 0 2 4 + MOV ds,[bp+ 2 + 2] ; + POP BP + +assume ds:nothing + push cs + pop es ; ES:DI points to empty slot +assume es:CodeR + mov si,dx ; DS:SI points to submit packet + cmp byte ptr ds:[si],0 + jnz IncorrectLevel + lds si,dword ptr ds:[si+1] ; DS:SI points to filename + mov cx,MaxFileLen ; maximum length of file name +CopyLop: + lodsb + call UpConv ; convert to upper case + stosb + or al,al ; nul? + je CopyDone ; yes, done with move... + loop CopyLop + push cs + pop ds +assume ds:CodeR + mov ax,error_name_too_long ; if normal exit from the loop then + stc + ret + +IncorrectLevel: + mov ax,error_invalid_function + stc + ret + +assume ds:nothing,es:nothing ; es:nothing = not true but lets +CopyDone: ; avoid possible problems... + push cs + pop ds +assume ds:CodeR + +;--- advance queue pointer + mov si,[QueueTail] ; pointer to slot just used + push si ; save for test open later + add si,MaxFileLen + mov [QueueTail],si ; store for next round + mov byte ptr [si],0 ; nul next entry (maybe the EndQueue) + +;--- Check that file exists + call Set24 + mov [PAbort],0 + pop dx ; get pointer to filename + MOV AX,(OPEN SHL 8) + call My21 + pushf + PUSH DX + call Res24 + POP DX + popf + JNC GOTFIL +; +; See if brain damaged user entered an invalid drive +; + PUSH AX + MOV SI,DX + CMP BYTE PTR CS:[SI+1],':' + JZ GotDrive + POP AX + JMP SHORT i24bf +GotDrive: + MOV AH,Get_default_drive ; get current + CALL My21 + PUSH AX + MOV DL,CS:[SI] ; get drive letter to test + OR DL,20h + SUB DL,'a' + MOV AH,Set_Default_Drive ; set it + CALL My21 + MOV AH,Get_default_drive ; get it back + CALL My21 + CMP AL,DL ; same? + JNZ BadDrive ; no, bad drive + POP DX ; get original back + MOV AH,Set_Default_Drive ; set original + CALL My21 + POP AX + MOV DX,SI + JMP SHORT i24bf +BadDrive: + POP DX ; get original back + MOV AH,Set_Default_Drive ; set original + CALL My21 + POP AX + MOV AX,error_invalid_drive + MOV DX,SI +I24BF: + mov si,[QueueTail] ; take bad name out of queue + sub si,MaxFileLen ; SI points to the slot with bad name + mov [QueueTail],si + mov byte ptr [si],0 ; nul the first byte + stc + ret + + +;--- Check if print currently busy +GotFil: + CMP [CURRFIL],0 ; currently printing? + JZ OKAFIL ; no, start new print + mov bx,ax ; busy, close handle + call Set24 + mov [PAbort],1 ; no Int24's + mov ah,Close + call My21 + call Res24 + clc + ret + +;--- Save file data +OKAFIL: + MOV [CURRHAND],AX ; Valid handle + MOV AX,[ENDPTR] + MOV [NXTCHR],AX ; Buffer empty + MOV [CURRFIL],1 + +;--- Send Open on output device + call Open_Dev + clc + ret + +BREAK + +; +; perform a system call as myself +; +My21: + call Context_switch + call Do_21 + ret + +Public do_21 +DO_21: +ASSUME DS:NOTHING,ES:NOTHING + IF IBM + CMP BYTE PTR CS:[INT15FLAG],0 + JZ REAL_21 + PUSH DS + PUSH BX + LDS BX,CS:[INT15PTR] + INC BYTE PTR [BX] + POP BX + POP DS + CALL OffSave + INT 21H + Call OnSave + PUSH DS + PUSH BX + PUSHF ; Flags from system call + LDS BX,CS:[INT15PTR] + DEC BYTE PTR [BX] + POPF + POP BX + POP DS + RET + ENDIF + +REAL_21: + Call OffSave + INT 21H + CALL OnSave + RET + +OffSave: + ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSH AX + PUSH DX + MOV AX,Set_CTRL_C_Trapping SHL 8 + 2 + XOR DL,DL + INT 21h + MOV CtrlC,DL + POP DX + POP AX + ret + +OnSave: + ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSH AX + PUSH DX + MOV AX,Set_CTRL_C_Trapping SHL 8 + 2 + MOV DL,CtrlC + INT 21h + POP DX + POP AX + ret + +BREAK + +ListMes2: +ASSUME DS:CodeR,ES:NOTHING + LODSB + cmp al,0 + jz LMesDone + CALL LOUT + JMP short LISTMES2 + + +LISTMES: +ASSUME DS:CodeR,ES:NOTHING + LODSB + CMP AL,"$" + JZ LMESDONE + CALL LOUT + JMP short LISTMES + +LMESDONE: + RET + +LOUT: + PUSH BX +LWAIT: + CALL PSTAT + JZ PREADY + CMP [ERRCNT],ERRCNT2 + JA POPRET ;Don't get stuck + JMP SHORT LWAIT +PREADY: + CALL POUT +POPRET: + POP BX + RET + +;Stuff for BIOS interface +IOBUSY EQU 0200H +IOERROR EQU 8000H + +public PRNR003S, PRNR003E +PRNR003S: + +BYTEBUF DB ? + +CALLAD DD ? + +IOCALL DB 22 + DB 0 +IOREQ DB ? +IOSTAT DW 0 + DB 8 DUP(?) + DB 0 + DW OFFSET CodeR:BYTEBUF +INTSEG DW ? +IOCNT DW 1 + DW 0 + +PRNR003E: + +; Following two routines perform device open and close on output device. +; NO REGISTERS (including flags) are modified. No errors generated. + +public open_dev +Open_Dev: +ASSUME DS:NOTHING,ES:NOTHING +; +; We are now going to use the printer... We must lock down the printer so +; that the network does not intersperse output on us... +; We must also signal the REDIRector for stream open. +; We must ask DOS to set the Printer Flag to busy +; + PUSH BX + PUSHF + PUSH AX + PUSH DX + MOV DX,PrinterNum + CMP DX,-1 + JZ NoORop + MOV AX,0203h ; redirector lock + INT 2FH + MOV AX,0201H ; Redirector OPEN + INT 2FH +NoORop: + mov ax,(SET_PRINTER_FLAG SHL 8) + 01 + int 21H + POP DX + POP AX + MOV BL,DEVOPN ; Device OPEN + CALL OP_CL_OP + POPF + POP BX + RET + +OP_CL_OP: + PUSH DS + PUSH SI + LDS SI,[LISTDEV] +ASSUME DS:NOTHING + TEST [SI.SDEVATT],DEVOPCL + JZ NO_OP_CL + PUSH CS + POP DS +ASSUME DS:CodeR + MOV [IOCALL],DOPCLHL + CALL DOCALL +NO_OP_CL: + POP SI + POP DS +ASSUME DS:NOTHING + Ret + + +public close_dev +Close_Dev: +ASSUME DS:NOTHING,ES:NOTHING +; +; At this point, we release the ownership of the printer... +; and do a redirector CLOSE. +; Also tell DOS to reset the Printer Flag +; + PUSH BX + PUSHF + MOV BL,DEVCLS + CALL OP_CL_OP ; Device CLOSE + PUSH AX + PUSH DX + MOV DX,PrinterNum + CMP DX,-1 + JZ NoCRop + MOV AX,0202H ; redirector CLOSE + INT 2FH + MOV AX,0204h ; redirector clear + INT 2FH +NoCRop: + MOV AX,(SET_PRINTER_FLAG SHL 8) +00 + INT 21H + POP DX + POP AX + POPF + POP BX + RET + +PSTAT: +ASSUME DS:CodeR + PUSH BX + INC [ERRCNT] + MOV BL,DEVOST + MOV [IOCALL],DSTATHL + CALL DOCALL + TEST [IOSTAT],IOERROR + JZ NOSTATERR + OR [IOSTAT],IOBUSY ;If error, show buisy +NOSTATERR: + TEST [IOSTAT],IOBUSY + JNZ RET13P ;Shows buisy + MOV [ERRCNT],0 +RET13P: + POP BX + RET + +POUT: +ASSUME DS:CodeR + MOV [BYTEBUF],AL + MOV BL,DEVWRT + MOV [IOCALL],DRDWRHL +DOCALL: + PUSH ES + MOV [IOREQ],BL + MOV BX,CS + MOV ES,BX + MOV [IOSTAT],0 + MOV [IOCNT],1 + PUSH DS + PUSH SI + PUSH AX + call Context_Switch + MOV BX,OFFSET CodeR:IOCALL + LDS SI,[LISTDEV] +ASSUME DS:NOTHING + MOV AX,[SI+SDEVSTRAT] + MOV WORD PTR [CALLAD],AX + CALL [CALLAD] + MOV AX,[SI+SDEVINT] + MOV WORD PTR [CALLAD],AX + CALL [CALLAD] + POP AX + POP SI + POP DS +ASSUME DS:CodeR + POP ES + RET + + IF IBM +Public PRNR004S, PRNR004E +PRNR004S: + +REAL_INT_13 DD ? +INT_13_RETADDR DW OFFSET CodeR:INT_13_BACK + +PRNR004E: + +INT_13 PROC FAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSHF + INC [BUSY] ;Exclude if dumb program call ROM + PUSH CS + PUSH [INT_13_RETADDR] + PUSH WORD PTR [REAL_INT_13+2] + PUSH WORD PTR [REAL_INT_13] + RET +INT_13 ENDP + +INT_13_BACK PROC FAR + PUSHF + DEC [BUSY] + POPF + RET 2 ;Chuck saved flags +INT_13_BACK ENDP + ENDIF + + + IF IBM + +Public PRNR005S, PRNR005E +PRNR005S: + +REAL_INT_15 DD ? +INT15FLAG DB 0 ; Init to off +INT15PTR DD ? + +PRNR005E: + +INT_15 PROC FAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP AH,20H + JNZ REAL_15 ; Not my function + CMP AL,1 + JA REAL_15 ; I only know 0 and 1 + JE FUNC1 + INC [INT15FLAG] ; Turn ON + MOV WORD PTR [INT15PTR],BX ; Save counter loc + MOV WORD PTR [INT15PTR+2],ES + IRET + +FUNC1: + MOV [INT15FLAG],0 ; Turn OFF + IRET + +REAL_15: + JMP [REAL_INT_15] + +INT_15 ENDP + + +Public PRNR006S, PRNR006E +PRNR006S: + +FLAG17_14 DB 0 ; Flags state of AUX/PRN redir +REAL_INT_5 DD ? +REAL_INT_17 DD ? +INT_17_NUM DW 0 + +PRNR006E: + +INT_17: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [FLAG17_14],1 + JNZ DO_INT_17 ;The PRN device is not used + CMP [CURRFIL],0 + JZ DO_INT_17 ;Nothing pending, so OK + CMP DX,[INT_17_NUM] + JNZ DO_INT_17 ;Not my unit + CMP [BUSY],0 + JNZ DO_INT_17 ;You are me + STI + MOV AH,0A1H ;You are bad, get time out + IRET + +DO_INT_17: + JMP [REAL_INT_17] ;Do a 17 + +Public PRNR007S, PRNR007E +PRNR007S: +REAL_INT_14 DD ? +INT_14_NUM DW 0 + +PRNR007E: + +INT_14: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [FLAG17_14],2 + JNZ DO_INT_14 ;The AUX device is not used + CMP [CURRFIL],0 + JZ DO_INT_14 ;Nothing pending, so OK + CMP DX,[INT_14_NUM] + JNZ DO_INT_14 ;Not my unit + CMP [BUSY],0 + JNZ DO_INT_14 ;You are me + STI + OR AH,AH + JZ SET14_AX + CMP AH,2 + JBE SET14_AH +SET14_AX: + MOV AL,0 +SET14_AH: + MOV AH,80H ;Time out + IRET + +DO_INT_14: + JMP [REAL_INT_14] ;Do a 14 + +INT_5: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [FLAG17_14],1 + JNZ DO_INT_5 ;The PRN device is not used + CMP [CURRFIL],0 + JZ DO_INT_5 ;Nothing pending, so OK + CMP [INT_17_NUM],0 + JNZ DO_INT_5 ;Only care about unit 0 + IRET ;Pretend it worked + +DO_INT_5: + JMP [REAL_INT_5] ;Do a 5 + ENDIF + +Public PRNR008S, PRNR008E +PRNR008S: + +ERRCNT DW 0 + + IF IBM +;Reserved names for parallel card +INT_17_HITLIST LABEL BYTE + DB 8,"PRN ",0 + DB 8,"LPT1 ",0 + DB 8,"LPT2 ",1 + DB 8,"LPT3 ",2 + DB 0 +;Reserved names for Async adaptor +INT_14_HITLIST LABEL BYTE + DB 8,"AUX ",0 + DB 8,"COM1 ",0 + DB 8,"COM2 ",1 + DB 0 + ENDIF + +LISTNAME DB "PRN " ;Device name + +PRNR008E: + +SETDEV: +ASSUME CS:CodeR,DS:CodeR,ES:NOTHING,SS:NOTHING +; LISTNAME has the 8 char device name IN UPPER CASE +; CARRY set if bad device +; DS preserved, others destroyed. + + MOV AH,GET_IN_VARS + call My21 + PUSH ES + POP DS + LEA SI,ES:[BX.SYSI_DEV] +ASSUME DS:NOTHING + PUSH CS + POP ES +ASSUME ES:CodeR + MOV DI,OFFSET CodeR:LISTNAME +LOOKDEV: + TEST [SI.SDEVATT],DEVTYP + JZ NEXTDEV ; Skip Block devs + PUSH SI + PUSH DI + ADD SI,SDEVNAME ; Point at name + MOV CX,8 + REPE CMPSB + POP DI + POP SI + JE GOTDEV +NEXTDEV: + LDS SI,[SI.SDEVNEXT] + CMP SI,-1 + JNZ LOOKDEV + PUSH CS + POP DS + STC + RET + +GOTDEV: + MOV WORD PTR CS:[CALLAD+2],DS ;Get I/O routines + MOV WORD PTR CS:[LISTDEV+2],DS ;Get I/O routines + MOV WORD PTR CS:[LISTDEV],SI + PUSH CS + POP DS +ASSUME DS:CodeR + + IF IBM + MOV PrinterNum,-1 ; Assume not an INT 17 device + PUSH CS + POP ES +ASSUME ES:CodeR + MOV BP,OFFSET CodeR:LISTNAME + MOV SI,BP + MOV DI,OFFSET CodeR:INT_17_HITLIST +CHKHIT: + MOV SI,BP + MOV CL,[DI] + INC DI + JCXZ NOTONHITLIST + REPE CMPSB + LAHF + ADD DI,CX ;Bump to next position without affecting flags + MOV BL,[DI] ;Get device number + INC DI + SAHF + JNZ CHKHIT + XOR BH,BH + MOV [INT_17_NUM],BX + MOV PrinterNum,BX ; Set this as well to the INT 17 device + MOV [FLAG17_14],1 + JMP SHORT ALLSET + +NOTONHITLIST: + MOV DI,OFFSET CodeR:INT_14_HITLIST +CHKHIT2: + MOV SI,BP + MOV CL,[DI] + INC DI + JCXZ NOTONHITLIST2 + REPE CMPSB + LAHF + ADD DI,CX ;Bump to next position without affecting flags + MOV BL,[DI] ;Get device number + INC DI + SAHF + JNZ CHKHIT2 + XOR BH,BH + MOV [INT_14_NUM],BX + MOV [FLAG17_14],2 + JMP SHORT ALLSET + +NOTONHITLIST2: + MOV [FLAG17_14],0 +ALLSET: + ENDIF + CLC + RET + + + IF HARDINT + +BREAK + +ReBtINT: +ASSUME CS:CodeR,DS:NOTHING,ES:NOTHING,SS:Nothing + + CLI + push cs + pop ds + +IntWhileBusy: + INT ComInt + JNC NotBusy + JMP IntWhileBusy + ret +NotBusy: + + INC [BUSY] ; Exclude hardware interrupts + INC [SOFINT] ; Exclude software interrupts + + call CanAll ; Purge the Queue + + LDS DX,CodeR:COMNEXT + mov ax,(set_interrupt_vector shl 8) or comint + INT 21H ;Set int 2f vector + + LDS DX,CodeR:NEXTINT + mov ax,(set_interrupt_vector shl 8) or intloc + INT 21H ;Set hardware interrupt + + mov ax,(set_interrupt_vector shl 8) or 15h + lds dx,CodeR:Real_Int_15 ; Reset the wait on event on ATs + int 21h + + mov ax,(set_interrupt_vector shl 8) or 17h + LDS DX,CodeR:Real_Int_17 + INT 21H ;Set printer interrupt + + mov ax,(set_interrupt_vector shl 8) or 5h + LDS DX,CodeR:Real_Int_5 + INT 21H ;Set print screen interrupt + + mov ax,(set_interrupt_vector shl 8) or 14h + LDS DX,CodeR:Real_Int_14 + INT 21H ;Set printer interrupt + + mov ax,(set_interrupt_vector shl 8) or 24h + LDS DX,CodeR:HERRINT + INT 21H ;Set printer interrupt + + LDS DX,CodeR:NEXT_REBOOT + mov ax,(set_interrupt_vector shl 8) or reboot + INT 21H ;Set bootstrap interrupt + + STI + INT 19H + + ENDIF ; HARDINT + + + + +;----- File name Queue and data buffer goes here +Public PRNR009S +PRNR009S: +FileQueue Label byte + db 0 ; the file queue starts empty + + +BREAK + +BADSPOOL: +ASSUME CS:CodeR,DS:CodeR,ES:NOTHING,SS:Nothing + MOV DX,OFFSET CODER:BADMES + mov cx,badmeslen + mov bx,stdout + mov ah,write + INT 21H +;********************************************************************* + MOV AX,(SET_PRINTER_FLAG SHL 8) ; Set flag to Idle + int 21H +;********************************************************************* + MOV AX,(EXIT SHL 8) OR 0FFH + INT 21H + +;--- move transient out of the way +ContTrans dd ? ; transient continuation address after move + +MoveTrans label far +ASSUME CS:CodeR,DS:CodeR,ES:CodeR,SS:Nothing + cli + CLD + MOV [INTSEG],CS + CALL SETDEV +ASSUME ES:NOTHING + JC BADSPOOL + MOV DX,OFFSET CodeR:SPINT + MOV AL,SOFTINT + MOV AH,GET_INTERRUPT_VECTOR + INT 21H ;Get soft vector + MOV WORD PTR [SPNEXT+2],ES + MOV WORD PTR [SPNEXT],BX + MOV AL,SOFTINT + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set soft vector + MOV DX,OFFSET CodeR:SPCOMINT + MOV AL,ComInt + MOV AH,GET_INTERRUPT_VECTOR + INT 21H ;Get communication vector + MOV WORD PTR [COMNEXT+2],ES + MOV WORD PTR [COMNEXT],BX + MOV AL,ComInt + MOV AH,SET_INTERRUPT_VECTOR ;Set communication vector + INT 21H + + IF IBM + MOV AL,13H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_13+2],ES + MOV WORD PTR [REAL_INT_13],BX + MOV DX,OFFSET CodeR:INT_13 + MOV AL,13H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set diskI/O interrupt + + MOV AL,15H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_15+2],ES + MOV WORD PTR [REAL_INT_15],BX + MOV DX,OFFSET CodeR:INT_15 + MOV AL,15H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set INT 15 vector + + MOV AL,17H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_17+2],ES + MOV WORD PTR [REAL_INT_17],BX + MOV DX,OFFSET CodeR:INT_17 + MOV AL,17H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set printer interrupt + MOV AL,14H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_14+2],ES + MOV WORD PTR [REAL_INT_14],BX + MOV DX,OFFSET CodeR:INT_14 + MOV AL,14H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set RS232 port interrupt + MOV AL,5H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_5+2],ES + MOV WORD PTR [REAL_INT_5],BX + MOV DX,OFFSET CodeR:INT_5 + MOV AL,5H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set print screen interrupt + ENDIF + + IF HARDINT + MOV AH,GET_INDOS_FLAG + INT 21H +ASSUME ES:NOTHING + MOV WORD PTR [INDOS+2],ES ;Get indos flag location + MOV WORD PTR [INDOS],BX + MOV AL,INTLOC + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [NEXTINT+2],ES + MOV WORD PTR [NEXTINT],BX + + MOV AL,REBOOT ; We also need to chain + MOV AH,GET_INTERRUPT_VECTOR ; Into the INT 19 sequence + INT 21H ; To properly "unhook" + MOV WORD PTR [NEXT_REBOOT+2],ES ; ourselves from the TimerTick + MOV WORD PTR [NEXT_REBOOT],BX ; sequence + + IF IBM + MOV AX,0B800H + INT 2FH + CMP AL,0 + JE SET_HDSPINT ; No NETWORK, set hardware int + TEST BX,0000000011000100B + JNZ NO_HDSPINT ; DO NOT set HDSPINT if RCV|MSG|SRV + ENDIF + +SET_HDSPINT: + MOV DX,OFFSET CodeR:HDSPINT + MOV AL,INTLOC + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set hardware interrupt + + MOV DX,OFFSET CodeR:ReBtINT + MOV AL,REBOOT + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set bootstrap interrupt + +NO_HDSPINT: + ENDIF + MOV DX,OFFSET CODER:GOODMES + mov cx,goodmeslen + mov bx,stdout + mov ah,write + int 21h + +;--- Move transient +; Note: do not use stack, it may get trashed in move! +public RealMove +RealMove: + + mov ax,offset dg:TransRet + mov word ptr [ContTrans],ax ; store return offset + mov ax,CodeR + add ax,[endres] ; get start of moved transient, actually + ; this is 100 bytes more than need be + ; because of lack of pdb, but who cares? + mov word ptr [ContTrans+2],ax ; return segment + mov es,ax ; new location for dg group +assume es:nothing + mov ax,dg + mov ds,ax +assume ds:nothing + mov cx,offset dg:TransSize + mov si,cx ; start from the bottom and move up + mov di,cx + std + rep movsb ; move all code, data and stack + cld ; restore to expected setting... + +;--- normalize transient segment regs + mov ax,es + mov ds,ax + sub ax,dg ; displacement + mov dx,ss + add dx,ax ; displace stack segemnt + mov ss,dx + +assume ds:nothing,es:nothing,ss:nothing + jmp ContTrans ; back to the transient... + +PRNR009E: + +CodeR EndS + + End + \ No newline at end of file diff --git a/SRC/CMD/PRINT/PRINT_RM.ASM b/SRC/CMD/PRINT/PRINT_RM.ASM new file mode 100644 index 0000000..f58186b --- /dev/null +++ b/SRC/CMD/PRINT/PRINT_RM.ASM @@ -0,0 +1,34 @@ +; SCCSID = @(#)print_rmes.asm 4.1 85/07/17 + INCLUDE pridefs.inc + + +BREAK + +; +; MSDOS V3.00 PRINT +; +; Resident Portion Messages +; +; 02/15/84 MAU Created as a separate link module +; from the include file. should +; always be linked first!! +; + +CodeR Segment public para + + public ERRMES, ERRMEST, BELMES, ErrMesT2, CanMes, CanFilNAm + public AllCan, ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, + public ERR7, ERR8, ERR9, ERR10, ERR11, ERR12, FATMES + public BADDRVM, BADMES, badmeslen, GOODMES, goodmeslen + +;INT 24 messages A La COMMAND +Public PRMES001S, PRMES001E +PRMES001S equ $ + +include print_rm.inc + +PRMES001E equ $ + +CodeR EndS + + End diff --git a/SRC/CMD/PRINT/PRINT_RM.INC b/SRC/CMD/PRINT/PRINT_RM.INC new file mode 100644 index 0000000..a9a0492 --- /dev/null +++ b/SRC/CMD/PRINT/PRINT_RM.INC @@ -0,0 +1,34 @@ + +ERRMES DB 13,10,13,10,"**********",13,10,"$" +ERRMEST DB " error reading file",13,10,"$" +BELMES DB 13,0CH,7,"$" + +ErrMesT2 db "File not found",13,10,"$" + +CanMes DB 13,10,13,10,"File $" +CanFilNam DB " canceled by operator$" + +AllCan DB 13,10,13,10,"All files canceled by operator$" + +ERR0 DB "Write protect$" +ERR1 DB "Bad unit$" +ERR2 DB "Not ready$" +ERR3 DB "Bad command$" +ERR4 DB "Data$" +ERR5 DB "Bad call format$" +ERR6 DB "Seek$" +ERR7 DB "Non-DOS disk$" +ERR8 DB "Sector not found$" +ERR9 DB "No paper$" +ERR10 DB "Write fault$" +ERR11 DB "Read fault$" +ERR12 DB "Disk$" + +FATMES DB "File allocation table bad drive " +BADDRVM DB "A.",13,10,"$" + +BADMES DB "List output is not assigned to a device",13,10 +badmeslen dw $-badmes +GOODMES DB "Resident part of PRINT installed",13,10 +goodmeslen dw $-goodmes + \ No newline at end of file diff --git a/SRC/CMD/PRINT/PRINT_T.ASM b/SRC/CMD/PRINT/PRINT_T.ASM new file mode 100644 index 0000000..273fba4 --- /dev/null +++ b/SRC/CMD/PRINT/PRINT_T.ASM @@ -0,0 +1,1434 @@ +; SCCSID = @(#)print_t.asm 4.5 85/09/10 + INCLUDE pridefs.inc + +SaveReg MACRO reglist ;; push those registers +IRP reg, + PUSH reg +ENDM +ENDM + +RestoreReg MACRO reglist ;; pop those registers +IRP reg, + POP reg +ENDM +ENDM + +BREAK + +; +; MSDOS V3.00 PRINT +; +; Transient Portion +; + + +CodeR Segment public para + +if hardint + extrn SliceCnt:BYTE, BusyTick:BYTE, MaxTick:BYTE, TimeSlice:BYTE +endif + extrn EndRes:WORD, BlkSiz:WORD, QueueLen:BYTE, PChar:BYTE + extrn ListName:BYTE, FileQueue:BYTE, EndQueue:WORD, Buffer:WORD + extrn EndPtr:WORD, NxtChr:WORD, MoveTrans:FAR + +CodeR EndS + + +BREAK + +;Transient data + +DATA SEGMENT public BYTE + + extrn badver:byte,conflictmes_ptr:word,invparm_ptr:word,crlf_ptr:word + extrn fullmes_ptr:word,nofils_ptr:word,dispmes_ptr:word + extrn whichmes:word,fstmes:byte,secmes:byte,badnamemes_ptr:word + extrn namtmes_ptr:word,badcanmes_ptr:word,cntmes_ptr:word + extrn prompt_ptr:word,invdrvmes_ptr:word,AccDen_PTR:WORD + + public namebuf,arg_buf + + ORG 0 + +Public PRNT001S, PRNT001E +PRNT001S equ $ + +SWITCHAR DB ? +PathChar db "\" + +SubPack db 0 ; Level + dd ? ; pointer to filename + +;--- Ints used by print. These ints are loaded here before the +; resident is installed, just in case an error before print +; is installed cases it to be never installed and the ints +; have to be restored. + +i28vec dd ? ; SOFTINT +i2fvec dd ? ; COMINT + if IBM +i05vec dd ? +i13vec dd ? +i14vec dd ? +i15vec dd ? +i17vec dd ? + endif + if HARDINT +i1cvec dd ? ; INTLOC + endif + +;--- Temp stack for use durint int 23 and 24 processing + db 278 + 80H dup (?) ; 278 == IBM's ROM requirements +intStk dw ? + + +;--- Print installed flag: +; 0 = Not installed yet: process only configuration parameters +; during the command line parse +; 1 = Partially installed: process only print commands AND flag +; configuration parameters as errors AND finish by executing +; the keep process +; 2 = Already installed: process only print commands AND flag +; configuration parameters as errors +PInst db 0 ; defaults to not installed +CanFlag db 0 ; cancel mode flag (0= no cancel) +Ambig db ? ; =1 if a filename is ambigous +DevSpec db 0 ; =1 a device was specified with the + ; /d option, do not prompt +QFullMes db 0 ; =1 queue full message issued already +HARDCH DD ? ;Pointer to real INT 24 handler + +TOKBUF DB 64 DUP (?) ; token buffer for CPARSE +LastSI dw ? ; pointer to last token for lok-ahead + +NulPtr dw ? ; pointer to the nul in NameBuf +FNamPtr dw ? ; pointer to name portion of file name +NameBuf db (MaxFileLen+16) dup(?) ; full name buffer for file + ; plus room for ambigous expansion +Arg_buf db (MaxFileLen+16) dup (?) + +SearchBuf find_buf <> ; search buffer + +PRNT001E equ $ + +DATA ENDS + + + +BREAK + +Code Segment public para + extrn std_printf:near,printf_crlf:near +Code EndS + +Code Segment public para + public TransRet,TransSize + +ASSUME CS:DG,DS:nothing,ES:nothing,SS:Stack + +TRANSIENT: +;Install + CLD + +;Code to print header +; MOV DX,OFFSET DG:HEADER +; MOV AH,STD_CON_STRING_OUTPUT +; INT 21H + + MOV AH,GET_VERSION + INT 21H + + CMP AX,EXPECTED_VERSION + JE OKDOS + +; XCHG AH,AL ;Turn it around to AH.AL +; CMP AX,DOSVER_LOW +; JB GOTBADDOS +; CMP AX,DOSVER_HIGH +; JBE OKDOS + +GOTBADDOS: + PUSH CS + POP DS +assume ds:dg + MOV DX,OFFSET DG:BADVER + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + push es + xor ax,ax + push ax + +foo proc far + ret ; Must use this method, version may be < 2.00 +foo endp + + +assume ds:nothing +OKDOS: + mov ax,ds:[pdb_environ] + or ax,ax + jz nofree + push es + mov es,ax + mov ah,dealloc + int 21h + pop es +nofree: + push cs + pop ds + push cs + pop es +assume ds:dg,es:dg + mov ax,0100H ; Ask if already installed + INT ComInt + OR AL,AL + jnz badinstal + +;--- save int vectors in case of error + + mov ax,(get_interrupt_vector shl 8) or SOFTINT ; (SOFTINT) + int 21h +assume es:nothing + mov word ptr [i28vec+2],es + mov word ptr [i28vec],bx + + mov ax,(get_interrupt_vector shl 8) or COMINT ; (COMINT) + int 21h + mov word ptr [i2fvec+2],es + mov word ptr [i2fvec],bx + + if IBM + + mov ax,(get_interrupt_vector shl 8) or 13h + int 21h + mov word ptr [i13vec+2],es + mov word ptr [i13vec],bx + + mov ax,(get_interrupt_vector shl 8) or 15h + int 21h + mov word ptr [i15vec+2],es + mov word ptr [i15vec],bx + + mov ax,(get_interrupt_vector shl 8) or 17h + int 21h + mov word ptr [i17vec+2],es + mov word ptr [i17vec],bx + + mov ax,(get_interrupt_vector shl 8) or 14h + int 21h + mov word ptr [i14vec+2],es + mov word ptr [i14vec],bx + + mov ax,(get_interrupt_vector shl 8) or 05h + int 21h + mov word ptr [i05vec+2],es + mov word ptr [i05vec],bx + + endif + + if HARDINT + + mov ax,(get_interrupt_vector shl 8) or INTLOC ; (INTLOC) + int 21h + mov word ptr [i1cvec+2],es + mov word ptr [i1cvec],bx + + endif + + push cs + pop es +assume es:dg + + jmp OKINST ; not installed yet... + +BADINSTAL: + CMP AL,1 + JZ PRINTCONFLICT + mov [PInst],2 ; remember print already installed + ; and that we only do one pass + jmp short okinst +ERREX: + call printf_crlf +ERREX2: + MOV AX,(EXIT SHL 8) OR 0FFH + INT 21H + +PRINTCONFLICT: + MOV DX,OFFSET DG:CONFLICTMES_ptr + JMP short ERREX + +Busy: + RestoreReg +IntWhileBusy: + SaveReg + INT ComInt + JNC NotBusy + CMP AX,error_busy + JZ Busy + add sp,2 ; clear off AX + stc + ret +NotBusy: + Add sp,2 ; clear off AX and clear carry + ret + +OKINST: + call GetHInt ; save current int 24 vector + call SetInts ; set int 23 and 24 vectors + MOV AX,CHAR_OPER SHL 8 + INT 21H + MOV [SWITCHAR],DL ; Get user switch character + cmp dl,"-" + jne RegPathChar + mov [PathChar],"/" ; alternate path character +RegPathChar: + MOV SI,81H ; Command line +ParseAgn1: ; come here when DI is trashed... + MOV DI,OFFSET DG:TOKBUF +ParseAgn: + CALL CPARSE + jc setbufj + jmp MORESTUFF ; End of command line? +SETBUFJ: + cmp [PInst],0 ; is print already installed? + jne setbufj2 + jmp NotYet +; +; Grab the pointer to the queue and lock it down. Remember that since there +; are threads in the background, we may get a busy return. We sit here in a +; spin loop until we can actually lock the queue. +; +setbufj2: + mov ax,0104H ; get status + call IntWhileBusy ; on return DS:SI points to queue +assume ds:nothing +;--- check for off-line + cmp dx,ErrCnt1 ; check count + jb CntOK + push ds + push cs + pop ds +assume ds:dg + mov dx,offset dg:CntMes_ptr ; printer might be off-line + call printf_crlf + pop ds +assume ds:nothing + +;--- display current queue +CntOk: + call copy_to_arg_buf + cmp byte ptr ds:[si],0 ; is the queue empty? + je QueueEmpty + mov di,offset dg:FstMes + push ds + push cs + pop ds +assume ds:dg + mov dx,offset dg:crlf_ptr + call std_printf +AnotherFile: + mov dx,offset dg:dispmes_ptr +assume ds:dg + mov whichmes,di ; print one of the two messages + mov di,offset dg:SecMes ; once 1st mes printed, always print second + call printf_crlf + pop ds +assume ds:nothing + add si,MaxFileLen ; point to next entry in queue + call copy_to_arg_buf + cmp byte ptr ds:[si],0 ; end of queue? + push ds + push cs + pop ds +assume ds:dg + jne AnotherFile + pop ax ; flush stack + jmp short quit_trans ; all done + +copy_to_arg_buf: + push di + push si + mov di,offset dg:arg_buf +copy_the_name: + lodsb + or al,al + jz name_copied + stosb + jmp short copy_the_name +name_copied: + stosb + pop si + pop di + ret + +QueueEmpty: +assume ds:nothing + push cs ; queue is empty, print message + pop ds +assume ds:dg + mov dx,offset dg:NoFils_ptr + call printf_crlf + +;--- exit transient +quit_trans: + mov ax,0105H ; unlock the print queue + call IntWhileBusy ; on return DS:SI points to queue + cmp [PInst],1 + jne RegQuit ; printer was installed when we arrived + mov ax,CodeR + mov ds,ax +assume ds:CodeR + XOR BX,BX + MOV CX,5 ; StdIN,StdOUT,StdERR,StdAUX,StdPRN +CLS_LP: ; Close STD handles before + ; keep process + MOV AH,CLOSE + INT 21H + INC BX + LOOP CLS_LP + MOV DX,[ENDRES] ; install print... + MOV AX,KEEP_PROCESS SHL 8 ; Exit code 0 + INT 21H + +assume ds:dg +RegQuit: + MOV AX,(EXIT SHL 8) ; quit with no error + INT 21H +NotYet: + JMP SETBUF + + +;--- Return the size of a filename in the queue --- +; Entry: DS:SI points to name +; Exit: CX = size of the name +GetNameSize: + push si + xor cx,cx +NSLoop: + lodsb + or al,al + jz NSDone + inc cx + jmp short NSLoop +NSDone: + pop si + ret + + + +ARGDEVJ: + JMP ARGDEV +MORESTUFF: + CMP AX,1 + jnz NotEOL + jmp SETBUF ; End of command line +NotEOL: + CMP AX,2 + jnz NotAFile + jmp PaFile ; Must be a filename to print +NotAFile: + CMP AX,4 + JNZ BADTOK ; Unknown return +; +; We have a switch. Figure out what it is... +; + OR [TOKBUF],20H ; Convert to lower case + CMP [TOKBUF],"b" + jnz NotSetSiz + jmp SETSIZ ; Buffer size +NotSetSiz: + CMP [TOKBUF],"d" + JZ ARGDEVJ ; Device + +if hardint + CMP [TOKBUF],"u" + jnz NotBusyVal + jmp BusyVal ; Set BUSYTICK +NotBusyVal: + CMP [TOKBUF],"m" + jnz NotMaxVal + jmp MAXVAL ; Set MAXTICK +NotMaxVal: + CMP [TOKBUF],"s" + jnz NotTimeVal + jmp TIMEVAL ; Set TIMESLICE and SLICECNT +NotTimeVal: +endif + cmp [TokBuf],"q" + jnz NotQVal + jmp QVal ; Set queue size +NotQVal: + cmp [TokBuf],"p" + jz SetPrintMode ; turn off cancel mode + cmp [TokBuf],"c" + jz SetCancelMode ; turn on cancel mode + cmp [TokBuf],"t" + jz CancelAll ; cancel all files +BADTOK: + MOV DX,OFFSET DG:INVPARM_ptr + call printf_crlf + cmp [PInst],0 ; print not installed? + jne OKParseAgn + jmp ERREX2 + + +;--- Turn Cancel mode off --- +SetPrintMode: + cmp [PInst],0 ; has print been installed? + jne OkSetPrintM + jmp SetBuf ; no, better do it now + +OkSetPrintM: + mov [CanFlag],0 + +OKParseAgn: + jmp ParseAgn + + +;--- Turn Cancel mode on --- +SetCancelMode: + cmp [PInst],0 ; has print been installed? + jne OkSetCancelM + jmp SetBuf ; no, better do it now + +OkSetCancelM: + mov [CanFlag],1 + jmp ParseAgn + + +;--- Cancel all files --- +CancelAll: + cmp [PInst],0 ; has print been installed? + jne OkCancelAll + jmp SetBuf ; no, better do it now + +OkCancelAll: + push si ; save parse pointer + mov ax,0103H ; cancel command + call IntWhileBusy + pop si ;restore parse pointer + jmp SetBufJ + + +if hardint +;--- Set value of BUSYTICK --- +BUSYVAL: + CALL CPARSE ; Get size + Jc BADTOK + CMP AX,2 + jnz BADTOK + cmp [PInst],0 + jne BadTok ; Allowed only before installing + CALL GETNUM ; Convert + JC BADTOK + OR AH,AH + JNZ BADTOK ; To big + push ds + mov dx,CodeR + mov ds,dx +assume ds:CodeR + MOV [BUSYTICK],AL + pop ds +assume ds:dg + JMP PARSEAGN + + +;--- Set value of MAXTICK --- +MAXVAL: + CALL CPARSE ; Get size + JC BADTOKJ2 + CMP AX,2 + JNZ BADTOKJ2 + cmp [PInst],0 + jne BadTokj2 ; Allowed only before installing + CALL GETNUM ; Convert + JC BADTOKJ2 + OR AH,AH + JNZ BADTOKJ2 ; To big + push ds + mov dx,CodeR + mov ds,dx +assume ds:CodeR + MOV [MAXTICK],AL + pop ds +assume ds:dg + JMP PARSEAGN + + +BadTokJ2: + jmp BadTok + +;--- Set value of Time parameters --- +TIMEVAL: + CALL CPARSE ; Get size + JC BADTOKJ2 + CMP AX,2 + JNZ BADTOKJ2 + cmp [PInst],0 + jne BadTokJ2 ; Allowed only before installing + CALL GETNUM ; Convert + JC BADTOKJ2 + OR AH,AH + JNZ BADTOKJ2 ; To big + push ds + mov dx,CodeR + mov ds,dx +assume ds:CodeR + MOV [TIMESLICE],AL + MOV [SLICECNT],AL + pop ds +assume ds:dg + JMP PARSEAGN +endif + +;--- Set Size of Buffer --- +SETSIZ: + CALL CPARSE ; Get size + JC BADTOKJ + CMP AX,2 + JNZ BADTOKJ + cmp [PInst],0 + jne BadTokJ ; Allowed only before installing + CALL GETNUM ; Convert + JC BADTOKJ + CMP AX,512 + JB BADTOKJ ; To small + CMP AX,1024 * 16 + JA BADTOKJ ; To Big + push ds + mov dx,CodeR + mov ds,dx +assume ds:CodeR + MOV [BLKSIZ],AX + pop ds +assume ds:dg + JMP PARSEAGN + + +;--- set file queue size --- +QVal: + CALL CPARSE ; Get size + JC BADTOKJ + CMP AX,2 + JNZ BADTOKJ + cmp [PInst],0 + jne BadTokJ ; Allowed only before installing + CALL GETNUM ; Convert + JC BADTOKJ + CMP AX,MinQueueLen + JB BADTOKJ ; To small + CMP AX,MaxQueueLen + JA BADTOKJ ; To Big + push ds + mov dx,CodeR + mov ds,dx +assume ds:CodeR + MOV [QueueLen],Al + pop ds +assume ds:dg + JMP PARSEAGN + +BADTOKJ: + JMP BADTOK + + +;--- process a file name --- +PaFile: + cmp [PInst],0 ; has print been installed? + jne OkPaFile + jmp SetBuf ; no, better do it now + +OkPaFile: + cld ; just in case... + mov [Ambig],0 ; assume not an ambigous file + +;--- Check for drive specifier + push si ; save parse pointer + mov si,di ; SI points to file token + mov di,offset dg:NameBuf ; buffer for full file name + cmp byte ptr [si+1],":" ; check if there is a drive designator + je DrvFound ; yes, use it... + mov ah,Get_Default_Drive ; no, get it... + int 21h + mov dl,al ; save for later (used in DoPath) + inc dl ; adjust to proper code (A=1,B=2,...) + add al,"A" ; conver to letter code + stosb ; store letter code + mov al,":" + stosb + jmp short DoPath + +DrvFound: + mov al,byte ptr [si] ; get drive letter + call UpConvt ; conver to upper case + sub al,"@" ; conver to proper code... + jbe BadDrvJ + mov dl,al ; save for later (used in DoPath) + movsb ; move the drive letter + movsb ; move the ":" + +;--- Check for full path +DoPath: + mov al,[PathChar] + cmp byte ptr [si],al ; does it start from the root? + je DrvChk ; yes, check for valid drive + stosb ; store path character + push si + mov si,di ; buffer for current directory + mov ah,Current_Dir ; get current directory + int 21h + jnc FEndLop + pop si +BadDrvJ: + jmp bad_drive + +FEndLop: ; find the terminating nul + lodsb + or al,al + jnz FEndLop + dec si ; adjust to point to nul + mov ax,di ; save pointer to beg. of path + mov di,si ; here is were the file name goes + pop si ; points to file name + cmp ax,di ; if equal then file is in the root + je PathFound ; if so, do not add another path char + mov al,[PathChar] + stosb ; put path separator before file name + jmp short PathFound + +;--- Check for valid drive. +; Done by getting current dir of the drive in question (already in +; DL) into NameBuf. If no error the valid drive and we throw +; away the current dir stuf by overwriting it with the filename. +; +DrvChk: ; DL has drive number (from DrvFound) + push si + mov si,di ; buffer for current directory + mov ah,Current_Dir ; get current directory + int 21h + pop si + jnc PathFound + jmp bad_drive + +PathFound: + mov cx,MaxFileLen ; lets not overflow file name buffer + mov ax,di ; CX := MaxFileLen - + ; long(&NameBuf - &PtrLastchar) + sub ax,offset dg:NameBuf ; size of the filename so far + sub cx,ax ; size left for the filename + jnc MovLop + + mov cx,1 ; Set cx to Fall through to FNTooLong + + +MovLop: ; WHILE (Length(FileName) <= MaxFileLen) + ; DO copy in the file name + lodsb + stosb + cmp al,"*" + je IsAmbig + cmp al,"?" + jne ContMov +IsAmbig: + mov [Ambig],1 ; ambigous filename found + +ContMov: + or al,al ; end of name? + jz MoveDone + loop MovLop ; END of Loop + + dec di + mov [NulPtr],di + jmp FNTooLong ; if we got here the name was too long + + +MoveDone: ; we have the full absolute name... + dec di + mov [NulPtr],di ; save pointer to termanting nul + +;--- check for an option following name + pop si ; restore pointer to parse line + mov di,offset dg:TokBuf ; get next token here + call CParse + cmp ax,4 ; an option? + jne NoOption ; no, do it later... + or [TokBuf],20h ; conver to lower case + cmp [TokBuf],"c" ; cancel option? + jne NotCancel + mov [CanFlag],1 ; set cancel flag + jmp short SkipTok + +NotCancel: + cmp [TokBuf],"p" + jne NoOption + mov [CanFlag],0 ; reset cancel flag + jmp short SkipTok + +NoOption: + mov si,[LastSI] ; whatever it is, lets do it later... + +;--- chose action on filename +SkipTok: + push si ; save pointer to parse line + cmp [CanFlag],1 ; are we in cancel mode + jne CheckName + jmp GoCancel ; yes, use name to cancel file + +;--- check file exists +CheckName: + cmp [Ambig],1 ; is this an ambigous name? + jne NotAmbig + +AnotherAmbig: ; do another ambigous name + call GetAbsN ; get abs name into NameBuf + jnc SubFile ; send it to resident + jmp bad_file ; an error + +NotAmbig: + mov dx,offset dg:NameBuf + mov ax,(open shl 8) ; open for reading... + int 21h + jc bad_file_open + mov bx,ax ; copy handle + mov ah,close + int 21h +SubFile: + mov dx,offset dg:NameBuf + mov word ptr [SubPack+1],dx ; store pointer to name in + mov word ptr [SubPack+3],ds ; submit packet + mov dx,offset dg:SubPack ; DS:DX address of packet + mov ax,0101H ; submit a file to resident + call IntWhileBusy + jnc Cont0 ; successfull, queue not full now... + cmp ax,error_queue_full + jne other_errs + cmp [QFullMes],1 ; Have wa already issued the message? + je Cont1 ; yes, not again... + mov [QFullMes],1 + mov dx,offset dg:FullMes_ptr + call printf_crlf + jmp short Cont1 + +other_errs: + +;***** PROCESS OTHER SUBMIT ERRORS + +Cont0: + mov [QFullMes],0 ; queue is not full +Cont1: + cmp [Ambig],1 ; are we processing an ambigous name? + jne Cont2 + call GetAbsN2 ; get another file name + jnc SubFile +Cont2: + pop si + jmp ParseAgn1 + + +;--- process file name errors +bad_drive: + mov dx,offset dg:InvDrvMes_ptr + jmp short BadName + +Bad_File_Open: + mov dx,offset dg:BadNameMes_ptr + PUSHF + SaveReg + MOV AH,GetExtendedError + INT 21h + RestoreReg ; restore original AX + MOV DX,OFFSET DG:AccDen_PTR + CMP AX,65 ; network access denied? + JZ NoMove ; Yes, return it. + MOV AX,BX + MOV DX,CX +NoMove: + RestoreReg + popf + Jmp short badname + +bad_file: + mov dx,offset dg:BadNameMes_ptr + jmp short BadName + +FNTooLong: + mov dx,offset dg:NamTMes_ptr + +BadName: + call printf_crlf + pop si + jmp ParseAgn1 + + +;--- Issue a cancel command --- +GoCancel: + mov dx,offset dg:NameBuf ; filename + mov ax,0102H + call IntWhileBusy + jc BadCancel + pop si + jmp ParseAgn1 + +BadCancel: + cmp ax,2 + je BadCanName + +;***** PROCESS CANCEL ERROR + +BadCanName: + mov dx,offset dg:BadCanMes_ptr + jmp badname + +;--- Calculate end of resident memory --- +SETBUF: + mov dl,[PathChar] + mov ax,CodeR + mov es,ax +assume es:CodeR + mov [PChar],dl ; sneaky, uh? + +;--- check device + cmp [DevSpec],1 ; was it already specified? + je DoQSize + mov dx,offset dg:prompt_ptr + call std_printf + mov dx,offset dg:TokBuf + mov [TokBuf],9 ; max of 9 chars + mov [TokBuf+1],0 ; assume zero in + mov ah,std_con_string_input + int 21h ; get dev name + mov dx,offset dg:crlf_ptr + call std_printf + mov cl,[TokBuf+1] ; check how many read in + or cl,cl + jz DoQSize ; a CR was typed + xor ch,ch + mov si,offset dg:TokBuf+2 + mov di,offset CodeR:ListName + push si + add si,cx + dec si + cmp byte ptr [si],':' + jne gdevn + dec cx ; get rid of trailing ':' +gdevn: + pop si +gdlop: + lodsb ; copy name + call UpConvT + stosb + loop gdlop + +;--- queue size +DoQSize: + push es + pop ds +assume ds:CodeR + mov ax,MaxFileLen ; maximum length of a file name + mul [QueueLen] ; AX = result + add ax,offset CodeR:FileQueue + mov [EndQueue],ax ; save pointer to last nul + inc ax + mov [buffer],ax ; beggining of buffer + +;--- buffer size + add ax,[BlkSiz] + mov [ENDPTR],AX ; Set end of buffer pointer + mov [NXTCHR],AX ; Buffer empty + add ax,100h ; allow for header + ADD AX,16 ; Convert to para + SHR AX,1 + SHR AX,1 + SHR AX,1 + SHR AX,1 + mov [EndRes],ax ; Add size of buffer to term res size + jmp MoveTrans + + +assume ds:dg,es:dg +TransRet: ; after moving the transient we come + ; here. Isn't this fun, uh? + sti ; Ints were off during initialization +;--- normalize int handlers for new location of dg + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H + MOV DX,OFFSET DG:INT_23 + INT 21H + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H + MOV DX,OFFSET DG:INT_24 + INT 21H + + mov [PInst],1 ; remember we just installed resident part + mov si,[LastSI] ; back up one token + jmp ParseAgn1 ; restart parse + + +ARGDEV: + push ds + mov ax,CodeR + sub ax,10h ; AX points to the header + mov ds,ax + LODSB ; mandatory colon before device + POP DS + CMP AL,':' + JZ DoCparse + dec si + jmp short xk00 +DoCparse: + CALL CPARSE ; Get device name, CX is size of token + jnc xk01 +xk00: + jmp BADTOK +xk01: + cmp [PInst],0 + jne xk00 + CMP AX,2 + jnz xk00 + PUSH SI + PUSH DI + MOV SI,DI + mov ax,CodeR + mov es,ax +assume es:CodeR + MOV WORD PTR [LISTNAME],2020H ; Nul out default + MOV [LISTNAME+2]," " + MOV DI,OFFSET CodeR:LISTNAME + ADD SI,CX + DEC SI ;Point to last char of name + CMP BYTE PTR [SI],':' + JNZ GOODCNT + DEC CX ;Chuck the trailing ':' +GOODCNT: + CMP CX,8 + JBE GOODCNT2 + MOV CX,8 ; Limit to 8 chars for device +GOODCNT2: + POP SI + PUSH SI +TRLOOP: + LODSB + CALL UPCONVt + STOSB + LOOP TRLOOP + POP DI + POP SI + push cs + pop es +assume es:dg + mov [DevSpec],1 ; remember that a device was specified + JMP PARSEAGN + +;--- Uper case convertion --- +UPCONVt: + CMP AL,'a' + JB NOCONVt + CMP AL,'z' + JA NOCONVt + SUB AL,20H +NOCONVt: + RET + +GETNUM: +; Return binary number in AX of number in ES:DI. DI,SI preserved + PUSH SI + PUSH DI + XOR BX,BX + MOV SI,DI + MOV CX,10 ; Base 10 multiplier + LODSB + CMP AL,':' + JNZ BADRET ; Must have leading ':' on numbers +NLP: + LODSB + OR AL,AL + JZ GOODRET + CMP AL,'0' + JB BADRET + CMP AL,'9' + JA BADRET + SUB AL,'0' + XOR AH,AH + XCHG AX,BX + MUL CX + ADD AX,BX + XCHG AX,BX + JMP NLP + +GOODRET: + CLC +MORERET: + MOV AX,BX + POP DI + POP SI + RET + +BADRET: + STC + JMP MORERET + + + +;-----------------------------------------------------------------------; +; Return first absolute name from ambigous name +; +; Entry: NameBuf has the ambigous File Name +; +; Exit: Carry Set if no files match +; else NameBuf has the absolute name +; +assume ds:dg, es:dg + +GetAbsN: + mov ah,Set_DMA ; buffer for ffirst / fnext + mov dx,offset dg:SearchBuf + int 21h + +;--- look for a match + mov dx,offset dg:NameBuf + mov cx,0 ; no attributes + mov ah,Find_First + int 21h + jnc FstFound + ret ; return with carry set + +;--- Place new name in NameBuf +FstFound: + mov si,[NulPtr] ; scan back + std +FstLoop: + lodsb + cmp al,PathChar + jne FstLoop + cld ; just in case... + inc si + inc si + mov [FnamPtr],si + call CopyName + clc + ret + + + +;-----------------------------------------------------------------------; +; Return next absolute name from ambigous +; +GetAbsN2: + mov ah,Set_DMA ; buffer for ffirst / fnext + mov dx,offset dg:SearchBuf + int 21h + mov ah,Find_Next + int 21h + jnc NxtFound + ret ; return with carry set + +NxtFound: + call CopyName + clc + ret + + + +;-----------------------------------------------------------------------; +; Copy name from search buf to NameBuf +; +CopyName: + mov di,[FNamPtr] + mov si,offset dg:SearchBuf.find_buf_pname + cld +CopyAgn: + lodsb + stosb + or al,al ; nul found? + jne CopyAgn + ret + + + +BREAK + +;-----------------------------------------------------------------------; +; ENTRY: ; +; (CodeR-10H):SI Points to input buffer ; +; ES:DI Points to the token buffer ; +; ; +; EXIT: ; +; DS:SI Points to next char in the input buffer ; +; ES:DI Points to the token buffer ; +; CX Character count ; +; AX Condition Code ; +; =1 same as carry set ; +; =2 normal token ; +; =4 switch character, char in token buffer ; +; Carry Flag Set if a CR was found, Reset otherwise ; +; ; +; MODIFIES: ; +; CX, SI, AX and the Carry Flag ; +; ; +;-----------------------------------------------------------------------; + +TAB equ 09h +CR equ 0dh + +CPARSE: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + pushf ; save flags + mov [LastSI],si ; remember last token in case of backup + push ds + mov ax,CodeR + sub ax,10h ; AX points to the header + mov ds,ax + push di ; save the token buffer addrss + xor cx,cx ; no chars in token buffer + call kill_bl + + cmp al,CR ; a CR? + jne sj2 ; no, skip +sj1: + mov ax,1 ; condition code + dec si ; adjust the pointer + pop di ; retrive token buffer address + pop ds + popf ;restore flags + stc ;set the carry bit + ret + +sj2: + mov dl,[SWITCHAR] + cmp al,dl ;is the char the switch char? + jne anum_char ;no, process... + call kill_bl + cmp al,CR ;a CR? + je sj1 ;yes, error exit + call move_char ;Put the switch char in the token buffer + mov ax,4 ;Flag switch + jmp short x_done2 + +anum_char: + call move_char ;just an alphanum string + lodsb + cmp al,' ' + je x_done + cmp al,tab + je x_done + cmp al,CR + je x_done + cmp al,',' + je x_done + cmp al,'=' + je x_done + cmp al,dl ;Switch character + jne anum_char +x_done: + dec si ;adjust for next round + mov ax,2 ;normal token +x_done2: + push ax ;save condition code + mov al,0 + stosb ;null at the end + pop ax + pop di ;restore token buffer pointer + pop ds + popf + clc ;clear carry flag + ret + + +kill_bl proc near + lodsb + cmp al,' ' + je kill_bl + cmp al,tab + je kill_bl + cmp al,',' ;a comma? + je kill_bl + cmp al,'=' + je kill_bl + ret +kill_bl endp + + +move_char proc near + stosb ;store char in token buffer + inc cx ;increment char count + ret +move_char endp + + +;-----------------------------------------------------------------------; +GetHInt: +assume ds:dg,es:dg + push es + MOV AX,(GET_INTERRUPT_VECTOR SHL 8) OR 24H + INT 21H +assume es:nothing + MOV WORD PTR [HARDCH],BX + MOV WORD PTR [HARDCH+2],ES + pop es +assume es:dg + ret + +;-----------------------------------------------------------------------; +SetInts proc near +assume ds:dg,es:dg + + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H + MOV DX,OFFSET DG:INT_23 + INT 21H + + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H + MOV DX,OFFSET DG:INT_24 + INT 21H + + ret +SetInts endp + + +;-----------------------------------------------------------------------; +Public PRNT002S, PRNT002E +PRNT002s: + +INT_24_RETADDR DW OFFSET DG:INT_24_BACK +in_int_23 db 0 ; reentrancy flag + +PRNT002E: + +INT_24 PROC FAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSHF + PUSH CS + PUSH [INT_24_RETADDR] + PUSH WORD PTR [HARDCH+2] + PUSH WORD PTR [HARDCH] + RET +INT_24 ENDP + +INT_24_BACK: + CMP AL,2 ;Abort? + JNZ IRETI + inc [in_int_23] ; no int 23's allowed + push cs + pop ds +assume ds:dg + push cs + pop ss +assume ss:dg + mov sp, offset dg:intStk ; setup local int stack + cmp [PInst],2 + je DoNotUndo +DoUndo: + call Restore_ints +DoNotUndo: + MOV AH,EXIT + MOV AL,0FFH + INT 21H +IRETI: + IRET + +;-----------------------------------------------------------------------; + +INT_23: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + cmp [in_int_23],0 ; check for a re-entrant call + je do_int_23 + iret ; discard further int 23's + +do_int_23: + inc [in_int_23] ; make sure no more int 23's + push cs + pop ds +assume ds:dg + push cs + pop ss +assume ss:dg + mov sp, offset dg:intStk ; setup local int stack + cmp [PInst],2 + jne DoUndo +UnlockQueue: + mov ax,0105H + call IntWhileBusy ; unlock print queue (just in case) + jmp short DoNotUndo + + +;-----------------------------------------------------------------------; +; Restore all ints used by print to original values + +Restore_ints proc near + +assume ds:dg,es:nothing,ss:dg + + CLI + mov ax,(set_interrupt_vector shl 8) or SOFTINT ; (SOFTINT) + push ds + lds dx,[i28vec] + int 21h + pop ds + + mov ax,(set_interrupt_vector shl 8) or COMINT ; (COMINT) + push ds + lds dx,[i2fvec] + int 21h + pop ds + + if IBM + + mov ax,(set_interrupt_vector shl 8) or 13h + push ds + lds dx,[i13vec] + int 21h + pop ds + + mov ax,(set_interrupt_vector shl 8) or 15h + push ds + lds dx,[i15vec] + int 21h + pop ds + + mov ax,(set_interrupt_vector shl 8) or 17h + push ds + lds dx,[i17vec] + int 21h + pop ds + + mov ax,(set_interrupt_vector shl 8) or 14h + push ds + lds dx,[i14vec] + int 21h + pop ds + + mov ax,(set_interrupt_vector shl 8) or 05h + push ds + lds dx,[i05vec] + int 21h + pop ds + + endif + + if HARDINT + + mov ax,(set_interrupt_vector shl 8) or INTLOC ; (INTLOC) + push ds + lds dx,[i1cvec] + int 21h + pop ds + + endif + STI + ret + +Restore_ints endp + +CODE ENDS + + +Stack Segment Stack + +Public PRNT003S, PRNT003E +PRNT003S: + dw 100 dup(0) + +TransSize label byte ; end of transient + ; only because code is para algned +PRNT003E: + +Stack Ends + + END Transient diff --git a/SRC/CMD/PRINT/PRINT_TM.ASM b/SRC/CMD/PRINT/PRINT_TM.ASM new file mode 100644 index 0000000..4d92c26 --- /dev/null +++ b/SRC/CMD/PRINT/PRINT_TM.ASM @@ -0,0 +1,42 @@ +; SCCSID = @(#)print_tmes.asm 4.1 85/07/17 + INCLUDE pridefs.inc + + +BREAK + +; +; MSDOS V3.00 PRINT +; +; Transient Portion Message +; +; 02/13/84 MAU Fixed bug with BadCanMes +; + + +addr macro sym,name + public name + ifidn ,<> + + dw offset dg:sym + else + +name dw offset dg:sym + endif + endm + + +DATA SEGMENT public BYTE + + extrn namebuf:byte,arg_buf:byte + public whichmes,fstmes,secmes + +Public PRNTMES001S, PRNTMES001E +PRNTMES001S equ $ + + +include print_tm.inc + +PRNTMES001E equ $ + +data ends + end diff --git a/SRC/CMD/PRINT/PRINT_TM.INC b/SRC/CMD/PRINT/PRINT_TM.INC new file mode 100644 index 0000000..22c7b45 --- /dev/null +++ b/SRC/CMD/PRINT/PRINT_TM.INC @@ -0,0 +1,53 @@ + +CONFLICTMES DB "Cannot use PRINT - Use NET PRINT",0 + addr conflictmes,conflictmes_ptr + +INVPARM DB "Invalid parameter",0 + addr invparm,invparm_ptr + +FULLMES DB "PRINT queue is full",0 + addr fullmes,fullmes_ptr + +NoFils db "PRINT queue is empty",0 + addr nofils,nofils_ptr + +Dispmes db " %s%s",0 + addr dispmes,dispmes_ptr + addr arg_buf +whichmes dw ? + +FstMes db " is currently being printed",0 +SecMes db " is in queue",0 + +BadNameMes db "%s File not found",0 + addr badnamemes,badnamemes_ptr + addr namebuf + +AccDen db "Access denied",0 + addr AccDen,AccDen_ptr + +InvDrvMes db "Invalid drive specification",0 + addr invdrvmes,invdrvmes_ptr + +NamTMes db "%s Pathname too long",0 + addr namtmes,namtmes_ptr + addr namebuf + +BadCanMes db "%s File not in PRINT queue",0 + addr badcanmes,badcanmes_ptr + addr namebuf + +;This message must be $ terminated and printed using std_con_string_output + public badver +BADVER DB "Incorrect DOS version$" + +CRLF DB 13,10,0 + addr crlf,crlf_ptr + +CNTMES DB "Errors on list device indicate that it",13,10 + DB "may be off-line. Please check it.",13,10,0 + addr cntmes,cntmes_ptr + +PROMPT DB "Name of list device [PRN]: ",0 + addr prompt,prompt_ptr + \ No newline at end of file diff --git a/SRC/CMD/SORT/MAKEFILE b/SRC/CMD/SORT/MAKEFILE new file mode 100644 index 0000000..cb3f7ea --- /dev/null +++ b/SRC/CMD/SORT/MAKEFILE @@ -0,0 +1,42 @@ +#** makefile for SORT + +DEST =sort +MSG =messages + +# Path definitions + +BIOS =..\..\BIOS +DOS =..\..\DOS + +# Definitions for assembler + +ASM =masm +AFLAGS =-Mx -t +AINC =-I..\..\inc -I$(DOS) + +# Definitions for C compiler + +CC =cl +CFLAGS =-Ox -Zlp +CINC =-I..\..\h + +# Definitions for linker + +LINK =link +LIBC =..\..\libc + + +# Rules and Dependencies follow + + + +SORT.OBJ: SORT.ASM $(DOS)\SYSCALL.INC + masm $(AFLAGS) $(AINC) SORT; + +$(MSG).OBJ: $(MSG).ASM $(MSG).inc + masm $(AFLAGS) $(AINC) $(MSG); + +SORT.COM: SORT.OBJ $(MSG).OBJ + LINK @SORT.LNK + EXEFIX SORT.EXE 1 1 + \ No newline at end of file diff --git a/SRC/CMD/SORT/MESSAGES.ASM b/SRC/CMD/SORT/MESSAGES.ASM new file mode 100644 index 0000000..685a62e --- /dev/null +++ b/SRC/CMD/SORT/MESSAGES.ASM @@ -0,0 +1,91 @@ +TITLE SORT Messages + +false equ 0 +true equ not false +msver equ true +ibm equ false +internat equ true + +;include version.inc + +msg Macro lbl,msg +local a +public lbl,lbl&len +lbl&len dw a - lbl +lbl db msg +a label byte +endm + +CONST SEGMENT PUBLIC BYTE + + PUBLIC BADVER + +include messages.inc + +if internat + public table +;This table defibes the coalating sequence to be used for +;international characters. This table also equates +;lower case character to upper case unlike a straight ASCII sort. +;If your character set is like the IBM PC simply turn +;on the IBM conditional. If it is different simply modify the +;table appropriately. Note: to insert a foreign language character +;between two ASCII characters it will be necessary to +;"shift" all the ASCII characters to make room for a new character. +;If this is done be sure to equate the foreign characters to the new +;values instead of the old values which have been set here to the +;upper case ASCII values. + +table db 0,1,2,3,4,5,6,7 + db 8,9,10,11,12,13,14,15 + db 16,17,18,19,20,21,22,23 + db 24,25,26,27,28,29,30,31 + db " ","!",'"',"#","$","%","&","'" + db "(",")","*","+",",","-",".","/" + db "0","1","2","3","4","5","6","7" + db "8","9",":",";","<","=",">","?" + db "@","A","B","C","D","E","F","G" + db "H","I","J","K","L","M","N","O" + db "P","Q","R","S","T","U","V","W" + db "X","Y","Z","[","\","]","^","_" + db "`","A","B","C","D","E","F","G" + db "H","I","J","K","L","M","N","O" + db "P","Q","R","S","T","U","V","W" + db "X","Y","Z","{","|","}","~",127 +if msver + db 128,129,130,131,132,133,134,135 + db 136,137,138,139,140,141,142,143 + db 144,145,146,147,148,149,150,151 + db 152,153,154,155,156,157,158,159 + db 160,161,162,163,164,165,166,167 + db 168,169,170,171,172,173,174,175 + endif +if ibm + db "C","U","E","A","A","A","A","C" + db "E","E","E","I","I","I","A","A" + db "E","A","A","O","O","O","U","U" + db "Y","O","U","$","$","$","$","$" + db "A","I","O","U","N","N",166,167 + db "?",169,170,171,172,"!",'"','"' + endif + db 176,177,178,179,180,181,182,183 + db 184,185,186,187,188,189,190,191 + db 192,193,194,195,196,197,198,199 + db 200,201,202,203,204,205,206,207 + db 208,209,210,211,212,213,214,215 + db 216,217,218,219,220,221,222,223 +if ibm + db 224,"S" +endif +if msver + db 224,225 +endif + db 226,227,228,229,230,231 + db 232,233,234,235,236,237,238,239 + db 240,241,242,243,244,245,246,247 + db 248,249,250,251,252,253,254,255 + endif + +CONST ENDS + END + \ No newline at end of file diff --git a/SRC/CMD/SORT/MESSAGES.INC b/SRC/CMD/SORT/MESSAGES.INC new file mode 100644 index 0000000..47d1d32 --- /dev/null +++ b/SRC/CMD/SORT/MESSAGES.INC @@ -0,0 +1,10 @@ + +BADVER DB "SORT: Incorrect DOS version",13,10,"$" + + msg NoMem,<"SORT: Insufficient memory",13,10> + + msg NoDisk,<"SORT: Insufficient disk space",13,10> + + msg BadParm,<"Invalid parameter",13,10> + + \ No newline at end of file diff --git a/SRC/CMD/SORT/SORT.ASM b/SRC/CMD/SORT/SORT.ASM new file mode 100644 index 0000000..3d7e99c --- /dev/null +++ b/SRC/CMD/SORT/SORT.ASM @@ -0,0 +1,470 @@ +TITLE SORT FILTER FOR MS-DOS +; 0 +; Sort /R /+n +; /R -> reverse sort +; /+n -> sort on column n +; +; Written by: Chris Peters +; +; Modification History: +; 3-18-83 MZ Fix CR-LF at end of buffer +; Fix small file sorting +; Fix CR-LF line termination bug +; Comment the Damn source +; +; 6-23-86 Russ Whitehead Add DOS 3.30 support for multiple languages +; Inclusion of common DOS VERSION check equate +; +; +FALSE EQU 0 +TRUE EQU NOT FALSE + +internat equ true +.xlist +.xcref + +;include version.inc + +BREAK MACRO subtitle + SUBTTL subtitle + PAGE +ENDM + + INCLUDE SYSCALL.INC + include versiona.inc +.cref +.list + +sys MACRO name ; system call macro + MOV AH,name + INT 21h + ENDM +save MACRO reglist ; push those registers +IRP reg, + PUSH reg +ENDM +ENDM +restore MACRO reglist ; pop those registers +IRP reg, + POP reg +ENDM +ENDM + +MAXREC EQU 256 ; MAXIMUM NUL RECORD SIZE + +SPACE EQU 0 ; Offset zero in the allocated block +BUFFER EQU MAXREC ; Offset MAXREC in the allocated block + +SUBTTL Segments used in load order + + +CODE SEGMENT +CODE ENDS + +CONST SEGMENT PUBLIC BYTE +CONST ENDS + +CSTACK SEGMENT STACK + DB 128 DUP (0) ; initial stack to be clear +;;; DB 100H DUP (0) ; This is a "trial" change IBM hasn't +;;; ; made up their minds about +CSTACK ENDS + +DG GROUP CODE,CONST,CSTACK + +CODE SEGMENT +ASSUME CS:DG,DS:NOTHING,ES:NOTHING,SS:CSTACK + +COLUMN DW 0 ; COLUMN TO USE FOR KEY + 1 +SWITCH DB '/' +;------------------------------------------RW +CTRY_INFO db ? +CTRY_TABLE_OFF dw ? +CTRY_TABLE_SEG dw ? +;------------------------------------------ + + +SORT: +; +; check for proper version number of system +; + sys GET_VERSION + cmp ax,expected_version + je okdos + + MOV DX,OFFSET DG:BADVER ; Get error message + PUSH CS ; Get DS addressability + POP DS + sys STD_CON_STRING_OUTPUT ; Send to STDOUT + PUSH ES ; long segment + PUSH COLUMN ; offset zero +LONG_RET PROC FAR + RET ; long return to OS +LONG_RET ENDP +; +; get proper switch character +; +OKDOS: + MOV AL,0 ; Get current switch character + sys CHAR_OPER + MOV SWITCH,DL +; +; parse command line +; + MOV SI,80H ; pointer to command line + CLD ; go left to right + XOR CX,CX + LODSB + MOV CL,AL ; CX = length of command line +SWITCH_LOOP: + CALL GET_CHAR ; get a character + CMP AL,SWITCH ; beginning of switch? + JNZ SWITCH_LOOP ; No, get next character + CALL GET_CHAR ; get 1st char of switch + CMP AL,'+' ; Column to sort? + JZ SWITCH_NUMBER ; Yes, parse a number + OR AL,20h ; convert to lower case + CMP AL,'r' ; Reverse sort? + JNZ SwitchError ; No, get next switch + MOV CS:CODE_PATCH,72h ; sleaze JAE into JB + JMP SWITCH_LOOP ; get next switch +SwitchError: + MOV SI,OFFSET DG:BadParmLen + JMP Error_Exit +SWITCH_NUMBER: + MOV COLUMN,0 ; start off at 0 +SWITCH_NEXT_NUMBER: + CALL GET_CHAR ; get supposed digit + SUB AL,'0' ; convert to number + JB SWITCH_LOOP ; less than '0' + CMP AL,9 ; is it a valid digit? + JA SWITCH_LOOP ; nope, get next switch + CBW ; make it a full word + MOV BX,AX ; save byte away + MOV AX,10 ; decimal number system + MUL COLUMN ; take previous result + ADD AX,BX ; add in low order digit + MOV COLUMN,AX ; save away value + JMP SWITCH_NEXT_NUMBER ; get next character +GET_CHAR: + JCXZ END_GET ; End of line + DEC CX ; dec char count + LODSB ; get the character + RET ; return +END_GET: + POP AX ; nuke return on stack +; +; set up column for proper sort offset +; +END_SWITCH: + ADD COLUMN,2 + CMP COLUMN,2 + JZ GOT_COL + DEC COLUMN + +; +; Get sorting area, no more than 64K +; +GOT_COL: + MOV BX,1000H ; 64K worth of paragraphs +GET_MEM: + sys ALLOC ; allocate them from somewhere + JNC GOT_MEM ; if error, BX has amount free, try to get it + OR BX,BX ; but, is BX = 0? + JNZ GET_MEM ; nope, try to allocate it + JMP SIZERR ; complain + +GOT_MEM: +;------------------------------------------Following add in DOS 3.3 for Nat Lang Support. -RW + push ax + push ds + push es ; Save ES + mov ah,065h ; Get extended country information + mov al,6 ; Function for Get collating sequence + mov bx,-1 ; Get active code page + mov dx,-1 ; Get info from active country + mov cx,5 ; Number of bytes to be returned + push cs ; Place DS + pop es ; in ES + mov di,offset ctry_info ; Return area for 5 byte requested information + int 021h ; Do it ! + ; Copy the table in DOS to our segment + lds si,dword ptr cs:ctry_table_off + mov di,seg dg + mov es,di + mov di,offset dg:table + mov cx,word ptr [si] + add si,2 + mov ax,256 + sub ax,cx + add di,ax + cld + rep movsb + + pop es ; Restore ES + pop ds ; Restore DS + pop ax ; Restore AX +;------------------------------------------ + MOV DS,AX ; Point DS to buffer + MOV ES,AX ; and point ES to buffer + MOV CL,4 ; 2^4 bytes per paragraph + SHL BX,CL ; Find out how many bytes we have + +; +; clear out temporary record area +; + MOV CX,MAXREC/2 ; Size of temporary buffer (words) + MOV AX,' ' ; Character to fill with + MOV DI,SPACE ; Beginning of temp buffer + REP STOSW ; Blam. +; +; read in file from standard input +; + MOV DX,BUFFER + 2 ; DX = place to begin reading + MOV CX,BX ; CX is the max number to read + SUB CX,MAXREC + 2 ; remember offset of temp buffer +SORTL: + XOR BX,BX ; Standard input + sys READ ; Read it in + ADD DX,AX ; Bump pointer by count read + SUB CX,AX ; subtract from remaining the count read + JZ SIZERR ; if buffer is full then error + OR AX,AX ; no chars read -> end of file + JNZ SORTL ; there were chars read. go read again + JMP SHORT SIZOK ; trim last ^Z terminated record +SIZERR: + MOV SI,OFFSET DG:NoMemLen ; not enough memory error +ERROR_EXIT: + PUSH CS ; DS addressability + POP DS + LODSW ; get length + MOV CX,AX ; put into appropriate register + MOV DX,SI ; get output destination + MOV BX,2 ; output to standard error + sys WRITE ; and write it out + MOV AL,1 ; return an error code + sys EXIT + +; +; Look for a ^Z. Terminate buffer at 1st ^Z. +; +SIZOK: + MOV BX,DX ; save end pointer + MOV CX,DX ; get pointer to end of text + SUB CX,BUFFER+2 ; dif in pointers is count + MOV AL,1AH ; char is ^Z + MOV DI,BUFFER+2 ; point to beginning of text + REPNZ SCASB ; find one + JNZ NoBack ; nope, try to find CRLF + DEC BX ; pretend that we didn't see ^Z +NoBack: + SUB BX,CX ; sub from endpointer the number left + SUB BX,2 ; Hope for a CR LF at end + CMP WORD PTR [BX],0A0Dh ; Was there one there? + JZ GOTEND ; yep, here is the end + ADD BX,2 ; nope, bump back to SCASB spot + CMP BYTE PTR [BX],AL ; Was there ^Z there? + JZ GOTEND ; yep, chop it + INC BX ; Nope, skip last char +GOTEND: + MOV BP,BX ; BP = filesize-2(CRLF)+temp buffer+2 + MOV WORD PTR DS:[BP],0 ; 0 at end of the file +; +; We now turn the entire buffer into a linked list of chains by +; replacing CRLFs with the length of the following line (with 2 for CRLF) +; + MOV BX,BUFFER ; pointer to line head (length) + MOV DI,BUFFER+2 ; pointer to line text +REPLACE_LOOP: + MOV AL,13 ; char to look for is CR + MOV CX,BP ; count = end pointer + SUB CX,DI ; chop off start point to get length + INC CX ; add 1??? +REPLACE_SCAN: + REPNZ SCASB ; look for CR + JNZ REPLACE_SKIP ; count exhausted + CMP BYTE PTR [DI],10 ; LF there? + JNZ REPLACE_SCAN ; nope, continue scanning +REPLACE_SKIP: + MOV AX,DI ; AX to point after CR + DEC AX ; AX to point to CR + save ; save pointer + SUB AX,BX ; AX is length of line found + MOV [BX],AX ; stuff it in previous link + restore ; get pointer to next + INC DI ; skip LF??? + JCXZ END_REPLACE_LOOP ; no more to scan -> go sort + JMP REPLACE_LOOP ; look for next + +END_REPLACE_LOOP: + MOV WORD PTR [BX],0 ; terminate file with nul + LEA BP,[BX+2] ; remember the null line at end + MOV DI,BUFFER ; DI is start of unsorted section + +; +; begin sort. Outer loop steps over all unsorted lines +; +OUTER_SORT_LOOP: + MOV BX,DI ; BX is start of unsorted section + MOV SI,BX ; SI is scanning place link + CMP WORD PTR [BX],0 ; are we at the end of the buffer? + JNZ INNER_SORT_LOOP ; No, do inner process + JMP END_OUTER_SORT_LOOP ; yes, go dump out + +; +; BX points to best guy found so far. We scan through the sorted section +; to find an appropriate insertion point +; +INNER_SORT_LOOP: + ADD SI,[SI] ; link to next fellow + MOV AX,[SI] ; get length of comparison guy + OR AX,AX ; test for end of buffer + JZ END_INNER_SORT_LOOP ; if zero then figure out insertion + save ; save SI,DI + MOV DI,BX ; DI = pointer to tester link + SUB AX,COLUMN ; adjust length for column + JA AXOK ; more chars in tester than column? + MOV SI,SPACE ; point SI to blank area + MOV AX,MAXREC ; make AX be max length +AXOK: + MOV DX,[DI] ; get length of best guy + SUB DX,COLUMN ; adjust length for column + JA DXOK ; there are more chars after column + MOV DI,SPACE ; point air to a space + MOV DX,MAXREC ; really big record +DXOK: + MOV CX,AX ; AX is shortest record + CMP AX,DX ; perhaps DX is shorter + JB SMALL ; nope, leace CX alone + MOV CX,DX ; DX is shorter, put length in CX +SMALL: + ADD DI,COLUMN ; offset into record + ADD SI,COLUMN ; offset into other record +if not internat + REPZ CMPSB ; compare every one + endif +if internat + push bx + push ax + mov bx,offset dg:table +tloop: lodsb + xlat byte ptr cs:[bx] + mov ah,al + mov al,es:[di] + inc di + xlat byte ptr cs:[bx] + cmp ah,al + loopz tloop + pop ax + pop bx + endif + restore ; get head pointers back + JNZ TESTED_NOT_EQUAL ; didn't exhaust counter, conditions set + CMP AX,DX ; check string lengths +TESTED_NOT_EQUAL: +; +; note! jae is patched to a jbe if file is to be sorted in reverse! +; +CODE_PATCH LABEL BYTE + JAE INNER_SORT_LOOP ; if this one wasn't better then go again + MOV BX,SI ; it was better, save header + JMP INNER_SORT_LOOP ; and scan again + +END_INNER_SORT_LOOP: + MOV SI,BX ; SI is now the best person + CMP SI,DI ; check best for current + JZ END_INSERT ; best equals current, all done + +; +; SI points to best line found so far +; DI points to a place to insert this line +; DI is guaranteed to be < SI +; make room for line at destination +; + MOV DX,[SI] ; get length of line + save ; save positions of people + STD ; go right to left + MOV CX,BP ; get end of file pointer + SUB CX,DI ; get length from destination to end + MOV SI,BP ; start from end + DEC SI ; SI points to end of file + MOV DI,SI ; destination is end of file + ADD DI,DX ; DI points to new end of file + REP MOVSB ; blam. Move every one up + CLD ; back left to right + restore ; get old source and destination +; +; MOVE NEW LINE INTO PLACE +; + save ; save destination + ADD SI,DX ; adjust for previous movement + save ; save this value + MOV CX,DX ; get number to move + REP MOVSB ; blam. move the new line in + restore ; get back destination and new source +; +; DELETE LINE FROM OLD PLACE +; + save ; save destination + MOV CX,BP ; pointer to end + ADD CX,DX ; remember bump + SUB CX,SI ; get count of bytes to move + INC CX ; turn it into a word + SHR CX,1 ; or a count of words + MOV DI,SI ; new destination of move + ADD SI,DX ; offset of block + REP MOVSW ; blam, squeeze out the space + restore ; get back original destination + MOV WORD PTR DS:[BP-2],0 ; remake the end of file mark + +END_INSERT: + ADD DI,[DI] ; link to next guy + JMP OUTER_SORT_LOOP ; and continue +; +; PUT BACK IN THE CR-LF +; +END_OUTER_SORT_LOOP: + MOV DI,BUFFER ; start at beginning (where else) + MOV CX,[DI] ; count of butes + +INSERT_LOOP: + ADD DI,CX ; point to next length + MOV CX,[DI] ; get length + MOV WORD PTR [DI],0A0DH ; replace length with CRLF + CMP CX,0 ; check for end of file + JNZ INSERT_LOOP ; nope, try again + +WRITE_FILE: + MOV DX,BUFFER+2 ; get starting point + MOV CX,BP ; pointer to end of buffer + SUB CX,DX ; dif in pointers is number of bytes + MOV BX,1 ; to standard output + sys WRITE ; write 'em out + JC BADWRT ; some bizarre error -> flag it + CMP AX,CX ; did we write what was expected? + JZ WRTOK ; yes, say bye bye +BADWRT: + MOV SI,OFFSET dg:NoDiskLen ; strange write error + JMP ERROR_EXIT ; bye bye +WRTOK: + XOR AL,AL ; perfect return (by convention) + sys EXIT ; bye! + +CODE ENDS + +CONST SEGMENT PUBLIC BYTE + EXTRN BADVER:BYTE,NoMemLen:WORD,NoDiskLen:WORD,BadParmLen:WORD +if internat + extrn table:byte + endif +CONST ENDS + +SUBTTL Initialized Data +PAGE +CSTACK SEGMENT STACK + DB (362 - 80h) + 96 dup (0) ; (362 - 80h) == New - Old IBM + ; interrupt reqs. == size of growth +CSTACK ENDS + + END SORT + \ No newline at end of file diff --git a/SRC/CMD/SORT/SORT.LNK b/SRC/CMD/SORT/SORT.LNK new file mode 100644 index 0000000..4c18522 --- /dev/null +++ b/SRC/CMD/SORT/SORT.LNK @@ -0,0 +1,2 @@ +SORT messages +SORT.EXE /m; diff --git a/SRC/CMD/SYS/MAKEFILE b/SRC/CMD/SYS/MAKEFILE new file mode 100644 index 0000000..70827a6 --- /dev/null +++ b/SRC/CMD/SYS/MAKEFILE @@ -0,0 +1,52 @@ +#** makefile for SYS + +DEST =sys +MSG =messages + +# Path definitions + +BIOS =..\..\BIOS +BOOT =..\..\BOOT +DOS =..\..\DOS +LIBC =..\..\libc + +# Definitions for assembler + +ASM =masm +AFLAGS =-Mx -t +AINC =-I..\..\inc -I$(DOS) + +# Definitions for C compiler + +CC =cl +CFLAGS =-Ox -Zlp +CINC =-I..\..\h + +# Definitions for linker + +LINK =link +LIBC =..\..\libc + + +# Rules and Dependencies follow + + +SYS.OBJ: SYS.ASM $(DOS)\DOSSYM.INC $(DOS)\DOSMAC.INC \ + $(DOS)\BPB.INC $(DOS)\BUFFER.INC $(DOS)\SYSVAR.INC \ + $(DOS)\MULT.INC $(DOS)\DIRENT.INC $(DOS)\DPB.INC \ + $(DOS)\CURDIR.INC $(DOS)\CPMFCB.INC $(DOS)\FIND.INC \ + $(DOS)\PDB.INC $(DOS)\SF.INC $(DOS)\ARENA.INC $(DOS)\INTNAT.INC \ + $(DOS)\ERROR.INC $(DOS)\SYSCALL.INC $(DOS)\IOCTL.INC \ + $(BOOT)\BOOT.INC + masm $(AFLAGS) $(AINC) SYS; + +$(MSG).OBJ: $(MSG).ASM $(MSG).inc + masm $(AFLAGS) $(AINC) $(MSG); + +$(LIBC)\printf.obj: $(LIBC)\printf.asm + masm $(AFLAGS) $(AINC) $(LIBC)\printf,$(LIBC)\printf; + +SYS.EXE: SYS.OBJ $(MSG).OBJ + link @sys.lnk + convert sys.exe + del sys.exe diff --git a/SRC/CMD/SYS/MESSAGES.ASM b/SRC/CMD/SYS/MESSAGES.ASM new file mode 100644 index 0000000..d6a40e5 --- /dev/null +++ b/SRC/CMD/SYS/MESSAGES.ASM @@ -0,0 +1,95 @@ +; SCCSID = @(#)sysmes.asm 1.4 85/10/03 + TITLE Message file for MS-DOS SYS Program + +FALSE EQU 0 +TRUE EQU NOT FALSE + +;IBMJAPVER EQU FALSE +;IBMVER EQU TRUE +;MSVER EQU FALSE +;IBMCOPYRIGHT EQU FALSE + +include version.inc + +addr macro sym,name + public name + ifidn ,<> + + dw offset dg:sym + else + +name dw offset dg:sym + endif + endm + +CODE SEGMENT BYTE PUBLIC +CODE ENDS + +CONST SEGMENT BYTE PUBLIC +CONST ENDS + +DATA SEGMENT BYTE PUBLIC +DATA ENDS + +DG GROUP CODE,DATA,CONST + + +CONST SEGMENT PUBLIC BYTE + + PUBLIC BadVer, sysdrv, TargDrv, GetTarg_ptr + + PUBLIC NotNetM_ptr + +include messages.inc + + IF IBMJAPVER + Public Baddisk_ptr + ENDIF + +; +; In order to allow SYS to work on disks that have been formatted on another +; MSDOS system, we use the following variables which can be set up accordingly +; before assembling and linking the variuos files for SYS. + +; +; Name of system files to be written to the disk +; File names must be terminated with a NULL. +; +Public SourceBIOSFile,SourceDOSFile + +IF IBMCOPYRIGHT +SourceBIOSFile db "IBMBIO.COM",0 +SourceDOSFile db "IBMDOS.COM",0 +ELSE +SourceBIOSFile db "IO.SYS",0 +SourceDOSFile db "MSDOS.SYS",0 +ENDIF + +; +; Tables of files to search for on destination disk +; NOTES: Each entry MUST be exactly 12 bytes long, with extra fields filled with +; NULLs. +; The files should be in corresponding order in the two tables. +; The end-of-table is indicated by an entry of -1. +; +Public BIOSNamesTable,DOSNamesTable + +IF IBMCOPYRIGHT +BIOSNamesTable db "IBMBIO.COM",0,0 + db -1 + +DOSNamesTable db "IBMDOS.COM",0,0 + db -1 +ELSE +BIOSNamesTable db "IO.SYS",0,0,0,0,0,0 + db -1 + +DOSNamesTable db "MSDOS.SYS",0,0,0 + db -1 +ENDIF + + +CONST ENDS + + END + \ No newline at end of file diff --git a/SRC/CMD/SYS/MESSAGES.INC b/SRC/CMD/SYS/MESSAGES.INC new file mode 100644 index 0000000..9cca608 --- /dev/null +++ b/SRC/CMD/SYS/MESSAGES.INC @@ -0,0 +1,48 @@ + +NotNetM db "Cannot SYS to a Network drive",0 + addr NotNetM,NotNetM_ptr + + IF IBMJAPVER +BadDisk db "Destination disk cannot be booted",0 + addr baddisk,baddisk_ptr + ENDIF + +;This message must be terminated by a $ and printed with std_con_output +BADVER DB "Incorrect DOS version",13,10,"$" + +BadDrv db "Invalid drive specification",0 + addr Baddrv,baddrv_ptr + +BadParm db "Invalid parameter",0 + addr BadParm,BadParm_ptr + +NoDest db "No room for system on destination disk",0 + addr NoDest,NoDest_ptr + +BadSiz db "Incompatible system size",0 + addr BadSiz,BadSiz_ptr + +Done db "System transferred",13,10,0 + addr done,done_ptr + +NoSys db "No system on default drive",13,10,0 + addr NoSys,NoSys_ptr + +GETSYS DB "Insert system disk in drive %c",13,10 + db "and strike any key when ready",0 + addr getsys,getsys_ptr + addr sysdrv + +SYSDRV DB "A",0 + +GetTarg DB "Insert destination disk in drive %c",13,10 + db "and strike any key when ready",0 + addr GetTarg,GetTarg_ptr + addr Targdrv + +TargDrv DB "B",0 + +crlf db 13,10,0 + addr crlf,crlf_ptr + + \ No newline at end of file diff --git a/SRC/CMD/SYS/SYS.ASM b/SRC/CMD/SYS/SYS.ASM new file mode 100644 index 0000000..d36e859 --- /dev/null +++ b/SRC/CMD/SYS/SYS.ASM @@ -0,0 +1,1168 @@ +; SCCSID = @(#)sys.asm 1.12 85/10/06 +TITLE MS-DOS SYS Program +; SYS - Copies system programs IBMBIO.COM/IO.SYS and IBMDOS.COM/MSDOS.SYS +; 1.6 05/21/82 Added rev number message +; 1.61 06/04/82 Allow SYS to blank disk TimP at SCP +; 1.70 06/30/82 NON contiguous DOS allowed on 2.00 IBM. Allows SYS to +; 1.0 1.1 disks. +; 1.71 07/02/82 Put in CHDIRs to make sure everything done in root dir. +; 1.80 04/26/83 MZ make sys work in small machines; use full 2.0 +; system calls +; 1.81 07/22/83 ARR Added check in IBM version for valid FAT ID on +; destination because of IBM problem with SYSing to +; unformatted disks which are really formatted. Prints +; NoDest message for ridic IBM reasons, should have a +; better message. +; 1.82 08/12/83 ARR ZIBOed again. Mark fails to check for errors on +; his file I/O. Results in SYS saying system +; transferred when it hasn't been. +; 1.83 09/08/83 EKE Added code to quit if sys called on a drive across +; a net. +; 1.84 09/09/83 CHRISP grabbed against his will to make this stupid +; program write out a boot sector +; 1.85 10/18/83 NP Printf to print messages and it's now an .EXE file +; 1.86 11/8/83 MZ fix hard file output of boot sector +; 1.87 5/1/84 MZ make sys prompt for system disk in default drive. +; 3.20 11/9/84 RS make sys write out a correct boot sector for the +; version of DOS. It grabs the boot sector off the system +; disk and inserts the correct BPB. +; Uses IOCTL Get Device Parms to get BPB for a Hard drive. +; 3.20 08/5/85 RS Allow FAT ID byte of 0F0H for 'strange' media +; layouts. These come about because of /T /N switches in +; FORMAT. +; 3.20 09/16/85 Incorporate tables of filenames to allow system files +; used by other OEMs to be SYSed onto disks formatted on +; other MSDOS systems. Allows the flexibility to replace +; system files for one OEM by system files for another. +; +; +; 3.30 06/04/86 MT removes initial check for IBMBIO and DOS - not needed +; because of later search of dirs +; 3.30 06/16/86 MT only force part of IBMBIO contig - do this by assuming +; contig part smaller than 1.10 BIOS +; 3.30 06/16/86 MT Check diks space for enough room to install BIO and DOS +.xlist +.xcref + include version.inc + INCLUDE DOSSYM.INC ;also defines version of dos + include ioctl.INC +.cref +.list + +;IBMJAPVER EQU FALSE ; this and the following are mutually +;IBMVER EQU TRUE ; exclusive +;IBMCOPYRIGHT EQU FALSE + +printf_code segment public + extrn printf:far +printf_code ends + +CODE SEGMENT PARA PUBLIC +CODE ENDS + +CONST SEGMENT BYTE PUBLIC + EXTRN BIOSNamesTable:byte, DOSNamesTable:byte + EXTRN SourceBIOSFile:byte, SourceDOSFile:byte +CONST ENDS + +cstack segment stack + db 278 + 80h dup (?) ; 278 == IBM's ROM requirements +cstack ends + +DATA SEGMENT BYTE PUBLIC + +DG GROUP CODE,DATA,CONST,cstack + + EXTRN BADDRV_ptr:byte, BADPARM_ptr:byte, GETSYS_ptr:byte + EXTRN SYSDRV:byte, NODEST_ptr:byte, BADSIZ_ptr:byte, DONE_ptr:byte + EXTRN BADVER:byte, Crlf_ptr:byte, NoSYS_PTR:byte, GetTarg_ptr:byte + EXTRN TargDrv:byte + + EXTRN NotNetM_ptr:byte + + +DEFALT DB 0 + + IF IBMCOPYRIGHT +BIOSName DB "A:\IBMBIO.COM",0 +DOSName DB "A:\IBMDOS.COM",0 + +SourceBIOSName DB "A:\IBMBIO.COM",0 +SourceDOSName DB "A:\IBMDOS.COM",0 + ELSE +BIOSName DB "A:\IO.SYS",0 +DOSName DB "A:\MSDOS.SYS",0 + +SourceBIOSName DB "A:\IO.SYS",0 +SourceDOSName DB "A:\MSDOS.SYS",0 + ENDIF + +IBMBIO_LOW DW 0 ;length of IBMBIO on disk +IBMBIO_HIGH DW 0 +IBMDOS_LOW DW 0 ;length of old IBMDOS on disk +IBMDOS_HIGH DW 0 + +SIZE_OLD_HIGH DW 0 +SIZE_OLD_LOW DW 0 + +NEWBIO_SIZE_LOW DW 0 +NEWBIO_SIZE_HIGH DW 0 +NEWDOS_SIZE_LOW DW 0 +NEWDOS_SIZE_HIGH DW 0 + + +Need_Clusters dw 0 +Bytes_Per_Cluster dw 0 +Number_Free_Clusters dw 0 + + +;*** WARNING *** +; KEEP THE FOLLOWING ITEMS IN THE EXACT ORDER BELOW!!! +DOSEntFree DB 1 +BIOSEntFree DB 1 + +BIOSInFH DW ? ; file handle of source BIOS +BIOSLenLow DW 2 DUP (?) ; 32-bit length of BIOS +BIOSLenHigh DW 2 DUP (?) ; 32-bit length of BIOS +BIOSTime DW 2 DUP (?) ; place to store time of BIOS write +BIOSOutFH DW ? ; fh of BIOS destination + +DOSInFH DW ? ; file handle of source DOS +DOSLenLow DW 2 DUP (?) ; 32-bit length of DOS +DOSLenHigh DW 2 DUP (?) ; 32-bit length of DOS +DOSTime DW 2 DUP (?) ; place to store time of DOS write +DOSOutFH DW ? ; fh of DOS destination + + +AllName DB "A:\*.*",0 + +;****************************************** +;FCB SNOT + +fcb_copy db 32 dup(?) + + IF IBMCOPYRIGHT +FCBDOS DB "IBMDOS COM" +FCBBIO DB "IBMBIO COM" + ELSE +FCBDOS DB "MSDOS SYS" +FCBBIO DB "IO SYS" + ENDIF + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +DOSFile_Offset dw 0 ; Index for system file names in Tables + +DirEnt DB 80h DUP (?) +cbBuf DW ? ; number of bytes in buffer +pDOS DW ? ; offset of beginning of DOS in buffer +pDOSEnd DW ? ; offset of end of DOS in buffer + +BIOSEG EQU 70H ; STARTING LOCATION OF BIOS +BPBLEN EQU 19 + +BPB LABEL DWORD ; POINTER TO HARDFILE BPB + DW 0000 + DW BIOSEG + +public boot +BOOT DB 0,0,0 ; SKIP THE THREE BYTE JUMP + DB "MSDOS3.3" +SECSIZ DW 512 ; SECTOR SIZE +SECALL DB 1 ; SECTOS PER ALLOCATION UNIT +RESNUM DW 1 ; RESERVED SECTORS +FATNUM DB 2 ; NUMBER OF FATS +DIRNUM DW 64 ; NUMBER OF DIRECTORY ENTRIES +SECNUM DW 1*8*40 ; NUMBER OF SECTORS +FATID DB 0FEH +FATSIZE DW 1 +SECLIM DW 8 +HDLIM DW 1 +HIDDEN DW 0 +PHYDRV DB 0 + DB 510-($-boot) dup (?) + DB 55H,0AAH ; MAGIC WORD +REORG LABEL BYTE + ORG BOOT + INCLUDE ..\BOOT\BOOT.INC + ORG REORG +FATID_TABLE LABEL WORD + DW 0 ; F8 FIXED DISK + DW -2 ; F9 + DW -1 ; FA + DW -1 ; FB + DW OFFSET DG:BPB91 ; FC + DW OFFSET DG:BPB92 ; FD + DW OFFSET DG:BPB81 ; FE + DW OFFSET DG:BPB82 ; FF + +; BIOS PARAMETER BLOCKS FOR THE VARIOUS MEDIA + +BPB81 DB 1 + DW 1 + DB 2 + DW 64 + DW 1*8*40 + DB 0FEH + DW 1 + DW 8 + DW 1 + DW 0 + DB 0 + +BPB82 DB 2 + DW 1 + DB 2 + DW 112 + DW 2*8*40 + DB 0FFH + DW 1 + DW 8 + DW 2 + DW 0 + DB 0 + +BPB91 DB 1 + DW 1 + DB 2 + DW 64 + DW 1*9*40 + DB 0FCH + DW 2 + DW 9 + DW 1 + DW 0 + DB 0 + +BPB92 DB 2 + DW 1 + DB 2 + DW 112 + DW 2*9*40 + DB 0FDH + DW 2 + DW 9 + DW 2 + DW 0 + DB 0 + +BPB96T DB 1 ; mjb001 + DW 1 + DB 2 + DW 224 + DW 2*15*80 + DB 0f9H + DW 7 + DW 15 + DW 2 + DW 0 + DB 0 +BPBSIZ = $-BPB96T + +BPB325 DB 2 ; mjb001 + DW 1 + DB 2 + DW 70h +cSec325 DW 2*9*80 + DB 0f9H + DW 3 + DW 9 + DW 2 + DW 0 + DB 0 + + + +; +; Following structure used by Generic IOCTL call Get Device Parameters to get +; the BPB of a hard disk. It 'overflows' into area of BUF. +; +DeviceParameters a_DeviceParameters <0,DEV_HARDDISK> + +BUF LABEL BYTE ; beginning of area for file reads + +DATA ENDS + +CODE SEGMENT PUBLIC PARA + + ASSUME CS:DG,DS:NOTHING,ES:NOTHING,SS:CSTACK + +start: + JMP SHORT CheckVersion + + DW OFFSET DG:BOOT + +HEADER DB "SYS 3.30" + +CheckVersion: + PUSH AX ; save drive letter validity + MOV AH,GET_VERSION + INT 21H ; get dos version + + cmp ax,expected_version + jne gotbaddos + +; XCHG AH,AL ; Turn it around to AH.AL +; CMP AX,DOSVER_LOW ; is it too low? +; JNE GOTBADDOS ; yes, error + + pop ax +ASSUME DS:NOTHING,ES:NOTHING + push cs + pop es +ASSUME ES:DG + mov si,5ch + mov di,offset dg:fcb_copy + mov cx,32 + rep movsb + push cs + pop ds +ASSUME DS:DG + MOV DX,OFFSET DG:DirEnt + MOV AH,SET_DMA + INT 21h + jmp sys + +GOTBADDOS: + push cs + pop ds +ASSUME DS:DG + MOV DX,OFFSET DG:BADVER ; message to dump + mov ah,std_con_string_output + int 21h + push es + xor ax,ax + push ax + +foo proc far + ret ; Must use this method, version may be < 2.00 +foo endp + +ERR0: +ASSUME DS:DG,ES:DG + MOV DX,OFFSET DG:BADPARM_ptr ; no drive letter + JMP xerror + +ERR1: +ASSUME DS:DG,ES:DG + MOV DX,OFFSET DG:BADDRV_ptr ; drive letter invalid + JMP xerror + +; +; We do not have a disk that has an available system in the root. See if the +; media is removable and if so, ask the user for a replacement. If the media +; is not removable, then die gracefully. +; +ERR2: +ASSUME DS:DG,ES:DG + MOV AH,GET_DEFAULT_DRIVE ;Will find out the default drive + INT 21H ;Default now in AL + MOV BL,AL + INC BL ; A = 1 + Call IsRemovable + jnc DoPrompt + MOV DX,OFFSET DG:NoSys_PTR + PUSH DX + CALL PRINTF + MOV AX,4C01h + INT 21h +DoPrompt: + MOV AL,DEFALT ; get default drive number + ADD AL,'A'-1 ; turn into letter + MOV SYSDRV,AL + MOV DX,OFFSET DG:GETSYS_ptr + push dx + call printf + CALL GetKeystroke ; wait for him to type simething + XOR AL,AL ; valid drive spec now... +SYS: +ASSUME DS:DG,ES:DG + mov DOSEntFree,1 + mov BIOSEntFree,1 + CMP BYTE PTR fcb_copy+1," " ; Was file specified? + JNZ ERR0 ; yes, no files are allowed -> error + CMP AL,-1 ; Invalid drive spec? + JZ ERR1 ; yes, must have valid drive -> error + CMP BYTE PTR fcb_copy,0 ; No drive specified? + JZ ERR1 ; yes, cannot sys to default drive error + MOV AH,GET_DEFAULT_DRIVE ; Get default drive + INT 21H + INC AL ; turn from phys drive to logical drive + MOV DEFALT,AL ; save it for possible printing + CMP BYTE PTR fcb_copy,AL ; did he specify the default drive? + JZ ERR1 ; yes, default drive not allowed + +;------Code to quit if sys called on a drive across a net----------------------- +CheckNet: + MOV BL,BYTE PTR fcb_copy ; x = IOCTL (getdrive, Drive+1); + MOV AX,(IOCTL SHL 8) + 9 + INT 21H + JC NotNet + TEST DX,1200H ; if(x & 0x1000)(redirected or shared) + JZ NotNet + MOV DX,OFFSET DG:NotNetM_ptr ; Fatal ("Can't do over net"); + JMP xerror + +;-------Load up BIOS and DOS at this point --------------------------------- +NotNet: + MOV AL,DEFALT + ADD AL,'A'-1 ; turn into letter + MOV SourceBIOSName,AL ; twiddle source name + MOV SourceDOSName,AL ; twiddle source name + CLD + MOV DX,OFFSET DG:SourceBIOSName ; source name + MOV CX,7 + MOV AH,4Eh + INT 21h + JC ERR2J + MOV AX,WORD PTR DG:DIRENt+26 + MOV WORD PTR NEWBIO_SIZE_LOW,AX + MOV AX,WORD PTR DG:DIRENt+28 + MOV WORD PTR NEWBIO_SIZE_HIGH,AX + MOV DX,OFFSET DG:SourceBIOSName ; source name + MOV DI,OFFSET DG:BIOSInFH ; pointer to block of data + CALL OpenFile + JNC NotERR2 +ERR2J: + JMP Err2 ; not found, go and try again + +NotERR2: + MOV DX,OFFSET DG:SourceDOSName ; source name + MOV CX,7 + MOV AH,4Eh + INT 21h + JC ERR2J + MOV AX,WORD PTR DG:DIRENt+26 + MOV WORD PTR NEWDOS_SIZE_LOW,AX + MOV AX,WORD PTR DG:DIRENt+28 + MOV WORD PTR NEWDOS_SIZE_HIGH,AX + MOV DX,OFFSET DG:SourceDOSName ; source of DOS + MOV DI,OFFSET DG:DOSInFH ; pointer to block of data + CALL OpenFile ; Look for DOS + JC ERR2J ; not there, go ask for a system disk + MOV CX,SP ; get lowest available spot + SUB CX,0200h+(OFFSET DG:BUF); leave room for all sorts of things + MOV cbBuf,CX ; store length away + CALL FillMem ; load up memory with files + JC ERR2J ; Some kind of error reading system + + +CheckDest: +;------------Check for "valid" destination----------------------------------- + MOV AH,0Dh + INT 21h + MOV AL,BYTE PTR fcb_copy + DEC AL + MOV BX,OFFSET DG:buf ; Temp space + MOV DX,1 ; Sector 1 (first sec of FAT) + MOV CX,DX ; One sector + INT 25H ; Read Fat sector + POP AX ; Flags + JC PromptDest ; Issue prompt to insert Destination + ; disk + CMP BYTE PTR [BUF],0F8H + JAE OKFAT +;---------Treat 0F0H as a valid 'IBM' FAT ID byte-------------------------------- + cmp BYTE PTR [BUF],0F0H + je OKFAT + JMP ERR3 + + +PromptDest: + push ax + + mov al,Byte ptr fcb_copy ; Get destination ID + ADD AL,'A'-1 ; turn into letter + MOV TargDrv,AL + + MOV DX,OFFSET DG:GetTarg_ptr + push dx + call printf + + CALL GetKeystroke ; wait for him to type simething + + pop ax + jmp CheckDest + +;-------The Fat appears to be OK... See if DOS/Bios there----------------- + + + + +OKFAT: +; +;Set up drive letter in destignation filespecs +; + + MOV AL,BYTE PTR fcb_copy + ADD AL,'A'-1 ; convert to letter + MOV BIOSName,AL ; point names at destination drive + MOV DOSName,AL + +; +; Read in first sector of directory +; +; The reason that we do the direct read of the directory is the find first/next +; or search first/next do an exclusive search for volume labels. By using these +; calls, there is no way to determine if a volume label occupies the first +; location in the directory. Hence we get sleazy and read the directory directly +; (no pun intended) to get this info. While its in there, go ahead and grab the file +; sizes. -MT +; +GetDir: + MOV DL,Byte PTR fcb_copy + MOV AH,Get_DPB + PUSH DS + INT 21h + +; DS:BX point to DPB + + MOV DX,[BX.dpb_dir_sector] + POP DS + MOV AL,BYTE PTR fcb_copy + DEC AL + MOV BX,OFFSET DG:BUF ; Temp space + MOV CX,1 ; Sector 1 (first sec of FAT) + INT 25H ; Read Fat sector + POP AX ; Flags + JNC Skip + +; +;NOTE!!!! This next jump is actually a bug left over from the MS days - if the +;dir is not read successfully then the SYS should be canned at that point - +;however, up thru 3.20 this would just jump to the actual sys. To make things +; a little better I jump to an error - this needs to be DCR'd for a real error +; + + JMP Err3 +Skip: + +; +; Now see if the first two directory entries are available... First check +; for being free: +; + MOV SI,OFFSET DG:BUF + CMP BYTE PTR [SI],0 ; empty dir? + JE Get_Space ; yes, go check for conflicts + CLD + CMP BYTE PTR [SI],0E5h + JE SecondFree +; +; The first entry is not free. See if the BIOS is there +; + MOV DI,OFFSET DG:FCBBIO + MOV CX,11 + REP CMPSB + JNE Err3jj ; not BIOS + DEC BIOSEntFree + +; added by dcl 8/24/86 - most cases solution + + mov ax,0002 ; is ibmbio allocated the 1st cluster? + cmp ax,word ptr DG:BUF+26 ; that being cluster 2??? + JNE Err3jj ; not cluster 2 - error; go display + +; end added by dcl 8/24/86 + +; +; IBM change - MT 6/16/86 +; Get the size of the file for IBMBIO +; + MOV ax,word ptr DG:BUF+28 + MOV word ptr IBMBIO_Low,ax + MOV ax,word ptr DG:BUF+30 + MOV word ptr IBMBIO_High,ax + +; Check the second entry +; + SecondFree: + MOV SI,OFFSET DG:BUF+32 + CMP BYTE PTR [SI],0 ; empty dir? + JE Get_Space ; yes, go check for conflicts + CMP BYTE PTR [SI],0E5h ; how about second? + JE Get_Space +; +; This entry is not free. Check it for IBMDOS +; + MOV DI,OFFSET DG:FCBDOS + MOV CX,11 + REP CMPSB +Err3jj: JNZ Err3j1 ; not DOS + DEC DOSEntFree +; +; IBM change - MT 6/16/86 +; Get the file size for IBMDOS +; + MOV ax,word ptr DG:BUF+60 + MOV word ptr IBMDOS_Low,ax + MOV ax,word ptr DG:BUF+62 + MOV word ptr IBMDOS_High,ax + +; +; We now have the following: +; Whether or not there is a DOS/BIOS on the disk +; Whether or not the appropriate entry is free +; We are guaranteed that if the entry is free, then it has the correct file in + + +; +;IBM CHANGE - MT 6/16/86 +; +; Here we make some VERY IMPORTANT assumptions. +; +;1) If IBMBIO exists on the disk currently, we assume it is in the correct +; place, i.e. at the front of the data area and contiguous. +;2) The stub loader portion of IBMBIO is less than 2048 bytes long. This +; number comes about by assuming we will never overlay anything smaller +; than 1920 bytes (DOS 1.10 IBMBIO size). This can be expanded to 2048 if +; we also assume the smallest possible cluster length is 512 bytes. +; +; Therefore, if we have an empty disk or IBMBIO exists, then we have enough +; contiguous room to install the portion of IBMBIO that requires itself to +; be contiguous. + + +; +;IBM CHANGE - MT 6/16/86 +; +;See if enough free space for IBMBIO and IBMDOS +; + +GET_SPACE: + MOV AH,36H ;Get free space + MOV DL,byte ptr fcb_copy ;Get the drive letter + INT 21h + +;16 bit math okay here, no danger of overflow + + MUL CX ;Get bytes/cluster + ;Result left in AX + PUSH AX ;Save it for later + MOV Bytes_Per_Cluster,AX + MOV Number_Free_Clusters,BX + +;Low result in AX, High result in DX +;Get IBMBIO size + + MOV AX,IBMBIO_Low + MOV DX,IBMBIO_High + + CALL Get_Clusters + ADD Number_Free_Clusters,AX + +;Low result in AX, High result in DX +;Get IBMDOS size + + MOV AX,IBMDOS_Low + MOV DX,IBMDOS_High + CALL Get_Clusters + ADD Number_Free_Clusters,AX + + +;Find the total size of new DOS and BIOS + + MOV AX,NEWBIO_Size_Low + MOV DX,NEWBIO_Size_High + + CALL Get_Clusters + +Got_NEW_BIO_Clusters: + MOV Need_Clusters,AX + + MOV AX,NEWDOS_Size_Low + MOV DX,NEWDOS_Size_High + CALL Get_Clusters + ADD AX,Need_Clusters + +;Now see if there is enough room for all of it on the disk + + CMP AX,Number_Free_Clusters + JBE PUT_SYS + +ERR3J1: + JMP ERR3 + +;Go do the sys +PUT_SYS: + CMP BIOSEntFree,0 + JNE GetRidDOS + MOV DX,OFFSET DG:BIOSName ; who to change mode + MOV CX,0 ; undo attributes + MOV AX,(ChMod SHL 8) + 1 ; set the attributes + INT 21h + MOV DX,OFFSET DG:BIOSName + MOV AX,(UNLINK SHL 8) + INT 21H ; Delete BIOS file +GetRidDOS: + CMP DOSEntFree,0 + JNE CreateBIOS + MOV DX,OFFSET DG:DOSName ; who to change mode + MOV CX,0 ; undo attributes + MOV AX,(ChMod SHL 8) + 1 ; set the attributes + INT 21h + MOV DX,OFFSET DG:DOSName + MOV AX,(UNLINK SHL 8) + INT 21H ; Delete DOS file +CreateBIOS: + MOV DX,OFFSET DG:BIOSName ; destination of BIOS + MOV CX,7 ; fancy attributes + MOV AH,Creat ; make a new one + INT 21h + JC err3j2 + MOV BIOSOutFH,AX ; save handle + MOV DX,OFFSET DG:DOSName ; destination of DOS + MOV AH,Creat ; make a new one + INT 21h + JC err3j2 + MOV DOSOutFH,AX ; save handle + PUSH DS + MOV AH,GET_DPB + MOV DL,BYTE PTR fcb_copy ; Target drive + INT 21H + MOV [BX.dpb_next_free],0 ; Reset Allocation to start of disk + ; so BIOS goes in right place! + POP DS +Copy: + CALL DumpMem ; flush out memory + JC ERR3J2 ; Disk full or some other error + MOV AX,DOSLenHigh ; more DOS? + OR AX,DOSLenLow ; more low dos + OR AX,BIOSLenHigh ; more high BIOS + OR AX,BIOSLenLow ; more low BIOS + JZ AllDone ; nope, all done + CALL FillMem ; reload world + JNC Copy + JMP ERR2 ; Start over again + +ERR3J2: + JMP ERR3 + +ERR4: + MOV DX,OFFSET DG:BADSIZ_ptr + JMP xerror + +AllDone: + MOV CX,BIOSTime ; get time and date + MOV DX,BIOSTime+2 + MOV BX,BIOSOutFH ; where to stuff the time + MOV AX,(File_Times SHL 8) + 1 + INT 21h + MOV AH,Close + INT 21h + MOV CX,DOSTime ; get time and date + MOV DX,DOSTime+2 + MOV BX,DOSOutFH ; where to stuff the time + MOV AX,(File_Times SHL 8) + 1 + INT 21h + MOV AH,Close + INT 21h + + CALL PUTBOOT ; copy the boot sector also + + MOV DX,OFFSET DG:DONE_ptr ; all finished message + push dx + call printf + XOR AL,AL ; ok error code + jmp short rexit + +xerror: + push dx + call printf + mov dx,offset dg:crlf_ptr + push dx + call printf + mov al,0ffh +rexit: + MOV AH,EXIT ; bye and return error code + INT 21h + +POPRET: + POP CX +SETERR: + STC + return + + +Get_Clusters: +;Round up to the next cluster size + + MOV BX,Bytes_Per_Cluster ;Bytes/cluster + DIV BX ;If there is a remainder in DX, then + ;we have another cluster to round up + CMP DX,0 + JE Got_CLUSTERS + INC AX ;Round up to next cluster +Got_Clusters: + RET + + +FillMem: + MOV CX,cbBuf ; get length of buffer + MOV BX,BIOSInFH ; get bios source handle + MOV DX,OFFSET DG:BUF+512 ; point to beginning of buffer + ; past area to read in boot rec + PUSH CX ; save away total length + CMP BIOSLenHigh,0 ; > 64K to read? + JA UseCX ; use CX + CMP BIOSLenLow,CX ; more left to read? + JA UseCX ; use CX + MOV CX,BIOSLenLow ; move new +UseCX: + MOV AH,Read + INT 21h ; read in what we can + JC POPRET ; Error + CMP AX,CX ; Did we get it all? + JNZ POPRET ; No, error + ADD DX,AX ; update pointer for DOS Read + MOV pDOS,DX ; point to beginning of DOS + SUB BIOSLenLow,AX ; decrement remaining + SBB BIOSLenHigh,0 ; do 32 bit + POP CX ; get original length + SUB CX,AX ; this much is left + MOV BX,DOSInFH ; get bios source handle + CMP DOSLenHigh,0 ; > 64K to read? + JA UseCXDOS ; use CX + CMP DOSLenLow,CX ; more left to read? + JA UseCXDOS ; use CX + MOV CX,DOSLenLow ; move new +UseCXDOS: + MOV AH,Read + INT 21h ; read in what we can + retc ; error + CMP AX,CX + JNZ SETERR ; Didn't read it all + ADD DX,AX ; update pointer for DOS Read + MOV pDOSEnd,DX ; point to End of dos DOS + SUB DOSLenLow,AX ; decrement remaining + SBB DOSLenHigh,0 ; do 32 bit arithmetic + CLC + return + +OpenFile: + MOV AX,(OPEN SHL 8) + 0 ; open for reading only + INT 21H ; Look for BIOS + retc ; not found, go and try again + STOSW ; stash away handle + MOV BX,AX ; get ready for seeks + MOV AX,(LSeek SHL 8) + 2 ; seek relative to eof + XOR CX,CX ; zero offset + XOR DX,DX ; zero offset + INT 21h ; get offsets + STOSW ; save low part of size + STOSW ; save low part of size + MOV AX,DX + STOSW ; save high part of size + STOSW ; save high part of size + XOR DX,DX ; zero offset + MOV AX,(LSeek SHL 8) + 0 ; seek relative to beginning + INT 21h + MOV AX,(File_Times SHL 8) + 0 + INT 21h ; get last write times + MOV AX,CX + STOSW ; save time + MOV AX,DX + STOSW ; save date + return + +ERR3: + MOV DX,OFFSET DG:NODEST_ptr + JMP xerror + +DumpMem: + MOV DX,OFFSET DG:BUF+512 ; get offset of bios start + MOV CX,pDOS ; beginning of next guy + SUB CX,DX ; difference is length + JZ DumpDos ; no bios to move + MOV BX,BIOSOutFH ; where to output + MOV AH,Write + INT 21h ; wham + retc ; error + CMP AX,CX ; Did it work? + JNZ WRERR ; No +DumpDos: + MOV DX,pDOS ; beginning of dos + MOV CX,pDOSEnd ; end of dos + SUB CX,DX ; difference is length + retz ; if zero no write + MOV BX,DOSOutFH ; where to output + MOV AH,Write + INT 21h ; wham + retc ; error + CMP AX,CX ; Did it work? + retz ; Yes, carry clear +WRERR: + STC + return + + + +; +; Output a boot sector apporpriate to the supposed version of DOS. We do this +; by reading in the boot sector for the drive and getting the BPB from there. +; This works fine until we get a 1.x diskette, when we have to grab the media +; descriptor byte and select the correct BPB using that. +; +public putboot +PUTBOOT: + mov ax,dg ; initialize DS. + mov ds,ax + mov al,byte ptr fcb_copy ; target drive 1-based + dec al ; convert to 0-based + mov dx,0000H ; get relative sector 0 + call Read_Sec + jc Do_Media_Byte + cmp word ptr DG:[Buf+1FEH], 0AA55H ; Is it a 1.x disk? + jnz Do_Media_Byte +PB0: + mov si,(offset DG:Buf)+13 ; Set up SI to point to 'SECALL' in + ; the BPB just read in. + jmp PB7 +; +; We were unable to use the BPB in the boot sector, so we must now get a +; valid BPB by examining the media descriptor byte. +; +Do_Media_Byte: + MOV AH,GET_DPB + MOV DL,BYTE PTR fcb_copy ; Target drive + INT 21H + MOV AL,[BX.dpb_media] ; Media byte + PUSH CS + POP DS + SUB AL,0F8H + CBW + MOV BX,AX ; BX has offset into bpb table + SHL BX,1 ; Word table, mult by 2 + MOV SI,[BX+FATID_TABLE] ; get pointer to bpb + OR SI,SI ; hardfile? + JNZ PB3 ; nope. + +; +; We have a hard drive. We can use the IOCTL Get Device Parameters to get the +; BPB for the hard drive. +; + mov bl,byte ptr fcb_copy ; Drive number + mov dx,offset DeviceParameters + mov ah,IOCTL + mov al,GENERIC_IOCTL + mov ch,RAWIO + mov cl,Get_Device_Parameters + int 21H + mov bx,dx ; ds:bx-> DeviceParameters + lea si,byte ptr [bx].DP_BPB ; SI -> BPB returned + inc si + inc si ; si-> secall in BPB + +PB3: CMP SI,-1 ; weird internal error? + JZ PB9 + CMP SI,-2 ; new multi-value FAT ID? + JNZ PB7 ; nope. +; +; We may have a FAT ID of F9. This may represent TWO different media in two +; incompatible drives. We do a get free space to determine which. +; + MOV AH,Get_Drive_freespace + MOV DL,BYTE PTR FCB_copy + INT 21h + MOV BX,DX + MUL BX ; compute total sectors + CMP AX,cSec325 + MOV SI,OFFSET DG:BPB325 + JB PB7 + MOV SI,OFFSET DG:BPB96T + +PB7: PUSH DS ; COPY IN THE NEW STUFF + POP ES + MOV DI,OFFSET DG:SECALL + MOV CX,BPBSIZ + CLD + REP MOVSB + +PB8: + cmp dg:FATID,0F8H ; Hard drive? + jnz not_hard +; NOTE: +; The physical hard drive number is placed in the third byte from the end in the +; boot sector in DOS 3.2. This is a change from the previous DOS versions. +; + mov byte ptr dg:[boot+1FDH],80H ; set physical hard drive number +not_hard: + MOV AL,BYTE PTR fcb_copy + DEC AL + MOV BX,OFFSET DG:BOOT ; Boot sector + XOR DX,DX ; Sector 0 + MOV CX,DX + INC CX ; One sector + INT 26H ; Write out 8 sector boot sector + jnc pb9 +PB9: POP AX ; Flags + RET + +; +; Read_Sec reads the sector and track specified in DX from the drive in AL. +; The sector is read into location Buf. Carry set if error. +; + +READ_SEC: + push ax ; save registers + mov cx,0001H + mov bx,Offset DG:Buf ; temp. buffer + int 25H + pop ax ; Pop flags pushed by Int 25 +Read_Ret: + pop ax + ret + + + +GetKeystroke: + MOV AX,(Std_CON_Input_Flush SHL 8) + Std_CON_Input_No_Echo + INT 21H + MOV AX,(Std_CON_Input_Flush SHL 8) + 0 + INT 21H + mov dx,offset dg:crlf_ptr + push dx + call printf + return + +; +; Determine if the drive indicated in BX is removable or not. +; +; Inputs: BX has drive (0=default, 1=A) +; Outputs: Carry clear => removable +; Carry set => non-removable +; +; Registers modified: none +; +IsRemovable: + SaveReg + mov AX,(IOCTL SHL 8) OR 8 ; do a media check + INT 21H + jnc CheckRemove + MOV AX,(IOCTL SHL 8) OR 9 ; Is it a net drive + INT 21H + jc NotRemove ; Yipe! Say non-removable + TEST DX,1000H + jnz NotRemove ; Is NET drive. Say non-removable. + JMP IsRemove +CheckRemove: + TEST ax,1 + jnz NotRemove +IsRemove: + CLC + RestoreReg + return +NotRemove: + STC + RestoreReg + return + +; +; Moves the name at the current locations in the system file name tables into +; the relevant system variables for later use. +; Preserves all registers (except flags). +; +MoveNames: + push bx + push cx + push di + push si + cld + mov bx,word ptr DOSFile_Offset + mov si,offset DG:BIOSNamesTable + add si,bx + mov di,offset DG:BIOSName + add di,3 ; skip over drive,colon,back-slash + mov cx,11 + repe movsb + mov si,offset DG:DOSNamesTable + add si,bx + mov di,offset DG:DOSName + add di,3 ; skip over drive,colon,back-slash + mov cx,11 + repe movsb + pop si + pop di + pop cx + pop bx + ret + +; +; Set up filename in FCB variables for searching directory entries. +; +SetUpFCB: + push si + push di + push bx + mov si,offset DG:BIOSNamesTable + mov bx,word ptr DOSFile_Offset + add si,bx + mov di,offset DG:FCBBIO + call MoveToFCB + mov si,offset DG:DOSNamesTable + mov bx,word ptr DOSFile_Offset + add si,bx + mov di,offset DG:FCBDOS + call MoveToFCB + pop bx + pop di + pop si + ret + +; +; Move ASCIZ filename to FCB-type filename from [SI] to [DI]. +; +MoveToFCB: + xor cx,cx +NextChar: + lodsb + cmp al,'.' + jz Fill_Blanks + stosb + inc cx + jmp short NextChar + +Fill_Blanks: + mov al,' ' + cmp cx,8 + jge See_Ext + stosb + inc cx + jmp short Fill_Blanks + +See_Ext: + mov cx,3 +Next_Ext: + lodsb + stosb + dec cx + jnz Next_Ext + RET + +; +; Gets source file names from SourceBIOSFile and SourceDOSFile and puts them +; into the ASCIZ strings SourceBIOSName and SourceDOSName. +; +GetSourceNames: + push si + push di + push cx + mov si,offset DG:SourceBIOSFile + mov di,offset DG:SourceBIOSName + add di,3 ; skip over drive,colon,back-slash + mov cx,12 + repe movsb + mov si,offset DG:SourceDOSFile + mov di,offset DG:SourceDOSName + add di,3 ; skip over drive,colon,back-slash + mov cx,12 + repe movsb + pop cx + pop di + pop si + ret + + + +CODE ENDS + END START + \ No newline at end of file diff --git a/SRC/CMD/SYS/SYS.LNK b/SRC/CMD/SYS/SYS.LNK new file mode 100644 index 0000000..efdb89b --- /dev/null +++ b/SRC/CMD/SYS/SYS.LNK @@ -0,0 +1,3 @@ +SYS messages+ +..\..\libc\PRINTF +SYS.EXE /m; diff --git a/SRC/DOS/ABORT.OBJ b/SRC/DOS/ABORT.OBJ new file mode 100644 index 0000000..8f8a0b3 Binary files /dev/null and b/SRC/DOS/ABORT.OBJ differ diff --git a/SRC/DOS/ALLOC.OBJ b/SRC/DOS/ALLOC.OBJ new file mode 100644 index 0000000..11a459a Binary files /dev/null and b/SRC/DOS/ALLOC.OBJ differ diff --git a/SRC/DOS/ARENA.INC b/SRC/DOS/ARENA.INC new file mode 100644 index 0000000..42b0b3f --- /dev/null +++ b/SRC/DOS/ARENA.INC @@ -0,0 +1,27 @@ +; SCCSID = @(#)arena.asm 1.1 85/04/09 +BREAK + +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +; +; arena item +; +arena STRUC +arena_signature DB ? ; 4D for valid item, 5A for last item +arena_owner DW ? ; owner of arena item +arena_size DW ? ; size in paragraphs of item +arena ENDS + +; +; CAUTION: The routines in ALLOC.ASM rely on the fact that arena_signature +; and arena_owner_system are all equal to zero and are contained in DI. Change +; them and change ALLOC.ASM. + +arena_owner_system EQU 0 ; free block indication + +arena_signature_normal EQU 4Dh ; valid signature, not end of arena +arena_signature_end EQU 5Ah ; valid signature, last block in arena +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; diff --git a/SRC/DOS/BPB.INC b/SRC/DOS/BPB.INC new file mode 100644 index 0000000..867a380 --- /dev/null +++ b/SRC/DOS/BPB.INC @@ -0,0 +1,39 @@ +; SCCSID = @(#)BPB.ASM 1.1 85/04/29 +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + +; BIOS PARAMETER BLOCK DEFINITION +; THIS STRUCTURE IS USED TO BUILD A FULL DPB + +BPBLOCK STRUC +BPSECSZ DW ? ; SIZE IN BYTES OF PHYSICAL SECTOR +BPCLUS DB ? ; SECTORS/ALLOC UNIT +BPRES DW ? ; NUMBER OF RESERVED SECTORS +BPFTCNT DB ? ; NUMBER OF FATS +BPDRCNT DW ? ; NUMBER OF DIRECTORY ENTRIES +BPSCCNT DW ? ; TOTAL NUMBER OF SECTORS +BPMEDIA DB ? ; MEDIA DESCRIPTOR BYTE +BPFTSEC DW ? ; NUMBER OF SECTORS TAKEN UP BY ONE FAT +BPBLOCK ENDS + +A_BPB STRUC +BPB_BYTESPERSECTOR DW ? +BPB_SECTORSPERCLUSTER DB ? +BPB_RESERVEDSECTORS DW ? +BPB_NUMBEROFFATS DB ? +BPB_ROOTENTRIES DW ? +BPB_TOTALSECTORS DW ? +BPB_MEDIADESCRIPTOR DB ? +BPB_SECTORSPERFAT DW ? +BPB_SECTORSPERTRACK DW ? +BPB_HEADS DW ? +BPB_HIDDENSECTORS DW ? + DW ? +BPB_BIGTOTALSECTORS DW ? + DW ? + DB 6 DUP(?) +A_BPB ENDS +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; diff --git a/SRC/DOS/BUF.OBJ b/SRC/DOS/BUF.OBJ new file mode 100644 index 0000000..caf26ee Binary files /dev/null and b/SRC/DOS/BUF.OBJ differ diff --git a/SRC/DOS/BUFFER.INC b/SRC/DOS/BUFFER.INC new file mode 100644 index 0000000..af7b422 --- /dev/null +++ b/SRC/DOS/BUFFER.INC @@ -0,0 +1,61 @@ +; SCCSID = @(#)buffer.asm 1.1 85/04/09 +BREAK +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + +; Field definition for I/O buffer information + +BUFFINFO STRUC +buf_link DD ? ; Pointer to next buffer in list +buf_ID DB ? ; Drive of buffer (bit 7 = 0) + ; SFT table index (bit 7 = 1) + ; = FFH if buffer free +buf_flags DB ? ; Bit 7 = 1 if Remote file buffer + ; = 0 if Local device buffer + ; Bit 6 = 1 if buffer dirty + ; Bit 5 = Reserved + ; Bit 4 = Search bit (bit 7 = 1) + ; Bit 3 = 1 if buffer is DATA + ; Bit 2 = 1 if buffer is DIR + ; Bit 1 = 1 if buffer is FAT + ; Bit 0 = Reserved +buf_sector DW ? ; Sector number of buffer (bit 7 = 0) +; The next two items are often refed as a word (bit 7 = 0) +buf_wrtcnt DB ? ; For FAT sectors, # times sector written out +buf_wrtcntinc DB ? ; " " " , # sectors between each write +buf_DPB DD ? ; Pointer to drive parameters +buf_fill DW ? ; How full buffer is (bit 7 = 1) +BUFFINFO ENDS + +buf_offset EQU DWORD PTR buf_sector + ;For bit 7 = 1, this is the byte + ;offset of the start of the buffer in + ;the file pointed to by buf_ID. Thus + ;the buffer starts at location + ;buf_offset in the file and contains + ;buf_fill bytes. + +BUFINSIZ EQU SIZE BUFFINFO + ; Size of structure in bytes + +buf_Free EQU 0FFh ; buf_id of free buffer + +;Flag byte masks +buf_isnet EQU 10000000B +buf_dirty EQU 01000000B +;*** +buf_visit EQU 00100000B +;*** +buf_snbuf EQU 00010000B + +buf_isDATA EQU 00001000B +buf_isDIR EQU 00000100B +buf_isFAT EQU 00000010B +buf_type_0 EQU 11110001B ; AND sets type to "none" + +buf_NetID EQU BUFINSIZ + +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; diff --git a/SRC/DOS/CLOSE.OBJ b/SRC/DOS/CLOSE.OBJ new file mode 100644 index 0000000..4000a1d Binary files /dev/null and b/SRC/DOS/CLOSE.OBJ differ diff --git a/SRC/DOS/CONST2.OBJ b/SRC/DOS/CONST2.OBJ new file mode 100644 index 0000000..a0b2f62 Binary files /dev/null and b/SRC/DOS/CONST2.OBJ differ diff --git a/SRC/DOS/CPMFCB.INC b/SRC/DOS/CPMFCB.INC new file mode 100644 index 0000000..3a418d4 --- /dev/null +++ b/SRC/DOS/CPMFCB.INC @@ -0,0 +1,124 @@ +; SCCSID = @(#)cpmfcb.asm 1.1 85/04/10 +; SCCSID = @(#)cpmfcb.asm 1.1 85/04/10 +BREAK + +; +; Field definition for FCBs +; The FCB has the following structure: +; +; +---------------------------+ +; | Drive indicator(byte) | +; +---------------------------+ +; | Filename (8 chars) | +; +---------------------------+ +; | Extension (3 chars) | +; +---------------------------+ +; | Current Extent(word) | +; +---------------------------+ +; | Record size (word) | +; +---------------------------+ +; | File Size (2 words) | +; +---------------------------+ +; | Date of write | +; +---------------------------+ +; | Time of write | +; +---------------------------+ +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +; +---------------------------+ +; | 8 bytes reserved | +; +---------------------------+ +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; | next record number | +; +---------------------------+ +; | random record number | +; +---------------------------+ +; + +sys_fcb STRUC +fcb_drive DB ? +fcb_name DB 8 DUP (?) +fcb_ext DB 3 DUP (?) +fcb_EXTENT DW ? +fcb_RECSIZ DW ? ; Size of record (user settable) +fcb_FILSIZ DW ? ; Size of file in bytes; used with the + ; following word +fcb_DRVBP DW ? ; BP for SEARCH FIRST and SEARCH NEXT +fcb_FDATE DW ? ; Date of last writing +fcb_FTIME DW ? ; Time of last writing +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +fcb_reserved DB 8 DUP (?) ; RESERVED +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +fcb_NR DB ? ; Next record +fcb_RR DB 4 DUP (?) ; Random record +sys_fcb ENDS + +FILDIRENT = fcb_FILSIZ ; Used only by SEARCH FIRST and SEARCH + ; NEXT + +fcb_sfn EQU BYTE PTR fcb_reserved + +; Note that fcb_net_handle, fcb_nsl_drive, fcb_nsld_drive and fcb_l_drive +; all must point to the same byte. Otherwise, the FCBRegen will fail. +; NOTE about this byte (fcb_nsl_drive) +; The high two bits of this byte are used as follows to indicate the FCB type +; 00 means a local file or device with sharing loaded +; 10 means a remote (network) file +; 01 means a local file with no sharing loaded +; 11 means a local device with no sharing loaded + +; +; Network FCB +; +fcb_net_drive EQU BYTE PTR fcb_reserved+1 +fcb_net_handle EQU WORD PTR fcb_reserved+2 +fcb_netID EQU DWORD PTR fcb_reserved+4 + +; +; No sharing local file FCB +; +fcb_nsl_drive EQU BYTE PTR fcb_reserved+1 +fcb_nsl_bits EQU BYTE PTR fcb_reserved+2 +fcb_nsl_firclus EQU WORD PTR fcb_reserved+3 +fcb_nsl_dirsec EQU WORD PTR fcb_reserved+5 +fcb_nsl_dirpos EQU BYTE PTR fcb_reserved+7 + +; +; No sharing local device FCB +; +fcb_nsld_drive EQU BYTE PTR fcb_reserved+1 +fcb_nsld_drvptr EQU DWORD PTR fcb_reserved+2 + +; +; Sharing local FCB +; +fcb_l_drive EQU BYTE PTR fcb_reserved+1 +fcb_l_firclus EQU WORD PTR fcb_reserved+2 +fcb_l_mfs EQU WORD PTR fcb_reserved+4 +fcb_l_attr EQU BYTE PTR fcb_reserved+6 + +; +; Bogusness: the four cases are: +; +; local file 00 +; local device 40 +; local sharing C0 +; network 80 +; +; Since sharing and network collide, we cannot use a test instruction for +; deciding whether a network or a share check in involved +; +FCBDEVICE EQU 040h +FCBNETWORK EQU 080h +FCBSHARE EQU 0C0h + +; FCBSPECIAL must be able to mask off both net and share +FCBSPECIAL EQU 080h +FCBMASK EQU 0C0h diff --git a/SRC/DOS/CPMIO.OBJ b/SRC/DOS/CPMIO.OBJ new file mode 100644 index 0000000..267c9a9 Binary files /dev/null and b/SRC/DOS/CPMIO.OBJ differ diff --git a/SRC/DOS/CPMIO2.OBJ b/SRC/DOS/CPMIO2.OBJ new file mode 100644 index 0000000..78a4cf8 Binary files /dev/null and b/SRC/DOS/CPMIO2.OBJ differ diff --git a/SRC/DOS/CREATE.OBJ b/SRC/DOS/CREATE.OBJ new file mode 100644 index 0000000..01f3dec Binary files /dev/null and b/SRC/DOS/CREATE.OBJ differ diff --git a/SRC/DOS/CRIT.OBJ b/SRC/DOS/CRIT.OBJ new file mode 100644 index 0000000..802df96 Binary files /dev/null and b/SRC/DOS/CRIT.OBJ differ diff --git a/SRC/DOS/CURDIR.INC b/SRC/DOS/CURDIR.INC new file mode 100644 index 0000000..c6325f3 --- /dev/null +++ b/SRC/DOS/CURDIR.INC @@ -0,0 +1,41 @@ +; SCCSID = @(#)curdir.asm 1.1 85/04/10 +; SCCSID = @(#)curdir.asm 1.1 85/04/10 +BREAK +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +; CDS items are used bu the internal routines to store cluster numbers and ; +; network identifiers for each logical name. The ID field is used dually, ; +; both as net ID and for a cluster number for local devices. In the case ; +; of local devices, the cluster number will be -1 if there is a potential ; +; of the disk being changed or if the path must be recracked. The END ; +; field is the location of the end of the definition. No .. is allowed ; +; past this point ; + +DIRSTRLEN EQU 64+3 ; Max length in bytes of directory strings +TEMPLEN EQU DIRSTRLEN*2 + +curdir_list STRUC +curdir_text DB DIRSTRLEN DUP (?) ; text of assignment and curdir +curdir_flags DW ? ; various flags +curdir_devptr DD ? ; local pointer to DPB or net device +curdir_ID DW ? ; cluster of current dir (net ID) + DW ? +curdir_user_word DW ? +curdir_end DW ? ; end of assignment +curdir_list ENDS + +curdirLen EQU Size curdir_list ; Needed for screwed up + ; ASM87 which doesn't allow + ; Size directive as a macro + ; argument +curdir_netID EQU DWORD PTR curdir_ID + +;Flag word masks +curdir_isnet EQU 1000000000000000B +curdir_inuse EQU 0100000000000000B +curdir_splice EQU 0010000000000000B +curdir_local EQU 0001000000000000B +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; diff --git a/SRC/DOS/DELETE.OBJ b/SRC/DOS/DELETE.OBJ new file mode 100644 index 0000000..d046f81 Binary files /dev/null and b/SRC/DOS/DELETE.OBJ differ diff --git a/SRC/DOS/DEV.OBJ b/SRC/DOS/DEV.OBJ new file mode 100644 index 0000000..bb50d17 Binary files /dev/null and b/SRC/DOS/DEV.OBJ differ diff --git a/SRC/DOS/DEVSYM.INC b/SRC/DOS/DEVSYM.INC new file mode 100644 index 0000000..aa739d7 --- /dev/null +++ b/SRC/DOS/DEVSYM.INC @@ -0,0 +1,162 @@ +; SCCSID = @(#)DEVSYM.ASM 1.10 85/09/04 +; SCCSID = @(#)DEVSYM.ASM 1.10 85/09/04 + +; THE DEVICE TABLE LIST HAS THE FORM: +SYSDEV STRUC +SDEVNEXT DD ? ;POINTER TO NEXT DEVICE HEADER +SDEVATT DW ? ;ATTRIBUTES OF THE DEVICE +SDEVSTRAT DW ? ;STRATEGY ENTRY POINT +SDEVINT DW ? ;INTERRUPT ENTRY POINT +SDEVNAME DB 8 DUP (?) ;NAME OF DEVICE (ONLY FIRST BYTE USED FOR BLOCK) +SYSDEV ENDS + +; +; ATTRIBUTE BIT MASKS +; +; CHARACTER DEVICES: +; +; BIT 15 -> MUST BE 1 +; 14 -> 1 IF THE DEVICE UNDERSTANDS IOCTL CONTROL STRINGS +; 13 -> 1 IF THE DEVICE SUPPORTS OUTPUT-UNTIL-BUSY +; 12 -> UNUSED +; 11 -> 1 IF THE DEVICE UNDERSTANDS OPEN/CLOSE +; 10 -> MUST BE 0 +; 9 -> MUST BE 0 +; 8 -> UNUSED +; 7 -> UNUSED +; 6 -> UNUSED +; 5 -> UNUSED +; 4 -> 1 IF DEVICE IS RECIPIENT OF INT 29H +; 3 -> 1 IF DEVICE IS CLOCK DEVICE +; 2 -> 1 IF DEVICE IS NULL DEVICE +; 1 -> 1 IF DEVICE IS CONSOLE OUTPUT +; 0 -> 1 IF DEVICE IS CONSOLE INPUT +; +; BLOCK DEVICES: +; +; BIT 15 -> MUST BE 0 +; 14 -> 1 IF THE DEVICE UNDERSTANDS IOCTL CONTROL STRINGS +; 13 -> 1 IF THE DEVICE DETERMINES MEDIA BY EXAMINING THE FAT ID BYTE. +; THIS REQUIRES THE FIRST SECTOR OF THE FAT TO *ALWAYS* RESIDE IN +; THE SAME PLACE. +; 12 -> UNUSED +; 11 -> 1 IF THE DEVICE UNDERSTANDS OPEN/CLOSE/REMOVABLE MEDIA +; 10 -> MUST BE 0 +; 9 -> MUST BE 0 +; 8 -> UNUSED +; 7 -> UNUSED +; 6 -> IF DEVICE HAS SUPPORT FOR GETMAP/SETMAP OF LOGICAL DRIVES. +; IF THE DEVICE UNDERSTANDS GENERIC IOCTL FUNCTION CALLS. +; 5 -> UNUSED +; 4 -> UNUSED +; 3 -> UNUSED +; 2 -> UNUSED +; 1 -> UNUSED +; 0 -> UNUSED +; + +DEVTYP EQU 8000H ; BIT 15 - 1 IF CHAR, 0 IF BLOCK +CHARDEV EQU 8000H +DEVIOCTL EQU 4000H ; BIT 14 - CONTROL MODE BIT +ISFATBYDEV EQU 2000H ; BIT 13 - DEVICE USES FAT ID BYTES, + ; COMP MEDIA. +OUTTILBUSY EQU 2000H ; OUTPUT UNTIL BUSY IS ENABLED +ISNET EQU 1000H ; BIT 12 - 1 IF A NET DEVICE, 0 IF + ; NOT. CURRENTLY BLOCK ONLY. +DEVOPCL EQU 0800H ; BIT 11 - 1 IF THIS DEVICE HAS + ; OPEN,CLOSE AND REMOVABLE MEDIA + ; ENTRY POINTS, 0 IF NOT + +EXTENTBIT EQU 0400H ; BIT 10 - CURRENTLY 0 ON ALL DEVS + ; THIS BIT IS RESERVED FOR FUTURE USE + ; TO EXTEND THE DEVICE HEADER BEYOND + ; ITS CURRENT FORM. + +; NOTE BIT 9 IS CURRENTLY USED ON IBM SYSTEMS TO INDICATE "DRIVE IS SHARED". +; SEE IOCTL FUNCTION 9. THIS USE IS NOT DOCUMENTED, IT IS USED BY SOME +; OF THE UTILITIES WHICH ARE SUPPOSED TO FAIL ON SHARED DRIVES ON SERVER +; MACHINES (FORMAT,CHKDSK,RECOVER,..). + +DEV320 EQU 0040H ;BIT 6 - FOR BLOCK DEVICES, THIS + ;DEVICE SUPPORTS SET/GET MAP OF + ;LOGICAL DRIVES, AND SUPPORTS + ;GENERIC IOCTL CALLS. + ;FOR CHARACTER DEVICES, THIS + ;DEVICE SUPPORTS GENERIC IOCTL. + ;THIS IS A DOS 3.2 DEVICE DRIVER. +ISSPEC EQU 0010H ;BIT 4 - THIS DEVICE IS SPECIAL +ISCLOCK EQU 0008H ;BIT 3 - THIS DEVICE IS THE CLOCK DEVICE. +ISNULL EQU 0004H ;BIT 2 - THIS DEVICE IS THE NULL DEVICE. +ISCOUT EQU 0002H ;BIT 1 - THIS DEVICE IS THE CONSOLE OUTPUT. +ISCIN EQU 0001H ;BIT 0 - THIS DEVICE IS THE CONSOLE INPUT. + +;STATIC REQUEST HEADER +SRHEAD STRUC +REQLEN DB ? ;LENGTH IN BYTES OF REQUEST BLOCK +REQUNIT DB ? ;DEVICE UNIT NUMBER +REQFUNC DB ? ;TYPE OF REQUEST +REQSTAT DW ? ;STATUS WORD + DB 8 DUP(?) ;RESERVED FOR QUEUE LINKS +SRHEAD ENDS + +;STATUS WORD MASKS +STERR EQU 8000H ;BIT 15 - ERROR +STBUI EQU 0200H ;BIT 9 - BUISY +STDON EQU 0100H ;BIT 8 - DONE +STECODE EQU 00FFH ;ERROR CODE + +;FUNCTION CODES +DEVINIT EQU 0 ;INITIALIZATION +DINITHL EQU 26 ;SIZE OF INIT HEADER +DEVMDCH EQU 1 ;MEDIA CHECK +DMEDHL EQU 15 ;SIZE OF MEDIA CHECK HEADER +DEVBPB EQU 2 ;GET BPB +DEVRDIOCTL EQU 3 ;IOCTL READ +DBPBHL EQU 22 ;SIZE OF GET BPB HEADER +DEVRD EQU 4 ;READ +DRDWRHL EQU 22 ;SIZE OF RD/WR HEADER +DEVRDND EQU 5 ;NON DESTRUCTIVE READ NO WAIT (CHARACTER DEVS) +DRDNDHL EQU 14 ;SIZE OF NON DESTRUCTIVE READ HEADER +DEVIST EQU 6 ;INPUT STATUS +DSTATHL EQU 13 ;SIZE OF STATUS HEADER +DEVIFL EQU 7 ;INPUT FLUSH +DFLSHL EQU 15 ;SIZE OF FLUSH HEADER +DEVWRT EQU 8 ;WRITE +DEVWRTV EQU 9 ;WRITE WITH VERIFY +DEVOST EQU 10 ;OUTPUT STATUS +DEVOFL EQU 11 ;OUTPUT FLUSH +DEVWRIOCTL EQU 12 ;IOCTL WRITE +DEVOPN EQU 13 ;DEVICE OPEN +DEVCLS EQU 14 ;DEVICE CLOSE +DOPCLHL EQU 13 ;SIZE OF OPEN/CLOSE HEADER +DEVRMD EQU 15 ;REMOVABLE MEDIA +REMHL EQU 13 ;SIZE OF REMOVABLE MEDIA HEADER +GENIOCTL EQU 19 +; THE NEXT THREE ARE USED IN DOS 4.0 +; 20 +; 21 +; 22 +DEVGETOWN EQU 23 ;GET DEVICE OWNER +DEVSETOWN EQU 24 ;SET DEVICE OWNER +OWNHL EQU 13 ;SIZE OF DEVICE OWNER HEADER + +DEVOUT EQU 16 ; OUTPUT UNTIL BUSY. +DEVOUTL EQU DEVWRT ; LENGTH OF OUTPUT UNTIL BUSY + +; GENERIC IOCTL REQUEST STRUCTURE +; SEE THE DOS 4.0 DEVICE DRIVER SPEC FOR FURTHER ELABORATION. +; +IOCTL_REQ STRUC + DB (SIZE SRHEAD) DUP(?) + ; GENERIC IOCTL ADDITION. +MAJORFUNCTION DB ? ;FUNCTION CODE +MINORFUNCTION DB ? ;FUNCTION CATEGORY +REG_SI DW ? +REG_DI DW ? +GENERICIOCTL_PACKET DD ? ; POINTER TO DATA BUFFER +IOCTL_REQ ENDS + +; DEFINITIONS FOR IOCTL_REQ.MINORFUNCTION +GEN_IOCTL_WRT_TRK EQU 40H +GEN_IOCTL_RD_TRK EQU 60H +GEN_IOCTL_FN_TST EQU 20H ; USED TO DIFF. BET READS AND WRTS diff --git a/SRC/DOS/DINFO.OBJ b/SRC/DOS/DINFO.OBJ new file mode 100644 index 0000000..51e147c Binary files /dev/null and b/SRC/DOS/DINFO.OBJ differ diff --git a/SRC/DOS/DIR.OBJ b/SRC/DOS/DIR.OBJ new file mode 100644 index 0000000..7ada256 Binary files /dev/null and b/SRC/DOS/DIR.OBJ differ diff --git a/SRC/DOS/DIR2.OBJ b/SRC/DOS/DIR2.OBJ new file mode 100644 index 0000000..dcfddfd Binary files /dev/null and b/SRC/DOS/DIR2.OBJ differ diff --git a/SRC/DOS/DIRCALL.OBJ b/SRC/DOS/DIRCALL.OBJ new file mode 100644 index 0000000..4ad978a Binary files /dev/null and b/SRC/DOS/DIRCALL.OBJ differ diff --git a/SRC/DOS/DIRENT.INC b/SRC/DOS/DIRENT.INC new file mode 100644 index 0000000..a6db992 --- /dev/null +++ b/SRC/DOS/DIRENT.INC @@ -0,0 +1,58 @@ +; SCCSID = @(#)dirent.asm 1.1 85/04/10 +; SCCSID = @(#)dirent.asm 1.1 85/04/10 +Break + +; +; +---------------------------+ +; | (12 BYTE) filename/ext | 0 0 +; +---------------------------+ +; | (BYTE) attributes | 11 B +; +---------------------------+ +; | (10 BYTE) reserved | 12 C +; +---------------------------+ +; | (WORD) time of last write | 22 16 +; +---------------------------+ +; | (WORD) date of last write | 24 18 +; +---------------------------+ +; | (WORD) First cluster | 26 1A +; +---------------------------+ +; | (DWORD) file size | 28 1C +; +---------------------------+ +; +; First byte of filename = E5 -> free directory entry +; = 00 -> end of allocated directory +; Time: Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour +; Date: Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980 +; + +dir_entry STRUC +dir_name DB 11 DUP (?) ; file name +dir_attr DB ? ; attribute bits +dir_pad DB 10 DUP (?) ; reserved for expansion +dir_time DW ? ; time of last write +dir_date DW ? ; date of last write +dir_first DW ? ; first allocation unit of file +dir_size_l DW ? ; low 16 bits of file size +dir_size_h DW ? ; high 16 bits of file size +dir_entry ENDS + +attr_read_only EQU 1h +attr_hidden EQU 2h +attr_system EQU 4h +attr_volume_id EQU 8h +attr_directory EQU 10h +attr_archive EQU 20h +attr_device EQU 40h ; This is a VERY special bit. + ; NO directory entry on a disk EVER + ; has this bit set. It is set non-zero + ; when a device is found by GETPATH + +attr_all EQU attr_hidden+attr_system+attr_directory + ; OR of hard attributes for FINDENTRY + +attr_ignore EQU attr_read_only+attr_archive+attr_device + ; ignore this(ese) attribute(s) during + ; search first/next + +attr_changeable EQU attr_read_only+attr_hidden+attr_system+attr_archive + ; changeable via CHMOD diff --git a/SRC/DOS/DISK.OBJ b/SRC/DOS/DISK.OBJ new file mode 100644 index 0000000..b8322b3 Binary files /dev/null and b/SRC/DOS/DISK.OBJ differ diff --git a/SRC/DOS/DISK2.OBJ b/SRC/DOS/DISK2.OBJ new file mode 100644 index 0000000..d402157 Binary files /dev/null and b/SRC/DOS/DISK2.OBJ differ diff --git a/SRC/DOS/DISK3.OBJ b/SRC/DOS/DISK3.OBJ new file mode 100644 index 0000000..b8609cb Binary files /dev/null and b/SRC/DOS/DISK3.OBJ differ diff --git a/SRC/DOS/DIVMES.INC b/SRC/DOS/DIVMES.INC new file mode 100644 index 0000000..9902382 --- /dev/null +++ b/SRC/DOS/DIVMES.INC @@ -0,0 +1,12 @@ +; THIS IS THE ONLY DOS "MESSAGE". IT DOES NOT NEED A TERMINATOR. + PUBLIC DIVMES +Public DIVM001S,DIVM001E +DIVM001S label byte + +;include divmes.inc +DIVMES DB 13,10,"Divide overflow",13,10 + + + PUBLIC DivMesLen +DivMesLen DW $-DivMes ; Length of the above message in bytes +DIVM001E label byte diff --git a/SRC/DOS/DOSCNTRY.INC b/SRC/DOS/DOSCNTRY.INC new file mode 100644 index 0000000..dceca6e --- /dev/null +++ b/SRC/DOS/DOSCNTRY.INC @@ -0,0 +1,86 @@ +; +;Equates for COUNTRY INFORMATION. +SetCountryInfo EQU 1 ;country info +SetUcase EQU 2 ;uppercase table +SetLcase EQU 3 ;lowercase table (Reserved) +SetUcaseFile EQU 4 ;uppercase file spec table +SetFileList EQU 5 ;valid file character list +SetCollate EQU 6 ;collating sequence +SetDBCS EQU 7 ;double byte character set +SetALL EQU -1 ;all the entries + + +;DOS country and code page information table structure. +;Internally, IBMDOS gives a pointer to this table. +;IBMBIO, MODE and NLSFUNC modules communicate with IBMDOS through +;this structure. +DOS_country_cdpg_info struc +ccInfo_reserved db 8 dup (?) ;reserved for internal use +ccPath_CountrySys db 64 dup (0);path and filename for country info +ccSysCodePage dw 0 ;system code page id +ccNumber_of_entries dw 5 +ccSetUcase db SetUcase +ccUcase_ptr dd ? ;pointer to Ucase table + +ccSetUcaseFile db SetUcaseFile +ccFileUcase_ptr dd ? ;pointer to File Ucase table + +ccSetFileList db SetFileList +ccFileChar_ptr dd ? ;pointer to File char list table + +ccSetCollate db SetCollate +ccCollate_ptr dd ? ;pointer to collate table + +ccSetCountryInfo db SetCountryInfo +ccCountryInfoLen dw ? ;length of country info +ccDosCountry dw ? ;system country code id +ccDosCodePage dw ? ;system code page id +ccDFormat dw ? ;date format +ccCurSymbol db " ",0;5 byte of (currency symbol+0) +cc1000Sep db " ",0 ;2 byte of (1000 sep. + 0) +ccDecSep db " ",0 ;2 byte of (Decimal sep. + 0) +ccDateSep db " ",0 ;2 byte of (date sep. + 0) +ccTimeSep db " ",0 ;2 byte of (time sep. + 0) +ccCFormat db ? ;currency format flags +ccCSigDigits db ? ;# of digits in currency +ccTFormat db ? ;time format +ccMono_Ptr dd ? ;monocase routine entry point +ccListSep db " ",0 ;data list separator +ccReserved_area dw 5 dup(?);reserved + +DOS_country_cdpg_info ends + +;Ucase table +CC_UCASE_TAB struc +ccUcase_leng dw 128 +ccUcase_data db 128 dup (?) +CC_UCASE_TAB ends + +;File Ucase table +CC_FILE_UCASE_TAB struc +ccFileucase_leng dw 128 +ccFileucase_data db 128 dup (?) +CC_FILE_UCASE_TAB ends + +;File char list +CC_FILE_CHAR_TAB struc +ccFilechar_leng dw ? +ccFilechar_data db 46 dup (?) +CC_FILE_CHAR_TAB ends + +;collate table +CC_COLLATE_TAB struc +ccCollate_leng dw 256 +ccCollate_data db 256 dup (?) +CC_COLLATE_TAB ends + +;DBCS table - Not for DOS 3.30 +;CC_DBCS_TAB struc +; ccDBCS_leng dw 4 +; ccDBCS_data db 4 dup (?) +;CC_DBCS_TAB ends + +OLD_COUNTRY_SIZE equ (type DOS_country_cdpg_info - ccDFormat - 10) +NEW_COUNTRY_SIZE equ (type DOS_country_cdpg_info - ccDosCountry) + + \ No newline at end of file diff --git a/SRC/DOS/DOSMAC.INC b/SRC/DOS/DOSMAC.INC new file mode 100644 index 0000000..bf500ae --- /dev/null +++ b/SRC/DOS/DOSMAC.INC @@ -0,0 +1,630 @@ +; SCCSID = @(#)dosmac.asm 1.1 85/04/10 +; SCCSID = @(#)dosmac.asm 1.1 85/04/10 +; +; Macro file for MSDOS. +; + +TRUE EQU 0FFFFh +FALSE EQU 0 + +SUBTTL BREAK a listing into pages and give new subtitles +PAGE +BREAK MACRO subtitle + SUBTTL subtitle + PAGE +ENDM +.xcref break + +BREAK + +AsmVars Macro varlist +IRP var, +AsmVar var +ENDM +ENDM + +AsmVar Macro var +IFNDEF var +var = FALSE +ENDIF +ENDM + +BREAK + +; +; declare a variable external and allocate a size +; +AsmVar InstalledData +I_NEED MACRO sym,len +IF NOT InstalledData + DATA SEGMENT WORD PUBLIC 'DATA' + IFIDN , + EXTRN &sym:WORD + ELSE + IFIDN , + EXTRN &sym:DWORD + ELSE + EXTRN &sym:BYTE + ENDIF + ENDIF + DATA ENDS +ENDIF +ENDM + .xcref I_need + +; +; call a procedure that may be external. The call will be short. +; +invoke MACRO name +.xcref + IF2 + IFNDEF name + EXTRN name:NEAR + ENDIF + ENDIF +.cref + CALL name +ENDM +.xcref invoke + +PAGE +; +; jump to a label that may be external. The jump will be near. +; +transfer MACRO name +.xcref + IF2 + IFNDEF name + EXTRN name:NEAR + ENDIF + ENDIF +.cref + JUMP name +ENDM +.xcref transfer + +; +; get a short address in a word +; +short_addr MACRO name + IFDIF , +.xcref + IF2 + IFNDEF name + EXTRN name:NEAR + ENDIF + ENDIF +.cref + DW OFFSET DOSGROUP:name + ELSE + DW ? + ENDIF +ENDM +.xcref short_addr + +; +; get a long address in a dword +; +long_addr MACRO name +.xcref + IF2 + IFNDEF name + EXTRN name:NEAR + ENDIF + ENDIF +.cref + DD name +ENDM +.xcref long_addr + +; +; declare a PROC near or far but PUBLIC nonetheless +; +.xcref ?frame +.xcref ?aframe +.xcref ?stackdepth +.xcref ?initstack +?frame = 0 ; initial +?aframe = 0 ; initial +?stackdepth = 0 ; initial stack size +?initstack = 0 ; initial stack size + +procedure MACRO name,distance + ?frame = 0 + ?aframe = 2 ;; remember the pushed BP + PUBLIC name + IF1 +;; %OUT name... pass 1 + ENDIF + IF2 +;; %OUT name... pass 2 + ENDIF +name PROC distance + ?initstack = ?stackdepth ;; beginning of procedure +ENDM +.xcref procedure + +; +; end a procedure and check that stack depth is preserved +; +EndProc MACRO name, chk + IFDIF , ;; check the stack size + IF2 + IF ?initstack NE ?stackdepth ;; is it different? + %OUT ***** Possible stack size error in name ***** + ENDIF + ENDIF + ENDIF +name ENDP +ENDM +.xcref endproc +PAGE +; +; define a data item to be public and of an appropriate size/type +; + +I_AM MACRO name,size,init +;; declare the object public + PUBLIC name +;; declare the type of the object + IFIDN , +name LABEL WORD + I_AM_SIZE = 1 + I_AM_LEN = 2 + ELSE + IFIDN , +name LABEL DWORD + I_AM_SIZE = 2 + I_AM_LEN = 2 + ELSE + IFIDN , +name LABEL BYTE + I_AM_SIZE = 1 + I_AM_LEN = 1 + ELSE +name LABEL BYTE + I_AM_SIZE = size + I_AM_LEN = 1 + ENDIF + ENDIF + ENDIF +;; if no initialize then allocate blank storage + IFB + DB I_AM_SIZE*I_AM_LEN DUP (?) + ELSE +IF NOT InstalledData + IRP itm, + IF I_AM_LEN EQ 1 + DB itm + ELSE + DW itm + ENDIF + I_AM_SIZE = I_AM_SIZE - 1 + ENDM + IF I_AM_SIZE NE 0 + %out ***** initialization of name not complete ***** + ENDIF +ELSE + DB I_AM_SIZE*I_AM_LEN DUP (?) +ENDIF + ENDIF +ENDM +.xcref I_AM +.xcref I_AM_SIZE +.xcref I_AM_LEN +I_AM_SIZE = 0 +I_AM_LEN = 0 + +PAGE + +; +; define an entry in a procedure +; +entry macro name + PUBLIC name +name: +endm +.xcref entry + +BREAK + +error macro code +.xcref + MOV AL,code + transfer SYS_RET_ERR +.cref +ENDM +.xcref error + +BREAK +; +; given a label either 2 byte jump to another label _J +; if it is near enough or 3 byte jump to +; + +jump macro lbl + local a +.xcref + + ifndef lbl&_J ;; is this the first invocation +a: JMP lbl + ELSE + IF (lbl&_J GE $) OR ($-lbl&_J GT 126) +a: JMP lbl ;; is the jump too far away? + ELSE +a: JMP lbl&_J ;; do the short one... + ENDIF + ENDIF + lbl&_j = a +.cref +endm +.xcref jump + +BREAK + +return macro x + local a +.xcref +a: + RET +ret_l = a +.cref +endm +.xcref return + +BREAK + +condret macro cc,ncc + local a +.xcref +.xcref a +.cref + ifdef ret_l ;; if ret_l is defined + if (($ - ret_l) le 126) and ($ gt ret_l) + ;; if ret_l is near enough then + a: j&cc ret_l ;; a: j to ret_l + ret_&cc = a ;; define ret_ to be a: + exitm + endif + endif + ifdef ret_&cc ;; if ret_ defined + if (($ - ret_&cc) le 126) and ($ gt ret_&cc) + ;; if ret_ is near enough + a: j&cc ret_&cc ;; a: j to ret_ + ret_&cc = a ;; define ret_ to be a: + exitm + endif + endif + j&ncc a ;; j a: + return ;; return + a: ;; a: + ret_&cc = ret_l ;; define ret_ to be ret_l +endm +.xcref condret + +BREAK + +retz macro + condret z,nz +endm +.xcref retz + +BREAK + +retnz macro + condret nz,z +endm +.xcref retnz + +BREAK + +retc macro + condret c,nc +endm +.xcref retc + +BREAK + +retnc macro + condret nc,c +endm +.xcref retnc + +BREAK + +context macro r + PUSH SS + POP r + ASSUME r:DOSGROUP +endm +.xcref context + +BREAK + +SaveReg MACRO reglist ;; push those registers +IRP reg, + ?stackdepth = ?stackdepth + 1 + PUSH reg +ENDM +ENDM +.xcref SaveReg + +BREAK + +RestoreReg MACRO reglist ;; pop those registers +IRP reg, + ?stackdepth = ?stackdepth - 1 + POP reg +ENDM +ENDM +.xcref RestoreReg + +BREAK + +EnterCrit MACRO section + Invoke E§ion +ENDM + +LeaveCrit MACRO section + Invoke L§ion +ENDM + +Break + +AsmVars + +if debug +fmt MACRO typ,lev,fmts,args +local a,b,c + PUSHF +IFNB + TEST BugTyp,typ + JZ c + CMP BugLev,lev + JB c +ENDIF + PUSH AX + PUSH BP + MOV BP,SP +If (not sharef) and (not redirector) +Table segment +a db fmts,0 +Table ends + MOV AX,OFFSET DOSGROUP:a +else + jmp short b +a db fmts,0 +if sharef +b: mov ax,offset share:a +else +b: mov ax,offset netwrk:a +endif +endif + PUSH AX +cargs = 2 +IRP item, +IFIDN , + MOV AX,[BP+2] +ELSE + MOV AX,item +ENDIF + PUSH AX +cargs = cargs + 2 +ENDM + invoke PFMT + ADD SP,Cargs + POP BP + POP AX +c: + POPF +ENDM +else +fmt macro +endm +endif + +Break + +AsmVar Debug,$temp + +IF debug +DOSAssume Macro reg,reglist,message +local a,b + IFIDN , + $temp = 1 + ELSE + IFIDN , + $temp = 0 + ELSE + %out ***** Invalid DOS register reg in DOSAssume ***** + ENDIF + ENDIF + IRP r, + IFIDN , + $temp = $temp OR 2 + ELSE + IFIDN , + $temp = $temp OR 4 + ELSE + %out ***** Invalid register reg in DOSAssume ***** + ENDIF + ENDIF + ENDM + PUSH AX + MOV AX,$temp + PUSH AX +IF SHAREF + MOV AX,OFFSET a +ELSE + MOV AX,OFFSET DOSGroup:a +ENDIF + PUSH AX + Invoke SegCheck + POP AX +IF NOT SHAREF +Table SEGMENT +a DB message,0 +Table ends +ELSE + JMP SHORT a +b DB message,0 +a: +ENDIF +IRP r, + ASSUME r:DOSGroup +ENDM +ENDM +ELSE +DOSAssume Macro reg,reglist,message +IRP r, + ASSUME r:DOSGroup +ENDM +ENDM +ENDIF + +BREAK + +IF DEBUG +Assert MACRO kind, objs, message + LOCAL a,b + IFIDN , + CMP objs,0 + JZ a + fmt <>,<>, +a: + ELSE + IFIDN , + CMP objs,0 + JNZ a + fmt <>,<>, +a: + ELSE + PUSH AX + IRP obj, + PUSH obj + ENDM + IF SHAREF + MOV AX,OFFSET b + ELSE + MOV AX,OFFSET DOSGroup:b + ENDIF + PUSH AX + IFIDN , + Invoke BUFCheck + ENDIF + IFIDN , + Invoke SFTCheck + ENDIF + IFIDN , + Invoke DPBCheck + ENDIF + POP AX + IF SHAREF + JMP SHORT a +b DB Message,0 +a: + ELSE +Table segment +b db Message,0 +Table ends + ENDIF + ENDIF + ENDIF +ENDM +ELSE +Assert Macro +ENDM +ENDIF + +Break + +CallInstall MACRO name,mpx,fn,save,restore +IF Installed + IFNB + SaveReg + ENDIF + MOV AX,(mpx SHL 8) + fn + INT 2Fh + IFNB + RestoreReg + ENDIF +ELSE + Invoke name +ENDIF +ENDM + +Break + +localvar macro name,length +local a + ifidn , + ?frame = ?frame + 1 + a = ?frame + name EQU BYTE PTR [BP-a] + else + ifidn , + ?frame = ?frame + 2 + a = ?frame + name EQU WORD PTR [BP-a] + else + ifidn , + ?frame = ?frame + 4 + a = ?frame + name EQU DWORD PTR [BP-a] + name&l EQU WORD PTR [BP-a] + name&h EQU WORD PTR [BP-a+2] + else + ?frame = ?frame + length + a = ?frame + name EQU BYTE PTR [BP-a] + endif + endif + endif +endm + +enter macro + push bp + mov bp,sp + sub sp,?frame +endm + +leave macro + mov sp,bp + pop bp +endm + +Argvar macro name,length +local a + ifidn , + a = ?aframe + ?aframe = ?aframe + 1 + name EQU BYTE PTR [BP+a] + else + ifidn , + a = ?aframe + ?aframe = ?aframe + 2 + name EQU WORD PTR [BP+a] + else + ifidn , + a = ?aframe + ?aframe = ?aframe + 4 + name EQU DWORD PTR [BP+a] + name&l EQU WORD PTR [BP+a] + name&h EQU WORD PTR [BP+a+2] + else + a = ?aframe + ?aframe = ?aframe + length + name EQU BYTE PTR [BP+a] + endif + endif + endif +endm + +BREAK + +errnz macro x +if x NE 0 + %out ***** FATAL error: x <> 0 +foobar +endif +endm diff --git a/SRC/DOS/DOSMES.INC b/SRC/DOS/DOSMES.INC new file mode 100644 index 0000000..61d65ef --- /dev/null +++ b/SRC/DOS/DOSMES.INC @@ -0,0 +1,485 @@ +; SCCSID = @(#)dosmes.asm 1.7 85/10/23 +; SCCSID = @(#)dosmes.asm 1.7 85/10/23 +; +; Message file for Internationalized messages. There is +; only one message here available for translation. +; + +IFNDEF KANJI +KANJI EQU FALSE +ENDIF + +IFNDEF Rainbow +Rainbow EQU FALSE +ENDIF + +include dosmac.inc +include intnat.inc +include doscntry.inc + +CONSTANTS SEGMENT WORD PUBLIC 'CONST' + + PUBLIC UserNum, OEMNum + Public DMES001S,DMES001E +DMES001S Label byte +USERNUM DW ? ; 24 bit user number + DB ? + IF IBM +OEMNUM DB 0 ; 8 bit OEM number + ELSE +OEMNUM DB 0FFH ; 8 bit OEM number + ENDIF + +; +; The next variable points to the country table for the current country +; ( the table returned by the AL=0 INTERNATIONAL call). +; + PUBLIC Current_Country + + IF KANJI +Current_Country DW OFFSET DOSGROUP:JAPTABLE + ELSE +Current_Country DW OFFSET DOSGROUP:USTABLE + ENDIF + +DMES001E label byte +CONSTANTS ENDS + +TABLE SEGMENT BYTE PUBLIC 'TABLE' +Public DMES002S +DMES002S label byte + +; +; The international tabel(s). Used for DOS 3.x (x < 3) +; This is simply a sequence of tables of the following form: +; +; Offset +; BYTE Size of this table excluding this byte and the next +; WORD Country code represented by this table +; A sequence of n bytes, where n is the number specified +; by the first byte above and is not > internat_block_max, +; in the correct order for being returned by the +; INTERNATIONAL call as follows: +; WORD Date format 0=mdy, 1=dmy, 2=ymd +; 5 BYTE Currency symbol null terminated +; 2 BYTE thousands separator null terminated +; 2 BYTE Decimal point null terminated +; 2 BYTE Date separator null terminated +; 2 BYTE Time separator null terminated +; 1 BYTE Bit field. Currency format. +; Bit 0. =0 $ before # =1 $ after # +; Bit 1. no. of spaces between # and $ (0 or 1) +; Bit 2. =1 imbedded at decimal point, & no spaces; +; 1 BYTE No. of significant decimal digits in currency +; 1 BYTE Bit field. Time format. +; Bit 0. =0 12 hour clock =1 24 hour +; WORD Segment offset for address of case conversion routine +; WORD RESERVED. Filled in by DOS. Segment value for above routine +; 2 BYTE Data list separator null terminated. +; NOTE: The segment part of the DWORD Map_call is set +; by the INTERNATIONAL call. Do not try to initialize +; it to anything meaningful. +; +; The list of tables is terminated by putting a byte of -1 after the last +; table (a table with length -1). + + PUBLIC international_table + +international_table LABEL BYTE + + IF KANJI + DB SIZE internat_block ; Size in bytes of this table + DW 81 ; Country code +JAPTABLE internat_block <2,'\',0,0,0,0,',',0,'.',0,'-',0,':',0,0,0,1,OFFSET DOSGROUP:MAP_CASE , 0,',',0> + ENDIF + + DB SIZE internat_block ; Size in bytes of this table + DW 1 ; Country code +USTABLE internat_block <0,'$',0,0,0,0,',',0,'.',0,'-',0,':',0,0,2,0,OFFSET DOSGROUP:MAP_CASE,0,',',0> +; Tables for the IBM PC character set follow. The values +; associated with some of the currency symbols may change with +; other character sets. You may wish to add or delete country +; entries. NOTE: It is not a mistake that the JAPANESE entry +; has different currency symbols for the KANJI and +; non-KANJI versions. + + DB -1 ; end of table + +; The following table is used for DOS 3.3 +;DOS country and code page information is defined here for DOS 3.3. +;The initial value for ccDosCountry is 1 (USA). +;The initial value for ccDosCodepage is 850. +; +; + PUBLIC COUNTRY_CDPG,UCASE_TAB,FILE_UCASE_TAB + PUBLIC FILE_CHAR_TAB +; +; country and code page infomation +; +COUNTRY_CDPG label byte + + db 0,0,0,0,0,0,0,0 ; reserved words + db '\COUNTRY.SYS',0 ; path name of country.sys + db 51 dup (?) + dw 437 ; system code page id + dw 5 ; number of entries + db SetUcase ; Ucase type + dw OFFSET DOSGROUP:UCASE_TAB ;pointer to upper case table + dw 0 ; segment of poiter + db SetUcaseFile ; Ucase file char type + dw OFFSET DOSGROUP:FILE_UCASE_TAB ;pointer to file upper case table + dw 0 ; segment of poiter + db SetFileList ; valid file chars type + dw OFFSET DOSGROUP:FILE_CHAR_TAB ;pointer to valid file char tab + dw 0 ; segment of poiter + db SetCollate ; collate type + dw OFFSET DOSGROUP:COLLATE_TAB ;pointer to collate table + dw 0 ; segment of poiter + db SetCountryInfo ; country info type + dw NEW_COUNTRY_SIZE ; extended country info size + dw 1 ; USA country id + dw 437 ; USA system code page id + dw 0 ; date format + db '$',0,0,0,0 ; currency symbol + db ',',0 ; thousand separator + db '.',0 ; decimal separator + db '-',0 ; date separator + db ':',0 ; time separator + db 0 ; currency format flag + db 2 ; # of disgit in currency + db 0 ; time format + dw OFFSET DOSGROUP:MAP_CASE ;mono case routine entry point + dw 0 ; segment of entry point + db ',',0 ; data list separator + dw 0,0,0,0,0 ; reserved + + + +; +; +; +; +; +; upper case table +; +UCASE_TAB label byte + dw 128 + db 128,154,069,065,142,065,143,128 + db 069,069,069,073,073,073,142,143 + db 144,146,146,079,153,079,085,085 + db 089,153,154,155,156,157,158,159 + db 065,073,079,085,165,165,166,167 + db 168,169,170,171,172,173,174,175 + db 176,177,178,179,180,181,182,183 + db 184,185,186,187,188,189,190,191 + db 192,193,194,195,196,197,198,199 + db 200,201,202,203,204,205,206,207 + db 208,209,210,211,212,213,214,215 + db 216,217,218,219,220,221,222,223 + db 224,225,226,227,228,229,230,231 + db 232,233,234,235,236,237,238,239 + db 240,241,242,243,244,245,246,247 + db 248,249,250,251,252,253,254,255 + +; +; file upper case table +; +FILE_UCASE_TAB label byte + dw 128 + db 128,154,069,065,142,065,143,128 + db 069,069,069,073,073,073,142,143 + db 144,146,146,079,153,079,085,085 + db 089,153,154,155,156,157,158,159 + db 065,073,079,085,165,165,166,167 + db 168,169,170,171,172,173,174,175 + db 176,177,178,179,180,181,182,183 + db 184,185,186,187,188,189,190,191 + db 192,193,194,195,196,197,198,199 + db 200,201,202,203,204,205,206,207 + db 208,209,210,211,212,213,214,215 + db 216,217,218,219,220,221,222,223 + db 224,225,226,227,228,229,230,231 + db 232,233,234,235,236,237,238,239 + db 240,241,242,243,244,245,246,247 + db 248,249,250,251,252,253,254,255 + +; +; file char list +; +FILE_CHAR_TAB label byte + dw 22 ; length + db 1,0,255 ; include all + db 0,0,20h ; exclude 0 - 20h + db 2,14,'."/\[]:|<>+=;,' ; exclude 14 special + db 24 dup (?) ; reserved +; +; collate table +; +COLLATE_TAB label byte + dw 256 + db 0,1,2,3,4,5,6,7 + db 8,9,10,11,12,13,14,15 + db 16,17,18,19,20,21,22,23 + db 24,25,26,27,28,29,30,31 + db " ","!",'"',"#","$","%","&","'" + db "(",")","*","+",",","-",".","/" + db "0","1","2","3","4","5","6","7" + db "8","9",":",";","<","=",">","?" + db "@","A","B","C","D","E","F","G" + db "H","I","J","K","L","M","N","O" + db "P","Q","R","S","T","U","V","W" + db "X","Y","Z","[","\","]","^","_" + db "`","A","B","C","D","E","F","G" + db "H","I","J","K","L","M","N","O" + db "P","Q","R","S","T","U","V","W" + db "X","Y","Z","{","|","}","~",127 + db "C","U","E","A","A","A","A","C" + db "E","E","E","I","I","I","A","A" + db "E","A","A","O","O","O","U","U" + db "Y","O","U","$","$","$","$","$" + db "A","I","O","U","N","N",166,167 + db "?",169,170,171,172,"!",'"','"' + db 176,177,178,179,180,181,182,183 + db 184,185,186,187,188,189,190,191 + db 192,193,194,195,196,197,198,199 + db 200,201,202,203,204,205,206,207 + db 208,209,210,211,212,213,214,215 + db 216,217,218,219,220,221,222,223 + db 224,"S" + db 226,227,228,229,230,231 + db 232,233,234,235,236,237,238,239 + db 240,241,242,243,244,245,246,247 + db 248,249,250,251,252,253,254,255 +; +; dbcs is not supported in DOS 3.3 +; DBCS_TAB CC_DBCS <> +; +; +include divmes.inc + +TABLE ENDS + +CODE SEGMENT BYTE PUBLIC 'CODE' +ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING + +;CASE MAPPER ROUTINE FOR 80H-FFH character range, DOS 3.3 +; ENTRY: AL = Character to map +; EXIT: AL = The converted character +; Alters no registers except AL and flags. +; The routine should do nothing to chars below 80H. +; +; Example: + +Procedure MAP_CASE,FAR +IF NOT KANJI +IF IBM + CMP AL,80H + JAE Map1 ;Map no chars below 80H ever + RET +Map1: + SUB AL,80H ;Turn into index value + PUSH DS + PUSH BX + MOV BX,OFFSET DOSGROUP:UCASE_TAB + 2 +FINISH: + PUSH CS ;Move to DS + POP DS + XLAT ds:[bx] ;Get upper case character + POP BX + POP DS +ENDIF +ENDIF +L_RET: RET +EndProc MAP_CASE + +SUBTTL EDIT FUNCTION ASSIGNMENTS AND HEADERS +PAGE +; The following two tables implement the current buffered input editing +; routines. The tables are pairwise associated in reverse order for ease +; in indexing. That is; The first entry in ESCTAB corresponds to the last +; entry in ESCFUNC, and the last entry in ESCTAB to the first entry in ESCFUNC. + + +TABLE SEGMENT + PUBLIC CANCHAR +CANCHAR DB CANCEL ;Cancel line character + PUBLIC ESCCHAR +ESCCHAR DB ESCCH ;Lead-in character for escape sequences + IF NOT Rainbow +ESCTAB LABEL BYTE + IF NOT IBM + IF WANG + DB 0C0h ; ^Z inserter + DB 0C1H ; Copy one char + DB 0C1H ; Copy one char + DB 0C7H ; Skip one char + DB 08AH ; Copy to char + DB 088H ; Skip to char + DB 09AH ; Copy line + DB 0CBH ; Kill line (no change in template) + DB 08BH ; Reedit line (new template) + DB 0C3H ; Backspace + DB 0C6H ; Enter insert mode + DB 0D6H ; Exit insert mode + DB 0C6H ; Escape character + DB 0C6H ; End of table + ELSE + ; VT52 equivalences + DB "Z" ; ^Z inserter + DB "S" ; F1 Copy one char + DB "S" ; F1 Copy one char + DB "V" ; F4 Skip one char + DB "T" ; F2 Copy to char + DB "W" ; F5 Skip to char + DB "U" ; F3 Copy line + DB "E" ; SHIFT ERASE Kill line (no change in template) + DB "J" ; ERASE Reedit line (new template) + DB "D" ; LEFT Backspace + DB "P" ; BLUE Enter insert mode + DB "Q" ; RED Exit insert mode + DB "R" ; GRAY Escape character + DB "R" ; End of table + ENDIF + ENDIF + IF IBM + DB 64 ; Ctrl-Z - F6 + DB 77 ; Copy one char - --> + DB 59 ; Copy one char - F1 + DB 83 ; Skip one char - DEL + DB 60 ; Copy to char - F2 + DB 62 ; Skip to char - F4 + DB 61 ; Copy line - F3 + DB 61 ; Kill line (no change to template ) - Not used + DB 63 ; Reedit line (new template) - F5 + DB 75 ; Backspace - <-- + DB 82 ; Enter insert mode - INS (toggle) + DB 82 ; Exit insert mode - INS (toggle) + DB 65 ; Escape character - F7 + DB 65 ; End of table + ENDIF +ESCEND LABEL BYTE +ESCTABLEN EQU ESCEND-ESCTAB + +ESCFUNC LABEL WORD + short_addr GETCH ; Ignore the escape sequence + short_addr TWOESC + short_addr EXITINS + short_addr ENTERINS + short_addr BACKSP + short_addr REEDIT + short_addr KILNEW + short_addr COPYLIN + short_addr SKIPSTR + short_addr COPYSTR + short_addr SKIPONE + short_addr COPYONE + short_addr COPYONE + short_addr CTRLZ + ENDIF +TABLE ENDS + +; +; OEMFunction key is expected to process a single function +; key input from a device and dispatch to the proper +; routines leaving all registers UNTOUCHED. +; +; Inputs: CS, SS are DOSGROUP +; Outputs: None. This function is expected to JMP to one of +; the following labels: +; +; GetCh - ignore the sequence +; TwoEsc - insert an ESCChar in the buffer +; ExitIns - toggle insert mode +; EnterIns - toggle insert mode +; BackSp - move backwards one space +; ReEdit - reedit the line with a new template +; KilNew - discard the current line and start from scratch +; CopyLin - copy the rest of the template into the line +; SkipStr - read the next character and skip to it in the template +; CopyStr - read next char and copy from template to line until char +; SkipOne - advance position in template one character +; CopyOne - copy next character in template into line +; CtrlZ - place a ^Z into the template +; Registers that are allowed to be modified by this function are: +; AX, CX, BP + +Procedure OEMFunctionKey,NEAR + ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP + invoke $std_con_input_no_echo ; Get the second byte of the sequence + + IF NOT Rainbow + MOV CL,ESCTABLEN ; length of table for scan + PUSH DI ; save DI (cannot change it!) + MOV DI,OFFSET DOSGROUP:ESCTAB ; offset of second byte table + REPNE SCASB ; Look it up in the table + POP DI ; restore DI + SHL CX,1 ; convert byte offset to word + MOV BP,CX ; move to indexable register + JMP [BP+OFFSET DOSGROUP:ESCFUNC] ; Go to the right routine + ENDIF + IF Rainbow + +TransferIf MACRO value,address + local a + CMP AL,value + JNZ a + transfer address +a: +ENDM + + CMP AL,'[' ; is it second lead char + JZ EatParm ; yes, go walk tree +GoGetCh: + transfer GetCh ; no, ignore sequence +EatParm: + invoke $std_con_input_no_echo ; get argument + CMP AL,'A' ; is it alphabetic arg? + JAE EatAlpha ; yes, go snarf one up + XOR BP,BP ; init digit counter + JMP InDigit ; jump into internal eat digit routine +EatNum: + invoke $std_con_input_no_echo ; get next digit +InDigit: + CMP AL,'9' ; still a digit? + JA CheckNumEnd ; no, go check for end char + SUB AL,'0' ; turn into potential digit + JL GoGetCh ; oops, not a digit, ignore + MOV CX,BP ; save BP for 10 multiply + CBW ; make AL into AX + SHL BP,1 ; 2*BP + SHL BP,1 ; 4*BP + ADD BP,CX ; 5*BP + SHL BP,1 ; 10*BP + ADD BP,AX ; 10*BP + digit + JMP EatNum ; continue with number +CheckNumEnd: + CMP AL,7Eh ; is it end char ~ + JNZ GoGetCh ; nope, ignore key sequence + MOV AX,BP + transferIf 1,SkipStr ; FIND key + transferIf 2,EnterIns ; INSERT HERE key + transferIf 3,SkipOne ; REMOVE + transferIf 4,CopyStr ; SELECT + transferIf 17,TwoEsc ; INTERRUPT + transferIf 18,ReEdit ; RESUME + transferIf 19,KilNew ; CANCEL + transferIf 21,CtrlZ ; EXIT + transferIf 29,CopyLin ; DO + JMP GoGetCh +EatAlpha: + CMP AL,'O' ; is it O? + JA GoGetCh ; no, after assume bogus + JZ EatPQRS ; eat the rest of the bogus key + transferIf 'C',CopyOne ; RIGHT + transferIf 'D',BackSp ; LEFT + JMP GoGetCh +EatPQRS: + invoke $std_con_input_no_echo ; eat char after O + JMP GoGetCh + ENDIF + +EndProc OEMFunctionKey + +CODE ENDS + + END diff --git a/SRC/DOS/DOSSEG.INC b/SRC/DOS/DOSSEG.INC new file mode 100644 index 0000000..a84d79b --- /dev/null +++ b/SRC/DOS/DOSSEG.INC @@ -0,0 +1,25 @@ +; SCCSID = @(#)dosseg.asm 1.1 85/04/10 +; SCCSID = @(#)dosseg.asm 1.1 85/04/10 +; +; segment ordering for MSDOS +; + +START SEGMENT BYTE PUBLIC 'START' +START ENDS + +CONSTANTS SEGMENT WORD PUBLIC 'CONST' +CONSTANTS ENDS + +DATA SEGMENT WORD PUBLIC 'DATA' +DATA ENDS + +TABLE SEGMENT BYTE PUBLIC 'TABLE' +TABLE ENDS + +CODE SEGMENT BYTE PUBLIC 'CODE' +CODE ENDS + +LAST SEGMENT PARA PUBLIC 'LAST' +LAST ENDS + +DOSGROUP GROUP START,CONSTANTS,DATA,TABLE,CODE,LAST diff --git a/SRC/DOS/DOSSYM.INC b/SRC/DOS/DOSSYM.INC new file mode 100644 index 0000000..26a9485 --- /dev/null +++ b/SRC/DOS/DOSSYM.INC @@ -0,0 +1,155 @@ +; SCCSID = @(#)dossym.asm 1.1 85/04/10 +; SCCSID = @(#)dossym.asm 1.1 85/04/10 + PAGE 80,132 +TRUE EQU 0FFFFh +FALSE EQU 0 + +Installed = TRUE +IFNDEF DEBUG + DEBUG = FALSE +ENDIF + +include dosmac.INC + +include VERSIONA.INC + +;;IF2 +;; %OUT DOSSYM in Pass 2 +;;ENDIF + +BREAK + +c_DEL EQU 7Fh ; ASCII rubout or delete previous char +c_BS EQU 08h ; ^H ASCII backspace +c_CR EQU 0Dh ; ^M ASCII carriage return +c_LF EQU 0Ah ; ^J ASCII linefeed +c_ETB EQU 17h ; ^W ASCII end of transmission +c_NAK EQU 15h ; ^U ASCII negative acknowledge +c_ETX EQU 03h ; ^C ASCII end of text +c_HT EQU 09h ; ^I ASCII tab + +BREAK + +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; ; +; C A V E A T P R O G R A M M E R ; +; ; +; Certain structures, constants and system calls below are private to ; +; the DOS and are extremely version-dependent. They may change at any ; +; time at the implementors' whim. As a result, they must not be ; +; documented to the general public. If an extreme case arises, they ; +; must be documented with this warning. ; +; ; +; Those structures and constants that are subject to the above will be ; +; marked and bracketed with the flag: ; +; ; +; C A V E A T P R O G R A M M E R ; +; ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +include bpb.INC + +include buffer.INC + +BREAK +; Location of user registers relative user stack pointer + +user_environ STRUC +user_AX DW ? +user_BX DW ? +user_CX DW ? +user_DX DW ? +user_SI DW ? +user_DI DW ? +user_BP DW ? +user_DS DW ? +user_ES DW ? +user_IP DW ? +user_CS DW ? +user_F DW ? +user_environ ENDS + +include sysvar.INC + +include vector.INC + +include mult.INC + +BREAK +; MSDOS partitions the disk into 4 sections: +; +; phys sector 0: +-------------------+ +; | | boot/reserved | +; | +-------------------+ +; | | File allocation | +; v | table(s) | +; | (multiple copies | +; | are kept) | +; +-------------------+ +; | Directory | +; +-------------------+ +; | File space | +; +-------------------+ +; | Unaddressable | +; | (to end of disk) | +; +-------------------+ +; +; All partition boundaries are sector boundaries. The size of the FAT is +; adjusted to maximize the file space addressable. + +include dirent.INC + +BREAK +; +; The File Allocation Table uses a 12-bit entry for each allocation unit on +; the disk. These entries are packed, two for every three bytes. The contents +; of entry number N is found by 1) multiplying N by 1.5; 2) adding the result +; to the base address of the Allocation Table; 3) fetching the 16-bit word +; at this address; 4) If N was odd (so that N*1.5 was not an integer), shift +; the word right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry +; number zero is used as an end-of-file trap in the OS and is passed to the +; BIOS to help determine disk format. Entry 1 is reserved for future use. +; The first available allocation unit is assigned entry number two, and even +; though it is the first, is called cluster 2. Entries greater than 0FF8H +; (12-bit fats) or 0FFF8H (16-bit fats) are end of file marks; entries of zero +; are unallocated. Otherwise, the contents of a FAT entry is the number of +; the next cluster in the file. +; +; Clusters with bad sectors are tagged with FF7H. Any non-zero number would +; do because these clusters show as allocated, but are not part of any +; allocation chain and thus will never be allocated to a file. A particular +; number is selected so that disk checking programs know what to do (ie. a +; cluster with entry FF7H which is not in a chain is not an error). + +include dpb.INC + +include curdir.INC + +include cpmfcb.INC + +include find.INC + +include pdb.INC + +include exe.INC + +include sf.INC + +include arena.INC + +include intnat.INC + +include mi.INC + +fChk equ 1 +fDelim equ 2 +fSpChk equ 4 +fFCB equ 8 + +include filemode.INC + +include error.INC + +include syscall.INC + +SUBTTL diff --git a/SRC/DOS/DPB.INC b/SRC/DOS/DPB.INC new file mode 100644 index 0000000..92fb7fe --- /dev/null +++ b/SRC/DOS/DPB.INC @@ -0,0 +1,34 @@ +; SCCSID = @(#)dpb.asm 1.1 85/04/10 +; SCCSID = @(#)dpb.asm 1.1 85/04/10 +BREAK +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +dpb STRUC +dpb_drive DB ? ; Logical drive # assoc with DPB (A=0,B=1,...) +dpb_UNIT DB ? ; Driver unit number of DPB +dpb_sector_size DW ? ; Size of physical sector in bytes +dpb_cluster_mask DB ? ; Sectors/cluster - 1 +dpb_cluster_shift DB ? ; Log2 of sectors/cluster +dpb_first_FAT DW ? ; Starting record of FATs +dpb_FAT_count DB ? ; Number of FATs for this drive +dpb_root_entries DW ? ; Number of directory entries +dpb_first_sector DW ? ; First sector of first cluster +dpb_max_cluster DW ? ; Number of clusters on drive + 1 +dpb_FAT_size DB ? ; Number of records occupied by FAT +dpb_dir_sector DW ? ; Starting record of directory +dpb_driver_addr DD ? ; Pointer to driver +dpb_media DB ? ; Media byte +dpb_first_access DB ? ; This is initialized to -1 to force a media + ; check the first time this DPB is used +dpb_next_dpb DD ? ; Pointer to next Drive parameter block +dpb_next_free DW ? ; Cluster # of last allocated cluster +dpb_free_cnt DW ? ; Count of free clusters, -1 if unknown +dpb ENDS + +DPBSIZ EQU SIZE dpb ; Size of the structure in bytes + +DSKSIZ = dpb_max_cluster ; Size of disk (temp used during init only) +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; diff --git a/SRC/DOS/DPL.INC b/SRC/DOS/DPL.INC new file mode 100644 index 0000000..c51676b --- /dev/null +++ b/SRC/DOS/DPL.INC @@ -0,0 +1,15 @@ +; SCCSID = @(#)dpl.inc 1.1 85/04/10 +; SCCSID = @(#)dpl.inc 1.1 85/04/10 +DPL STRUC +DPL_AX DW ? ; AX register +DPL_BX DW ? ; BX register +DPL_CX DW ? ; CX register +DPL_DX DW ? ; DX register +DPL_SI DW ? ; SI register +DPL_DI DW ? ; DI register +DPL_DS DW ? ; DS register +DPL_ES DW ? ; ES register +DPL_reserved DW ? ; Reserved +DPL_UID DW ? ; User (Machine) ID (0 = local macine) +DPL_PID DW ? ; Process ID (0 = local user PID) +DPL ENDS diff --git a/SRC/DOS/DUP.OBJ b/SRC/DOS/DUP.OBJ new file mode 100644 index 0000000..ae9ea4a Binary files /dev/null and b/SRC/DOS/DUP.OBJ differ diff --git a/SRC/DOS/ERROR.INC b/SRC/DOS/ERROR.INC new file mode 100644 index 0000000..e43017a --- /dev/null +++ b/SRC/DOS/ERROR.INC @@ -0,0 +1,151 @@ +; SCCSID = @(#)error.asm 1.1 85/04/10 +; SCCSID = @(#)error.asm 1.1 85/04/10 +BREAK + +; +; XENIX calls all return error codes through AX. If an error occurred then +; the carry bit will be set and the error code is in AX. If no error occurred +; then the carry bit is reset and AX contains returned info. +; +; Since the set of error codes is being extended as we extend the operating +; system, we have provided a means for applications to ask the system for a +; recommended course of action when they receive an error. +; +; The GetExtendedError system call returns a universal error, an error +; location and a recommended course of action. The universal error code is +; a symptom of the error REGARDLESS of the context in which GetExtendedError +; is issued. +; + +; +; These are the 2.0 error codes +; +error_invalid_function EQU 1 +error_file_not_found EQU 2 +error_path_not_found EQU 3 +error_too_many_open_files EQU 4 +error_access_denied EQU 5 +error_invalid_handle EQU 6 +error_arena_trashed EQU 7 +error_not_enough_memory EQU 8 +error_invalid_block EQU 9 +error_bad_environment EQU 10 +error_bad_format EQU 11 +error_invalid_access EQU 12 +error_invalid_data EQU 13 +;**** reserved EQU 14 ; ***** +error_invalid_drive EQU 15 +error_current_directory EQU 16 +error_not_same_device EQU 17 +error_no_more_files EQU 18 +; +; These are the universal int 24 mappings for the old INT 24 set of errors +; +error_write_protect EQU 19 +error_bad_unit EQU 20 +error_not_ready EQU 21 +error_bad_command EQU 22 +error_CRC EQU 23 +error_bad_length EQU 24 +error_Seek EQU 25 +error_not_DOS_disk EQU 26 +error_sector_not_found EQU 27 +error_out_of_paper EQU 28 +error_write_fault EQU 29 +error_read_fault EQU 30 +error_gen_failure EQU 31 +; +; These are the new 3.0 error codes reported through INT 24 +; +error_sharing_violation EQU 32 +error_lock_violation EQU 33 +error_wrong_disk EQU 34 +error_FCB_unavailable EQU 35 +error_sharing_buffer_exceeded EQU 36 +; +; New OEM network-related errors are 50-79 +; +error_not_supported EQU 50 +; +; End of INT 24 reportable errors +; +error_file_exists EQU 80 +error_DUP_FCB EQU 81 ; ***** +error_cannot_make EQU 82 +error_FAIL_I24 EQU 83 +; +; New 3.0 network related error codes +; +error_out_of_structures EQU 84 +error_Already_assigned EQU 85 +error_invalid_password EQU 86 +error_invalid_parameter EQU 87 +error_NET_write_fault EQU 88 + +BREAK + +error_I24_write_protect EQU 0 +error_I24_bad_unit EQU 1 +error_I24_not_ready EQU 2 +error_I24_bad_command EQU 3 +error_I24_CRC EQU 4 +error_I24_bad_length EQU 5 +error_I24_Seek EQU 6 +error_I24_not_DOS_disk EQU 7 +error_I24_sector_not_found EQU 8 +error_I24_out_of_paper EQU 9 +error_I24_write_fault EQU 0Ah +error_I24_read_fault EQU 0Bh +error_I24_gen_failure EQU 0Ch +; NOTE: Code 0DH is used by MT-DOS. +error_I24_wrong_disk EQU 0Fh + +; THE FOLLOWING ARE MASKS FOR THE AH REGISTER ON Int 24 + +Allowed_FAIL EQU 00001000B +Allowed_RETRY EQU 00010000B +Allowed_IGNORE EQU 00100000B +;NOTE: ABORT is ALWAYS allowed + +I24_operation EQU 00000001B ;Z if READ,NZ if Write +I24_area EQU 00000110B ; 00 if DOS + ; 01 if FAT + ; 10 if root DIR + ; 11 if DATA +I24_class EQU 10000000B ;Z if DISK, NZ if FAT or char + +BREAK + +; Values for error CLASS + +errCLASS_OutRes EQU 1 ; Out of Resource +errCLASS_TempSit EQU 2 ; Temporary Situation +errCLASS_Auth EQU 3 ; Permission problem +errCLASS_Intrn EQU 4 ; Internal System Error +errCLASS_HrdFail EQU 5 ; Hardware Failure +errCLASS_SysFail EQU 6 ; System Failure +errCLASS_Apperr EQU 7 ; Application Error +errCLASS_NotFnd EQU 8 ; Not Found +errCLASS_BadFmt EQU 9 ; Bad Format +errCLASS_Locked EQU 10 ; Locked +errCLASS_Media EQU 11 ; Media Failure +errCLASS_Already EQU 12 ; Collision with Existing Item +errCLASS_Unk EQU 13 ; Unknown/other + +; Values for error ACTION + +errACT_Retry EQU 1 ; Retry +errACT_DlyRet EQU 2 ; Delay Retry, retry after pause +errACT_User EQU 3 ; Ask user to regive info +errACT_Abort EQU 4 ; abort with clean up +errACT_Panic EQU 5 ; abort immediately +errACT_Ignore EQU 6 ; ignore +errACT_IntRet EQU 7 ; Retry after User Intervention + +; Values for error LOCUS + +errLOC_Unk EQU 1 ; No appropriate value +errLOC_Disk EQU 2 ; Random Access Mass Storage +errLOC_Net EQU 3 ; Network +errLOC_SerDev EQU 4 ; Serial Device +errLOC_Mem EQU 5 ; Memory diff --git a/SRC/DOS/EXE.INC b/SRC/DOS/EXE.INC new file mode 100644 index 0000000..e768f6b --- /dev/null +++ b/SRC/DOS/EXE.INC @@ -0,0 +1,78 @@ +; SCCSID = @(#)exe.asm 1.1 85/04/10 +; SCCSID = @(#)exe.asm 1.1 85/04/10 +BREAK +; +; EXEC arg block - load/go program +; + +; +; The following get used as arguments to the EXEC system call. They indicate +; whether or not the program is executed or whether or not a program header +; gets created. +; +exec_func_no_execute EQU 1 ; no execute bit +exec_func_overlay EQU 2 ; overlay bit + +Exec0 STRUC +Exec0_environ DW ? ; seg addr of environment +Exec0_com_line DD ? ; pointer to asciz command line +Exec0_5C_FCB DD ? ; default fcb at 5C +Exec0_6C_FCB DD ? ; default fcb at 6C +Exec0 ENDS + +Exec1 STRUC +Exec1_environ DW ? ; seg addr of environment +Exec1_com_line DD ? ; pointer to asciz command line +Exec1_5C_FCB DD ? ; default fcb at 5C +Exec1_6C_FCB DD ? ; default fcb at 6C +Exec1_SP DW ? ; stack pointer of program +Exec1_SS DW ? ; stack seg register of program +Exec1_IP DW ? ; entry point IP +Exec1_CS DW ? ; entry point CS +Exec1 ENDS + +Exec3 STRUC +Exec3_load_addr DW ? ; seg address of load point +Exec3_reloc_fac DW ? ; relocation factor +Exec3 ENDS + +; +; Exit codes in upper byte +; +Exit_terminate EQU 0 +Exit_abort EQU 0 +Exit_Ctrl_C EQU 1 +Exit_Hard_Error EQU 2 +Exit_Keep_process EQU 3 + +; +; EXE file header +; + +EXE_file STRUC +exe_signature DW ? ; must contain 4D5A (yay zibo!) +exe_len_mod_512 DW ? ; low 9 bits of length +exe_pages DW ? ; number of 512b pages in file +exe_rle_count DW ? ; count of reloc entries +exe_par_dir DW ? ; number of paragraphs before image +exe_min_BSS DW ? ; minimum number of para of BSS +exe_max_BSS DW ? ; max number of para of BSS +exe_SS DW ? ; stack of image +exe_SP DW ? ; SP of image +exe_chksum DW ? ; checksum of file (ignored) +exe_IP DW ? ; IP of entry +exe_CS DW ? ; CS of entry +exe_rle_table DW ? ; byte offset of reloc table +exe_iov DW ? ; overlay number (0 for root) +exe_sym_tab DD ? ; offset of symbol table in file +EXE_file ENDS + +exe_valid_signature EQU 5A4Dh +exe_valid_old_signature EQU 4D5Ah + +symbol_entry STRUC +sym_value DD ? +sym_type DW ? +sym_len DB ? +sym_name DB 255 dup (?) +symbol_entry ENDS diff --git a/SRC/DOS/FAT.OBJ b/SRC/DOS/FAT.OBJ new file mode 100644 index 0000000..5ea1b29 Binary files /dev/null and b/SRC/DOS/FAT.OBJ differ diff --git a/SRC/DOS/FCB.OBJ b/SRC/DOS/FCB.OBJ new file mode 100644 index 0000000..c3000e7 Binary files /dev/null and b/SRC/DOS/FCB.OBJ differ diff --git a/SRC/DOS/FCBIO.OBJ b/SRC/DOS/FCBIO.OBJ new file mode 100644 index 0000000..2c4e783 Binary files /dev/null and b/SRC/DOS/FCBIO.OBJ differ diff --git a/SRC/DOS/FCBIO2.OBJ b/SRC/DOS/FCBIO2.OBJ new file mode 100644 index 0000000..4712d7b Binary files /dev/null and b/SRC/DOS/FCBIO2.OBJ differ diff --git a/SRC/DOS/FILE.OBJ b/SRC/DOS/FILE.OBJ new file mode 100644 index 0000000..ae7d4d7 Binary files /dev/null and b/SRC/DOS/FILE.OBJ differ diff --git a/SRC/DOS/FILEMODE.INC b/SRC/DOS/FILEMODE.INC new file mode 100644 index 0000000..b263ef6 --- /dev/null +++ b/SRC/DOS/FILEMODE.INC @@ -0,0 +1,25 @@ +; SCCSID = @(#)filemode.asm 1.1 85/04/10 +; SCCSID = @(#)filemode.asm 1.1 85/04/10 +BREAK + +stdin EQU 0 +stdout EQU 1 +stderr EQU 2 +stdaux EQU 3 +stdprn EQU 4 + +BREAK + +access_mask EQU 0FH +open_for_read EQU 00h +open_for_write EQU 01h +open_for_both EQU 02h + +sharing_mask EQU 0F0H +sharing_compat EQU 000H +sharing_deny_both EQU 010H +sharing_deny_write EQU 020H +sharing_deny_read EQU 030H +sharing_deny_none EQU 040H +sharing_net_FCB EQU 070h +sharing_no_inherit EQU 080H diff --git a/SRC/DOS/FIND.INC b/SRC/DOS/FIND.INC new file mode 100644 index 0000000..4c8610e --- /dev/null +++ b/SRC/DOS/FIND.INC @@ -0,0 +1,25 @@ +; SCCSID = @(#)find.asm 1.1 85/04/10 +; SCCSID = @(#)find.asm 1.1 85/04/10 +Break + +find_buf STRUC +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +find_buf_drive DB ? ; drive of search +find_buf_name DB 11 DUP (?) ; formatted name +find_buf_sattr DB ? ; attribute of search +find_buf_LastEnt DW ? ; LastEnt +find_buf_DirStart DW ? ; DirStart +find_buf_NetID DB 4 DUP (?) ; Reserved for NET +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +find_buf_attr DB ? ; attribute found +find_buf_time DW ? ; time +find_buf_date DW ? ; date +find_buf_size_l DW ? ; low(size) +find_buf_size_h DW ? ; high(size) +find_buf_pname DB 13 DUP (?) ; packed name +find_buf ENDS diff --git a/SRC/DOS/FINFO.OBJ b/SRC/DOS/FINFO.OBJ new file mode 100644 index 0000000..ac03fb1 Binary files /dev/null and b/SRC/DOS/FINFO.OBJ differ diff --git a/SRC/DOS/GETSET.OBJ b/SRC/DOS/GETSET.OBJ new file mode 100644 index 0000000..ef08831 Binary files /dev/null and b/SRC/DOS/GETSET.OBJ differ diff --git a/SRC/DOS/HANDLE.OBJ b/SRC/DOS/HANDLE.OBJ new file mode 100644 index 0000000..4ca2a49 Binary files /dev/null and b/SRC/DOS/HANDLE.OBJ differ diff --git a/SRC/DOS/INTNAT.INC b/SRC/DOS/INTNAT.INC new file mode 100644 index 0000000..125484d --- /dev/null +++ b/SRC/DOS/INTNAT.INC @@ -0,0 +1,39 @@ +; SCCSID = @(#)intnat.asm 1.1 85/04/10 +BREAK + +; +; Current structure of the data returned by the international call +; +internat_block STRUC +Date_tim_format DW ? ; 0-USA, 1-EUR, 2-JAP +Currency_sym DB ? ; Currency Symbol 5 bytes + DB ? + DB ? + DB ? + DB ? +Thous_sep DB ? ; Thousands separator 2 bytes + DB ? +Decimal_sep DB ? ; Decimal separator 2 bytes + DB ? +Date_sep DB ? ; Date separator 2 bytes + DB ? +Time_sep DB ? ; Decimal separator 2 bytes + DB ? +Bit_field DB ? ; Bit values + ; Bit 0 = 0 if currency symbol first + ; = 1 if currency symbol last + ; Bit 1 = 0 if No space after currency symbol + ; = 1 if space after currency symbol +Currency_cents DB ? ; Number of places after currency dec point +Time_24 DB ? ; 1 if 24 hour time, 0 if 12 hour time +Map_call DW ? ; Address of case mapping call (DWORD) + DW ? ; THIS IS TWO WORDS SO IT CAN BE INITIALIZED + ; in pieces. +Data_sep DB ? ; Data list separator character + DB ? +internat_block ENDS + +; +; Max size of the block returned by the INTERNATIONAL call +; +internat_block_max EQU 32 diff --git a/SRC/DOS/IOCTL.INC b/SRC/DOS/IOCTL.INC new file mode 100644 index 0000000..902cd7d --- /dev/null +++ b/SRC/DOS/IOCTL.INC @@ -0,0 +1,169 @@ +;; +;;%OUT IOCTL.INC... +;; THESE ARE ALL THE IMPORTANT STRUCTURES AND EQUATES FOR IOCTL + +;General Guide - +;Category Code: +; 0... .... DOS Defined +; 1... .... User defined +; .xxx xxxx Code + +;Function Code: +; 0... .... Return error if unsupported +; 1... .... Ignore if unsupported +; .0.. .... Intercepted by DOS +; .1.. .... Passed to driver +; ..0. .... Sends data/commands to device +; ..1. .... Quries data/info from device +; ...x .... Subfunction +; +; Note that "Sends/queries" data bit is intended only to regularize the +; function set. It plays no critical role; some functions may contain both +; command and query elements. The convention is that such commands are +; defined as "sends data". + +;*****************************;* +; BLOCK DRIVERS ;* +;*****************************;* + +; IOCTL SUB-FUNCTIONS +IOCTL_GET_DEVICE_INFO EQU 0 +IOCTL_SET_DEVICE_INFO EQU 1 +IOCTL_READ_HANDLE EQU 2 +IOCTL_WRITE_HANDLE EQU 3 +IOCTL_READ_DRIVE EQU 4 +IOCTL_WRITE_DRIVE EQU 5 +IOCTL_GET_INPUT_STATUS EQU 6 +IOCTL_GET_OUTPUT_STATUS EQU 7 +IOCTL_CHANGEABLE? EQU 8 +IOCTL_SHARING_RETRY EQU 11 +GENERIC_IOCTL_HANDLE EQU 12 +GENERIC_IOCTL EQU 13 + +; GENERIC IOCTL CATEGORY CODES +IOC_OTHER EQU 0 ; Other device control 4/29/86 +IOC_SE EQU 1 ; SERIAL DEVICE CONTROL +IOC_TC EQU 2 ; TERMINAL CONTROL +IOC_SC EQU 3 ; SCREEN CONTROL +IOC_KC EQU 4 ; KEYBOARD CONTROL +IOC_PC EQU 5 ; PRINTER CONTROL +IOC_DC EQU 8 ; DISK CONTROL (SAME AS RAWIO) + +; GENERIC IOCTL SUB-FUNCTIONS +RAWIO EQU 8 + +; RAWIO SUB-FUNCTIONS +GET_DEVICE_PARAMETERS EQU 60H +SET_DEVICE_PARAMETERS EQU 40H +READ_TRACK EQU 61H +WRITE_TRACK EQU 41H +VERIFY_TRACK EQU 62H +FORMAT_TRACK EQU 42H + +; SPECIAL FUNCTION FOR GET DEVICE PARAMETERS +BUILD_DEVICE_BPB EQU 000000001B + +; SPECIAL FUNCTIONS FOR SET DEVICE PARAMETERS +INSTALL_FAKE_BPB EQU 000000001B +ONLY_SET_TRACKLAYOUT EQU 000000010B +TRACKLAYOUT_IS_GOOD EQU 000000100B + +; SPECIAL FUNCTION FOR FORMAT TRACK +STATUS_FOR_FORMAT EQU 000000001B +; CODES RETURNED FROM FORMAT STATUS CALL +FORMAT_NO_ROM_SUPPORT EQU 000000001B +FORMAT_COMB_NOT_SUPPORTED EQU 000000010B + +; DEVICETYPE VALUES +MAX_SECTORS_IN_TRACK EQU 63 ; MAXIMUM SECTORS ON A DISK.(Was 40 in DOS 3.2) +DEV_5INCH EQU 0 +DEV_5INCH96TPI EQU 1 +DEV_3INCH720KB EQU 2 +DEV_8INCHSS EQU 3 +DEV_8INCHDS EQU 4 +DEV_HARDDISK EQU 5 +DEV_OTHER EQU 7 + +MAX_DEV_TYPE EQU 7 ; MAXIMUM DEVICE TYPE THAT WE + ; CURRENTLY SUPPORT. +IFNDEF A_BPB + INCLUDE BPB.INC +ENDIF + +A_SECTORTABLE STRUC +ST_SECTORNUMBER DW ? +ST_SECTORSIZE DW ? +A_SECTORTABLE ENDS + +A_DEVICEPARAMETERS STRUC +DP_SPECIALFUNCTIONS DB ? +DP_DEVICETYPE DB ? +DP_DEVICEATTRIBUTES DW ? +DP_CYLINDERS DW ? +DP_MEDIATYPE DB ? +DP_BPB DB SIZE A_BPB DUP(?) +DP_TRACKTABLEENTRIES DW ? +DP_SECTORTABLE DB MAX_SECTORS_IN_TRACK * SIZE A_SECTORTABLE DUP(?) +A_DEVICEPARAMETERS ENDS + +A_TRACKREADWRITEPACKET STRUC +TRWP_SPECIALFUNCTIONS DB ? +TRWP_HEAD DW ? +TRWP_CYLINDER DW ? +TRWP_FIRSTSECTOR DW ? +TRWP_SECTORSTOREADWRITE DW ? +TRWP_TRANSFERADDRESS DD ? +A_TRACKREADWRITEPACKET ENDS + +A_FORMATPACKET STRUC +FP_SPECIALFUNCTIONS DB ? +FP_HEAD DW ? +FP_CYLINDER DW ? +A_FORMATPACKET ENDS + +A_VERIFYPACKET STRUC +VP_SPECIALFUNCTIONS DB ? +VP_HEAD DW ? +VP_CYLINDER DW ? +A_VERIFYPACKET ENDS + + +;********************************;* +; CHARACTER DEVICES (PRINTERS) ;* +;********************************;* + +;RAWIO SUB-FUNCTIONS +GET_RETRY_COUNT EQU 65H +SET_RETRY_COUNT EQU 45H + +A_RETRYCOUNT STRUC +RC_COUNT DW ? +A_RETRYCOUNT ENDS + +;********************************;* ; 4/29/86 +; CHARACTER DEVICES (SCREEN) ;* +;********************************;* ; 4/29/86 +; +;SC_MODE_INFO struc +;SC_INFO_LENGTH DW 9 +;SC_MODE DB 0 +;SC_COLORS DW 0 +;SC_WIDTH DW 0 +;SC_LENGTH DW 0 +;SC_MODE_INFO ends +; +;SC_INFO_PACKET_LENGTH EQU 9 ;LENGTH OF THE INFO PACKET. + +;SUBFUNCTIONS FOR CON$GENIOCTL +;GET_SC_MODE EQU 60h +;SET_SC_MODE EQU 40h +;The following subfunctions are reserved for installable CODE PAGE switch +;console devices. - 4/29/86 +;Get_active_codepage equ 6Ah +;Invoke_active_codepage equ 4Ah +;Start_designate_codepage equ 4Ch +;End_designate_codepage equ 4Dh +;Get_list_of_designated_codepage equ 6Bh +; 4/29/86 *** End of Con$genioctl equates & structures + + diff --git a/SRC/DOS/IOCTL.OBJ b/SRC/DOS/IOCTL.OBJ new file mode 100644 index 0000000..afeef94 Binary files /dev/null and b/SRC/DOS/IOCTL.OBJ differ diff --git a/SRC/DOS/ISEARCH.OBJ b/SRC/DOS/ISEARCH.OBJ new file mode 100644 index 0000000..2a27069 Binary files /dev/null and b/SRC/DOS/ISEARCH.OBJ differ diff --git a/SRC/DOS/LOCK.OBJ b/SRC/DOS/LOCK.OBJ new file mode 100644 index 0000000..76c71a6 Binary files /dev/null and b/SRC/DOS/LOCK.OBJ differ diff --git a/SRC/DOS/MACRO.OBJ b/SRC/DOS/MACRO.OBJ new file mode 100644 index 0000000..268e9a9 Binary files /dev/null and b/SRC/DOS/MACRO.OBJ differ diff --git a/SRC/DOS/MACRO2.OBJ b/SRC/DOS/MACRO2.OBJ new file mode 100644 index 0000000..747644a Binary files /dev/null and b/SRC/DOS/MACRO2.OBJ differ diff --git a/SRC/DOS/MAKEFILE b/SRC/DOS/MAKEFILE new file mode 100644 index 0000000..c3699f0 --- /dev/null +++ b/SRC/DOS/MAKEFILE @@ -0,0 +1,49 @@ +#** Makefile for MSDos.sys + +DEST = msdos +MSG = messages + +# Path definitions + +BIOS =..\bios +BOOT =..\boot +DINC =..\inc + +# Definitions for assembler + +ASM = masm +AFLAGS = -Mx -t +AINC = -I..\inc + +# Definitions for C compiler + +CC = cl +CFLAGS = -c -Ox -Zlp +CINC = -I..\h + +# Definitions for linker + +LINK = link +LIBC = ..\libc + + +# Rules and Dependencies follow + +stddosmes.obj: stddosmes.asm stdsw.inc dosseg.inc \ + dosmes.inc DOSMAC.INC INTNAT.INC \ + divmes.inc divmes.inc + masm $(AFLAGS) $(AINC) stddosmes; + +msdos.exe: nibdos.obj const2.obj stddata.obj stdtable.obj stddisp.obj \ + stdcode.obj stddosmes.obj time.obj getset.obj \ + parse.obj misc.obj misc2.obj crit.obj cpmio.obj cpmio2.obj \ + fcbio.obj fcbio2.obj \ + search.obj path.obj ioctl.obj delete.obj rename.obj finfo.obj \ + dup.obj create.obj open.obj dinfo.obj isearch.obj \ + abort.obj close.obj dircall.obj disk.obj disk2.obj disk3.obj dir.obj \ + dir2.obj dev.obj mknode.obj rom.obj fcb.obj stdctrlc.obj fat.obj buf.obj \ + proc.obj alloc.obj srvcall.obj util.obj macro.obj macro2.obj \ + handle.obj file.obj lock.obj share.obj + LINK @msdos.lnk + EXE2BIN MSDOS.EXE MSDOS.SYS + DEL MSDOS.EXE diff --git a/SRC/DOS/MI.INC b/SRC/DOS/MI.INC new file mode 100644 index 0000000..89e26bb --- /dev/null +++ b/SRC/DOS/MI.INC @@ -0,0 +1,19 @@ +; SCCSID = @(#)mi.asm 1.1 85/04/10 +BREAK + +mi_INT EQU 0CDh +mi_Long_JMP EQU 0EAh +mi_Long_CALL EQU 09Ah +mi_Long_RET EQU 0CBh +mi_Near_RET EQU 0C3h + +; xxxxoditszxaxpxc +f_Overflow EQU 0000100000000000B +f_Direction EQU 0000010000000000B +f_Interrupt EQU 0000001000000000B +f_Trace EQU 0000000100000000B +f_Sign EQU 0000000010000000B +f_Zero EQU 0000000001000000B +f_Aux EQU 0000000000010000B +f_Parity EQU 0000000000000100B +f_Carry EQU 0000000000000001B diff --git a/SRC/DOS/MISC.OBJ b/SRC/DOS/MISC.OBJ new file mode 100644 index 0000000..e438f64 Binary files /dev/null and b/SRC/DOS/MISC.OBJ differ diff --git a/SRC/DOS/MISC2.OBJ b/SRC/DOS/MISC2.OBJ new file mode 100644 index 0000000..c0c1c30 Binary files /dev/null and b/SRC/DOS/MISC2.OBJ differ diff --git a/SRC/DOS/MKNODE.OBJ b/SRC/DOS/MKNODE.OBJ new file mode 100644 index 0000000..7b2d7b2 Binary files /dev/null and b/SRC/DOS/MKNODE.OBJ differ diff --git a/SRC/DOS/MSDOS.LNK b/SRC/DOS/MSDOS.LNK new file mode 100644 index 0000000..fe062ff --- /dev/null +++ b/SRC/DOS/MSDOS.LNK @@ -0,0 +1,13 @@ +nibdos.obj const2.obj stddata.obj stdtable.obj + +stddisp.obj stdcode.obj stddosmes.obj time.obj + +getset.obj parse.obj misc.obj misc2.obj crit.obj + +cpmio.obj cpmio2.obj fcbio.obj fcbio2.obj + +search.obj path.obj ioctl.obj delete.obj rename.obj + +finfo.obj dup.obj create.obj open.obj dinfo.obj+ +isearch.obj abort.obj close.obj dircall.obj+ +disk.obj disk2.obj disk3.obj dir.obj dir2.obj + +dev.obj mknode.obj rom.obj fcb.obj stdctrlc.obj + +fat.obj buf.obj proc.obj alloc.obj srvcall.obj + +util.obj macro.obj macro2.obj handle.obj file.obj + +lock.obj share.obj +MSDOS.exe /m; diff --git a/SRC/DOS/MULT.INC b/SRC/DOS/MULT.INC new file mode 100644 index 0000000..9dfe1f3 --- /dev/null +++ b/SRC/DOS/MULT.INC @@ -0,0 +1,158 @@ +; SCCSID = @(#)mult.asm 1.2 85/04/12 +Break + +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +; Critical section definitions +; +; These below are subject to leave-all sections +critDisk EQU 1 ; Disk I/O critical section +critDevice EQU 2 ; Device I/O critical section +critShare EQU 1 ; Sharer I/O critical section +critMem EQU 1 ; memory maintenance critical section +critNet EQU 5 ; network critical section +critSFT EQU 1 ; sft table allocation +; These below are not subject to leave-all sections +critASSIGN EQU 8 ; Assign has munged a system call +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +; +; The current set of defined multiplex channels is (* means documented): +; +; Channel(h) Issuer Receiver Function +; 00 server PSPRINT print job control +; *01 print/apps PRINT Queueing of files +; 02 BIOS REDIR signal open/close of printers +; +; 05 command REDIR obtain text of net int 24 message +; *06 server/assign ASSIGN Install check +; +; 08 external driver IBMBIO interface to internal routines +; +; 10 sharer/server Sharer install check +; 11 DOS/server Redir install check/redirection funcs +; 12 sharer/redir DOS dos functions and structure maint +; 13 MSNET MSNET movement of NCBs +; 14 DOS NLSFUNC down load NLS country info,DOS 3.3 +; 14 Apps Popup DOS 4.XX popup screen functions +; ***> NOTE <*** Yes there are 2 users of 14h but since DOS 4.XX +; doesn't use NLSFUNC, there is no conflict +; 15 Apps MSCDEX CD-ROM redirector interface +; 16 Winoldap (?) WIN386 Private Windows communication +; 17 Winoldap (?) WIN386 Win386 clipboard interface +; 18 Apps MS-Manager Toggle interface to manager +; 19,(13h) external driver IBMBIO Reset_Int_13, allows installation +; of alternative INT_13 drivers after +; boot_up +; B0 GRAFTABL GRAFTABL +; + +MultSHARE EQU 10h ; sharer + ; 1 MFT_enter + ; 2 MFTClose + ; 3 MFTclU + ; 4 MFTCloseP + ; 5 MFTCloN + ; 6 set_block + ; 7 clr_block + ; 8 chk_block + ; 9 MFT_get + ; 10 ShSave + ; 11 ShChk + ; 12 ShCol + ; 13 ShCloseFile + +MultNET EQU 11h ; Network support + ; 1 NET_RMDIR + ; 2 NET_SEQ_RMDIR + ; 3 NET_MKDIR + ; 4 NET_SEQ_MKDIR + ; 5 NET_CHDIR + ; 6 NET_CLOSE + ; 7 NET_COMMIT + ; 8 NET_READ + ; 9 NET_WRITE + ; 10 NET_LOCK + ; 11 NET_UNLOCK + ; 12 NET_DISK_INFO + ; 13 NET_SET_FILE_ATTRIBUTE + ; 14 NET_SEQ_SET_FILE_ATTRIBUTE + ; 15 NET_GET_FILE_INFO + ; 16 NET_SEQ_GET_FILE_INFO + ; 17 NET_RENAME + ; 18 NET_SEQ_RENAME + ; 19 NET_DELETE + ; 20 NET_SEQ_DELETE + ; 21 NET_OPEN + ; 22 NET_SEQ_OPEN + ; 23 NET_CREATE + ; 24 NET_SEQ_CREATE + ; 25 NET_SEQ_SEARCH_FIRST + ; 26 NET_SEQ_SEARCH_NEXT + ; 27 NET_SEARCH_FIRST + ; 28 NET_SEARCH_NEXT + ; 29 NET_ABORT + ; 30 NET_ASSOPER + ; 31 Printer_SET_STRING + ; 32 NetFlushBuf + ; 33 NetBufWrite + ; 34 NetResetEnvironment + ; 35 NetSpoolCheck + ; 36 NetSpoolClose + +MultDOS EQU 12h ; DOS call back + ; 1 DOS_CLOSE + ; 2 RECSET + ; 3 Get DOSGROUP + ; 4 PATHCHRCMP + ; 5 OUT + ; 6 NET_I24_ENTRY + ; 7 PLACEBUF + ; 8 FREE_SFT + ; 9 BUFWRITE + ; 10 SHARE_VIOLATION + ; 11 SHARE_ERROR + ; 12 SET_SFT_MODE + ; 13 DATE16 + ; 14 SETVISIT + ; 15 SCANPLACE + ; 16 SKIPVISIT + ; 17 StrCpy + ; 18 StrLen + ; 19 Ucase + ; 20 POINTCOMP + ; 21 CHECKFLUSH + ; 22 SFFromSFN + ; 23 GetCDSFromDrv + ; 24 Get_User_Stack + ; 25 GetThisDrv + ; 26 DriveFromText + ; 27 SETYEAR + ; 28 DSUM + ; 29 DSLIDE + ; 30 StrCmp + ; 31 initcds + ; 32 pjfnfromhandle + ; 33 $NameTrans + ; 34 CAL_LK + ; 35 DEVNAME + ; 36 Idle + ; +NLSFUNC EQU 14h ; NLSFUNC CALL , DOS 3.3 + ; 0 NLSInstall + ; 1 ChgCodePage + ; 2 GetExtInfo + ; 3 SetCodePage + ; 4 GetCntry + ; +;FASTOPEN is not chained through INT 2F ; DOS 3.3 F.C. +; it calls Multdos 42 to set up an entry routine address + ; 0 Install status (reserved) + ; 1 Lookup + ; 2 Insert + ; 3 Delete + ; 4 Purge (reserved) + diff --git a/SRC/DOS/NIBDOS.OBJ b/SRC/DOS/NIBDOS.OBJ new file mode 100644 index 0000000..32ed62c Binary files /dev/null and b/SRC/DOS/NIBDOS.OBJ differ diff --git a/SRC/DOS/OPEN.OBJ b/SRC/DOS/OPEN.OBJ new file mode 100644 index 0000000..4a5ca57 Binary files /dev/null and b/SRC/DOS/OPEN.OBJ differ diff --git a/SRC/DOS/PARSE.OBJ b/SRC/DOS/PARSE.OBJ new file mode 100644 index 0000000..6722a8a Binary files /dev/null and b/SRC/DOS/PARSE.OBJ differ diff --git a/SRC/DOS/PATH.OBJ b/SRC/DOS/PATH.OBJ new file mode 100644 index 0000000..416800b Binary files /dev/null and b/SRC/DOS/PATH.OBJ differ diff --git a/SRC/DOS/PDB.INC b/SRC/DOS/PDB.INC new file mode 100644 index 0000000..25cc981 --- /dev/null +++ b/SRC/DOS/PDB.INC @@ -0,0 +1,47 @@ +; SCCSID = @(#)pdb.asm 1.1 85/04/10 +BREAK + +; +; Process data block (otherwise known as program header) +; + +FilPerProc EQU 20 + +Process_data_block STRUC +PDB_Exit_Call DW ? ; INT int_abort system terminate +PDB_block_len DW ? ; size of execution block + DB ? +PDB_CPM_Call DB 5 DUP (?) ; ancient call to system +PDB_Exit DD ? ; pointer to exit routine +PDB_Ctrl_C DD ? ; pointer to ^C routine +PDB_Fatal_abort DD ? ; pointer to fatal error +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +PDB_Parent_PID DW ? ; PID of parent (terminate PID) +PDB_JFN_Table DB FilPerProc DUP (?) + ; indices into system table +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +PDB_environ DW ? ; seg addr of environment +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +PDB_User_stack DD ? ; stack of self during system calls +PDB_JFN_Length DW ? ; number of handles allowed +PDB_JFN_Pointer DD ? ; pointer to JFN table +PDB_Next_PDB DD ? ; pointer to nested PDB's +PDB_PAD1 DB 14h DUP (?) +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +PDB_Call_system DB 5 DUP (?) ; portable method of system call +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +PDB_PAD2 DB 7h DUP (?) +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +Process_data_block ENDS diff --git a/SRC/DOS/PROC.OBJ b/SRC/DOS/PROC.OBJ new file mode 100644 index 0000000..d64a5e6 Binary files /dev/null and b/SRC/DOS/PROC.OBJ differ diff --git a/SRC/DOS/RENAME.OBJ b/SRC/DOS/RENAME.OBJ new file mode 100644 index 0000000..e1c3f69 Binary files /dev/null and b/SRC/DOS/RENAME.OBJ differ diff --git a/SRC/DOS/ROM.OBJ b/SRC/DOS/ROM.OBJ new file mode 100644 index 0000000..d833c1b Binary files /dev/null and b/SRC/DOS/ROM.OBJ differ diff --git a/SRC/DOS/SEARCH.OBJ b/SRC/DOS/SEARCH.OBJ new file mode 100644 index 0000000..ac153bf Binary files /dev/null and b/SRC/DOS/SEARCH.OBJ differ diff --git a/SRC/DOS/SF.INC b/SRC/DOS/SF.INC new file mode 100644 index 0000000..54039dd --- /dev/null +++ b/SRC/DOS/SF.INC @@ -0,0 +1,158 @@ +; SCCSID = @(#)sf.asm 1.1 85/04/10 +BREAK + +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +; +; system file table +; + +SF STRUC +SFLink DD ? +SFCount DW ? ; number of entries +SFTable DW ? ; beginning of array of the following +SF ENDS + +; +; system file table entry +; + +sf_entry STRUC +sf_ref_count DW ? ; number of processes sharing entry + ; if FCB then ref count +sf_mode DW ? ; mode of access or high bit on if FCB +sf_attr DB ? ; attribute of file +sf_flags DW ? ;Bits 8-15 + ; Bit 15 = 1 if remote file + ; = 0 if local file or device + ; Bit 14 = 1 if date/time is not to be + ; set from clock at CLOSE. Set by + ; FILETIMES and FCB_CLOSE. Reset by + ; other reseters of the dirty bit + ; (WRITE) + ; Bit 13 = Pipe bit (reserved) + ; + ; Bits 0-7 (old FCB_devid bits) + ; If remote file or local file, bit + ; 6=0 if dirty Device ID number, bits + ; 0-5 if local file. + ; bit 7=0 for local file, bit 7 + ; =1 for local I/O device + ; If local I/O device, bit 6=0 if EOF (input) + ; Bit 5=1 if Raw mode + ; Bit 0=1 if console input device + ; Bit 1=1 if console output device + ; Bit 2=1 if null device + ; Bit 3=1 if clock device +sf_devptr DD ? ; Points to DPB if local file, points + ; to device header if local device, + ; points to net device header if + ; remote +sf_firclus DW ? ; First cluster of file (bit 15 = 0) +sf_time DW ? ; Time associated with file +sf_date DW ? ; Date associated with file +sf_size DD ? ; Size associated with file +sf_position DD ? ; Read/Write pointer or LRU count for FCBs +; +; Starting here, the next 7 bytes may be used by the file system to store an +; ID +; +sf_cluspos DW ? ; Position of last cluster accessed +sf_lstclus DW ? ; Last cluster accessed +sf_dirsec DW ? ; Sector number of directory sector for this file +sf_dirpos DB ? ; Offset of this entry in the above +; +; End of 7 bytes of file-system specific info. +; +sf_name DB 11 DUP (?) ; 11 character name that is in the + ; directory entry. This is used by + ; close to detect file deleted and + ; disk changed errors. +; SHARING INFO +sf_chain DD ? ; link to next SF +sf_UID DW ? +sf_PID DW ? +sf_MFT DW ? +sf_entry ENDS + +sf_netid EQU BYTE PTR sf_cluspos +sf_OpenAge EQU WORD PTR sf_position+2 +sf_LRU EQU WORD PTR sf_position + +sf_default_number EQU 5h + +; +; Note that we need to mark an SFT as being busy for OPEN/CREATE. This is +; because an INT 24 may prevent us from 'freeing' it. We mark this as such +; by placing a -1 in the ref_count field. +; + +sf_busy EQU -1 + + +; mode mask for FCB detection +sf_isfcb EQU 1000000000000000B + +; Flag word masks +sf_isnet EQU 1000000000000000B +sf_close_nodate EQU 0100000000000000B +sf_pipe EQU 0010000000000000B +sf_no_inherit EQU 0001000000000000B +sf_net_spool EQU 0000100000000000B + +; Local file/device flag masks +devid_file_clean EQU 40h ; true if file and not written +devid_file_mask_drive EQU 3Fh ; mask for drive number + +devid_device EQU 80h ; true if a device +devid_device_EOF EQU 40h ; true if end of file reached +devid_device_raw EQU 20h ; true if in raw mode +devid_device_special EQU 10h ; true if special device +devid_device_clock EQU 08h ; true if clock device +devid_device_null EQU 04h ; true if null device +devid_device_con_out EQU 02h ; true if console output +devid_device_con_in EQU 01h ; true if consle input +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +; +; structure of devid field as returned by IOCTL is: +; +; BIT 7 6 5 4 3 2 1 0 +; |---|---|---|---|---|---|---|---| +; | I | E | R | S | I | I | I | I | +; | S | O | A | P | S | S | S | S | +; | D | F | W | E | C | N | C | C | +; | E | | | C | L | U | O | I | +; | V | | | L | K | L | T | N | +; |---|---|---|---|---|---|---|---| +; ISDEV = 1 if this channel is a device +; = 0 if this channel is a disk file +; +; If ISDEV = 1 +; +; EOF = 0 if End Of File on input +; RAW = 1 if this device is in Raw mode +; = 0 if this device is cooked +; ISCLK = 1 if this device is the clock device +; ISNUL = 1 if this device is the null device +; ISCOT = 1 if this device is the console output +; ISCIN = 1 if this device is the console input +; +; If ISDEV = 0 +; EOF = 0 if channel has been written +; Bits 0-5 are the block device number for +; the channel (0 = A, 1 = B, ...) +; +devid_ISDEV EQU 80h +devid_EOF EQU 40h +devid_RAW EQU 20h +devid_SPECIAL EQU 10H +devid_ISCLK EQU 08h +devid_ISNUL EQU 04h +devid_ISCOT EQU 02h +devid_ISCIN EQU 01h + +devid_block_dev EQU 1Fh ; mask for block device number diff --git a/SRC/DOS/SHARE.OBJ b/SRC/DOS/SHARE.OBJ new file mode 100644 index 0000000..01e699b Binary files /dev/null and b/SRC/DOS/SHARE.OBJ differ diff --git a/SRC/DOS/SMDOSSYM.INC b/SRC/DOS/SMDOSSYM.INC new file mode 100644 index 0000000..490a50b --- /dev/null +++ b/SRC/DOS/SMDOSSYM.INC @@ -0,0 +1,156 @@ +; SCCSID = @(#)dossym.asm 1.1 85/04/10 +; SCCSID = @(#)dossym.asm 1.1 85/04/10 + PAGE 80,132 +TRUE EQU 0FFFFh +FALSE EQU 0 + +Installed = TRUE +IFNDEF DEBUG + DEBUG = FALSE +ENDIF + +include dosmac.INC +INCLUDE VERSIONA.INC ;DEFINE THE MAJOR AND MINOR VERSION NUMBERS + +;;IF2 +;; %OUT DOSSYM in Pass 2 +;;ENDIF + +BREAK + +c_DEL EQU 7Fh ; ASCII rubout or delete previous char +c_BS EQU 08h ; ^H ASCII backspace +c_CR EQU 0Dh ; ^M ASCII carriage return +c_LF EQU 0Ah ; ^J ASCII linefeed +c_ETB EQU 17h ; ^W ASCII end of transmission +c_NAK EQU 15h ; ^U ASCII negative acknowledge +c_ETX EQU 03h ; ^C ASCII end of text +c_HT EQU 09h ; ^I ASCII tab + +BREAK + +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; ; +; C A V E A T P R O G R A M M E R ; +; ; +; Certain structures, constants and system calls below are private to ; +; the DOS and are extremely version-dependent. They may change at any ; +; time at the implementors' whim. As a result, they must not be ; +; documented to the general public. If an extreme case arises, they ; +; must be documented with this warning. ; +; ; +; Those structures and constants that are subject to the above will be ; +; marked and bracketed with the flag: ; +; ; +; C A V E A T P R O G R A M M E R ; +; ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +include bpb.INC + +include buffer.INC + +BREAK +; Location of user registers relative user stack pointer + +user_environ STRUC +user_AX DW ? +user_BX DW ? +user_CX DW ? +user_DX DW ? +user_SI DW ? +user_DI DW ? +user_BP DW ? +user_DS DW ? +user_ES DW ? +user_IP DW ? +user_CS DW ? +user_F DW ? +user_environ ENDS + +include sysvar.INC + +include vector.INC + +;include mult.INC + +BREAK +; MSDOS partitions the disk into 4 sections: +; +; phys sector 0: +-------------------+ +; | | boot/reserved | +; | +-------------------+ +; | | File allocation | +; v | table(s) | +; | (multiple copies | +; | are kept) | +; +-------------------+ +; | Directory | +; +-------------------+ +; | File space | +; +-------------------+ +; | Unaddressable | +; | (to end of disk) | +; +-------------------+ +; +; All partition boundaries are sector boundaries. The size of the FAT is +; adjusted to maximize the file space addressable. + +include dirent.INC + +BREAK +; +; The File Allocation Table uses a 12-bit entry for each allocation unit on +; the disk. These entries are packed, two for every three bytes. The contents +; of entry number N is found by 1) multiplying N by 1.5; 2) adding the result +; to the base address of the Allocation Table; 3) fetching the 16-bit word +; at this address; 4) If N was odd (so that N*1.5 was not an integer), shift +; the word right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry +; number zero is used as an end-of-file trap in the OS and is passed to the +; BIOS to help determine disk format. Entry 1 is reserved for future use. +; The first available allocation unit is assigned entry number two, and even +; though it is the first, is called cluster 2. Entries greater than 0FF8H +; (12-bit fats) or 0FFF8H (16-bit fats) are end of file marks; entries of zero +; are unallocated. Otherwise, the contents of a FAT entry is the number of +; the next cluster in the file. +; +; Clusters with bad sectors are tagged with FF7H. Any non-zero number would +; do because these clusters show as allocated, but are not part of any +; allocation chain and thus will never be allocated to a file. A particular +; number is selected so that disk checking programs know what to do (ie. a +; cluster with entry FF7H which is not in a chain is not an error). + +include dpb.INC + +include curdir.INC + +;include cpmfcb.INC + +;include find.INC + +include pdb.INC + +include exe.INC + +include sf.INC + +include arena.INC + +include intnat.INC + +include mi.INC + +fChk equ 1 +fDelim equ 2 +fSpChk equ 4 +fFCB equ 8 + +;include filemode.INC + +;include error.INC + +include syscall.INC + +include doscntry.inc ;J.K. 5/26/86 + +SUBTTL diff --git a/SRC/DOS/SRVCALL.OBJ b/SRC/DOS/SRVCALL.OBJ new file mode 100644 index 0000000..4c1dd74 Binary files /dev/null and b/SRC/DOS/SRVCALL.OBJ differ diff --git a/SRC/DOS/STDCODE.OBJ b/SRC/DOS/STDCODE.OBJ new file mode 100644 index 0000000..41bb424 Binary files /dev/null and b/SRC/DOS/STDCODE.OBJ differ diff --git a/SRC/DOS/STDCTRLC.OBJ b/SRC/DOS/STDCTRLC.OBJ new file mode 100644 index 0000000..87e08ce Binary files /dev/null and b/SRC/DOS/STDCTRLC.OBJ differ diff --git a/SRC/DOS/STDDATA.OBJ b/SRC/DOS/STDDATA.OBJ new file mode 100644 index 0000000..9e91302 Binary files /dev/null and b/SRC/DOS/STDDATA.OBJ differ diff --git a/SRC/DOS/STDDISP.OBJ b/SRC/DOS/STDDISP.OBJ new file mode 100644 index 0000000..bce9c32 Binary files /dev/null and b/SRC/DOS/STDDISP.OBJ differ diff --git a/SRC/DOS/STDDOSME.ASM b/SRC/DOS/STDDOSME.ASM new file mode 100644 index 0000000..6a7ee0d --- /dev/null +++ b/SRC/DOS/STDDOSME.ASM @@ -0,0 +1,16 @@ +; SCCSID = @(#)stddosmes.asm 1.1 85/04/10 +; +; Standard device IO for MSDOS (first 12 function calls) +; +debug=0 +.xlist +.xcref +include stdsw.inc +include dosseg.inc +.cref +.list + +TITLE STDDOSMES - DOS OEM dependancies +NAME STDDOSMES + +include dosmes.inc diff --git a/SRC/DOS/STDSW.INC b/SRC/DOS/STDSW.INC new file mode 100644 index 0000000..2217ad4 --- /dev/null +++ b/SRC/DOS/STDSW.INC @@ -0,0 +1,33 @@ +; SCCSID = @(#)stdsw.asm 1.1 85/04/10 +TRUE EQU 0FFFFH +FALSE EQU 0 + +; Use the switches below to produce the standard Microsoft version of the IBM +; version of the operating system +;MSVER EQU FALSE +;IBM EQU TRUE +WANG EQU FALSE +;ALTVECT EQU FALSE + +include version.inc + +; Set this switch to cause DOS to move itself to the end of memory +HIGHMEM EQU FALSE + +; Turn on switch below to allow testing disk code with DEBUG. It sets +; up a different stack for disk I/O (functions > 11) than that used for +; character I/O which effectively makes the DOS re-entrant. + + IF IBM +ESCCH EQU 0 ; character to begin escape seq. +CANCEL EQU 27 ;Cancel with escape +TOGLPRN EQU TRUE ;One key toggles printer echo +ZEROEXT EQU TRUE + ELSE +ESCCH EQU 1BH +CANCEL EQU "X"-"@" ;Cancel with Ctrl-X +TOGLPRN EQU FALSE ;Separate keys for printer echo on + ;and off +ZEROEXT EQU TRUE + ENDIF + \ No newline at end of file diff --git a/SRC/DOS/STDTABLE.OBJ b/SRC/DOS/STDTABLE.OBJ new file mode 100644 index 0000000..b1fa149 Binary files /dev/null and b/SRC/DOS/STDTABLE.OBJ differ diff --git a/SRC/DOS/SYSCALL.INC b/SRC/DOS/SYSCALL.INC new file mode 100644 index 0000000..e95691a --- /dev/null +++ b/SRC/DOS/SYSCALL.INC @@ -0,0 +1,160 @@ +; SCCSID = @(#)syscall.asm 1.1 85/04/10 +BREAK + +Abort EQU 0 ; 0 0 +Std_Con_Input EQU 1 ; 1 1 +Std_Con_Output EQU 2 ; 2 2 +Std_Aux_Input EQU 3 ; 3 3 +Std_Aux_Output EQU 4 ; 4 4 +Std_Printer_Output EQU 5 ; 5 5 +Raw_Con_IO EQU 6 ; 6 6 +Raw_Con_Input EQU 7 ; 7 7 +Std_Con_Input_No_Echo EQU 8 ; 8 8 +Std_Con_String_Output EQU 9 ; 9 9 +Std_Con_String_Input EQU 10 ; 10 A +Std_Con_Input_Status EQU 11 ; 11 B +Std_Con_Input_Flush EQU 12 ; 12 C +Disk_Reset EQU 13 ; 13 D +Set_Default_Drive EQU 14 ; 14 E +FCB_Open EQU 15 ; 15 F +FCB_Close EQU 16 ; 16 10 +Dir_Search_First EQU 17 ; 17 11 +Dir_Search_Next EQU 18 ; 18 12 +FCB_Delete EQU 19 ; 19 13 +FCB_Seq_Read EQU 20 ; 20 14 +FCB_Seq_Write EQU 21 ; 21 15 +FCB_Create EQU 22 ; 22 16 +FCB_Rename EQU 23 ; 23 17 +Get_Default_Drive EQU 25 ; 25 19 +Set_DMA EQU 26 ; 26 1A +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +Get_Default_DPB EQU 31 ; 31 1F +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +FCB_Random_Read EQU 33 ; 33 21 +FCB_Random_Write EQU 34 ; 34 22 +Get_FCB_File_Length EQU 35 ; 35 23 +Get_FCB_Position EQU 36 ; 36 24 +Set_Interrupt_Vector EQU 37 ; 37 25 +Create_Process_Data_Block EQU 38 ; 38 26 +FCB_Random_Read_Block EQU 39 ; 39 27 +FCB_Random_Write_Block EQU 40 ; 40 28 +Parse_File_Descriptor EQU 41 ; 41 29 +Get_Date EQU 42 ; 42 2A +Set_Date EQU 43 ; 43 2B +Get_Time EQU 44 ; 44 2C +Set_Time EQU 45 ; 45 2D +Set_Verify_On_Write EQU 46 ; 46 2E +; Extended functionality group +Get_DMA EQU 47 ; 47 2F +Get_Version EQU 48 ; 48 30 +Keep_Process EQU 49 ; 49 31 +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +Get_DPB EQU 50 ; 50 32 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +Set_CTRL_C_Trapping EQU 51 ; 51 33 +Get_InDOS_Flag EQU 52 ; 52 34 +Get_Interrupt_Vector EQU 53 ; 53 35 +Get_Drive_Freespace EQU 54 ; 54 36 +Char_Oper EQU 55 ; 55 37 +International EQU 56 ; 56 38 +; Directory Group +MKDir EQU 57 ; 57 39 +RMDir EQU 58 ; 58 3A +CHDir EQU 59 ; 59 3B +; File Group +Creat EQU 60 ; 60 3C +Open EQU 61 ; 61 3D +Close EQU 62 ; 62 3E +Read EQU 63 ; 63 3F +Write EQU 64 ; 64 40 +Unlink EQU 65 ; 65 41 +LSeek EQU 66 ; 66 42 +CHMod EQU 67 ; 67 43 +IOCtl EQU 68 ; 68 44 +XDup EQU 69 ; 69 45 +XDup2 EQU 70 ; 70 46 +Current_Dir EQU 71 ; 71 47 +; Memory Group +Alloc EQU 72 ; 72 48 +Dealloc EQU 73 ; 73 49 +Setblock EQU 74 ; 74 4A +; Process Group +Exec EQU 75 ; 75 4B +Exit EQU 76 ; 76 4C +Wait EQU 77 ; 77 4D +Find_First EQU 78 ; 78 4E +; Special Group +Find_Next EQU 79 ; 79 4F +; SPECIAL SYSTEM GROUP +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +Set_Current_PDB EQU 80 ; 80 50 +Get_Current_PDB EQU 81 ; 81 51 +Get_In_Vars EQU 82 ; 82 52 +SetDPB EQU 83 ; 83 53 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +Get_Verify_On_Write EQU 84 ; 84 54 +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +Dup_PDB EQU 85 ; 85 55 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +Rename EQU 86 ; 86 56 +File_Times EQU 87 ; 87 57 +AllocOper EQU 88 ; 88 58 +; Network extention system calls +GetExtendedError EQU 89 ; 89 59 +CreateTempFile EQU 90 ; 90 5A +CreateNewFile EQU 91 ; 91 5B +LockOper EQU 92 ; 92 5C Lock and Unlock +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +ServerCall EQU 93 ; 93 5D CommitAll, ServerDOSCall, + ; CloseByName, CloseUser, + ; CloseUserProcess, + ; GetOpenFileList +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +UserOper EQU 94 ; 94 5E Get and Set +AssignOper EQU 95 ; 95 5F On, Off, Get, Set, Cancel +xNameTrans EQU 96 ; 96 60 +PathParse EQU 97 ; 97 61 +GetCurrentPSP EQU 98 ; 98 62 +Hongeul EQU 99 ; 99 63 +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +Set_Printer_Flag EQU 100 ; 100 64 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +GetExtCntry EQU 101 ; 101 65 +GetSetCdPg EQU 102 ; 102 66 +ExtHandle EQU 103 ; 103 67 +Commit EQU 104 ; 104 68 +; +; +Set_Oem_Handler EQU 248 ; 248 F8 +OEM_C1 EQU 249 ; 249 F9 +OEM_C2 EQU 250 ; 250 FA +OEM_C3 EQU 251 ; 251 FB +OEM_C4 EQU 252 ; 252 FC +OEM_C5 EQU 253 ; 253 FD +OEM_C6 EQU 254 ; 254 FE +OEM_C7 EQU 255 ; 255 FF + \ No newline at end of file diff --git a/SRC/DOS/SYSVAR.INC b/SRC/DOS/SYSVAR.INC new file mode 100644 index 0000000..ecd3e48 --- /dev/null +++ b/SRC/DOS/SYSVAR.INC @@ -0,0 +1,24 @@ +; SCCSID = @(#)sysvar.asm 1.1 85/04/10 +SysInitVars STRUC +SYSI_DPB DD ? ; DPB chain +SYSI_SFT DD ? ; SFT chain +SYSI_CLOCK DD ? ; CLOCK device +SYSI_CON DD ? ; CON device +SYSI_MAXSEC DW ? ; maximum sector size +SYSI_BUF DD ? ; buffer chain +SYSI_CDS DD ? ; CDS list +SYSI_FCB DD ? ; FCB chain +SYSI_Keep DW ? ; keep count +SYSI_NUMIO DB ? ; Number of block devices +SYSI_NCDS DB ? ; number of CDS's +SYSI_DEV DD ? ; device list +SysInitVars ENDS + +;This is added for more information exchage between DOS, BIOS. +;DOS will give the pointer to SysInitTable in ES:DI. - J.K. 5/29/86 +SysInitVars_Ext struc +SYSI_InitVars DD 0 ; Points to the above structure. +SYSI_Country_Tab DD 0 ; DOS_Country_cdpg_info +SysInitVars_Ext ends + + \ No newline at end of file diff --git a/SRC/DOS/TIME.OBJ b/SRC/DOS/TIME.OBJ new file mode 100644 index 0000000..d411890 Binary files /dev/null and b/SRC/DOS/TIME.OBJ differ diff --git a/SRC/DOS/UTIL.OBJ b/SRC/DOS/UTIL.OBJ new file mode 100644 index 0000000..f244718 Binary files /dev/null and b/SRC/DOS/UTIL.OBJ differ diff --git a/SRC/DOS/VECTOR.INC b/SRC/DOS/VECTOR.INC new file mode 100644 index 0000000..f653784 --- /dev/null +++ b/SRC/DOS/VECTOR.INC @@ -0,0 +1,72 @@ +; SCCSID = @(#)vector.asm 1.1 85/04/10 +BREAK + +Asmvar AltVect + +INTTAB EQU 20H +INTBASE EQU 4 * inttab +ENTRYPOINT EQU INTBASE+40H + + IF ALTVECT +ALTTAB EQU 0F0H +ALTBASE EQU 4 * ALTTAB + ENDIF + +; +; interrupt assignments +; + IF NOT ALTVECT +int_abort EQU INTTAB ; abort process +int_command EQU int_abort+1 ; call MSDOS +int_terminate EQU int_abort+2 ; int to terminate address +int_ctrl_c EQU int_abort+3 ; ^c trapper +int_fatal_abort EQU int_abort+4 ; hard disk error +int_disk_read EQU int_abort+5 ; logical sector disk read +int_disk_write EQU int_abort+6 ; logical sector disk write +int_keep_process EQU int_abort+7 ; terminate program and stay + ; resident +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +int_spooler EQU int_abort+8 ; spooler call +int_fastcon EQU int_abort+9 ; fast CON interrupt +int_IBM EQU int_abort+10; critical section maintenance +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + ELSE +int_abort EQU INTTAB ; abort process +int_command EQU int_abort+1 ; call MSDOS +int_terminate EQU ALTTAB ; int to terminate address +int_ctrl_c EQU int_terminate+1 ; ^c trapper +int_fatal_abort EQU int_terminate+2 ; hard disk error +int_disk_read EQU int_abort+5 ; logical sector disk read +int_disk_write EQU int_abort+6 ; logical sector disk write +int_keep_process EQU int_abort+7 ; terminate program and stay resident +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +int_spooler EQU int_terminate+3 ; spooler call +int_fastcon EQU int_abort+9 ; fast CON interrupt +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + ENDIF + +addr_int_abort EQU 4 * int_abort +addr_int_command EQU 4 * int_command +addr_int_terminate EQU 4 * int_terminate +addr_int_ctrl_c EQU 4 * int_ctrl_c +addr_int_fatal_abort EQU 4 * int_fatal_abort +addr_int_disk_read EQU 4 * int_disk_read +addr_int_disk_write EQU 4 * int_disk_write +addr_int_keep_process EQU 4 * int_keep_process +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +addr_int_spooler EQU 4 * int_spooler +addr_int_fastcon EQU 4 * int_fastcon +addr_int_IBM EQU 4 * int_IBM +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; diff --git a/SRC/INC/MACRO.INC b/SRC/INC/MACRO.INC new file mode 100644 index 0000000..cf11a24 --- /dev/null +++ b/SRC/INC/MACRO.INC @@ -0,0 +1,19 @@ + PAGE +;***************************************************************************; +; MACRO DEFINITION ; +;***************************************************************************; + +PRINT MACRO MESSAGE + MOV DX,OFFSET MESSAGE&_PTR + PUSH DX + PUSH CS + CALL PRINTF +ENDM + + + +INPUT MACRO MESSAGE + PRINT MESSAGE + CALL PROMPT +ENDM + \ No newline at end of file diff --git a/SRC/INC/STRUC.INC b/SRC/INC/STRUC.INC new file mode 100644 index 0000000..7a81ed6 --- /dev/null +++ b/SRC/INC/STRUC.INC @@ -0,0 +1,573 @@ +;;STRUC.INC--Stucture Macro Library +;;Version 2.10 03/07/86 + +if1 +$noconj equ 0 +$and equ 1 +$or equ 2 +$short equ 3 +$near equ 4 +$andor = 0 +$temp = 0 +$temp2 = 0 +$dist = 0 + +$notype equ 10 +$conjif equ 11 +$iftype equ 12 +$elsetype equ 13 +$whiletype equ 14 +$conjwhile equ 15 +$repeattype equ 16 +$conjuntil equ 17 +$fortype equ 18 +$conjleave equ 19 + +jbuild macro c1,c2,blank +j&c1 macro tgt +.xcref j&c1 + j&c2 tgt + blank&endm + endm + + irp x,<,,,,,,,> + jbuild x + endm + + irp x, + jbuild nn&x,x + endm + +jncxz macro tgt + local skip + jcxz skip + jmp short tgt +skip: + endm + + purge jbuild + +$getconj macro p1 + ifidn , + $andor = $and + endif + ifidn , + $andor = $and + endif + ifidn , + $andor = $or + endif + ifidn , + $andor = $or + endif + endm + +$getdist macro p1 + ifidn , + $dist = $short + endif + ifidn , + $dist = $short + endif + ifidn , + $dist = $near + endif + ifidn , + $dist = $near + endif + endm + + +$poke macro num,value + $st&num = value +.xcref $st&num + endm + +$peek macro sym,num + sym = $st&num + endm + +$push macro value + $st = $st+1 + $poke %$st,value + endm + +$pop macro sym + $peek sym,%$st + $st = $st-1 + endm + +$labl macro num +$l&num: + endm + +$cjump macro lnum,tf,cond,d1,d2 + local skip + $dist = $defdist + ifnb + $getdist d1 + ifnb + $getdist d2 + endif + endif + + if $dist eq $short + ifb + jmp short $l&lnum + else + ifidn , + jn&cond $l&lnum + else + j&cond $l&lnum + endif + endif + else + ifnb + ifidn , + j&cond skip + else + jn&cond skip + endif + endif + jmp $l&lnum + ifnb +skip: + endif + endif + endm + +$cloop macro lnum,cond + loop&cond $l&lnum + endm +;;***************************************************************************** +.if macro tst,p2,p3 + $if_2 p2,p3,tst + endm +$if_2 macro p1,p2,a1,a2,a3 + ifb + $if_3 ,a1,,p1,p2 + else + $if_3 ,a2,,p1,p2 + endif + endm +$if_3 macro arg1,cond,arg2,p4,p5 + $peek $temp,%$st + if $temp eq $conjif + $pop $temp + else + $push $elseiffound + $elseiffound = 0 + $orfound = 0 + $sn = $sn+1 + $push $sn + $sn = $sn+1 + $push $sn + $sn = $sn+1 + $push $sn + endif + + $andor = $noconj + ifnb + $getconj p4 + ifnb + $getconj p5 + endif + endif + + ifnb + cmp arg1,arg2 + endif + + if $andor eq $noconj + $cjump %$sn-1,f,cond,p4,p5 + $pop $temp + if $orfound + $labl %$temp + endif + $push $iftype + else + if $andor eq $and + $cjump %$sn-1,f,cond,p4,p5 + else + $orfound = 1 + $cjump %$sn,t,cond,p4,p5 + endif + $push $conjif + endif + endm +;;***************************************************************************** +.then macro + $peek $temp,%$st + if $temp ne $iftype + structure error--then without if + endif + endm +;;***************************************************************************** +.elseif macro tst,p2,p3 + $elseif_2 p2,p3,tst + endm +$elseif_2 macro p1,p2,a1,a2,a3 + ifb + $elseif_3 ,a1,,p1,p2 + else + $elseif_3 ,a2,,p1,p2 + endif + endm +$elseif_3 macro arg1,cond,arg2,p4,p5 + $pop $temp + if $temp ne $iftype + structure error--elseif without if + exitm + endif + $elseiffound = 1 + $orfound = 0 + $pop $temp + $peek $temp2,%$st + $cjump %$temp2,,,near + $labl %$temp + $sn = $sn+1 + $push $sn + $sn = $sn+1 + $push $sn + + $andor = $noconj + ifnb + $getconj p4 + ifnb + $getconj p5 + endif + endif + + ifnb + cmp arg1,arg2 + endif + + if $andor eq $noconj + $cjump %$sn-1,f,cond,p4,p5 + $pop $temp + if $orfound + $labl %$temp + endif + $push $iftype + else + if $andor eq $and + $cjump %$sn-1,f,cond,p4,p5 + else + $orfound = 1 + $cjump %$sn,t,cond,p4,p5 + endif + $push $conjif + endif + endm +;;***************************************************************************** +.else macro dist + $pop $temp + if $temp ne $iftype + structure error--else without if + exitm + endif + $sn = $sn+1 + $cjump %$sn,,,dist + $pop $temp + $labl %$temp + $push $sn + $push $elsetype + endm +;;***************************************************************************** +.endif macro + $pop $temp + if $temp ne $iftype + if $temp ne $elsetype + structure error--endif without if + exitm + endif + endif + $pop $temp + $labl %$temp + $pop $temp + if $elseiffound + $labl %$temp + endif + $pop $elseiffound + endm +;;***************************************************************************** +.while macro tst,p2,p3 + $while_2 p2,p3,tst + endm +$while_2 macro p1,p2,a1,a2,a3 + ifb + $while_3 ,a1,,p1,p2 + else + $while_3 ,a2,,p1,p2 + endif + endm +$while_3 macro arg1,cond,arg2,p4,p5 + $peek $temp,%$st + if $temp eq $conjwhile + $pop $temp + else + $push $endloop + $orfound = 0 + $sn = $sn + 1 + $push $sn + $labl %$sn + $sn = $sn + 2 + $push $sn + $endloop = $sn - 1 + endif + + $andor = $noconj + ifnb + $getconj p4 + ifnb + $getconj p5 + endif + endif + + ifnb + cmp arg1,arg2 + endif + + if $andor eq $noconj + $cjump %$sn-1,f,cond,p4,p5 + $pop $temp + if $orfound + $labl %$temp + endif + $push $whiletype + else + if $andor eq $and + $cjump %$sn-1,f,cond,p4,p5 + else + $orfound = 1 + $cjump %$sn,t,cond,p4,p5 + endif + $push $conjwhile + endif + endm +;;***************************************************************************** +.endwhile macro + $pop $temp + if $temp ne $whiletype + structure error -- endwhile without while + exitm + endif + $pop $temp + $cjump %$temp,,,near + $labl %$temp+1 + $pop $endloop + endm +;;***************************************************************************** +.repeat macro + $push $endloop + $push $leavefound + $sn = $sn+1 + $labl %$sn + $push $sn + $push $repeattype + $sn = $sn+1 + $endloop = $sn + $leavefound = 0 + endm +;;***************************************************************************** +.until macro tst,p2,p3 + $until_2 p2,p3,tst + endm +$until_2 macro p1,p2,a1,a2,a3 + ifb + $until_3 ,,,near + else + ifb + $until_3 ,a1,,p1,p2 + else + $until_3 ,a2,,p1,p2 + endif + endif + endm +$until_3 macro arg1,cond,arg2,p4,p5 + $pop $temp + if $temp ne $repeattype + if $temp ne $conjuntil + structure error -- until without repeat + exitm + endif + else + $orfound = 0 + endif + + ifnb + cmp arg1,arg2 + endif + + $andor = $noconj + ifnb + $getconj p4 + ifnb + $getconj p5 + endif + endif + + if $andor eq $noconj + $pop $temp + $cjump %$temp,f,cond,p4,p5 + if $orfound or $leavefound + $labl %$temp+1 + endif + $pop $leavefound + $pop $endloop + else + $peek $temp,%$st + if $andor eq $and + $cjump %$temp,f,cond,p4,p5 + else + $orfound = 1 + $cjump %$temp+1,t,cond,p4,p5 + endif + $push $conjuntil + endif + endm +;;***************************************************************************** +.loop macro cond + $pop $temp + if $temp ne $repeattype + structure error -- loop without repeat + exitm + endif + $pop $temp + $cloop %$temp,cond + if $leavefound + $labl %$temp+1 + endif + $pop $leavefound + $pop $endloop + endm +;;***************************************************************************** +.for macro index,equals,start,to,stop,by,step,dist + mov index,start + $push $endloop + $sn = $sn+1 + $push $sn + $labl %$sn + $sn = $sn+1 + $endloop = $sn + cmp index,stop + + ifb + $push 1 + $cjump %$sn,t,gt,by + else + $push %(step) + if step lt 0 + $cjump %$sn,t,lt,dist + else + $cjump %$sn,t,gt,dist + endif + endif + $push $fortype + endm +;;***************************************************************************** +.next macro index + $pop $temp + if $temp ne $fortype + structure error -- next without for + exitm + endif + $pop $temp + if $temp eq 1 + inc index + else + if $temp eq -1 + dec index + else + add index,$temp + endif + endif + $pop $temp + $cjump %$temp,,,near + $labl %$temp+1 + $pop $endloop + endm +;;***************************************************************************** +.leave macro tst,p2,p3 + $leave_2 p2,p3,tst + endm + +$leave_2 macro p1,p2,a1,a2,a3 + $dist = 0 + $getdist + if $dist + $leave_3 ,,,a1 + else + ifb + $leave_3 ,a1,,p1,p2 + else + $leave_3 ,a2,,p1,p2 + endif + endif + endm + +$leave_3 macro arg1,cond,arg2,p4,p5 + ife $endloop + structure error--leave outside a loop + exitm + endif + $leavefound = 1 + $peek $temp,%$st + if $temp eq $conjleave + $pop $temp + else + $orfound = 0 + $sn = $sn + 1 + endif + + $andor = $noconj + ifnb + $getconj p4 + ifnb + $getconj p5 + endif + endif + + ifnb + cmp arg1,arg2 + endif + + if $andor eq $noconj + $cjump %$endloop,t,cond,p4,p5 + if $orfound + $labl %$sn + endif + else + if $andor eq $and + $orfound = 1 + $cjump %$sn,f,cond,p4,p5 + else + $cjump %$endloop,t,cond,p4,p5 + endif + $push $conjleave + endif + endm +;;***************************************************************************** +else + $pop $temp + if $temp ne $notype + structure error -- open structure(s) + endif + .xcref $noconj,$and,$or,$short,$near,$andor,$temp,$temp2,$dist + .xcref $notype,$conjif,$iftype,$elsetype,$whiletype,$conjwhile + .xcref $repeattype,$conjuntil,$fortype,$conjleave,jncxz + .xcref jeq,jgt,jlt,jneq,jngt,jnlt,jnna,jnnae,jnnb,jnnbe,jnnc,jnncxz + .xcref jnne,jnng,jnnge,jnnl,jnnle,jnno,jnnp,jnns,jnnz,jnpe,jnpo,jbuild + .xcref $getconj,$getdist,$poke,$peek,$push,$pop,$labl,$cjump,$cloop + .xcref $if_2,$if_3,$elseif_2,$elseif_3,$while_2,$while_3 + .xcref $until_2,$until_3,$leave_2,$leave_3 + .xcref $st,$sn,$orfound,$elseiffound,$endloop,$leavefound,$defdist +endif +$st = 0 +$sn = 0 +$orfound = 0 +$elseiffound = 0 +$endloop = 0 +$leavefound = 0 +$defdist = $short +$push %$notype diff --git a/SRC/INC/VERSION.INC b/SRC/INC/VERSION.INC new file mode 100644 index 0000000..96febeb --- /dev/null +++ b/SRC/INC/VERSION.INC @@ -0,0 +1,92 @@ +TRUE EQU 0FFFFh +TRUEBYTE EQU 0FFh +FALSE EQU 0 +; +; Use the following switches to control cmacros.inc +; +?PLM = 0 +?WIN = 0 + +memS EQU 1 ; Small model +; +; Use the switches below to produce the standard Microsoft version or the IBM +; version of the operating system +; +; The below chart will indicate how to set the switches to build the various +; versions +; +; IBMVER IBMCOPYRIGHT +; -------------------------------------------------------- +; IBM Version | TRUE TRUE +; -------------------------------------------------------- +; MS Version | FALSE FALSE +; -------------------------------------------------------- +; Clone Version | TRUE FALSE +; +IBMVER EQU TRUE +IBMCOPYRIGHT EQU FALSE + +MSVER EQU NOT IBMVER +IBM EQU IBMVER +; +; + IF1 + IF IBMVER + IF IBMCOPYRIGHT + %OUT ... IBM version build switch on ... + ELSE + %OUT ... CLONE version build switch on ... + ENDIF + ELSE + IF NOT IBMCOPYRIGHT + %OUT ... MS version build switch on ... + ELSE + %OUT !!!!!!!!! VERSION SWITCHES SET INCORECTLY !!!!!!!!! + %OUT !!!!!!!!! CHECK SETTINGS IN INC\VERSION.INC !!!!!!!!! + ENDIF + ENDIF + ENDIF +; +; +;*************************************************************************** +;* The following switches are for DBCS or SBCS support * +;* * +;* Set INTERNAT EQU TRUE FOR DBCS * +;* Set INTERNAT EQU FALSE FOR SBCS * +;* * +;*************************************************************************** +; +IBMJAPVER EQU FALSE ;If TRUE set KANJI true also + +; +; Switch INTERNAT for DBCS support +; +INTERNAT EQU FALSE +; + IF INTERNAT +ALTVECT EQU FALSE ;Switch to build ALTVECT version +KANJI EQU TRUE +IBMJAPAN EQU TRUE + ELSE +ALTVECT EQU FALSE ;Switch to build ALTVECT version +KANJI EQU FALSE +IBMJAPAN EQU FALSE + ENDIF +; +; Country code switches +; The default contry code is assumed as USA. +; + IF INTERNAT + KOREA EQU TRUE + JAPAN EQU FALSE + ELSE + KOREA EQU FALSE + JAPAN EQU FALSE + ENDIF +; + IF1 + IF INTERNAT +%OUT Internat(ECS) version build switch on + ENDIF + ENDIF + \ No newline at end of file diff --git a/SRC/INC/VERSIONA.INC b/SRC/INC/VERSIONA.INC new file mode 100644 index 0000000..20435f3 --- /dev/null +++ b/SRC/INC/VERSIONA.INC @@ -0,0 +1,19 @@ + +major_version equ 3 ;Major DOS version +minor_version equ 30 ;Minor DOS Version + +expected_version equ (MINOR_VERSION SHL 8)+MAJOR_VERSION + + if1 + %OUT ... for DOS Version 3.30 ... + endif + + ;****************************** + ;Each assembler program should: + ; mov ah,030h ;DOS Get Version function + ; int 021h ;Version ret. in AX,minor version first + ; cmp ax,expected_version ;ALL utilities should check for an + ; jne error_handler ; EXACT version match. + ;****************************** + + \ No newline at end of file diff --git a/SRC/LIBC/CDS.C b/SRC/LIBC/CDS.C new file mode 100644 index 0000000..fe0a1d9 --- /dev/null +++ b/SRC/LIBC/CDS.C @@ -0,0 +1,129 @@ +/* cds utilities */ +#include "types.h" +#include "sysvar.h" +#include "cds.h" +#include "dpb.h" +#include + +extern struct sysVarsType SysVars ; + +char fGetCDS(i, pLCDS) +int i ; +struct CDSType *pLCDS ; +{ + struct CDSType far *cptr ; + int j ; + + if (i >= 0 && i < SysVars.cCDS) { + *(long *)(&cptr) = SysVars.pCDS + (i * sizeof(*pLCDS)) ; + + for (j=0 ; j <= sizeof(*pLCDS) ; j++) + *((char *)pLCDS+j) = *((char far *)cptr+j) ; + + return TRUE ; + } ; + return FALSE ; +} + + + + +char fPutCDS(i, pLCDS) +int i ; +struct CDSType *pLCDS ; +{ + struct CDSType far *cptr ; + int j ; + + if (i >= 0 && i < SysVars.cCDS) { + *(long *)(&cptr) = SysVars.pCDS + (i * sizeof(*pLCDS)) ; + + for (j=0 ; j <= sizeof(*pLCDS) ; j++) + *((char far *)cptr+j) = *((char *)pLCDS+j) ; + + return TRUE ; + } ; + return FALSE ; +} + +/* returns TRUE if drive i is a physical drive. Physical means that logical + * drive n corresponds with physical drive n. This is the case ONLY if the + * CDS is inuse and the DPB corresponding to the CDS has the physical drive + * equal to the original drive. + */ + +char fPhysical(i) +int i ; +{ + struct DPBType DPB ; + struct DPBType *pd = &DPB ; + struct DPBType far *dptr ; + int j ; + + struct CDSType CDS ; + + if (!fGetCDS(i, &CDS)) + return FALSE ; + + if (TESTFLAG(CDS.flags,CDSNET | CDSSPLICE | CDSLOCAL)) + return FALSE ; + + *(long *)(&dptr) = CDS.pDPB ; + + for (j=0 ; j <= sizeof(DPB) ; j++) + *((char *)pd+j) = *((char far *)dptr+j) ; + + return(i == DPB.drive) ; +} + +/* return TRUE if the specified drive is a network drive. i is a 0-based + * quantity + */ + +/* MODIFICATION HISTORY + * + * M000 June 5/85 Barrys + * Removed extra net check. + */ + +char fNet(i) +int i ; +{ + union REGS ir ; + register union REGS *iregs = &ir ; /* Used for DOS calls */ + + struct CDSType CDS ; + + if (!fGetCDS(i, &CDS)) + return FALSE ; + + iregs->x.ax = IOCTL9 ; /* Function 0x4409 */ + iregs->x.bx = i + 1 ; + intdos(iregs, iregs) ; + +/*** M000 + return(TESTFLAG(CDS.flags,CDSNET) || TESTFLAG(iregs->x.dx,0x1000)) ; +***/ + return(TESTFLAG(CDS.flags,CDSNET)) ; +} + + +/* return TRUE if the specified drive is a shared drive. i is a 0-based + * quantity + */ +char fShared(i) +int i ; +{ + struct CDSType CDS ; + union REGS ir ; + register union REGS *iregs = &ir ; /* Used for DOS calls */ + + if (!fGetCDS(i, &CDS)) + return FALSE ; + + iregs->x.ax = IOCTL9 ; /* Function 0x4409 */ + iregs->x.bx = i + 1 ; + intdos(iregs, iregs) ; + + return TESTFLAG(CDS.flags,CDSNET) || TESTFLAG(iregs->x.dx,0x0200) ; +} diff --git a/SRC/LIBC/DPB.C b/SRC/LIBC/DPB.C new file mode 100644 index 0000000..1776f5d --- /dev/null +++ b/SRC/LIBC/DPB.C @@ -0,0 +1,37 @@ +/* dpb.c - retrieve DPB for physical drive */ + +#include "types.h" +#include "sysvar.h" +#include "dpb.h" +#include "cds.h" + +extern char NoMem[], ParmNum[], BadParm[] ; +extern struct sysVarsType SysVars ; + + +/* Walk the DPB list trying to find the appropriate DPB */ + +long GetDPB(i) +int i ; +{ + struct DPBType DPB ; + struct DPBType *pd = &DPB ; + struct DPBType far *dptr ; + int j ; + + *(long *)(&dptr) = DPB.nextDPB = SysVars.pDPB ; + DPB.drive = -1 ; + + while (DPB.drive != i) { + if ((int)DPB.nextDPB == -1) + return -1L ; + + *(long *)(&dptr) = DPB.nextDPB ; + + for (j=0 ; j <= sizeof(DPB) ; j++) + *((char *)pd+j) = *((char far *)dptr+j) ; + + } ; + return (long)dptr ; +} + diff --git a/SRC/LIBC/ERRTST.C b/SRC/LIBC/ERRTST.C new file mode 100644 index 0000000..e253779 --- /dev/null +++ b/SRC/LIBC/ERRTST.C @@ -0,0 +1,271 @@ +#include "types.h" +#include "dpb.h" +#include + +/* #define KANJI TRUE */ + +/* return FALSE if drive is valid AND the path is not a prefix of a non-root + * current directory. + */ +char fPathErr(p) +char *p ; +{ + char buf[MAXARG] ; + int d ; +#ifdef KANJI + char *p1; +#endif + + if (p[1] == ':') + d = *p-'A'+1 ; + else + d = 0 ; + + if (curdir(buf, d) == -1) /* drive is invalid => error */ + return(TRUE) ; + + if (strlen(buf) == 3) /* current directory is root => OK */ + return(FALSE) ; + + if (strpre(p, buf)) { +#ifdef KANJI + p1 = p; + while (*p1 != NULL) { + if(testkanj(*p1 & 0xFF)) + p1 += 2 ; + else + if((*p1++ == '\\') && (*p1 == NULL)) + return(TRUE) ; + } +#else + if (p[strlen(p)-1] == '\\') /* prefix matched, prefix had...*/ + return(TRUE) ; /* ...trailing / => valid ... */ + /* ...prefix => ERROR */ +#endif + d = buf[strlen(p)] ; + if (d == 0 || d == '\\') /* prefix matched,... */ + return(TRUE) ; /* ...prefix had no trailing /, */ + /* ...next char was / => ... */ + /* ...valid prefix => ERROR */ + } ; + + return(FALSE) ; /* drive letter good and not valid prefix => OK */ +} + + +strpre(pre, tot) + char *pre; + char *tot; +{ + return(!strncmp(pre, tot, strlen(pre))); +} + + + +Fatal(p) +char *p ; +{ + printf("%s\n", p) ; + exit(1) ; +} + + + + +ffirst(pb, attr, pfbuf) +char *pb ; +int attr ; +struct findType *pfbuf ; +{ + union REGS regs ; + + /* set DMA to point to buffer */ + + regs.h.ah = 0x1A ; + regs.x.dx = (unsigned) pfbuf ; + intdos (®s, ®s) ; + + /* perform system call */ + + regs.h.ah = 0x4E ; + regs.x.cx = attr ; + regs.x.dx = (unsigned) pb ; + intdos (®s, ®s) ; + + return (regs.x.cflag ? -1 : 0) ; +} + +fnext (pfbuf) +struct findType *pfbuf; +{ + union REGS regs; + + /* set DMA to point to buffer */ + regs.h.ah = 0x1A; + regs.x.dx = (unsigned) pfbuf; + intdos (®s, ®s); + /* perform system call */ + regs.h.ah = 0x4F; + intdos (®s, ®s); + return (regs.x.cflag ? -1 : 0) ; +} + + +char *strbscan(str, class) +char *str ; +char *class ; +{ + char *p ; + char *strpbrk() ; + + p = strpbrk(str, class) ; + return((p == NULL) ? (str + strlen(str)) : p) ; +} + + + + + +/* curdir.c - return text of current directory for a particular drive */ + + +curdir (dst, drive) +char *dst ; +int drive ; +{ + union REGS regs ; + + *dst++ = PathChr ; + regs.h.ah = 0x47 ; + regs.h.dl = drive ; + regs.x.si = (unsigned) dst ; + intdos (®s, ®s) ; + return(regs.x.cflag ? -1 : 0) ; +} + + + + +/* + rootpath +*/ + +/*** rootpath -- convert a pathname argument to root based cannonical form + * + * rootpath determines the current directory, appends the path argument (which + * may affect which disk the current directory is relative to), and qualifies + * "." and ".." references. The result is a complete, simple, path name with + * drive specifier. + * + * If the relative path the user specifies does not include a drive spec., the + * default drive will be used as the base. (The default drive will never be + * changed.) + * + * entry: relpath -- pointer to the pathname to be expanded + * fullpath -- must point to a working buffer, see warning + * exit: fullpath -- the full path which results + * return: true if an error occurs, false otherwise + * + * calls: curdir, getdrv + * + * warning: fullpath must point to a working buffer large enough to hold the + * longest possible relative path argument plus the longest possible + * current directory path. + * + */ +int rootpath(relpath, fullpath) +char *relpath ; +char *fullpath ; +{ + int drivenum ; + char tempchar, getdrv() ; + register char *lead, *follow ; + char *p1, *p2; + + + /* extract drive spec */ + drivenum = getdrv() ; + if ((*relpath != NULL) && (relpath[1] == COLON)) { + drivenum = toupper(*relpath) - 'A' ; + relpath += 2 ; + } + fullpath[0] = (char) ('A' + drivenum) ; + fullpath[1] = COLON ; + + /* append relpath to fullpath/base */ + if (*relpath == PathChr) { + /* relpath starts at base */ + strcpy(fullpath+2, relpath) ; + } + else { + /* must get base path first */ + if (curdir(fullpath+2, drivenum+1)) + return(TRUE) ; /* terrible error */ + if ((*relpath != ASCNULL) && (strlen(fullpath) > 3)) + strcat(fullpath, "\\") ; + strcat(fullpath, relpath) ; + } + + + /* convert path to cannonical form */ + lead = fullpath ; + while(*lead != ASCNULL) { + /* mark next path segment */ + follow = lead ; + lead = (char *) strpbrk(follow+1, "\\") ; + if (lead == NULL) + lead = fullpath + strlen(fullpath) ; + tempchar = *lead ; + if (tempchar == PathChr) + tempchar = BACKSLASH ; /* make breaks uniform */ + *lead = ASCNULL ; + + /* "." segment? */ + if (strcmp(follow+1, ".") == 0) { + *lead = tempchar ; + strcpy(follow, lead) ; /* remove "." segment */ + lead = follow ; + } + + /* ".." segment? */ + else if (strcmp(follow+1, "..") == 0) { + *lead = tempchar ; + tempchar = *follow ; + *follow = NULL ; + p2 = fullpath - 1 ; + while(*(p2=strbscan(p1=p2+1,"\\")) != NULL) ; + /* p1 now points to the start of the previous element */ + *follow = tempchar ; + if(p1 == fullpath) + return(TRUE) ; /* tried to .. the root */ + follow = p1 - 1 ; /* follow points to path sep */ + strcpy(follow, lead) ; /* remove ".." segment */ + lead = follow ; + } + + /* normal segment */ + else + *lead = tempchar ; + } + if (strlen(fullpath) == 2) /* 'D:' or some such */ + strcat(fullpath, "\\") ; + + /* shift to upper case */ + strupr(fullpath) ; + + return(FALSE) ; +} + + +/* getdrv - return current drive as a character */ + + +char getdrv() +{ + union REGS regs ; + + regs.h.ah = CURDISK ; /* Function 0x19 */ + intdos (®s, ®s) ; + return(regs.h.al) ; +} + \ No newline at end of file diff --git a/SRC/LIBC/ITOUPPER.ASM b/SRC/LIBC/ITOUPPER.ASM new file mode 100644 index 0000000..481f44b --- /dev/null +++ b/SRC/LIBC/ITOUPPER.ASM @@ -0,0 +1,34 @@ +.xlist +include cmacros.inc +.list + +sBegin code +assumes cs,code + +; +; c = IToupper (c, routine); +; +; c is char to be converted +; routine is case map call in international table +; + +cProc IToupper, +parmW c +parmD routine +cBegin + mov ax,c + or ah,ah + jnz donothing + cmp al,'a' + jb noconv + cmp al,'z' + ja noconv + sub al,20H +noconv: + call routine +donothing: +cEnd + +sEnd + +end diff --git a/SRC/LIBC/JOIN.C b/SRC/LIBC/JOIN.C new file mode 100644 index 0000000..b741e63 --- /dev/null +++ b/SRC/LIBC/JOIN.C @@ -0,0 +1,253 @@ +/*** MSDOS JOIN Utility Vers 4.0 + * + * This utility allows the splicing of a physical drive to a pathname + * on another physical drive such that operations performed using the + * pathname as an arguement take place on the physical drive. + * + * MODIFICATION HISTORY + * + * Converted to CMERGE 03/26/85 by Greg Tibbetts + * + * M000 May 23/85 Barrys + * Disallow splicing similar drives. + * + * M001 May 24/85 Barrys + * The original IBM version of JOIN allowed the delete splice switch + * "/D" immediately after the drive specification. The argument parsing + * code has been modified to allow this combination. + * + * M002 June 5/85 Barrys + * Changed low version check for specific 320. + * + * M003 July 15/85 Barrys + * Checked for any possible switch characters in the other operands. + * + * M004 July 15/85 Barrys + * Moved check for physical drive before check for NET and SHARED tests. + * + * 33D0016 July 16/86 Rosemarie Gazzia + * Put SHARED test on an equal basis with physical drive check. + * Last fix (M004) erroneously allowed joining physical or local shared + * drives. This is because it only performed the SHARED test if the drive + * failed the physical test. + */ + +#include "types.h" +#include "versionc.h" +#include "sysvar.h" +#include "cds.h" +#include +#include + +extern char NoMem[], ParmNum[], BadParm[], DirNEmp[], NetErr[], BadVer[] ; +extern char *strchr(); /* M003 */ + +struct sysVarsType SysVars ; + + +/*** main - program entry point + * + * Purpose: + * To test arguements for validity and perform the splice + * + * int main(int c, char *v[]) + * + * Args: + * c - the number of command line arguements + * v - pointer to pointers to the command line arguements + * + * Links: + * ERRTST.C - Drive and path validity testing functions + * SYSVAR.C - Functions to get/set DOS System Variable structures + * CDS.C - Functions to get/set DOS CDS structures + * + * Returns: + * Appropriate return code with error message to stdout if + * necessary. + * + */ + +main(c, v) +int c ; +char *v[] ; +{ + char *strbscan() ; + + union REGS ir; + register union REGS *iregs = &ir ; /* Used for DOS calls */ + struct findType findbuf ; + char path [MAXPATHLEN],*p ; + struct CDSType CDS ; + int i ; + int dstdrv; /* dest. drive number M000 */ + int delflag = FALSE; /* delete splice flag M001 */ + int arglen; /* length of argument M001 */ + + /* check os version */ + iregs->h.ah = GETVERS ; /* Function 0x30 */ + intdos(iregs, iregs) ; + + if ( (iregs->h.al != expected_version_major) || (iregs->h.ah != expected_version_minor) ) + Fatal(BadVer); + + /* i = (iregs->h.al * 100) + iregs->h.ah; */ + /* if (i < LowVersion || i > HighVersion) */ + /* Fatal(BadVer) ; */ + + SHIFT(c,v) ; + + for (i=0 ; i < c ; i++) /* Convert to upper case */ + strupr(v[i]) ; + + GetVars(&SysVars) ; /* Access to DOS data structures */ + + if (c > 2) /* M001 */ + Fatal(ParmNum); /* M001 */ + + if (c == 0) + DoList() ; /* list splices */ + else { + /* Process drive letter */ + i = **v - 'A' ; + if ((*v)[1] != ':') { + if (c == 1) { + Fatal(ParmNum); + } + else { + Fatal(BadParm) ; + } + } + if (!fGetCDS(i, &CDS)) { + Fatal(BadParm) ; + } + + /* Accept arguments separate or mixed with drive spec M001 */ + arglen = strlen(*v); + if (arglen != 2) { + if ((*v)[2] != SwitChr) { + Fatal(ParmNum); + } + if (arglen != 4) { + if (c == 1) { + Fatal(BadParm); + } + else { + Fatal(ParmNum); + } + } + /* Advance arg pointer to possible switches */ + (*v)++; (*v)++; + } + else { + SHIFT(c,v) ; + } + /* Check for splice deletion switch */ + if (**v == SwitChr) { + if ((*v)[1] == 'D') + delflag = TRUE; + else { + Fatal(BadParm); + } + } + + if (delflag == TRUE) { /* Deassigning perhaps? */ + + if (!TESTFLAG(CDS.flags, CDSSPLICE)) { + Fatal(BadParm) ; /* If NOT spliced */ + } + + if (fPathErr(CDS.text)) { + Fatal(BadParm) ; /* If prefix of curdir */ + } + + CDS.text[0] = i + 'A' ; + CDS.text[1] = ':' ; + CDS.text[2] = '\\' ; + CDS.text[3] = 0 ; + CDS.cbEnd = 2 ; + + if (i >= SysVars.cDrv) + CDS.flags = FALSE ; + else + CDS.flags = CDSINUSE ; + GetVars(&SysVars) ; + SysVars.fSplice-- ; + PutVars(&SysVars) ; + fPutCDS(i, &CDS) ; + } + else { + /* Test if there are any other possible switches + * in the operand M003 + */ + if (strchr(v[0], SwitChr)) { + Fatal(ParmNum); + } + + if (TESTFLAG(CDS.flags,CDSSPLICE)) { + Fatal(BadParm) ; /* If now spliced */ + } + + rootpath(*v, path) ; /* Get root path */ + strupr(path) ; /* Upper case */ + + /* M004 Start */ + if (i == getdrv() || /* Can't mov curdrv */ + fPathErr(path) || /* or curdir prefix */ + *strbscan(path+3, "/\\") != 0 || + !fPhysical(i) || + fShared(i)) { /* 33D0016 RG */ + /* Determine if it was a NET error */ + if (fNet(i) || fShared(i)) { + Fatal(NetErr) ; + } + Fatal(BadParm) ; + } + + if (fNet(path[0] - 'A') || fNet(path[0] - 'A')) { + Fatal(NetErr) ; /* Same for dest */ + } + /* M004 End */ + + + /* Check src and dst drives are not same */ + dstdrv = *path - 'A'; /* M000 */ + if (i == dstdrv) /* M000 */ + Fatal (BadParm); /* M000 */ + if (mkdir(path) == -1) { /* If can't mkdir */ + /* or if no dir or */ + /* if node is file */ + if (ffirst(path, A_D, &findbuf) == -1 || + !TESTFLAG(findbuf.attr,A_D)) + Fatal(BadParm) ; + + p = path + strlen(path) ; + strcat(p, "\\*.*") ; + + if (ffirst(path, 0, &findbuf) != -1) + Fatal(DirNEmp) ; /* if dir */ + /* not empty */ + *p = 0 ; + } ; + + strcpy(CDS.text, path) ; + CDS.flags = CDSINUSE | CDSSPLICE ; + fPutCDS(i, &CDS) ; + GetVars(&SysVars) ; + SysVars.fSplice++ ; + PutVars(&SysVars) ; + } ; + } + exit(0) ; +} + +DoList() +{ + int i ; + struct CDSType CDS ; + + for (i=0 ; fGetCDS(i, &CDS) ; i++) { + if (TESTFLAG(CDS.flags,CDSSPLICE)) + printf("%c: => %s\n", i+'A', CDS.text) ; + } ; +} + \ No newline at end of file diff --git a/SRC/LIBC/KSTRING.C b/SRC/LIBC/KSTRING.C new file mode 100644 index 0000000..f686ea3 --- /dev/null +++ b/SRC/LIBC/KSTRING.C @@ -0,0 +1,118 @@ +#include "internat.h" +#include +#define NULL 0 +#define TRUE 0xffff +#define FALSE 0 +#define KANJI TRUE +char haveinttab = FALSE; +/* + * ECS Support - This module provides support for international >7FH and + * TWO-BYTE character sets. The toupper routine uses the DOS MAP_CASE call. + * In addition, STRING.C contains a default_tab containing a default lead + * byte table for two byte character sets. If single byte operation is + * desired, modify this table as follows: ="\000". If this utility + * is run on a DOS with Function 63H support, the default table will + * be replaced by the table in the DOS. The lbtbl_ptr is the far ptr to + * which ever table is in use. +*/ +long lbtbl_ptr; +char *default_tab="\201\237\340\374\000\000"; +char have_lbtbl = FALSE; + +struct InterTbl Currtab; + +int toupper(c) +int c; +{ + union REGS regs ; + + if(!haveinttab) { + regs.x.ax = 0x3800 ; + regs.x.dx = (unsigned) &Currtab ; + intdos (®s, ®s) ; /* INIT the table */ + + haveinttab = TRUE; + } + + return(IToupper(c,Currtab.casecall)); + +} + +char *strupr(string) +char *string; +{ + register char *p1; + + p1 = string; + while (*p1 != NULL) { + /* + * A note about the following " & 0xFF" stuff. This is + * to prevent the damn C compiler from converting bytes + * to words with the CBW instruction which is NOT correct + * for routines like toupper + */ +#ifdef KANJI + if(testkanj(*p1 & 0xFF)) + p1 += 2 ; + else + *p1++ = toupper(*p1 & 0xFF); +#else + *p1++ = toupper(*p1 & 0xFF); +#endif + } + return(string); +} + +char *strpbrk(string1,string2) +char *string1; +char *string2; +{ + register char *p1; + + while (*string1 != NULL) { + /* + * A note about the following " & 0xFF" stuff. This is + * to prevent the damn C compiler from converting bytes + * to words with the CBW instruction which is NOT correct + * for routines like toupper + */ +#ifdef KANJI + if(testkanj(*string1 & 0xFF)) + string1 += 2 ; + else { +#endif + p1 = string2; + while (*p1 != NULL) { + if(*p1++ == *string1) + return(string1); + } + string1++; +#ifdef KANJI + } +#endif + + } + return(NULL); /* no matches found */ +} + +#ifdef KANJI +testkanj(c) +unsigned char c; +{ + long *p1; + union REGS regs ; + int i; + + p1 = &lbtbl_ptr ; + if (!have_lbtbl ) { + lbtbl_ptr = default_tab ; /* Load offset in pointer */ + get_lbtbl( p1 ); + have_lbtbl=TRUE; + } + + if ( test_ecs( c, lbtbl_ptr )) + return(TRUE); + else + return(FALSE); +} +#endif diff --git a/SRC/LIBC/PRINTF.ASM b/SRC/LIBC/PRINTF.ASM new file mode 100644 index 0000000..4aabc21 --- /dev/null +++ b/SRC/LIBC/PRINTF.ASM @@ -0,0 +1,414 @@ +TITLE PRINTF ROUTINE FOR MS-DOS +; +; PRINTF(Control String, arg1, arg2,...,argn-1,argn) +; +; Characters are output to PFHandle according to the +; specifications contained in the Control String. +; +; The conversion characters are as follow: +; +; %c - output the next argument as a character +; %s - output the next argument as a string +; %x - output the next argument as a hexidecimal number +; using abcedf +; %X - output the next argument as a hexidecimal number +; using ABCDEF +; %d - output the next argument as a decimal number +; +; +; Other format specifiers that may precede the conversion character are: +; +; - (minus sign) - causes the field to be left-adjusted +; + (plus sign) - causes the field to be right-adjusted (default) +; n - digit specifing the minimum field width (default to 1) +; L - specifing a long integer +; +; On entry to PRINTF the stack contains the return address and a pointer +; to an argument list. +; +; ____________________ +; | Ret Addr | <= SP +; -------------------- +; | Ptr to Arg List | +; -------------------- +; +; And the argument list contains the following: +; +; String_ptr (a pointer to the control string) +; Arg 1 +; Arg 2 +; . +; . +; . +; Arg n-1 +; Arg n +; +; If the argument is a %s or %c the arg contains a pointer to the string +; or character. +; +; The arguments are used in one-to-one correspondence to % specifiers. + +.xlist +.xcref + INCLUDE dossym.inc +.cref +.list + +printf_CODE SEGMENT public byte +ASSUME CS:PRINTF_CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING + + PUBLIC PRINTF, PFHandle + PUBLIC PRINTF_LAST + +PFHandle DW 1 +PRINTF_LEFT DB 0 +PRINTF_LONG DB 0 +PRINTF_HEX DB 0 +TABLE_INDEX DB 0 +S_FLAG DB 0 +PRINTF_WIDTH DW 0 +PRINTF_BASE DW 0 +PAD_CHAR DB " " + +PRINTF_TABLE DB "0123456789ABCDEFabcdef" + +PRINTF_STACK STRUC +OLDES DW ? +OLDDS DW ? +OLDSI DW ? +OLDDI DW ? +OLDAX DW ? +OLDBX DW ? +OLDCX DW ? +OLDDX DW ? +OLDBP DW ? +OLDCS DW ? +OLDIP DW ? +STRING DW ? +PRINTF_STACK ENDS + +PRINTF_ARGS STRUC +CONSTR DW ? +ARG DW ? +PRINTF_ARGS ENDS + +RET_ADDR1 DW ? +RET_ADDR2 DW ? + +BUFSIZ = 20 +PRINTF_BUF DB BUFSIZ DUP (?) + db 0 ;This buffer is always nul terminated +BUFEND DW $-PRINTF_BUF + +PRINTF proc far + PUSH BP ;Save the callers' registers + PUSH DX + PUSH CX + PUSH BX + PUSH AX + PUSH DI + PUSH SI + PUSH ES + PUSH DS + MOV BP,SP + PUSH CS + POP ES ;ES points to Printf segment + MOV DI,OFFSET PRINTF_BUF ;DI points to the output buffer + MOV BP,[BP.STRING] ;BP points to the argument list + MOV SI,DS:[BP] ;SI points to the control string + XOR BX,BX ;BX is the index into the arg list + CALL Clear_flags ; initialize the world +GET_CHAR: + LODSB ;Get a character + CMP AL,"%" ;Is it a conversion specifier? + JZ CONV_CHAR ;Yes - find out which one + OR AL,AL ;Is it the end of the control string? + JZ PRINTF_DONE ;Yes - then we're done + CALL OUTCHR ;Otherwise store the character + JMP SHORT GET_CHAR ;And go get another + +PRINTF_DONE: + CALL FLUSH + POP DS + POP ES + POP SI + POP DI + POP AX + POP BX + POP CX + POP DX + POP BP + POP CS:[RET_ADDR1] ;Fix up the stack + POP CS:[RET_ADDR2] + POP AX + PUSH CS:[RET_ADDR2] + PUSH CS:[RET_ADDR1] + RET + +printf endp + +PRINTF_PERCENT: + CALL OUTCHR + JMP GET_CHAR + +CONV_CHAR: + ;Look for any format specifiers preceeding the conversion character + LODSB + CMP AL,"%" ;Just print the % + JZ PRINTF_PERCENT + CMP AL,"-" ;Right justify the field + JZ LEFT_ADJ + CMP AL,"+" ;Left justify the field + JZ NXT_CONV_CHAR + CMP AL,"L" ;Is it a long integer + JZ LONG_INT + CMP AL,"l" + JZ LONG_INT + CMP AL,"0" ;Is it a precision specification + JB LOOK_CONV_CHAR + CMP AL,"9" + JA LOOK_CONV_CHAR + CMP AL,"0" + JNZ NOT_PAD + CMP CS:[PRINTF_WIDTH],0 + JNZ NOT_PAD + MOV CS:BYTE PTR [PAD_CHAR],"0" +NOT_PAD: + PUSH AX ;Adjust decimal place on precision + MOV AX,10 + MUL CS:[PRINTF_WIDTH] + MOV CS:[PRINTF_WIDTH],AX + POP AX + XOR AH,AH + SUB AL,"0" + ADD CS:[PRINTF_WIDTH],AX ;And save the total + JMP SHORT NXT_CONV_CHAR + + ;Set the correct flags for the options in a conversion + +LEFT_ADJ: + INC CS:BYTE PTR[PRINTF_LEFT] + JMP SHORT NXT_CONV_CHAR + +LONG_INT: + INC CS:BYTE PTR[PRINTF_LONG] +NXT_CONV_CHAR: + JMP CONV_CHAR + + ;Look for a conversion character + +LOOK_CONV_CHAR: + CMP AL,"X" + JZ HEX_UP + + ;Make all other conversion characters upper case + + CMP AL,"a" + JB CAPS + CMP AL,"z" + JG CAPS + AND AL,0DFH +CAPS: + CMP AL,"X" + JZ HEX_LO + CMP AL,"D" + JZ DECIMAL + CMP AL,"C" + JZ C_PUT_CHAR + CMP AL,"S" + JZ S_PUT_STRG + + ;Didn't find any legal conversion character - IGNORE it + + call clear_flags + jmp get_char + +HEX_LO: + MOV CS:[TABLE_INDEX],6 ;Will print lower case hex digits +HEX_UP: + MOV CS:[PRINTF_BASE],16 ;Hex conversion + JMP CONV_TO_NUM + +DECIMAL: + MOV CS:[PRINTF_BASE],10 ;Decimal conversion + JMP CONV_TO_NUM + +S_PUT_STRG: + INC CS:[S_FLAG] ;It's a string specifier +C_PUT_CHAR: + PUSH SI ;Save pointer to control string + MOV SI,BX + ADD BX,2 + MOV SI,ds:[BP+SI.ARG] ;Point to the % string or character + CMP BYTE PTR CS:[S_FLAG],0 + JNZ S_PUT_1 + LODSB + cmp al,0 + jz short c_s_end + CALL OUTCHR ;Put it into our buffer + JMP SHORT C_S_END + +S_PUT_1: + mov cx,cs:[printf_width] + or cx,cx + jz s_put_2 + cmp cs:byte ptr[printf_left],0 + jnz s_put_2 + push si + call Pad_string + pop si +s_put_2: + push si +s_put_3: + LODSB ;Put them all in our buffer + CMP AL,0 + jz s_put_4 + CALL OUTCHR + jmp short S_PUT_3 +s_put_4: + pop si + cmp byte ptr[printf_left],0 + jz c_s_end + mov cx,cs:[printf_width] + or cx,cx + jz c_s_end + call Pad_string +C_S_END: + call clear_flags + POP SI ;Restore control string pointer + JMP GET_CHAR ;Go get another character + +pad_string: + xor dx,dx +count_loop: + lodsb + or al,al + jz count_done + inc dx + jmp short count_loop +count_done: + sub cx,dx + jbe count_ret + call pad +count_ret: + ret + +CONV_TO_NUM: + + PUSH SI ;Save pointer to control string + MOV SI,BX ;Get index into argument list + ADD BX,2 ;Increment the index + MOV AX,ds:[BP+SI.ARG] ;Lo word of number in SI + CMP BYTE PTR CS:[PRINTF_LONG],0 ;Is this is a short or long integer? + JZ NOT_LONG_INT + MOV SI,BX ;Copy index + ADD BX,2 ;Increment the index + MOV DX,ds:[BP+SI.ARG] ;Hi word of number in BP + JMP SHORT DO_CONV +NOT_LONG_INT: + XOR DX,DX ;Hi word is zero +DO_CONV: + PUSH BX ;Save index into arguemnt list + MOV si,CS:[PRINTF_BASE] + MOV cx,CS:[PRINTF_WIDTH] + CALL PNUM + CALL PAD +CONV_DONE: + call clear_flags + POP BX + POP SI + jmp get_char + +PNUM: + DEC CX + PUSH AX + MOV AX,DX + XOR DX,DX + DIV SI + MOV BX,AX + POP AX + DIV SI + XCHG BX,DX + PUSH AX + OR AX,DX + POP AX + JZ DO_PAD + PUSH BX + CALL PNUM + POP BX + JMP SHORT REM +DO_PAD: + CMP CS:BYTE PTR[PRINTF_LEFT],0 + JNZ REM + CALL PAD +REM: + MOV AX,BX + CMP AL,10 + JB NOT_HEX + CMP CS:BYTE PTR [PRINTF_HEX],0 + JNZ NOT_HEX + ADD AL,CS:BYTE PTR [TABLE_INDEX] +NOT_HEX: + MOV BX,OFFSET PRINTF_TABLE + PUSH DS + PUSH CS + POP DS + XLAT 0 + POP DS + push cx + CALL OUTCHR + pop cx + RET + +PAD: + OR CX,CX + JLE PAD_DONE + MOV AL,CS:BYTE PTR [PAD_CHAR] +PAD_LOOP: + push cx + CALL OUTCHR + pop cx + LOOP PAD_LOOP +PAD_DONE: + RET + +OUTCHR: + STOSB + CMP DI,offset bufend-1 ;Don't count the nul + RETNZ + MOV CX,BUFSIZ +WRITE_CHARS: + push bx + MOV BX,PFHandle + push ds + PUSH CS + POP DS + MOV DX,OFFSET PRINTF_BUF + MOV AH,WRITE + INT 21H + pop ds + pop bx + MOV DI,OFFSET PRINTF_BUF + RET + +FLUSH: + CMP DI,OFFSET PRINTF_BUF + RETZ + SUB DI,OFFSET PRINTF_BUF + MOV CX,DI + call write_chars + ret + +CLEAR_FLAGS: + XOR ax,ax + MOV BYTE PTR CS:[PRINTF_LEFT],al ;Reset justifing flag + MOV BYTE PTR CS:[PRINTF_LONG],al ;Reset long flag + MOV BYTE PTR CS:[TABLE_INDEX],al ;Reset hex table index + MOV CS:[PRINTF_WIDTH],ax ;Reinitialize width to 0 + MOV BYTE PTR CS:[PAD_CHAR]," " ;Reset padding character + MOV BYTE PTR CS:[S_FLAG],al ;Clear the string flag + ret + +PRINTF_LAST LABEL WORD +printf_CODE ENDS + END diff --git a/SRC/LIBC/PRINTF.OBJ b/SRC/LIBC/PRINTF.OBJ new file mode 100644 index 0000000..0d9d016 Binary files /dev/null and b/SRC/LIBC/PRINTF.OBJ differ diff --git a/SRC/LIBC/STRING.C b/SRC/LIBC/STRING.C new file mode 100644 index 0000000..3a2d74a --- /dev/null +++ b/SRC/LIBC/STRING.C @@ -0,0 +1,94 @@ +#include "types.h" +#include "internat.h" +#include + +/* #define KANJI TRUE */ + +char haveinttab = FALSE; + +struct InterTbl Currtab; + +int toupper(c) +int c; +{ + union REGS regs ; + + if(!haveinttab) { + regs.x.ax = 0x3800 ; + regs.x.dx = (unsigned) &Currtab ; + intdos (®s, ®s) ; /* INIT the table */ + + haveinttab = TRUE; + } + + return(IToupper(c,Currtab.casecall)); + +} + +char *strupr(string) +char *string; +{ + register char *p1; + + p1 = string; + while (*p1 != NULL) { + /* + * A note about the following " & 0xFF" stuff. This is + * to prevent the damn C compiler from converting bytes + * to words with the CBW instruction which is NOT correct + * for routines like toupper + */ +#ifdef KANJI + if(testkanj(*p1 & 0xFF)) + p1 += 2 ; + else + *p1++ = toupper(*p1 & 0xFF); +#else + *p1++ = toupper(*p1 & 0xFF); +#endif + } + return(string); +} + +char *strpbrk(string1,string2) +char *string1; +char *string2; +{ + register char *p1; + + while (*string1 != NULL) { + /* + * A note about the following " & 0xFF" stuff. This is + * to prevent the damn C compiler from converting bytes + * to words with the CBW instruction which is NOT correct + * for routines like toupper + */ +#ifdef KANJI + if(testkanj(*string1 & 0xFF)) + string1 += 2 ; + else { +#endif + p1 = string2; + while (*p1 != NULL) { + if(*p1++ == *string1) + return(string1); + } + string1++; +#ifdef KANJI + } +#endif + + } + return(NULL); /* no matches found */ +} + +#ifdef KANJI +testkanj(c) +unsigned char c; +{ + if((c >= 0x81 && c <= 0x9F) || (c >= 0xE0 && c <= 0xFC)) + return(TRUE); + else + return(FALSE); +} +#endif diff --git a/SRC/LIBC/SYSVAR.C b/SRC/LIBC/SYSVAR.C new file mode 100644 index 0000000..bc649ed --- /dev/null +++ b/SRC/LIBC/SYSVAR.C @@ -0,0 +1,48 @@ +/* return the system variables in sysVars */ + +#include "types.h" +#include "sysvar.h" +#include + +GetVars(pSVars) +struct sysVarsType *pSVars ; +{ + struct sysVarsType far *vptr ; + int i ; + + union REGS ir ; + register union REGS *iregs = &ir ; /* Used for DOS calls */ + struct SREGS syssegs ; + + iregs->h.ah = GETVARS ; /* Function 0x52 */ + intdosx(iregs, iregs, &syssegs) ; + + *(long *)(&vptr) = (((long)syssegs.es) << 16)+(iregs->x.bx & 0xffffL) ; + + for (i=0 ; i <= sizeof(*pSVars) ; i++) + *((char *)pSVars+i) = *((char far *)vptr+i) ; + +} + + + + +PutVars(pSVars) +struct sysVarsType *pSVars ; +{ + struct sysVarsType far *vptr ; + int i ; + + union REGS ir ; + register union REGS *iregs = &ir ; /* Used for DOS calls */ + struct SREGS syssegs ; + + iregs->h.ah = GETVARS ; /* Function 0x52 */ + intdosx(iregs, iregs, &syssegs) ; + + *(long *)(&vptr) = (((long)syssegs.es) << 16)+(iregs->x.bx & 0xffffL) ; + + for (i=0 ; i <= sizeof(*pSVars) ; i++) + *((char far *)vptr+i) = *((char *)pSVars+i) ; + +} diff --git a/SRC/MAKEFILE b/SRC/MAKEFILE new file mode 100644 index 0000000..993334d --- /dev/null +++ b/SRC/MAKEFILE @@ -0,0 +1,13 @@ +make=msmake /I makefile + +all: + cd boot + $(make) + cd ..\dos + $(make) + cd ..\bios + $(make) + cd ..\cmd + $(make) + + \ No newline at end of file diff --git a/SRC/TOOLS/CONVERT.EXE b/SRC/TOOLS/CONVERT.EXE new file mode 100644 index 0000000..0511410 Binary files /dev/null and b/SRC/TOOLS/CONVERT.EXE differ diff --git a/SRC/TOOLS/DBOF.EXE b/SRC/TOOLS/DBOF.EXE new file mode 100644 index 0000000..1d46e71 Binary files /dev/null and b/SRC/TOOLS/DBOF.EXE differ diff --git a/SRC/TOOLS/EXE2BIN.EXE b/SRC/TOOLS/EXE2BIN.EXE new file mode 100644 index 0000000..5535f7e Binary files /dev/null and b/SRC/TOOLS/EXE2BIN.EXE differ diff --git a/SRC/TOOLS/EXEFIX.EXE b/SRC/TOOLS/EXEFIX.EXE new file mode 100644 index 0000000..30728e6 Binary files /dev/null and b/SRC/TOOLS/EXEFIX.EXE differ diff --git a/SRC/TOOLS/LINK.EXE b/SRC/TOOLS/LINK.EXE new file mode 100644 index 0000000..8ba4573 Binary files /dev/null and b/SRC/TOOLS/LINK.EXE differ diff --git a/SRC/TOOLS/MASM.EXE b/SRC/TOOLS/MASM.EXE new file mode 100644 index 0000000..c6cd283 Binary files /dev/null and b/SRC/TOOLS/MASM.EXE differ diff --git a/SRC/TOOLS/MASM401.EXE b/SRC/TOOLS/MASM401.EXE new file mode 100644 index 0000000..9515fce Binary files /dev/null and b/SRC/TOOLS/MASM401.EXE differ diff --git a/SRC/TOOLS/MSMAKE.EXE b/SRC/TOOLS/MSMAKE.EXE new file mode 100644 index 0000000..20d4949 Binary files /dev/null and b/SRC/TOOLS/MSMAKE.EXE differ diff --git a/UPDSRC/BIOS/MSBIO2.ASM b/UPDSRC/BIOS/MSBIO2.ASM new file mode 100644 index 0000000..03a80f2 --- /dev/null +++ b/UPDSRC/BIOS/MSBIO2.ASM @@ -0,0 +1,649 @@ + TITLE MSBIO2 - DOS 3.3 + +;------------------------------------------------------------------------------- +; : +; Microsoft Bio : +; : +; The file msbio.asm is the main file in the Mircosoft bio. This file : +; includes the other main files in the bio. Most of the routines are : +; in these include files. The main files included are: : +; : +; File Contains : +; : +; msdisk.inc Disk device driver routines : +; ms96tpi.inc Routines for 96tpi drives : +; msaux.inc Device driver for the rs-232 serial ports : +; msclock.inc Device driver for "clock$" device : +; mscon.inc Device driver for "con" : +; mslpt.inc Device driver for the printers : +; : +; Each of these files contain a header section documenting the code : +; in that file. : +; Msbio also includes several files for equ's, structure definition, : +; macro definitions, etc. These are: : +; : +; msbiomes.inc msmacro.inc devsym.inc : +; dskprm.inc error.inc : +; : +; Each of these file contains explanitory notes. : +; : +; The actual code in msbio can be broken down into several piece: : +; : +; macro definitions Several marco are defined in msbio. They : +; are a few odds and end that did not fit : +; anywhere else. : +; : +; Command Jump Table List of entry points in the device drivers. : +; See notation below for full explination. : +; : +; Interrupt and Strategy : +; Entry points Calls on the device driver first come to here. : +; There is common code with pushes registers and : +; the like before jumping to routines in the : +; driver files. The common exit points are also : +; in this file. : +; : +; Miscellaneous Code There are several routines and data structure : +; declarations. See below for details. : +; : +;------------------------------------------------------------------------------- + + + +; +; If the variable TEST is non-zero then code for debugging is included. +; The extra code will make the binary file nuch larger. +; The symbol is also defined in msequ.inc. Both must be changed to +; turn debugging on or off. +; +; The level of the debugging is controled by the variable fTestBits in +; this file. See the comment preceeding the variable for more information. +; The actual routines which print the messages are in msmacro.inc +; See the header comment in this file for more information. +; + + +; +; Revision History +; +; REV 2.1 5/1/83 ARR added timer int handler and changed order of AUX +; PRN init for HAL0 +; +; REV 2.15 7/13/83 ARR Because of IBM design issues, and that BASCOM +; is ill behaved with respect to the 1CH timer interrupt, +; the timer handler has to be backed out! The intended +; code is commented out and has an ARR 2.15 annotation. +; This means the BIOS will go back to the multiple roll +; over bug. +; +; REV 2.20 8/5/83 ARR IBM makes hardware change. Now wants to use half +; height drives for HAL0, and back fit for PC/PC XT. Problem +; with head settle time. Previous drives got by on a 0 +; settle time, 1/2 hight drives need 15 head settle when +; doing WRITEs (0 ok on READ) if the head is being stepped. +; This requires a last track value to be kept so that BIOS +; knows when head is being moved. To help out +; programs that issue INT 13H directly, the head settle will +; normally be set to 15. It will be changed to 0 on READs, +; or on WRITEs which do not require head step. +; +; REV 2.21 8/11/83 MZ IBM wants write with verify to use head settle 0. +; Use same trick as above. +; +; REV 2.25 6/20/83 mjb001 added support for 96tpi and salmon +; +; REV 2.30 6/27/83 mjb002 added real-time clock +; +; REV 2.40 7/8/83 mjb003 added volume-id checking and int 2f macro +; definitions push* and pop* +; +; REV 2.41 7/12/83 ARR more 2.X enhancements. Open/Close media change +; +; REV 2.42 11/3/83 ARR more 2.X enhancements. Disk OPEN/CLOSE, FORMAT +; code and other misc hooked out to shrink BIOS. Code for +; Disk OPEN/CLOSE, FORMAT included only with 96tpi disks. +; +; Rev 2.43 12/6/83 MZ Examine boot sectors on hard disks for 16-bit fat +; check. Examine large fat bit in BPB for walk of media for +; DOS +; +; Rev 2.44 12/9/83 ARR Change to error reporting on INT 17H +; +; Rev 2.45 12/22/83 MZ Make head settle change only when disk parm is 0. + +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +; IBM ADDRESSES FOR I/O +; +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +;Below was moved from sysinit1 +ROMSEGMENT EQU 0F000H +MODELBYTE EQU DS:BYTE PTR [0FFFEH] +MODELPCJR EQU 0FDH + + test=0 +;;Rev 3.30 modification ---------------------------- + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + INCLUDE MSEQU.INC + INCLUDE DEVSYM.INC + INCLUDE PUSHPOP.INC + INCLUDE MSMACRO.INC + + ASSUME DS:NOTHING,ES:NOTHING + + EXTRN DSK$IN:NEAR + EXTRN SETPTRSAV:NEAR + EXTRN OUTCHR:NEAR + EXTRN SETDRIVE:NEAR + EXTRN FLUSH:NEAR + EXTRN HARDERR:NEAR + EXTRN HARDERR2:NEAR + EXTRN MAPERROR:NEAR + EXTRN GETBP:NEAR + EXTRN CHECKSINGLE:NEAR + EXTRN CHECK_TIME_OF_ACCESS:NEAR + EXTRN EXIT:NEAR + EXTRN HAS1:NEAR + EXTRN HAS1_res:NEAR + EXTRN READ_SECTOR:NEAR + EXTRN INT_2F_13:FAR + + EXTRN OLD13:DWORD + +;DATA + EXTRN PTRSAV:DWORD + EXTRN START_BDS:WORD + EXTRN FDRIVE1:WORD + EXTRN FDRIVE2:WORD + EXTRN FDRIVE3:WORD + EXTRN FDRIVE4:WORD + EXTRN FLAGBITS:WORD + EXTRN TIM_DRV:BYTE + EXTRN MEDBYT:BYTE + EXTRN DRVMAX:BYTE + + PATHSTART 005,DISK + EVENB + PUBLIC ORIG19 +ORIG19 DD ? + + PUBLIC INT19SEM +INT19SEM DB 0 ; INDICATE THAT ALL INT 19 + ; INITIALIZATION IS COMPLETE + + IRP AA,<02,08,09,0A,0B,0C,0D,0E,70,72,73,74,76,77> + public Int19OLD&AA +Int19OLD&AA dd -1 ;Orignal hw int. vec for INT 19h. + ENDM + + EVENB + PUBLIC DSKDRVS +DSKDRVS DW FDRIVE1 + DW FDRIVE2 + DW FDRIVE3 + DW FDRIVE4 + PUBLIC HDSKTAB +HDSKTAB DW HDRIVE + DW DRIVEX +;* Next area is reseved for mini disk BPB pointers *** 4/7/86 +;* Don't change this pos. Should be add. from DskDrvs *** 4/7/86 +MINI_DISK_BPB_PTRS DB 40 dup (?) ;4/7/86 - mem res for Mini disk. + + EVENB + PUBLIC INT_2F_NEXT +INT_2F_NEXT DD ? + +RET_ADDR DD ? + + PATHEND 005,DISK +;;End of modification ---------------------------- + +; INT19 +; +; We "hook" the INT_REBOOT vector, because contrary to IBM documentation, +; it does NOT "bootstrap" the machine. It leaves memory almost untouched. +; Since the BIOS_INIT code assumes that certain Interrupt Vectors point to +; the ROM_BIOS we must "unhook" them before issuing the actual INT_REBOOT. +; Currently the following vectors need to be unhooked: +; 02,08,09,0A,0B,0C,0D,0E,70,72,73,74,75,76,77 +; + +Public Int19 +Int19 proc FAR + xor AX,AX ; get data segment to + mov DS,AX ; point to the vector table + assume ds:nothing + assume es:nothing + les DI,Old13 ; get ES to point to this segment + mov DS:[13h*4],DI ; restore old int13 value + mov DS:[13h*4+2],ES + + cmp Byte ptr Int19Sem, 0 + jnz int19vecs + jmp doint19 + +;;Dos 3.30 Will not support the PC-Jr +;;Rev 3.30 modification ---------------------------- +; ON THE PCJR, DON'T REPLACE ANY VECTORS +; MODEL BYTE DEFINITIONS FROM MSSTACK.ASM +; MOV AX,ROMSEGMENT +; MOV DS,AX +; MOV AL,MODELPCJR +; +; CMP AL,MODELBYTE +; JNE INT19VECS +; JMP DOINT19 + + +;Stacks code has changed these hardware interrupt vectors +;STKINIT in SYSINIT1 will initialzie Int19hOLDxx values. +int19vecs: + +; +; we now need to unhook all the vector replace to prevent stack overflow +; + +;;Rev 3.30 modification ---------------------------- + XOR AX,AX + MOV DS,AX + + IRP AA,<02,08,09,0A,0B,0C,0D,0E,70,72,73,74,76,77> + + LES DI,Int19OLD&AA + + mov ax,es ; Put segment where we can compare it + cmp ax,-1 ; OPT 0ffffh is not likely + je skip_int&AA ; OPT could get away without checking + cmp di,-1 ; OPT offset here. + je skip_int&AA + + MOV DS:[AA&H*4],DI + MOV DS:[AA&H*4+2],ES +skip_int&AA: + ENDM +;;End of modification ---------------------------- + +doint19: + LES DI,Orig19 + MOV DS:[19h*4],DI + MOV DS:[19h*4+2],ES + + INT 19h +INT19 ENDP +ASSUME DS:CODE + +;***************************************************************************** +PUBLIC DSK$INIT +DSK$INIT PROC NEAR + PUSH CS + POP DS + MOV AH,BYTE PTR DRVMAX + MOV DI,OFFSET DskDrvs + JMP SetPTRSAV +DSK$INIT ENDP + + +; +; Int 2f handler for external block drivers to communicate with the internal +; block driver in msdisk. The multiplex number chosen is 8. The handler +; sets up the pointer to the request packet in [PTRSAV] and then jumps to +; DSK$IN, the entry point for all disk requests. +; On exit from this driver (at EXIT), we will return to the external driver +; that issued this Int 2F, and can then remove the flags from the stack. +; This scheme allows us to have a small external device driver, and makes +; the maintainance of the various drivers (DRIVER and msBIO) much easier, +; since we only need to make changes in one place (most of the time). +; +; AL contains the Int2F function: +; 0 - Check for installed handler - RESERVED +; 1 - Install the BDS into the linked list +; 2 - DOS request +; + +MYNUM EQU 8 + +Public Int2F_Disk +Int2F_Disk PROC FAR + cmp ah,MYNUM + je Mine + jmp cs:[Int_2F_Next] ; chain to next Int 2F handler +Mine: + cmp al,0F8H ; IRET on reserved functions + jb Do_Func + IRET +Do_Func: + or al,al ; A GET INSTALLED STATE request? + jne Disp_Func + mov al,0FFH + IRET +Disp_Func: + Message fTestInit,<"Int2F_disk",cr,lf> + cmp al,1 ; Request for installing BDS? + jne Do_DOS_Req + call Install_BDS + IRET + +Do_DOS_Req: +; Set up pointer to request packet + MOV WORD PTR CS:[PTRSAV],BX + MOV WORD PTR CS:[PTRSAV+2],ES + jmp DSK$IN + +Int2F_Disk ENDP + +; +; Install_BDS installs a BDS a location DS:DI into the current linked list of +; BDS maintained by this device driver. It places the BDS at the END of the +; list. +Public Install_BDS +INSTALL_BDS PROC NEAR + message ftestinit,<"Install BDS",cr,lf> +; ds:di point to BDS to be installed + les si,dword ptr cs:[Start_BDS] ; Start at beginning of list + push es ; Save pointer to current BDS + push si +; es:si now point to BDS in linked list +Loop_Next_BDS: + cmp si,-1 ; got to end of linked list? + jz Install_Ret +; If we have several logical drives using the same physical drive, we must +; set the I_Am_Mult flag in each of the appropriate BDSs. + mov al,byte ptr ds:[di].DriveNum + cmp byte ptr es:[si].DriveNum,al + jnz Next_BDS + message ftestinit,<"Logical Drives",cr,lf> + xor bx,bx + mov bl,fI_Am_Mult + or word ptr ds:[di].flags,bx ; set flags in both BDSs concerned + or word ptr es:[si].flags,bx + mov bl,fI_Own_Physical + xor bx,-1 + and word ptr ds:[di].flags,bx ; reset that flag for 'new' BDS +; We must also set the fChangeline bit correctly. + mov bx,word ptr es:[si].flags ; determine if changeline available + and bl,fChangeline + xor bh,bh + or word ptr ds:[di].flags,bx + +Next_BDS: +; Before moving to next BDS, preserve pointer to current one. This is needed at +; the end when the new BDS is linked into the list. + pop bx ; discard previous pointer to BDS + pop bx + push es + push si + mov bx,word ptr es:[si].link + 2 + mov si,word ptr es:[si].link + mov es,bx + jmp short Loop_Next_BDS + +Install_Ret: + pop si ; Retrieve pointer to last BDS + pop es ; in linked list. + mov ax,ds + mov word ptr es:[si].link+2,ax ; install BDS + mov word ptr es:[si].link,di + mov word ptr ds:[di].link,-1 ; set NEXT pointer to NULL + RET +INSTALL_BDS ENDP + +; +; RE_INIT installs the Int 2F vector that will handle communication between +; external block drivers and the internal driver. It also installs the +; Reset_Int_13 interface. It is called by SYSYINIT +; +PUBLIC RE_INIT +RE_INIT PROC FAR + Message ftestinit,<"REINIT",CR,LF> + PUSH AX + PUSH DS + PUSH DI + XOR DI,DI + MOV DS,DI + MOV DI,2FH*4 ; point it to Int 2F Vector + MOV AX,WORD PTR DS:[DI] + MOV WORD PTR CS:[INT_2F_NEXT],AX + MOV AX,WORD PTR DS:[DI+2] ; preserve old Int 2F vector + MOV WORD PTR CS:[INT_2F_NEXT+2],AX + +; INSTALL the Reset_Int_13 +; interface + + + CLI + MOV Word Ptr DS:[DI],Offset Int_2f_13 ; install new vectors + MOV Word Ptr DS:[DI+2],CS + STI + POP DI + POP DS + POP AX + RET + +RE_INIT ENDP + +;------------------------------------------------- +; +; Ask to swap the disk in drive A: +; Using a different drive in a one drive system so +; request the user to change disks +; +Public SWPDSK +SWPDSK PROC NEAR + mov al,byte ptr ds:[di].drivelet ; get the drive letter + add al,"A" + mov cs:DRVLET,AL + push ds ; preserve segment register + push cs + pop ds + mov SI,OFFSET SNGMSG ; ds:si -> message + push BX + call WRMSG ;Print disk change message + call FLUSH + ; wait for a keyboard character + xor AH, AH ; set command to read character + int 16h ; call rom-bios + POP BX + pop ds ; restore segment register +WRMRET: + ret +SWPDSK ENDP + +;---------------------------------------------- +; +; WrMsg writes out message pointed to by [SI] +; +Public WrMsg +WRMSG PROC NEAR + lodsb ; get the next character of the message + or AL,AL ; see fi end of message + jz WRMRET + pushf + push CS + call OUTCHR + jmp SHORT WRMSG +WRMSG ENDP + + INCLUDE BIOMES.INC + +; +; End of support for multiple floppies with no logical drives +; This is not 'special' any more because we now have the capability of +; defining logical drives in CONFIG.SYS. We therefore keep the code for +; swapping resident ALL the time. +; + +;;Rev 3.30 modification ---------------------------- +;Variables for Dynamic Relocatable modules +;These should be stay resident. + + public INT6C_RET_ADDR +INT6C_RET_ADDR DD ? ;ret add from INT 6C for P12 mach + + PATHSTART 001,CLK +; +; DATA STRUCTURES FOR REAL-TIME DATE AND TIME +; + public BIN_DATE_TIME + public MONTH_TABLE + public DAYCNT2 + public FEB29 +BIN_DATE_TIME: + DB 0 ; CENTURY (19 OR 20) OR HOURS (0-23) + DB 0 ; YEAR IN CENTURY (0-99) OR MINUTES (0-59) + DB 0 ; MONTH IN YEAR (1-12) OR SECONDS (0-59) + DB 0 ; DAY IN MONTH (1-31) +MONTH_TABLE: + DW 0 ;MJB002 JANUARY + DW 31 ;MJB002 FEBRUARY + DW 59 ;MJB002 + DW 90 ;MJB002 + DW 120 ;MJB002 + DW 151 ;MJB002 + DW 181 ;MJB002 + DW 212 ;MJB002 + DW 243 ;MJB002 + DW 273 ;MJB002 + DW 304 ;MJB002 + DW 334 ;MJB002 +DAYCNT2 DW 0000 ;MJB002 TEMP FOR CNT OF DAYS SINCE 1-1-80 +FEB29 DB 0 ;MJB002 FEBRUARY 29 IN A LEAP YEAR FLAG + PATHEND 001,CLK + +;;End of modification modification ---------------------------- + +Public EndFloppy +EndFloppy Label Byte +; +; End of code for virtual floppy drives +; +Public EndSwap +EndSwap Label Byte + + PATHSTART 004,BIO + +Public HNUM +HNUM DB 0 ; number of hardfile (hard drives) + +Public HardDrv +HARDDRV DB 80H ;Physical drive number of first hardfile + + +; +; "HDRIVE" is a hard disk with 512 byte sectors +; + + EVENB +Public BDSH +BDSH DW -1 ; Link to next structure + DW Code + DB 80h ; physical drive number + DB "C" ; Logical Drive Letter +Public HDRIVE +HDRIVE: + DW 512 + DB 1 ; Sectors/allocation unit + DW 1 ; Reserved sectors for DOS + DB 2 ; No. of allocation tables + DW 16 ; Number of directory entries + DW 0000 ; Number of sectors (at 512 bytes each) + DB 11111000B ; Media descriptor + DW 1 ; Number of FAT sectors + DW 00 ; Sector limit + DW 00 ; Head limit + DW 00 ; Hidden sector count + DB 0 ; TRUE => bigfat +OPCNTH DW 0 ; Open Ref. Count +VOLIDH DB "NO NAME ",0 ; Volume ID for this disk + DB 3 ; Form Factor +FLAGSH DW 0020H ; Various Flags + dw 40 ; number of cylinders +RecBPBH db 31 dup (?) ; Recommended BPB for drive +TRACKH DB -1 ; Last track accessed on this drive +TIM_LOH DW -1 ; Keep these two contiguous (?) +TIM_HIH DW -1 +; +; End of single hard disk section +; + + +Public EndOneHard +EndOneHard Label Byte + + + + +; +;"DRIVEX" is an extra type of drive usually reserved for an +; additional hard file +; + + EVENB +Public BDSX +BDSX DW -1 ; Link to next structure + DW Code + DB 81h ; physical drive number + DB "D" ; Logical Drive Letter +Public DRIVEX +DRIVEX: + DW 512 + DB 00 ; Sectors/allocation unit + DW 1 ; Reserved sectors for DOS + DB 2 ; No. of allocation tables + DW 0000 ; Number of directory entries + DW 0000 ; Number of sectors (at 512 bytes each) + DB 11111000B ; Media descriptor + DW 0000 ; Number of FAT sectors + DW 00 ; Sector limit + DW 00 ; Head limit + DW 00 ; Hidden sector count + DB 0 ; TRUE => bigfat +OPCNTD DW 0 ; Open Ref. Count +VOLIDD DB "NO NAME ",0 ; Volume ID for this disk + DB 3 ; Form Factor +FLAGSD DW 0020H ; Various Flags + dw 40 ; number of cylinders +RecBPBD db 31 dup (?) ; Recommended BPB for drive +TRACKD DB -1 ; Last track accessed on this drive +TIM_LOD DW -1 ; Keep these two contiguous +TIM_HID DW -1 + +; +; End of section for two hard disks +Public EndTwoHard +EndTwoHard Label Byte + + PATHEND 004,BIO + + +Public TwoHard +TWOHARD LABEL BYTE + +PAGE +include ms96tpi.inc + +;;Rev 3.30 modification ---------------------------- +;Memory allocation for BDSM table. + PUBLIC BDSMs +BDSMs BDSM_type Max_mini_dsk_num dup (<>) ;currently max. 23 + +;** End_of_BDSM defined in MSINIT.ASM will be used to set the appropriate +;** ending address of BDSM table. +;;End of modification ---------------------------- + +; +;;3.3 BUG FIX -SP ------------------------------ +;Paragraph buffer between the BDSMs and MSHARD +; +;The relocation code for MSHARD needs this. this cannot be used for +;anything. nothing can come before this or after this.....IMPORTANT!!!! +;don't get too smart and using this buffer for anything!!!!!! +; + db 16 dup(0) +; +;end of bug fix buffer +;; +;;3.3 BUG FIX -SP------------------------------ + +CODE ENDS + END diff --git a/UPDSRC/BIOS/MSDISK.ASM b/UPDSRC/BIOS/MSDISK.ASM new file mode 100644 index 0000000..0afeb4d --- /dev/null +++ b/UPDSRC/BIOS/MSDISK.ASM @@ -0,0 +1,2410 @@ + TITLE MSDISK - DOS 3.3 +;------------------------------------------------------------------------ +; : +; DISK INTERFACE ROUTINES : +; : +; : +; This file contains the Disk Device Driver. : +; : +; The routines in this files are: : +; : +; routine function : +; ------- -------- : +; : +; MEDIA$CHK Determine if media in drive has changed : +; : +; GET$BPB Build a valid BPB for drive : +; : +; DSK$REM Determine if disk has removable media : +; : +; DSK$WRTV Disk write with verify : +; : +; DSK$WRT Disk write : +; : +; DSK$READ Read disk : +; : +; : +; These routines are not called directly. Call are made via : +; the strategy and interrupt entry point (see Device Header). : +; : +; Data structures: : +; There are two main types of data structures associated with : +; the disk drives. The first is the BDS. BDS is the Bios Data : +; structure. There is one BDS for each logical drive in the system. : +; All the BDS's are linked together in a list with the pointer to the : +; first BDS being found in Start_BDS. The BDS hold various values : +; important to the disk drive. For example there is a field for last : +; time accesses. As actions take place in the system the BDS are : +; update to reflect the actions. For example if there is a read to : +; a disk the last access field for the BDS for that drive is updated : +; to the current time. : +; The second data structure associated with disk drives is the : +; BPB. A BPB is a Bios Parameter Block. The BPB contains information : +; about the media inside a disk drive. Some on the fields in the BPB : +; are Sectors per track, number of FATs, and number of tracks. This : +; information is used to tell where sectors are on the disk. For : +; example, if we need to read logical sector 52: : +; : +; Diskette Track Sector Side : +; single density : +; eight sectors per track 6 5 0 : +; : +; double density : +; nine sectors per track 2 7 1 : +; : +; The BPB for the media in the drive is stored in the BDS for the : +; drive. If the user changes the floppy in the drive a call is : +; made to GET$BPB to build a new BPB in the BDS. See this routine : +; for the algorithm. : +; : +; : +;------------------------------------------------------------------------ +;;Rev 3.30 Modification +;for testing, set test to 1. So as MSBIO1.ASM. + test=0 + EXTRN NUMERR:ABS ;MSDATA + + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + INCLUDE MSEQU.INC + INCLUDE PUSHPOP.INC + INCLUDE MSMACRO.INC + INCLUDE DEVSYM.INC + INCLUDE DSKPRM.INC + + EXTRN INT2F_DISK:FAR ;MSBIO2 + EXTRN MEDIACHECK:NEAR ;96TPI + EXTRN HASCHANGE:NEAR ;96TPI + EXTRN MEDIA_SET_VID:NEAR ;96TPI + EXTRN HIDENSITY:NEAR ;96TPI + EXTRN CHECKLATCHIO:NEAR ;96TPI + EXTRN CHECKIO:NEAR ;96TPI + EXTRN SET_CHANGED_DL:NEAR ;96TPI + EXTRN SET_VOLUME_ID:NEAR ;MSVOLID + EXTRN SWPDSK:NEAR ;MSBIO2 + EXTRN CMDERR:NEAR ;MSBIO1 + EXTRN STRATEGY:NEAR ;MSBIO1 + EXTRN ERR$CNT:NEAR ;MSBIO1 + EXTRN DSK$IN:NEAR ;MSBIO1 + EXTRN EXIT:NEAR ;MSBIO1 + EXTRN BUS$EXIT:NEAR ;MSBIO1 + EXTRN ERR$EXIT:NEAR ;MSBIO1 + +;DATA + EXTRN OLD13:DWORD ;MSBIO2 + EXTRN PTRSAV:DWORD ;MSBIO1 + EXTRN COM1DEV:WORD ;MSAUX + EXTRN DAYCNT:WORD ;MSCLOCK + EXTRN TIM_DRV:BYTE ;MSDATA + EXTRN ACCESSCOUNT:BYTE ;MSDATA + EXTRN SM92:BYTE ;MSDATA + EXTRN DISKSECTOR:BYTE ;MSDATA + EXTRN MEDIABYTE:BYTE ;MSDATA + EXTRN SECPERCLUSINSECTOR:BYTE ;MSDATA + EXTRN BPB_IN_SECTOR:WORD ;MSDATA + EXTRN DISKSECTOR:BYTE ;MSDATA + EXTRN STEP_DRV:BYTE ;MSDATA + EXTRN START_BDS:WORD ;MSDATA + EXTRN PHYS_DRV:BYTE ;MSDATA + EXTRN WRTVERIFY:WORD ;MSDATA + EXTRN FSETOWNER:BYTE ;MSDATA + EXTRN SINGLE:BYTE ;MSDATA + EXTRN RFLAG:BYTE ;MSDATA + EXTRN MEDBYT:BYTE ;MSDATA + EXTRN SPSAV:WORD ;MSDATA + EXTRN SECCNT:WORD ;MSDATA + EXTRN DPT:DWORD ;MSDATA + EXTRN CURSEC:BYTE,CURHD:BYTE ;MSDATA + EXTRN CURTRK:WORD ;MSDATA + EXTRN EOT:BYTE ;MSDATA + EXTRN MOTORSTARTUP:BYTE,SETTLECURRENT:BYTE,SETTLESLOW:BYTE ;MSDATA + EXTRN CURHD:BYTE ;MSDATA + EXTRN LSTERR:BYTE ;MSDATA + EXTRN ERRIN:BYTE,ERROUT:BYTE ;MSDATA + EXTRN PREVOPER:WORD ;MSDATA + EXTRN ORIG13:DWORD ;MSDATA + EXTRN FLAGBITS:WORD ;MSDATA + EXTRN NUMBER_OF_SEC:BYTE ;MSDATA + EXTRN FHAVE96:BYTE ;MSDATA + EXTRN NEW_ROM:BYTE ;MSDATA + EXTRN FORMT_EOT:BYTE,HDNUM:BYTE,TRKNUM:WORD,GAP_PATCH:BYTE ;MSDATA + EXTRN NEXT2F_13:WORD ;MSDATA + extrn Save_head_sttl:byte ;MSdata + extrn Secrete_Code:word ;MSdata +;;Rev 3.30 Modification + + +; +; Maximum number of retries in case of error +; + +MAXERR = 5 +LSTDRV = 504H + + +; +; Some floppy drives do not have changeline support. The result is a +; large amount of inefficiency in the code. A media-check always returns +; "I don`t know". This cause DOS to reread the FAT on every access and +; always discard any cached data. +; We get around this inefficiency by implementing a "Logical Door Latch". +; The following three items are used to do this. The logical door latch is +; based on the premise that it is not physically possible to change floppy +; disks in a drive in under two seconds (most people take about 10). The +; logical door latch is implemented by saving the time of the last successful +; disk operation (in the value TIM_DRV). When a new request is made the +; current time is compared to the saved time. If less than two seconds have +; passed then the value "No Change" is returned. If more than two seconds +; have passed the value "Don't Know" is returned. +; There is one complecation to this algorithm. Some programs change the +; value of the timer. In this unfortunate case we have an invalid timer. +; This possiblity is detected by counting the number of disk operations +; which occur without any time passing. If this count exceeds the value of +; "AccessMax" we assume the counter is invalid and always return "Don't +; Know". The variable "AccessCount" is used to keep track of the number +; of disk operation which occur without the time changing. +; + +AccessMax = 5 + + +; +; Some of the older versions of the IBM rom-bios always assumed a seek would +; have to be made to read the diskette. Consequently a large head settle +; time was always used in the I/O operations. To get around this problem +; we need to continually adjust the head settle time. The following +; algorithm is used: +; +; Get the current head settle value. +; If it is 1, then +; set slow = 15 +; else +; set slow = value +; ... +; if we are seeking and writing then +; use slow +; else +; use fast +; ... +; restore current head settle value +; +; +; flags for size of FAT +; +fTOOBIG EQU 80h +fBIG EQU 40h + +error_unknown_media equ 7 ; for use in BUILD BPB call + +BPB_TYPE STRUC +SECSIZE DW ? +SECALL DB ? +RESNUM DW ? +FATNUM DB ? +DIRNUM DW ? +SECNUM DW ? +FATID DB ? +FATSIZE DW ? +SLIM DW ? +HLIM DW ? +HIDDEN DW ? +BPB_TYPE ENDS +;------------------------------------------------------------------------ +; : +; The next 100 or so lines of code do the Media Check. Media Check : +; determines if the diskette (media) in the drive has been changed. : +; : +; SI is used to hold media check code: : +; -1 media changed : +; 0 Don't know : +; 1 media has not been changed : +; : +; The algorithm used is a follows: : +; if (hard disk) : +; if (changed by format) : +; return (not changed) : +; if not (changed by format) : +; return (changed) : +; else we have a floppy : +; if floppy has change line support go ask the floppy : +; if floppy does not have change line do the following : +; read the time : +; if more than two second have passed return don't know : +; if no time has passed then might be unreliable : +; counter (some program fool with the counter when : +; they should not). See note below for procedure with : +; unreliable counter : +; if sometime has passed but not two second return : +; media has not changed. This is based on the : +; assumption that it is not physically possilbe to : +; change a disk in less the two seconds (most people : +; take about 10 seconds). : +; : +;------------------------------------------------------------------------ + + public media$chk +MEDIA$CHK PROC NEAR + Message ftestdisk,<"Disk Media Check "> + MNUM ftestdisk,AX + Message ftestdisk, + Call SetDrive ; point DS:DI to BDS for specified drive + + cmp cs:Secrete_Code, 'jk' ; Secrete code for + jne media$done ; DOS 3.3 MSBIO. +; +; For non-removable disks only return changed if changed by format, +; otherwise return 'not changed'. +; + + mov si,1 ; assume no change + test word ptr [di].flags,fChanged_By_Format + jz WeAreNotFakingIt + ; reset flag + and word ptr [di].flags,NOT fChanged_By_Format + +; +; If media has been changed by format, must use the ROM. +; Cannot rely on the 2 second time check. +; + mov cs:[TIM_DRV],-1 ; Ensure that we ask the ROM if media + ; has changed + test word ptr [di].flags,fNon_Removable + jz WeHaveAFloppy + mov SI,-1 ; Indicate media changed + jmp short Media$Done +; +; return 'not changed' if disk is a hard file. +; + +WeAreNotFakingIt: + test word ptr [di].flags,fNon_Removable + jnz Media$Done + +; +; If this code is reached disk is a diskette drive +; + +WeHaveAFloppy: + + xor si,si ; Presume "I don't know" + +; +; If drive is a floppy with changeline support the rom is called to +; determine if the media has changed. It is not necessary to do the 2 +; second check on these drives. +; +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in MSINIT ;| + Public Media_Patch ;| +Media_Patch: ;| + CALL MediaCheck ;| + jc Err$Exitj ;| + call HasChange ;| + jnz Media$Done ;| +;----------------------------------------| +; +; If this code is reached the drive is a floppy with no changeline support +; + MOV SI,1 ; PRESUME NO CHANGE + mov al,cs:[TIM_DRV] ; last drive accessed + ;is drive of last access the same? + CMP AL,byte ptr [di].DriveNum + JNZ Media$Unk ; no, then return don't know +; +; CHECK TO SEE IF THIS DRIVE HAS BEEN ACCESSED IN THE LAST 2 SECONDS. +; + call Check_Time_of_Access + jmp short Media$Done + + +Media$Unk: + DEC SI ; RETURN "I DON'T KNOW" + +; +; SI now contains the correct value for media change. Clean up the left overs +; +Media$Done: + les bx,cs:[ptrsav] ; get original packet + mov WORD PTR es:[BX].Trans,SI + or SI,SI + js Init_Patch + jmp EXIT + +MEDIA$CHK ENDP + +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| + Public Init_Patch ;| +INIT_PATCH PROC NEAR ;| + CALL Media_Set_VID ;| +;----------------------------------------| + mov cs:[Tim_Drv],-1 ; make sure we ask ROM for media check +VOLIDOK: + jmp EXIT +INIT_PATCH ENDP + + + +ERR$EXITJ PROC NEAR + + MESSAGE FTESTCOM,<"ERR$EXITJ: "> + MNUM FTESTCOM,AX + MESSAGE FTESTCOM,<" == "> + CALL MAPERROR + MNUM FTESTCOM,AX + MESSAGE FTESTCOM, + JMP ERR$EXIT +ERR$EXITJ ENDP + +; +; PERFORM A CHECK ON THE TIME PASSED SINCE THE LAST ACCESS FOR THIS +; PHYSICAL DRIVE. +; WE ARE ACCESSING THE SAME DRIVE. IF THE TIME OF LAST SUCCESSFUL ACCESS +; WAS LESS THAN 2 SECONDS AGO, THEN WE MAY PRESUME THAT THE DISK WAS NOT +; CHANGED +; RETURNS IN SI: +; 0 - IF TIME OF LAST ACCESS WAS >= 2 SECONDS +; 1 - IF TIME WAS < 2 SECONDS (I.E NO MEDIA CHANGE ASSUMED) +; REGISTERS AFFECTED AX,CX,DX, FLAGS. +; +CHECK_TIME_OF_ACCESS PROC NEAR + PUBLIC CHECK_TIME_OF_ACCESS + mov si,1 ; Presume no change +;;Rev 3.30 Modification + xor AH, AH ; set command to read time + int 1Ah ; call rom-bios clock routine + +; +; Once time is read, must make sure the date wrap is not lost. The ROM will +; return the value only once, it must check for day wrap on each call. +; + SHR AL,1 + ADC CS:[DAYCNT],0 ; ADD IT TO OUR SAVED DAY COUNT +; +; Compute elapsed time +; + MOV AX,WORD PTR DS:[DI].TIM_LO ; GET STORED TIME + SUB DX,AX + MOV AX,WORD PTR DS:[DI].TIM_HI + SBB CX,AX +;;End of Modification +; +; CX:DX is the elapsed time +; + JNZ TimeCheck_Unk ; CX <> 0 => > 1 hour + OR DX,DX ; did some time pass? + JNZ TimePassed ; yes, examine max value +; +; No noticeable time has passed. There are two possiblities. First there +; could be two driver calls with in one clock tick (55 milliseconds). The +; second possiblity is the program has reprogramed the counter -- this is +; the unreliable counter case. To distinguish between the case a count is +; kept of the number of calls that happen without a clock tick (the variable +; is AccessCount). If this count exceeds a set limit (MaxAccess) it is +; assumed the counter is unreliable and the value don't know is returned. +; If AccessCount is less than MaxAccess we assume the time is valid and +; therefor the media has not changed. +; + inc byte ptr cs:AccessCount + ; Exceeded threshold for count? + cmp byte ptr cs:AccessCount,AccessMax + jb TimeCheck_Ret ; no, return media unchanged + dec byte ptr cs:AccessCount ; don't let the count wrap + jmp short TimeCheck_Unk ; "I don't know" if media changed + + +; +; If this code is reached some time has passed. Need to determine if +; 2 seconds have passed. Note: 18.2 ticks per second. +; +TimePassed: + CMP DX,18 * 2 ; IF ( Time_passed <= 2secs ) + JBE TimeCheck_Ret ; presume no change + + +; Everything indicates that we do not know what has happened. +; +TimeCheck_Unk: + DEC SI ; Presume I don't know +TimeCheck_Ret: + RET + +CHECK_TIME_OF_ACCESS ENDP + +ERR$EXITJ2: JMP ERR$EXITJ + + +;------------------------------------------------------------------------ +; : +; Get Bios Parameter Block : +; : +; GET$BPB is called to build a valid BPB for the media in the disk : +; drive. A BPB (Bios Parameter Block) contains information about : +; the media which is currently in the drive. The values stored is : +; information like number of fat sectors, size of drive, 8 or 9 sectors,: +; etc. : +; : +; This routine is called by the device drive code. : +; : +; On entry AL contains the logical drive number which needs : +; the BPB built. : +; ES:[di] points to a buffer; the first byte of the buffer is a : +; media decriptor byte. : +; : +;------------------------------------------------------------------------ +; +; Build a valid BPB for the disk in the drive. +; + + public GET$BPB +GET$BPB PROC NEAR + Message fTestDisk,<"Disk Build BPB "> ; print debug messages + MNUM fTestDisk,AX + Message fTestDisk, + mov AH,byte ptr ES:[DI] ; get FAT IB byte read by DOS + call SetDrive ; get the correct BDS for the drv +;;Rev 3.30 Modification + TEST WORD PTR [DI].FLAGS,FNON_REMOVABLE + JNZ ALREADY_GOTBPB ; NO NEED TO BUILD FOR FIXED DISKS +;;End of Modification + call GETBP ; build a BPB if necessary. + jc Err$exitj2 ; if error exit +GET$BPB ENDP +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| + Public SET_PATCH ;| +SET_PATCH PROC NEAR ;| + CALL set_volume_id ;| +;----------------------------------------| + ; print debug messages + message ftestdisk,<"Set Volume ID"> + mnum ftestdisk,di + message ftestdisk,<" "> + mnum ftestdisk,ds + message ftestdisk, +ALREADY_GOTBPB: + add di,BytePerSec ; return the BPB that is in the current BDS + + PUBLIC SetPTRSAV +SetPTRSAV: ; return point for DSK$INIT + les BX,cs:[PTRSAV] + mov ES:[BX].MEDIA,AH + mov ES:[BX].COUNT,DI + mov ES:[BX].COUNT+2,DS + jmp EXIT +SET_PATCH ENDP + + + + +; +; +; GETBP fills the BDS with the BPB for the media currently in the drive. +; The following steps are followed: +; If the Return_Fake_BPB flag is set then the GETBP just returns. +; If the BDS is for a hard disk (non-removable) then GETBP returns since +; the BPB cannot change on a hard disk drive. +; For all other cases GETBP reads the boot sector and looks for a BPB +; in the boot sector. (All DOS 2.X and about disks should have a valid +; BPB in the boot sector.) +; If no valid BPB is found (DOS 1.X disk) then GETBP reads the FAT +; sector and gets the FAT ID byte. With this byte a valid BPB is build. +; +; Inputs: +; DS:DI points to correct BDS +; +; Outputs: +; Fills in BPB in current BDS if valid BPB or FAT ID on disk. +; Carry set, and AL=7 if invalid disk. +; Carry set and error code in AL if other error. +; + + Public GETBP +GETBP PROC NEAR + ; if non-removable or returning + ; fake BPB then return BPB as is. + TEST WORD PTR [DI].FLAGS,RETURN_FAKE_BPB OR FNON_REMOVABLE + jz GETBP1 + JMP GETRET_EXIT + + +GETBP1: + message ftestdisk,<"Building BPB from scratch",CR,LF> + SaveReg +; +; Attempt to read in boot sector and determine BPB. +; We assume that the 2.x and greater DOS disks all have a valid boot sector. +; +Rdboot: + call ReadBootSec + jnc NoRdErr + jmp GetBP_Err_Ret ; Carry set if there was error. +NoRdErr: + cmp bx,0 ; BX is 0 if boot sector is valid. + jnz DoFatBPB ; if not go read FAT + + call MovBPB ; Move BPB into registers. + jmp Has1 + +; +; At this point the drive contains a 1.X diskette. We read the FAT byte +; and fill in the BPB from there. +; + +DoFatBPB: + call ReadFat ; puts media descriptor byte in AH + jc GetBP_Err_Ret ; if carry set, there was error, get out + +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| +Public GETBP1_PATCH ;| +GETBP1_PATCH: ;| + call hidensity ;| +;----------------------------------------| +; Test for a valid 3.5" medium + cmp [di].FormFactor, ffsmall + jnz Is_Floppy + cmp ah,0F9H ; is it a valid fat ID byte for 3.5" ? + jnz Got_Unknown_Medium + mov bx,offset sm92 ; pointer to correct BPB + push cs + pop es +ASSUME ES:CODE +;--------------------------------------------------------------bug330a08 + mov al,es:[bx.spf] + mov cx,es:[bx.csec] + mov dx,word ptr es:[bx.spa] + mov bx,word ptr es:[bx.spt] +;--------------------------------------------------------------bug330a08 + jmp short HAS1_res ; Need to load reserved sectors +; +; must be a 5.25" floppy if we come here +; +Is_Floppy: + mov CL,AH ; save media + and CL,0F8H ; normalize + cmp CL,0F8H ; cmopare with good media byte + jnz Got_Unknown_Medium + +GOODID: mov AL,1 ; set number of FAT sectors + mov BX,64*256+8 ; set dir entries and sector max + mov CX,40*8 ; set size of drive + mov DX,01*256+1 ; set head limit and sec/all unit + test AH,00000010B ; test for 8 or 9 sectors + jnz HAS8 ; NZ = has 8 sectors + inc AL ; inc number of FAT sectors + inc BL ; inc sector max + add CX,40 ; increase size +HAS8: test AH,00000001B ; test for 1 or 2 heads + jz HAS1_res ; Z = 1 head + add CX,CX ; double size of disk + mov BH,112 ; increase number of directory entries + inc DH ; inc sec/all unit + inc DL ; inc head limit + +PUBLIC HAS1_res +HAS1_res: + mov si,word ptr ds:[di].RESSEC +PUBLIC HAS1 ; save values in BDS +HAS1: mov byte ptr ds:[DI].SecPerClus,DH + mov byte ptr ds:[DI].cDir,BH + mov word ptr ds:[DI].Drvlim,CX + mov byte ptr ds:[DI].Mediad,AH + mov byte ptr ds:[DI].csecFat,AL + mov byte ptr ds:[DI].SecLim,BL + mov byte ptr ds:[DI].HdLim,DL + mov word ptr ds:[DI].RESSEC,SI +GETRET: pop BX + RestoreReg +ASSUME ES:NOTHING +GETRET_Exit: + RET + +GetBP_Err_Ret: + CALL MapError + JMP SHORT GETRET + +; +; We have a 3.5" diskette for which we cannot build a BPB. We do not assume any +; type of BPB for this medium. +; +Got_Unknown_Medium: + mov al,error_unknown_media + stc + jmp short GETRET + +GETBP ENDP + +bpbType struc +spf db ? +spt db ? +cdire db ? +csec dw ? +spa db ? +chead db ? +bpbType ends + +; +; end of GET$BPB code +;------------------------------------------------- + +; +; Read in the boot sector. Set carry if error in reading sector. +; BX is set to 1 if the boot sector is invalid, otherwise it is 0. +; +READBOOTSEC PROC NEAR + mov CX, 0001h ; set track and sector number + xor DH, DH ; set head number for read_sector + call read_sector + jc Err_Ret ; error - get out + xor bx,bx ; assume valid boot sector. + + ; at this point the boot sector has been + ; read in from the disk. We now need to + ; determine if the boot sector contains + ; a valid BPB. Currently there are only + ; a few simple checks. Expanding the + ; number or types of checks would not be + ; a bad idea. +;******************************************************************************* +; Put a sanity check for the boot sector in here to detect boot sectors that +; do not have valid BPBs. +; We examine the first two bytes - they must contain a long jump or a short +; jump followed by a NOP. +; If this test is passed, we further check by examining the signature at +; the end of the boot sector for the word AA55H. +; If the signature is not present, we examine the media descriptor byte to +; see if it is valid. +;****************************************************************************** + cmp byte ptr cs:[DiskSector],069H ; Is it a direct jump? + JE Check_bpb_MediaByte ; DON'T NEED TO FIND A NOP + cmp byte ptr cs:[DiskSector],0E9H ; DOS 2.0 jump? + JE Check_bpb_MediaByte ; NO NEED FOR NOP + cmp byte ptr cs:[DiskSector],0EBH ; How about a short jump. + JNE INVALIDBOOTSEC + cmp byte ptr cs:[DiskSector]+2,090H ; Is next one a NOP? + JNE INVALIDBOOTSEC + + +; Don't have to perform the following signature check since +; we need to check the media byte even with the good signatured diskette. +;CHECK_SIGNATURE: +; CMP WORD PTR CS:[DISKSECTOR+1FEH],0AA55H ; SEE IF NON-IBM +; ; DISK OR 1.X MEDIA. +; JZ CHECKSINGLESIDED ; GO SEE IF SINGLE SIDED MEDIUM. +; ; MAY NEED SOME SPECIAL HANDLING +; +; CHECK FOR NON-IBM DISKS WHICH DO NOT HAVE THE SIGNATURE AA55 AT THE +; END OF THE BOOT SECTOR, BUT STILL HAVE A VALID BOOT SECTOR. THIS IS DONE +; BY EXAMINING THE MEDIA DESCRIPTOR IN THE BOOT SECTOR. +; + +;;Rev 3.30 Modification +Check_bpb_MediaByte: + + MOV AL,BYTE PTR CS:MEDIABYTE + AND AL,0F0H + CMP AL,0F0H ; ALLOW FOR STRANGE MEDIA + JNZ INVALIDBOOTSEC +; +; THERE WERE SOME (APPARENTLY A BUNCH) DISKETTES THAT HAD BEEN FORMATTED +; UNDER DOS 3.1 AND EARLIER VERSIONS WHICH HAVE INVALID BPBS IN THEIR BOOT +; SECTORS. THESE ARE SPECIFICALLY DISKETTES THAT WERE FORMATTED IN DRIVES +; WITH ONE HEAD, OR WHOSE SIDE 0 WAS BAD. THESE CONTAIN BPBS IN THE BOOT +; SECT THAT HAVE THE SEC/CLUS FIELD SET TO 2 INSTEAD OF 1, AS IS STANDARD +; IN DOS. TO SUPPORT THEM, WE HAVE TO INTRODUCE A "HACK" THAT WILL +; HELP OUR BUILD BPB ROUTINE TO RECOGNISE THESE SPECIFIC CASES, AND TO +; SET UP OUT COPY OF THE BPB ACCORDINGLY. +; WE DO THIS BY CHECKING TO SEE IF THE BOOT SECTOR IS OFF A DISKETTE THAT +; IS SINGLE-SIDED AND IS A PRE-DOS 3.20 DISKETTE. IF IT IS, WE SET THE +; SEC/CLUS FIELD TO 1. IF NOT, WE CARRY ON AS NORMAL. +CHECKSINGLESIDED: + MOV AL,BYTE PTR CS:MEDIABYTE + TEST AL,0001H ; IS LOW BIT SET? - INDICATES DOUBLE SIDED + JNZ GOODDSK + CMP WORD PTR CS:[DISKSECTOR+8],"." SHL 8 + "3" + JNZ MUSTBEEARLIER + CMP BYTE PTR CS:[DISKSECTOR+10],"2" + JAE GOODDSK + +; WE MUST HAVE A PRE-3.20 DISKETTE. SET THE SEC/CLUS FIELD TO 1 +MUSTBEEARLIER: + MOV BYTE PTR CS:[SECPERCLUSINSECTOR],1 + JMP SHORT GOODDSK + +INVALIDBOOTSEC: + INC BX ; SET THAT BOOT SECTOR INVALID +;;End of Modification + +GoodDsk: ; carry already reset + clc + ret + +Err_Ret: ; carry is already set on entry here + message ftestdisk,<"error in readboot",cr,lf> + ret + +READBOOTSEC ENDP + +; +; MovBPB moves the BPB read from the Boot sector into registers for use by +; GETBP routine at Has1 +; +MOVBPB PROC NEAR + SaveReg + push cs + pop ds + mov di,offset BPB_In_Sector + mov dh,Byte Ptr [di].secall ;sectors per unit + mov bh,Byte Ptr [di].dirnum ;number of directory entries + mov cx,Word Ptr [di].secnum ;size of drive + mov ah,Byte Ptr [di].fatid ;media descriptor + mov al,Byte Ptr [di].fatsize ;number of FAT sectors + mov bl,Byte Ptr [di].slim ;sectors per track + mov dl,Byte Ptr [di].hlim ;number of heads + mov si,word ptr [di].resnum ;reserved sectors + RestoreReg + ret +MOVBPB ENDP + + + +; +; Read in the FAT sector and get the Media Byte from it. +; Input : AL contains logical drive. +; Output: +; Carry set if an error occurs, AX contains error code. +; Otherwise, AH contains media byte on exit. AL is preserved. + +READFAT PROC NEAR + push ax ; preserve logical drive in AL + MOV DH,0 ; HEAD 0 + mov CX,0002 ; set track and sector number + call read_sector ; CS:BX points to fat sector + jc Bad_FAT_Ret ; error, get out + pop ax ; reset logical drive + mov ah,Byte Ptr CS:[BX] ; media byte + ret + +Bad_FAT_Ret: ; carry set on entry + message ftestdisk,<"error in FAT read",cr,lf> + pop cx ; clear stack + ret +READFAT ENDP + + + +; +; Read_sector reads a single sector into the tempory buffer 'DiskSector'. +; Up to three retries are done in case of error. +; +; Inputs: +; DS:DI points to BDS for drive +; CH - track number +; CL - sector number +; DH - head number +; +; Outputs: +; If carry is clear -- successful read +; CS:BX points to buffer holding sector +; AX, BX are not preserved, CX, DX, BP, and ES are preserved +; +; If carry is set -- error on read +; AX, BX, and DX are not preserved; CX, BP, and ES are preserved +; +; + +READ_SECTOR PROC NEAR + PUBLIC READ_SECTOR + push BP ; preserve BP register + mov BP,3 ; BP is retry count, set to 3 + push ES ; preserve ES also + mov DL, byte ptr [di].DriveNum + mov BX, offset DiskSector ; Get ES:BX to point to buffer + push CS ; get the segment right + pop ES ; now ES:BX is correct + +RD_RET: + ; set command to read (AH=2) and + mov AX, 0201h ; number of sectors to 1 (AL=1) + int 13h ; call rom-bios disk routines + + jnc OKRET2 ; if no carry then no error - done +Rd_rty: + call Again ; reset disk and decrement BP + jz Err_RD_RET + test word ptr ds:[di].flags,fNon_Removable + JNZ RD_RET +;;Rev 3.30 Modification ----------------------------------------- + push ds ; For retry, set head settle + push ax ; time to 0Fh. + lds si,cs:DPT + mov al, ds:[si].disk_head_sttl + mov cs:[save_head_sttl],al + mov byte ptr ds:[si].disk_head_sttl, NormSettle + pop ax + pop ds + ; SET CMD TO READ (AH=2) AND + MOV AX, 0201h ; NUM OF SECTORS TO 1 (AL=1) + INT 13h ; CALL ROM-BIOS DISK ROUTINES + push ds + push ax + lds si,cs:DPT + mov al, cs:[save_head_sttl] + mov byte ptr ds:[si].disk_head_sttl, al + pop ax + pop ds + jnc OKRET2 + jmp Rd_rty +ERR_RD_RET: + MOV DL,-1 ; MAKE SURE WE ASK ROM IF MEDIA CHANGED + STC ; RETURN ERROR +;;End of Modification ----------------------------------------- + + ; Update information pertaining to last drive + ; accessed, time of access, last track accessed + ; in that drive. +OKRET2: + ; set up for head settle logic in DISK + mov CS:[STEP_DRV],DL ; save last drive accessed + mov CS:[TIM_DRV],DL ; save the values + mov byte ptr [di].track,CH ; + pushf ; save the flags + call SET_TIM + popf ; restore flags + pop ES ; restore registers + pop BP + ret + +READ_SECTOR ENDP + + + +;------------------------------------------------------------------------ +; : +; Disk Removable Routine : +; : +; This routine determines if a particular logical drive has : +; removable media. : +; : +; Input : +; AL contains the logical drive number which the check is being : +; done. : +;------------------------------------------------------------------------ + +DSK$REM PROC NEAR ;ARR 2.41 + PUBLIC DSK$REM + Message fTestDisk,<"Disk Removable "> ; print debug messages + MNUM fTestDisk,AX + Message fTestDisk, + ; AL is logical unit number + call SetDrive ; get BDS for this drive + test word ptr [di].flags,fNon_Removable + jnz NON_REM + jmp EXIT + +NON_REM: ; if non removable set busy bit + jmp BUS$EXIT + +DSK$REM ENDP + + + +; +; SetDrive scans through the data structure of BDSs and returns a +; pointer to the BDS that belongs to the drive specified in AL. +; Carry is set if no BDS has a logical drive number which matches the +; value in AL. +; Input: +; AL contains the logical drive number +; Output: +; DS:DI points to correct BDS if Carry is clear. +; +; All register execpt DS and DI are preserved +; + + Public SetDrive +SETDRIVE PROC NEAR + message ftestdisk,<"SetDrive",cr,lf> ; print debug messages + push bx + push cs + pop ds + ; assume first BDS is in this segment + ASSUME DS:CODE + mov di,word ptr Start_BDS +Scan_Loop: +;;Rev 3.30 Modification ----------------------------------------- + CMP BYTE PTR CS:[PHYS_DRV],1 ; DOES AL HAVE PHYS DRV? + JB USE_LOGICAL_DRV + CMP BYTE PTR [DI].DRIVENUM,AL + JE SETDRV + JMP SHORT GET_NXT_BDS +USE_LOGICAL_DRV: + CMP BYTE PTR [DI].DRIVELET,AL + JE SETDRV +GET_NXT_BDS: + MOV BX,WORD PTR [DI].LINK+2 ; GO TO NEXT BDS + MOV DI,WORD PTR [DI].LINK + mov ds,bx + ASSUME DS:NOTHING +;;End of Modification ----------------------------------------- + + cmp di,-1 ; at end of list? + jnz Scan_Loop ; no, keep looking + stc ; yes, indicate error set carry +SetDrv: + pop bx ; restore bx + ret ; return + +SETDRIVE ENDP + + + +;------------------------------------------------------------------------ +; : +; DISK I/O ROUTINES : +; : +; On entry the register contain the following values: : +; : +; AH - Media Descriptor byte : +; AL - logical drive number : +; CX - count of sectors to be read or written : +; DX - start sector : +; DI - offset of destination buffer : +; : +;------------------------------------------------------------------------ + + +;------------------------------------------------------------------------ +; : +; Disk Write with Verify : +; : +; Input : +; See about header for register contents on entry. : +; : +;------------------------------------------------------------------------ + + +DSK$WRITV PROC NEAR + PUBLIC DSK$WRITV + Message fTestDisk,<"Disk Write with verify "> + MNUM fTestDisk,AX + Message fTestDisk,<" "> + MNUM fTestDisk,DX + Message fTestDisk,<" for "> + MNUM fTestDisk,CX + Message fTestDisk, + MOV CS:[WRTVERIFY],103H + JMP SHORT DSK$CL + +;------------------------------------------------------------------------ +; : +; Disk Write : +; : +; Input : +; See about header for register contents on entry. : +; : +;------------------------------------------------------------------------ + +DSK$WRIT: + PUBLIC DSK$WRIT + Message fTestDisk,<"Disk Write "> + MNUM fTestDisk,AX + Message fTestDisk,<" "> + MNUM fTestDisk,DX + Message fTestDisk,<" for "> + MNUM fTestDisk,CX + Message fTestDisk, + MOV CS:[WRTVERIFY],ROMWrite + +DSK$CL: + CALL DISKIO +DSK$IO: + JC DSKBad + JMP EXIT +DSKBad: + JMP ERR$CNT + +DSK$WRITV ENDP + + +;------------------------------------------------------------------------ +; : +; Disk Read : +; : +; Input : +; See about header for register contents on entry. : +; : +;------------------------------------------------------------------------ + +DSK$READ PROC NEAR + PUBLIC DSK$READ + Message fTestDisk,<"Disk Read "> + MNUM fTestDisk,AX + Message fTestDisk,<" "> + MNUM fTestDisk,DX + Message fTestDisk,<" for "> + MNUM fTestDisk,CX + Message fTestDisk, + CALL DISKRD + JMP DSK$IO +DSK$READ ENDP +; +; Miscellaneous odd jump routines. Moved out of mainline for speed. +; + + +; +; CheckSingle determines if the drive specified is a virtual drive (more +; than one logical drive associated with one physical drive). If this +; is the case we need to prompt the user to place the correct disk in +; the drive. +; +; Input: +; DS:DI pints to the BDS for the drive being checked. +; +; If there is a error the carry flag is set on return +; +; All registers are preserved. +; + +CHECKSINGLE PROC NEAR + PUBLIC CHECKSINGLE + push AX ; save affected registers + push BX + mov BX,word ptr ds:[di].flags + TEST BL,FNON_REMOVABLE OR FI_OWN_PHYSICAL ;Can't change disk + jnz SingleRet ; on hard drive so return + ; is there a drive sharing this + TEST BL,FI_AM_MULT ; physical drive? + jz SingleRet ; if not, then return + + ; At this point there is more than one + ; logical drive mapped to this physical drive. + ; But the drive being accessed is not the + ; owner of the physical drive. What needs to + ; be done is find the current owner BDS and + ; turn off the owner flag and then make current + ; BDS the owner of the drive. Then prompt the + ; user to change disks. + mov al,ds:[di].DriveNum ; get physical drive number + push ds ; preserve pointer to current BDS + push di + push cs + + pop ds ; Point to start of BDS linked list + ASSUME DS:CODE + + mov di,offset Start_BDS + +Scan_List: + mov bx,word ptr [di].link+2 ; go to next BDS + mov di,word ptr [di].link + mov ds,bx + ASSUME DS:NOTHING + + cmp di,-1 ; end of list? + jz single_err_ret ; if so there must be an error + ; same physical drive? + cmp byte ptr [di].DriveNum,al + jnz Scan_List ; no, keep looking + +Check_Own: ; yes, check to see if owner + mov bx,word ptr [di].flags + test bl,fI_Own_Physical + jz Scan_List ; not owner, keep looking + xor bl,fI_Own_Physical ; yes owner reset ownership flag + mov word ptr ds:[di].flags,bx + pop di ; Restore pointer to current BDS + pop ds + xor bx,bx + or bl,fI_Own_Physical ; establish current BDS as owner + or word ptr [di].flags,bx + + + ; + ; We examine the fSetOwner flag. If it is + ; set, then we are using the code in + ; CheckSingle to just set the owner of + ; a drive. We must not issue the prompt + ; in this case. + ; + + cmp byte ptr cs:[fSetOwner],1 + jz SingleRet + ; + ; To support "backward" compatibility with + ; IBM's "single drive status byte" we now + ; check to see if we are in a single drive + ; system and the Application has "cleverly" + ; diddled the SDSB (Single Drive Status Byte) + ; + + cmp cs:[single],2 ; single drive system? + jne short Ignore_SDSB ; no, jump down + + SaveReg ; yes... + mov al,ds:[di].DriveLet ; IF (Curr_drv == Req_drv) + mov ah,al + xor di,di + mov ds,di + xchg al,ds:byte ptr LSTDRV ; THEN swap(Curr_drv,Req_drv) + cmp ah,al ; ELSE + RestoreReg ; swap(Curr_drv,Req_drv) + je SingleRet ; Issue Swap_dsk_msg + +Ignore_SDSB: + call SWPDSK ; ask user for correct disk + +SingleRet: + pop BX ; restore registers + pop ax + ret ; return + +Single_Err_Ret: + stc ; set carry flage to indicate error + pop di ; restore current BDS + pop ds + jmp short SingleRet + + +; +; BadDrive is called when sector specified is greater than last +; sector on disk. +; or when BDS is not found for drive +; + +BadDrive: + mov AL,8 ; error code 'sector not found' + stc ; indicate error +IORET: ret ; return + + + +BogusSettle: + MOV AL,NormSettle ; someone has diddled the settle + JMP GotSlowSettle + +CHECKSINGLE ENDP + + + + +;------------------------------------------------------------ +; +; DISK I/O HANDLER +; +; On entry: +; AL = Drive Number (0-6) +; AH = media Descriptor +; CX = sector count +; DX = first sector +; DS = CS +; ES:DI = transfer address +; [RFLAG] = operation (2 for read, 3 for write) +; [VERIFY] = 1 for verity after write +; +; On exit: +; if successful carry flag = 0 +; else CF=1 and AL contains error code +; + + + Public DISKRD +DISKRD PROC NEAR + mov CS:[RFLAG],ROMRead ; set command to read + +DISKIO: + mov BX,DI ; ES:BX is transfer address + Call SetDrive ; map logical and physical + jc BadDrive ; carry means BDS not found + mov al,BYTE PTR DS:[DI].Mediad + mov cs:MedByt,al ; Preserve media byte for drive for use + ; in determining media change. + jcxz IORET + mov cs:[SPSAV],SP ; save the sp value +; +; Ensure that we are trying to access valid sectors on the drive +; + mov SI,DX ; start with first sector + add SI,CX ; add in sector count + add DX,WORD PTR [DI].HIDSEC ; add in the hidden sectors + cmp SI,WORD PTR [DI].DRVLIM ; compare against drive maximum + ja BADDRIVE ; if greater than max, error + mov cs:[SECCNT],CX ; save sector count +;;Rev 3.30 Modification ----------------------------------------- +; SET UP POINTER TO DISK BASE TABLE IN [DPT]. WE CANNOT ASSUME THAT IOSETUP +; WILL DO IT BECAUSE WE WILL SKIP THE SET UP STUFF WITH HARD DISKS. + PUSH DS + XOR AX,AX + MOV DS,AX + LDS SI,DWORD PTR DS:[DSKADR]; CURRENT DISK PARM TABLE + MOV WORD PTR CS:DPT,SI + MOV WORD PTR CS:DPT+2,DS + POP DS +;;End of Modification ----------------------------------------- +; +; For hard drives do not do media check or set DPT. +; + test word ptr [di].flags,fNon_Removable + jnz Skip_Setup + CALL CHECKSINGLE +; +; Check to see if we have previously noted a change line. The routine +; returns if everything is OK. Otherwise, it pops off the stack and returns +; the proper error code. +; +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| + Public DiskIO_Patch ;| +DiskIO_PATCH: ;| + CALL CheckLatchIO ;| +;----------------------------------------| +; +; Set up tables and variables for I/O + call IOSetUp +; +; Now the settle values are correct for the following code +; +Skip_Setup: + mov AX,DX ; setup locical sector for divide + xor DX,DX + div word ptr [DI].SECLIM ; divide by sectors per track + inc DL + mov cs:[CURSEC],DL ; save current sector + mov CX,word ptr [DI].HDLIM ; get number of heads + xor DX,DX ; divide tracks by heads per cylinder + div CX + mov cs:[CURHD],DL ; save current head + mov cs:[CURTRK],AX ; save current track +; +; We are now set up for the I/O. Normally, we consider the DMA boundary +; violations here. Not true. We perform the operation as if everything is +; symmetric; let the DISK INT handler worry about the DMA violations. +; + mov AX, cs:[SECCNT] + call BLOCK + call DONE + ret + +DISKRD ENDP + + + +; +; IOSetUp: +; +; IOSetUp does the following functions: +; * Set the drive-last-accessed flag (for diskette only). No need to +; update these flags for hard disks becuase we know a hard disk will +; not be removed. +; * Set the proper last sector number in the Disk Parameter Table (DPT) +; * Set the proper motor start up time in DPT +; * Set the proper head settle time in the DPT +; +; Input: +; DS:DI -> current BDS. +; Output: +; AX,CX,SI are destroyed. +; + public IOSetUp +IOSETUP PROC NEAR + MOV AL,[DI].DRIVENUM + MOV CS:[TIM_DRV],AL ; SAVE DRIVE LETTER +; +; determine proper head settle values +; + mov CX,DS + LDS SI,DWORD PTR CS:[DPT] ; GET POINTER TO DISK BASE TABLE + MOV AL,CS:[EOT] + mov [SI].DISK_EOT,AL ; bump for us + mov AL,[si].DISK_Motor_Strt ; preserve old motor start time + mov cs:MotorStartup,AL +; +; For 3.5" drives, both external as well as on the K09, we need to set the +; Motor Start Time to 4. This checking for every I/O is going to affect +; performance across the board, but is necessary!! +; + push es + mov es,cx ; ES:DI -> to current BDS + cmp byte ptr es:[di].FormFactor,ffsmall + jnz Motor_Start_OK + mov AL,4 + xchg AL,[si].DISK_MOTOR_STRT +Motor_Start_OK: + pop ES +; +; DS:SI now points to disk parameter table. Get current settle and set fast +; settle +; + + XOR AL,AL + INC AL ; IBM WANTS FAST SETTLE = 1 - RS + xchg AL,[SI].DISK_Head_Sttl ; get settle and set up for fast + mov cs:SettleCurrent,AL + MOV AL,NORMSETTLE ; SOMEONE HAS DIDDLED THE SETTLE +GotSlowSettle: + mov DS,CX + mov cs:SettleSlow,AL + ret + + + + +; +; Set time of last access, and reset default values in the DPT. +; +DONE: + test word ptr [di].Flags,fNon_Removable + jnz RETZ ; Do not set for non-removable Media + call SET_TIM ; set time of last access for drive +; +; Restore head settle and EOT values +; +DiddleBack: + push ax ; preserve AX + mov DX,DS ; save DS in DX + mov AL,cs:SettleCurrent ; get value in registers + mov AH,cs:MotorStartup + lds SI,cs:DPT ; get pointer to DPT + mov [SI].Disk_EOT,9 ; save values in DPT + mov [SI].Disk_Head_Sttl,AL + mov [si].Disk_Sector_Siz,2 + mov [si].Disk_Motor_Strt,AH + mov DS,DX ; restore DS + pop ax ; restore AX +RETZ: + ret + + + + + +; +; Block reads or writes the number of sectors specified in AX +; handling track boundaries. For example, on an 8 sector per track +; disk there might be a request to read 6 sectors starting at the 5th +; sector. Block breaks this request into a read of sectors 5-8 on +; the first track and a read of sectors 1-2 on the next track. Disk is +; called to do the actual read. +; +; Inputs: +; AX - number of sectors to be read +; DS:DI points to BDS for disk drive +; cs:CurSec - sector on track where read should start +; cs:CurTrk - track where read should start +; cs:CurHd - head for read +; ES:BX - transfer address +; AX, CX, and BL are not preserved +; + +BLOCK: + or AX,AX ; see if any sectors to read + jz RETZ ; if not, return +;;Rev 3.30 Modification ----------------------------------------- +; Fixed disk will not be restricted to the trk-by-trk basis. + test word ptr [di].Flags, fNon_Removable + jz BLOCK_FLOPPY + call DISK + xor ax,ax + RET +BLOCK_FLOPPY: +;;End of Modification ----------------------------------------- +; +; READ AT MOST 1 TRACK WORTH. PERFORM MINIMIZATION AT SECTOR / TRACK +; + mov CL,byte ptr [DI].SecLim ; get sectors per track + inc CL + sub CL,cs:CurSec ; set CX to number of sector after current + xor CH,CH ; sector on the current track + cmp AX,CX ; is all of request on current track? + jae GotMin ; no, jump down + mov CX,AX ; yes, set number of sector on this track to AX +GotMin: + ; now + ; AX is the requested number of sectors to read + ; CX is the number that we can do on this track + push AX + push CX + mov AX,CX ; AL is number of sectors to read + call Disk + pop CX + pop AX + + ; CX is the number of sectors just transferred + sub AX,CX ; reduce sectors-remaining by last I/O + shl CL,1 + add BH,CL ; adjust transfer address + jmp Block ; jump to do any remaining sectors + +IOSETUP ENDP + + + + + +; +; DISK: +; Disk is called to read or write one or more sectors on a track. +; Retries are make if an error occurs. +; +; Input: +; AL - number of sector to be read/written (they must all be on one track) +; DS:DI points to BDS for the drive +; ES:BX is transfer address (must not cross 64k physical boundry) +; [RFLAG] is 2 for read and 3 for write +; [VERIFY] is 0 for normal, 1 for verify after write +; [CurTrk] is track (cylinder) to be read/written. +; [CurHd] is head to be used in operation. +; [CurSec] is sector to start read on. +; +; The following are overwritten: BP, +; Output: +; [SECCNT] is decrement by the number of sectors read or written + + + public disk +DISK PROC NEAR + mov BP,MAXERR ; set up retry count + MOV AH,CS:RFLAG ;GET READ/WRITE INDICATOR + +RETRY: + ; AX is overwritten in int 13 call, so + ; to do a retry we need to save the + ; value by pushing on the stack + push AX + ; the next five lines of code put the + ; sector number in bit 5-0 of CL and the + ; cylinder number in CH and bits 7-6 of + ; CL. The register must be set up in this + ; way for the bios. + mov DX,cs:[CURTRK] ;Load current cylinder +;;Rev 3.30 Modification ----------------------------------------- + test word ptr [di].FLAGS, fNon_Removable ;Fixed disk + jz DISK_NOT_MINI ;no, skip this. + cmp [di].IsMini, 1 ;Is this a mini disk? + jnz DISK_NOT_MINI ;No. continue to next. + add dx, [di].Hidden_Trks ;else add hidden trks. +DISK_NOT_MINI: +;;End of Modification ----------------------------------------- + ror DH,1 ; get high two bits of cylinder in correct place + ror DH,1 + + or DH,cs:[CURSEC] ; get sector value + mov CX,DX ; put cylinder/sector values in correct register + ; get head value + xchg CH,CL ; put bytes in correct place + mov DH,byte ptr cs:[CurHD] + ; get drive number + mov DL,byte ptr [DI].DriveNum + + CMP BYTE PTR [DI].FORMFACTOR,FFHARDFILE + JZ DO_FAST ; HARD FILES USE FAST SPEED +; +; The registers are now all set up for call on rom-bios. +; The next dozen or so line determines whether we call Do_Fast or Do_Norm +; for the actual I/O read. Do_Fast calls FastSpeed for the actual I/O. +; Do_Norm calls NormSpeed. NormSpeed changes the value for the head settle +; time in the disk parameter table to a larger value and then calls FastSpeed +; to do the I/O. So Do_Fast just has a shorter head settle time. +; + CMP CS:[STEP_DRV],-1 + jz Do_Writej + + cmp AH,ROMRead ; For read... + je Do_Fast ; ... alway use fast + + cmp AH, ROMVerify ; For verify... + je Do_Fast ; ... alway use fast + +Do_Writej: + jmp DO_Write ; Jump down for write... + + +DO_Fast: + CALL FastSpeed ; do I/O carry set if error +TestErr: + jc DSKERR ; error -- get out +; SET DRIVE AND TRACK OF LAST ACCESS + mov cs:[STEP_DRV],DL ; save the last drive accessed + mov byte ptr [di].track,CH ; save in BDS + +NO_SET: + cmp CS:WRTVERIFY,103H ; Check for write and verify + jz DoVerify ; yes -- go do verify +NOVERIFY: + pop AX ; pop command and num sec. from stack + and CL,03FH ; Eliminate cylinder bits from sector + xor AH,AH + sub cs:[SECCNT],AX ; Reduce count of sectors to go + add CL,AL ; Next sector + mov cs:[CURSEC],CL + cmp CL,BYTE PTR [DI].SECLIM ; See if sector/track limit reached + jbe Disk_Ret ; yes, return +NextTrack: + mov cs:[CURSEC],1 ; Start with first sector of next track + mov DH,CS:[CURHD] + inc DH ; go to next head + cmp DH,BYTE PTR [DI].HDLIM ; at head limit? + jb NOXOR ; no, jump down + xor DH,DH ; at head limit, reset to head zero ... + inc cs:[CURTRK] ; and go to next head +NOXOR: + mov cs:[CURHD],DH ; save new head number +Disk_Ret: + clc ; successful return so clear error flag + ret ; all done +DISK ENDP +; +; The request is for write. Determine if we are talking about the same +; track and drive. If so, use the fast speed. +; +DO_WRITE PROC NEAR + cmp DL,cs:[STEP_DRV] ; same drive? + jnz DO_Norm ; no, do normal speed + cmp CH,byte ptr [di].track ; same track on drive + jz DO_Fast ; yes, do fast speed +DO_Norm: + call NormSpeed ; use larger head settle time + jmp SHORT TestErr ; test for error + +DO_WRITE ENDP + + +; +; we have a verify request also. Get state info and go verify +; + +DOVERIFY PROC NEAR + pop AX ; get number of sectors from stack + push AX ; in non-detructive fashion + MOV AH,ROMVERIFY ; REQUEST VERIFY + CALL FastSpeed ; MZ 2.21 change settle mode + JNC NoVerify +DOVERIFY ENDP + +; +; Need to special case the change-line error AH=06h. If we get this, we +; need to return it. +; +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| + Public DSKERR ;| +DSKERR PROC NEAR ;| + CALL CheckIO ;| +;---------------------------------------;| + + Call AGAIN ; reset the disk and decrement retry cnt + jz HARDERR ; if z flag set, did all retries-give up + cmp AH,80H ; timeout? + jz HARDERR ; yes, jump to hard error +DSKERR1: + pop AX ; Restore sector count + jmp RETRY ; and try again + +HARDERR: + PUBLIC HARDERR + CALL MapError + +HARDERR2: ; for routines that call MapError themselves + PUBLIC HARDERR2 + mov cs:[Tim_Drv],-1 ;Force a media check through ROM + mov CX,cs:SECCNT ;Get count of sectors to go + mov SP,cs:[SPSAV] ;Recover entry stack pointer +; +; Since we are performing a non-local goto, restore the disk parameters +; +MedByt_OK: + call DiddleBack + ret ;and return + +DSKERR ENDP + + +; +; change settle value from SettleCurrent to whatever is appropriate +; +NORMSPEED PROC NEAR + push DS ; save two registers + push AX + mov AL,cs:SettleSlow ; change value in current disk parm tbl + lds SI,cs:DPT ; current disk parm table + mov [SI].Disk_Head_Sttl,AL + pop AX ; restore command and sector count + pop DS + call FastSpeed ; do I/0 + push DS ; restore the value in disk parm table + lds SI,cs:DPT + mov [SI].Disk_Head_Sttl,1 ; 1 is fast settle + pop DS + ret + +NORMSPEED ENDP + + +FASTSPEED PROC NEAR +; +; If the drive has been marked as too big (i.e. starting sector of the +; partition is > 16 bits, then ALWAYS return drive not ready. +; + TEST BYTE PTR [DI].FatSiz,fTOOBIG + + + IF TEST + JZ Ready ; if debugging use jmp rather + JMP NotReady ; than local jnz +Ready: + else + JNZ NotReady + endif + + Message fTestINIT,<"<"> ; print debug messages + MNUM fTestINIT,AX + Message fTestINIT,<","> + MNUM fTestINIT,ES + Message fTestINIT,<":"> + MNUM fTestINIT + Message fTestINIT,<","> + MNUM fTestINIT,CX + Message fTestINIT,<","> + MNUM fTestINIT,DX + Message fTestINIT,<">"> + + int 13h ; call rom-bios disk routines + +Death: + ret +NotReady: + stc ; set carry to indicate error + mov AH,80h ; put error code in AH + jmp Death ; jump to ret + +FASTSPEED ENDP + + +; +; Map error returned by ROM into corresponding code to be returned to +; DOS in AL. +; +MAPERROR PROC NEAR + PUBLIC MAPERROR + push CX ; save cx + push CS + pop ES ; make ES the local segment + mov AL,AH ; move error code into AL + mov cs:[LSTERR],AL ; terminate list with error code + mov CX,NUMERR ; number of possible error conditions + mov DI,OFFSET ERRIN ; point to error conditions + repne SCASB + mov AL,cs:[DI + NUMERR - 1] ; get translation + pop cx ; restore cx + stc ; flag error condition + ret +MAPERROR ENDP + +; +; Set the time of last access for this drive. This is done only for removable +; media. +; + public SET_TIM +SET_TIM PROC NEAR + push ax + xor AH, AH ; set command to get time + int 1Ah ; call rom-bios timer function + or AL,AL ; is there 24 hour rollover? + jz NOROLL3 ; no, skip down + inc cs:[DayCnt] ; yes, then increment DayCnt +NOROLL3: +; We have the new time. If we see that the time has passed, then we reset +; the threshold counter... + cmp DX,word ptr [di].TIM_LO ; Did any time pass? + jnz SetAccess ; yes, update access time + cmp CX,word ptr [di].TIM_HI ; now look at the high bits + jz Done_Set ; if equal then no time passed +SetAccess: ; we get here if some time has passed + ; zero AccessCount to show time passage + mov byte ptr cs:[AccessCount],0 + MOV WORD PTR DS:[DI].TIM_LO,DX ; save low time bits + MOV WORD PTR DS:[DI].TIM_HI,CX ; save high time bit +Done_Set: + clc ; indicate no error + pop ax ; restore AX register + ret + +SET_TIM ENDP + ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING + +; +; This is the true DISK INT handler. We parse the request to see if there is +; a DMA violation. If so, depending on the function, we: +; READ/WRITE Break the request into three pieces and move the middle one +; into our internal buffer. +; FORMAT Copy the format table into the buffer +; VERIFY Point the transfer address into the buffer +; +; This is the biggest bogosity of all. The IBM controller does NOT handle +; operations that cross physical 64K boundaries. In these cases, we copy +; the offending sector into the buffer below and do the I/O from there. +; + +INT13FRAME STRUC +oldbp dw ? +oldax dw ? +oldbx dw ? +oldcx dw ? +olddx dw ? +olddd dd ? +oldf dw ? +INT13FRAME ENDS + +;;Rev 3.30 Modification ----------------------------------------- +;To handle the INT 13h, AH = 8 Problem. +;Save Registers here. +Save_AX DW ? +Save_BX DW ? +Save_CX DW ? +Save_DX DW ? +Save_DI DW ? +Save_SI DW ? +Save_BP DW ? +Save_DS DW ? +Save_ES DW ? +Prev_DX DW ? +Save_Flag DW ? +;;End of Modification ----------------------------------------- + + +; +; Block13: +; +; Entry conditions: +; AH = function +; AL = number of sectors +; ES:BX = DMA address +; CX = packed track and sector +; DX = head and drive +; Output conditions: +; NO DMA violation. +; + Public Block13 +Block13 PROC FAR +; +; Let the opperation proceed. If there is a DMA violation, then we do things. +; + mov cs:PrevOper,AX ; save request + pushf ; preserve the flags + cmp AH,ROMFormat ; format request? + jnz Not_Format ; no, skip down + +; Set changed by format bit for all logical drives using this physical drive +;---------------------------------------------------------| +; Warning: Do Not Change the following. | +; It gets patched in at INIT time | + Public Changed_Patch +Changed_Patch: + mov word ptr cs:[FlagBits],fChanged_By_Format+fChanged + call Set_Changed_DL ; Indicate that media changed by format +; | +;---------------------------------------------------------| + +Not_Format: +;;Rev 3.30 Modification ----------------------------------------- + cmp ah, 8 ; Read Driver Parm ? + je Bus_Problem + cmp ah, 15h + je Bus_Problem + CALL ORIG13 ; SIMULATE INT 13 + JC GOTERR13_br ; ERROR? + RET 2 ; NO, RETURN AND CLEAR FLAGS + +GOTERR13_br: jmp Goterr13 + +;Some machines have a problem with Int 13h function=8 +;This function does not reset the common buses after the execution. +;To solve this problem, when we detect AH=8h, then we will save the result +;and will issue AH=1 (Read Status) call to reset the buses. + +Bus_Problem: + mov cs:Prev_DX, DX ;save orignal drive number + call Orig13 ;Do "Read drive parm" + + mov cs:Save_AX, AX ;Save registers,flag + mov cs:Save_BX, BX + mov cs:Save_CX, CX + mov cs:Save_DX, DX + mov cs:Save_DI, DI + mov cs:Save_SI, SI + mov cs:Save_BP, BP + mov cs:Save_DS, DS + mov cs:Save_ES, ES + pushf + pop cs:Save_Flag + + mov dx, cs:Prev_DX ;restore orignal drive + pushf + mov ah, 1 ;Read Status. + call Orig13 ;Reset the bus as a side effect + + mov AX, cs:Save_AX ;restore registers,flag + mov BX, cs:Save_BX + mov CX, cs:Save_CX + mov DX, cs:Save_DX + mov DI, cs:Save_DI + mov SI, cs:Save_SI + mov BP, cs:Save_BP + mov DS, cs:Save_DS + mov ES, cs:Save_ES + push cs:Save_Flag + popf + jc GotErr13 ;AH=8 had been an error? + ret 2 +; +; Some kind of error occurred. See if it is DMA violation +; +GotErr13: + pushf + cmp AH, 09h ; is error DMA error code? + JNZ CHECK_ECC + JMP GOTDMAERR +CHECK_ECC: + CMP AH,11H + JZ OK11 + POPF + RET 2 +; +; We have an error status 11h. This indicates an ECC-corrected error. Note +; that this indicates that the data is PROBABLY correct but not CERTAINLY +; correct. The ROMs on PC-1s and PC_XTs have a 'bug' in that if an ECC error +; occurs for a multi-sector read, only the sectors up to the one where the +; error occurred are read in. We have no way of knowing how many were read in +; this case, so we redo the operation, reading one sector at a time. If we +; get an ECC error on reading one sector, we ignore the error because the +; sector has been read in. +; + PUBLIC OK11 +OK11: +; popf ; restore flags +;;Rev 3.30 Modification ----------------------------------------- +; Here, it is better reset the system. So, we are going to +; call Orig13 again + mov ah, 0 + call Orig13 ;reset. Don't care about result +;;End of Modification ----------------------------------------- + + mov ax,cs:[PrevOper] ; Retrieve request +; +; This will provide a termination point. +; + cmp AL,1 ; If request for one sector, assume OK + jnz ECC_Err_Handle ; more than one sector -- jump down + xor AH,AH ; clear carry too! + ret 2 + + Public ECC_Err_Handle +ECC_Err_Handle: + SAVEREG + mov cs:[Number_Of_Sec],AL +Loop_ECC: + mov AX,CS:[PrevOper] ; set command to previos command + mov AL,1 ; but request only one sector +; +; we do reads one sector at a time. this ensures that we will eventually +; finish the request since ecc errors on 1 sector do read in that sector. +; +; we need some "intelligence" in the ecc handler to handle reads +; that attempt to read more sectors than are available on a particular +; track. +; we call check_wrap to set up the sector #, head # and cylinder # for +; this request. +; at this point, all registers are set up for the call to orig13, except +; that there maybe a starting sector number that is bigger than the number +; of sectors on a track. +; + + CALL Check_Wrap ; see if wrapping around cylinder + + pushf ; save flags + call ORIG13 ; call original rom-bios code +;;Rev 3.30 Modification ------------------------------------------------------ + JNC OK11_OP + CMP AH,11H ; ONLY ALLOW ECC ERRORS + JNZ OK11_EXIT_err ; Other error? + mov ah, 0 ; ECC error. Reset it again. + pushf + call Orig13 +OK11_Op: + dec cs:[Number_of_Sec] ; adjust number of sectors for one read + jz OK11_Exit ; all done? + inc CL ; advance sector number + inc BH ; add 200H to address + inc BH + jmp short Loop_ECC ; and around for reading another sector + +OK11_EXIT_err: + stc ; Set carry bit again. +;;End of Modification ------------------------------------------------------ + +OK11_Exit: + RESTOREREG + Ret 2 + + + +; +; we truly have a DMA violation. Restore register AX and retry the +; operation as best we can. +; +GotDMAErr: + pop AX ; clean up stack + mov AX,cs:PrevOper ; restore command + sti ; restore interrupts + cmp AH,ROMRead ; determine the command + jb IntDone + cmp AH,ROMVerify + jz IntVerify + cmp AH,ROMFormat + jz IntFormat + ja IntDone +; +; We are doing a read/write call. Check for DMA problems +; + SaveReg ; save register we overwrite + push BP + mov BP,SP + mov DX,ES ; Check for 64k boundary error + + shl DX,1 + shl DX,1 + shl DX,1 + shl DX,1 ; Segment converted to absolute address + + add DX,BX ; Combine with offset + add DX,511 ; simulate a transfer +; +; If carry is set, then we are within 512 bytes of the end of the segment. +; We skip the first transfer and perform the remaining buffering and transfer +; + JNC NO_SKIP_FIRST + mov DH,byte ptr [bp.olddx+1] ; set correct head number + jmp Buffer + +NO_SKIP_FIRST: +; +; DX is the physical 16 bits of start of transfer. Compute remaining +; sectors in segment. +; + shr DH,1 ; DH = number of sectors before address + mov AH,128 ; AH = max number of sectors in segment + sub AH,DH +; +; AH is now the number of sectors that we can successfully write in this +; segment. If this number is above or equal to the requested number, then we +; continue the operation as normal. Otherwise, we break it into pieces. +; + cmp AH,AL ; can we fit it in? + jb DoBlock ; no, perform blocking. +; +; Yes, the request fits. Let it happen +; + MOV DH,BYTE PTR [BP.OLDDX+1] ; SET UP HEAD NUMBER + call DoInt + jmp Bad13 +; +; Verify the given sectors. Place the buffer pointer into our space. +; +IntVerify: + SaveReg + push CS + pop ES +DoSimple: + mov BX,OFFSET DiskSector + pushf + call Orig13 + RestoreReg + ret 2 + +; +; Format operation. Copy the parameter table into memory +; +IntFormat: + SaveReg + SaveReg + push ES + push CS + pop ES + pop DS + mov SI,BX + mov DI,OFFSET DiskSector + call Move + RestoreReg + jmp DoSimple +; +; Inline continuation of operation +; +IntDone: + jmp Orig13 +; +; We can't fit the request into the entire block. Perform the operation on +; the first block. +; +; +; DoBlock is modified to correctly handle multi-sector disk I/O. +; Old DoBlock had added the number of sectors I/Oed (Ah in Old DoBlock) after +; the DoInt call to CL. Observing only the lower 6 bits of CL(=max. 64) can +; represent a starting sector, if AH was big, then CL would be clobbered. +; By the way, we still are going to use CL for this purpose since Checkwrap +; routine will use it as an input. To prevent CL from being clobbered, a +; safe number of sectors should be calculated like "63 - # of sectors/track". +; DoBlock will handle the first block of requested sectors within the +; boundary of this safe value. + +;Try to get the # of sectors/track from BDS via Rom drive number. +;For any mini disks installed, here we have to pray that they have the +;same # of sector/track as the main DOS partition disk drive. + +DoBlock: +;;Rev 3.30 Modification ------------------------------------------------------ + Message ftestDisk,<"!!!DMA DoBlock!!!"> + + mov dx, word ptr [bp.olddx] ;set head # + push di + push ds + push ax ;AH=# of sectors before DMA err + ;AL - User requeseted # of sectors + mov byte ptr CS:[phys_drv],1 + mov al, dl + call SetDrive ;get BDS pointer for this DISK. + pop ax + mov byte ptr CS:[phys_drv],0 + test word ptr [DI].Flags, fNon_Removable ;don't have to worry + jnz DoBlockHard ;about floppies. They are track by + ;track operatiions + mov al, ah ;set al = ah for floppies + jmp short DoBlockCont +DoBlockHard: + push cx + xor cx, cx + mov cx, [DI].SecLim ;# of sectors/track + mov ch, 63 + sub ch, cl + mov al, ch + xchg ah, al ;now ah - safe # of sectors + ;al - # of sectors before DMA err + pop cx +DoBlockCont: + pop ds + pop di +DoBlockContinue: + Message ftestDisk,<"%%DMA DoBlock Loop%%"> + cmp ah, al ;if safe_# >= #_of_sectors_to_go_before DMA, + jae DoBlocklast ;then #_of_sectors_to_go as it is for DoInt. + push ax ;save AH, AL + mov al, ah ;Otherwise, set al to ah to operate. + jmp short DoBlockDoInt ;DoInt will set AH to a proper function in [BP.Oldax] +DoBlocklast: + mov ah, al + push ax ;save AH +DoBlockDoInt: ;let AH=AL=# of sectors this shot + CALL DoInt + JC BAD13 ;something happened, bye! + pop ax + SUB BYTE PTR [BP.oldax], AH ;decrement by the successful operation + ADD CL,AH ;advance sector number. Safety gauranteed. + ADD BH,AH ;advance DMA address + ADD BH,AH ;twice for 512 byte sectors. + cmp ah, al ;check the previous value + je Buffer ;if #_of_sectors_to_go < safe_#, then we are done already. + sub al, ah ;otherwise, #_sector_to_go = #_of_sector_to_go - safe_# + call Check_Wrap ;get new CX, DH for the next operation. + jmp short DoBlockContinue ;handles next sectors left. +;;End of Modification ------------------------------------------------------ +; +Buffer: + push BX + mov AH,BYTE PTR [BP.oldax+1] + cmp AH,ROMWrite + jnz DoRead +; +; Copy the offending sector into local buffer +; + SaveReg + push CS ; exchange segment registers + push ES + pop DS + pop ES + mov DI,OFFSET DiskSector ; where to move + push DI ; save it + mov SI,BX ; source + call Move + pop BX ; new transfer address + RestoreReg + mov AL,1 + mov DL,byte ptr [BP.olddx] ; set drive number + call Check_Wrap ; check for head or cylinder wrap + +; +; AH is function +; AL is 1 for single sector transfer +; ES:BX is local transfer addres +; CX is track/sector number +; DX is head/drive number +; SI,DI unchanged +; + CALL DoInt + RestoreReg + jc Bad13 ; go clean up + jmp SHORT DoTail +; +; Reading a sector. Do INT first, then move things around +; +DoRead: + SaveReg + push CS + pop ES + mov BX,OFFSET DiskSector + mov AL,1 + mov DL,byte ptr [BP.olddx] ; set drive number + call Check_Wrap ; check for head or cylinder wrap + +; +; AH = function +; AL = 1 for single sector +; ES:BX points to local buffer +; CX, DX are track/sector, head/drive +; + CALL DoInt + RestoreReg + jc Bad13 ; error => clean up + SaveReg + push CS + pop DS + mov DI,BX + mov SI,OFFSET DiskSector + call Move + RestoreReg +; +; Note the fact that we've done 1 more sector +; +DoTail: + pop BX ; retrieve new DMA area + add BH,2 ; advance over sector + inc CX + mov AL,BYTE PTR [BP.oldAX] + clc + dec AL + jz Bad13 ; no more I/O + mov DL,byte ptr [BP.olddx] ; set drive number + call Check_Wrap ; check for head or cylinder wrap + call DoInt +; +; We are done. AX has the final code; we throw away what we got before +; +Bad13: + mov SP,BP + RestoreReg + ret 2 +Block13 ENDP + + + + + PAGE + + include msioctl.inc + + PAGE +; +; Check_Wrap is a routine that adjusts the starting sector, starting head +; and starting cylinder for an Int 13 request that requests I/O of a lot +; of sectors. It only does this for fixed disks. It is used in the sections +; of code that handle ECC errors and DMA errors. It is necessary, because +; ordinarily the ROM would take care of wraps around heads and cylinders, +; but we break down a request when we get an ECC or DMA error into several +; I/O of one or more sectors. In this case, we may already be beyond the +; number of sectors on a track on the medium, and the request would fail. +; +; Input conditions: +; ALL registers set up for an Int 13 request. +; +; Output: +; - contains starting head number for request +; - contains starting sector and cylinder numbers +; (The above may or may not have been changed, and are 0-based) +; All other registers preserved. +; + public check_wrap +Check_Wrap: + Message ftestDisk,<"Entering Check_Wrap...",cr,lf> + SaveReg + mov byte ptr cs:[Phys_drv],1;Use phys. drive in AL to get BDS + mov al,dl ; put drive number in AL for get BDS + call SetDrive ; Get pointer to BDS for drive. + mov byte ptr cs:[phys_drv],0; Restore flag to use Logical Drive + jc No_wrap ; Do nothing if wrong phys. drive + + test word ptr [di].Flags,fNon_Removable + jz No_wrap ; No wrapping for removable media + MOV BX,[DI].SECLIM + MOV AX,CX + AND AX,003FH ; EXTRACT SECTOR NUMBER + cmp ax,bx ; If Wrap + jbe No_wrap + + div bl ; AH=new sector#, AL = # of head wraps + +; We need to be careful here. If the new sector number == 0, then we are +; on the last sector on that track + or ah,ah + jnz Not_on_Bound + + mov ah,bl ; set sector = SECLIM if on Bndry + dec al ; and decrement Num. head wraps + +Not_on_Bound: + and CL,0C0H ; zero out sector # + + or CL,ah ; OR in new sector # + xor ah,ah ; AX = # of head wraps + inc ax + add al,DH ; add in starting head # + adc ah,0 ; catch any carry + CMP AX,[DI].HDLIM ; are we going to wrap around a head? + jbe No_Wrap_Head ; Do not lose new head number!! + + push DX ; preserve drive number and head number + xor dx,dx + mov bx,[DI].HDLIM + div bx ; DX=new head #, AX=# of cylinder wraps +; Careful here! If new head # is 0, then we are on the last head. + or dx,dx + jnz No_Head_Bound + + mov dx,bx ; On boundary. Set to HDLIM +; If we had some cylinder wraps, we need to reduce them by one!! + or ax,ax + jz No_Head_Bound + + dec ax ; Reduce number of cylinder wraps +No_Head_Bound: + mov bh,dl ; bh has new head number + POP DX ; restore drive number and head number + + dec bh ; get it 0-based + mov DH,bh ; set up new head number in DH + + mov bh,CL + and bh,3FH ; preserve sector number + mov bl,6 + xchg cl,bl + shr bl,cl ; get ms cylinder bits to ls end + + ADD CH,AL ; ADD IN CYLINDER WRAP + adc bl,ah ; add in high byte + shl bl,cl ; move up to ms end + xchg bl,cl ; restore cylinder bits into CL + or CL,bh ; OR in sector number + +No_Wrap: + clc ; reset carry + RestoreReg + RET + +No_Wrap_Head: + mov DH,al ; Do not lose new head number + dec DH ; get it 0-based + jmp short No_Wrap + +; +; INT_2F_13: +; This code is chained into the INT_2F interrupt during bios +; initialization. It allows the user to change the ORIG13 int_13 vector + +; INT_2F_13: +; This code is chained into the INT_2F interrupt during bios +; initialization. It allows the user to change the ORIG13 int_13 vector +; after booting. This allows testing and implementation of custom int_13 +; handlers, without giving up MS-DOS error recovery +; +; Entry Conditions +; AH == RESET_Int_13 (13h) +; DS:DX == Address of New INT_13 Handler +; ES:BX == Address of New INT_13 vector used by WARM BOOT +; (INT 19) +; +; Exit Conditions +; Orig13 == Address of new Int_13 Handler +; DS:DX == Old ORIG13 value +; ES:BX == Old OLD13 value + + ASSUME CS:CODE,DS:Nothing,ES:nothing,SS:NOTHING + + Public INT_2F_13 +INT_2F_13 Proc Far + + cmp AH,13h ; IF (interrupt_value != Reset_Int_13) + je Chg_Orig13 + jmp CS:[Next2f_13] ; THEN Continue on Int_2F chain + +Chg_Orig13: ; ELSE + push word ptr cs:[Orig13] ; Save Old value of OLD13 and + push word ptr cs:[Orig13 + 2]; ORIG13 so that we can + + Push word ptr cs:[OLD13] ; Return them to caller + Push word ptr cs:[OLD13 + 2] + + mov Word Ptr CS:[Orig13],DX ; Orig13 := Addr. Of New INT_13 + ; Vector + mov Word Ptr CS:[Orig13+2],DS + + mov Word Ptr CS:[Old13],BX ; Old13 := Addr. Of New + ; Boot_13 vector + mov Word Ptr CS:[Old13+2],ES + + pop ES ; ES:BX := Old OLD13 vector + pop BX + + pop DS ; DS:DX := Old ORIG13 vector + pop DX + + iret ; END else + +Int_2F_13 ENDP + + + + + + +Move Proc Near + push CX + mov CX,512/2 + cld + rep MOVSW + pop CX + ret +Move Endp + + + + +DoINT proc NEAR + mov DL,byte ptr [BP.olddx] + xor AH,AH + or AL,AL + jz DoIntDone + mov AH,BYTE PTR [BP.oldax+1] + push [BP.oldf] + call Orig13 + pushf + pop [BP.oldf] +DoIntDone: + ret +DoInt endp + +CODE ENDS + END diff --git a/UPDSRC/BIOS/MSINIT.ASM b/UPDSRC/BIOS/MSINIT.ASM new file mode 100644 index 0000000..cef2022 --- /dev/null +++ b/UPDSRC/BIOS/MSINIT.ASM @@ -0,0 +1,2228 @@ + +; modification history +; +; 3.21 sp added pushf-popf fix around NoParms to fix bug + +;;Rev 3.30 Modification ----------------------------------------------- + test = 0 + include msgroup.inc ;define code segment + include dskprm.inc + include msequ.inc + include msmacro.inc + include msextrn.inc + include biostruc.inc + include cmosequ.inc + + EXTRN OLD13:DWORD + +; THE FOLLOWING LABEL DEFINES THE END OF THE AT ROM PATCH. THIS IS USED +; AT CONFIGURATION TIME. +; Warning!!! This code will be dynamically relocated by MSINIT. + + PUBLIC ENDATROM ;NOT REFERENCES EXTERNALLY, BUT + ; JUST TO CAUSE ENTRY IN LINK MAP +ENDATROM LABEL BYTE + +;CMOS Clock setting support routines used by MSCLOCK. +;Warning!!! This code will be dynamically relocated by MSINIT. + + EXTRN base_century:byte + EXTRN base_year:byte + EXTRN month_tab:byte + + public Daycnt_to_day ;for real time clock support +Daycnt_to_day proc near ;for real time clock support +;Entry: [DAYCNT] = number of days since 1-1-80 +;Return: CH=centry in BCD, CL=year in BCD, DH=month in BCD, DL=day in BCD + + push [daycnt] ;save daycnt + cmp daycnt, (365*20+(20/4)) ;# days from 1-1-1980 to 1-1-2000 + jae century20 + mov base_century, 19 + mov base_year, 80 + jmp years +century20: ;20th century + mov base_century, 20 + mov base_year, 0 + sub daycnt, (365*20+(20/4)) ;adjust daycnt +years: + xor dx, dx + mov ax, daycnt + mov bx, (366+365*3) ;# of days in a Leap year block + div bx ;AX = # of leap block, DX=daycnt + mov daycnt, dx ;save daycnt left +; or ah, ah ;ax should be less than 256 +; jz OK1 +; jmp Erroroccur +;OK1: + mov bl,4 + mul bl ;AX=# of years. Less than 100 + add base_year, al ;So, ah = 0. Adjust year + inc daycnt ;set daycnt to 1 base + cmp daycnt, 366 ;daycnt=remainder of leap year bk + jbe Leapyear ;within 366+355+355+355 days. + inc base_year ;if daycnt <= 366, then leap year + sub daycnt, 366 ;else daycnt--, base_year++; + ;And next three years are normal + mov cx, 3 +Regularyear: + cmp daycnt, 365 ;for(i=1; i>3 or daycnt <=365;i++) + jbe YearDone ;{if (daycnt > 365) + inc base_year ; { daycnt -= 365 + sub daycnt, 365 ; } + loop regularyear ;} +; jmp Erroroccur ;cannot come to here +Leapyear: + mov byte ptr month_tab+1,29 ;leap year. change month table. +Yeardone: + xor bx,bx + xor dx,dx + mov ax, daycnt + mov si, offset month_tab + mov cx, 12 +Months: + inc bl ; + mov dl, byte ptr ds:[si] ;cmp daycnt for each month til fit + cmp ax, dx ;dh=0. + jbe Month_done + inc si ;next month + sub ax, dx ;adjust daycnt + loop Months +; jmp Erroroccur +Month_done: + mov byte ptr month_tab+1, 28 ;restore month table value + mov dl, bl + mov dh, base_year + mov cl, base_century ;al=day,dl=month,dh=year,cl=cntry + call word ptr BinToBCD ;To save 15 bytes, Bin_To_BCD proc + ;was rel from Daycnt_to_Day proc. +; call Bin_to_bcd ;convert "day" to bcd + xchg dl, al ;dl = bcd day, al = month + call word ptr BinToBCD +; call Bin_to_bcd + xchg dh, al ;dh = bcd month, al = year + call word ptr BinToBCD +; call Bin_to_bcd + xchg cl, al ;cl = bcd year, al = century + call word ptr BinToBCD +; call Bin_to_bcd + mov ch, al ;ch = bcd century + pop [daycnt] ;restore original value + ret +Daycnt_to_day endp + + public EndDaycntToDay +EndDaycntToDay label byte + + public Bin_to_bcd +Bin_to_bcd proc near ; real time clock sup +;Convert a binary input in AL (less than 63h or 99 decimal) +;into a bcd value in AL. AH destroyed. + push cx + xor ah, ah + mov cl, 10 + div cl ;al=high digit bcd, ah=low digit bcd + mov cl, 4 + shl al, cl ;mov the high digit to high nibble + or al, ah + pop cx + ret +Bin_to_bcd endp + + Public EndCMOSClockset ;End of routines for CMOS clock +EndCMOSClockset label byte +; + + EXTRN INT6C_RET_ADDR:DWORD ; RETURN ADDRESS FROM INT 6C + EXTRN BIN_DATE_TIME:BYTE + EXTRN MONTH_TABLE:WORD + EXTRN DAYCNT2:WORD + EXTRN FEB29:BYTE + EXTRN TimeToTicks:Word ;indirect intra-segment call add + + EVENB +; +; THE K09 REQUIRES ROUTINES FOR READING THE CLOCK BECAUSE OF THE SUSPEND/ +; RESUME FACILITY. THE SYSTEM CLOCK NEEDS TO BE RESET AFTER RESUME. +; + ASSUME ES:NOTHING + +; THE FOLLOWING ROUTINE IS EXECUTED AT RESUME TIME WHEN THE SYSTEM +; POWERED ON AFTER SUSPENSION. IT READS THE REAL TIME CLOCK AND +; RESETS THE SYSTEM TIME AND DATE, AND THEN IRETS. +; Warning!!! This code will be dynamically relocated by MSINIT. +INT6C PROC FAR + PUSH CS + POP DS + + ASSUME DS:CODE + + POP WORD PTR INT6C_RET_ADDR ; POP OFF RETURN ADDRESS + POP WORD PTR INT6C_RET_ADDR+2 + POPF + CALL READ_REAL_DATE ; GET THE DATE FROM THE CLOCK + CLI + MOV DS:DAYCNT,SI ; UPDATE DOS COPY OF DATE + STI + CALL READ_REAL_TIME ; GET THE TIME FROM THE RTC + CLI + MOV AH, 01h ; COMMAND TO SET THE TIME + INT 1Ah ; CALL ROM-BIOS TIME ROUTINE + STI + JMP INT6C_RET_ADDR ; LONG JUMP + +INT6C ENDP + + + INCLUDE READCLOCK.INC + INCLUDE CLOCKSUB.INC + + PUBLIC ENDK09 ;NOT REFERENCES EXTERNALLY, BUT + ; JUST TO CAUSE ENTRY IN LINK MAP +ENDK09 LABEL BYTE + ASSUME DS:NOTHING,ES:NOTHING +;;End of Modification ----------------------------------------------- + +;------------------------------------------------------------------------ +; : +; System initiailzation : +; : +; The entry conditions are established by the bootstrap : +; loader and are considered unknown. The following jobs : +; will be performed by this module: : +; : +; 1. All device initialization is performed : +; 2. A local stack is set up and DS:SI are set : +; to point to an initialization table. Then : +; an inter-segment call is made to the first : +; byte of the dos : +; 3. Once the dos returns from this call the ds : +; register has been set up to point to the start : +; of free memory. The initialization will then : +; load the command program into this area : +; beginning at 100 hex and transfer control to : +; this program. : +; : +;------------------------------------------------------------------------ + +; DRVFAT must be the first location of freeable space! + EVENB +DRVFAT DW 0000 ; Drive and FAT ID of DOS +BIOS$ DW 0000 ; First sector of data +DOSCNT DW 0000 ; How many sectors to read +fBigFAT DB 0 ; Flags for drive +FatLen DW ? ; number of sectors in FAT. +FatLoc DW ? ; seg addr of fat sector + +;;Rev 3.30 Modification ----------------------------------------------- +; THE FOLLOWING TWO BYTES ARE USED TO SAVE INFO RETURNED BY INT 13, AH=8 +; CALL TO DETERMINE DRIVE PARAMETERS. +NUM_HEADS DB 2 ; NUMBER OF HEADS RETURNED BY ROM +SEC_TRK DB 9 ; SEC/TRK RETURNED BY ROM +NUM_CYLN DB 40 ; NUMBER OF CYLINDERS RET BY ROM + + public Model_Byte +MODEL_BYTE DB 0FFH ; MODEL BYTE. SET UP AT INIT TIME. + ; FF - PC-1, EXPANSION, OLD PC-2 + ; FE - NEWER PC-2 (64/256K PLANAR) + ; FD - + ; FC - + public Secondary_Model_Byte +Secondary_Model_Byte db 0 +;;End of Modification ----------------------------------------------- + +BOOTBIAS = 200H + EVENB +DiskTable DW 512, 0100h, 64, 0 + DW 2048, 0201h, 112, 0 + DW 8192, 0402h, 256, 0 + DW 32680, 0803h, 512, 0 + DW 65535, 1004h, 1024, 0 + +DiskTable2 DW 32680, 0803h, 512, 0 + DW 65535, 0402h, 512, fBIG + +;;Rev 3.30 Modification ----------------------------------------------- +;************************************************************************* +;Variables for Mini disk initialization +;************************************************************************* +End_Of_BDSM dw ? ;offset value of the ending add + ;of BDSM table. Needed to figure + ;the Final_DOS_Location. +numh db 0 ;number of hard files +mininum db 0 ;logical drive num for mini disk +num_mini_dsk db 0 ;# of mini disk installed +Rom_Minidsk_num db 80h ;physical mini disk number +Mini_HDLIM dw 0 +Mini_SECLIM dw 0 +Mini_BPB_ptr dw 0 ;temporary variable used to save + ;Mini Disk BPB pt add in DskDrvs. +;;End of Modification ----------------------------------------------- + +Bios_Date DB '01/10/84',0 + +; +; The following are the recommended BPBs for the media that we know of so +; far. + +; 48 tpi diskettes + EVENB +BPB48T DW 512 + DB 2 + DW 1 + DB 2 + DW 112 + DW 2*9*40 + DB 0FDH + DW 2 + DW 9 + DW 2 + DD 0 ;hidden sectors - sp + DD 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved + +; 96tpi diskettes + EVENB +BPB96T DW 512 + DB 1 + DW 1 + DB 2 + DW 224 + DW 2*15*80 + DB 0f9H + DW 7 + DW 15 + DW 2 + DD 0 ;hidden sectors - sp + DD 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved + +BPBSIZ = $-BPB96T + +; 3 1/2 inch diskette BPB + EVENB +BPB35 DW 512 + DB 2 + DW 1 ; Double sided with 9 sec/trk + DB 2 + DW 70h + DW 2*9*80 + DB 0f9H + DW 3 + DW 9 + DW 2 + DD 0 ;hidden sectors - sp + DD 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved + + + EVENB +BPBTable dw BPB48T ; 48tpi drives + dw BPB96T ; 96tpi drives + dw BPB35 ; 3.5" drives + ;dw BPB48T ; Not used - 8" drives + ;dw BPB48T ; Not Used - 8" drives + ;dw BPB48T ; Not Used - hard files + ;dw BPB48T ; Not Used - tape drives + ;dw BPB48T ; Not Used - Other + +PatchTable LABEL BYTE + DW 10,media_patch + DW 3,getbp1_patch + DW 3,SET_PATCH + DW 3,DiskIO_Patch + DW 3,DSKErr + DW 10,Changed_Patch + DW 3,INIT_PATCH + DW 0 + + ASSUME DS:NOTHING,ES:NOTHING + +; +; Entry from boot sector. The register contents are: +; DL = INT 13 drive number we booted from +; CH = media byte +; BX = First data sector on disk (0-based) +; +Public INIT +INIT PROC NEAR + MESSAGE FTESTINIT,<"MSBIO",CR,LF> ;3.30 + CLI + XOR AX,AX + MOV DS,AX +; +; Preserve original int 13 vector +; We need to save INT13 in two places in case we are running on an AT. +; On ATs we install the IBM supplied ROM_BIOS patch DISK.OBJ which hooks +; INT13 ahead of ORIG13. Since INT19 must unhook INT13 to point to the +; ROM INT13 routine, we must have that ROM address also stored away. +; + MOV AX,DS:[13h*4] + MOV WORD PTR Old13,AX + MOV WORD PTR Orig13,AX + MOV AX,DS:[13h*4+2] + MOV WORD PTR Old13+2,AX + MOV WORD PTR Orig13+2,AX +; +; Set up INT 13 for new action +; + MOV WORD PTR DS:[13h*4],OFFSET Block13 + MOV DS:[13h*4+2],CS +; +; Preserve original int 19 vector +; + MOV AX,DS:[19h*4] + MOV WORD PTR Orig19,AX + MOV AX,DS:[19h*4+2] + MOV WORD PTR Orig19+2,AX +; +; Set up INT 19 for new action +; + MOV WORD PTR DS:[19h*4],OFFSET int19 + MOV DS:[19h*4+2],CS + STI + + + int 11h ; rom-bios equipment determination + ROL AL,1 ;PUT BITS 6 & 7 INTO BITS 0 & 1 + ROL AL,1 + AND AX,3 ;ONLY LOOK AT BITS 0 & 1 + JNZ NOTSINGLE ;ZERO MEANS SINGLE DRIVE SYSTEM + INC AX ;PRETEND IT'S A TWO DRIVE SYSTEM + INC CS:SINGLE ;REMEMBER THIS +NOTSINGLE: + INC AX ;AX HAS NUMBER OF DRIVES, 2-4 + ;IS ALSO 0 INDEXED BOOT DRIVE IF WE + ; BOOTED OFF HARD FILE + mov CL, AL ; save number of diskette drives in CL + test DL, 80h ; booted from hard disk ? + jnz GotHrd ; yes, jump down + xor AX, AX ; no - indicate boot from drive A +GotHrd: + + ; At this point the registers contain these values: + ; AX = 0-based drive we booted from + ; BX = the logical number of the first data sector on the disk + ; CL = number of floppies including logical one + ; CH = media byte + ; + + Message fTestINIT,<"Init",CR,LF> + +; +; set up local stack +; + xor DX,DX + cli ; turn interrupts off while manupulating stack + mov SS,DX ; set stack segment register + mov SP,700h ; set stack pointer + sti ; turn interrupts on +ASSUME SS:NOTHING + + ; preserve some of the values in registers + + push CX ; save number of floppies and media byte + mov BIOS$,BX ; save first data sector + mov AH,CH ; FAT ID to AH too + push AX ; save boot drive number, and media byte +;;Rev 3.30 Modification ----------------------------------------------- +; Let Model_byte, Secondary_Model_Byte be set here!!! + mov ah,0c0h ; return system environment + int 15h ; call ROM-Bios routine + jc No_Rom_System_Conf ; just use Model_Byte + cmp ah, 0 ; double check + jne No_Rom_System_Conf + mov al, ES:[BX.bios_SD_modelbyte] ;get the model byte + mov [Model_Byte], al + mov al, ES:[BX.bios_SD_scnd_modelbyte] ;secondary model byte + mov [Secondary_Model_Byte], al + jmp short Turn_Timer_On +No_Rom_System_Conf: + MOV SI,0FFFFH ;MJB001 + MOV ES,SI ;MJB001 + MOV AL,ES:[0EH] ; GET MODEL BYTE ARR 2.41 + MOV MODEL_BYTE,AL ; SAVE MODEL BYTE ARR 2.41 +;;End of Modification ----------------------------------------------- +Turn_Timer_On: + mov AL,EOI + out AKPORT,AL ; turn on the timer + + Message fTestINIT,<"COM devices",CR,LF> + +;;Rev 3.30 Modification ----------------------------------------------- + mov si,offset COM4DEV + call AUX_INIT + mov si,offset COM3DEV + call AUX_INIT +;;End of Modification ----------------------------------------------- + mov SI,OFFSET COM2DEV + call AUX_INIT ;INIT COM2 + mov SI,OFFSET COM1DEV + call AUX_INIT ;INIT COM1 + + Message fTestINIT,<"LPT devices",CR,LF> + mov SI,OFFSET LPT3DEV + call PRINT_INIT ;INIT LPT3 + mov SI,OFFSET LPT2DEV + call PRINT_INIT ;INIT LPT2 + mov SI,OFFSET LPT1DEV + call PRINT_INIT ;INIT LPT1 + + xor DX,DX + mov DS,DX ;TO INITIALIZE PRINT SCREEN VECTOR + mov ES,DX + + xor AX,AX + mov DI,INITSPOT + stosw ;INIT four bytes to 0 + stosw + + mov AX,CS ;FETCH SEGMENT + + mov DS:WORD PTR BRKADR,OFFSET CBREAK ;BREAK ENTRY POINT + mov DS:BRKADR+2,AX ;VECTOR FOR BREAK + + mov DS:WORD PTR CHROUT*4,OFFSET WORD PTR OUTCHR + mov DS:WORD PTR CHROUT*4+2,AX + + Message fTestINIT,<"Interrupt vectors",CR,LF> + mov DI,4 + mov BX,OFFSET INTRET ;WILL INITIALIZE REST OF INTERRUPTS + xchg AX,BX + stosw ;Location 4 + xchg AX,BX + stosw ;INT 1 ;Location 6 + add DI,4 + xchg AX,BX + stosw ;Location 12 + xchg AX,BX + stosw ;INT 3 ;Location 14 + xchg AX,BX + stosw ;Location 16 + xchg AX,BX + stosw ;INT 4 ;Location 18 + + mov DS:WORD PTR 500H,DX ;SET PRINT SCREEN & BREAK =0 + mov DS:WORD PTR LSTDRV,DX ;clean out last drive spec + + Message fTestINIT,<"Disk parameter table",CR,LF> + + EXTRN MotorStartup:byte + EXTRN SettleCurrent:byte + + mov SI,WORD PTR DS:DSKADR ; ARR 2.41 + mov DS,WORD PTR DS:DSKADR+2 ; DS:SI -> current table ARR 2.41 + + mov DI,SEC9 ; ES:DI -> New Table ARR 2.41 + mov CX,SIZE DISK_PARMS ; ARR 2.41 + rep MOVSB ; Copy Table ARR 2.41 + push ES ; ARR 2.41 + pop DS ; DS = 0 ARR 2.41 + + mov WORD PTR DS:DSKADR,SEC9 ; ARR 2.41 + mov WORD PTR DS:DSKADR+2,DS ; Point disk parm vector to new table + ; ARR 2.41 + + +;----------------------------------------------- +; +; THE FOLLOWING DEPEND ON THE TYPE OF MACHINE. +; + CMP MODEL_BYTE,0FDH ; IS THIS AN OLD ROM? ARR 2.41 + JB NO_DIDDLE ; NO ARR 2.41 + MOV WORD PTR DS:(SEC9 + DISK_HEAD_STTL),0200H+NORMSETTLE + ; SET HEAD SETTLE AND MOTOR START + ; ON PC-1 PC-2 PC-XT HAL0 ARR 2.41 + MOV DS:(SEC9 + DISK_SPECIFY_1),0DFH + ; SET 1ST SPECIFY BYTE + ; ON PC-1 PC-2 PC-XT HAL0 ARR 2.41 +NO_DIDDLE: ; ARR 2.41 + +;--------------------------------------------------------------bug330a08 +; sp - fix from IBM +; + mov al,byte ptr ds:(sec9+disk_motor_strt) + mov cs:MotorStartup,al + + mov al,byte ptr ds:(sec9+disk_head_sttl) + mov cs:SettleCurrent,al + +;--------------------------------------------------------------bug330a08 + + int 12h ; call rom-bios for memory size + mov CL, 6 ; get ready for shift + shl AX, CL ; change from K to 16 byte blocks + pop CX ; restore CX + mov DRVFAT, CX + push AX + mov dx,ds:(7C00h + 16h) ; number of sectors/fat from boot sec + xor dh,dh + mov FatLen,DX +; +; Convert sector count to paragraph count:512 bytes / sec / 16 bytes / para +; = 32 para /sector +; +;;Rev 3.30 Modification ----------------------------------------------- + SHL DX,1 + SHL DX,1 + SHL DX,1 + SHL DX,1 + SHL DX,1 +;;End of Modification ----------------------------------------------- + SUB AX,dx ; room for FAT + MOV FatLoc,AX ; location to read fat + POP AX + + MOV DX,SYSINITSEG + MOV DS,DX + + ASSUME DS:SYSINITSEG + + MOV WORD PTR DEVICE_LIST,OFFSET CONHeader + MOV WORD PTR DEVICE_LIST+2,CS + +; Allocation of buffers has moved to SYSINIT - Aug 19/85 BAS + +;DEF_BUFF: + + MOV MEMORY_SIZE,AX + INC CL + MOV DEFAULT_DRIVE,CL ;SAVE DEFAULT DRIVE SPEC + +;DOSSEG = ((((OFFSET END$)-(OFFSET START$))+15)/16)+BIOSEG+SYSIZE + +; BAS DEBUG +;MOV CURRENT_DOS_LOCATION,((((OFFSET END$)-(OFFSET START$))+15)/16)+SYSIZE + MOV AX, OFFSET END$ + SUB AX, OFFSET START$ + ADD AX, 15 + RCR AX, 1 ; DIVIDE BY 16 + SHR AX, 1 + SHR AX, 1 + SHR AX, 1 + ADD AX, SYSIZE + ADD AX, CODE + MOV Current_DOS_Location, AX +; BAS DEBUG +; ADD Current_DOS_Location,CODE + +; +; IMPORTANT: Some old IBM hardware generates spurious INT F's due to bogus +; printer cards. We initialize this value to point to an IRET ONLY IF +; +; 1) The original segment points to storage inside valid RAM. +; +; 2) The original segment is 0F000:xxxx +; +; Theses are capricious requests from our OEM for reasons behind them, read +; the DCR's for the IBM DOS 3.2 project. +; + push ax + +ASSUME ES:SYSINITSEG, DS:NOTHING + mov ax,SYSINITSEG + mov es,ax + xor ax,ax + mov ds,ax + + mov ax,word ptr ds:(0fH*4+2) ; segment for Int 15 + + cmp ax,es:MEMORY_SIZE ; Condition 1 + jna ResetIntF + + cmp ax, 0F000h ; Condition 2 + jne KeepIntF + +ResetIntF: + mov word ptr ds:[0FH*4],offset INTRET + mov word ptr ds:[0FH*4+2],cs + +KeepIntF: + pop ax +; +; END IMPORTANT +; + +;************************************************************** +; WILL INITIALIZE THE NUMBER OF DRIVES +; AFTER THE EQUIPMENT CALL (INT 11H) BITS 6&7 WILL TELL +; THE INDICATIONS ARE AS FOLLOWS: +; +; BITS 7 6 DRIVES +; 0 0 1 +; 0 1 2 +; 1 0 3 +; 1 1 4 +;************************************************************** + PUSH CS + POP DS + PUSH CS + POP ES + + ASSUME DS:CODE,ES:CODE + + call CMOS_Clock_Read ;Before doing anything if CMOS clock, + ;then set the system time accordingly. + ;Also, reset the cmos clock rate. + + Message fTestINIT,<"Disk devices",CR,LF> + + XOR SI,SI + MOV WORD PTR [SI],OFFSET HARDDRV ;set up pointer to hdrive + + POP AX ;number of floppies and FAT ID + XOR AH,AH ; Chuck FAT ID byte + MOV HARDNUM,AL ;Remember which drive is hard disk + MOV DRVMAX,AL ;And set initial number of drives + SHL AX,1 ;Two bytes per address + MOV DI,OFFSET DSKDRVS + ADD DI,AX ;Point to hardfile location + MOV SI,OFFSET HDSKTAB + MOVSW ;Two addresses to move + MOVSW + MESSAGE FTESTINIT,<"BEFORE INT 13",CR,LF> + mov DL, 80h ; tell rom bios to look at hard drives + mov AH, 8h ; set command to get drive parameter + int 13h ; call ROM-BIOS to get number of drives + jc ENDDRV ; old, rom therefore no hard disks + mov HNUM, DL ; save number of hard drives in HNUM + +ENDDRV: + Message fTestINIT,<"Setting up BDSs",CR,LF> + +; +; Scan the list of drives to determine their type. We have three flavors of +; diskette drives: +; +; 48tpi drives We do nothing special for them +; 96tpi drives Mark the fact that they have changeline support. +; 3 1/4 drives Mark changeline support and small. +; +; The following code uses registers for certain values: +; DL - Physical Drive +; DS:DI - points to current BDS +; CX - Flag bits for BDS +; DH - Form Factor for the drive (1 - 48tpi, 2 - 96tpi, 3 - 3.5" medium) +; + XOR DL,DL ; start out with drive 0. + push cs + pop ds + ASSUME DS:CODE + MOV EOT,9 + mov di,offset Start_BDS +loop_drive: + cmp dl,drvmax + jb got_more + jmp Done_Drives +got_more: + xor cx,cx ; zero all flags + mov di,word ptr [di].link ; get next BDS + mov dh,ff48tpi ; Set Form Factor to 48 tpi + MOV NUM_CYLN,40 ; 40 TRACKS PER SIDE + + PUSH DS + PUSH DI + PUSH DX + PUSH CX + PUSH ES + + MOV AH, 8h ;GET DRIVE PARAMETERS + INT 13h ;CALL ROM-BIOS + JNC PARMSFROMROM + JMP NOPARMSFROMROM ; GOT AN OLD ROM +PARMSFROMROM: +;If CMOS is bad, it gives ES,AX,BX,CX,DH,DI=0. CY=0. +;In this case, we are going to put bogus informations to BDS table. +;We are going to set CH=39,CL=9,DH=1 to avoid divide overflow when +;they are calculated at the later time. This is just for the Diagnostic +;Diskette which need IO.SYS,MSDOS to boot up before it sets CMOS. +;This should only happen with drive B. + +;;Rev 3.30 Modification ----------------------------------------------- + CMP CH,0 ; if ch=0, then cl,dh=0 too. + JNE PFR_OK + MOV CH,39 ; ROM gave wrong info. + MOV CL,9 ; Let's default to 360K. + MOV DH,1 +PFR_OK: + INC DH ; MAKE NUMBER OF HEADS 1-BASED + INC CH ; MAKE NUMBER OF CYLINDERS 1-BASED + MOV NUM_HEADS,DH ; SAVE PARMS RETURNED BY ROM + AND CL,00111111B ; EXTRACT SECTORS/TRACK + MOV SEC_TRK,CL + MOV NUM_CYLN,CH ; ASSUME LESS THAN 256 CYLINDERS!! +; MAKE SURE THAT EOT CONTAINS THE MAX NUM OF SEC/TRK IN SYSTEM OF FLOPPIES + CMP CL,EOT ; MAY SET CARRY + JBE EOT_OK + MOV EOT,CL +EOT_OK: + POP ES + POP CX + POP DX + POP DI + POP DS + +; +; Check for presence of changeline +; + mov AH, 15h ; set command to get DASD type + int 13h ; call ROM-BIOS + JC CHANGELINE_DONE + CMP AH,02 ; CHECK FOR PRESENCE OF CHANGELINE + JNE CHANGELINE_DONE +;;End of Modification ----------------------------------------------- +; +; We have a drive with change line support. +; + Message fTestINIT,<"96tpi devices",CR,LF> + + or CL,fChangeLine ; signal type + mov fHave96,1 ; Remember that we have 96tpi disks +; ;3.30 +; WE NOW TRY TO SET UP THE FORM FACTOR FOR THE TYPES OF MEDIA THAT WE KNOW;3.30 +; AND CAN RECOGNISE. FOR THE REST, WE SET THE FORM FACTOR AS "OTHER". ;3.30 +; ;3.30 +CHANGELINE_DONE: ;3.30 +; 40 CYLINDERS AND 9 OR LESS SEC/TRK, TREAT AS 48 TPI MEDIUM. ;3.30 + CMP NUM_CYLN,40 ;3.30 + JNZ TRY_80 ;3.30 + CMP SEC_TRK,9 ;3.30 + JBE GOT_FF ;3.30 +GOTOTHER: ;3.30 + MOV DH,FFOTHER ; WE HAVE A "STRANGE" MEDIUM ;3.30 + JMP SHORT GOT_FF ;3.30 + ;3.30 +; ;3.30 +; 80 CYLINDERS AND 9 SECTORS/TRACK => 720 KB DEVICE ;3.30 +; 80 CYLINDERS AND 15 SEC/TRK => 96 TPI MEDIUM ;3.30 +; ;3.30 +TRY_80: ;3.30 + CMP NUM_CYLN,80 ;3.30 + JNZ GOTOTHER ;3.30 + CMP SEC_TRK,15 ;3.30 + JZ GOT96 ;3.30 + CMP SEC_TRK,9 ;3.30 + JNZ GOTOTHER ;3.30 + MOV DH,FFSMALL ;3.30 + JMP SHORT GOT_FF ;3.30 + ;3.30 +GOT96: ;3.30 + MOV DH,FF96TPI ;3.30 + ;3.30 +GOT_FF: ;3.30 + JMP SHORT NEXTDRIVE ;3.30 + ;3.30 +; AN OLD ROM, SO WE EITHER HAVE A 48TPI OR 96TPI DRIVE. IF THE DRIVE ;3.30 +; HAS CHANGELINE, WE ASSUME IT IS A 96TPI, OTHERWISE IT IS A 48TPI. ;3.30 + ;3.30 +NOPARMSFROMROM: ;3.30 + POP ES ;3.30 + POP CX ;3.30 + POP DX ;3.30 + POP DI ;3.30 + POP DS ;3.30 + ;3.30 + MOV AH, 15h ; SET COMMAND TO GET DASD TYPE ;3.30 + INT 13h ; CALL ROM-BIOS ;3.30 + JC NEXTDRIVE ;3.30 + CMP AH,2 ; IS THERE CHANGELINE? ;3.30 + JNZ NEXTDRIVE ;3.30 + OR CL,FCHANGELINE ;3.30 + MOV FHAVE96,1 ; REMEMBER WE HAVE 96TPI DRIVES ;3.30 + MOV NUM_CYLN,80 ;3.30 + MOV DH,FF96TPI ;3.30 + MOV AL,15 ; SET EOT IF NECESSARY ;3.30 + CMP AL, EOT ;3.30 + JBE EOT_OK2 ;3.30 + MOV EOT,AL ;3.30 +EOT_OK2: ;3.30 + +NextDrive: + or cl,fI_Own_Physical ; set this true for all drives + mov bh,dl ;save Int13 drive number +; +; We need to do special things if we have a single drive system and are setting +; up a logical drive. It needs to have the same Int13 drive number as its +; counterpart, but the next drive letter. Also reset ownership flag. +; We detect the presence of this situation by examining the flag SINGLE for the +; value 2. +; + cmp single,2 + jnz Not_Special + dec bh ; Int13 drive number same for logical drive + xor cl,fI_Own_Physical ; reset ownership flag for logical drive +Not_Special: +; The values that we put in for RHdlim and RSeclim will only remain if the +; form factor is of type "ffOther". + xor ax,ax ; fill BDS for drive + mov al,num_heads + mov word ptr [di].RHdlim,ax + mov al,sec_trk + mov word ptr [di].RSeclim,ax + mov word ptr [di].flags,cx + mov byte ptr [di].FormFactor,dh + mov byte ptr [di].DriveLet,dl + mov byte ptr [di].DriveNum,bh + MOV BL,BYTE PTR NUM_CYLN ;3.30 + mov byte ptr [di].cCyln,bl ; only the l.s. byte is set here + cmp single,1 ; Special case for single drive system + jnz No_Single + message fTestINIT,<"Single Drive System",CR,LF> + ; Don't forget we have + mov single,2 ; single drive system + or cx,fI_Am_Mult ; set that this is one of + ; several drives + or word ptr [di].flags,cx ; save flags + mov di,word ptr [di].link ; move to next BDS in list + inc dl ; add a number + jmp short NextDrive ; Use same info for BDS as previous + + + +No_Single: + inc dl + jmp loop_drive + +Done_Drives: + mov ax,-1 ; Signify end of list by + mov word ptr [di].link,ax ; setting pointer to -1 +; +; Set up all the hard drives in the system +; +DoHard: + MNUM fTestINIT+fTestHARD,AX + Message fTestINIT+fTestHARD,<" Hard disk(s) to initialize",CR,LF> + Message fTestINIT+fTestHARD,<"Hard disk 1",CR,LF> + + CMP HNUM,0 ; IF (No_Hard_files) + JLE STATIC_CONFIGURE ; THEN EXIT TO CONFIGURE ;3.30 + mov DL, 80h ; set first hard file number + mov di,offset BDSH ; Set up first hard file. + mov bl,HARDNUM + call SETHARD + jnc HardFile1_OK + + dec HNUM ; First hard file is bad. + cmp HNUM,0 ; IF (Second_Hard_File) + jg Second_Hard ; THEN Set up second hard file + JMP SHORT STATIC_CONFIGURE ;3.30 + +HardFile1_OK: + call Install_BDS ; install BDS into linked list + cmp HNUM,2 ; IF (Only_one_hardfile) + jb SetIt ; THEN SetIt "in place" + + mov bl,HARDNUM + inc BL ; next drive letter + mov di,offset BDSX + +Second_Hard: ; SETUP Second Hard FILE + + Message fTestINIT+fTestHARD,<"Hard disk 2",CR,LF> + mov DL, 81h ; set second hard file number + call SETHARD + jnc HardFile2_OK + dec HNUM + jmp short SetIt + +HardFile2_OK: + Call Install_BDS + +SETIT: + mov al,HNUM + or al,al + JZ STATIC_CONFIGURE ;3.30 + add al,HARDNUM + mov DRVMAX,al + +; End of physical drive initialization. ;3.30 +; *** Do not change the position of the following statement. +; *** DoMini routine will use [DRVMAX] value for the start of the logical ;3.30 +; *** drive number of Mini disk(s). ;3.30 + ;3.30 + call DoMini ;For setting up mini disks, if found -;3.30 + +; End of drive initialization. + +;9/24/86 We now decide, based on the configurations available so far,;3.30 +;what code or data we need to keep as a stay resident code. The following;3.30 +;table shows the configurations under consideration. They are listed in ;3.30 +;the order of their current position memory. ;3.30 +;Configuration will be done in two ways: ;3.30 +;First, we are going to set "Static configuration". Static configuration ;3.30 +;will consider from basic configuration to ENDOF96TPI configuration. ;3.30 +;The result of static configuration will be the address the Dynamic ;3.30 +;configuration will use to start with. ;3.30 +;Secondly, "Dynamic cofiguration" will be performed. Dynamic configuration;3.30 +;involves possible relocation of CODE/DATA. Dynamic configuration routine ;3.30 +;will take care of BDSM tables and AT ROM Fix module thru K09 suspend/res ;3.30 +;code individually. After these operation, FINAL_DOS_LOCATION will be set.;3.30 +;This will be the place SYSINIT routine will relocate MSDOS module. ;3.30 +; ;3.30 +; 1. BASIC CONFIGURATION FOR MSBIO (EndFloppy, EndSwap) ;3.30 +; 2. ENDONEHARD ;3.30 +; 3. ENDTWOHARD ;3.30 +; 4. END96TPI ;a system that supports "Change Line Error" ;3.30 +; 5. End of BDSM ;BDSM tables for mini disks. ;3.30 +; 6. ENDATROM ;Some of AT ROM fix module. ;3.30 +; 7. ENDCMOSCLOCKSET;Supporting program for CMOS clock write. ;3.30 +; 8. ENDK09 ;K09 CMOS Clock module to handle SUSPEND/RESUME ;3.30 +; ;3.30 +;9/24/86. ;3.30 + ;3.30 +; *** For mini disk configuration. 4/7/86 ;3.30 +; *** END_OF_BDSM will contain the ending address(off) of BDSM table for ;3.30 +; *** mini disks which is located right after the label END96TPI. ;3.30 +; *** The variable NUM_MINI_DSK will indicate the existance. 4/7/86 ;3.30 + ;3.30 + ;3.30 +STATIC_CONFIGURE: ;3.30 + ;3.30 + ;3.30 + PUSH AX ;3.30 + mov ax, offset END96TPI ;let's start with the biggest one.;3.30 + cmp fHave96, 0 ;Is change line support there? ;3.30 + jnz Config96 ;Yes. ;3.30 + ;3.30 + mov ax, offset ENDTWOHARD ;3.30 + cmp HNUM, 1 ;1 hard file? ;3.30 + jbe No_Two_HRD ;3.30 + jmp ConfigTwoHard ;3.30 +No_Two_HRD: ;3.30 + mov ax, offset ENDONEHARD ;3.30 + jnz Basic_Floppy ;3.30 + jmp ConfigOneHard ;3.30 +Basic_Floppy: ;3.30 + mov ax, offset ENDFLOPPY ;3.30 + jmp Dynamic_Configure ;static configuration is done! ;3.30 + +; +; Keep the 96tpi code +; +Config96: +; +; Save old INT 13 vector +; + PUSH AX + PUSH DS + XOR AX,AX + MOV DS,AX + ASSUME DS:NOTHING ;3.30 + MOV AX,DS:[4 * 13h] + MOV WORD PTR CS:Real13,AX + MOV AX,DS:[4 * 13h+2] + MOV WORD PTR CS:Real13+2,AX +; +; Insert new vector +; + MOV WORD PTR DS:[4 * 13h],OFFSET INT13 + MOV DS:[4 * 13h + 2],CS + POP DS + ASSUME DS:CODE ;3.30 + POP AX +; +; Keep two hard disk BPBs +; +ConfigTwoHard: +; +; Keep one hard disk BPB +; +ConfigOneHard: +; +; Adjust the number of drives to include the hard disks. +; + PUSH AX + MOV AL,HardNum + ADD AL,HNum + add al, num_mini_dsk ;4/7/86 for mini disks installed ;3.30 + ;if not installed, then num_mini_dsk = 0. ;3.30 + MOV DrvMax,AL + POP AX + +DYNAMIC_CONFIGURE: ;3.30 + call Get_Para_Offset ;For dynamic allocation, we are ;3.30 + ;going to use offset address that ;3.30 + ;is in paragraph boundary. ;3.30 + push cs ;3.30 + pop es ;es -> code ;3.30 + assume es:code ;3.30 + cld ;clear direction ;3.30 + ;3.30 + cmp [num_mini_dsk], 0 ;Mini disk(s) installed ? ;3.30 + jz CheckATROM ;No. ;3.30 + mov ax, End_Of_BDSM ;set the new ending address ;3.30 + call Get_Para_Offset ;3.30 +CheckATROM: ;3.30 + cmp Model_Byte, 0FCh ;AT ? ;3.30 + jnz CheckCMOSClock ;3.30 + cmp HNUM, 0 ;No hard file? ;3.30 + jz CheckCMOSClock ;3.30 + mov si, 0F000h ;3.30 + mov es, si ;ES -> BIOS segment ;3.30 + assume es:nothing ;3.30 + mov si, offset BIOS_DATE ;3.30 + mov di, 0FFF5H ;ROM BIOS string is at F000:FFF5 ;3.30 +Cmpbyte: ;Only patch ROM for bios 01/10/84 ;3.30 + cmpsb ;3.30 + jnz CheckCMOSClock ;3.30 + cmp byte ptr [si-1],0 ;3.30 + jnz Cmpbyte ;3.30 + ;3.30 +SetRomCode: ;Now we have to install ROM fix ;3.30 + ;AX is the address to move. ;3.30 + push cs ;3.30 + pop es ;set ES to CODE seg ;3.30 + assume es:code ;3.30 + mov word ptr ORIG13, ax ;3.30 + mov word ptr ORIG13+2, cs ;set new ROM bios int 13 vector ;3.30 + mov cx, offset ENDATROM ;3.30 + mov si, offset IBM_DISK_IO ;3.30 + sub cx, si ;size of AT ROM FIX module ;3.30 + mov di, ax ;destination ;3.30 + rep movsb ;relocate it ;3.30 + mov ax, di ;new ending address ;3.30 + call Get_Para_Offset ;in AX ;3.30 + ;3.30 +CheckCMOSClock: ;3.30 + push cs ;3.30 + pop es ;set ES to CODE seg ;3.30 + assume es:code ;3.30 + cmp HaveCMOSClock, 1 ;CMOS Clock exists? ;3.30 + jne CheckK09 ;3.30 + mov DaycntToDay, ax ;set the address for MSCLOCK ;3.30 + mov cx, offset EndDaycntToDay ;3.30 + mov si, offset Daycnt_To_Day ;3.30 + sub cx, si ;size of CMOS clock sup routine ;3.30 + mov di, ax ;3.30 + rep movsb ;3.30 + mov ax, di ;3.30 + call Get_Para_Offset ;3.30 + mov BinToBCD, ax ;set the address for MSCLOCK ;3.30 + mov cx, offset EndCMOSClockSet ;3.30 + mov si, offset Bin_To_BCD ;3.30 + sub cx, si ;3.30 + mov di, ax ;3.30 + rep movsb ;3.30 + mov ax, di ;3.30 + call Get_Para_Offset ;3.30 + ;3.30 +CheckK09: ;3.30 + push ax ;save ax ;3.30* + mov ax,4100h ;Q: is it a K09 ;3.30* + mov bl,0 ; ;3.30* + int 15h ; ;3.30* + pop ax ;3.30 + jc CONFIGDONE ;3.30 + ;3.30 + mov si, offset INT6C ;3.30 + mov cx, offset ENDK09 ;3.30 + sub cx, si ;size of K09 routine ;3.30 + mov di, ax ;3.30 + push di ;save destination ;3.30 + rep movsb ;3.30 + mov ax, di ; ;3.30 + call Get_Para_Offset ;AX = new ending address ;3.30 + pop di ;3.30 + ;3.30 + push ax ;3.30 + push ds ;3.30 + mov fHaveK09, 1 ;remember we have a K09 type ;3.30 + xor ax,ax ;3.30 + mov ds, ax ;3.30 + assume ds:nothing ;3.30 + ;3.30 + mov word ptr ds:[4 * 6Ch], di ;new INT 6Ch handler ;3.30 + mov ds:[4 * 6Ch +2], cs ;3.30 + ;3.30 + pop ds ;3.30 + assume ds:code ;3.30 + pop ax ;restore the ending address ;3.30 + +; +; Set up config stuff for SYSINIT +; +ConfigDone: + MOV DX,SYSINITSEG + MOV DS,DX + ASSUME DS:SYSINITSEG + SUB AX,OFFSET START$ ;3.30 + ADD AX,15 + RCR AX,1 + SHR AX, 1 + SHR AX, 1 + SHR AX, 1 + MOV FINAL_DOS_LOCATION, AX + POP AX + +GOINIT: + ADD Final_DOS_Location,CODE + Message fTestINIT,<"Final DOS location is "> + MNUM fTestINIT,Final_DOS_Location + Message fTestINIT, + PUSH CS + POP DS + + ASSUME DS:CODE,ES:NOTHING + + CMP BYTE PTR fHave96,0 + JNZ ReadDos + call purge_96tpi ;mjb001 eliminate calls to 96tpi hoohah + +ReadDos: + Message fTestINIT,<"Load FAT",CR,LF> + mov ax,DRVFAT ; Get drive and FAT ID + call SetDrive ; Get BDS for drive + call GetBP ; Ensure valid BPB is present + call GETFAT ; Read in the FAT sector + xor DI,DI + mov AL,ES:[DI] ; Get fat id byte + mov BYTE PTR DRVFAT+1,AL ; Save FAT byte + mov AX,DRVFAT + Message fTestINIT,<"FATID read "> + mnum ftestinit,ax + message ftestinit, + call SETDRIVE ; Get Correct BDS for this drive + mov BL,[DI].FatSiz ; get size of fat on media + mov fBigFat,BL + mov CL,[DI].SecPerClus ; get sectors/cluster + mov AX,[DI].HIDSEC ; get number of hidden sectors + sub BIOS$,AX ; subtract hidden sector offset + xor CH,CH ; CX = sectors/cluster +; +; THE BOOT PROGRAM HAS LEFT THE DIRECTORY AT 0:500 +; + PUSH DS + XOR DI,DI + MOV DS,DI ; ES:DI POINTS TO LOAD LOCATION + MOV BX,DS:WORD PTR [53AH] ; clus=*53A; + POP DS ; + Message fTestINIT,<"Load DOS",CR,LF> +; BAS DEBUG +;LOADIT: MOV AX,((((OFFSET END$)-(OFFSET START$))+15)/16)+SYSIZE +LOADIT: + MOV AX, OFFSET END$ ;3.30 + SUB AX, OFFSET START$ ;3.30 + ADD AX, 15 + RCR AX, 1 ; DIVIDE BY 16 + SHR AX, 1 + SHR AX, 1 + SHR AX, 1 + ADD AX, SYSIZE + + ADD AX,CODE + + MOV ES,AX ; + CALL GETCLUS ; clus = GetClus (clus); + +IsEof: + TEST fBigFat,fBIG ; if (fBigFAT) + JNZ EOFBig + Message fTestINIT, + CMP BX,0FF7h ; return (clus > 0ff7h); + JMP SHORT ISEOFX ;3.30 +EOFBig: + Message fTestINIT, + CMP BX,0FFF7h ; else +ISEOFX: ;3.30 + JB LOADIT ; } WHILE (!ISEOF (CLUS)); ;3.30 + ;3.30 + CALL SETDRVPARMS ;3.30 + ;3.30 + MESSAGE FTESTINIT,<"SYSINIT",CR,LF> ;3.30 + ZWAIT ;3.30 + MESSAGE FTESTINIT,<"ON TO SYSINIT...",CR,LF> ;3.30 + JMP SYSINIT ;3.30 + ;3.30 +INIT ENDP ;3.30 + ;3.30 +;**************************** ;3.30 + ;3.30 +Get_Para_Offset proc near ;3.30 +;in: AX - offset value ;3.30 +;out: AX - offset value adjusted for the next paragraph boundary. ;3.30 + add ax, 15 ;make a paragraph ;3.30 + rcr ax, 1 ;3.30 + shr ax, 1 ;3.30 + shr ax, 1 ;3.30 + shr ax, 1 ;3.30 + shl ax, 1 ;now, make it back to offset value ;3.30 + shl ax, 1 ;3.30 + shl ax, 1 ;3.30 + shl ax, 1 ;3.30 + ret ;3.30 +Get_Para_Offset endp ;3.30 + +; +; READ A FAT SECTOR INTO fat location +; +GETFAT PROC NEAR ;3.30 + XOR DI,DI ; offset + MOV DX,1 ; relative sector (1st sector of fat) + MOV CX,FatLen ; read entire fat. + MOV AX,FatLoc ; + MOV ES,AX ; location to read + MOV AX,DRVFAT ; AH FAT ID byte, AL drive + JMP DISKRD +GETFAT ENDP ;3.30 + + +; +; READ A BOOT RECORD INTO 7C0:BootBias +; GetBoot reads the boot record into 7C0:BootBias +; On Entry: +; DL contains ROM drive number (80 or 81) +; On Exit: +; if carry set error +; if carry clear: +; ES:BX piont to boot sector +; AX and CX are not preserved +; BX and ES are used to return values +; +GETBOOT PROC NEAR + mov AX, 07C0h ; prepare to load ES + mov ES, AX ; load ES segment register + mov BX, BootBias ; load BX, ES:BX is where sector goes + mov AX, 0201h ; command to read & num sec. to 1 + xor DH, DH ; head number zero + mov CX, 0001h ; cylinder zero and sector one + int 13h ; call rom bios + jc ERRET + cmp WORD PTR ES:[BootBias+1FEH],0AA55H ; DAVE LITTON MAGIC BYTE? + jz Norm_Ret + message ftesthard,<"Signature AA55 not found",cr,lf> +ERRET: + message ftesthard,<"Error in Getboot",cr,lf> + STC +Norm_Ret: + RET +GETBOOT ENDP ;3.30 +; +; SetHard - generate BPB for a variable sized hard file. IBM has a +; partitioned hard file; we must read physical sector 0 to determine where +; our own logical sectors start. We also read in our boot sector to +; determine version number +; +; Inputs: DL is ROM drive number (80 OR 81) +; DS:DI points to BDS +; Outputs: Carry clear -> BPB is filled in +; Carry set -> BPB is left uninitialized due to error +; + +SETHARD PROC NEAR ;3.30 + push di + push bx + push ds + mov byte ptr [di].DriveLet,bl + mov byte ptr [di].DriveNum,dl + xor ax,ax + or al,fNon_Removable + or word ptr [di].flags,ax + mov byte ptr [di].FormFactor,ffHardFile + MOV fBigFat,0 ; Assume 12 bit FAT + PUSH DX + + mov AH, 8 ; set command to get drive parameters + int 13h ; call rom-bios disk routine + + ; DH is number of heads-1 + ; DL is number of hard disks attached + ; Low 6 bits of CL is sectors/track + ; High 2 bits of CL with CH are max # of cylinders + INC DH ; get number of heads + MOV BYTE PTR [DI].HDLIM,DH + POP DX + JC SETRET ; carry here means no hard disk + AND CL,3FH ; extract number of sectors/track + MOV BYTE PTR [DI].SECLIM,CL + CALL GETBOOT ; if (getBoot ()) + JC SETRET ; return -1; + MOV BX,1C2H+BootBias ; p = &boot[0x1C2]; +SET1: + CMP BYTE PTR ES:[BX],1 ; while (p->PartitionType != 1 && + JZ SET2 + CMP Byte Ptr ES:[BX],4 ; p->PartitionType != 4) { + JZ Set2 + ADD BX,16 ; p += sizeof Partition; + CMP BX,202H+BootBias ; if (p == &boot[0x202h]) + JNZ SET1 ; return -1; +SETRET: + STC ; } + jmp Ret_Hard + +SET2: + PUSH DX + MOV AX,WORD PTR ES:[BX+4] + MOV DX,WORD PTR ES:[BX+6] + +;Decrement the sector count by 1 to make it zero based. Exactly 64k ;3.30 +;sectors should be allowed ;3.30 +; ;3.30 + SUB AX,1 ; PTM 901 12/12/86 MT ;3.30 + SBB DX,0 ; PTM 901 12/12/86 MT ;3.30 + + ADD AX,WORD PTR ES:[BX+8] + ADC DX,WORD PTR ES:[BX+10] + JZ OKDrive + Message fTestHard,<"Partition invalid",CR,LF> + OR fBigFat,fTOOBIG +OKDrive: + POP DX + MOV AX,WORD PTR ES:[BX+4] + MOV [DI].HIDSEC,AX ; BPB->HidSecCt = p->PartitionBegin; + MOV AX,WORD PTR ES:[BX+8] + CMP AX,64 ; if (p->PartitionLength < 64) + JB SETRET ; return -1; + + MOV WORD PTR [DI].DRVLIM,AX ; BPB->MaxSec = p->PartitionLength; + PUSH AX + + PUSH DX + MOV AX,[DI].HidSec ; boot sector number + XOR DX,DX + MOV BH,DH + MOV BL,byte ptr [DI].SecLim + DIV BX + MOV CL,DL ; CL is sector number + INC CL ; sectors are 1 based + CWD + MOV BL,byte ptr [DI].HdLim + DIV BX ; DL is head, AX is cylinder +; +; DL is head. +; AX is cylinder +; CL is sector number +; TOS is drive +; + +;*** For Mini Disks *** 4/7/86 ;3.30 + cmp word ptr [di].IsMini, 1 ;check for mini disk - 4/7/86 ;3.30 + jnz OKnotMini ;not mini disk. - 4/7/86 ;3.30 + add ax, [di].hidden_trks ;set phy track num - 4/7/86 ;3.30 +OKnotMini: ; 4/7/86 ;3.30 +;*** End of added logic for mini disk ;3.30 + + ROR AH,1 ; move high two bits of cyl to high + ROR AH,1 ; two bits of upper byte + AND AH,0C0h ; turn off remainder of bits + OR CL,AH ; move two bits to correct spot + MOV CH,AL ; CH is Cylinder +; +; CL is sector + 2 high bits of cylinder +; CH is low 8 bits of cylinder +; DL is head +; TOS is drive +; + POP AX ; AL is drive + MOV DH,DL ; DH is head + MOV DL,AL ; DL is drive +; +; CL is sector + 2 high bits of cylinder +; CH is low 8 bits of cylinder +; DH is head +; DL is drive +; + xor BX, BX ; clear BX -- ES:BX points to buffer + mov ax, 0201h ; set command to read one sector + int 13h ; call rom-bios to read sector + pop AX + +; +; ES:[0] points to the boot sector. In theory, (ha ha) the BPB in this thing +; is correct. We can, therefore, pull out all the relevant statistics on the +; media if we recognize the version number. +; + CMP WORD PTR ES:[3], "B" SHL 8 + "I" + JNZ Unknownj + CMP WORD PTR ES:[5], " " SHL 8 + "M" + JNZ Unknownj + CMP WORD PTR ES:[8], "." SHL 8 + "2" + JNZ Try5 + CMP BYTE PTR ES:[10], "0" + JNZ Try5 + Message fTestHard,<"Version 2.0 media",CR,LF> + JMP SHORT CopyBPB +unknownj: + jmp unknown +Try5: + CMP WORD PTR ES:[8],"." SHL 8 + "3" + JNZ Unknownj + cmp byte ptr es:[10],"1" ;do not trust 3.0 boot record. 4/15/86;3.30 + jb unknownj ;if version >= 3.1, then O.K. 4/15/86 ;3.30 + Message ftestHard,<"VERSION 3.1 OR ABOVE MEDIA",CR,LF> + +CopyBPB: +; We have a valid Boot sector. Use the BPB in it to build the +; BPB in BIOS. It is assumed that ONLY SecPerClus, cDIR, and +; cSecFat need to be set (all other values in already). fBigFat +; is also set. + MOV AX,WORD PTR ES:[11+DRVLIM-BytePerSec] ; Total sectors + MNUM fTestHard,AX + Message fTestHard,<" Sec "> + DEC AX ; Subtract # reserved (always 1) + MOV DX,WORD PTR ES:[11+cSecFAT-BytePerSec] ; Sectors for 1 fat + MNUM fTestHard,DX + Message fTestHard,<" Sec/Fat "> + MOV [DI+cSecFAT],DX ; Set in BIOS BPB + SHL DX,1 ; Always 2 FATs + SUB AX,DX ; Sub # FAT sectors + MOV DX,WORD PTR ES:[11+cDIR-BytePerSec] ; # root entries + MOV [DI+cDIR],DX ; Set in BIOS BPB + MNUM fTestHard,DX + Message fTestHard,<" directory entries "> + MOV CL,4 + SHR DX,CL ; Div by 16 ents/sector + SUB AX,DX ; Sub # dir sectors + ; AX now contains the # of data sectors. + MOV CL,BYTE PTR ES:[11+SecPerClus-BytePerSec] ; Sectors per cluster + MOV [DI.SecPerClus],CL ; Set in BIOS BPB + XOR DX,DX + MOV CH,DH + MNUM fTestHard,CX + Message fTestHard,<" SecPerClus",CR,LF> + DIV CX + ; AX now contains the # clusters. + CMP AX,4096-10 ; is this 16-bit fat? + JB GoodRetj ; No + OR fBigFat,fBIG ; 16 bit FAT +GoodRetj: + JMP GoodRet + +Unknown: + Message fTestHard,<"Unknown hard media. Assuming 3.0.",CR,LF> + MOV SI,OFFSET DiskTable2 +Scan: + CMP AX,[SI] + JBE GotParm + ADD SI,4 * 2 + JMP Scan +GotParm: + MOV CL,BYTE PTR [SI+6] + OR fBigFat,CL + MOV CX,[SI+2] + MOV DX,[SI+4] +; +; AX = number of sectors on disk drive +; DX = number of dir entries, +; CH = number of sectors per cluster +; CL = log base 2 of ch +; +; NOW CALCULATE SIZE OF FAT TABLE +; + MNUM fTestHard,AX + Message fTestHard,<" sectors "> + MNUM fTestHard,DX + Message fTestHard,<" directory entries "> + MNUM fTestHard,CX + Message fTestHard,<" SecPerClus|ClusShift"> + MOV WORD PTR cDir[DI],DX ;SAVE NUMBER OF DIR ENTRIES + MOV BYTE PTR SecPerClus[DI],CH ;SAVE SECTORS PER CLUSTER + TEST fBigFAT,fBIG ; if (fBigFat) + JNZ DoBig ; goto DoBig; + Message fTestHard,<" Small fat",CR,LF> + XOR BX,BX + MOV BL,CH + DEC BX + ADD BX,AX + SHR BX,CL ; BX = 1+(BPB->MaxSec+SecPerClus-1)/ + INC BX ; SecPerClus + AND BL,11111110B ; BX &= ~1; (=number of clusters) + MOV SI,BX + SHR BX,1 + ADD BX,SI + ADD BX,511 ; BX += 511 + BX/2 + SHR BH,1 ; BH >>= 1; (=BX/512) + MOV BYTE PTR [DI].cSecFat,BH ;SAVE NUMBER OF FAT SECTORS + JMP SHORT GOODRET ;3.30 +DoBig: + Message fTestHard,<" Big fat",CR,LF> + MOV CL,4 ; 16 (2^4) directory entries per sector + SHR DX,CL ; cSecDir = cDir / 16; + SUB AX,DX ; AX -= cSecDir; AX -= cSecReserved; + DEC AX ; ax = t - r - d + MOV BL,2 + MOV BH,SecPerClus[DI] ; bx = 256 * secperclus + 2 + XOR DX,DX + ADD AX,BX ; ax = t-r-d+256*spc+2 + ADC DX,0 + SUB AX,1 ; ax = t-r-d+256*spc+1 + SBB DX,0 + DIV BX ; cSecFat = ceil((total-dir-res)/ + ; (256*secperclus+2)); + MOV WORD PTR [DI].cSecFat,AX ; number of fat sectors +GoodRet: + MOV BL,fBigFat + MOV [DI].FatSiz,BL ; set size of fat on media + CLC +Ret_Hard: + pop ds + pop bx + pop di + RET +SETHARD ENDP ;3.30 + + +; +; SetDrvParms sets up the recommended BPB in each BDS in the system based on +; the form factor. It is assumed that the BPBs for the various form factors +; are present in the BPBTable. For hard files, the Recommended BPB is the same +; as the BPB on the drive. +; No attempt is made to preserve registers since we are going to jump to +; SYSINIT straight after this routine. +; +SETDRVPARMS PROC NEAR ;3.30 + message ftestinit,<"Setting Drive Parameters",cr,lf> + xor bx,bx + les di,dword ptr cs:[Start_BDS] ; get first BDS in list +Next_BDS: + cmp di,-1 + jnz Do_SetP +Done_SetParms: + RET +Do_SetP: + push es + push di ; preserve pointer to BDS + mov bl,es:[di].FormFactor + cmp bl,ffHardFile + jnz NotHardFF + mov ax,es:[di].DrvLim + push ax + mov ax,word ptr es:[di].hdlim + mul word ptr es:[di].seclim + mov cx,ax ; cx has # sectors per cylinder + pop ax + xor dx,dx ; set up for div + div cx ; div #sec by sec/cyl to get # cyl + or dx,dx + jz No_Cyl_Rnd ; came out even + inc ax ; round up +No_Cyl_Rnd: + mov es:[di].cCyln,ax + message ftestinit,<"Ccyln "> + MNUM ftestinit,AX + message ftestinit, + push es + pop ds + lea si,[di].BytePerSec ; ds:si -> BPB for hard file + jmp short Set_RecBPB +NotHardFF: + push cs + pop ds + cmp bl,ffOther ; Special case "other" type of medium + JNZ NOT_PROCESS_OTHER ;3.30 +Process_Other: + xor dx,dx + mov ax,[di].cCyln + mov bx,[di].RHdlim + mul bx + mov bx,[di].RSeclim + mul bx + mov [di].RDrvlim,ax ; Have the total number of sectors + dec ax + +; New logic to get the sectors/fat area. ;3.30 + ;Fat entry assumed to be 1.5 bytes;3.30 + mov bx, 3 ;3.30 + mul bx ;3.30 + mov bx,2 ;3.30 + div bx ;3.30 + xor dx, dx ;3.30 + mov bx, 512 ;3.30 + div bx ;3.30 + inc ax ;3.30 + +No_Round_Up: + mov [di].RcSecFat,ax + jmp short Go_To_Next_BDS + +NOT_PROCESS_OTHER: ;3.30 + shl bx,1 ; bx is word index into table of BPBs + mov si,offset BPBTable + mov si,word ptr [si+bx] ; get address of BPB +Set_RecBPB: + lea di,[di].RBytePerSec ; es:di -> RecBPB + mov cx,BPBSIZ + REP MOVSB ; MOVE BPBSIZ BYTES ;3.30 +Go_To_Next_BDS: + pop di + pop es ; restore pointer to BDS + mov bx,word ptr es:[di].link+2 + mov di,word ptr es:[di].link + mov es,bx + jmp Next_BDS +SETDRVPARMS ENDP ;3.30 + + +; +; READ CLUSTER SPECIFIED IN BX +; CX = SECTORS PER CLUSTER +; DI = LOAD LOCATION +; +GETCLUS PROC NEAR ;3.30 + PUSH CX + PUSH DI + MOV DOSCNT,CX ;SAVE NUMBER OF SECTORS TO READ + MOV AX,BX + DEC AX + DEC AX + MUL CX ;CONVERT TO LOGICAL SECTOR + ADD AX,BIOS$ ;ADD IN FIRST DATA SECTOR + MOV DX,AX ;DX = FIRST SECTOR TO READ + +GETCL1: + MNUM fTestINIT + Message fTestINIT,<" => "> + ;SI = BX, BX = NEXT ALLOCATION UNIT +; +; GET THE FAT ENTRY AT BX, WHEN FINISHED SI=ENTRY BX +; +UNPACK: + PUSH DS + PUSH BX + MOV SI,FatLoc + TEST fBigFat,fBIG ; if (!fBigFat) { + JNZ Unpack16 + MOV DS,SI + MOV SI,BX + SHR SI,1 + MOV BX,[SI+BX] ; p = fat[clus+clus/2]; + JNC HAVCLUS ; if (clus&1) + SHR BX,1 ; p >>= 4; + SHR BX,1 + SHR BX,1 + SHR BX,1 +HAVCLUS: + AND BX,0FFFH ; oldclus=clus; clus = p & 0xFFF; + JMP SHORT UNPACKX ;3.30 +Unpack16: ; else { + MOV DS,SI + SHL BX,1 ; oldclus = clus; + MOV BX,[BX] ; clus = fat[2*clus]; +UNPACKX: ;3.30 + POP SI ; return; + POP DS + ; } + MNUM fTestINIT + Message fTestINIT,<" "> + SUB SI,BX + CMP SI,-1 ;one apart? + JNZ GETCL2 + ADD DOSCNT,CX + JMP GETCL1 + +GETCL2: + PUSH BX + MOV AX,DRVFAT ;GET DRIVE AND FAT SPEC + MOV CX,DOSCNT + CALL DISKRD ;READ THE CLUSTERS + POP BX + POP DI + MOV AX,DOSCNT ;GET NUMBER OF SECTORS READ + XCHG AH,AL ;MULTIPLY BY 256 + SHL AX,1 ;TIMES 2 EQUAL 512 + ADD DI,AX ;UPDATE LOAD LOCATION + POP CX ;RESTORE SECTORS/CLUSTER + RET +GETCLUS ENDP ; RETURN; ;3.30 + +; +; SI POINTS TO DEVICE HEADER +; +; 4/22/86 - print_init, aux_init is modified to eliminate the ;3.30 +; self-modifying code. ;3.30 + ;3.30 +PRINT_INIT: ;3.30 + call Get_device_number ;3.30 + mov ah,1 ;initalize printer port ;3.30 + int 17h ;call ROM-Bios routine ;3.30 + ret ;3.30 + ;3.30 +AUX_INIT: ;3.30 + call Get_device_number ;3.30 + mov al,RSINIT ;2400,N,1,8 (MSEQU.INC) ;3.30* + mov ah,0 ;initalize AUX port ;3.30* + int 14h ;call ROM-Bios routine ;3.30* + ret ;3.30 + ;3.30 +GET_DEVICE_NUMBER: ;3.30 +;SI -> device header ;3.30 + MOV AL,CS:[SI+13] ;GET DEVICE NUMBER FROM THE NAME ;3.30 + SUB AL,"1" ;3.30 + CBW ;3.30 + MOV DX,AX ;3.30 + RET ;3.30 + +; +; purge_96tpi NOP's calls to 96tpi support. +; +PURGE_96TPI PROC NEAR ;MJB001 ;3.30 + PUSH DS + PUSH ES + + push cs ;mjb001 + pop es ;mjb001 + push cs ;mjb001 + pop ds ;mjb001 + ASSUME DS:CODE,ES:CODE ;3.30 + MOV SI,OFFSET PatchTable +PatchLoop: + LODSW + MOV CX,AX + JCXZ PatchDone + LODSW + MOV DI,AX + MOV AL,90h + REP STOSB + JMP PatchLoop + +PatchDone: + mov di,offset TABLE_PATCH ; ARR 2.42 + MOV AX,OFFSET EXIT + STOSW + STOSW + + POP ES + POP DS + ret ;mjb001 +PURGE_96TPI ENDP ;3.30 + +;Mini disk initialization routine. Called right after DoHard - 4/7/86;3.30 +; DoMini **************************************************************** ;3.30 +; **CS=DS=ES=code ;3.30 +; **DoMini will search for every extended partition in the system, and ;3.30 +; initialize it. ;3.30 +; **BDSM stands for BDS table for Mini disk and located right after the ;3.30 +; label End96Tpi. End_Of_BDSM will have the offset value of the ending ;3.30 +; address of BDSM table. ;3.30 +; **BDSM is the same as usual BDS except that TIM_LO, TIM_HI entries are ;3.30 +; overlapped and used to id mini disk and the number of Hidden_trks. ;3.30 +; Right now, they are called as IsMini, Hidden_Trks respectively. ;3.30 +; **DoMini will use the same routine in SETHARD routine after label SET1 ;3.30 +; to save coding. ;3.30 +; **DRVMAX determined in DoHard routine will be used for the next ;3.30 +; available logical mini disk drive number. ;3.30 +; ;3.30 +; Input: DRVMAX, DSKDRVS ;3.30 +; ;3.30 +; Output: MiniDisk installed. BDSM table established and installed to BDS.;3.30 +; num_mini_dsk - number of mini disks installed in the system. ;3.30 +; End_Of_BDSM - ending offset address of BDSM. ;3.30 +; ;3.30 +; ;3.30 +; Called modules: ;3.30 +; GetBoot, WRMSG, int 13h (AH=8, Rom) ;3.30 +; FIND_MINI_PARTITION (new), Install_BDSM (new), ;3.30 +; SetMini (new, it will use SET1 routine) ;3.30 +; Variables used: End_Of_BDSM, numh, mininum, num_mini_dsk, ;3.30 +; Rom_Minidsk_num, Mini_HDLIM, Mini_SECLIM ;3.30 +; BDSMs, BDSM_type (struc), Start_BDS ;3.30 +;************************************************************************ ;3.30 +; ;3.30 + ;3.30 +DoMini: ;3.30 + Message fTestHard,<"Start of DoMini...",cr,lf> ;3.30 + ;3.30 + push ax ;Do I need to do this? ;3.30 + ;3.30 + mov di, offset BDSMs ;from now on, DI points to BDSM ;3.30 + mov dl, 80h ;look at first hard drive ;3.30* + mov ah, 8h ;get drive parameters ;3.30* + int 13h ;call ROM-Bios ;3.30* + cmp dl, 0 ;3.30 + jz DoMiniRet ;no hard file? Then exit. ;3.30 + mov numh, dl ;save the number of hard files. ;3.30 + xor ax,ax ;3.30 + mov al, drvmax ;3.30 + mov mininum, al ;this will be logical drive letter;3.30 + ;for mini disk to start with. ;3.30 + ;3.30 + shl ax, 1 ;ax=number of devices. word bndry ;3.30 + push bx ;3.30 + mov bx, offset DSKDRVS ;3.30 + add bx, ax ;3.30 + mov Mini_BPB_ptr, BX ;Mini_BPB_ptr points to first avlb;3.30 + ;spot in DskDrvs for Mini disk ;3.30 + ;which points to BPB area of BDSM.;3.30 + pop bx ;3.30 + ;3.30 + mov Rom_Minidsk_num, 80h ;3.30 +DoMiniBegin: ;3.30 + inc dh ;Get # of heads (conv to 1 based) ;3.30 + xor ax, ax ;3.30 + mov al, dh ;3.30 + mov Mini_HDLIM, ax ;save it. ;3.30 + xor ax, ax ;3.30 + and cl, 3fh ;Get # of sectors/track ;3.30 + mov al, cl ;3.30 + mov Mini_SECLIM, ax ;and save it. ;3.30 + ;3.30 + mov dl, Rom_Minidsk_num ;drive number
;3.30 + call GETBOOT ;rd master boot rec 7c0:BootBias ;3.30 + jc DoMiniNext ;3.30 + call FIND_MINI_PARTITION ;3.30 +DoMiniNext: ;3.30 + dec numh ;3.30 + jz DoMiniRet ;3.30 + inc Rom_MiniDsk_Num ;Next hard file ;3.30 + mov dl, Rom_MiniDsk_Num ;look at next hard drive ;3.30* + mov ah, 8h ;get drive parameters ;3.30* + int 13h ;call ROM-Bios ;3.30* + jmp DoMiniBegin ;3.30 + ;3.30 +DoMiniRet: ;3.30 + pop ax ;3.30 + ret ;3.30 + ;3.30 + ;3.30 +;Find_Mini_Partition tries to find every Extended partition on a disk. ;3.30 +;At entry: DI -> BDSM entry ;3.30 +; ES:BX -> 07c0:BootBias - Master Boot Record ;3.30 +; Rom_MiniDsk_Num - ROM drive number ;3.30 +; MiniNum - Logical drive number ;3.30 +; Mini_HDLIM, Mini_SECLIM ;3.30 +; ;3.30 +;Called routine: SETMINI which uses SET1 (in SETHARD routine) ;3.30 +;Variables & equates used from orig BIOS - flags, fNon_Removable, fBigfat ;3.30 +; ;3.30 +; ;3.30 +FIND_MINI_PARTITION: ;3.30 + ;3.30 + add bx, 1C2h ;BX -> system id. ;3.30 + ;3.30 +FmpNext: ;3.30 + cmp byte ptr ES:[BX], 5 ; 5 = extended partition ID. ;3.30 + jz FmpGot ;3.30 + add bx, 16 ; for next entry ;3.30 + cmp bx, 202h+BootBias ;3.30 + jnz FmpNext ;3.30 + jmp FmpRet ;not found extended partition ;3.30 + ;3.30 +FmpGot: ;found my partition. ;3.30 + Message ftestHard,<"Found my partition...",cr,lf> ;3.30 + xor ax,ax ;3.30 + or al, fNon_Removable ;3.30 + or word ptr [DI].Flags, ax ;3.30 + mov byte ptr [DI].FormFactor, ffHardFile ;3.30 + mov fBigFat, 0 ;assume 12 bit Fat. ;3.30 + mov ax, Mini_HDLIM ;3.30 + mov [DI].HDLIM, ax ;3.30 + mov ax, Mini_SECLIM ;3.30 + mov [DI].SECLIM, ax ;3.30 + mov al, Rom_MiniDsk_Num ;3.30 + mov [DI].DriveNum, al ;set physical number ;3.30 + mov al, Mininum ;3.30 + mov [DI].DriveLet, al ;set logical number ;3.30 + ;3.30 + cmp word ptr ES:[BX+8], 64 ;**With current BPB, only lower word ;3.30 + ; is meaningful. ;3.30 + je FmpRet ;should be bigger than 64 sectors at least ;3.30 + sub bx, 4 ;let BX point to the start of the entry ;3.30 + mov dh, byte ptr ES:[BX+2] ;3.30 + and dh, 11000000b ;get higher bits of cyl ;3.30 + rol dh, 1 ;3.30 + rol dh, 1 ;3.30 + mov dl, byte ptr ES:[BX+3] ;cyl byte ;3.30 + mov [DI].Hidden_Trks, dx ;set hidden trks ;3.30 +;** Now, read the volume boot record into BootBias. ;3.30 + mov cx,ES:[BX+2] ;cylinder,cylinder/sector ;3.30* + mov dh,ES:[BX+1] ;head ;3.30* + mov dl,Rom_MiniDsk_Num ;drive ;3.30* + mov ax,7c0h ; ;3.30* + mov es,ax ;buffer segment ;3.30* + mov bx,BOOTBIAS ;buffer offset ;3.30* + mov ax,0201h ;read,1 sector ;3.30* + int 13h ;call ROM-Bios routine ;3.30* + jc FmpRet ;cannot continue. ;3.30 + mov bx, 1c2h+BootBias ;3.30 + ;3.30 + call SetMini ;install a mini disk. BX value saved. ;3.30 + jc FmpnextChain ;3.30 + ;3.30 + call Install_BDSM ;install the BDSM into the BDS table ;3.30 +; call Show_Installed_Mini ;show the installed message. 3/35/86 - Don't show messages. ;3.30 + inc mininum ;increase the logical drive number for next ;3.30 + inc num_mini_dsk ;increase the number of mini disk installed. ;3.30 + ;3.30 + push bx ;now, set the DskDrvs pointer to BPB info. ;3.30 + mov bx, Mini_BPB_ptr ;3.30 + lea si, [di].BytePerSec ;points to BPB of BDSM ;3.30 + mov [bx], si ;3.30 + inc Mini_BPB_ptr ;advance to the next address ;3.30 + inc Mini_BPB_ptr ;3.30 + pop bx ;3.30 + ;3.30 + add DI, type BDSM_type ;adjust to the next BDSM table entry. ;3.30 + mov End_OF_BDSM, DI ;set the ending address of BDSM table to this. ;3.30 +; Message fTestHard,<"Mini disk installed.",cr,lf> ;3.30 +FmpnextChain: jmp FmpNext ;let's find out if we have any chained partition ;3.30 +FmpRet: ;3.30 + ret ;3.30 + ;3.30 +SetMini: ;3.30 + push di ;3.30 + push bx ;3.30 + push ds ;3.30 + jmp SET1 ;will be returned to Find mini partition routine. ;3.30 + ;Some logic has been added to SET1 to ;3.30 + ;deal with Mini disks. ;3.30 + ;3.30 +; ;3.30 +;Install BDSM installs a BDSM (pointed by DS:DI) into the end of the current ;3.30 +;linked list of BDS. ;3.30 +;Also, set the current BDSM pointer segment to DS. ;3.30 +;At entry: DS:DI -> BDSM ;3.30 +; ;3.30 +Install_BDSM: ;3.30 + ;3.30 + push ax ;3.30 + push si ;3.30 + push es ;3.30 + ;3.30 + les si, dword ptr cs:Start_BDS ;start of the beginning of list ;3.30 +I_BDSM_Next: ;3.30 + cmp word ptr es:[si], -1 ;end of the list? ;3.30 + jz I_BDSM_New ;3.30 + mov si, word ptr es:[si].link ;3.30 + mov ax, word ptr es:[si].link+2 ;next pointer ;3.30 + mov es, ax ;3.30 + jmp short I_BDSM_Next ;3.30 +I_BDSM_New: ;3.30 + mov ax, ds ;3.30 + mov word ptr ds:[di].link+2, ax ;BDSM segment had not been initialized. ;3.30 + mov word ptr es:[si].link+2, ax ;3.30 + mov word ptr es:[si].link, di ;3.30 + mov word ptr ds:[di].link, -1 ;make sure it is a null ptr. ;3.30 + ;3.30 +I_BDSM_ret: ;3.30 + pop es ;3.30 + pop si ;3.30 + pop ax ;3.30 + ret ;3.30 + ;3.30 +;***The following code is not needed any more. Don't show any ;3.30 +;***messages to be compatible with the behavior of IO.SYS. ;3.30 +;;Show the message "Mini disk installed ..." ;3.30 +;;This routine uses WRMSG procedure which will call OUTCHR. ;3.30 +;Show_Installed_Mini: ;3.30 +; push ax ;3.30 +; push bx ;3.30 +; push ds ;3.30 +; ;3.30 +; mov al, Mininum ;logical drive number ;3.30 +; add al, Drv_Letter_Base ;='A' ;3.30 +; mov Mini_Drv_Let, al ;3.30 +; mov si, offset Installed_Mini ;3.30 +; call WRMSG ;3.30 +; ;3.30 +; pop ds ;3.30 +; pop bx ;3.30 +; pop ax ;3.30 +; ret ;3.30 +;**End of mini disk initialization** ; 4/7/86 ;3.30 + ;3.30 + ;3.30 +CMOS_Clock_Read proc near ;3.30 + ;3.30 +; IN ORDER TO DETERMINE IF THERE IS A CLOCK PRESENT IN THE SYSTEM, THE FOLLOWING ;3.30 +; NEEDS TO BE DONE. ;3.30 + PUSH AX ;3.30 + PUSH CX ;3.30 + PUSH DX ;3.30 + PUSH BP ;3.30 + ;3.30 + XOR BP,BP ;3.30 +LOOP_CLOCK: ;3.30 + XOR CX,CX ;3.30 + XOR DX,DX ;3.30 + MOV AH,2 ;READ REAL TIME CLOCK ;3.30 + INT 1Ah ;CALL ROM-BIOS ROUTINE ;3.30 + CMP CX,0 ;3.30 + JNZ CLOCK_PRESENT ;3.30 + ;3.30 + CMP DX,0 ;3.30 + JNZ CLOCK_PRESENT ;3.30 + ;3.30 + CMP BP,1 ; READ AGAIN AFTER A SLIGHT DELAY, IN CASE CLOCK ;3.30 + JZ NO_READDATE ; WAS AT ZERO SETTING. ;3.30 + ;3.30 + INC BP ; ONLY PERFORM DELAY ONCE. ;3.30 + MOV CX,4000H ;3.30 +DELAY: ;3.30 + LOOP DELAY ;3.30 + JMP LOOP_CLOCK ;3.30 + ;3.30 +CLOCK_PRESENT: ;3.30 + mov cs:HaveCMOSClock, 1 ; Set the flag for cmos clock ;3.30 + ;3.30 + call CMOSCK ; Reset CMOS clock rate that may be ;3.30 + ;possibly destroyed by CP DOS and POST routine did not ;3.30 + ;restore that. ;3.30 + ;3.30 + PUSH SI ;3.30 + MESSAGE FTESTINIT,<"CLOCK DEVICE",CR,LF> ;3.30 + CALL READ_REAL_DATE ;MJB002 READ REAL-TIME CLOCK FOR DATE ;3.30 + ;3.30 + CLI ;MJB002 ;3.30 + MOV DAYCNT,SI ;MJB002 SET SYSTEM DATE ;3.30 + STI ;MJB002 ;3.30 + POP SI ;MJB002 ;3.30 +NO_READDATE: ;3.30 + POP BP ;3.30 + POP DX ;3.30 + POP CX ;3.30 + POP AX ;3.30 + RET ;3.30 + ;3.30 +CMOS_Clock_Read endp ;3.30 +; ;3.30 +; 10/28/86 ;3.30 +; THE FOLLOWING CODE IS WRITTEN BY JACK GULLEY IN ENGINEERING GROUP. ;3.30 +; CP DOS IS CHANGING CMOS CLOCK RATE FOR ITS OWN PURPOSES AND IF THE ;3.30 +; USE COLD BOOT THE SYSTEM TO USE PC DOS WHILE RUNNING CP DOS, THE CMOS ;3.30 +; CLOCK RATE ARE STILL SLOW WHICH SLOW DOWN DISK OPERATIONS OF PC DOS ;3.30 +; WHICH USES CMOS CLOCK. PC DOS IS PUT THIS CODE IN MSINIT TO FIX THIS ;3.30 +; PROBLEM AT THE REQUEST OF CP DOS. ;3.30 +; THE PROGRAM IS MODIFIED TO BE RUN ON MSINIT. Equates are defined in CMOSEQU.INC. ;3.30 +; This program will be called by CMOS_Clock_Read procedure. ;3.30 +; ;3.30 +; The following code CMOSCK is used to insure that the CMOS has not ;3.30 +; had its rate controls left in an invalid state on older AT's. ;3.30 +; ;3.30 +; It checks for an AT model byte "FC" with a submodel type of ;3.30 +; 00, 01, 02, 03 or 06 and resets the periodic interrupt rate ;3.30 +; bits incase POST has not done it. This initilization routine ;3.30 +; is only needed once when DOS loads. It should be ran as soon ;3.30 +; as possible to prevent slow diskette access. ;3.30 +; ;3.30 +; This code exposes one to DOS clearing CMOS setup done by a ;3.30 +; resident program that hides and re-boots the system. ;3.30 +; ;3.30 +CMOSCK PROC NEAR ; CHECK AND RESET RTC RATE BITS ;3.30 + ;3.30 +;Model byte and Submodel byte were already determined in MSINIT. ;3.30 + push ax ;3.30 + cmp cs:Model_byte, 0FCh ;check for PC-AT model byte ;3.30 + ; EXIT IF NOT "FC" FOR A PC-AT ;3.30 + JNE CMOSCK9 ; Exit if not an AT model ;3.30 + ;3.30 + CMP cs:Secondary_Model_Byte,06H ; Is it 06 for the industral AT ;3.30 + JE CMOSCK4 ; Go reset CMOS periodic rate if 06 ;3.30 + CMP cs:Secondary_Model_Byte,04H ; Is it 00, 01, 02, or 03 ;3.30 + JNB CMOSCK9 ; EXIT if problem fixed by POST ;3.30 + ; Also,Secondary_model_byte = 0 when AH=0c0h, int 15h failed. ;3.30 +CMOSCK4: ; RESET THE CMOS PERIODIC RATE ;3.30 + ; Model=FC submodel=00,01,02,03 or 06 ;3.30 + + mov al,CMOS_REG_A or NMI ;NMI disabled on return + mov ah,00100110b ;Set divider & rate selection + call CMOS_WRITE + + + mov al,CMOS_REG_B or NMI ;NMI disabled on return + call CMOS_READ + and al,00000111b ;clear SET,PIE,AIE,UIE,SQWE + mov ah,al + mov al,CMOS_REG_B ;NMI enabled on return + call CMOS_WRITE + +CMOSCK9: ; EXIT ROUTINE ;3.30 + pop ax ;3.30 + RET ; RETurn to caller ;3.30 + ; Flags modifyied ;3.30 +CMOSCK ENDP ;3.30 +PAGE ;3.30 +;--- CMOS_READ ----------------------------------------------------------------- ;3.30 +; READ BYTE FROM CMOS SYSTEM CLOCK CONFIGURATION TABLE : ;3.30 +; : ;3.30 +; INPUT: (AL)= CMOS TABLE ADDRESS TO BE READ : ;3.30 +; BIT 7 = 0 FOR NMI ENABLED AND 1 FOR NMI DISABLED ON EXIT : ;3.30 +; BITS 6-0 = ADDRESS OF TABLE LOCATION TO READ : ;3.30 +; : ;3.30 +; OUTPUT: (AL) VALUE AT LOCATION (AL) MOVED INTO (AL). IF BIT 7 OF (AL) WAS : ;3.30 +; ON THEN NMI LEFT DISABLED. DURING THE CMOS READ BOTH NMI AND : ;3.30 +; NORMAL INTERRUPTS ARE DISABLED TO PROTECT CMOS DATA INTEGRITY. : ;3.30 +; THE CMOS ADDRESS REGISTER IS POINTED TO A DEFAULT VALUE AND : ;3.30 +; THE INTERRUPT FLAG RESTORED TO THE ENTRY STATE ON RETURN. : ;3.30 +; ONLY THE (AL) REGISTER AND THE NMI STATE IS CHANGED. : ;3.30 +;------------------------------------------------------------------------------- ;3.30 + ;3.30 +CMOS_READ PROC NEAR ; READ LOCATION (AL) INTO (AL) ;3.30 + PUSHF ; SAVE INTERRUPT ENABLE STATUS AND FLAGS ;3.30 + + cli + push bx + push ax ;save user NMI state + or al,NMI ;disable NMI for us + out CMOS_PORT,al + nop ;undocumented delay needed + in al,CMOS_DATA ;get data value + + ;set NMI state to user specified + mov bx,ax ;save data value + pop ax ;get user NMI + and al,NMI + or al,CMOS_SHUT_DOWN + out CMOS_PORT,al + nop + in al,CMOS_DATA + + mov ax,bx ;data value + pop bx + + PUSH CS ; *PLACE CODE SEGMENT IN STACK AND ;3.30 + CALL CMOS_POPF ; *HANDLE POPF FOR B- LEVEL 80286 ;3.30 + RET ; RETURN WITH FLAGS RESTORED ;3.30 + ;3.30 +CMOS_READ ENDP ;3.30 + ;3.30 +CMOS_POPF PROC NEAR ; POPF FOR LEVEL B- PARTS ;3.30 + IRET ; RETURN FAR AND RESTORE FLAGS ;3.30 + ;3.30 +CMOS_POPF ENDP ;3.30 + ;3.30 +;--- CMOS_WRITE ---------------------------------------------------------------- ;3.30 +; WRITE BYTE TO CMOS SYSTEM CLOCK CONFIGURATION TABLE : ;3.30 +; : ;3.30 +; INPUT: (AL)= CMOS TABLE ADDRESS TO BE WRITTEN TO : ;3.30 +; BIT 7 = 0 FOR NMI ENABLED AND 1 FOR NMI DISABLED ON EXIT : ;3.30 +; BITS 6-0 = ADDRESS OF TABLE LOCATION TO WRITE : ;3.30 +; (AH)= NEW VALUE TO BE PLACED IN THE ADDRESSED TABLE LOCATION : ;3.30 +; : ;3.30 +; OUTPUT: VALUE IN (AH) PLACED IN LOCATION (AL) WITH NMI LEFT DISABLED : ;3.30 +; IF BIT 7 OF (AL) IS ON. DURING THE CMOS UPDATE BOTH NMI AND : ;3.30 +; NORMAL INTERRUPTS ARE DISABLED TO PROTECT CMOS DATA INTEGRITY. : ;3.30 +; THE CMOS ADDRESS REGISTER IS POINTED TO A DEFAULT VALUE AND : ;3.30 +; THE INTERRUPT FLAG RESTORED TO THE ENTRY STATE ON RETURN. : ;3.30 +; ONLY THE CMOS LOCATION AND THE NMI STATE IS CHANGED. : ;3.30 +;------------------------------------------------------------------------------- ;3.30 + ;3.30 +CMOS_WRITE PROC NEAR ; WRITE (AH) TO LOCATION (AL) ;3.30 + PUSHF ; SAVE INTERRUPT ENABLE STATUS AND FLAGS ;3.30 + PUSH AX ; SAVE WORK REGISTER VALUES ;3.30 + + cli + push ax ;save user NMI state + or al,NMI ;disable NMI for us + out CMOS_PORT,al + nop + mov al,ah + out CMOS_DATA,al ;write data + + ;set NMI state to user specified + pop ax ;get user NMI + and al,NMI + or al,CMOS_SHUT_DOWN + out CMOS_PORT,al + nop + in al,CMOS_DATA + + POP AX ; RESTORE WORK REGISTERS ;3.30 + PUSH CS ; *PLACE CODE SEGMENT IN STACK AND ;3.30 + CALL CMOS_POPF ; *HANDLE POPF FOR B- LEVEL 80286 ;3.30 + RET ;3.30 + ;3.30 +CMOS_WRITE ENDP ;3.30 +; ;3.30 + +END$: +code ends +end diff --git a/UPDSRC/BIOS/MSIOCTL.INC b/UPDSRC/BIOS/MSIOCTL.INC new file mode 100644 index 0000000..dd67b14 --- /dev/null +++ b/UPDSRC/BIOS/MSIOCTL.INC @@ -0,0 +1,1039 @@ + include ioctl.inc + +; +; Generic IOCTL dispatch tables +; +IOReadJumpTable db 2 + dw offset GetDeviceParameters + dw offset ReadTrack + dw offset VerifyTrack + +IOWriteJumpTable db 2 + dw offset SetDeviceParameters + dw offset WriteTrack + dw offset FormatTrack + +MAX_SECTORS_CURR_SUP EQU 63 ; CURRENT MAXIMUM SEC/TRK THAT ;3.30 + ; WE SUPPORT (Was 40 in DOS 3.2) ;3.30 +; +; TrackTable is an area for saving information passwd by the set device +; parameter function for laster use my Read/Write/Format/Verify. +; +; Entries are 4-Tuples (C,H,R,N) where: +; C = Cylinder, H = Head, R = Sector, N = Bytes/Sector +; +; fixed for bug0016 - initialised table with values - sp +TrackTable db 0,0,1,2 + db 0,0,2,2 + db 0,0,3,2 + db 0,0,4,2 + db 0,0,5,2 + db 0,0,6,2 + db 0,0,7,2 + db 0,0,8,2 + db 0,0,9,2 + db 0,0,10,2 + db 0,0,11,2 + db 0,0,12,2 + db 0,0,13,2 + db 0,0,14,2 + db 0,0,15,2 + db 0,0,16,2 + db 0,0,17,2 + db 0,0,18,2 + db MAX_SECTORS_CURR_SUP * size a_SectorTable - ($-tracktable) dup (0) + +sectorsPerTrack dw 15 + + +; This is a real ugly place to put this +; it should really go in the BDS +mediaType db 0 + +Media_Set_For_Format db 0 ; 1 if we have done an Int 13 Set Media + ; Type for Format call +; Rev 3.30 ***************************************************************** +Had_Format_Error db 0 ; 1 if the previous format operation + ; failed. +Dsk_time_out_Err equ 80h ; Time out error (No media present). +Dsk_change_line_Err equ 6h ; Change line error +Dsk_illegal_combination equ 0Ch ; Return code of ah=18h function. +; Rev 3.30 ***************************************************************** + +; +; TempDPT is a temporary place to hold a pointer to the original +; Disk Parameter Table while DPT is made to point to a table returned +; by a BIOS call. A value of -1 indicateds no value has been saved. +; + +TempDPT DD -1 + +; +; Generic$IOCTL: +; Perform Generic IOCTL request +; Input: +; al - unit number +; Output: +; if carry set then al contains error code +; + Public Generic$IOCTL +Generic$IOCTL: + Message ftestdisk,<"Generic IOCTL",cr,lf> + les bx,cs:[PTRSAV] ; es:bx points to request header. + call SetDrive ; ds:di points to BDS for drive. +; +; At this point: +; es:bx - points to the Request Header +; ds:di points to the BDS for the drive +; + cmp es:[bx].MajorFunction, RAWIO + jne IOCTL_Func_Err + mov al, es:[bx].MinorFunction + mov si, offset IOReadJumpTable + test al, GEN_IOCTL_FN_TST ; Test of req. function + jnz NotGenericIoctlWrite ; function is a Read. + mov si, offset IOWriteJumpTable +NotGenericIoctlWrite: + and al, 0fH + cmp al, cs:[si] + ja IOCTL_Func_Err + cbw + shl ax, 1 + inc si + add si,ax + les bx, es:[bx].GenericIOCTL_Packet + call cs:[si] + jc FailGeneric$IOCTL + jmp exit + +FailGeneric$IOCTL: + jmp err$exit + +IOCTL_Func_Err: + jmp CMDERR + + + + + +; +; GetDeviceParameters: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to device parameter packet +; + + PUBLIC GETDEVICEPARAMETERS ;3.30 +GetDeviceParameters proc near +; Copy info from BDS to the device parameters packet + mov al, byte ptr ds:[di].FormFactor + mov byte ptr es:[bx].DP_DeviceType, al + mov ax, word ptr ds:[di].Flags + and ax,fNon_Removable+fChangeline ; mask off other bits + mov word ptr es:[bx].DP_DeviceAttributes, ax + mov ax, word ptr ds:[di].cCyln + mov word ptr es:[bx].DP_Cylinders, ax + +; Set media type to default + xor al, al + mov byte ptr es:[bx].DP_MediaType, al + +; Copy recommended BPB + lea si, byte ptr [di].RBytePerSec + test byte ptr es:[bx].DP_SpecialFunctions, BUILD_DEVICE_BPB + jz use_BPB_present +; Get the correct disk in the drive + call CheckSingle +; Build the BPB from scratch + call GETBP + jc Get_Parm_Ret + lea si,byte ptr [di].BytePerSec +use_BPB_present: + lea di, byte ptr [bx].DP_BPB + mov cx, size BPB_Type ; for now use 'small' BPB + rep movsb + clc +Get_Parm_Ret: + ret +GetDeviceParameters endp + + + + + +; +; SetDeviceParameters: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to device parameter packet +; + + PUBLIC SETDEVICEPARAMETERS ;3.30 +SetDeviceParameters proc near + +; Make sure the fChanged_By_Format flag gets set to kick DOS into looking at +; the BPB + or word ptr ds:[di].Flags, fChanged_By_Format or fChanged + test byte ptr es:[bx].DP_SpecialFunctions, ONLY_SET_TRACKLAYOUT + jz short SetDevParm_1 + jmp SetTrackTable ; Originally TrackLayout + +SetDevParm_1: +; Copy info from the device parameters packet to BDS + mov al, byte ptr es:[bx].DP_DeviceType + mov byte ptr ds:[di].FormFactor, al + + mov ax, word ptr es:[bx].DP_Cylinders + mov word ptr ds:[di].cCyln, ax + +; If change line is not loaded then ignore changeling flag + mov ax, word ptr es:[bx].DP_DeviceAttributes + cmp cs:[fHave96],0 + jnz Have_Change + and ax,not fChangeline +Have_Change: +; ignore all bits except Non_removable and Changeline + and ax,fNon_Removable or fChangeline + mov cx, word ptr ds:[di].Flags + and cx, not (fNon_Removable or fChangeline or GOOD_TRACKLAYOUT) + or ax, cx + mov word ptr ds:[di].Flags, ax + +; Set media type + mov al, byte ptr es:[bx].DP_MediaType + mov cs:mediaType, al +; the media changed (maybe) so we will have to do a SetDASD the next time +; we format a track + or word ptr ds:[di].Flags, SET_DASD_true + + SaveReg +; Figure out what we are supposed to do with the BPB + +; Were we asked to install a fake BPB? + test byte ptr es:[bx].DP_SpecialFunctions, INSTALL_FAKE_BPB + jnz short InstallFakeBPB + +; Were we returning a fake BPB when asked to build a BPB? + test word ptr ds:[di].Flags, RETURN_FAKE_BPB + jz short InstallRecommendedBPB + +; We were returning a fake BPB but we can stop now + and word ptr ds:[di].Flags, not RETURN_FAKE_BPB + jmp DoneWithBPBstuff + +InstallRecommendedBPB: + mov cx, size a_BPB + lea di, byte ptr [di].RBytePerSec + jmp short CopyTheBPB + +InstallFakeBPB: + mov cx, size BPB_Type ; move 'smaller' BPB + lea di, byte ptr [di].BytePerSec +CopyTheBPB: + lea si, byte ptr [bx].DP_BPB +; exchange es and ds + push es + push ds + pop es + pop ds + + rep movsb + +DoneWithBPBstuff: + Call RestoreOldDPT + RestoreReg + +; Set up track table (if neccessary) +SetTrackTable: + mov cx, word ptr es:[bx].DP_TrackTableEntries + mov cs:sectorsPerTrack, cx + and word ptr ds:[di].Flags, not GOOD_TRACKLAYOUT + test byte ptr es:[bx].DP_SpecialFunctions, TRACKLAYOUT_IS_GOOD + jz UglyTrackLayout + or word ptr ds:[di].Flags, GOOD_TRACKLAYOUT + +UglyTrackLayout: + cmp cx, MAX_SECTORS_IN_TRACK + ja TooManySectorsPerTrack + jcxz SectorInfoSaved ; if no value don't copy table + ; save information in the track table + + push BX ; get ES:BX to point to sector + add BX, DP_SectorTable ; table in Device param. struct + + push DI + mov DI, offset TrackTable + 2 ; CS:DI now points to sector id + ; of the first track table entry + push AX ; preserve AX value + + ; For MAX_SECTORS_IN_TRACK +TrackLoop: ; DO: + mov AX, word ptr ES:[BX] ; get sector number + mov byte ptr CS:[DI], AL ; save in track table + + mov AX, word ptr ES:[BX]+2 ; get sector size + call SectorSizeToSectorIndex ; convert size to index number + mov byte ptr CS:[DI]+1, AL ; save size in track table + + add BX, size a_sectorTable ; advance pointers to next + add DI, size a_sectorTable ; entries + loopnz TrackLoop ; End FOR + + pop AX ; restore the saved values + pop DI + pop BX + +SectorInfoSaved: + clc + ret + +TooManySectorsPerTrack: + mov al, 0cH + stc + ret + +SetDeviceParameters endp + + +; +; FormatTrack: +; If SpecialFunction byte is 1, then this is a status call to see if there is +; ROM support for the combination of sec/trk and # of cyln, and if the +; combination is legal. If SpecialFunction byte is 0, then format the track. +; +; Input: DS:DI points to BDS for drive +; ES:BX points to format packet +; +; Output: +; For status call: +; SpecialFunction byte set to: +; 0 - ROM support + legal combination +; 1 - No ROM support +; 2 - Illegal Combination +; 3 - no media present ;Rev 3.30 +; Carry cleared. +; +; For format track: +; Carry set if error +; +; +; Flags also may be altered. All other registers preserved. +; If the call to ROM returns no error, then the current DPT is "replaced" by +; the one returned by the ROM. This is done by changing the pointer in [DPT] +; to the one returned. The original pointer to the disk base table is stored +; in TempDPT, until it is restored. +; +; This proc was changed to force a status for format call if we are on the +; new ROM. +; +; +FormatTrack proc near + test byte ptr es:[bx].DP_SpecialFunctions,Status_For_Format + jz SkipStatusOnly + +Do_Status_Only: + call FormatStatus + mov byte ptr es:[bx].DP_SpecialFunctions,al + ret + +SkipStatusOnly: ; for a hard disk only do the verify + cmp byte ptr ds:[di].FormFactor, DEV_HARDDISK + jnz SkipVerify + jmp DoVerifyTrack +SkipVerify: + SaveReg ; Format a Track + call FormatStatus ; SetDASD checks media_set_for_format + cmp al,3 ; Check for time out + je Format_Failed ; Fail if time out + call SetDASD +; +; Store Cylinder,Head in track table +; ***** ASSUMPTION ******* +; Since format requests on Fixed Media are converted to Verifies, we +; assume that we are formatting a floppy and hence have 255 or less +; tracks and heads. We therefore must change the Cylinder, Head data +; from the Request Packet Size to that of the TrackTable (see Int 13 +; interface in IBM's Tech Ref.). + +; Check to ensure correct disk is in drive + call CheckSingle + + mov ax, word ptr es:[bx].FP_Cylinder + mov word ptr cs:[TRKNUM],ax + mov cx, word ptr es:[bx].FP_Head + mov byte ptr cs:[HDNUM],cl + mov ah,cl + ; this next piece of code copies the correct head + ; and cylinder numbers to the tracktable + push di ; preserve DI + mov di, offset TrackTable + mov CX, cs:SectorsPerTrack ; get number of sectors + jcxz EndSetUpTrackTable ; if nothing to do skip down +SetUpLoop: + mov cs:[di], AX ; set head and track value + add di, 4 ; move to next entry + loopnz SetUpLoop ; loop if not done yet +EndSetUpTrackTable: + pop di ; restore DI (BDS pointer) + mov cx, MAXERR ; Set up retry count +FormatRetry: + push cx + ; set up registers for format call to TO_ROM + mov AX, word ptr CS:SectorsPerTrack ; set number of sectors + mov AH, ROMFormat + push cs ; set ES:BX to point to + pop es ; the track table + mov BX, offset TrackTable + ; don't need to set CL on format + call to_rom + jnc FormatOk + pop cx + mov cs:[Had_Format_Error],1 ; Mark the error + push ax ;3.30 + push cx ;3.30 + push dx ;3.30 + call ResetDisk + call FormatStatus ;3.30 + cmp al, 1 ;3.30 + jnz While_Err ;3.30 + call SetDASD ;3.30 +While_Err: ;3.30 + pop dx ;3.30 + pop cx ;3.30 + pop ax ;3.30 + loop FormatRetry + +; Format failed +Format_Failed: + mov cs:[Had_Format_Error],1 ; Indicate a format error + cmp ah,Dsk_Change_Line_Err ; Convert change line to + jne Map_Err ; to time out. + mov ah,Dsk_Time_Out_Err +Map_Err: + call MapError + RestoreReg + ret + +FormatOk: + mov cs:[Had_Format_Error],0 ; Reset format error flag + pop cx ; clean up stack after bailing out + ; of FormatRetry loop early + RestoreReg + +DoVerifyTrack: + call VerifyTrack ; Will reset DPT entries. + ret + +FormatTrack endp + +; +; FormatStatus: +; If SpecialFunction byte is 1, then this routine is called to see if there is +; ROM support for the combination of sec/trk and # of cyln, and if the +; combination is legal. +; +; Input: DS:DI points to BDS for drive +; ES:BX points to format packet +; +; Output: +; SpecialFunction byte set to: +; 0 - ROM support + legal combination +; 1 - No ROM support +; 2 - Illegal Combination +; 3 - No media present, ROM support exists but can't determine +; media +; Carry cleared. +; +; For format track: +; Carry set if error +; +; +; Flags also may be altered. All other registers preserved. +; If the call to ROM returns no error, then the current DPT is "replaced" by +; the one returned by the ROM. This is done by changing the pointer in [DPT] +; to the one returned. The original pointer to the disk base table is stored +; in TempDPT, until it is restored. +; +; +FormatStatus proc near + SaveReg + cmp cs:[Had_Format_Error],1 ; Are we here because of a format err + je Fstat01 + cmp byte ptr cs:[Media_Set_For_Format],1 + jnz FStat03 + jmp Stat_Ret +Fstat03: + mov byte ptr cs:[Media_Set_For_Format],0 +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; modification - sp001 +; +; remove check for new rom from here. we shall just assume the +; prescence of the new rom and go ahead and issue the int13 call +; anyway. later on if there is an error we shall check this to +; see if it is there because of lack of rom support, in which +; case the appropriate error will be indicated by setting al to 1 +; +; I would ideally like to see the new rom testing code shifted to +; msinit and this code reintroduced. however for this version we +; are aiming to stick close to the IBM variety. +; +; More changes to support this commenting out will follow. All +; will be marked as modification sp001 +; +; mov al,1 ; No ROM support available error code +; test byte ptr cs:[New_ROM],1 +; jnz FStat01 +; jmp Stat_Ret +Fstat01: + SaveReg + + xor ax,ax + mov ds,ax + lds si, dword ptr ds:[DskAdr] ; DS:SI := pDPT + + mov word ptr cs:[DPT],si ; cs:[DPT] := pDPT + mov word ptr cs:[DPT + 2],ds + + RestoreReg + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; modification sp001 +; +; the following instruction introduced for the new rom modification +; + mov cs:[New_Rom],1 ; assume new rom +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + mov ax,word ptr [di].cCyln + mov cx,word ptr [di].Seclim + ; set up registers for format status call + and AH, 03h ; 'and' out unneeded track bits + ror AH, 1 ; get track and sector values correct + ror AH, 1 + or AH, CL ; set sector number + xchg AH, AL + mov CX, AX + dec CH + mov DL, byte ptr [DI].DriveNum ; get drive number + mov AH, 18h ; set command to "sec/trk supported?" + + SaveReg + int 13h ; call rom bios to see if supported + jc Format_Stat_Err ; if carry, combination is not supported + + ; ES:DI points to new Disk Base Table + ; combination for this drive replace + ; current (DskAdr) pointer with new one, + ; saving the old one in TempDPT. + + cmp cs:[Had_Format_Error],1 ; Are we here because of a format err + jnz Fstat02 ; Then skip the disk base setup + + xor al,al ; Supported and OK + mov cs:[Had_Format_Error],al ; Clear format error + jmp Pop_Stat_Ret ; Back to work + +Fstat02: + xor ax,ax + mov ds,ax + lds si, dword ptr ds:[DskAdr] ; DS:SI := pDPT + + mov word ptr cs:[TempDPT],si + mov word ptr cs:[TempDPT + 2],ds ; Save pDPT + + mov word ptr ds:[DskAdr],DI ; Setup New DPT returned by + mov word ptr ds:[DskAdr + 2],ES ; ROM + + mov byte ptr cs:[Media_Set_For_Format],1 ; set flag + xor al,al ; Legal combination + ROM support code + jmp short Pop_Stat_Ret + +Format_Stat_Err: + mov al,3 ; Assume a time out + cmp ah,Dsk_Time_Out_Err ; Was it a time out??? + jz Pop_Stat_Ret ; Yes - then done + dec al ; Assume an illegal comb. + cmp ah,Dsk_illegal_combination ; Was it an illegal comb??? + jz Pop_Stat_Ret ; Yes - then done + dec al ; Assume No ROM Support +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; modification sp001 +; +; the following instruction was introduced for the new_rom modification +; + mov cs:[New_Rom],0 ; the old rom +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Return result of status call +Pop_Stat_Ret: + RestoreReg +Stat_Ret: + clc + RestoreReg + ret +FormatStatus endp + + + +; +; VerifyTrack: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to verify packet +; + PUBLIC VERIFYTRACK ;3.30 +VerifyTrack proc near + mov cs:RFLAG, ROMverify + mov ax, word ptr es:[bx].VP_Cylinder + mov cs:curtrk, ax + mov ax, word ptr es:[bx].VP_Head + +; ****** ASSUMPTION ****** +; we assume that we have less than 256 heads, and that the Request +; Header Data Structure is unneccessarily big + mov cs:curhd, al + xor ax, ax + mov cx, cs:sectorsPerTrack +; Use 0:0 as the transfer address for verify + xor bx, bx + mov es, bx + call TrackIO + ret +VerifyTrack endp + +; +; ReadTrack: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to read packet +; + PUBLIC READTRACK ;3.30 +ReadTrack: + mov cs:RFLAG, ROMread + jmp ReadWriteTrack + +; +; WriteTrack: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to write packet +; + PUBLIC WRITETRACK ;3.30 +WriteTrack: + mov cs:RFLAG, ROMwrite + jmp ReadWriteTrack +; +; ReadWriteTrack: +; +; Input: +; DS:DI points to BDS for drive +; ES:BX points to write packet +; RFLAG - 2 for read, 3 for write +; + PUBLIC READWRITETRACK ;3.30 +ReadWriteTrack proc near + mov ax, word ptr es:[bx].TRWP_Cylinder + mov cs:curtrk, ax + mov ax, word ptr es:[bx].TRWP_Head + +; ****** ASSUMPTION ****** +; we assume that we have less than 256 heads, and that the Request +; Header Data Structure is unneccessarily big + mov cs:curhd, al + mov ax, word ptr es:[bx].TRWP_FirstSector + mov cx, word ptr es:[bx].TRWP_SectorsToReadWrite + les bx, es:[bx].TRWP_TransferAddress + call TrackIO + ret +ReadWriteTrack endp + + +; +; TrackIO: +; Performs Track Read/Write/Verify +; +; Input: +; RFLAG - 2 = Read +; 3 = Write +; 4 = Verify +; ax - Index into track table of first sector to IO +; cx - number of sectors to IO +; es:bx - Transfer address +; ds:di - pointer to BDS +; curtrk - current cylinder +; curhd - current head +; + public trackio +TrackIO proc near +; procedure `disk' will pop stack to SPsav and return if error + mov cs:SPsav, sp +; Ensure correct disk is in drive + call CheckSingle +; +; Set up tables and variables for I/O +; + cmp byte ptr cs:[Media_Set_For_Format],1 + jz DPTAlreadySet + +; ;3.30 +; SET UP TABLES AND VARIABLES FOR I/O ;3.30 +; ;3.30 + SaveReg + call IOSetUp + RestoreReg +; +; point si at the table entry of the first sector to be IO'd +; +DPTAlreadySet: + mov si, offset trackTable + shl ax, 1 + shl ax, 1 + add si, ax +; +; we want: +; cx to be the number of times we have to loop +; dx to be the number of sectors we read on each iteration + mov dx, 1 + test word ptr ds:[di].Flags, GOOD_TRACKLAYOUT + jz IOnextSector + +; Hey! we can read all the sectors in one blow + xchg dx, cx + +IOnextSector: + push cx + push dx +; skip over the cylinder and head in the track table + inc si + inc si + +; Get sector id from track table + mov AL, byte ptr cs:[si] ; get current sector value + mov cs:[cursec], AL ; save cursec value + +;*** For a Fixed disk multi-track disk I/O - 4/14/86 ;3.30 +;Assumptions: 1). In the input CX (# of sectors to go) to TRACKIO, only CL;3.30 is +;valid. 2). Sector size should be set to 512 bytes. 3). GOODTRACKLAYOUT. ;3.30 +; ;3.30 + test word ptr [di].Flags, fNon_Removable ;Fixed disk? - J.K;3.30 . + jz IOREMOVABLE ;no - ;3.30 + mov cs:[seccnt], dx ;# of sectors to I;3.30 /O - + mov ax, dx ; ;3.30 + call disk ; ;3.30 + pop dx ; ;3.30 + pop cx ; ;3.30 + clc ; ;3.30 + ret ; ;3.30 +IOREMOVABLE: ; ;3.30 + + mov AL, byte ptr cs:[si]+1 ; get sector size index + + ; The next eight lines put sector size index in DPT + push ES ; save value while getting pointer + push SI ; to DPT + push AX + + les SI, cs:DPT ; ES:SI points to DPT + ; put size in DPT + mov byte ptr ES:[si].Disk_Sector_Siz, AL + mov AX, word ptr [di].seclim ; get number of sector/track + mov byte ptr ES:[si].Disk_EOT,AL ; patch in DPT + + pop AX ; restore register values + pop SI + pop ES + ; convert index to byte value + call SectorSizeIndexToSectorSize + push AX ; save number of bytes in sector + mov AX, DX ; get number of sector for I/0 + +DoTheIO: + mov cs:[SECCNT],ax ; set up the count of sectors to I/O + call disk + ; advance buffer pointer by adding + ; sector size + pop ax + add bx, ax + pop dx + pop cx + loop IOnextSector + call DONE ; Set time of last access, and reset + clc ; entries in DPT. + ret + +TrackIO endp +; +; The sector size in bytes needs to be converted to an index value for the IBM +; ROM. (0=>128, 1=>256,2=>512,3=>1024). It is assumed that only these values +; are permissible. +; On Input AX contains sector size in bytes +; On Output AL contains index +; + public SectorSizeToSectorIndex +SectorSizeToSectorIndex proc near + and AH, 07h ; very simple error correction + mov AL, AH ; shift left 8 bits + cmp AL, 4 ; size 1024? + jnz SecToIndexRet ; no, then we are done + sub AL, 1 ; if 1024, adjust index to 3 +SecToIndexRet: + ret +SectorSizeToSectorIndex endp + +SectorSizeIndexToSectorSize proc near +; value in AH on entry is not important + push CX ; save CX value + mov CL, AL ; use index number as shift size + mov AX, 0080h ; set AX to 128 + shl AX, CL ; shift by index to get proper value + pop CX ; restore CX value + ret +SectorSizeIndexToSectorSize endp + + + +; +; Set up the ROM for formatting. +; we have to tell the ROM BIOS what type of disk is in the drive. +; On Input - DS:DI - points to BDS +; +SetDASD proc near +; See if we have new ROM and have issues Set Media Type For Format call + test byte ptr cs:[Media_Set_For_Format],1 + jnz DasdHasBeenSet +; See if we have previously set DASD type + cmp cs:[Had_Format_Error],1 + je DoSetDasd + test word ptr ds:[di].Flags, SET_DASD_true + jz DASDhasBeenSet + and word ptr ds:[di].Flags, not SET_DASD_true + ; the next nine lines determine and put the DASD type in AL +DoSetDasd: + mov cs:[Had_Format_Error],0 + mov cs:[GAP_PATCH], 50h ; assume 48tpi or 3.5" drive + cmp [di].FormFactor, ffSmall; is 3.5" drive? + jnz not35Drive ; no, skip down + mov AL, 04h ; yes set proper DASD value + jmp short Do_Set ; jump down + +Not35Drive: + mov AL, 01h ; + cmp [di].FormFactor, ff96tpi; 96tpi disk drive? + jnz Do_Set ; no skip down to rom call + inc AL ; reflect 96tpi drive in DASD type + cmp [di].seclim, 15 ; 96tpi media in drive? + jnz Do_Set ; no, skip down to rom call + inc AL ; reflect 96tpi media in DASD type + mov cs:[GAP_PATCH], 54h ; and in the GAP_PATCH +Do_Set: + mov AH, 17h ; set command to Set DASD type + mov DL, [di].DriveNum ; set drive number + int 13h ; call rom-bios +DASDhasBeenSet: + mov ah,byte ptr [di].seclim + mov cs:[FORMT_EOT],ah + ret +SetDasd endp + + +; +; This routine is called if an error occurs while formatting or verifying. +; It resets the drive, and decrements the retry count. +; On Entry - DS:DI - points to BDS for the drive +; BP - contains retry count +; On Exit Flags indicate result of decrementing retry count +; +; +; There are some drives that "lose" the changeline indication if another +; floppy drive is accessed before the changeline is recorded by the device +; driver. In this situation, it is possible for the ROM to also not detect +; that the medium has changed. So, the end result is that we could have a +; diskette in the drive for which we can not even read the boot sector. +; We "fix" this by setting the byte at location DISK_STATE_MACHINE_DRV_0 (hex) +; for physical drive 0 (or DISK_STATE_MACHINE_DRV_1 for drive 1) to 0 (See +; IBM PC/AT "blessed" addresses Document for explanation) . This tells the ROM +; that the medium is 'unknown'. The ROM actually uses these locations for +; itself. Note that we do this only for internal drives; we do not do this for +; fixed disks or for physical drives > 1. We may end up corrupting some +; other bytes in memory that may be used for something else. +; NOTE: We do not stuff this byte if the last operation was a FORMAT because +; the ROM loses track of what it is trying to format!! +; +; This routine was changed to only stuff 61H when the drive indicated it +; supported changeline. The Phoenix ROM was taking a very long time +; to figure out what the media was which caused disk time outs to take +; forever +; +; We assume that DS:DI points to the current BDS for this drive. +; no registers should be touched +; + +AGAIN: + call ResetDisk + dec bp ; decrement retry count + RET + + PUBLIC RESETDISK +ResetDisk: + push ax + xor AH, AH ; set command to reset disk + int 13h ; call the rom-bios + pop ax + mov cs:[STEP_DRV],-1 ; zap up the speed + ret + +; +; This routine sets up the Drive Parameter Table with the values needed for +; Format, does an Int 13. Values in DPT are restored after a VERIFY is done. +; +; On Entry - DS:DI - points to BDS for the drive +; ES:BX - points to TRKBUF +; AL - number of sectors +; AH - Int 13 function code +; CL - Sector number for verify +; On Exit - DS,DI,ES,BX remain unchanged. +; ax and flags are the results of the int 13 +; + Public To_ROM +To_ROM: + SAVEREG ;3.30 + +; The below line was replaced because saving the DPT is predicated upon +; whether the functionality of the new ROM was used, not if it exists. +; test byte ptr cs:[New_ROM],1 + + test byte ptr cs:[Media_Set_For_Format],1 + jnz Got_Valid_DPT + +; Set up values in the DPT +; Set up motor start correctly for 3.5" drives. + push ax + push ds + + xor ax,ax + mov ds,ax + lds si,dword ptr ds:[DskAdr] ; DS:SI := pDPT + + mov word ptr cs:[DPT],si + mov word ptr cs:[DPT+2],ds ; Save pDPT + + pop ds + push ES ; save value in ES + LES SI, CS:DPT + + mov DX, [di].seclim ; set the sector per track in + mov es:[si].DISK_EOT, DL ; the Disk Parameter Table + cmp DX, 15 ; 96tip media? + jz To_ROM1 ; yes, skip down + ; no - set Format Gap to 320/360 media value + mov CL, cs:[Gap_Patch] + mov byte ptr ES:[si].DISK_FORMT_GAP, CL +To_ROM1: ; 3.5" floppy drive? + cmp byte ptr [di].FormFactor, ffSmall + jnz To_ROM2 ; no, skip down + ; yes - reset disk moter start value + mov byte ptr ES:[si].DISK_MOTOR_STRT, 4 +To_ROM2: + pop ES ; restore ES value + pop ax + +Got_Valid_DPT: + ; now set up the registers + mov DL, [di].DriveNum ; set drive number + mov DH, CS:[HDNUM] ; set head number + mov CX, CS:[TRKNUM] ; set track number + ror CH,1 + ror CH,1 + xchg CH, CL + int 13h ; call the rom-bios disk routines + RestoreReg + ret + + +; +; Get the owner of the physical drive represented by the logical drive in BL. +; The assumption is that we **ALWAYS** keep track of the owner of a drive!! +; If this is not the case, the system may hang, just following the linked list. +; + PUBLIC IOCTL$GETOWN +IOCTL$GETOWN: + call SetDrive + mov al,byte ptr [di].DriveNum ; Get physical drive number + push cs + pop ds + mov di,word ptr Start_BDS +Own_Loop: + cmp byte ptr [di].DriveNum,al + jne GetNextBDS + test word ptr [di].flags,fI_Own_Physical + jnz Done_GetOwn +GetNextBDS: + mov bx,word ptr [di].link+2 + mov di,word ptr [di].link + mov ds,bx + jmp short Own_Loop +Done_GetOwn: + JMP SHORT EXIT_OWN + +; +; Set the ownership of the physical drive represented by the logical drive in +; BL. +; + PUBLIC IOCTL$SETOWN +IOCTL$SETOWN: + call SetDrive + mov byte ptr cs:[fSetOwner],1 ; set flag for CheckSingle to + ; look at. + call CheckSingle ; Set ownership of drive + mov byte ptr cs:[fSetOwner],0 ; reset flag + xor bx,bx + mov es,bx + mov cl,-1 + mov byte ptr es:[LSTDRV],cl ; Set up SDSB as well + +EXIT_OWN: +; If there is only one logical drive assigned to this physical drive, return +; 0 to user to indicate this. + xor cl,cl + test word ptr [di].flags,fI_Am_Mult + jz EXIT_NO_MULT + mov cl,byte ptr [di].DriveLet ; Get logical drive number + inc cl ; get it 1-based +EXIT_NO_MULT: + LDS BX,CS:[PtrSav] + mov byte ptr [BX].UNIT,CL + jmp EXIT + + + + +; +; Moves the old DPT that had been saved in TempDPT back to DPT. This is done +; only if the first byte of TempDPT is not -1. +; All registers (including flags) are preserved. +; + Public RestoreOldDPT +RestoreOldDPT: +; If we have already restored the disk base table earlier, do not do it +; again. + push ax + xor al,al +; Reset flag and get current flag setting + mov cs:[Had_Format_Error],al + xchg byte ptr cs:[Media_Set_For_Format],al + or al,al + jz DontRestore + SaveReg + LDS SI,CS:[TempDPT] + xor ax,ax + mov es,ax ; have ES -> segment 0 + MOV WORD PTR ES:[DskAdr],SI + MOV WORD PTR ES:[DskAdr+2],DS +GotCurrentDPT: + RestoreReg +DontRestore: + pop ax + clc ; clear carry + ret ; (7/31/86) + +;end of file msioctl.asm diff --git a/UPDSRC/BIOS/MSSTACK.INC b/UPDSRC/BIOS/MSSTACK.INC new file mode 100644 index 0000000..edf01c9 --- /dev/null +++ b/UPDSRC/BIOS/MSSTACK.INC @@ -0,0 +1,306 @@ +; MSStack.inc +; +; Interrupt level 2, 3, 4, 5, 6, 7,(10, 11, 12, 14, 15 - AT level) +; should follow the standard Interrupt Sharing Scheme which has +; a standard header structure. +; Fyi, the following shows the relations between +; the interrupt vector and interrupt level. +; VEC(Hex) 2 8 9 A B C D E 70 72 73 74 76 77 +; LVL(Deci) 9 0 1 2 3 4 5 6 8 10 11 12 14 15 +; MSSTACK module modifies the following interrupt vectors +; to meet the standard Interrupt Sharing standard; +; A, B, C, D, E, 72, 73, 74, 76, 77. +; Also, for interrupt level 7 and 15, the FirstFlag in a standard header +; should be initialized to indicat whether this interrupt handler is +; the first (= 80h) or not. The FirstFlag entry of INT77h's +; program header is initialized in STKINIT.INC module. +; FirstFlag is only meaningful for interrupt level 7 and 15. +; + +; User specifies the number of stack elements - default = 9 +; minimum = 8 +; maximum = 64 +; +; Intercepts Asynchronous Hardware Interrupts only +; +; Picks a stack from pool of stacks and switches to it +; +; Calls the previously saved interrupt vector after pushing flags +; +; On return, returns the stack to the stack pool +; + + +; This is a modification of STACKS: +; 1. To fix a bug which was causing the program to take up too much space. +; 2. To dispense stack space from hi-mem first rather than low-mem first. +; . Clobbers the stack that got too big instead of innocent stack +; . Allows system to work if the only stack that got too big was the most +; deeply nested one +; 3. Disables NMI interrupts while setting the NMI vector. +; 4. Does not intercept any interupts on a PCjr. +; 5. Double checks that a nested interrupt didn't get the same stack. +; 6. Intercepts Ints 70, 72-77 for PC-ATs and other future products + +;The following variables are for MSSTACK.inc + EVEN + dw 0 ; SPARE FIELD BUT LEAVE THESE IN ORDER +StackCount dw 0 +StackAt dw 0 +StackSize dw 0 +Stacks dw 0 + dw 0 + +FirstEntry dw Stacks +LastEntry dw Stacks+(DefaultCount*EntrySize)-EntrySize +NextEntry dw Stacks+(DefaultCount*EntrySize)-EntrySize + +;End of variables defined for MSSTACK. + +;******************************************************************* +;Macro Interrupt handler for the ordinary interrupt vectors and +;the shared interrupt vectors. +;***************************** +Stack_Main MACRO AA + ASSUME DS:NOTHING + ASSUME ES:NOTHING + ASSUME SS:NOTHING +PUBLIC Int&AA +PUBLIC Old&AA +;----------------------------- + ife IntSharingFlag ;if not IntSharingFlag +;----------------------------- + Old&AA DD 0 +Int&AA PROC FAR +;----------------------------- + else ;for shared interrupt. A Header exists. + +PUBLIC FirstFlag&AA +Int&AA PROC FAR + jmp short Entry_Int&AA&_Stk + Old&AA dd 0 ;Forward pointer + dw 424Bh ;compatible signature for Int. Sharing + FirstFlag&AA db 0 ;the firstly hooked. + jmp short Intret_&AA ;Reset routine. We don't care this. + db 7 dup (0) ;Reserved for future. +Entry_Int&AA&_Stk: +;----------------------------- + endif +;----------------------------- + +; +; Keyboard interrupt must have a three byte jump, a NOP and a zero byte +; as its first instruction for compatibility reasons + ifidn <&aa>,<09> + jmp Keyboard_lbl + nop + db 0 +Keyboard_lbl label near + endif + +; This patches INTERRUPT 75h to be "unhooked". We do this Wierdness, +; rather than never hooking INT 75h, to maintain maximum compat. with IBMs +; post production patch. + push ax + + ifidn <&aa>,<02> + +; ********************************************************************* +; +; This is special support for the P12 / NMI handler +; +; On the P12, there is a situation where an NMI can be caused by +; using the "OUT" instructions to certain ports. When this +; occurs, the P12 hardware *GUARANTEES* that **NOTHING** can stop +; the NMI or interfere with getting to the NMI handler. This +; includes other type of interrupts (hardware and software), and +; also includes other type of NMI's. When any NMI has occured, +; no other interrtupt (hardware, software or NMI) can occur until +; the software takes specific steps to allow further interrupting. +; +; For P12, the situation where the NMI is generated by the "OUT" +; to a control port requires "fixing-up" and re-attempting. In +; otherwords, it is actually a "restartable exception". In this +; case, the software handler must be able to get to the stack in +; order to figure out what instruction caused the problem, where +; it was "OUT"ing to and what value it was "OUT"ing. Therefore, +; we will not switch stacks in this situation. This situation is +; detected by interrogating port 62h, and checking for a bit value +; of 80h. If set, *****DO NOT SWITCH STACKS*****. +; +; ********************************************************************* + + push ds + mov ax,0f000h + mov ds,ax + cmp byte ptr ds:[0fffeh],0f9h ;check if P12 + pop ds + jne Normal&aa + + in al,62h + test al,80h + jz Normal&aa + +Special&aa: + pop ax + jmp dword ptr Old&aa + +Normal&aa: + +; ********************************************************************* + + endif + + push bp + push es + mov es, cs:[STACKS+2] ; Get segment of stacks + + mov bp,NextEntry ; get most likely candidate + mov al,Allocated + xchg AllocByte,al ; grab the entry + cmp al,Free ; still avail? + jne NotFree&aa + + sub NextEntry,EntrySize ; set for next interrupt + +Found&aa: + mov SavedSP,sp ; save sp value + mov SavedSS,ss ; save ss also +; mov IntLevel,aa&h ; save the int level + + mov ax,bp ; temp save of table offset + + mov bp,NewSP ; get new SP value + cmp es:[bp],ax ; check for offset into table + jne FoundBad&aa + + mov ax,es ; point ss,sp to the new stack + mov ss,ax + mov sp,bp + + pushf ; go execute the real interrupt handler + call dword ptr old&aa ; which will iret back to here + + mov bp,sp ; retrieve the table offset for us + mov bp,es:[bp] ; but leave it on the stack + mov ss,SavedSS ; get old stack back + mov sp,SavedSP + +; cmp AllocByte,Allocated ; If an error occured, +; jne NewError&aa ; do not free us + + mov AllocByte,Free ; free the entry + mov NextEntry,bp ; setup to use next time + +NewError&aa: + pop es + pop bp ; saved on entry + pop ax ; saved on entry + +INTRET_&AA: ;3.30 + iret ; done with this interrupt + +NotFree&aa: + cmp al,Allocated ; error flag + je findnext&aa ; no, continue + xchg AllocByte,al ; yes, restore error value + +FindNext&aa: + call LongPath + jmp Found&aa + +FoundBad&aa: + cmp bp,FirstEntry + jc findnext&aa + mov bp,ax ; flag this entry + mov AllocByte,Clobbered +; add bp,EntrySize ; and previous entry +; mov AllocByte,Overflowed +; sub bp,EntrySize + jmp findnext&aa ; keep looking + +int&aa endp + + + endm + +;***************************** ;3.30 +;End of Macro definition ;3.30 +;******************************************************************** ;3.30 +; THESE ARE THE INDIVIDUAL INTERRUPT HANDLERS ;3.30 + ;3.30 + IRP A,<02,08,09,70> ;3.30 + IntSharingFlag=0 ;3.30 + Stack_Main &A ;3.30 + ENDM ;3.30 + ;3.30 + IRP A,<0A,0B,0C,0D,0E,72,73,74,76,77> ;3.30 + IntSharingFlag=1 ;3.30 + Stack_Main &A ;3.30 + ENDM ;3.30 + ;3.30 +;******************************************************************** ;3.30 +;Common routines ;3.30 + +longpath: + mov bp,LastEntry ; start with last entry in table + +LPLOOPP: ;3.30 + cmp AllocByte,Free ; is entry free? + jne inuse ; no, try next one + + mov al,Allocated + xchg AllocByte,al ; allocate entry + cmp al,Free ; is it still free? + je found ; yes, go use it + + cmp al,Allocated ; is it other than Allocated or Free? + je inuse ; no, check the next one + + mov AllocByte,al ; yes, put back the error state + +inuse: + cmp bp,FirstEntry + je Fatal + sub bp,EntrySize + JMP LPLOOPP ;3.30 + +found: + ret + + page + +fatal proc near + push ds ;3.30 + mov ax, 0f000h ;loook at the model byte ;3.30 + mov ds, ax ;3.30 + cmp ds:byte ptr [0fffeh], 0f9h ;convertible ;3.30 + pop ds ;3.30 + jne Skip_NMIS ;3.30 + ;3.30 + mov al,07h ; disable p12 NMIs + out 72h,al + +Skip_NMIS: ;3.30 + cli ; disable and mask + mov al,0ffh ; all other ints + out 021h,al + out 0a1h,al + + mov si,cs + mov ds,si + mov si,offset fatal_msg + +fatal_loop: + lodsb + cmp al,'$' + je fatal_done + + mov bl,7 ;3.30* + mov ah,14 ;3.30* + int 010h ; whoops, this enables ints ;3.30* + jmp fatal_loop + +fatal_done: + jmp fatal_done +fatal endp diff --git a/UPDSRC/BIOS/SYSINIT2.ASM b/UPDSRC/BIOS/SYSINIT2.ASM new file mode 100644 index 0000000..e2356da --- /dev/null +++ b/UPDSRC/BIOS/SYSINIT2.ASM @@ -0,0 +1,1276 @@ +TITLE BIOS SYSTEM INITIALIZATION +TRUE EQU 0FFFFh +FALSE EQU 0 + +;IBMVER EQU TRUE +;IBM EQU IBMVER +STACKSW EQU TRUE ;Include Switchable Hardware Stks ;3.30 +;IBMJAPVER EQU FALSE ;If TRUE set KANJI true also +;MSVER EQU FALSE +;ALTVECT EQU FALSE ;Switch to build ALTVECT version +;KANJI EQU FALSE + +include version.inc + + IF IBMJAPVER +NOEXEC EQU TRUE + ELSE +NOEXEC EQU FALSE + ENDIF + +DOSSIZE EQU 0A000H + +.xlist + include smdossym.inc ; Reduced version of DOSSYM.INC ;3.30 + INCLUDE devsym.inc + include ioctl.inc +.list + + IF NOT IBM + IF NOT IBMJAPVER + EXTRN RE_INIT:FAR + ENDIF + ENDIF + +SYSINITSEG SEGMENT PUBLIC 'SYSTEM_INIT' BYTE + +ASSUME CS:SYSINITSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING + + EXTRN BADOPM:BYTE,CRLFM:BYTE,BADCOM:BYTE,BADMEM:BYTE,BADBLOCK:BYTE + EXTRN BADSIZ_PRE:BYTE,BADLD_PRE:BYTE + EXTRN BADSIZ_POST:BYTE,BADLD_POST:BYTE + EXTRN SYSSIZE:BYTE,BADCOUNTRY:BYTE + + EXTRN dosinfo:dword,entry_point:dword, + EXTRN MEMORY_SIZE:WORD,fcbs:byte,keep:byte + EXTRN DEFAULT_DRIVE:BYTE,confbot:word,alloclim:word + EXTRN BUFFERS:WORD,zero:byte,sepchr:byte + EXTRN FILES:BYTE,stall:near + EXTRN count:word,chrptr:word + EXTRN bufptr:byte,memlo:word,prmblk:byte,memhi:word + EXTRN ldoff:word,area:word,PACKET:BYTE,UNITCOUNT:BYTE, + EXTRN BREAK_ADDR:DWORD,BPB_ADDR:DWORD,drivenumber:byte + + PUBLIC Int24,Open_Dev,Organize,Mem_Err,Newline,CallDev,Badload + PUBLIC PrnDev,AuxDev,Config,Commnd,Condev,GetNum,BadFil,PrnErr + PUBLIC Round,Delim,Print,Set_Break + PUBLIC SetParms, ParseLine, DiddleBack + PUBLIC Skip_delim,SetDOSCountryInfo,Set_Country_Path,Move_Asciiz ;3.30 + PUBLIC Cntry_Drv,Cntry_Root,Cntry_Path ;3.30 + PUBLIC Delim ;3.30 + +ASSUME DS:SYSINITSEG +; +; The following set of routines is used to parse the DRIVPARM = command in +; the CONFIG.SYS file to change the default drive parameters. +; +SetParms: + push ds + push ax + push bx + push cx + push dx + xor bx,bx + mov bl,byte ptr drive + inc bl ; get it correct for IOCTL call (1=A,2=B...) + push cs + pop ds + mov dx,offset DeviceParameters + mov ah, IOCTL + mov al, GENERIC_IOCTL + mov ch, RAWIO + mov cl, SET_DEVICE_PARAMETERS + int 21H + pop dx + pop cx + pop bx + pop ax + pop ds + ret + +; +; Replace default values for further DRIVPARM commands +; +DiddleBack: + mov word ptr DeviceParameters.DP_Cylinders,80 + mov byte ptr DeviceParameters.DP_DeviceType, DEV_3INCH720KB + mov word ptr DeviceParameters.DP_DeviceAttributes,0 + mov word ptr switches,0 ; zero all switches + ret + +; +; Entry point is ParseLine. AL contains the first character in command line. +; +ParseLine: ; don't get character first time + push ds + push cs + pop ds +NextSwtch: + cmp al,13 ; carriage return? + jz done_line + cmp al,10 ; linefeed? + jz put_back ; put it back and done +; Anything less or equal to a space is ignored. + cmp al,' ' ; space? + jbe get_next ; skip over space + cmp al,'/' + jz getparm + stc ; mark error invalid-character-in-input + jmp short exitpl + +getparm: + call Check_Switch + mov word ptr Switches,BX ; save switches read so far + jc swterr +get_next: + invoke getchr + jc done_line + jmp NextSwtch +swterr: + jmp exitpl ; exit if error + +done_line: + test word ptr Switches,flagdrive ; see if drive specified + jnz okay + stc ; mark error no-drive-specified + jmp short exitpl + +okay: + mov ax,word ptr switches + and ax,0003H ; get flag bits for changeline and non-rem + mov word ptr DeviceParameters.DP_DeviceAttributes,ax + mov word ptr DeviceParameters.DP_TrackTableEntries, 0 + clc ; everything is fine + call SetDeviceParameters +exitpl: + pop ds + ret + +put_back: + inc count ; one more char to scan + dec chrptr ; back up over linefeed + jmp short done_line +; +; Processes a switch in the input. It ensures that the switch is valid, and +; gets the number, if any required, following the switch. The switch and the +; number *must* be separated by a colon. Carry is set if there is any kind of +; error. +; +Check_Switch: + invoke getchr + jc err_check + and al,0DFH ; convert it to upper case + cmp al,'A' + jb err_check + cmp al,'Z' + ja err_check + push es + push cs + pop es + mov cl,byte ptr switchlist ; get number of valid switches + mov ch,0 + mov di,1+offset switchlist ; point to string of valid switches + repne scasb + pop es + jnz err_check + mov ax,1 + shl ax,cl ; set bit to indicate switch + mov bx,word ptr switches ; get switches so far + or bx,ax ; save this with other switches + mov cx,ax + test ax,7cH ; test against switches that require number to follow + jz done_swtch + invoke getchr + jc err_Swtch + cmp al,':' + jnz err_swtch + invoke getchr + push bx ; preserve switches + mov byte ptr cs:sepchr,' ' ; allow space separators + call GetNum + mov byte ptr cs:sepchr,0 + pop bx ; restore switches +; Because GetNum does not consider carriage-return or line-feed as OK, we do +; not check for carry set here. If there is an error, it will be detected +; further on (hopefully). + call Process_Num + +done_swtch: + clc + ret + +err_swtch: + xor bx,cx ; remove this switch from the records +err_check: + stc + ret + +; +; This routine takes the switch just input, and the number following (if any), +; and sets the value in the appropriate variable. If the number input is zero +; then it does nothing - it assumes the default value that is present in the +; variable at the beginning. Zero is OK for form factor and drive, however. +; +Process_Num: + test word ptr Switches,cx ; if this switch has been done before, + jnz done_ret ; ignore this one. + test cx,flagdrive + jz try_f + mov byte ptr drive,al + jmp short done_ret + +try_f: + test cx,flagff + jz try_t +; Ensure that we do not get bogus form factors that are not supported + ;cmp al,Max_Dev_Type + ;ja done_ret + mov byte ptr DeviceParameters.DP_DeviceType,al + jmp short done_ret + +try_t: + or ax,ax + jz done_ret ; if number entered was 0, assume default value + test cx,flagcyln + jz try_s + mov word ptr DeviceParameters.DP_Cylinders,ax + jmp short done_ret + +try_s: + test cx,flagseclim + jz try_h + mov word ptr slim,ax + jmp short done_ret +; +; Must be for number of heads +try_h: + mov word ptr hlim,ax + +done_ret: + clc + ret + +; +; SetDeviceParameters sets up the recommended BPB in each BDS in the +; system based on the form factor. It is assumed that the BPBs for the +; various form factors are present in the BPBTable. For hard files, +; the Recommended BPB is the same as the BPB on the drive. +; No attempt is made to preserve registers since we are going to jump to +; SYSINIT straight after this routine. +; +SetDeviceParameters: + push es + push cs + pop es +ASSUME ES:SYSINITSEG + xor bx,bx + mov bl,byte ptr DeviceParameters.DP_DeviceType + cmp bl,DEV_5INCH + jnz Got_80 + mov cx,40 ; 48tpi has 40 cylinders + mov word ptr DeviceParameters.DP_Cylinders,cx +Got_80: + shl bx,1 ; get index into BPB table + mov si,offset BPBTable + mov si,word ptr [si+bx] ; get address of BPB +Set_RecBPB: + mov di,offset DeviceParameters.DP_BPB ; es:di -> BPB + mov cx,size a_BPB + cld + repe movsb + pop es +ASSUME ES:NOTHING + test word ptr switches,flagseclim + jz see_heads + mov ax,word ptr slim + mov word ptr DeviceParameters.DP_BPB.BPB_SectorsPerTrack,ax +see_heads: + test word ptr switches,flagheads + jz Set_All_Done + mov ax,word ptr hlim + mov word ptr DeviceParameters.DP_BPB.BPB_Heads,ax +; +; We need to set the media byte and the total number of sectors to reflect the +; number of heads. We do this by multiplying the number of heads by the number +; of 'sectors per head'. This is not a fool-proof scheme!! +; + mov cx,ax ; cx has number of heads + dec cl ; get it 0-based + mov ax,DeviceParameters.DP_BPB.BPB_TotalSectors ; this is OK for two heads + sar ax,1 ; ax contains # of sectors/head + sal ax,cl + jc Set_All_Done ; We have too many sectors - overflow!! + mov DeviceParameters.DP_BPB.BPB_TotalSectors,ax +; Set up correct Media Descriptor Byte + cmp cl,1 + mov bl,0F0H + mov al,2 ; AL contains sectors/cluster + ja Got_Correct_Mediad + mov bl,byte ptr DeviceParameters.DP_BPB.BPB_MediaDescriptor + je Got_Correct_Mediad +; We have one head - OK for 48tpi medium + mov al,1 ; AL contains sectors/cluster + mov ch,DeviceParameters.DP_DeviceType + cmp ch,DEV_5INCH + jz Dec_Mediad + mov bl,0F0H + jmp short Got_Correct_Mediad +Dec_Mediad: + dec bl ; adjust for one head +Got_Correct_Mediad: + mov byte ptr DeviceParameters.DP_BPB.BPB_MediaDescriptor,bl + mov byte ptr DeviceParameters.DP_BPB.BPB_SectorsPerCluster,al + clc +Set_All_Done: + RET + +ASSUME DS:NOTHING, ES:NOTHING + +NOCHAR1: STC + return + +ORGANIZE: + MOV CX,[COUNT] + JCXZ NOCHAR1 + CALL MAPCASE + XOR SI,SI + MOV DI,SI + +ORG1: CALL GET ;SKIP LEADING CONTROL CHARACTERS + CMP AL,' ' + JB ORG1 + + PUSH CX + PUSH SI + PUSH DI + MOV BP,SI + DEC BP + MOV SI,OFFSET COMTAB ;Prepare to search command table + MOV CH,0 +FINDCOM: + MOV DI,BP + MOV CL,[SI] + INC SI + JCXZ NOCOM + REPE CMPSB + LAHF + ADD SI,CX ;Bump to next position without affecting flags + SAHF + LODSB ;Get indicator letter + JNZ FINDCOM + POP DI + POP SI + POP CX + JMP SHORT GOTCOM + +NOCOM: + POP DI + POP SI + POP CX + MOV AL,'Z' +GOTCOM: STOSB ;SAVE INDICATOR CHAR IN BUFFER + +ORG2: CALL GET2 ;SKIP NAME UNTIL DELIMITER + CALL DELIM ; + JNZ ORG2 + +;--------------------------------------------------------------bug330a03 +; - isp +;* the following two lines in the parsing caused the drivparm line to break +;* we cannot let the "/" character be counted as a delimiter here. +; CALL GET ;GET CHARS TO RIGHT OF EQUALS SIGN +; STOSB +;--------------------------------------------------------------bug330a03 + +;--------------------------------------------------------------bug330a03 +; - isp +;* the following lines replaced the lines taken out +ORG3: CALL GET2 + call delim1 + jz ORG3 + cmp al,'/' + jz ORG_EXT + stosb +;--------------------------------------------------------------bug330a03 + +ORG4: CALL GET2 + call delim ; 5/30/86. "device=filename/p..." ;3.30 + jz ORG_EXT ; 5/30/86 ;3.30 + STOSB + CMP AL,' ' + JA ORG4 + CMP AL,10 + JZ ORG1 + + MOV BYTE PTR ES:[DI-1],0 +ORG5: CALL GET2 + STOSB + CMP AL,10 + JNZ ORG5 + JMP ORG1 + +ORG_EXT: ;3.30 + mov byte ptr es:[di], 0 ;put 0 at DI to make it an ASCIIZ ;3.30 + inc DI ; ;3.30 + stosb ;and copy the delimeter char. ;3.30 + jmp short ORG5 ;and continue as usual. ;3.30 + +GET2: + JCXZ NOGET + MOV AL,ES:[SI] + INC SI + DEC CX + return + +GET: JCXZ NOGET + MOV AL,ES:[SI] + INC SI + DEC CX + CALL DELIM + JZ GET + return + + +;--------------------------------------------------------------bug330a03 +; isp - small changes here, new entry point into routine +DELIM: + CMP AL,'/' ; 5/30/86. IBM will assume "/" delim ;3.30 + retz ;3.30 +DELIM1: + CMP AL,' ' + retz + CMP AL,9 + retz + CMP AL,'=' + retz + CMP AL,',' + retz + CMP AL,';' + retz ; 5/23/86 ;3.30 + cmp al, 0 ; 5/23/86 Special case for sysinit!!! ;3.30 + return + +;--------------------------------------------------------------bug330a03 + +NOGET: POP CX + MOV COUNT,DI + XOR SI,SI + MOV CHRPTR,SI + return +; +; NEWLINE RETURNS WITH FIRST CHARACTER OF NEXT LINE +; +NEWLINE:invoke GETCHR ;SKIP NON-CONTROL CHARACTERS + retc + CMP AL,10 ;LOOK FOR LINE FEED + JNZ NEWLINE + invoke GETCHR + return + +MAPCASE: + PUSH CX + PUSH SI + PUSH DS + PUSH ES + POP DS + XOR SI,SI +CONVLOOP: + LODSB + + IF KANJI + CALL TESTKANJ + JZ NORMCONV + INC SI ;Skip next char + DEC CX + JCXZ CONVDONE ;Just ignore 1/2 kanji error +;Fall through, know AL is not in 'a'-'z' range +NORMCONV: + ENDIF + + CMP AL,'a' + JB NOCONV + CMP AL,'z' + JA NOCONV + SUB AL,20H + MOV [SI-1],AL +NOCONV: + LOOP CONVLOOP +CONVDONE: + POP DS + POP SI + POP CX + return + + IF KANJI +TESTKANJ: + CMP AL,81H + JB NOTLEAD + CMP AL,9FH + JBE ISLEAD + CMP AL,0E0H + JB NOTLEAD + CMP AL,0FCH + JBE ISLEAD +NOTLEAD: + PUSH AX + XOR AX,AX ;Set zero + POP AX + return + +ISLEAD: + PUSH AX + XOR AX,AX ;Set zero + INC AX ;Reset zero + POP AX + return + ENDIF + +ASSUME DS:NOTHING + +Yes_Break_Failed: ;dev drv Init failed and aborted. ;3.30 + stc ;3.30 + pop ax ;3.30 + return ;3.30 + +SET_BREAK: +; 8/14/86 For DOS 3.3, this routine is modified to take care of the ;3.30 +;Device driver's initialization error and abort. ;3.30 +;If [break_addr+2] == [memhi] && [break_addr] = 0 then assume ;3.30 +;that the device driver's initialization has an error and wanted to ;3.30 +;abort the device driver. In this case, this routine will set carry ;3.30 +;and return to the caller. ;3.30 +; ;3.30 + PUSH AX + MOV AX,WORD PTR [BREAK_ADDR+2] ;REMOVE THE INIT CODE + cmp ax, [MEMHI] ;3.30 + jne Set_Break_Continue ;if not same, then O.K. ;3.30 + ;3.30 + cmp word ptr [BREAK_ADDR],0 ;3.30 + je Yes_Break_failed ;[Break_addr+2]=[MEMHI] & [Break_addr]=0 ;3.30 + ;3.30 +Set_Break_Continue: ;3.30 + MOV [MEMHI],AX + MOV AX,WORD PTR [BREAK_ADDR] + MOV [MEMLO],AX + POP AX ; NOTE FALL THROUGH + +; +; Round the values in MEMLO and MEMHI to paragraph boundary. +; Perform bounds check. +; +ROUND: + PUSH AX + MOV AX,[MEMLO] + + invoke ParaRound ; para round up + + ADD [MEMHI],AX + MOV [MEMLO],0 + mov ax,memhi ; ax = new memhi + CMP AX,[ALLOCLIM] ; if new memhi >= alloclim, error + JAE MEM_ERR + POP AX + clc ;clear carry ;3.30 + return + +MEM_ERR: + MOV DX,OFFSET BADMEM + PUSH CS + POP DS + CALL PRINT + JMP STALL + +CALLDEV:MOV DS,WORD PTR CS:[ENTRY_POINT+2] + ADD BX,WORD PTR CS:[ENTRY_POINT] ;Do a little relocation + MOV AX,DS:[BX] + PUSH WORD PTR CS:[ENTRY_POINT] + MOV WORD PTR CS:[ENTRY_POINT],AX + MOV BX,OFFSET PACKET + CALL [ENTRY_POINT] + POP WORD PTR CS:[ENTRY_POINT] + return + +BADNUM: + MOV sepchr,0 + XOR AX,AX ; Set Zero flag, and AX = 0 + pop bx ; ;3.30 + stc ; AND carry set + return + +ToDigit: + SUB AL,'0' + JB NotDig + CMP AL,9 + JA NotDig + CLC + return +NotDig: STC + return + +; GetNum parses a decimal number. +; Returns it in AX, sets zero flag if AX = 0 (MAY BE considered an +; error), if number is BAD carry is set, zero is set, AX=0. +GETNUM: push bx ; ;3.30 + XOR BX,BX ; running count is zero +B2: CALL ToDigit ; do we have a digit + JC BadNum ; no, bomb + XCHG AX,BX ; put total in AX + PUSH BX ; save digit + MOV BX,10 ; base of arithmetic + MUL BX ; shift by one decimal di... + POP BX ; get back digit + ADD AL,BL ; get total + ADC AH,0 ; make that 16 bits + JC BADNUM ; too big a number + XCHG AX,BX ; stash total + + invoke GETCHR ;GET NEXT DIGIT + JC B1 ; no more characters + cmp al, ' ' ; 5/23/86 space? ;3.30 + jz B15 ; 5/23/86 then end of digits ;3.30 + cmp al, ',' ; 5/23/86 ',' is a seperator! ;3.30 + jz B15 ; 5/23/86 then end of digits. ;3.30 + cmp al, 9 ; 5/23/86 TAB ;3.30 + jz B15 ; ;3.30 + CMP AL,SepChr ; allow , separators + JZ b15 + cmp al,SWTCHR ; See if another switch follows + JZ b15 + cmp al,10 ; Line-feed? + jz b15 + cmp al,13 ; Carriage return? + jz b15 + OR AL,AL ; end of line separator? + JNZ B2 ; no, try as a valid char... +b15: INC COUNT ; one more character to s... + DEC CHRPTR ; back up over separator +B1: MOV AX,BX ; get proper count + OR AX,AX ; Clears carry, sets Zero accordingly + pop bx ;3.30 + return + +SKIP_DELIM proc near ; ;3.30 +;Skip the delimeters pointed by CHRPTR. AL will contain the first non delimete;3.30r +;character encountered and CHRPTR will point to the next character. ;3.30 +;This rouitne will assume the second "," found as a non delimiter character. So;3.30 +;in case if the string is " , , ", this routine will stop at the second ",". At;3.30 +;this time, Zero flag is set. ;3.30 +;If COUNT is exhausted, then carry will be set. ;3.30 +Skip_delim_char: ;3.30 + call getchr ;3.30 + jc Skip_delim_exit ;3.30 + cmp al, ',' ;the first comma? ;3.30 + je Skip_delim_next ;3.30 + call delim ;check the charater in AL. ;3.30 + jz Skip_delim_char ;3.30 + jmp short Skip_delim_exit ;found a non delim char ;3.30 +Skip_delim_next: ;3.30 + call getchr ;3.30 + jc Skip_delim_exit ;3.30 + cmp al, ',' ;the second comma? ;3.30 + je Skip_delim_exit ;done ;3.30 + call delim ;3.30 + jz Skip_delim_next ;3.30 +Skip_delim_exit: ;3.30 + return ;3.30 +SKIP_DELIM endp ;3.30 + ;3.30 +; 5/26/86 *****************************************************************;3.30 +SetDOSCountryInfo proc near ;3.30 +;Input: ES:DI -> pointer to DOS_COUNTRY_CDPG_INFO ;3.30 +; DS:0 -> buffer. ;3.30 +; SI = 0 ;3.30 +; AX = country id ;3.30 +; DX = code page id. (If 0, then use ccSysCodePage as a default.) ;3.30 +; BX = file handle ;3.30 +; This routine can handle maxium 72 COUNTRY_DATA entries. ;3.30 +;Output: DOS_country_cdpg_info set. ;3.30 +; Carry set if any file read failure or wrong information in the file. ;3.30 +; Carry set and CX = -1 if cannot find the matching COUNTRY_id, CODEPAGE;3.30 +; _id in the file. ;3.30 + ;3.30 + push di ;3.30 + push ax ;3.30 + push dx ;3.30 + ;3.30 + xor cx,cx ;3.30 + xor dx,dx ;3.30 + mov ax, 512 ;read 512 bytes ;3.30 + call ReadInControlBuffer ;Read the file header ;3.30 + jc SetDOSData_fail ;3.30 + push es ;3.30 + push si ;3.30 + push cs ;3.30 + pop es ;3.30 + mov di, offset COUNTRY_FILE_SIGNATURE ;3.30 + mov cx, 8 ;length of the signature ;3.30 + repz cmpsb ;3.30 + pop si ;3.30 + pop es ;3.30 + jnz SetDOSData_fail ;signature mismatch ;3.30 + ;3.30 + add si, 18 ;SI -> county info type ;3.30 + cmp byte ptr ds:[si], 1 ;Only accept type 1 (Currently only 1 h;3.30eader type) + jne SetDOSData_fail ;cannot proceed. error return ;3.30 + inc si ;SI -> file offset ;3.30 + mov dx, word ptr ds:[si] ;Get the INFO file offset. ;3.30 + mov cx, word ptr ds:[si+2] ;3.30 + mov ax, 1024 ;read 1024 bytes. ;3.30 + call ReadInControlBuffer ;Read INFO ;3.30 + jc SetDOSData_fail ;3.30 + mov cx, word ptr ds:[si] ;get the # of country, codepage combina;3.30tion entries + cmp cx, 72 ;cannot handle more than 72 entries. ;3.30 + ja SetDOSData_fail ;3.30 + inc si ;3.30 + inc si ;SI -> entry information packet ;3.30 + pop dx ;restore code page id ;3.30 + pop ax ;restore country id ;3.30 + pop di ;3.30 + ;3.30 +SetDOSCntry_find: ;Search for desired country_id,codepage;3.30_id. + cmp ax, word ptr ds:[si+2] ;compare country_id ;3.30 + jne SetDOSCntry_next ;3.30 + cmp dx, 0 ;No user specified code page ? ;3.30 + je SetDOSCntry_any_codepage;then no need to match code page id. ;3.30 + cmp dx, word ptr ds:[si+4] ;compare code page id ;3.30 + je SetDOSCntry_got_it ;3.30 +SetDOSCntry_next: ;3.30 + add si, word ptr ds:[si] ;next entry ;3.30 + inc si ;3.30 + inc si ;take a word for size of entry itself ;3.30 + loop SetDOSCntry_find ;3.30 + mov cx, -1 ;signals that bad country id entered. ;3.30 +SetDOSCntry_fail: ;3.30 + stc ;3.30 + ret ;3.30 + ;3.30 +SetDOSData_fail: ;3.30 + pop si ;3.30 + pop cx ;3.30 + pop di ;3.30 + jmp short SetDOSCntry_fail ;3.30 + ;3.30 +SetDOSCntry_any_CodePage: ;use the code_page_id of the country_id;3.30 found. + mov dx, word ptr ds:[si+4] ;3.30 +SetDOSCntry_got_it: ;found the matching entry ;3.30 + mov cs:CntryCodePage_Id, dx ;save code page ID for this country. ;3.30 + mov dx, word ptr ds:[si+10] ;get the file offset of country data ;3.30 + mov cx, word ptr ds:[si+12] ;3.30 + mov ax, 512 ;read 512 bytes ;3.30 + call ReadInControlBuffer ;3.30 + jc SetDOSCntry_fail ;3.30 + mov cx, word ptr ds:[si] ;get the number of entries to handle. ;3.30 + inc si ;3.30 + inc si ;SI -> first entry ;3.30 + ;3.30 +SetDOSCntry_data: ;3.30 + push di ;ES:DI -> DOS_COUNTRY_CDPG_INFO ;3.30 + push cx ;save # of entry left ;3.30 + push si ;si -> current entry in Control buffer ;3.30 + ;3.30 + mov al, byte ptr ds:[si+2] ;get data entry id ;3.30 + call GetCountryDestination ;get the address of destination in ES:D;3.30I + jc SetDOSCntry_data_next ;No matching data entry id in DOS ;3.30 + ;3.30 + ;3.30 + mov dx, word ptr ds:[si+4] ;get offset of data ;3.30 + mov cx, word ptr ds:[si+6] ;3.30 + mov ax, 4200h ;3.30 + stc ;3.30 + int 21h ;move pointer ;3.30 + jc SetDOSData_fail ;3.30 + mov dx, 512 ;start of data buffer ;3.30 + mov cx, word ptr es:[di] ;length of the corresponding data in DO;3.30S. + add cx, 10 ;Signature + A word for the length itse;3.30lf + mov ah, 3fh ;3.30 + stc ;3.30 + int 21h ;read the country.sys data ;3.30 + jc SetDOSData_fail ;read failure ;3.30 + cmp ax, cx ;3.30 + jne SetDOSData_fail ;3.30 + ;3.30 + mov al, byte ptr ds:[si+2] ;save Data id for future use. ;3.30 + mov si, (512+8) ;SI-> data buffer + id tag field ;3.30 + mov cx, word ptr ds:[si] ;get the length of the file ;3.30 + inc cx ;Take care of a word for lenght of tab ;3.30 + inc cx ;itself. ;3.30 + cmp cx, (2048 - 512 - 8) ;Fit into the buffer? ;3.30 + ja SetDOSData_fail ;3.30 + cmp al, SetCountryInfo ;is the data for SetCountryInfo table? ;3.30 + jne SetDOSCntry_Mov ;no, don't worry ;3.30 + push word ptr es:[di+24] ;Cannot destroy ccMono_ptr address. Sav;3.30e them. + push word ptr es:[di+26] ;3.30 + push di ;save DI ;3.30 + ;3.30 + push ax ;3.30 + mov ax,cs:CntryCodePage_Id ;Do not use the Code Page info in Count;3.30ry_Info + mov ds:[si+4], ax ;Use the saved one for this !!!! ;3.30 + pop ax ;3.30 + ;3.30 +SetDOSCntry_Mov: ;3.30 + rep movsb ;copy the table into DOS ;3.30 + cmp al, SetCountryInfo ;was the ccMono_ptr saved? ;3.30 + jne SetDOSCntry_data_next ;3.30 + pop di ;restore DI ;3.30 + pop word ptr es:[di+26] ;restore ccMono_ptr in DOS. ;3.30 + pop word ptr es:[di+24] ;3.30 + ;3.30 +SetDOSCntry_data_next: ;3.30 + pop si ;restore control buffer pointer ;3.30 + pop cx ;restore # of entries left ;3.30 + pop di ;restore pointer to DSO_COUNTRY_CDPG ;3.30 + add si, word ptr ds:[si] ;try to get the next entry ;3.30 + inc si ;3.30 + inc si ;take a word of entry length itself ;3.30 + loop SetDOSCntry_data ;3.30 + ret ;3.30 +SetDOSCountryInfo endp ;3.30 +; ;3.30 + ;3.30 +GetCountryDestination proc near ;3.30 +;Get the destination address in the DOS country info table. ;3.30 +;Input: AL - Data ID ;3.30 +; ES:DI -> DOS_COUNTRY_CDPG_INFO ;3.30 +;On return: ;3.30 +; ES:DI -> Destination address of the matching data id ;3.30 +; carry set if no matching data id found in DOS. ;3.30 + ;3.30 + push cx ;3.30 + add di, ccNumber_of_entries ;skip the reserved area, syscodepage et;3.30c. + mov cx, word ptr es:[di] ;get the number of entries ;3.30 + inc di ;3.30 + inc di ;SI -> the first start entry id ;3.30 +GetCntryDest: ;3.30 + cmp byte ptr es:[di], al ;3.30 + je GetCntryDest_OK ;3.30 + cmp byte ptr es:[di], SetCountryInfo ;was it SetCountryInfo entry? ;3.30 + je GetCntryDest_1 ;3.30 + add di, 5 ;next data id ;3.30 + jmp short GetCntryDest_loop ;3.30 +GetCntryDest_1: ;3.30 + add di, NEW_COUNTRY_SIZE + 3 ;next data id ;3.30 +GetCntryDest_loop: ;3.30 + loop GetCntryDest ;3.30 + stc ;3.30 + jmp short GetCntryDest_exit ;3.30 +GetCntryDest_OK: ;3.30 + cmp al, SetCountryInfo ;select country info? ;3.30 + jne GetCntryDest_OK1 ;3.30 + inc di ;now DI -> ccCountryInfoLen ;3.30 + jmp short GetCntryDest_exit ;3.30 +GetCntryDest_OK1: ;3.30 + les di, dword ptr es:[di+1] ;get the destination in ES:DI ;3.30 +GetCntryDest_Exit: ;3.30 + pop cx ;3.30 + ret ;3.30 +GetCountryDestination endp ;3.30 + ;3.30 +; ;3.30 +ReadInControlBuffer proc near ;3.30 +;Move file pointer to CX:DX ;3.30 +;Read AX bytes into the control buffer. (Should be less than 2 Kb) ;3.30 +;SI will be set to 0 hence DS:SI points to the control buffer. ;3.30 +;Entry: CX,DX offset from the start of the file where the read/write pointer ;3.30 +; be moved. ;3.30 +; AX - # of bytes to read ;3.30 +; BX - file handle ;3.30 +; DS - buffer seg. ;3.30 +;Return: The control data information is read into DS:0 - DS:0200. ;3.30 +; CX,DX value destroyed. ;3.30 +; Carry set if error in Reading file. ;3.30 +; ;3.30 + push ax ;# of bytes to read ;3.30 + mov ax, 4200h ;3.30 + stc ;3.30 + int 21h ;move pointer ;3.30 + pop cx ;# of bytes to read ;3.30 + jc RICB_exit ;3.30 + xor dx,dx ;ds:dx -> control buffer ;3.30 + xor si,si ;3.30 + mov ah,3fh ;read into the buffer ;3.30 + stc ;3.30 + int 21h ;should be less than 1024 bytes. ;3.30 +RICB_exit: ;3.30 + ret ;3.30 +ReadInControlBuffer endp ;3.30 + ;3.30 +; ;3.30 +SET_COUNTRY_PATH proc near ;3.30 +;In: DS - SYSINITSEG, ES - CONFBOT, SI -> start of the asciiz path string ;3.30 +; DOSINFO_EXT, CNTRY_DRV, CNTRY_ROOT, CNTRY_PATH ;3.30 +; Assumes current directory is the ROOT directory. ;3.30 +;Out: DS:DI -> full path (CNTRY_DRV). ;3.30 +; Set the CNTRY_DRV string from the COUNTRY=,,path command. ;3.30 +; DS, ES, SI value saved. ;3.30 + ;3.30 + push si ;3.30 + push ds ;switch ds, es ;3.30 + push es ;3.30 + pop ds ;3.30 + pop es ;now DS -> CONFBOT, ES -> SYSINITSEG ;3.30 + ;3.30 + call chk_drive_letter ;current DS:[SI] is a drive letter? ;3.30 + jc SCP_Default_drv ;no, use current default drive. ;3.30 + mov al, byte ptr DS:[SI] ;3.30 + inc si ;3.30 + inc si ;SI -> next char after ":" ;3.30 + jmp short SCP_SetDrv ;3.30 +SCP_Default_drv: ;3.30 + mov ah, 19h ;3.30 + int 21h ;3.30 + add al, "A" ;convert it to a character. ;3.30 +SCP_SetDrv: ;3.30 + mov cs:CNTRY_DRV, al ;set the drive letter. ;3.30 + mov di, offset CNTRY_PATH ;3.30 + mov al, byte ptr DS:[SI] ;3.30 + cmp al, "\" ;3.30 + je SCP_Root_Dir ;3.30 + cmp al, cs:SWTCHR ;let's accept "/" as an directory delim;3.30 + je SCP_Root_Dir ;3.30 + jmp short SCP_Path ;3.30 +SCP_Root_Dir: ;3.30 + dec di ;DI -> CNTRY_ROOT ;3.30 +SCP_Path: ;3.30 + call MOVE_ASCIIZ ;copy it ;3.30 + mov di, offset CNTRY_DRV ;3.30 +SCPath_Exit: ;3.30 + push ds ;switch ds, es ;3.30 + push es ;3.30 + pop ds ;3.30 + pop es ;DS, ES value restored ;3.30 + pop si ;3.30 + RET ;3.30 +SET_COUNTRY_PATH endp ;3.30 + ;3.30 +; ;3.30 +CHK_DRIVE_LETTER proc near ;3.30 +;Check if DS:[SI] is a drive letter followed by ":". ;3.30 +;Assume that every alpha charater is already converted to UPPER CASE. ;3.30 +;Carry set if not. ;3.30 +; ;3.30 + push ax ;3.30 + cmp byte ptr ds:[si], "A" ;3.30 + jb CDLetter_NO ;3.30 + cmp byte ptr ds:[si], "Z" ;3.30 + ja CDLetter_NO ;3.30 + cmp byte ptr ds:[si+1], ":" ;3.30 + jne CDLetter_NO ;3.30 + jmp short CDLetter_exit ;3.30 +CDLetter_NO: ;3.30 + stc ;3.30 +CDLetter_exit: ;3.30 + pop ax ;3.30 + ret ;3.30 +CHK_DRIVE_LETTER endp ;3.30 + ;3.30 +; ;3.30 +MOVE_ASCIIZ proc near ;3.30 +;In: DS:SI -> source ES:DI -> target ;3.30 +;Out: copy the string until 0. ;3.30 +;Assumes there exists a 0. ;3.30 +MASCIIZ_loop: ;3.30 + movsb ;3.30 + cmp byte ptr DS:[SI-1], 0 ;Was it 0? ;3.30 + jne MASCIIZ_loop ;3.30 + ret ;3.30 +MOVE_ASCIIZ endp ;3.30 + +; +; DS:DX POINTS TO STRING TO OUTPUT (ASCIZ) +; +; PRINTS +; +; +; +BADFIL: + PUSH CS + POP ES + MOV SI,DX +BADLOAD: + MOV DX,OFFSET BADLD_PRE ;WANT TO PRINT CONFIG ERROR + MOV BX,OFFSET BADLD_POST +PRNERR: + PUSH CS + POP DS + MOV AH,STD_CON_STRING_OUTPUT + INT 21H +PRN1: MOV DL,ES:[SI] + OR DL,DL + JZ PRN2 + MOV AH,STD_CON_OUTPUT + INT 21H + INC SI + JMP PRN1 +PRN2: MOV DX,BX +PRINT: MOV AH,STD_CON_STRING_OUTPUT + INT 21H + return + + + IF NOEXEC +; +; LOAD NON EXE FILE CALLED [DS:DX] AT MEMORY LOCATION ES:BX +; +LDFIL: + PUSH AX + PUSH BX + PUSH CX + PUSH DX + PUSH SI + PUSH DS + PUSH BX + XOR AX,AX ;OPEN THE FILE + MOV AH,OPEN + STC ;IN CASE OF INT 24 + INT 21H + POP DX ;Clean stack in case jump + JC LDRET + PUSH DX + MOV BX,AX ;Handle in BX + XOR CX,CX + XOR DX,DX + MOV AX,(LSEEK SHL 8) OR 2 + STC ;IN CASE OF INT 24 + INT 21H ; Get file size in DX:AX + JC LDCLSP + OR DX,DX + JNZ LDERRP ; File >64K + POP DX + PUSH DX + MOV CX,ES ; CX:DX is xaddr + ADD DX,AX ; Add file size to Xaddr + JNC DOSIZE + ADD CX,1000H ; ripple carry +DOSIZE: + mov ax,dx + call ParaRound + mov dx,ax + + ADD CX,DX + CMP CX,[ALLOCLIM] + JB OKLD + JMP MEM_ERR + +OKLD: + XOR CX,CX + XOR DX,DX + MOV AX,LSEEK SHL 8 ;Reset pointer to beginning of file + STC ;IN CASE OF INT 24 + INT 21H + JC LDCLSP + POP DX + PUSH ES ;READ THE FILE IN + POP DS ;Trans addr is DS:DX + MOV CX,0FF00H ; .COM files arn't any bigger than + ; 64k-100H + MOV AH,READ + STC ;IN CASE OF INT 24 + INT 21H + JC LDCLS + MOV SI,DX ;CHECK FOR EXE FILE + CMP WORD PTR [SI],"ZM" + CLC ; Assume OK + JNZ LDCLS ; Only know how to do .COM files + STC + JMP SHORT LDCLS + +LDERRP: + STC +LDCLSP: + POP DX ;Clean stack +LDCLS: + PUSHF + MOV AH,CLOSE ;CLOSE THE FILE + STC + INT 21H + POPF + +LDRET: POP DS + POP SI + POP DX + POP CX + POP BX + POP AX + return + ENDIF + +; +; OPEN DEVICE POINTED TO BY DX, AL HAS ACCESS CODE +; IF UNABLE TO OPEN DO A DEVICE OPEN NULL DEVICE INSTEAD +; +OPEN_DEV: + CALL OPEN_FILE + JNC OPEN_DEV3 +OPEN_DEV1: + MOV DX,OFFSET NULDEV + CALL OPEN_FILE + return + +OPEN_DEV3: + MOV BX,AX ; Handle from open to BX + XOR AX,AX ; GET DEVICE INFO + MOV AH,IOCTL + INT 21H + TEST DL,10000000B + retnz + MOV AH,CLOSE + INT 21H + JMP OPEN_DEV1 + +OPEN_FILE: + MOV AH,OPEN + STC + INT 21H + return + +INT24: ADD SP,6 ;RESTORE MACHINE STATE + POP AX + POP BX + POP CX + POP DX + POP SI + POP DI + POP BP + POP DS + POP ES + PUSH AX + MOV AH,GET_DEFAULT_DRIVE ;INITIALIZE DOS + INT 21H + POP AX + IRET ;BACK TO USER + + IF ALTVECT +BOOTMES DB 13,10,"MS-DOS version " + DB MAJOR_VERSION + "0" + DB "." + DB (MINOR_VERSION / 10) + "0" + DB (MINOR_VERSION MOD 10) + "0" + DB 13,10 + DB "Copyright 1981,82 Microsoft Corp.",13,10,"$" + ENDIF + +NULDEV DB "NUL",0 +CONDEV DB "CON",0 +AUXDEV DB "AUX",0 +PRNDEV DB "PRN",0 + +CONFIG DB "\CONFIG.SYS",0 + +CNTRY_DRV DB "A:" ;3.30 +CNTRY_ROOT DB "\" ;3.30 +CNTRY_PATH DB "COUNTRY.SYS",0 ;3.30 + DB 52 DUP (0) ;3.30 + ;3.30 +COUNTRY_FILE_SIGNATURE db 0FFh,'COUNTRY' ;3.30 + ;3.30 +CntryCodePage_Id DW ? ;3.30 + +COMMND DB "\COMMAND.COM",0 + DB 20 dup (0) ;3.30 + +COMTAB LABEL BYTE +;;;; DB 8,"AVAILDEV",'A' ; NO LONGER SUPPORTED + DB 7,"BUFFERS", 'B' + DB 5,"BREAK", 'C' + DB 6,"DEVICE", 'D' + DB 5,"FILES", 'F' + DB 4,"FCBS", 'X' + DB 9,"LASTDRIVE",'L' + DB 8,"DRIVPARM", 'P' ; RS for DOS 3.2 + IF STACKSW ;3.30 + DB 6,"STACKS", 'K' ; BAS for DOS 3.2 ;3.30 + ENDIF ;3.30 + DB 7,"COUNTRY", 'Q' + DB 5,"SHELL", 'S' +;;;; DB 8,"SWITCHAR",'W' ; NO LONGER SUPPORTED + DB 0 + +public DeviceParameters +DeviceParameters a_DeviceParameters <0,DEV_3INCH720KB,0,80> + +hlim dw 2 +slim dw 9 + +public drive +drive db ? + +public switches +Switches dw ? + +; +; The following are the recommended BPBs for the media that we know of so +; far. + +; 48 tpi diskettes + +BPB48T DW 512 + DB 2 + DW 1 + DB 2 + DW 112 + DW 2*9*40 + DB 0FDH + DW 2 + DW 9 + DW 2 + Dd 0 ;hidden sectors - sp + Dd 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved - sp + +; 96tpi diskettes + +BPB96T DW 512 + DB 1 + DW 1 + DB 2 + DW 224 + DW 2*15*80 + DB 0f9H + DW 7 + DW 15 + DW 2 + Dd 0 ;hidden sectors - sp + Dd 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved - sp + +; 3 1/2 inch diskette BPB + +BPB35 DW 512 + DB 2 + DW 1 ; Double sided with 9 sec/trk + DB 2 + DW 70h + DW 2*9*80 + DB 0f9H + DW 3 + DW 9 + DW 2 + Dd 0 ;hidden sectors - sp + Dd 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved - sp + + +BPBTable dw BPB48T ; 48tpi drives + dw BPB96T ; 96tpi drives + dw BPB35 ; 3.5" drives +; The following are not supported, so default to 3.5" media layout + dw BPB35 ; Not used - 8" drives + dw BPB35 ; Not Used - 8" drives + dw BPB35 ; Not Used - hard files + dw BPB35 ; Not Used - tape drives + dw BPB35 ; Not Used - Other + +switchlist db 7,"FHSTDCN" ; Preserve the positions of N and C. + +; The following depend on the positions of the various letters in SwitchList + +flagdrive equ 0004H +flagcyln equ 0008H +flagseclim equ 0010H +flagheads equ 0020H +flagff equ 0040H + +SWTCHR EQU "/" ; switch follows this character + +SYSINITSEG ENDS + END diff --git a/UPDSRC/CMD/PRINT/PRINT_R.ASM b/UPDSRC/CMD/PRINT/PRINT_R.ASM new file mode 100644 index 0000000..91beec1 --- /dev/null +++ b/UPDSRC/CMD/PRINT/PRINT_R.ASM @@ -0,0 +1,2192 @@ +; SCCSID = @(#)print_r.asm 4.7 85/09/13 + INCLUDE pridefs.inc + + +BREAK + +; +; MSDOS V3.00 PRINT +; +; Resident Portion +; + +Code Segment public para + extrn TransRet:WORD,TransSize:WORD +Code EndS + + + +BREAK + +CodeR Segment public para + + extrn ERRMES:BYTE, ERRMEST:BYTE, BELMES:BYTE, ErrMesT2:BYTE + extrn CanMes:BYTE, CanFilNAm:BYTE, AllCan:BYTE, ERR0:BYTE + extrn ERR1:BYTE, ERR2:BYTE, ERR3:BYTE, ERR4:BYTE, ERR5:BYTE + extrn ERR6:BYTE, ERR7:BYTE, ERR8:BYTE, ERR9:BYTE, ERR10:BYTE + extrn ERR11:BYTE, ERR12:BYTE, FATMES:BYTE, BADDRVM:BYTE, + extrn BADMES:BYTE, badmeslen:WORD, GOODMES:BYTE, goodmeslen:WORD + +if hardint + public SliceCnt, BusyTick, MaxTick, TimeSlice +endif + + public EndRes, BlkSiz, QueueLen, PChar + public ListName, FileQueue, EndQueue, Buffer + public EndPtr, NxtChr, MoveTrans + +assume CS:CodeR + +public PRNR001S,PRNR001E +PRNR001S: + db "*** Microsoft/V310 ***" + + DB (362 - 80h) + 310 DUP (?) ; (362 - 80h) is IBM's New + ; recommended Stack Size - + ; Old recommended Stack Size + ; == New stack growth +ISTACK LABEL WORD ;Stack starts here and grows down the + +;Resident data + +; +; Due to flagrant bogosity by file servers, BUSY is *ALWAYS* relevant. +; +BUSY DB 0 ;Internal ME flag + + IF HARDINT +; +; WARNING!!! The *&^%(*&^ 286 chip hangs if you access a word that will wrap +; at the segment boundary. Make the initial INDOS point somewhere reasonable. +; +INDOS DD TimeSlice ;DOS buisy flag +NEXTINT DD ? ;Chain for int +NEXT_REBOOT DD ? ;Chain for ROM bootstrap + +fFake db 0 ; TRUE => do not diddle I/O ports +SOFINT DB 0 ;Internal ME flag +TICKCNT DB 0 ;Tick counter +TICKSUB DB 0 ;Tick miss counter +SLICECNT DB 8 ;Time slice counter, init to same val + ; as TIMESLICE + +TIMESLICE DB 8 ;The PRINT scheduling time slice. PRINT + ; lets this many "ticks" go by before + ; using a time slice to pump out characters. + ; Setting this to 3 for instance means PRINT + ; Will skip 3 slices, then take the fourth. + ; Thus using up 1/4 of the CPU. Setting it + ; to one gives PRINT 1/2 of the CPU. + ; The above examples assume MAXTICK is + ; 1. The actual PRINT CPU percentage is + ; (MAXTICK/(1+TIMESLICE))*100 + +MAXTICK DB 2 ;The PRINT in timeslice. PRINT will pump + ; out characters for this many clock ticks + ; and then exit. The selection of a value + ; for this is dependent on the timer rate. + +BUSYTICK DB 1 ;If PRINT sits in a wait loop waiting for + ; output device to come ready for this + ; many ticks, it gives up its time slice. + ; Setting it greater than or equal to + ; MAXTICK causes it to be ignored. + +;User gets TIMESLICE ticks and then PRINT takes MAXTICK ticks unless BUSYTICK +; ticks go by without getting a character out. + ENDIF + +QueueLen db DefQueueLen ; Actual length of print queue + even +EndQueue dw ? ; pointer to end of print queue +QueueTail dw offset CodeR:FileQueue ; pointer to next free entry + ; in the print queue +buffer dw ? ; pointer to data buffer + +I24_ERR DW ? ;Save location for INT 24H error code +Ctrlc DB ? ; saved ^C trapping state +SPNEXT DD ? ;Chain location for INT 28 +COMNEXT DD ? ;Chain location for INT 2F +SSsave DW ? ;Stack save area for INT 24 +SPsave DW ? +HERRINT DD ? ;Place to save Hard error interrupt +LISTDEV DD ? ;Pointer to Device +COLPOS DB 0 ;Column position for TAB processing +CURRFIL DB 0 +NXTCHR DW ? +CURRHAND DW -1 +PrinterNum DW -1 ; index for printer +QueueLock db 0 ; queue lock, 0=unlocked + + +PChar db ? ; path character +AmbCan db ? ; = 1 ambigous cancel +CanFlg db ? ; = 1 Current was already canceled +ACanOcrd db ? ; = 1 a file was found during an + ; ambigous cancel + +;--- Warnning: this is a FCB!! +ACBuf db ? +ACName db 8 dup(?) +ACExt db 3 dup(?) + db 4 dup(?) ; how big is an unopened fcb??? + + +CONTXTFLAG DB 0 ;0 means his context, NZ means me +HISPDB DW ? +PABORT DB 0 ;Abort flag +BLKSIZ DW 512 ;Size of the PRINT I/O block in bytes +ENDPTR DW ? + +COMDISP LABEL WORD ; Communications dispatch table + DW OFFSET CodeR:INST_REQ + DW OFFSET CodeR:ADDFIL + DW OFFSET CodeR:CANFIL + DW offset CodeR:CanAll + DW OFFSET CodeR:QSTAT + DW offset CodeR:EndStat + DW offset CodeR:QSTATDEV + +;Resident messages + +MESBAS DW OFFSET CodeR:ERR0 + DW OFFSET CodeR:ERR1 + DW OFFSET CodeR:ERR2 + DW OFFSET CodeR:ERR3 + DW OFFSET CodeR:ERR4 + DW OFFSET CodeR:ERR5 + DW OFFSET CodeR:ERR6 + DW OFFSET CodeR:ERR7 + DW OFFSET CodeR:ERR8 + DW OFFSET CodeR:ERR9 + DW OFFSET CodeR:ERR10 + DW OFFSET CodeR:ERR11 + DW OFFSET CodeR:ERR12 +ENDRES DW ? ; filled in at initialization time +PRNR001E: + +CodeR EndS + + + +BREAK + +CodeR Segment public para + +Break + +TestSetServer: +IF IBM + CLC + PUSH AX + MOV AX,8700h ; Can I run? + INT 2Ah + POP AX +ENDIF + ret + +LeaveServer: +IF IBM + PUSH AX + MOV AX,8701h + INT 2Ah + POP AX +ENDIF + ret + +;Interrupt routines +ASSUME CS:CodeR,DS:NOTHING,ES:NOTHING,SS:NOTHING +; +; PRINT is stimulated by a hardware interrupt. +; +; +; The Server may also stimulate us during timer ticks (if we handled the +; ticks ourselves, it would be disasterous. Therefore, we have a substitute +; entry here that simulates the timer stuff but does NOT muck with the ports. +; + IF HARDINT +FakeINT1C: + MOV fFake,-1 + JMP SHORT InnerHardInt + +HDSPINT: ;Hardware interrupt entry point + mov fFake,0 +InnerHardInt: + CALL TestSetServer + JNC TickTime + jmp ChainInt +TickTime: + INC [TICKCNT] ;Tick + INC [TICKSUB] ;Tick + CMP [SLICECNT],0 + JZ TIMENOW + DEC [SLICECNT] ;Count down + JMP SHORT HardIntDone ;Not time yet +TIMENOW: + CMP BUSY,0 ;See if interrupting ourself + JNZ HardIntDone + + IF IBM + push ax ; check for nested interrupts + mov al,00001011b ; select ISR in 8259 + out 20H,al + JMP x +x: + in al,20H ; get ISR register + and al,0FEH ; mask timer int + pop ax + jnz HardIntDone ; there was another int in service... + ENDIF + + PUSH DS + PUSH SI + LDS SI,[INDOS] ;Check for making DOS calls +; +; WARNING!!! Due to INT 24 clearing the INDOS flag, we must test both INDOS +; and ERRORMODE at once! These must be contiguous in MSDATA. +; + CMP WORD PTR [SI-1],0 + POP SI + POP DS + JNZ HardIntDone ;DOS is Busy + INC [BUSY] ;Exclude furthur interrupts + MOV [TICKCNT],0 ;Reset tick counter + MOV [TICKSUB],0 ;Reset tick counter + STI ;Keep things rolling + + IF AINT + TEST fFake,-1 + JNZ NoAck + PUSH AX + MOV AL,EOI ;Acknowledge interrupt + OUT AKPORT,AL + POP AX +NoAck: + ENDIF + + CALL DOINT + CLI + PUSH AX + MOV AL,[TIMESLICE] + MOV [SLICECNT],AL ;Either soft or hard int resets time slice + POP AX + DEC Busy ;Done, let others in +HardIntDone: + Call LeaveServer +CHAININT: + TEST fFake,-1 + JNZ DoIRET + JMP [NEXTINT] ;Chain to next clock routine +DoIRET: + IRET + ENDIF + + +; +; PRINT is stimulated by a spooler idle interrupt +; +SPINT: ;INT 28H entry point + CALL TestSetServer + JC NxtSp + + IF HARDINT + CMP [BUSY],0 + JNZ SpIntDone + INC [BUSY] ;Exclude hardware interrupt + INC [SOFINT] ;Indicate a software int in progress + ENDIF + + STI ;Hardware interrupts ok on INT 28H entry + CALL DOINT + + IF HARDINT + CLI + MOV [SOFINT],0 ;Indicate INT done + PUSH AX + MOV AL,[TIMESLICE] + MOV [SLICECNT],AL ;Either soft or hard int resets time slice + POP AX + DEC Busy + ENDIF +SpIntDone: + call LeaveServer + +NXTSP: JMP [SPNEXT] ;Chain to next INT 28 + +; +; Since we may be entering at arbitrary times, we need to get/set the extended +; error as we may end up blowing it away. We do not do this on spooler ints. +; + +public PRNR002S, PRNR002E +PRNR002S: + +SaveState DPL <> ; empty DPL + +PRNR002E: + +public enterprint +EnterPRINT: + IF HardInt + TEST SofInt,-1 + JNZ EnterDone + ENDIF + MOV AH,GetExtendedError + CALL DO_21 + MOV SaveState.DPL_AX,AX + MOV SaveState.DPL_BX,BX + MOV SaveState.DPL_CX,CX + MOV SaveState.DPL_DX,DX + MOV SaveState.DPL_SI,SI + MOV SaveState.DPL_DI,DI + MOV SaveState.DPL_DS,DS + MOV SaveState.DPL_ES,ES +EnterDone: + RET + +public leaveprint +LeavePRINT: + IF HardInt + TEST SofInt,-1 + JNZ LeaveDone + ENDIF + MOV AX,(ServerCall SHL 8) + 10 + PUSH CS + POP DS + MOV DX,OFFSET CodeR:SaveState + CALL Do_21 +LeaveDone: + RET + +public doint +DOINT: +ASSUME CS:CodeR,DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [CURRFIL],0 + JNZ GOAHEAD +SPRET: + ret ;Nothing to do + +GOAHEAD: + cmp [QueueLock],1 + je spret ; queue locked, do nothing... + PUSH AX ;Need a working register + MOV [SSsave],SS + MOV [SPsave],SP + MOV AX,CS + CLI +;Go to internal stack to prevent INT 24 overflowing system stack + MOV SS,AX + MOV SP,OFFSET CodeR:ISTACK + STI + PUSH ES + PUSH DS + PUSH BP + PUSH BX + PUSH CX + PUSH DX + PUSH SI + PUSH DI + PUSH CS + POP DS +ASSUME DS:CodeR + + Call EnterPRINT + + MOV BX,[NXTCHR] + CMP BX,[ENDPTR] + JB PLOOP + JMP READBUFF ;Buffer empty + +DONEJMPJP: + POPF +DONEJMPJ: + JMP DONEJMP + +FILEOFJ: +ASSUME DS:CodeR + JMP FILEOF + +PLOOP: + IF HARDINT + MOV BX,[NXTCHR] + CMP BX,[ENDPTR] + JAE DONEJMPJ ;Buffer has become empty + CMP [SOFINT],0 + JNZ STATCHK + PUSH AX + MOV AL,[MAXTICK] + CMP [TICKCNT],AL ;Check our time slice + POP AX + JAE DONEJMPJ +STATCHK: + ENDIF + + CALL PSTAT + PUSHF + CMP [CURRFIL],0 + JZ DONEJMPJP ;File got cancelled by error + POPF + + IF HARDINT + JZ DOCHAR ;Printer ready + CMP [SOFINT],0 + ENDIF + + JNZ DONEJMP ;If soft int give up + + IF HARDINT + PUSH AX + MOV AL,[BUSYTICK] + CMP [TICKSUB],AL ;Check our busy timeout + POP AX + JAE DONEJMP + JMP PLOOP + ENDIF + +DOCHAR: + MOV AL,BYTE PTR [BX] + CMP AL,1AH ;^Z? + JZ FILEOFJ ;CPM EOF + CMP AL,0DH ;CR? + JNZ NOTCR + MOV [COLPOS],0 +NOTCR: + CMP AL,9 ;TAB? + JNZ NOTABDO + MOV CL,[COLPOS] ;expand tab to # spaces + OR CL,0F8H + NEG CL + XOR CH,CH + JCXZ TABDONE ;CX contains # spaces to print +TABLP: + MOV AL," " + INC [COLPOS] + PUSH CX + CALL POUT + POP CX + DEC CX ;G + JZ TABDONE ;G We're done - get next char + JMP PLOOP ;G Keep processing tab + +;G LOOP TABLP +;G JMP TABDONE + +NOTABDO: + CMP AL,8 ;Back space? + JNZ NOTBACK + DEC [COLPOS] +NOTBACK: + CMP AL,20H ;Non Printing char? + JB NOCHAR + INC [COLPOS] ;Printing char +NOCHAR: + CALL POUT ;Print it +TABDONE: + INC [NXTCHR] ;Next char + + IF HARDINT + MOV [TICKSUB],0 ;Got a character out, Reset counter + CMP [SOFINT],0 ;Soft int does one char at a time + JNZ DONEJMP + JMP PLOOP + ENDIF + +DONEJMP: + CALL CONTEXT_BACK + Call LeavePRINT + + POP DI + POP SI + POP DX + POP CX + POP BX + POP BP + POP DS + POP ES +ASSUME DS:NOTHING,ES:NOTHING + CLI + MOV SS,[SSsave] ;Restore Entry Stack + MOV SP,[SPsave] + STI + POP AX + RET + +CONTEXT_BACK: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [CONTXTFLAG],0 + JZ CONTOK + SaveReg + MOV BX,[HISPDB] + MOV AH,SET_CURRENT_PDB + call do_21 + RestoreReg + MOV [CONTXTFLAG],0 +CONTOK: + RET + +CONTEXT_SWITCH: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [CONTXTFLAG],0 + JNZ RET45 + SaveReg + MOV AH,GET_CURRENT_PDB + call do_21 + MOV [HISPDB],BX + MOV BX,CS + sub bx,10h ; The 2.5 print is an exe program + MOV AH,SET_CURRENT_PDB + call do_21 + RestoreReg + MOV [CONTXTFLAG],1 +RET45: RET + + +;--- Refill the print buffer --- +READBUFF: +ASSUME DS:CodeR,ES:NOTHING,SS:NOTHING + + call Set24 ; switch Int24 vector + MOV [PABORT],0 ;No abort + MOV BX,[CURRHAND] + MOV CX,[BLKSIZ] + MOV DX,[BUFFER] + MOV AH,READ + call My21 + PUSHF + call Res24 ; reset Int 24 vector + CMP [PABORT],0 + JZ NOHERR + POP AX ;Flags from read + jmp FilClose ;Barf on this file, got INT 24 + + +NOHERR: + POPF + JC FILEOF + CMP AX,0 + JZ FILEOF ;Read EOF? + MOV BX,[BUFFER] ;Buffer full + MOV DI,BX + ADD DI,AX + MOV [NXTCHR],BX + MOV CX,[BLKSIZ] + SUB CX,AX + JCXZ DONEJ ; Buffer is completely full + PUSH CS + POP ES + MOV AL,1AH + cld + REP STOSB ; ^Z pad the buffer +DONEJ: + JMP DONEJMP + +FILEOF: + MOV AL,0CH ;Form feed + CALL POUT + +;--- Close file +; note: we came here from an i24 then PAbort is already = 1 +FilClose: + call Set24 + mov pAbort,-1 + MOV BX,[CURRHAND] + MOV AH,CLOSE + call My21 + call Res24 + MOV [CURRFIL],0 ; No file + MOV [CURRHAND],-1 ; Invalid handle + MOV AX,[ENDPTR] + MOV [NXTCHR],AX ; Buffer empty + +;--- Send close on output device + call Close_Dev + +;--- compact the print queue +CompQAgn: + call CompQ + +;--- Check if there are any more files to print + mov si,offset CodeR:FileQueue + cmp byte ptr [si],0 ; no more left if name starts with nul + je NoFilesLeft + call Set24 + MOV [PABORT],0 ;No abort + mov dx,si ; DS:DX points to file name + mov ax,(open shl 8) + call My21 ; try opening new file + pushf + call Res24 + cmp [PAbort],0 + je NoI24a + popf + jmp short CompQAgn ; try next file + +NoI24a: + popf + jnc GotNewFile + call PrtOpErr + jmp short CompQAgn + +GotNewFile: ; buffer was already marked as empty + mov [CurrHand],ax + mov [CurrFil],1 + +;--- Send Open on output device + call Open_Dev + +NoFilesLeft: + JMP DONEJMP + + +;--- Print open error --- +; preserves DS + +PrtOpErr: +assume ds:CodeR,es:Nothing + +; This stuff constitutes a "file" so it is bracketed by an open/close +; on the output device. + +;--- Send Open on output device + call Open_Dev + + push cs + pop es +assume es:CodeR + mov si,offset CodeR:ErrMes + call ListMes + mov si,offset CodeR:ErrMesT2 + call ListMes + mov si,offset CodeR:FileQueue + call ListMes2 + mov si,offset CodeR:BelMes + call ListMes + +;--- Send close on output device + call Close_Dev + + ret + + +;--- Compact File Queue --- +; modifies: AX,CX,SI,DI,ES + +CompQ: +assume ds:CodeR,es:nothing,ss:nothing + push cs + pop es +assume es:CodeR + mov di,offset CodeR:FileQueue ; ES:DI points to top of queue + mov si,(offset CodeR:FileQueue + MaxFileLen) ; DS:SI points to next entry + mov cx,[EndQueue] + sub cx,si ; length in bytes of the queue + cld + rep movsb ; compact the queue + mov ax,[QueueTail] ; normalize tail pointer as we + sub ax,MaxFileLen ; know have a new "next empty slot" + mov [QueueTail],ax + mov si,ax + mov byte ptr [si],0 ; nul first byte of last entry + ret + + +BREAK + +;--- Set Local Int 24 vector --- +; modifies: AX,DX + +Set24: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + push es + push bx + push dx + MOV AL,24H + MOV AH,GET_INTERRUPT_VECTOR + call do_21 + MOV WORD PTR [HERRINT+2],ES ; Save current vector + MOV WORD PTR [HERRINT],BX + MOV DX,OFFSET CodeR:DSKERR + MOV AL,24H + MOV AH,SET_INTERRUPT_VECTOR ; Install our own + call do_21 ; Spooler must catch its errors + pop dx + pop bx + pop es + ret + + +;--- Reset Old Int 24 vector --- +; modifies: none + +Res24: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + push ds + PUSH AX + push dx + LDS DX,[HERRINT] +ASSUME DS:NOTHING + MOV AL,24H + MOV AH,SET_INTERRUPT_VECTOR + call do_21 ;Restore Error INT + pop dx + POP AX + pop ds + ret + + +;--- INT 24 handler --- +DSKERR: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [PABORT],0 + JNZ IGNRET + STI + PUSH BX + PUSH CX + PUSH DX + PUSH DI + PUSH SI + PUSH BP + PUSH ES + PUSH DS + PUSH CS + POP DS + PUSH CS + POP ES +ASSUME DS:CodeR,ES:CodeR + ADD [BADDRVM],AL ;Set correct drive letter + MOV SI,OFFSET CodeR:ERRMES + CALL LISTMES + TEST AH,080H + JNZ FATERR + AND DI,0FFH + CMP DI,12 + JBE HAVCOD + MOV DI,12 +HAVCOD: + MOV [I24_ERR],DI + SHL DI,1 + MOV DI,WORD PTR [DI+MESBAS] ; Get pointer to error message + MOV SI,DI + CALL LISTMES ; Print error type + MOV SI,OFFSET CodeR:ERRMEST + CALL LISTMES + mov si,offset CodeR:FileQueue ; print filename + call ListMes2 ; print name + mov si,offset CodeR:BelMes + call ListMes +SETABORT: + INC [PABORT] ;Indicate abort + POP DS + POP ES + POP BP + POP SI + POP DI + POP DX + POP CX + POP BX +IGNRET: + XOR AL,AL ;Ignore + IRET + +FATERR: + MOV [I24_ERR],0FFH + MOV SI,OFFSET CodeR:FATMES + CALL LISTMES + JMP SHORT SETABORT + + +BREAK + +;--- Communications interrupt --- +SPCOMINT proc far +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP AH,1 + JBE MINE + JMP [COMNEXT] + +MINE: + CMP AL,0F8H + JAE RESERVED_RET +IF HardInt + CMP AX,0080h + JNZ CheckPSP + JMP FakeINT1C +ENDIF +CheckPSP: + OR AH,AH + JNE PSPDO + MOV AL,1 ; Tell PSPRINT to go away (AH = 1) +RESERVED_RET: + IRET + +PSPDO: + OR AL,AL + JNE PSPDISP +INST_REQ: + MOV AL,0FFH + IRET + +PSPDISP: + CMP [BUSY],0 + JZ SETCBUSY +ErrBusy: + MOV AX,error_busy +setcret: + push bp + mov bp,sp + or word ptr [bp+6],f_Carry + pop bp + iret + +SETCBUSY: + XOR AH,AH + CMP AX,6 ; check function within valid range + Jbe GoForIt + mov ax,error_invalid_function + jmp setcret +GoForIt: + INC [BUSY] ;Exclude + STI ;Turn ints back on + PUSH DI ;G + PUSH ES + PUSH DS + PUSH CS + POP DS +ASSUME DS:CodeR + mov [QueueLock],0 ; unlock the print queue + SHL AX,1 ;Turn into word index + mov di,ax + call ComDisp[DI] + assume ds:nothing + jc ErrRet +ASSUME DS:CodeR,ES:NOTHING + push ds + push cs + pop ds +ASSUME DS:CodeR,ES:NOTHING + CALL PSTAT ; Tweek error counter + pop ds + assume ds:nothing +ErrRet: + pushf + call Context_Back + popf + CLI + DEC BUSY ; leaves carry alone! + POP DS +ASSUME DS:NOTHING + POP ES + POP DI ;G + jc setcret + push bp + mov bp,sp + and word ptr [bp+6],NOT f_Carry + pop bp + iret +SpComInt Endp + +BREAK + +;--- Return pointer to file queue --- +QSTAT: +ASSUME DS:CodeR,ES:NOTHING + + mov [QueueLock],1 ; lock the print queue + CALL PSTAT ; Tweek error counter + push bp + mov bp,sp ; 0 2 4 + MOV [bp+ 2 + 2],cs ; + POP BP + mov si,offset CodeR:FileQueue + mov dx,[ErrCnt] ; return error count + clc + ret + +;--- Return pointer to device driver if active --- +QSTATDEV: +ASSUME DS:CodeR,ES:NOTHING + + xor ax,ax ;g assume not busy + mov [QueueLock],1 ;g lock the print queue + CALL PSTAT ;g Tweek error counter + cmp byte ptr FileQueue,0 ;g is there anything in the queue? + clc ;g + jz qstatdev_end ;g no - just exit + mov ax,error_queue_full ;g yes - set error queue full + mov si,word ptr [listdev+2] ;g get segment of list device + push bp ;g + mov bp,sp ;g 0 2 4 + MOV [bp+2+2],si ;g seg of device to DS + pop bp ;g + mov si,word ptr [listdev] ;g offset of device to SI + stc ;g + +qstatdev_end: ;g + mov [QueueLock],0 ;g unlock the print queue + ret ;g + +BREAK + +;--- Unlock the print queue --- +EndStat: +assume ds:CodeR,es:nothing + mov [QueueLock],0 + clc + ret + +BREAK + +; +; Note that we need to spin until the background is free +; +CanAll: +assume ds:CodeR,es:nothing + + cmp [CurrFil],0 ; are we currently printing? + jnz DoCanAll ; yes, go and cancel + ret ; carry is clear + +DoCanAll: + +;--- Cancel active file + mov bx,[CurrHand] ; close the current file + call Set24 + mov [PAbort],1 ; no Int24's + mov ah,Close + call My21 + call Res24 + mov [CurrFil],0 ; no files to print + mov [CurrHand],-1 ; invalidate handle + mov ax,[EndPtr] ; buffer empty + mov [NxtChr],ax + +;--- Cancel rest of files + mov si,offset CodeR:FileQueue + mov [QueueTail],si ; next free entry is the first + mov byte ptr [si],0 ; nul first byte of firts entry + mov si,offset CodeR:AllCan + call ListMes ; print cancelation message + mov si,offset CodeR:BelMes + call ListMes ; ring!! + +;--- Send close on output device + call Close_Dev + clc + ret + +BREAK + +CANFIL: +ASSUME DS:CodeR,ES:NOTHING + + CMP [CURRFIL],0 + JNZ DOCAN + ret ; carry is clear + +DOCAN: + +;--- find which file to cancel + push bp + mov bp,sp ; 0 2 4 + MOV ds,[bp+ 2 + 2] ; + POP BP + +assume ds:nothing + push cs + pop es +assume es:CodeR + mov CS:[CanFlg],0 ; reset message flag + mov CS:[ACanOcrd],0 ; no cancelation has ocured yet + mov bx,offset CodeR:FileQueue ; ES:BX points to 1st entry in queue + call AmbChk + +AnotherTry: + mov di,bx ; ES:DI points to 1st entry in queue + mov si,dx ; DS:SI points to filename to cancel +MatchLoop: + lodsb + cmp al,byte ptr es:[di] ; names in queue are all in upper case + je CharMatch + call UpConv ; did not match, try upper case + cmp al,byte ptr es:[di] + jne AnotherName ; a mismatch, try another name +CharMatch: + cmp es:byte ptr es:[di],0 ; was this the terminating nul? + je NameFound ; yes we got our file... + inc di + jmp MatchLoop + +AnotherName: + cmp CS:[AmbCan],1 ; ambigous file name specified? + jne AnName ; if not then no more work to do + cmp al,"?" + jne AnName + cmp byte ptr es:[di],"." + je FindPeriod + cmp byte ptr es:[di],0 ; if nul then file names match + jne CharMatch ; only if only ?'s are left... +FindNul: + lodsb + cmp al,"?" + je FindNul + cmp al,"." + je FindNul + or al,al + jne AnName ; found something else, no match + jmp short NameFound + +FindPeriod: ; ambigous files always have 8 chars + lodsb ; in name so we can not look for the + or al,al ; period twice (smart uh?) + je AnName ; no period found, files do not match + cmp al,"." + jne FindPeriod + jmp short CharMatch + +AnName: + add bx,MaxFileLen + cmp byte ptr es:[bx],0 ; end of queue? + jne AnotherTry ; no, continue... + cmp CS:[ACanOcrd],1 ; yes, was there a file found? + jne sk2 + push cs + pop ds +assume ds:CodeR ; StartAnFil likes it this way... + jmp StartAnFil ; restart printing + +sk2: +assume ds:nothing + + mov ax,error_file_not_found + stc + ret + + +;--- Name found, check if current file +NameFound: + push cs + pop ds +assume ds:CodeR + mov [ACanOcrd],1 ; remember we found a file + cmp bx,offset CodeR:FileQueue ; is the file being printed? + jne NotCurrent ; no, just compact the queue + cmp [CanFlg],0 + jne NotCurrent ; only cance current once + +;--- Cancel current file + mov [CanFlg],1 ; remeber we already canceled current + push bx + mov bx,[CurrHand] ; close the current file + call Set24 + mov [PAbort],1 ; no Int24's + mov ah,Close + call My21 + call Res24 + mov [CurrFil],0 ; no files to print + mov [CurrHand],-1 ; invalidate handle + mov ax,[EndPtr] ; buffer empty + mov [NxtChr],ax + pop bx + +;--- print cancelation message + push bx + mov si,offset CodeR:CanMes + call ListMes ; print cancelation message + mov si,bx ; points to filename + call ListMes2 ; print filename + mov si,offset CodeR:CanFilNam + call ListMes + mov si,offset CodeR:BelMes + call ListMes ; ring!! + pop bx + +;--- Send close on output device + call Close_Dev + +NotCurrent: + mov di,bx ; DI points to entry to cancel + mov si,bx + add si,MaxFileLen ; SI points to next entry + cmp si,[QueueTail] ; is the entry being canceled the last? + jne DoCompact ; no, do compaction + mov byte ptr [di],0 ; yes, just nul the first byte + jmp short CompactDone +DoCompact: + mov cx,[EndQueue] ; CX points to the end of the queue + sub cx,si ; length of the remainning of the queue + cld + rep movsb ; compact the queue +CompactDone: + mov ax,[QueueTail] ; remember new end of queue + sub ax,MaxFileLen + mov [QueueTail],ax + mov si,ax + mov byte ptr [si],0 ; nul first byte of last entry + + cmp byte ptr [bx],0 ; is there another file to consider? + je StartAnFil + push bp + mov bp,sp ; 0 2 4 + MOV ds,[bp+ 2 + 2] ; + POP BP +assume ds:nothing + jmp AnotherTry ; yes do it again... + + +;--- Start new file... +StartAnFil: +assume ds:CodeR + cmp [CurrHand],-1 ; was the canceled name the current? + jne NoneLeft ; no, just quit +StartAnFil2: + mov si,offset CodeR:FileQueue ; points to new current file + cmp byte ptr[si],0 ; is there one there? + je NoneLeft ; no, we canceled current and are none left + call Set24 + mov [PAbort],0 + mov dx,si + mov ax,(open shl 8) + call My21 + pushf + call Res24 + cmp [PAbort],0 + je NoI24b + popf + call CompQ ; compact file queue + jmp short StartAnFil2 + +NoI24b: + popf + jnc GoodNewCurr + call PrtOpErr ; print open error + call CompQ ; compact file queue + jmp short StartAnFil2 + +GoodNewCurr: + mov [CurrHand],ax ; save handle + mov [CurrFil],1 ; signal active (buffer is already empty) + +;--- Send Open on output device + call Open_Dev +NoneLeft: + clc + ret + +;--- Upper case conversion --- +UpConv: + CMP AL,'a' + JB NOCONV + CMP AL,'z' + JA NOCONV + SUB AL,20H +NOCONV: + RET + + +;--- Ambigous file name check --- +; entry: ds:dx points to filename +; preserves ds:dx and es +; +assume ds:nothing,es:CodeR +AmbChk: + mov CS:[AmbCan],0 ; assume not ambigous + mov si,dx + cld +AmbLoop: + lodsb + or al,al ; the nul? + jne AmbLoop + dec si ; points to nul + std ; scan backwards +ScanBack: + lodsb + cmp al,"*" + jne NotAStar + mov CS:[AmbCan],1 +NotAStar: + cmp al,"?" + jne NotAQues + mov CS:[AmbCan],1 +NotAQues: + cmp al,CS:[PChar] + jne ScanBack + cld ; be safe + cmp CS:[AmbCan],1 ; an ambigous cancel? + je AmbCanFnd ; no, just proceed + ret + +;--- transform * to ?'s +AmbCanFnd: + inc si + inc si ; points to actual name (past path char) + mov di,offset CodeR:ACBuf + push di + mov cx,12 + mov al,20h + cld + rep stosb ; fill fcb with blanks + pop di + push si + mov ax,(Parse_file_descriptor shl 8) and 0FF00h + call My21 + pop si + +;--- Copy name to expanded name + push ds + pop es +assume ds:nothing + push cs + pop ds +assume ds:CodeR + push es + mov di,si + mov si,offset CodeR:ACName + mov cx,8 +ACMovNam: + lodsb ; move name + cmp al,20h + je ACMovDn1 + stosb + loop ACMovNam + +ACMovDn1: + mov si,offset CodeR:ACExt + cmp byte ptr [si],20h ; if extension starts with blank + je ACMovDn2 ; then do not put period + mov al,"." + stosb + mov cx,3 + +ACMovExt: + lodsb ; move name + cmp al,20h + je ACMovDn2 + stosb + loop ACMovExt + +ACMovDn2: + mov byte ptr es:[di],0 ; nul terminate + pop ds +assume ds:nothing + push cs + pop es +assume es:CodeR + ret + + + +BREAK + +ADDFIL: +ASSUME DS:CodeR,ES:NOTHING + +;--- Check that queue is not full + mov di,[QueueTail] ; load pointer to next empty entry + cmp di,[EndQueue] ; queue full? + jb OkToQueue ; no, place in queue... + mov ax,error_queue_full + stc + ret + +;--- Copy name to empty slot in queue +OkToQueue: +; +; Retrieve old DS +; + push bp + mov bp,sp ; 0 2 4 + MOV ds,[bp+ 2 + 2] ; + POP BP + +assume ds:nothing + push cs + pop es ; ES:DI points to empty slot +assume es:CodeR + mov si,dx ; DS:SI points to submit packet + cmp byte ptr ds:[si],0 + jnz IncorrectLevel + lds si,dword ptr ds:[si+1] ; DS:SI points to filename + mov cx,MaxFileLen ; maximum length of file name +CopyLop: + lodsb + call UpConv ; convert to upper case + stosb + or al,al ; nul? + je CopyDone ; yes, done with move... + loop CopyLop + push cs + pop ds +assume ds:CodeR + mov ax,error_name_too_long ; if normal exit from the loop then + stc + ret + +IncorrectLevel: + mov ax,error_invalid_function + stc + ret + +assume ds:nothing,es:nothing ; es:nothing = not true but lets +CopyDone: ; avoid possible problems... + push cs + pop ds +assume ds:CodeR + +;--- advance queue pointer + mov si,[QueueTail] ; pointer to slot just used + push si ; save for test open later + add si,MaxFileLen + mov [QueueTail],si ; store for next round + mov byte ptr [si],0 ; nul next entry (maybe the EndQueue) + +;--- Check that file exists + call Set24 + mov [PAbort],0 + pop dx ; get pointer to filename + MOV AX,(OPEN SHL 8) + call My21 + pushf + PUSH DX + call Res24 + POP DX + popf + JNC GOTFIL +; +; See if brain damaged user entered an invalid drive +; + PUSH AX + MOV SI,DX + CMP BYTE PTR CS:[SI+1],':' + JZ GotDrive + POP AX + JMP SHORT i24bf +GotDrive: + MOV AH,Get_default_drive ; get current + CALL My21 + PUSH AX + MOV DL,CS:[SI] ; get drive letter to test + OR DL,20h + SUB DL,'a' + MOV AH,Set_Default_Drive ; set it + CALL My21 + MOV AH,Get_default_drive ; get it back + CALL My21 + CMP AL,DL ; same? + JNZ BadDrive ; no, bad drive + POP DX ; get original back + MOV AH,Set_Default_Drive ; set original + CALL My21 + POP AX + MOV DX,SI + JMP SHORT i24bf +BadDrive: + POP DX ; get original back + MOV AH,Set_Default_Drive ; set original + CALL My21 + POP AX + MOV AX,error_invalid_drive + MOV DX,SI +I24BF: + mov si,[QueueTail] ; take bad name out of queue + sub si,MaxFileLen ; SI points to the slot with bad name + mov [QueueTail],si + mov byte ptr [si],0 ; nul the first byte + stc + ret + + +;--- Check if print currently busy +GotFil: + CMP [CURRFIL],0 ; currently printing? + JZ OKAFIL ; no, start new print + mov bx,ax ; busy, close handle + call Set24 + mov [PAbort],1 ; no Int24's + mov ah,Close + call My21 + call Res24 + clc + ret + +;--- Save file data +OKAFIL: + MOV [CURRHAND],AX ; Valid handle + MOV AX,[ENDPTR] + MOV [NXTCHR],AX ; Buffer empty + MOV [CURRFIL],1 + +;--- Send Open on output device + call Open_Dev + clc + ret + +BREAK + +; +; perform a system call as myself +; +My21: + call Context_switch + call Do_21 + ret + +Public do_21 +DO_21: +ASSUME DS:NOTHING,ES:NOTHING + IF IBM + CMP BYTE PTR CS:[INT15FLAG],0 + JZ REAL_21 + PUSH DS + PUSH BX + LDS BX,CS:[INT15PTR] + INC BYTE PTR [BX] + POP BX + POP DS + CALL OffSave + INT 21H + Call OnSave + PUSH DS + PUSH BX + PUSHF ; Flags from system call + LDS BX,CS:[INT15PTR] + DEC BYTE PTR [BX] + POPF + POP BX + POP DS + RET + ENDIF + +REAL_21: + Call OffSave + INT 21H + CALL OnSave + RET + +OffSave: + ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSH AX + PUSH DX + MOV AX,Set_CTRL_C_Trapping SHL 8 + 2 + XOR DL,DL + INT 21h + MOV CtrlC,DL + POP DX + POP AX + ret + +OnSave: + ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSH AX + PUSH DX + MOV AX,Set_CTRL_C_Trapping SHL 8 + 2 + MOV DL,CtrlC + INT 21h + POP DX + POP AX + ret + +BREAK + +ListMes2: +ASSUME DS:CodeR,ES:NOTHING + LODSB + cmp al,0 + jz LMesDone + CALL LOUT + JMP short LISTMES2 + + +LISTMES: +ASSUME DS:CodeR,ES:NOTHING + LODSB + CMP AL,"$" + JZ LMESDONE + CALL LOUT + JMP short LISTMES + +LMESDONE: + RET + +LOUT: + PUSH BX +LWAIT: + CALL PSTAT + JZ PREADY + CMP [ERRCNT],ERRCNT2 + JA POPRET ;Don't get stuck + JMP SHORT LWAIT +PREADY: + CALL POUT +POPRET: + POP BX + RET + +;Stuff for BIOS interface +IOBUSY EQU 0200H +IOERROR EQU 8000H + +public PRNR003S, PRNR003E +PRNR003S: + +BYTEBUF DB ? + +CALLAD DD ? + +IOCALL DB 22 + DB 0 +IOREQ DB ? +IOSTAT DW 0 + DB 8 DUP(?) + DB 0 + DW OFFSET CodeR:BYTEBUF +INTSEG DW ? +IOCNT DW 1 + DW 0 + +PRNR003E: + +; Following two routines perform device open and close on output device. +; NO REGISTERS (including flags) are modified. No errors generated. + +public open_dev +Open_Dev: +ASSUME DS:NOTHING,ES:NOTHING +; +; We are now going to use the printer... We must lock down the printer so +; that the network does not intersperse output on us... +; We must also signal the REDIRector for stream open. +; We must ask DOS to set the Printer Flag to busy +; + PUSH BX + PUSHF + PUSH AX + PUSH DX + MOV DX,PrinterNum + CMP DX,-1 + JZ NoORop + MOV AX,0203h ; redirector lock + INT 2FH + MOV AX,0201H ; Redirector OPEN + INT 2FH +NoORop: + mov ax,(SET_PRINTER_FLAG SHL 8) + 01 + int 21H + POP DX + POP AX + MOV BL,DEVOPN ; Device OPEN + CALL OP_CL_OP + POPF + POP BX + RET + +OP_CL_OP: + PUSH DS + PUSH SI + LDS SI,[LISTDEV] +ASSUME DS:NOTHING + TEST [SI.SDEVATT],DEVOPCL + JZ NO_OP_CL + PUSH CS + POP DS +ASSUME DS:CodeR + MOV [IOCALL],DOPCLHL + CALL DOCALL +NO_OP_CL: + POP SI + POP DS +ASSUME DS:NOTHING + Ret + + +public close_dev +Close_Dev: +ASSUME DS:NOTHING,ES:NOTHING +; +; At this point, we release the ownership of the printer... +; and do a redirector CLOSE. +; Also tell DOS to reset the Printer Flag +; + PUSH BX + PUSHF + MOV BL,DEVCLS + CALL OP_CL_OP ; Device CLOSE + PUSH AX + PUSH DX + MOV DX,PrinterNum + CMP DX,-1 + JZ NoCRop + MOV AX,0202H ; redirector CLOSE + INT 2FH + MOV AX,0204h ; redirector clear + INT 2FH +NoCRop: + MOV AX,(SET_PRINTER_FLAG SHL 8) +00 + INT 21H + POP DX + POP AX + POPF + POP BX + RET + +PSTAT: +ASSUME DS:CodeR + PUSH BX + INC [ERRCNT] + MOV BL,DEVOST + MOV [IOCALL],DSTATHL + CALL DOCALL + TEST [IOSTAT],IOERROR + JZ NOSTATERR + OR [IOSTAT],IOBUSY ;If error, show buisy +NOSTATERR: + TEST [IOSTAT],IOBUSY + JNZ RET13P ;Shows buisy + MOV [ERRCNT],0 +RET13P: + POP BX + RET + +POUT: +ASSUME DS:CodeR + MOV [BYTEBUF],AL + MOV BL,DEVWRT + MOV [IOCALL],DRDWRHL +DOCALL: + PUSH ES + MOV [IOREQ],BL + MOV BX,CS + MOV ES,BX + MOV [IOSTAT],0 + MOV [IOCNT],1 + PUSH DS + PUSH SI + PUSH AX + call Context_Switch + MOV BX,OFFSET CodeR:IOCALL + LDS SI,[LISTDEV] +ASSUME DS:NOTHING + MOV AX,[SI+SDEVSTRAT] + MOV WORD PTR [CALLAD],AX + CALL [CALLAD] + MOV AX,[SI+SDEVINT] + MOV WORD PTR [CALLAD],AX + CALL [CALLAD] + POP AX + POP SI + POP DS +ASSUME DS:CodeR + POP ES + RET + + IF IBM +Public PRNR004S, PRNR004E +PRNR004S: + +REAL_INT_13 DD ? +INT_13_RETADDR DW OFFSET CodeR:INT_13_BACK + +PRNR004E: + +INT_13 PROC FAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSHF + INC [BUSY] ;Exclude if dumb program call ROM + PUSH CS + PUSH [INT_13_RETADDR] + PUSH WORD PTR [REAL_INT_13+2] + PUSH WORD PTR [REAL_INT_13] + RET +INT_13 ENDP + +INT_13_BACK PROC FAR + PUSHF + DEC [BUSY] + POPF + RET 2 ;Chuck saved flags +INT_13_BACK ENDP + ENDIF + + + IF IBM + +Public PRNR005S, PRNR005E +PRNR005S: + +REAL_INT_15 DD ? +INT15FLAG DB 0 ; Init to off +INT15PTR DD ? + +PRNR005E: + +INT_15 PROC FAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP AH,20H + JNZ REAL_15 ; Not my function + CMP AL,1 + JA REAL_15 ; I only know 0 and 1 + JE FUNC1 + INC [INT15FLAG] ; Turn ON + MOV WORD PTR [INT15PTR],BX ; Save counter loc + MOV WORD PTR [INT15PTR+2],ES + IRET + +FUNC1: + MOV [INT15FLAG],0 ; Turn OFF + IRET + +REAL_15: + JMP [REAL_INT_15] + +INT_15 ENDP + + +Public PRNR006S, PRNR006E +PRNR006S: + +FLAG17_14 DB 0 ; Flags state of AUX/PRN redir +REAL_INT_5 DD ? +REAL_INT_17 DD ? +INT_17_NUM DW 0 + +PRNR006E: + +INT_17: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [FLAG17_14],1 + JNZ DO_INT_17 ;The PRN device is not used + CMP [CURRFIL],0 + JZ DO_INT_17 ;Nothing pending, so OK + CMP DX,[INT_17_NUM] + JNZ DO_INT_17 ;Not my unit + CMP [BUSY],0 + JNZ DO_INT_17 ;You are me + STI + MOV AH,0A1H ;You are bad, get time out + IRET + +DO_INT_17: + JMP [REAL_INT_17] ;Do a 17 + +Public PRNR007S, PRNR007E +PRNR007S: +REAL_INT_14 DD ? +INT_14_NUM DW 0 + +PRNR007E: + +INT_14: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [FLAG17_14],2 + JNZ DO_INT_14 ;The AUX device is not used + CMP [CURRFIL],0 + JZ DO_INT_14 ;Nothing pending, so OK + CMP DX,[INT_14_NUM] + JNZ DO_INT_14 ;Not my unit + CMP [BUSY],0 + JNZ DO_INT_14 ;You are me + STI + OR AH,AH + JZ SET14_AX + CMP AH,2 + JBE SET14_AH +SET14_AX: + MOV AL,0 +SET14_AH: + MOV AH,80H ;Time out + IRET + +DO_INT_14: + JMP [REAL_INT_14] ;Do a 14 + +INT_5: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [FLAG17_14],1 + JNZ DO_INT_5 ;The PRN device is not used + CMP [CURRFIL],0 + JZ DO_INT_5 ;Nothing pending, so OK + CMP [INT_17_NUM],0 + JNZ DO_INT_5 ;Only care about unit 0 + IRET ;Pretend it worked + +DO_INT_5: + JMP [REAL_INT_5] ;Do a 5 + ENDIF + +Public PRNR008S, PRNR008E +PRNR008S: + +ERRCNT DW 0 + + IF IBM +;Reserved names for parallel card +INT_17_HITLIST LABEL BYTE + DB 8,"PRN ",0 + DB 8,"LPT1 ",0 + DB 8,"LPT2 ",1 + DB 8,"LPT3 ",2 + DB 0 +;Reserved names for Async adaptor +INT_14_HITLIST LABEL BYTE + DB 8,"AUX ",0 + DB 8,"COM1 ",0 + DB 8,"COM2 ",1 +;--------------------------------------------------------------bug330a09 + DB 8,"COM3 ",2 + DB 8,"COM4 ",3 +;--------------------------------------------------------------bug330a09 + DB 0 + ENDIF + +LISTNAME DB "PRN " ;Device name + +PRNR008E: + +SETDEV: +ASSUME CS:CodeR,DS:CodeR,ES:NOTHING,SS:NOTHING +; LISTNAME has the 8 char device name IN UPPER CASE +; CARRY set if bad device +; DS preserved, others destroyed. + + MOV AH,GET_IN_VARS + call My21 + PUSH ES + POP DS + LEA SI,ES:[BX.SYSI_DEV] +ASSUME DS:NOTHING + PUSH CS + POP ES +ASSUME ES:CodeR + MOV DI,OFFSET CodeR:LISTNAME +LOOKDEV: + TEST [SI.SDEVATT],DEVTYP + JZ NEXTDEV ; Skip Block devs + PUSH SI + PUSH DI + ADD SI,SDEVNAME ; Point at name + MOV CX,8 + REPE CMPSB + POP DI + POP SI + JE GOTDEV +NEXTDEV: + LDS SI,[SI.SDEVNEXT] + CMP SI,-1 + JNZ LOOKDEV + PUSH CS + POP DS + STC + RET + +GOTDEV: + MOV WORD PTR CS:[CALLAD+2],DS ;Get I/O routines + MOV WORD PTR CS:[LISTDEV+2],DS ;Get I/O routines + MOV WORD PTR CS:[LISTDEV],SI + PUSH CS + POP DS +ASSUME DS:CodeR + + IF IBM + MOV PrinterNum,-1 ; Assume not an INT 17 device + PUSH CS + POP ES +ASSUME ES:CodeR + MOV BP,OFFSET CodeR:LISTNAME + MOV SI,BP + MOV DI,OFFSET CodeR:INT_17_HITLIST +CHKHIT: + MOV SI,BP + MOV CL,[DI] + INC DI + JCXZ NOTONHITLIST + REPE CMPSB + LAHF + ADD DI,CX ;Bump to next position without affecting flags + MOV BL,[DI] ;Get device number + INC DI + SAHF + JNZ CHKHIT + XOR BH,BH + MOV [INT_17_NUM],BX + MOV PrinterNum,BX ; Set this as well to the INT 17 device + MOV [FLAG17_14],1 + JMP SHORT ALLSET + +NOTONHITLIST: + MOV DI,OFFSET CodeR:INT_14_HITLIST +CHKHIT2: + MOV SI,BP + MOV CL,[DI] + INC DI + JCXZ NOTONHITLIST2 + REPE CMPSB + LAHF + ADD DI,CX ;Bump to next position without affecting flags + MOV BL,[DI] ;Get device number + INC DI + SAHF + JNZ CHKHIT2 + XOR BH,BH + MOV [INT_14_NUM],BX + MOV [FLAG17_14],2 + JMP SHORT ALLSET + +NOTONHITLIST2: + MOV [FLAG17_14],0 +ALLSET: + ENDIF + CLC + RET + + + IF HARDINT + +BREAK + +ReBtINT: +ASSUME CS:CodeR,DS:NOTHING,ES:NOTHING,SS:Nothing + + CLI + push cs + pop ds + +IntWhileBusy: + INT ComInt + JNC NotBusy + JMP IntWhileBusy + ret +NotBusy: + + INC [BUSY] ; Exclude hardware interrupts + INC [SOFINT] ; Exclude software interrupts + + call CanAll ; Purge the Queue + + LDS DX,CodeR:COMNEXT + mov ax,(set_interrupt_vector shl 8) or comint + INT 21H ;Set int 2f vector + + LDS DX,CodeR:NEXTINT + mov ax,(set_interrupt_vector shl 8) or intloc + INT 21H ;Set hardware interrupt + + mov ax,(set_interrupt_vector shl 8) or 15h + lds dx,CodeR:Real_Int_15 ; Reset the wait on event on ATs + int 21h + + mov ax,(set_interrupt_vector shl 8) or 17h + LDS DX,CodeR:Real_Int_17 + INT 21H ;Set printer interrupt + + mov ax,(set_interrupt_vector shl 8) or 5h + LDS DX,CodeR:Real_Int_5 + INT 21H ;Set print screen interrupt + + mov ax,(set_interrupt_vector shl 8) or 14h + LDS DX,CodeR:Real_Int_14 + INT 21H ;Set printer interrupt + + mov ax,(set_interrupt_vector shl 8) or 24h + LDS DX,CodeR:HERRINT + INT 21H ;Set printer interrupt + + LDS DX,CodeR:NEXT_REBOOT + mov ax,(set_interrupt_vector shl 8) or reboot + INT 21H ;Set bootstrap interrupt + + STI + INT 19H + + ENDIF ; HARDINT + + + + +;----- File name Queue and data buffer goes here +Public PRNR009S +PRNR009S: +FileQueue Label byte + db 0 ; the file queue starts empty + + +BREAK + +BADSPOOL: +ASSUME CS:CodeR,DS:CodeR,ES:NOTHING,SS:Nothing + MOV DX,OFFSET CODER:BADMES + mov cx,badmeslen + mov bx,stdout + mov ah,write + INT 21H +;********************************************************************* + MOV AX,(SET_PRINTER_FLAG SHL 8) ; Set flag to Idle + int 21H +;********************************************************************* + MOV AX,(EXIT SHL 8) OR 0FFH + INT 21H + +;--- move transient out of the way +ContTrans dd ? ; transient continuation address after move + +MoveTrans label far +ASSUME CS:CodeR,DS:CodeR,ES:CodeR,SS:Nothing + cli + CLD + MOV [INTSEG],CS + CALL SETDEV +ASSUME ES:NOTHING + JC BADSPOOL + MOV DX,OFFSET CodeR:SPINT + MOV AL,SOFTINT + MOV AH,GET_INTERRUPT_VECTOR + INT 21H ;Get soft vector + MOV WORD PTR [SPNEXT+2],ES + MOV WORD PTR [SPNEXT],BX + MOV AL,SOFTINT + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set soft vector + MOV DX,OFFSET CodeR:SPCOMINT + MOV AL,ComInt + MOV AH,GET_INTERRUPT_VECTOR + INT 21H ;Get communication vector + MOV WORD PTR [COMNEXT+2],ES + MOV WORD PTR [COMNEXT],BX + MOV AL,ComInt + MOV AH,SET_INTERRUPT_VECTOR ;Set communication vector + INT 21H + + IF IBM + MOV AL,13H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_13+2],ES + MOV WORD PTR [REAL_INT_13],BX + MOV DX,OFFSET CodeR:INT_13 + MOV AL,13H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set diskI/O interrupt + + MOV AL,15H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_15+2],ES + MOV WORD PTR [REAL_INT_15],BX + MOV DX,OFFSET CodeR:INT_15 + MOV AL,15H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set INT 15 vector + + MOV AL,17H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_17+2],ES + MOV WORD PTR [REAL_INT_17],BX + MOV DX,OFFSET CodeR:INT_17 + MOV AL,17H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set printer interrupt + MOV AL,14H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_14+2],ES + MOV WORD PTR [REAL_INT_14],BX + MOV DX,OFFSET CodeR:INT_14 + MOV AL,14H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set RS232 port interrupt + MOV AL,5H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_5+2],ES + MOV WORD PTR [REAL_INT_5],BX + MOV DX,OFFSET CodeR:INT_5 + MOV AL,5H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set print screen interrupt + ENDIF + + IF HARDINT + MOV AH,GET_INDOS_FLAG + INT 21H +ASSUME ES:NOTHING + MOV WORD PTR [INDOS+2],ES ;Get indos flag location + MOV WORD PTR [INDOS],BX + MOV AL,INTLOC + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [NEXTINT+2],ES + MOV WORD PTR [NEXTINT],BX + + MOV AL,REBOOT ; We also need to chain + MOV AH,GET_INTERRUPT_VECTOR ; Into the INT 19 sequence + INT 21H ; To properly "unhook" + MOV WORD PTR [NEXT_REBOOT+2],ES ; ourselves from the TimerTick + MOV WORD PTR [NEXT_REBOOT],BX ; sequence + + IF IBM + MOV AX,0B800H + INT 2FH + CMP AL,0 + JE SET_HDSPINT ; No NETWORK, set hardware int + TEST BX,0000000011000100B + JNZ NO_HDSPINT ; DO NOT set HDSPINT if RCV|MSG|SRV + ENDIF + +SET_HDSPINT: + MOV DX,OFFSET CodeR:HDSPINT + MOV AL,INTLOC + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set hardware interrupt + + MOV DX,OFFSET CodeR:ReBtINT + MOV AL,REBOOT + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set bootstrap interrupt + +NO_HDSPINT: + ENDIF + MOV DX,OFFSET CODER:GOODMES + mov cx,goodmeslen + mov bx,stdout + mov ah,write + int 21h + +;--- Move transient +; Note: do not use stack, it may get trashed in move! +public RealMove +RealMove: + + mov ax,offset dg:TransRet + mov word ptr [ContTrans],ax ; store return offset + mov ax,CodeR + add ax,[endres] ; get start of moved transient, actually + ; this is 100 bytes more than need be + ; because of lack of pdb, but who cares? + mov word ptr [ContTrans+2],ax ; return segment + mov es,ax ; new location for dg group +assume es:nothing + mov ax,dg + mov ds,ax +assume ds:nothing + mov cx,offset dg:TransSize + mov si,cx ; start from the bottom and move up + mov di,cx + std + rep movsb ; move all code, data and stack + cld ; restore to expected setting... + +;--- normalize transient segment regs + mov ax,es + mov ds,ax + sub ax,dg ; displacement + mov dx,ss + add dx,ax ; displace stack segemnt + mov ss,dx + +assume ds:nothing,es:nothing,ss:nothing + jmp ContTrans ; back to the transient... + +PRNR009E: + +CodeR EndS + + End diff --git a/UPDSRC/DOS/DISK2.OBJ b/UPDSRC/DOS/DISK2.OBJ new file mode 100644 index 0000000..54f40f5 Binary files /dev/null and b/UPDSRC/DOS/DISK2.OBJ differ