diff --git a/.gitattributes b/.gitattributes index dfe0770..d612cfe 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ -# Auto detect text files and perform LF normalization -* text=auto +# Treat all files as binary so we don't screw them up +* binary diff --git a/Disk01.img b/Disk01.img new file mode 100644 index 0000000..6c45733 Binary files /dev/null and b/Disk01.img differ diff --git a/Disk01/CHKDSK.COM b/Disk01/CHKDSK.COM new file mode 100644 index 0000000..152bc38 Binary files /dev/null and b/Disk01/CHKDSK.COM differ diff --git a/Disk01/COMMAND.COM b/Disk01/COMMAND.COM new file mode 100644 index 0000000..820f393 Binary files /dev/null and b/Disk01/COMMAND.COM differ diff --git a/Disk01/DEBUG.COM b/Disk01/DEBUG.COM new file mode 100644 index 0000000..41d127b Binary files /dev/null and b/Disk01/DEBUG.COM differ diff --git a/Disk01/DISKCOPY.COM b/Disk01/DISKCOPY.COM new file mode 100644 index 0000000..ea4e0d2 Binary files /dev/null and b/Disk01/DISKCOPY.COM differ diff --git a/Disk01/EDLIN.COM b/Disk01/EDLIN.COM new file mode 100644 index 0000000..81e097b Binary files /dev/null and b/Disk01/EDLIN.COM differ diff --git a/Disk01/EXE2BIN.EXE b/Disk01/EXE2BIN.EXE new file mode 100644 index 0000000..f4b0dd7 Binary files /dev/null and b/Disk01/EXE2BIN.EXE differ diff --git a/Disk01/FC.EXE b/Disk01/FC.EXE new file mode 100644 index 0000000..aa06624 Binary files /dev/null and b/Disk01/FC.EXE differ diff --git a/Disk01/FIND.EXE b/Disk01/FIND.EXE new file mode 100644 index 0000000..b5d07d0 Binary files /dev/null and b/Disk01/FIND.EXE differ diff --git a/Disk01/LINK.EXE b/Disk01/LINK.EXE new file mode 100644 index 0000000..aa58151 Binary files /dev/null and b/Disk01/LINK.EXE differ diff --git a/Disk01/MORE.COM b/Disk01/MORE.COM new file mode 100644 index 0000000..b28f807 Binary files /dev/null and b/Disk01/MORE.COM differ diff --git a/Disk01/MSDOS.SYS b/Disk01/MSDOS.SYS new file mode 100644 index 0000000..803eb70 Binary files /dev/null and b/Disk01/MSDOS.SYS differ diff --git a/Disk01/PRINT.COM b/Disk01/PRINT.COM new file mode 100644 index 0000000..b2788d3 Binary files /dev/null and b/Disk01/PRINT.COM differ diff --git a/Disk01/README.DOC b/Disk01/README.DOC new file mode 100644 index 0000000..c5bbf25 --- /dev/null +++ b/Disk01/README.DOC @@ -0,0 +1,177 @@ + MSDOS 2.0 RELEASE + + +The 2.0 Release of MSDOS includes five 5 1/4 double density single sided +diskettes or three 8 iinch CP/M 80 format diskettes. + +The software/documentation on the five inch diskettes is arranged +as follows: + +1. DOS distribution diskette. This diskette contains files which + should be distriibuted to all users. This allows the DOS distri- + bution diskette to meet the requirements of users of high level + language compilers as well as users running only applications. + Many compilers marketed independently through the retail channel + (including those of Microsoft) assume LINK comes with the DOS, as + in the case of IBM. How you choose to distrubute BASIC (contracted + for separately) is up to you. + +2. Assembly Language Development System diskette. This diskette + contains files of interest to assembly language programmers. + High level language programmers do not need these programs unless + they are writing assembly language subroutines. IBM chose to + unbundle this package from the DOS distribution diskette (except + for DEBUG), but you do not have to do so. + +3. PRINT and FORMAT diskette. This diskette contains .ASM source + files which are necessary to assemble the print spooler, which you + may wish to customize for greater performance. .OBJ files are also + included for the FORMAT utility. + +4. Skeltal BIOS and documentation diskette. This diskette contains + the skeltal BIOS source code and the SYSINIT and SYSIMES object + modules which must be linked with your BIOS module. The proper + sequence for linking is BIOS - SYSINIT - SYSIMES. + A profiler utiliity is also included on the diskette, but this + is not intended for end-users. This is distributed for use by + your development staff only and is not supported by Microsoft + If you do decide to distribute it, it is at your own risk! + + +5. Documentation. Features of 2.0 are documented on this disk. + +The user manual contains some significant errors. Most of these are +due to last minute changes to achieve a greater degree of compatibility +with IBM's implementation of MS-DOS (PC DOS). This includes the use +of "\" instead of "/" as the path separator, and "/" instead of "-" +as the switch character. For transporting of batch files across +machines, Microsoft encourages the use of "\" and "/" respectively +in the U.S. market. (See DOSPATCH.TXT for how you can overide this. +The user guide explains how the end-user can override this in CONFIG.SYS). +Both the printer echo keys and insert mode keys have now been made to +toggle. The default prompt (this may also be changed by the user +with the PROMPT command) has been changed from "A:" to "A>". +We apologize for any inconveniences these changes may have caused +your technical publications staff. + + +Here is what you need to do to MSDOS 2.0 to create a shipable product: +(see "Making a Bootable Diskette" below) + +1. BIOS. If you have developed a BIOS for the Beta Test 2.0 version + You should link your BIOS module to SYSINIT.OBJ and SYSIMES.OBJ. + You must modify your BIOS to accomodate the call back to the BIOS + at the end of SYSINIT. If you have no need for this call, simply + find a far RET and label it RE_INIT and declare it public. + An example of this can be found in the skeletal BIOS. In addition + please add support for the new fast console output routine as + described in the device drivers document. We strongly recommend + that you adapt the standard boot sector format also described in + device drivers. Once again, please refer to the skeletal BIOS. + If you have not yet implemented version 2.0 please read the device + drivers document. Microsoft strongly recommends that machines + incorporating integrated display devices with memory mapped video + RAM implement some sort of terminal emulations through the use of + escape sequences. The skeletal BIOS includes a sample ANSI + terminal driver. + +2. Please refer to DOSPATCH.TXT for possible changes you might wish + to make. We strongly recommend that you not patch the switch + characters for the U.S. market. Your one byte serial number + will be issued upon signing the license agreement. Please patch + the DOS accordingly. If you wish to serialize the DOS, this is + described in DOSPATCH.TXT. Please patch the editing template + definitions. Please note the addition of the Control-Z entry + at the beginning of the table. Also note that the insert switches + have now both been made to toggle. + +3. Utilities. FORMAT must be configured for each specific system. + GENFOR is a generic example of a system independent format module, + but it is not recommended that this be distributed to your customers. + Link in the following order: FORMAT, FORMES, (your format module). + The print spooler is distributed as an executable file, which only + prints during wait for keyboard input. If you wish with your + implementation to steal some compute time when printing as well, + you will need to customize it and reassemble. Please note that + you can use a printer-ready or timer interrupt. The former is more + efficient, but ties the user to a specific device. Sample code + is conditionaled out for the IBM PC timer interrupt. + +The following problems are known to exist: + +1. Macro assembler does not support the initialization of 10-byte + floating point constants in 8087 emulation mode - the last two bytes + are zero filled. + +2. LIB has not been provided. The version which incorporates support + for 2.0 path names will be completed in a couple of weeks. The + 1.x version should work fine if you cannot wait. Because the library + manager acts as a counterpart to the linker, we recommend that it + be distributed with the DOS distribution diskette as opposed to the + assembly language development system. + +3. International (French, German, Japanese, and U.K.) versions will be + available in several months. + +4. COMMAND.ASM is currently too large to assemble on a micro. It is + being broken down into separate modules so it can be asembled on + a machine. Source licensees should realize that the resultant + binaries from the new version will not correspond exactly to the + old version. + +5. If you have any further questions regarding the MSDOS 2.0 distribution + please contact Don Immerwahr (OEM technical support (206) 828-8086). + + + Sincerely yours, + + + Chris Larson + MS-DOS Product Marketing Manager + (206) 828-8080 + + + + BUILDING A BOOTABLE (MSDOS FORMAT) DISKETTE + + +1. In implementing MSDOS on a new machine, it is highly recommended + that an MSDOS machine be available for the development. + Please note that utilities shipped with MSDOS 2.0 use MSDOS 2.0 + system calls and WILL NOT not run under MSDOS 1.25. + +2. Use your MSDOS development machine and EDLIN or a word processor + package to write BOOT.ASM, your bootstrap loader BIOS.ASM and + your Format module. + +3. Use MASM, the Microsoft Macro-86 Assembler, to assemble these + modules. LINK is then used to link together the .OBJ modules in + the order specified. + +4. Link creates .EXE format files which are not memory image files + and contain relocation information in their headers. Since your + BIOS and BOOT routines will not be loaded by the EXE loader in + MSDOS, they must first be turned into memory image files by + using the EXE2BIN utility. + +5. The easiest thing to do is to (using your development machine) + FORMAT a single sided diskette without the system. Use DEBUG + to load and write your BOOT.COM bootstrap loader to the BOOT + sector of that diskette. You may decide to have your bootstrap + load BIOS and let the BIOS load MSDOS or it may load both. Note that + the Bootstrap loader will have to know physically where to go on + the disk to get the BIOS and the DOS. COMMAND.COM is loaded + by the SYSINIT module. + +6. Use the COPY command to copy your IO.SYS file (what the + BIOS-SYSINIT-SYSIMES module is usually called) onto the disk + followed by MSDOS.SYS and COMMAND.COM. You may use DEBUG + to change the directory attribute bytes to make these files hidden. + +CAUTION: + +At all times, the BIOS writer should be careful to preserve the state +of the DOS - including the flags. You should be also be cautioned that +the MSDOS stack is not deep. You should not count on more than one or +two pushes of the registers. + \ No newline at end of file diff --git a/Disk01/RECOVER.COM b/Disk01/RECOVER.COM new file mode 100644 index 0000000..fa51fae Binary files /dev/null and b/Disk01/RECOVER.COM differ diff --git a/Disk01/SORT.EXE b/Disk01/SORT.EXE new file mode 100644 index 0000000..9e2c19a Binary files /dev/null and b/Disk01/SORT.EXE differ diff --git a/Disk01/SYS.COM b/Disk01/SYS.COM new file mode 100644 index 0000000..2d315d7 Binary files /dev/null and b/Disk01/SYS.COM differ diff --git a/Disk02.img b/Disk02.img new file mode 100644 index 0000000..5cf311b Binary files /dev/null and b/Disk02.img differ diff --git a/Disk02/CREF.EXE b/Disk02/CREF.EXE new file mode 100644 index 0000000..a88c2fa Binary files /dev/null and b/Disk02/CREF.EXE differ diff --git a/Disk02/MASM.EXE b/Disk02/MASM.EXE new file mode 100644 index 0000000..d43bfb7 Binary files /dev/null and b/Disk02/MASM.EXE differ diff --git a/Disk03.img b/Disk03.img new file mode 100644 index 0000000..579c6cb Binary files /dev/null and b/Disk03.img differ diff --git a/Disk03/DEVSYM.ASM b/Disk03/DEVSYM.ASM new file mode 100644 index 0000000..b648f04 Binary files /dev/null and b/Disk03/DEVSYM.ASM differ diff --git a/Disk03/DOSMAC.ASM b/Disk03/DOSMAC.ASM new file mode 100644 index 0000000..35c16f1 Binary files /dev/null and b/Disk03/DOSMAC.ASM differ diff --git a/Disk03/DOSPATCH.TXT b/Disk03/DOSPATCH.TXT new file mode 100644 index 0000000..e2f597a --- /dev/null +++ b/Disk03/DOSPATCH.TXT @@ -0,0 +1,62 @@ +There are three locations in the DOS where OEMs may want to +patch in information specific to their installation. + + +The first is the location of the default switch character. +This character is one byte at DEBUG location 1E5, and is +set to '/'. To change it to '-' (XENIX compatible) +do: + + DEBUG MSDOS.SYS + + >e1e5 + XXXX:01E5 2F. + >w + Writing YYYY Bytes + >q + +If the byte at 1E5 is not 2F, look around in the immediate +vacinity (do d1e0) for it. It is the only 2F in that area. + + +The second is the location of the 24 bit user number and the +8 bit OEM number. These values are returned by the GET_VERSION +system call. +The user number is 3 bytes starting at +debug location 683, The OEM number is one byte at debug location +686. The user number is initialized to 0, the OEM number to -1 +and they immediatly follow the Microsoft Copyright message. If these +bytes are not zero, look for the four bytes following the +Copyright message which should be in the vacinity of 683. +OEMs should request an OEM number from Microsoft if they +want one of their very own, this prevents selecting one someone +else already has. + + +The third is the location of the editing template definitions. +This is a table which defines the two byte edit function keys +for system call 10 and for EDLIN. This table is at debug location +33EA, and should start with a 1B. If the byte at 33EA is not +1B, look around in the immediate vacinity. Here is what the +default table looks like. It is a definition for the Zenith +Z-19 terminal: + +ESCCHAR DB 1BH ;The Escape character, Nul (0) on IBM +ESCTAB: + DB "Z" ;5AH Put a ^Z in the template, F6 on IBM + DB "S" ;53H Copy one char, --> on IBM + DB "V" ;56H Skip one char, DEL on IBM + DB "T" ;54H Copy to char, F2 on IBM + DB "W" ;57H Skip to char, F4 on IBM + DB "U" ;55H Copy line, F3 on IBM + DB "E" ;45H Kill line, Not used on IBM + DB "J" ;4AH Reedit line, F5 on IBM + DB "D" ;44H Backspace, <-- on IBM + DB "P" ;50H Toggle insert mode, INS on IBM + DB "Q" ;51H Toggle insert mode, INS on IBM + DB "R" ;52H Escape char, F7 on IBM + DB "R" ;52H End of table, must be same as previos character + + \ No newline at end of file diff --git a/Disk03/DOSSYM.ASM b/Disk03/DOSSYM.ASM new file mode 100644 index 0000000..918ed5d --- /dev/null +++ b/Disk03/DOSSYM.ASM @@ -0,0 +1,904 @@ +include DOSMAC.ASM +IF2 + %OUT DOSSYM in Pass 2 +ENDIF + +IFNDEF ALTVECT +ALTVECT EQU 0 ;FALSE +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 ; +; ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +BREAK +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; 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 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +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 +NEXTBUF DD ? ; Pointer to next buffer in list +; The next two items are often refed as a word +BUFDRV DB ? ; Logical drive # assoc with buffer FF = free +BUFDIRTY DB ? ; Dirty flag +BUFPRI DB ? ; Buffer selection priority (see EQUs below) +VISIT DB ? ; Visit flag for buffer pool scans +BUFSECNO DW ? ; Sector number of buffer +; The next two items are often refed as a word +BUFWRTCNT DB ? ; For FAT sectors, # times sector written out +BUFWRTINC DB ? ; " " " , # sectors between each write +BUFDRVDP DD ? ; Pointer to drive parameters +BUFFINFO ENDS + +BUFINSIZ EQU SIZE BUFFINFO + ; Size of structure in bytes + +FREEPRI EQU 0 +LBRPRI EQU 2 ; Last byte of buffer read +LBWPRI EQU 4 ; Last byte written +RPRI EQU 6 ; Read but not last byte +WPRI EQU 8 ; Written but not last byte +DIRPRI EQU 15 ; Directory Sector +FATPRI EQU 30 ; FAT sector +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +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 + +BREAK + +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 +; ; +; 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 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +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. + +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_all EQU attr_hidden+attr_system+attr_directory + ; OR of hard attributes for FINDENTRY + +attr_ignore EQU attr_read_only+attr_archive + ; ignore this(ese) attribute(s) + ; during search first/next + +attr_changeable EQU attr_read_only+attr_hidden+attr_system+attr_archive + ; changeable via CHMOD + +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 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). + +BREAK +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + +DIRSTRLEN EQU 64 ; Max length in bytes of directory strings + +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_current_dir DW ? ; Cluster number of start of current directory + ; 0 indicates root, -1 indicates invalid + ; (disk ? changed) +dpb_dir_text DB DIRSTRLEN DUP(?) + ; ASCIZ string of current directory +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 ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +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 ; +; ; +; | Flags: | +; | bit 7=0 file/1 device | +; | bit 6=0 if dirty | +; | bits 0-5 deviceid | +; +---------------------------+ +; | first cluster in file | +; +---------------------------+ +; | position of last cluster | +; +---------------------------+ +; | last cluster accessed | 12 bit-+--- packed in 3 bytes +; +---------------------------+ | +; | parent directory | <------+ +; +---------------------------+ +; ; +; 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_DEVID DB ? ; Device ID number, bits 0-5 if file. + ; bit 7=0 for file, bit 7=1 for I/O device + ; If file, bit 6=0 if dirty + ; If 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 +fcb_FIRCLUS DW ? ; First cluster of file +fcb_CLUSPOS DW ? ; Position of last cluster accessed +fcb_LSTCLUS DW ? ; Last cluster accessed and directory + DB ? ; pack 2 12 bit numbers into 24 bits... +; ; +; 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 + +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +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 + +; +; 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 + +; +; find first/next buffer +; +find_buf STRUC +find_buf_sattr DB ? ; attribute of search +find_buf_drive DB ? ; drive of search +find_buf_name DB 11 DUP (?) ; formatted name +find_buf_LastEnt DW ? ; LastEnt +find_buf_ThisDPB DD ? ; This DPB +find_buf_DirStart DW ? ; DirStart +; ; +; 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 + +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_PAD1 DB 1Eh 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 6h DUP (?) ; +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +Process_data_block ENDS + +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 + +BREAK +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +; +; system file table +; + +sft STRUC +sft_link DD ? +sft_count DW ? ; number of entries +sft_table DW ? ; beginning of array of the following +sft ENDS + +; +; system file table entry +; + +sf_entry STRUC +sf_ref_count DB ? ; number of processes sharing fcb +sf_mode DB ? ; mode of access +sf_attr DB ? ; attribute of file +sf_fcb DB (SIZE sys_fcb) DUP (?) + ; actual FCB +sf_entry ENDS + +sf_default_number EQU 5h +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +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 + +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 ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +BREAK + +mi_INT EQU 0CDh +mi_Long_JMP EQU 0EAh +mi_Long_CALL EQU 09Ah +mi_Long_RET EQU 0CBh + +BREAK + +stdin EQU 0 +stdout EQU 1 +stderr EQU 2 +stdaux EQU 3 +stdprn EQU 4 + +BREAK + +open_for_read EQU 0 +open_for_write EQU 1 +open_for_both EQU 2 + +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. +; + +no_error_occurred EQU 0 ? + +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 +;**** unused EQU 14 +error_invalid_drive EQU 15 +error_current_directory EQU 16 +error_not_same_device EQU 17 +error_no_more_files EQU 18 + +alloc_not_enough_memory EQU error_not_enough_memory +alloc_arena_trashed EQU error_arena_trashed + +close_invalid_handle EQU error_invalid_handle +close_invalid_function EQU error_invalid_function + +chdir_path_not_found EQU error_path_not_found + +chmod_path_not_found EQU error_path_not_found +chmod_access_denied EQU error_access_denied +chmod_invalid_function EQU error_invalid_function + +creat_access_denied EQU error_access_denied +creat_path_not_found EQU error_path_not_found +creat_too_many_open_files EQU error_too_many_open_files + +curdir_invalid_drive EQU error_invalid_drive + +dealloc_invalid_block EQU error_invalid_block +dealloc_arena_trashed EQU error_arena_trashed + +dup_invalid_handle EQU error_invalid_handle +dup_too_many_open_files EQU error_too_many_open_files + +dup2_invalid_handle EQU error_invalid_handle + +exec_invalid_function EQU error_invalid_function +exec_bad_environment EQU error_bad_environment +exec_bad_format EQU error_bad_format +exec_not_enough_memory EQU error_not_enough_memory +exec_file_not_found EQU error_file_not_found + +filetimes_invalid_function EQU error_invalid_function +filetimes_invalid_handle EQU error_invalid_handle + +findfirst_file_not_found EQU error_file_not_found +findfirst_no_more_files EQU error_no_more_files +findnext_no_more_files EQU error_no_more_files + +international_invalid_function EQU error_invalid_function + +ioctl_invalid_handle EQU error_invalid_handle +ioctl_invalid_function EQU error_invalid_function +ioctl_invalid_data EQU error_invalid_data + +lseek_invalid_handle EQU error_invalid_handle +lseek_invalid_function EQU error_invalid_function + +mkdir_path_not_found EQU error_path_not_found +mkdir_access_denied EQU error_access_denied + +open_invalid_access EQU error_invalid_access +open_file_not_found EQU error_file_not_found +open_access_denied EQU error_access_denied +open_too_many_open_files EQU error_too_many_open_files + +read_invalid_handle EQU error_invalid_handle +read_access_denied EQU error_access_denied + +rename_file_not_found EQU error_file_not_found +rename_not_same_device EQU error_not_same_device +rename_access_denied EQU error_access_denied + +rmdir_path_not_found EQU error_path_not_found +rmdir_access_denied EQU error_access_denied +rmdir_current_directory EQU error_current_directory + +setblock_invalid_block EQU error_invalid_block +setblock_arena_trashed EQU error_arena_trashed +setblock_not_enough_memory EQU error_not_enough_memory +setblock_invalid_function EQU error_invalid_function + +unlink_file_not_found EQU error_file_not_found +unlink_access_denied EQU error_access_denied + +write_invalid_handle EQU error_invalid_handle +write_access_denied EQU error_access_denied + +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 +; XENIX CALLS +; 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 + +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 +SUBTTL + \ No newline at end of file diff --git a/Disk03/FORMAT.DOC b/Disk03/FORMAT.DOC new file mode 100644 index 0000000..ab47f54 --- /dev/null +++ b/Disk03/FORMAT.DOC @@ -0,0 +1,393 @@ +FORMAT - formats a new disk, clears the FAT and DIRECTORY +and optionally copies the SYSTEM and COMMAND.COM to this +new disk. + +Command syntax: + + FORMAT [drive:][/switch1][/switch2]...[/switch16] + + Where "drive:" is a legal drive specification and if + omitted indicates that the default drive will be used. + There may be up to 16 legal switches included in the + command line. + + + The OEM must supply five (NEAR) routines to the program +along with 6 data items. The names of the routines are INIT, +DISKFORMAT, BADSECTOR, WRTFAT and DONE, and their flow of +control (by the Microsoft module) is like this: + + | + +---------+ + | INIT | + +---------+ + | + |<------------------------------+ ++------------+ | +| DISKFORMAT | | ++------------+ | + |<-------+ | ++-----------+ |-This loop is done |- This loop done +| BADSECTOR | | for each group of | once for each disk ++-----------+ | bad sectors | to be formatted. + |----->--+ | If variable HARDFLAG + | | is set then the loop ++----------+ | is only performed +| | | once. +| WRTFAT | | ++----------+ | + | | + +------+ | + | DONE | | + +------+ | + +---->--------------------------+ + + The 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. + +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 which are the switches to + be accepted by the command line scanner. Alphabetic + characters must be in upper case (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 which causes the + system files IO.SYS, MSDOS.SYS, and COMMAND.COM to be + transfered to the disk after it is formatted thus + making a "S"ystem 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", + regardles 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. Again, 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 0E5 Hex free entry designator. This + results in a very marked directory search performance + increase due to an optimization in the DOS. Disks + made this way cause trouble on IBM PC DOS 1.X + versions, however, 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 Personnal Computer DOS version 2.00 and + MS-DOS version 1.25 will have no trouble with these + disks, since they have the same optimization. The "O" + switch causes FORMAT to re-do the directory with a 0E5 + Hex 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 MS-DOS 1.25/2.00 and IBM PC DOS 2.00. This switch + should only be given when needed because it takes a + fair amount of time for FORMAT to perform the + conversion, and it noticably decreases 1.25 and 2.00 + 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 previosly formatted and used + disk. + + HARDFLAG - BYTE location which specifies whether the + OEM routine is formatting a fixed disk or a a drive + with removable media. A zero indicates removable + media, any other value indicates a fixed disk. The + status of this byte only effect 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 + F8 hex to FF hex. + + 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 FAT. This + area must not overlap the FREESPACE area. + + FREESPACE - WORD location which 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. + +The following routines must be declared PUBLIC in the +OEM-supplied module: + + 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 only 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 can be used to detect + conflicting switches (like specifying both single + and double density) and cause FORMAT to quit without + doing anything. + + 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 neccessary it + must transfer the Bootstrap loader. If any error + conditions are detected, set the CARRY flag and return + to FORMAT. FORMAT will report a 'Format failure' + and prompt for another disk. (If you only require + a clear directory and FAT then simply setting the + appropriate FATID, if not done by INIT, will be all + that DISKFORMAT must do.) + + 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 AX 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 in register BX, the number + of consecutive bad sectors in register AX, and carry + clear. FORMAT will then process the bad sectors + and call BADSECTOR again. When BADSECTOR returns + with AX = 0 this means there are no more bad sectors; + FORMAT clears the directory and goes on to DONE, + so 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 FF7 hex in the File Allocation Table. CHKDSK + understands the FF7 mark as a flag for bad sectors + and accordingly reports the number of bytes marked + in this way. + + NOTE: Actual formatting of the disk can be done in + BADSECTOR instead of DISKFORMAT on a "report as you + go" basis. Formatting goes 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. Its + purpose is to write 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 FAT ID byte on the disk yet (in + this case WRTFATs primary job is to get the FAT ID + byte out on the disk and thus solve the chicken and + egg problem). + + DONE - This routine is called after the formatting is + complete, the disk directory has been initialized, + and the system has been transferred. 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 certain extra files to be put + on the diskette by default, or according to a switch, + this could be done in DONE. 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 with a bit vector indicating what + switches have been included in the command line. The + correspondence of the bits to the switches is + determined by SWITCHLIST. The right-most + (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 is + necessary to load the system; 2) after the last + BADSECTOR call, to determine if the system is to be + written, E5 directory conversion is to be done, and/or + a volume label is to 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 which is used to restore SWITCHMAP for + each disk to be formatted. FORMAT itself 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 do affect ALL disks.) + + DRIVE - A byte 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. +If the OEM-supplied module is called OEMFOR.OBJ, then the +following linker command will do: + + LINK FORMAT FORMES OEMFOR; + +This command will produce a file called FORMAT.EXE. FORMAT +has been designed to run under MS-DOS as a simple binary +.COM file. This conversion is performed by LOCATE (EXE2BIN) +with the command + + LOCATE FORMAT.EXE FORMAT.COM + +which will produce the file FORMAT.COM. + +;***************************************** +; +; A Sample OEM module +; +;***************************************** + +CODE SEGMENT BYTE PUBLIC 'CODE' +; This segment must be +; named CODE, it must be +; PUBLIC, and it's +; classname must be 'CODE' + + + ASSUME CS:CODE,DS:CODE,ES:CODE + +; Must declare data and routines PUBLIC + +PUBLIC FATID,STARTSECTOR,SWITCHLIST,FREESPACE +PUBLIC INIT,DISKFORMAT,BADSECTOR,DONE,WRTFAT +PUBLIC FATSPACE,HARDFLAG + +; This data defined in Microsoft-supplied module + + EXTRN SWITCHMAP:WORD,DRIVE:BYTE + +INIT: + +; Read the boot sector into memory + CALL READBOOT + ... +; Set FATID to double sided if "D" switch specified + TEST SWITCHMAP,10H + JNZ SETDBLSIDE + ... + RET + +DISKFORMAT: + ... + +; Use the bit map in SWITCHMAP to determine +; what switches are set + + TEST SWITCHMAP,8 ;Is there a "/C"? + JNZ CLEAR ; Yes -- clear operation + ; requested jump around the + ; format code + < format the disk > +CLEAR: + ... +; Transfer the boot from memory to the new disk + CALL TRANSBOOT + ... + RET + +; Error return - set carry + +ERRET: + STC + RET + +BADSECTOR: + ... + RET + + +WRTFAT: + ... + +WRTFATLOOP: + < Set up call to write out a fat to disk> + ... + MOV BX,[FATSPACE] + + < Write out one fat to disk> + JC ERRET + ... + < Decrement fat counter > + JNZ WRTFATLOOP + CLC ;Good return + RET + + +DONE: + ... + RET + +; Default Single sided +FATID DB 0FEH + +HARDFLAG DB 0 + +STARTSECTOR DW 9 + +SWITCHLIST DB 5,"DCOVS" ; "OVS" must be the last + ; switches in the list + +FATSPACE DW FATBUF + +FREESPACE DW ENDBOOT + +BOOT DB BOOTSIZE DUP(?) ; Buffer for the + ; boot sector + +FATBUF DB 6 * 1024 DUP(?) ; Fat buffer +ENDBOOT LABEL BYTE + +CODE ENDS + END + \ No newline at end of file diff --git a/Disk03/FORMAT.OBJ b/Disk03/FORMAT.OBJ new file mode 100644 index 0000000..61fe107 Binary files /dev/null and b/Disk03/FORMAT.OBJ differ diff --git a/Disk03/FORMES.OBJ b/Disk03/FORMES.OBJ new file mode 100644 index 0000000..247f39e Binary files /dev/null and b/Disk03/FORMES.OBJ differ diff --git a/Disk03/GENFOR.ASM b/Disk03/GENFOR.ASM new file mode 100644 index 0000000..a108593 Binary files /dev/null and b/Disk03/GENFOR.ASM differ diff --git a/Disk03/PRINT.ASM b/Disk03/PRINT.ASM new file mode 100644 index 0000000..dd58735 --- /dev/null +++ b/Disk03/PRINT.ASM @@ -0,0 +1,1645 @@ +;MS-DOS PRINT program for background printing of text files to the list +; device. 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. +; +; VERSION 1.00 07/03/82 + + +FALSE EQU 0 +TRUE EQU NOT FALSE + +IBM EQU FALSE +IBMVER EQU IBM +MSVER EQU TRUE + + 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) +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 1000 +ERRCNT2 EQU 20000 + ELSE +ERRCNT1 EQU 1000 +ERRCNT2 EQU 20000 + ENDIF + + IF HARDINT +TIMESLICE EQU 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 EQU 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 EQU 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 + + +;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 PRINT + ; This vector number is DOS reserved. It + ; is not generally available to programs + ; other than PRINT. + +BLKSIZ EQU 512 ;Size of the PRINT I/O block in bytes +FCBSIZ EQU 40 ;Size of an FCB + + INCLUDE DOST:DOSSYM.ASM + +FCB EQU 5CH +PARMS EQU 80H + +DG GROUP CODE,DATA + +CODE SEGMENT +ASSUME CS:DG + + ORG 100H +START: + JMP TRANSIENT + +HEADER DB "Vers 1.00" + + DB 128 DUP (?) +ISTACK LABEL WORD ;Stack starts here and grows down + +;Resident data + + IF HARDINT +INDOS DD ? ;DOS buisy flag +NEXTINT DD ? ;Chain for int +BUSY DB 0 ;Internal ME flag +SOFINT DB 0 ;Internal ME flag +TICKCNT DB 0 ;Tick counter +TICKSUB DB 0 ;Tick miss counter +SLICECNT DB TIMESLICE ;Time slice counter + ENDIF + +CBUSY DB 0 ;ME on com interrupt +SPNEXT DD ? ;Chain location for INT 28 +PCANMES DB 0 ;Cancel message flag +SSsave DW ? ;Stack save area for INT 24 +SPsave DW ? +DMAADDR DD ? ;Place to save DMA address +HERRINT DD ? ;Place to save Hard error interrupt +LISTDEV DD ? ;Pointer to Device +COLPOS DB 0 ;Column position for TAB processing +NXTCHR DW OFFSET DG:BUFFER + BLKSIZ ;Buffer pointer +CURRFIL DW OFFSET DG:SPLFCB ;Current file being printed + +LASTFCB DW ? ;Back pointer +LASTFCB2 DW ? ;Another back pointer +PABORT DB 0 ;Abort flag + +;Resident messages + +ERRMES DB 13,10,13,10,"**********",13,10,"$" +ERRMEST DB " error reading file",13,10 +EMFILNAM DB " : . " +BELMES DB 13,0CH,7,"$" + +CANMES DB 13,10,13,10 +CANFILNAM DB " : . " + DB " Canceled by operator$" + +ALLCAN DB 13,10,13,10,"All files canceled by operator$" + +MESBAS DW OFFSET DG:ERR0 + DW OFFSET DG:ERR1 + DW OFFSET DG:ERR2 + DW OFFSET DG:ERR3 + DW OFFSET DG:ERR4 + DW OFFSET DG:ERR5 + DW OFFSET DG:ERR6 + DW OFFSET DG:ERR7 + DW OFFSET DG:ERR8 + DW OFFSET DG:ERR9 + DW OFFSET DG:ERR10 + DW OFFSET DG:ERR11 + DW OFFSET DG:ERR12 + +;INT 24 messages A La COMMAND + +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,"$" + +;The DATA buffer +BUFFER DB BLKSIZ DUP(0) + DB ? +CODE ENDS + +;Transient data + +DATA SEGMENT BYTE + ORG 0 +SWITCHAR DB ? ;User switch character +FULLFLAG DB 0 ;Flag for printing queue full message +MAKERES DB 0 ;Flag to indicate presence of resident +ARGSETUP DB 0 ;Flag to indicate a formatted FCB exists at 5C +DEFDRV DB 0 ;Default drive +CANFLG DB 0 ;Flag to indicate cancel +FILCNT DB 0 ;Number of files +SPLIST DD ? ;Pointer to FCBs in resident +CURFILE DD ? ;Pointer to current FCB +SRCHFCB DB 38 DUP (0) ;SEARCH-FIRST/NEXT FCB +ENDRES DW OFFSET DG:DEF_ENDRES ;Term-Res location + +;Messages + +NOFILS DB "PRINT queue is empty",13,10,"$" +CURMES DB 13,10," " +CURFNAM DB " : . is currently being printed",13,10,"$" +FILMES DB " " +FILFNAM DB " : . is in queue" +CRLF DB 13,10,"$" +OPMES DB "Cannot open " +OPFILNAM DB " : . ",13,10,"$" +FULLMES DB "PRINT queue is full",13,10,"$" +SRCHMES LABEL BYTE +SRCHFNAM DB " : . "," File not found",13,10,"$" +BADMES DB "List output is not assigned to a device",13,10,"$" +GOODMES DB "Resident part of PRINT installed",13,10,"$" +PROMPT DB "Name of list device [PRN]: $" +CNTMES DB "Errors on list device indicate that it",13,10 + DB "may be off-line. Please check it.",13,10,13,10,"$" +BADSWT DB "Invalid parameter",13,10,"$" + + +BADVER DB "Incorrect DOS version",13,10,"$" + + 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 + +COMBUF DB 14,0 ;Device name buffer + DB 14 DUP (?) +LISTFCB DB 0,"PRN " ;Device name FCB + DB 25 DUP (0) +PARSEBUF DB 80 DUP (?) ;Parsing space + +DATA ENDS + +CODE SEGMENT +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + + +;Interrupt routines +ASSUME CS:DG,DS:NOTHING,ES:NOTHING,SS:NOTHING + IF HARDINT +HDSPINT: ;Hardware interrupt entry point + INC [TICKCNT] ;Tick + INC [TICKSUB] ;Tick + CMP [SLICECNT],0 + JZ TIMENOW + DEC [SLICECNT] ;Count down + JMP SHORT CHAININT ;Not time yet +TIMENOW: + CMP [BUSY],0 ;See if interrupting ourself + JNZ CHAININT + PUSH DS + PUSH SI + LDS SI,[INDOS] ;Check for making DOS calls + CMP BYTE PTR [SI],0 + POP SI + POP DS + JNZ CHAININT ;DOS is Buisy + INC [BUSY] ;Exclude furthur interrupts + MOV [TICKCNT],0 ;Reset tick counter + MOV [TICKSUB],0 ;Reset tick counter + STI ;Keep things rolling + + IF AINT + MOV AL,EOI ;Acknowledge interrupt + OUT AKPORT,AL + ENDIF + + CALL DOINT + CLI + MOV [SLICECNT],TIMESLICE ;Either soft or hard int resets time slice + MOV [BUSY],0 ;Done, let others in +CHAININT: + JMP [NEXTINT] ;Chain to next clock routine + ENDIF + + +SPINT: ;INT 28H entry point + IF HARDINT + CMP [BUSY],0 + JNZ NXTSP + 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 + MOV [SLICECNT],TIMESLICE ;Either soft or hard int resets time slice + MOV [BUSY],0 + ENDIF + +NXTSP: JMP [SPNEXT] ;Chain to next INT 28 + +DOINT: + PUSH SI + MOV SI,[CURRFIL] + INC SI + INC SI + CMP BYTE PTR CS:[SI],-1 + POP SI + JNZ GOAHEAD + JMP SPRET ;Nothing to do +GOAHEAD: + 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 DG:ISTACK + STI + PUSH ES + PUSH DS + PUSH BX + PUSH CX + PUSH DX + PUSH SI + PUSH DI + PUSH CS + POP DS +ASSUME DS:DG + + MOV BX,[NXTCHR] + CMP BX,OFFSET DG:BUFFER + BLKSIZ + JNZ PLOOP + JMP READBUFF ;Buffer empty + +PLOOP: + IF HARDINT + MOV BX,[NXTCHR] + CMP BX,OFFSET DG:BUFFER + BLKSIZ + JZ DONEJMP ;Buffer has become empty + CMP [SOFINT],0 + JNZ STATCHK + CMP [TICKCNT],MAXTICK ;Check our time slice + JAE DONEJMP +STATCHK: + ENDIF + + CALL PSTAT + + IF HARDINT + JZ DOCHAR ;Printer ready + CMP [SOFINT],0 + ENDIF + + JNZ DONEJMP ;If soft int give up + + IF HARDINT + CMP [TICKSUB],BUSYTICK ;Check our busy timeout + 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] + OR CL,0F8H + NEG CL + XOR CH,CH + JCXZ TABDONE +TABLP: + MOV AL," " + INC [COLPOS] + PUSH CX + CALL POUT + POP CX + LOOP TABLP + 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 + JZ PLOOP + ENDIF + +DONEJMP: + POP DI + POP SI + POP DX + POP CX + POP BX + POP DS + POP ES +ASSUME DS:NOTHING,ES:NOTHING + CLI + MOV SS,[SSsave] ;Restore Entry Stack + MOV SP,[SPsave] + STI + POP AX +SPRET: + RET + +FILEOFJ: JMP FILEOF + +READBUFF: +ASSUME DS:DG,ES:NOTHING + + MOV AL,24H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [HERRINT+2],ES ;Save current vector + MOV WORD PTR [HERRINT],BX + MOV DX,OFFSET DG:DSKERR + MOV AL,24H + MOV AH,SET_INTERRUPT_VECTOR ;Install our own + INT 21H ;Spooler must catch its errors + MOV AH,GET_DMA + INT 21H + MOV WORD PTR [DMAADDR+2],ES ;Save DMA address + MOV WORD PTR [DMAADDR],BX + MOV DX,OFFSET DG:BUFFER + MOV AH,SET_DMA + INT 21H ;New DMA address + MOV [PABORT],0 ;No abort + MOV DX,[CURRFIL] ;Read + INC DX + INC DX ;Skip over pointer + MOV AH,FCB_SEQ_READ + INT 21H + PUSH AX + LDS DX,[DMAADDR] +ASSUME DS:NOTHING + MOV AH,SET_DMA + INT 21H ;Restore DMA + LDS DX,[HERRINT] + MOV AL,24H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Restore Error INT + POP AX + PUSH CS + POP DS +ASSUME DS:DG + CMP [PABORT],0 + JNZ TONEXTFIL ;Barf on this file, got INT 24 + CMP AL,01 + JZ FILEOF ;Read EOF? + MOV BX,OFFSET DG:BUFFER ;Buffer full + MOV [NXTCHR],BX + JMP DONEJMP + +FILEOF: + MOV AL,0CH ;Form feed + CALL LOUT +TONEXTFIL: + CALL NEXTFIL + JMP DONEJMP + +;INT 24 handler + +DSKERR: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + STI + CMP [PABORT],0 + JNZ IGNRET + 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:DG,ES:DG + ADD [BADDRVM],AL ;Set correct drive letter + MOV SI,OFFSET DG:ERRMES + CALL LISTMES + TEST AH,080H + JNZ FATERR + AND DI,0FFH + CMP DI,12 + JBE HAVCOD + MOV DI,12 +HAVCOD: + SHL DI,1 + MOV DI,WORD PTR [DI+MESBAS] ; Get pointer to error message + MOV SI,DI + CALL LISTMES ; Print error type + MOV DI,OFFSET DG:EMFILNAM + MOV SI,[CURRFIL] + ADD SI,2 ;Get to file name + LODSB + ADD AL,'@' + STOSB + INC DI + MOV CX,4 + REP MOVSW + INC DI + MOVSW + MOVSB + MOV SI,OFFSET DG:ERRMEST + 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 SI,OFFSET DG:FATMES + CALL LISTMES + JMP SHORT SETABORT + +ADDFILJ: JMP ADDFIL + +COMBUSY: + MOV AX,-1 + IRET + +;Communications interrupt +SPCOMINT: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [CBUSY],0 + JNZ COMBUSY + INC [CBUSY] ;Exclude + STI ;Turn ints back on + PUSH SI + PUSH DI + PUSH CX + PUSH DS + PUSH CS + POP DS +ASSUME DS:DG + MOV [PCANMES],0 ;Havn't printed cancel message + OR AH,AH + JZ ADDFILJ ;Add file + CMP AH,1 + JZ CANFIL ;Cancel File(s) + XOR AL,AL +SETCOUNT: + PUSH AX ;Save AL return code + XOR AH,AH + MOV SI,OFFSET DG:SPLFCB + MOV CX,[NUMFCBS] +CNTFILS: + CMP BYTE PTR [SI+2],-1 ;Valid? + JZ LNEXT + INC AH +LNEXT: + ADD SI,FCBSIZ + LOOP CNTFILS +COMRET: + MOV BX,OFFSET DG:SPLFCB + MOV DX,[CURRFIL] + PUSH DS + POP ES +ASSUME ES:NOTHING + MOV CH,AH + POP AX ;Get AL return + MOV AH,CH + + IF HARDINT +BWAIT3: + CMP [BUSY],0 + JNZ BWAIT3 + INC [BUSY] + ENDIF + + CALL PSTAT ; Tweek error counter + + IF HARDINT + MOV [BUSY],0 + ENDIF + + POP DS +ASSUME DS:NOTHING + POP CX + POP DI + POP SI + MOV [CBUSY],0 + IRET + +DELALLJ: JMP DELALL + +CANFIL: +ASSUME DS:DG,ES:NOTHING + MOV CX,[NUMFCBS] + + IF HARDINT +BWAIT: + CMP [BUSY],0 + JNZ BWAIT + INC [BUSY] + ENDIF + + MOV SI,[CURRFIL] + CMP DX,-1 + JZ DELALLJ + MOV BX,[SI] + PUSH BX +LOOKEND: ;Set initial pointer values + CMP BX,SI + JZ GOTLAST + POP AX + PUSH BX + MOV BX,[BX] + JMP SHORT LOOKEND + +GOTLAST: + POP BX + MOV [LASTFCB],BX + MOV [LASTFCB2],BX + POP ES + PUSH ES + MOV BX,SI +LOOKMATCH: + MOV DI,DX + ADD SI,2 ;Skip pointer + CMP BYTE PTR [SI],-1 + JZ CANTERMJ ;No more + CMPSB + JNZ SKIPFIL ;DRIVE + PUSH CX + MOV CX,11 +NXTCHAR: + MOV AL,ES:[DI] + INC DI + CALL UPCONV + MOV AH,AL + LODSB + CALL UPCONV + CMP AH,"?" ;Wild card? + JZ NXTCHRLP ;Yes + CMP AH,AL + JNZ SKIPFILC +NXTCHRLP: + LOOP NXTCHAR +MATCH: + POP CX + MOV AH,-1 + XCHG AH,[BX+2] ;Zap it + CMP BX,[CURRFIL] ;Is current file? + JNZ REQUEUE ;No + MOV AL,1 + XCHG AL,[PCANMES] + OR AL,AL + JNZ DIDCMES ;Only print cancel message once + PUSH ES + PUSH CS + POP ES + MOV DI,OFFSET DG:CANFILNAM + MOV SI,BX + ADD SI,3 ;Get to file name + MOV AL,AH + ADD AL,'@' + STOSB + INC DI + MOV CX,4 + REP MOVSW + INC DI + MOVSW + MOVSB + POP ES + MOV SI,OFFSET DG:CANMES + CALL LISTMES + MOV SI,OFFSET DG:BELMES + CALL LISTMES +DIDCMES: + PUSH CX + CALL NEXTFIL +SKIPFILC: + POP CX +SKIPFIL: + MOV [LASTFCB2],BX + MOV BX,[BX] +NEXTFC: + MOV SI,BX + LOOP LOOKMATCH +CANTERMJ: JMP SHORT CANTERM + +REQUEUE: + MOV AX,[BX] + CMP AX,[CURRFIL] ;Is last FCB? + JZ SKIPFIL ;Yes, is in right place + MOV SI,[LASTFCB2] + MOV [SI],AX ;Unlink FCB + MOV SI,[CURRFIL] + MOV [BX],SI + MOV SI,[LASTFCB] + MOV [SI],BX ;Link FCB at end + MOV [LASTFCB],BX ;New end + MOV BX,AX ;Process what it pointed to + JMP SHORT NEXTFC + +DELALL: + CMP BYTE PTR CS:[SI+2],-1 ;Examine current file +DELALL2: + MOV BYTE PTR [SI+2],-1 ;Zap it + MOV SI,[SI] + LOOP DELALL2 + JZ CANTERM1 ;No message if nothing was in progress + MOV SI,OFFSET DG:ALLCAN + CALL LISTMES + MOV SI,OFFSET DG:BELMES + CALL LISTMES +CANTERM1: + MOV [NXTCHR],OFFSET DG:BUFFER + BLKSIZ ;Buffer empty +CANTERM: + + IF HARDINT + MOV [BUSY],0 + ENDIF + + XOR AX,AX + JMP SETCOUNT + +UPCONV: + CMP AL,'a' + JB NOCONV + CMP AL,'z' + JA NOCONV + SUB AL,20H +NOCONV: + RET + +ADDFIL: +ASSUME DS:DG,ES:NOTHING + MOV SI,[CURRFIL] + MOV CX,[NUMFCBS] + + IF HARDINT +BWAIT2: + CMP [BUSY],0 + JNZ BWAIT2 + INC [BUSY] + ENDIF + +LOOKSPOT: + CMP BYTE PTR [SI+2],-1 + JZ GOTSPOT + MOV SI,[SI] + LOOP LOOKSPOT + + IF HARDINT + MOV [BUSY],0 + ENDIF + + MOV AL,1 + JMP SETCOUNT + +GOTSPOT: + PUSH DS + POP ES + POP DS + PUSH DS +ASSUME DS:NOTHING + PUSH SI + MOV DI,SI + ADD DI,2 + MOV SI,DX + MOV CX,19 + REP MOVSW ;Copy in and set FCB + POP SI + PUSH ES + POP DS +ASSUME DS:DG + MOV WORD PTR [SI+2+fcb_EXTENT],0 + MOV BYTE PTR [SI+2+fcb_NR],0 + MOV WORD PTR [SI+2+fcb_RECSIZ],BLKSIZ + + IF HARDINT + MOV [BUSY],0 + ENDIF + + XOR AL,AL + JMP SETCOUNT + +NEXTFIL: +ASSUME DS:DG,ES:NOTHING + MOV SI,[CURRFIL] + MOV BYTE PTR [SI+2],-1 ;Done with current file + MOV SI,[SI] + MOV [CURRFIL],SI + MOV [NXTCHR],OFFSET DG:BUFFER + BLKSIZ ;Buffer empty + MOV [COLPOS],0 ;Start of line + RET + +LISTMES: +ASSUME DS:DG,ES:NOTHING + LODSB + CMP AL,"$" + JZ LMESDONE + CALL LOUT + JMP 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 + +BYTEBUF DB ? + +CALLAD DD ? + +IOCALL DB 22 + DB 0 +IOREQ DB ? +IOSTAT DW 0 + DB 8 DUP(?) + DB 0 + DW OFFSET DG:BYTEBUF +INTSEG DW ? +IOCNT DW 1 + DW 0 + +PSTAT: +ASSUME DS:DG + PUSH BX + INC [ERRCNT] + MOV BL,10 + 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:DG + MOV [BYTEBUF],AL + MOV BL,8 +DOCALL: + PUSH ES + MOV [IOREQ],BL + MOV BX,CS + MOV ES,BX + MOV BX,OFFSET DG:IOCALL + MOV [IOSTAT],0 + MOV [IOCNT],1 + PUSH DS + PUSH SI + PUSH AX + LDS SI,[LISTDEV] +ASSUME DS:NOTHING + MOV AX,[SI+6] + MOV WORD PTR [CALLAD],AX + CALL [CALLAD] + MOV AX,[SI+8] + MOV WORD PTR [CALLAD],AX + CALL [CALLAD] + POP AX + POP SI + POP DS +ASSUME DS:DG + POP ES + RET + + IF IBM +REAL_INT_13 DD ? +INT_13_RETADDR DW OFFSET DG:INT_13_BACK + +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 + +REAL_INT_5 DD ? +REAL_INT_17 DD ? +INT_17_NUM DW 0 + +INT_17: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSH SI + MOV SI,[CURRFIL] + INC SI + INC SI + CMP BYTE PTR CS:[SI],-1 + POP SI + 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 out of paper + IRET + +DO_INT_17: + JMP [REAL_INT_17] ;Do a 17 + +REAL_INT_14 DD ? +INT_14_NUM DW 0 + +INT_14: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSH SI + MOV SI,[CURRFIL] + INC SI + INC SI + CMP BYTE PTR CS:[SI],-1 + POP SI + 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 + PUSH SI + MOV SI,[CURRFIL] + INC SI + INC SI + CMP BYTE PTR CS:[SI],-1 + POP SI + 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 + + +;The following data is order and position dependant +NUMFCBS DW 10 +ERRCNT DW 0 + +SPLFCB DW OFFSET DG:FC1 + DB (FCBSIZ - 2) DUP (-1) +FC1 DW OFFSET DG:FC2 + DB (FCBSIZ - 2) DUP (-1) +FC2 DW OFFSET DG:FC3 + DB (FCBSIZ - 2) DUP (-1) +FC3 DW OFFSET DG:FC4 + DB (FCBSIZ - 2) DUP (-1) +FC4 DW OFFSET DG:FC5 + DB (FCBSIZ - 2) DUP (-1) +FC5 DW OFFSET DG:FC6 + DB (FCBSIZ - 2) DUP (-1) +FC6 DW OFFSET DG:FC7 + DB (FCBSIZ - 2) DUP (-1) +FC7 DW OFFSET DG:FC8 + DB (FCBSIZ - 2) DUP (-1) +FC8 DW OFFSET DG:FC9 + DB (FCBSIZ - 2) DUP (-1) +FC9 DW OFFSET DG:SPLFCB + DB (FCBSIZ - 2) DUP (-1) + +DEF_ENDRES LABEL BYTE + +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + +BADSPOOL: + MOV DX,OFFSET DG:BADMES + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + INT 20H + +SETUP: +;Called once to install resident + CLD + MOV [INTSEG],CS + MOV DX,OFFSET DG:PROMPT + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + MOV DX,OFFSET DG:COMBUF + MOV AH,STD_CON_STRING_INPUT + INT 21H ;Get device name + MOV DX,OFFSET DG:CRLF + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + MOV CL,[COMBUF+1] + OR CL,CL + JZ DEFSPOOL ;User didn't specify one + XOR CH,CH + MOV DI,OFFSET DG:LISTFCB + 1 + MOV SI,OFFSET DG:COMBUF + 2 + REP MOVSB +DEFSPOOL: + MOV DX,OFFSET DG:LISTFCB + MOV AH,FCB_OPEN + INT 21H + OR AL,AL + JNZ BADSPOOL ;Bad + TEST BYTE PTR [LISTFCB.fcb_DEVID],080H + JZ BADSPOOL ;Must be a device + LDS SI,DWORD PTR [LISTFCB.fcb_FIRCLUS] +ASSUME DS:NOTHING + MOV WORD PTR [CALLAD+2],DS ;Get I/O routines + MOV WORD PTR [LISTDEV+2],DS ;Get I/O routines + MOV WORD PTR [LISTDEV],SI + PUSH CS + POP DS +ASSUME DS:DG + MOV DX,OFFSET DG: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 DG:SPCOMINT + 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 DG:INT_13 + MOV AL,13H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set diskI/O interrupt + 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 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 AL,5H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_5+2],ES + MOV WORD PTR [REAL_INT_5],BX + PUSH CS + POP ES + MOV BP,OFFSET DG:LISTFCB + 1 + MOV SI,BP + MOV CX,8 +CONLP: ;Make sure device name in upper case + LODSB + CMP AL,'a' + JB DOCONLP + CMP AL,'z' + JA DOCONLP + SUB BYTE PTR [SI-1],20H +DOCONLP: + LOOP CONLP + MOV DI,OFFSET DG: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 DX,OFFSET DG:INT_17 + MOV AL,17H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set printer interrupt + MOV DX,OFFSET DG:INT_5 + MOV AL,5H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set print screen interrupt + JMP SHORT ALLSET +NOTONHITLIST: + MOV DI,OFFSET DG:INT_14_HITLIST +CHKHIT2: + MOV SI,BP + MOV CL,[DI] + INC DI + JCXZ ALLSET + 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 DX,OFFSET DG:INT_14 + MOV AL,14H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set RS232 port interrupt +ALLSET: + ENDIF + + IF HARDINT + MOV AH,GET_INDOS_FLAG + INT 21H + 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 DX,OFFSET DG:HDSPINT + MOV AL,INTLOC + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set hardware interrupt + ENDIF + + MOV [MAKERES],1 ;Indicate to do a terminate stay resident + MOV DX,OFFSET DG:GOODMES + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + RET + +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + +TRANSIENT: +;User interface + CLD + +;Code to print header +; MOV DX,OFFSET DG:HEADER +; MOV AH,STD_CON_STRING_OUTPUT +; INT 21H + +DOSVER_LOW EQU 0136H ;1.54 in hex +DOSVER_HIGH EQU 0200H ;2.00 in hex + MOV AH,GET_VERSION + INT 21H + 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 + MOV DX,OFFSET DG:BADVER + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + INT 20H +OKDOS: + MOV AX,CHAR_OPER SHL 8 + INT 21H + MOV [SWITCHAR],DL ;Get user switch character + MOV AH,GET_INTERRUPT_VECTOR + MOV AL,COMINT + INT 21H +ASSUME ES:NOTHING + MOV DI,BX + MOV SI,OFFSET DG:SPCOMINT + MOV CX,13 + REPE CMPSB + JZ GOTRES ;Signature matched + PUSH CS + POP ES + CALL SETUP +GOTRES: + PUSH CS + POP ES + MOV AH,GET_DEFAULT_DRIVE + INT 21H + MOV [DEFDRV],AL + MOV SI,PARMS + LODSB + OR AL,AL + JNZ GOTPARMS +TRANEXIT: + CALL GETSPLIST + CMP [MAKERES],0 + JNZ SETRES + INT 20H + +SETRES: + MOV DX,[ENDRES] + INT 27H + +ARGSDONE: + CMP [ARGSETUP],0 + JZ TRANEXIT + CALL PROCESS + JMP SHORT TRANEXIT + +GOTPARMS: +PARSE: + MOV DI,OFFSET DG:PARSEBUF + CALL CPARSE + JC ARGSDONE + CMP AX,4 ;Switch? + JNZ GOTNORMARG + MOV AL,[DI] ;Get the switch character + CMP AL,'C' + JZ SETCAN + CMP AL,'c' + JNZ CHKSPL +SETCAN: + MOV [CANFLG],1 + JMP SHORT PARSE +CHKSPL: + CMP AL,'P' + JZ RESETCAN + CMP AL,'p' + JNZ CHKTERM +RESETCAN: + MOV [CANFLG],0 + JMP SHORT PARSE +CHKTERM: + CMP AL,'T' + JZ SETTERM + CMP AL,'t' + JZ SETTERM + MOV DX,OFFSET DG:BADSWT + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + JMP SHORT PARSE + +SETTERM: + CALL TERMPROCESS + JMP TRANEXIT ; Ignore everything after T switch + +GOTNORMARG: + XOR AL,AL + XCHG AL,[ARGSETUP] + OR AL,AL + JZ PARSEARG + CALL NORMPROC ;Don't test ARGSETUP, it just got zeroed +PARSEARG: + PUSH SI + MOV SI,DI + MOV DI,FCB + MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 1 + INT 21H ;Parse the arg + CMP BYTE PTR [DI],0 + JNZ DRVOK + MOV DL,[DEFDRV] + INC DL + MOV BYTE PTR [DI],DL ;Set the default drive +DRVOK: + POP SI + INC [ARGSETUP] + JMP SHORT PARSE + +TERMPROCESS: + MOV DX,-1 +PROCRET: + MOV AH,1 + CALL DOSET +PROCRETNFUNC: + MOV [ARGSETUP],0 + PUSH CS + POP ES +RET14: RET + +PROCESS: + CMP [ARGSETUP],0 + JZ RET14 ;Nothing to process +NORMPROC: + MOV AL,BYTE PTR DS:[FCB+1] + CMP AL," " + JZ SRCHBADJ + MOV DX,FCB + MOV AH,[CANFLG] + CMP AH,0 + JNZ PROCRET + MOV DX,OFFSET DG:SRCHFCB + MOV AH,SET_DMA + INT 21H + MOV DX,FCB + MOV AH,DIR_SEARCH_FIRST + INT 21H + OR AL,AL + JNZ SRCHBADJ +SRCHLOOP: + MOV DX,OFFSET DG:SRCHFCB + MOV AH,FCB_OPEN + INT 21H + OR AL,AL + JZ OPENOK + CALL OPENERR + JMP SHORT NEXTSEARCH +SRCHBADJ: JMP SRCHBAD +OPENOK: + MOV DX,OFFSET DG:SRCHFCB + MOV AH,0 + CALL DOSET + OR AL,AL + JZ NEXTSEARCH + XCHG AL,[FULLFLAG] ;Know AL non-zero + OR AL,AL + JNZ NEXTSEARCH ;Only print message once + MOV DX,OFFSET DG:FULLMES ;Queue full + MOV AH,STD_CON_STRING_OUTPUT + INT 21H +NEXTSEARCH: + MOV DX,OFFSET DG:SRCHFCB + MOV AH,SET_DMA + INT 21H + MOV DX,FCB + MOV AH,DIR_SEARCH_NEXT + INT 21H + OR AL,AL + JNZ PROCRETNFUNC + JMP SRCHLOOP + +DOSET: + INT COMINT + MOV [FILCNT],AH ;Suck up return info + MOV WORD PTR [SPLIST+2],ES + MOV WORD PTR [CURFILE+2],ES + MOV WORD PTR [SPLIST],BX + MOV WORD PTR [CURFILE],DX + RET + +OPENERR: + PUSH SI + PUSH DI + MOV SI,OFFSET DG:OPFILNAM + PUSH DS + POP ES + MOV DI,OFFSET DG:SRCHFCB + CALL MVFNAM + MOV DX,OFFSET DG:OPMES + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + POP DI + POP SI + RET + +SRCHBAD: + PUSH SI + PUSH DI + MOV SI,OFFSET DG:SRCHFNAM + PUSH DS + POP ES + MOV DI,FCB + CALL MVFNAM + MOV DX,OFFSET DG:SRCHMES + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + POP DI + POP SI + JMP PROCRETNFUNC + +GETSPLIST: + MOV AH,0FFH + CALL DOSET + PUSH DS + LDS DI,[SPLIST] + MOV DI,[DI-2] ;Get the error count + POP DS + CMP DI,ERRCNT1 + JB CNTOK + MOV DX,OFFSET DG:CNTMES + MOV AH,STD_CON_STRING_OUTPUT + INT 21H +CNTOK: + MOV CL,[FILCNT] + OR CL,CL + JZ NOFILES + XOR CH,CH + LES DI,[CURFILE] + PUSH DI + INC DI + INC DI + MOV SI,OFFSET DG:CURFNAM + CALL MVFNAM + POP DI + MOV DX,OFFSET DG:CURMES + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + DEC CX + JCXZ RET12 +FILOOP: + MOV DI,ES:[DI] + PUSH DI + INC DI + INC DI + MOV SI,OFFSET DG:FILFNAM + CALL MVFNAM + POP DI + MOV DX,OFFSET DG:FILMES + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + LOOP FILOOP +RET12: RET + +NOFILES: + MOV DX,OFFSET DG:NOFILS + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + RET + +;Make a message with the file name +MVFNAM: +ASSUME DS:NOTHING,ES:NOTHING + PUSH SI + PUSH DI + PUSH CX + MOV AX,ES + PUSH DS + POP ES + MOV DS,AX + XCHG SI,DI + LODSB + ADD AL,"@" + CMP AL,"@" + JNZ STCHR + MOV AL,[DEFDRV] + ADD AL,"A" +STCHR: + STOSB + INC DI + MOV CX,4 + REP MOVSW + INC DI + MOVSW + MOVSB + MOV AX,ES + PUSH DS + POP ES + MOV DS,AX + POP CX + POP DI + POP SI + RET + +;-----------------------------------------------------------------------; +; ENTRY: ; +; DS:SI Points 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 + 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 + 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 + 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 + +CODE ENDS + END START + \ No newline at end of file diff --git a/Disk04.img b/Disk04.img new file mode 100644 index 0000000..95601d6 Binary files /dev/null and b/Disk04.img differ diff --git a/Disk04/FILBP.PAS b/Disk04/FILBP.PAS new file mode 100644 index 0000000..71decc8 Binary files /dev/null and b/Disk04/FILBP.PAS differ diff --git a/Disk04/HRDDRV.ASM b/Disk04/HRDDRV.ASM new file mode 100644 index 0000000..672b99d --- /dev/null +++ b/Disk04/HRDDRV.ASM @@ -0,0 +1,501 @@ + TITLE HRDDRV.SYS for the ALTOS ACS-86C. + +; Hard Disk Drive for Version 2.x of MSDOS. + +; Constants for commands in Altos ROM. + +ROM_CONSTA EQU 01 ;Return status AL of console selected in CX. +ROM_CONIN EQU 02 ;Get char. from console in CX to AL +ROM_CONOUT EQU 03 ;Write char. in DL to console in CX. +ROM_PMSG EQU 07 ;Write string ES:DX to console in CX. +ROM_DISKIO EQU 08 ;Perform disk I/O from IOPB in ES:CX. +ROM_INIT EQU 10 ;Returns boot console and top memory ES:DX. + + +CODE SEGMENT +ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE + + ORG 0 ;Starts at an offset of zero. + + PAGE + SUBTTL Device driver tables. + +;-----------------------------------------------+ +; DWORD pointer to next device | 1 word offset. +; (-1,-1 if last device) | 1 word segement. +;-----------------------------------------------+ +; Device attribute WORD ; 1 word. +; Bit 15 = 1 for chacter devices. ; +; 0 for Block devices. ; +; ; +; Charcter devices. (Bit 15=1) ; +; Bit 0 = 1 current sti device. ; +; Bit 1 = 1 current sto device. ; +; Bit 2 = 1 current NUL device. ; +; Bit 3 = 1 current Clock device. ; +; ; +; Bit 13 = 1 for non IBM machines. ; +; 0 for IBM machines only. ; +; Bit 14 = 1 IOCTL control bit. ; +;-----------------------------------------------+ +; Device strategy pointer. ; 1 word offset. +;-----------------------------------------------+ +; Device interrupt pointer. ; 1 word offset. +;-----------------------------------------------+ +; Device name field. ; 8 bytes. +; Character devices are any valid name ; +; left justified, in a space filled ; +; field. ; +; Block devices contain # of units in ; +; the first byte. ; +;-----------------------------------------------+ + +DSKDEV: ;Header for hard disk driver. + DW -1,-1 ;Last device + DW 2000H ;Is a block device + DW STRATEGY + DW DSK_INT +MEMMAX DB 1 ;Number of Units + + PAGE + SUBTTL Dispatch tables for each device. + +DSK_TBL:DW DSK_INI ;0 - Initialize Driver. + DW MEDIAC ;1 - Return current media code. + DW GET_BPB ;2 - Get Bios Parameter Block. + DW CMDERR ;3 - Reserved. (currently returns error) + DW DSK_RED ;4 - Block read. + DW BUS_EXIT ;5 - (Not used, return busy flag) + DW EXIT ;6 - Return status. (Not used) + DW EXIT ;7 - Flush input buffer. (Not used.) + DW DSK_WRT ;8 - Block write. + DW DSK_WRV ;9 - Block write with verify. + DW EXIT ;10 - Return output status. + DW EXIT ;11 - Flush output buffer. (Not used.) + DW EXIT ;12 - IO Control. + + PAGE + SUBTTL Strategy and Software Interrupt routines. + +;Define offsets for io data packet + +IODAT STRUC +CMDLEN DB ? ;LENGTH OF THIS COMMAND +UNIT DB ? ;SUB UNIT SPECIFIER +CMD DB ? ;COMMAND CODE +STATUS DW ? ;STATUS + DB 8 DUP (?) +MEDIA DB ? ;MEDIA DESCRIPTOR +TRANS DD ? ;TRANSFER ADDRESS +COUNT DW ? ;COUNT OF BLOCKS OR CHARACTERS +START DW ? ;FIRST BLOCK TO TRANSFER +IODAT ENDS + +PTRSAV DD 0 ;Strategy pointer save. + +; +; Simplistic Strategy routine for non-multi-Tasking system. +; +; Currently just saves I/O packet pointers in PTRSAV for +; later processing by the individual interrupt routines. +; + +STRATP PROC FAR + +STRATEGY: + MOV WORD PTR CS:[PTRSAV],BX + MOV WORD PTR CS:[PTRSAV+2],ES + RET + +STRATP ENDP + + +; +; Ram memory driver interrupt routine for processing I/O packets. +; + +DSK_INT: + PUSH SI ;Save SI from caller. + MOV SI,OFFSET DSK_TBL + +; +; Common program for handling the simplistic I/O packet +; processing scheme in MSDOS 2.0 +; + +ENTRY: PUSH AX ;Save all nessacary registers. + PUSH CX + PUSH DX + PUSH DI + PUSH BP + PUSH DS + PUSH ES + PUSH BX + + LDS BX,CS:[PTRSAV] ;Retrieve pointer to I/O Packet. + + MOV AL,[BX.UNIT] ;AL = Unit code. + MOV AH,[BX.MEDIA] ;AH = Media descriptor. + MOV CX,[BX.COUNT] ;CX = Contains byte/sector count. + MOV DX,[BX.START] ;DX = Starting Logical sector. + XCHG DI,AX ;Save Unit and Media Temporarily. + MOV AL,[BX.CMD] ;Retrieve Command type. (1 => 11) + XOR AH,AH ;Clear upper half of AX for calculation. + ADD SI,AX ;Compute entry pointer in dispatch table. + ADD SI,AX + CMP AL,11 ;Verify that not more than 11 commands. + JA CMDERR ;Ah, well, error out. + XCHG AX,DI + LES DI,[BX.TRANS] ;DI contains addess of Transfer address. + ;ES contains segment. + PUSH CS + POP DS ;Data segment same as Code segment. + JMP [SI] ;Perform I/O packet command. + + PAGE + SUBTTL Common error and exit points. + +BUS_EXIT: ;Device busy exit. + MOV AH,00000011B ;Set busy and done bits. + JMP SHORT EXIT1 + +CMDERR: MOV AL,3 ;Set unknown command error #. + +; +; Common error processing routine. +; AL contains actual error code. +; +; Error # 0 = Write Protect violation. +; 1 = Unkown unit. +; 2 = Drive not ready. +; 3 = Unknown command in I/O packet. +; 4 = CRC error. +; 5 = Bad drive request structure length. +; 6 = Seek error. +; 7 = Unknown media discovered. +; 8 = Sector not found. +; 9 = Printer out of paper. +; 10 = Write fault. +; 11 = Read fault. +; 12 = General failure. +; + +ERR_EXIT: + MOV AH,10000001B ;Set error and done bits. + STC ;Set carry bit also. + JMP SHORT EXIT1 ;Quick way out. + +EXITP PROC FAR ;Normal exit for device drivers. + +EXIT: MOV AH,00000001B ;Set done bit for MSDOS. +EXIT1: LDS BX,CS:[PTRSAV] + MOV [BX.STATUS],AX ;Save operation compete and status. + + POP BX ;Restore registers. + POP ES + POP DS + POP BP + POP DI + POP DX + POP CX + POP AX + POP SI + RET ;RESTORE REGS AND RETURN +EXITP ENDP + + PAGE + + subttl Hard Disk drive control. + +; +; Read command = 09 hex. +; Write command = 02 hex. +; Seek command = 10 hex. +; Recal command = 20 hex. +; Rezero command = 40 hex. +; Reset command = 80 hex. +; +; Busy = 01 hex. +; Operation Complete = 02 hex. +; Bad Sector = 04 hex. +; Record Not found = 08 hex. +; CRC error = 10 hex. +; (not used) = 20 hex. +; Write fault = 40 hex. +; Drive Ready = 80 hex. +; + +hd_read equ 09h +hd_writ equ 02h +hd_wmsk equ 5dh +hd_rmsk equ 9ch + page + + SUBTTL Altos monitor ram and 8089 IOPB structures. + +; +; Structure to reference 8089 and ROM command table. +; + +SIOPB STRUC + DB 4 DUP (?) ;Monitor Use Only +OPCODE DB ? ;I/O operation code. +DRIVE DB ? ;Logical drive spec. +TRACK DW ? ;Logical track number. +HEAD DB ? ;Logical head number. +SECTOR DB ? ;Logical sector to start with. +SCOUNT DB ? ;Number of logical sectors in buffer. +RETCODE DB ? ;Error code after masking. +RETMASK DB ? ;Error mask. +RETRIES DB ? ;Number of retries before error exit. +DMAOFF DW ? ;Buffer offset address. +DMASEG DW ? ;Buffer segment. +SECLENG DW ? ;Sector Length. + DB 6 DUP (?) ;8089 use only. +SIOPB ENDS + +IOPB SIOPB <,0,0,0,0,0,0,0,0,0,0,0,0,> + + PAGE + SUBTTL Common Drive parameter block definitions on Altos. + +DBP STRUC + +JMPNEAR DB 3 DUP (?) ;Jmp Near xxxx for boot. +NAMEVER DB 8 DUP (?) ;Name / Version of OS. + +;------- Start of Drive Parameter Block. + +SECSIZE DW ? ;Sector size in bytes. (dpb) +ALLOC DB ? ;Number of sectors per alloc. block. (dpb) +RESSEC DW ? ;Reserved sectors. (dpb) +FATS DB ? ;Number of FAT's. (dpb) +MAXDIR DW ? ;Number of root directory entries. (dpb) +SECTORS DW ? ;Number of sectors per diskette. (dpb) +MEDIAID DB ? ;Media byte ID. (dpb) +FATSEC DW ? ;Number of FAT Sectors. (dpb) + +;------- End of Drive Parameter Block. + +SECTRK DW ? ;Number of Sectors per track. +HEADS DW ? ;Number of heads per cylinder. +HIDDEN DW ? ;Number of hidden sectors. + +DBP ENDS + +HDDRIVE DBP <,,512,4,0,2,256,4000,0F5H,3,12,4,0> + + +INI_TAB DW OFFSET HDDRIVE.SECSIZE + + PAGE + SUBTTL Media check routine + +; +; Media check routine. +; On entry: +; AL = memory driver unit number. +; AH = media byte +; On exit: +; +; [MEDIA FLAG] = -1 (FF hex) if disk is changed. +; [MEDIA FLAG] = 0 if don't know. +; [MEDIA FLAG] = 1 if not changed. +; + +MEDIAC: LDS BX,CS:[PTRSAV] + MOV BYTE PTR [BX.TRANS],1 + JMP EXIT + + PAGE + SUBTTL Build and return Bios Parameter Block for a diskette. + +; +; Build Bios Parameter Blocks. +; +; On entry: ES:BX contains the address of a scratch sector buffer. +; AL = Unit number. +; AH = Current media byte. +; +; On exit: Return a DWORD pointer to the associated BPB +; in the Request packet. +; + +GET_BPB: + MOV SI,OFFSET HDDRIVE+11 + LDS BX,CS:[PTRSAV] + MOV WORD PTR [BX.COUNT],SI + MOV WORD PTR [BX.COUNT+2],CS + JMP EXIT + + PAGE + SUBTTL MSDOS 2.x Disk I/O drivers. + +; +; Disk READ/WRITE functions. +; +; On entry: +; AL = Disk I/O driver number +; AH = Media byte. +; ES = Disk transfer segment. +; DI = Disk transfer offset in ES. +; CX = Number of sectors to transfer +; DX = Logical starting sector. +; +; On exit: +; Normal exit through common exit routine. +; +; Abnormal exit through common error routine. +; + +DSK_RED: + MOV AH,HD_READ + JMP SHORT DSK_COM +DSK_WRV: +DSK_WRT: + MOV AH,HD_WRIT +DSK_COM: + MOV SI,OFFSET HDDRIVE ;Keeps code size down. + MOV [IOPB.DMASEG],ES + MOV [IOPB.DMAOFF],DI + MOV DI,[SI.SECSIZE] + MOV [IOPB.SECLENG],DI + MOV [IOPB.RETRIES],1 + MOV [IOPB.RETMASK],05DH ;Error return mask. + MOV [IOPB.OPCODE],AH + MOV [IOPB.DRIVE],4 ;Drive 4 is only available. + ADD DX,[SI.HIDDEN] ;Account for invisible sectors. + MOV BP,CX ;Save number of sectors to R/W +DSK_IO1: + PUSH DX ;Save starting sector. + MOV AX,DX + MOV DX,0 ;32 bit divide coming up. + MOV CX,[SI.SECTRK] + DIV CX ;Get track+head and start sector. + MOV [IOPB.SECTOR],DL ;Starting sector. + MOV BL,DL ;Save starting sector for later. + MOV DX,0 + MOV CX,[SI.HEADS] + DIV CX ;Compute head we are on. + MOV [IOPB.HEAD],DL + MOV [IOPB.TRACK],AX ;Track to read/write. + MOV AX,[SI.SECTRK] ;Now see how many sectors + INC AL ; we can burst read. + SUB AL,BL ;BL is the starting sector. + MOV AH,0 + POP DX ;Retrieve logical sector start. + CMP AX,BP ;See if on last partial track+head. + JG DSK_IO2 ;Yes, on last track+head. + SUB BP,AX ;No, update number of sectors left. + ADD DX,AX ;Update next starting sector. + JMP SHORT DSK_IO3 +DSK_IO2:MOV AX,BP ;Only read enough of sector + MOV BP,0 ;to finish buffer and clear # left. +DSK_IO3:MOV [IOPB.SCOUNT],AL + MOV DI,AX ;Save number sectors for later. + MOV BX,ROM_DISKIO + MOV CX,OFFSET IOPB + PUSH CS + POP ES + CALL ROM_CALL ;Do disk operation. + MOV AL,[IOPB.RETCODE] ;Get error code. + OR AL,AL + JNZ DERROR + MOV AX,DI ;Retrieve number of sectors read. + MOV CX,[SI.SECSIZE] ;Number of bytes per sector. + PUSH DX + MUL CX + POP DX + TEST AL,0FH ;Make sure no strange sizes. + JNZ SERR1 + MOV CL,4 + SHR AX,CL ;Convert number of bytes to para. + ADD AX,[IOPB.DMASEG] + MOV [IOPB.DMASEG],AX + OR BP,BP + JNZ DSK_IO1 ;Still more to do. + MOV AL,0 + JMP EXIT ;All done. +SERR1: MOV AL,12 + JMP ERR_EXIT + + PAGE + SUBTTL Disk Error processing. + +; +; Disk error routine. +; + +DERROR: + LDS BX,CS:[PTRSAV] + MOV [BX.COUNT],0 + PUSH CS + POP DS + + MOV BL,-1 + MOV AH,AL + MOV BH,14 ;Lenght of table. + MOV SI,OFFSET DERRTAB +DERROR2:INC BL ;Increment to next error code. + LODS BYTE PTR CS:[SI] + CMP AH,AL ;See if error code matches disk status. + JZ DERROR3 ;Got the right error, exit. + DEC BH + JNZ DERROR2 ;Keep checking table. + MOV BL,12 ;Set general type of error. +DERROR3:MOV AL,BL ;Now we've got the code. + JMP ERR_EXIT + +DERRTAB DB 00H ; 0. Write protect error + DB 00H ; 1. Unknown unit. + DB 00H ; 2. Not ready error. + DB 00H ; 3. Unknown command. + DB 10H ; 4. CRC error + DB 00H ; 5. Bad drive request. + DB 00H ; 6. Seek error + DB 00H ; 7. Unknown media. + DB 08H ; 8. Sector not found + DB 00H ; 9. (Not used.) + DB 40H ;10. Write fault. + DB 04H ;11. Read fault. + DB 01H ;12. General type of failure. + + PAGE + SUBTTL Common ROM call routine. + +; +; Save all registers except CX, BX and AX. + +ROMRTN DD 0FE000000H ;Main ROM entry point. + +ROM_CALL: + PUSH DI + PUSH SI + PUSH BP + PUSH DX + PUSH ES + CALL CS:DWORD PTR [ROMRTN] + POP ES + POP DX + POP BP + POP SI + POP DI + RET + + + PAGE + SUBTTL Hard Disk Drive initalization routine. + +DSK_INI: + LDS BX,CS:[PTRSAV] + MOV BYTE PTR [BX.MEDIA],1 + MOV WORD PTR [BX.TRANS],OFFSET DSK_INI + MOV WORD PTR [BX.TRANS+2],CS + MOV WORD PTR [BX.COUNT],OFFSET INI_TAB + MOV WORD PTR [BX.COUNT+2],CS + JMP EXIT + +CODE ENDS + + END +  \ No newline at end of file diff --git a/Disk04/PCLOCK.ASM b/Disk04/PCLOCK.ASM new file mode 100644 index 0000000..6018bfd Binary files /dev/null and b/Disk04/PCLOCK.ASM differ diff --git a/Disk04/PROFIL.ASM b/Disk04/PROFIL.ASM new file mode 100644 index 0000000..08a5ada --- /dev/null +++ b/Disk04/PROFIL.ASM @@ -0,0 +1,705 @@ + TITLE PROFIL - MS-DOS Profile program + +;Profiler for MS-DOS 1.25 2.00 +; +; Lots of stuff stolen from debug. +; User provides # of paragraphs per bucket, program is cut up accordingly. +; User also specifies clock interval + + +;System calls +PRINTBUF EQU 9 +SETDMA EQU 26 +CREATE EQU 22 +OPEN EQU 15 +CLOSE EQU 16 +GETBUF EQU 10 +BLKWRT EQU 40 +BLKRD EQU 39 +OUTCH EQU 2 +SETBASE EQU 38 + +FCB EQU 5CH +BUFLEN EQU 80 + +; FCB offsets +RR EQU 33 +RECLEN EQU 14 +FILELEN EQU 16 + + +;Segments in load order + +CODE SEGMENT PUBLIC +CODE ENDS + +DATA SEGMENT BYTE +DATA ENDS + +INIT SEGMENT BYTE +INIT ENDS + +DG GROUP CODE,DATA,INIT + +;The data segment + +DATA SEGMENT BYTE + ORG 0 +ENDMES DB 13,10,"Program terminated normally",13,10,"$" +ABORTMES DB 13,10,"Program aborted",13,10,"$" +TOOBIG DB "Program too big",13,10,"$" +EXEBAD DB "EXE file bad",13,10,"$" + +OUT_FCB LABEL WORD + DB 0 +OUTNAME DB " PRF" + DB 30 DUP(0) + + DB 80H DUP(?) +STACK LABEL WORD + +BYTEBUF DB BUFLEN DUP(?) ;Processed input queue +AXSAVE DW ? ;See interrupt routine +BXSAVE DW ? ; " " " +PROG_AREA DW ? ;Segment of program start + +;EXE file header +RUNVAR LABEL WORD +RELPT DW ? +LASTP LABEL WORD +RELSEG DW ? +PSIZE LABEL WORD +PAGES DW ? +RELCNT DW ? +HEADSIZ DW ? + DW ? +LOADLOW DW ? +PROG_SS LABEL WORD ;Program stack seg +INITSS DW ? +PROG_SP LABEL WORD ;Program SP +INITSP DW ? + DW ? +PROG_ENTRY EQU THIS DWORD +PROG_RA LABEL WORD ;Program start offset +INITIP DW ? +PROG_SA LABEL WORD ;Program start segment (may be different from PROG_AREA) +INITCS DW ? +RELTAB DW ? +RUNVARSIZ EQU $-RUNVAR + +EXEFILE DB 0 ;Flag to indicate EXE file +DRV_VALID DW ? ;Init for AX register +OUTPUT_DATA LABEL WORD ;Start of the profile data +CLOCK_GRAIN DW ? ;Clock interval micro-seconds +BUCKET_NUM DW ? ;Number of buckets +BUCKET_SIZE DW ? ;Paragraphs per bucket +PROG_LOW_PA DW ? ;Start of program (PARA #) +PROG_HIGH_PA DW ? ;End of program (PARA #) +DOS_PA DW ? ;IO-DOS PARA boundry +HIT_IO DW 0 ;IO bucket +HIT_DOS DW 0 ;DOS bucket +HIT_HIGH DW 0 ;Above Program bucket +NUM_DATA_WORDS EQU ($-OUTPUT_DATA)/2 ;Number of word items +BUCKET LABEL WORD ;Bucket count area + +;The following data will be overwritten when the buckets are initialized +LINEBUF DB BUFLEN,1,0DH ;Raw input buffer + DB BUFLEN DUP(?) + +NOFILE DB "File not found",13,10,"$" +OUTERR DB "Cannot open output file",13,10,"$" +GRAIN_PROMPT DB "Sample time (micro-sec) >= 60 ? ","$" +SIZE_PROMPT DB "Number of paragraphs (16 bytes) per bucket? ","$" +PARAM_PROMPT DB "Parameters to program? ","$" +DATA ENDS + +;The resident code portion +CODE SEGMENT PUBLIC +ASSUME CS:DG,DS:DG,ES:DG,SS:DG + +;The clock interrupt routine + PUBLIC CLK_INTER + +;Stuff provided by external clock handler routine + EXTRN CLOCKON:NEAR,CLOCKOFF:NEAR,LEAVE_INT:NEAR + + ORG 100H +START: + CLD + MOV SP,OFFSET DG:STACK ;Use internal stack + CALL SETUP +;The following setup stuff cannot be done in SETUP because we're probably +; overwritting the INIT area + MOV DX,[PROG_AREA] + MOV AH,SETBASE + INT 21H ;Set base for program + MOV ES,[PROG_AREA] + PUSH SI ;Points to BYTEBUF + MOV DI,81H ;Set unformatted params +COMTAIL: + LODSB + STOSB + CMP AL,13 + JNZ COMTAIL + SUB DI,82H ;Figure length + XCHG AX,DI + MOV BYTE PTR ES:[80H],AL + POP SI + MOV DI,FCB ;First param + MOV AX,2901H + INT 21H + MOV BYTE PTR [DRV_VALID],AL + MOV AX,2901H + MOV DI,6CH ;Second param + INT 21H + MOV BYTE PTR [DRV_VALID+1],AL + + MOV AX,ES ;Prog segment to AX + MOV DX,[PROG_RA] ;Offset + CMP [EXEFILE],1 + JZ EXELOAD ;EXE file + JMP BINFIL ;Regular file (.COM) + +EXELOAD: + MOV AX,[HEADSIZ] ;Size of header in paragraphs + ADD AX,31 + MOV CL,4 + ROL AX,CL ;Size in bytes + MOV BX,AX + AND AX,0FE00H + AND BX,0FH + MOV WORD PTR DS:[FCB+RR],AX ;Position in file of program + MOV WORD PTR DS:[FCB+RR+2],BX ;Record size + MOV DX,[PAGES] ;Size in 512 byte blocks + DEC DX + XCHG DH,DL + ROL DX,1 + MOV DI,DX + MOV SI,DX + AND DI,0FE00H + AND SI,1FFH + SUB DI,AX + SBB SI,BX + MOV AX,[LASTP] + OR AX,AX + JNZ PARTP + MOV AX,200H +PARTP: + ADD DI,AX + ADC SI,0 + MOV AX,DI + ADD AX,15 + AND AL,0F0H + OR AX,SI + MOV CL,4 + ROR AX,CL + XCHG AX,CX + MOV BX,[PROG_AREA] + ADD BX,10H + MOV AX,WORD PTR DS:[2] + SUB AX,CX + MOV DX,OFFSET DG:TOOBIG + JB ERROR + CMP BX,AX + JA ERROR + CMP [LOADLOW],-1 + JNZ LOADEXE + XCHG AX,BX +LOADEXE: + MOV BP,AX + XOR DX,DX + CALL READ + JC HAVEXE +BADEXE: + MOV DX,OFFSET DG:EXEBAD + +ERROR: + MOV AH,PRINTBUF ;Print the message in DX + INT 21H + INT 20H ;Exit + +HAVEXE: + MOV AX,[RELTAB] ;Get position of relocation table + MOV WORD PTR DS:[FCB+RR],AX + MOV WORD PTR DS:[FCB+RR+2],0 + MOV DX,OFFSET DG:RELPT ;Four byte buffer + MOV AH,SETDMA + INT 21H + CMP [RELCNT],0 + JZ NOREL +RELOC: + MOV AH,BLKRD + MOV DX,FCB + MOV CX,4 + INT 21H ;Read in one relocation pointer + OR AL,AL + JNZ BADEXE + MOV DI,[RELPT] ;Pointer offset + MOV AX,[RELSEG] ;pointer segment + ADD AX,BP ;Bias with actual load segment + MOV ES,AX + ADD ES:[DI],BP ;Relocate + DEC [RELCNT] + JNZ RELOC + +NOREL: + ADD [INITSS],BP + ADD [INITCS],BP + JMP SHORT PROGGO + +BINFIL: + MOV WORD PTR DS:[FCB+RECLEN],1 + MOV SI,-1 + MOV DI,SI + CALL READ + MOV ES,[PROG_SA] ;Prog segment to ES + MOV AX,WORD PTR ES:[6] + MOV [PROG_SP],AX ;Default SP for non EXE files + DEC AH + MOV WORD PTR ES:[6],AX ;Fix size + +PROGGO: + PUSH DS + MOV AX,[PROG_AREA] + MOV DS,AX + MOV DX,80H + MOV AH,SETDMA + INT 21H ;Set default disk transfer address + POP DS + MOV BX,[BUCKET_NUM] + SHL BX,1 ;Mult by 2 to get #bytes in bucket area +CLEAR: + MOV BUCKET[BX],0 ;Zero counts + SUB BX,2 + JGE CLEAR + MOV DX,[CLOCK_GRAIN] + PUSH DS + POP ES + CLI ;Don't collect data yet + CALL CLOCKON ;Set the interrupt + MOV SI,[PROG_RA] + MOV DI,[PROG_AREA] + MOV BX,[PROG_SS] + MOV CX,[PROG_SP] + MOV AX,[DRV_VALID] + MOV DX,[PROG_SA] + MOV SS,BX + MOV SP,CX + XOR CX,CX + PUSH CX ;0 on prog stack + PUSH DX + PUSH SI + MOV DS,DI ;Set up segments + MOV ES,DI + STI ;Start collecting data +XXX PROC FAR + RET ;Hop to program +XXX ENDP + +READ: +; AX:DX is disk transfer address (segment:offset) +; SI:DI is 32 bit length + +RDLOOP: + MOV BX,DX + AND DX,000FH + MOV CL,4 + SHR BX,CL + ADD AX,BX + PUSH AX + PUSH DX + PUSH DS + MOV DS,AX + MOV AH,SETDMA + INT 21H + POP DS + MOV DX,FCB + MOV CX,0FFF0H ;Keep request in segment + OR SI,SI ;Need > 64K? + JNZ BIGRD + MOV CX,DI ;Limit to amount requested +BIGRD: + MOV AH,BLKRD + INT 21H + SUB DI,CX ;Subtract off amount done + SBB SI,0 ;Ripple carry + CMP AL,1 ;EOF? + POP DX + POP AX ;Restore transfer address + JZ RET10 + ADD DX,CX ;Bump transfer address by last read + MOV BX,SI + OR BX,DI ;Finished with request + JNZ RDLOOP +RET10: STC + RET + + +;Return here on termination or abort + +TERMINATE: + CLI ;Stop collecting data + MOV DX,OFFSET DG:ENDMES + JMP SHORT WRITEOUT +ABORT: + CLI ;Stop collecting data + MOV DX,OFFSET DG:ABORTMES +WRITEOUT: + MOV AX,CS + MOV DS,AX + MOV SS,AX + MOV SP,OFFSET DG:STACK ;Use internal stack + PUSH DX + CALL CLOCKOFF ;Restore original clock routine + STI ;Back to normal clock + POP DX + MOV AH,PRINTBUF + INT 21H ;Apropriate termination message + MOV [OUT_FCB+14],2 ;Word size records + MOV DX,OFFSET DG:OUTPUT_DATA + MOV AH,SETDMA + INT 21H ;Set the transfer address + MOV CX,NUM_DATA_WORDS + ADD CX,[BUCKET_NUM] + MOV DX,OFFSET DG:OUT_FCB + MOV AH,BLKWRT + INT 21H ;Write out data + MOV DX,OFFSET DG:OUT_FCB + MOV AH,CLOSE + INT 21H + INT 20H ;Exit + + +;The clock interrupt routine +CLK_INTER PROC NEAR + CLI + PUSH DS + PUSH CS + POP DS ;Get profile segment + MOV [AXSAVE],AX + MOV [BXSAVE],BX + POP AX ;old DS + MOV BX,OFFSET DG:LEAVE_INT + PUSH BX + PUSH AX + PUSH ES + PUSH [AXSAVE] + PUSH [BXSAVE] + PUSH CX + PUSH DX + + +;Stack looks like this +; +; +18 OLDFLAGS +; +16 OLDCS +; +14 OLDIP +; +12 RETURN TO LEAVE_INT +; +10 OLDDS +; +8 OLDES +; +6 OLDAX +; +4 OLDBX +; +2 OLDCX +;SP-> OLDDX + + MOV BX,SP + LES BX,DWORD PTR SS:[BX+14] ;Get CS:IP + MOV AX,BX + MOV CL,4 + SHR AX,CL + MOV CX,ES + ADD AX,CX ;Paragraph of CS:IP + CMP AX,[DOS_PA] ;Below DOS? + JB IOHIT + CMP AX,[PROG_LOW_PA] ;Below program? + JB DOSHIT + CMP AX,[PROG_HIGH_PA] ;Above program? + JAE MISSH + + SUB AX,[PROG_LOW_PA] ;Paragraph offset + XOR DX,DX + + DIV [BUCKET_SIZE] + MOV BX,AX + SHL BX,1 ;Mult by 2 to get byte offset + INC BUCKET[BX] + JMP SHORT DONE + +IOHIT: + INC [HIT_IO] + JMP SHORT DONE + +DOSHIT: + INC [HIT_DOS] + JMP SHORT DONE + +MISSH: + INC [HIT_HIGH] + +DONE: + POP DX + POP CX + POP BX + POP AX + POP ES + POP DS + STI + RET ;To LEAVE_INT + +CLK_INTER ENDP + +CODE ENDS + +;The init segment contains code to process input parameters +; It will be blasted as soon as the program to be run is read in +; And/or the bucket area is initialized + +INIT SEGMENT BYTE + ORG 0 + +SETUP: + MOV DX,FCB + MOV AH,OPEN + INT 21H ;Open program file + AND AL,AL + JZ OPENOK + MOV DX,OFFSET DG:NOFILE + JMP ERROR + +OPENOK: + XOR BX,BX + MOV WORD PTR DS:[FCB+RR],BX + MOV WORD PTR DS:[FCB+RR+2],BX ;RR to 0 + MOV SI,FCB + MOV DI,OFFSET DG:OUT_FCB + MOV CX,4 + REP MOVSW + MOVSB ;Transfer drive spec and file to output + MOV DX,OFFSET DG:OUT_FCB + MOV AH,CREATE + INT 21H ;Try to create the output file + AND AL,AL + JZ GETSIZE + MOV DX,OFFSET DG:OUTERR + JMP ERROR + +GETSIZE: ;Get bucket size + MOV DX,OFFSET DG:SIZE_PROMPT + MOV AH,PRINTBUF + INT 21H + CALL INBUF + CALL SCANB + JZ GETSIZE ;SCANB went to CR + XOR BX,BX + INC BX ;Size >=1 + CALL GETNUM + JC GETSIZE ;Bad number + MOV [BUCKET_SIZE],DX + + CMP WORD PTR DS:[FCB+9],5800H+"E" ;"EX" + JNZ NOTEXE + CMP BYTE PTR DS:[FCB+11],"E" + JNZ NOTEXE + +LOADEXEHEAD: ;Load the EXE header + MOV [EXEFILE],1 + MOV DX,OFFSET DG:RUNVAR ;Read header in here + MOV AH,SETDMA + INT 21H + MOV CX,RUNVARSIZ + MOV DX,FCB + MOV WORD PTR DS:[FCB+RECLEN],1 + OR AL,AL + MOV AH,BLKRD + INT 21H + CMP [RELPT],5A4DH ;Magic number + JZ EXEOK + JMP BADEXE +EXEOK: + MOV AX,[PAGES] ;Size of file in 512 byte blocks + MOV CL,5 + SHL AX,CL ;Size in paragraphs + JMP SHORT SETBUCKET + +NOTEXE: + MOV AX,WORD PTR DS:[FCB+FILELEN] + MOV DX,WORD PTR DS:[FCB+FILELEN+2] ;Size of file in bytes DX:AX + ADD AX,15 + ADC DX,0 ;Round to PARA + MOV CL,4 + SHR AX,CL + AND AX,0FFFH + MOV CL,12 + SHL DX,CL + AND DX,0F000H + OR AX,DX ;Size in paragraphs to AX + MOV [PROG_RA],100H ;Default offset + +SETBUCKET: + PUSH AX ;Save size + XOR DX,DX + DIV [BUCKET_SIZE] + INC AX ;Round up + MOV [BUCKET_NUM],AX + MOV BX,OFFSET DG:BUCKET + SHL AX,1 ;Number of bytes in bucket area + ADD AX,BX ;Size of profil in bytes + ADD AX,15 ;Round up to PARA boundry + MOV CL,4 + SHR AX,CL ;Number of paragraphs in profil + INC AX ;Insurance + MOV BX,CS + ADD AX,BX + MOV [PROG_AREA],AX + + CMP [EXEFILE],1 + JZ SETBOUNDS + MOV AX,[PROG_AREA] ;Set up .COM segments + MOV [PROG_SS],AX + MOV [PROG_SA],AX + +SETBOUNDS: ;Set the sample window + MOV BX,10H ;Get start offset + ADD BX,[PROG_AREA] ;PARA # of start + MOV [PROG_LOW_PA],BX + POP AX ;Recall size of PROG in paragraphs + ADD BX,AX + MOV [PROG_HIGH_PA],BX + +SETDOS: + XOR DX,DX + MOV ES,DX ;look in interrupt area + MOV DX,WORD PTR ES:[82H] ;From int #20 + MOV [DOS_PA],DX + PUSH DS + POP ES + +GETGRAIN: ;Get sample interval + MOV DX,OFFSET DG:GRAIN_PROMPT + MOV AH,PRINTBUF + INT 21H + CALL INBUF + CALL SCANB + JZ GETGRAIN ;SCANB went to CR + MOV BX,60 ;Grain >=60 + CALL GETNUM + JC GETGRAIN ;Bad number + MOV [CLOCK_GRAIN],DX + + MOV DX,OFFSET DG:PARAM_PROMPT + MOV AH,PRINTBUF + INT 21H + CALL INBUF ;Get program parameters + + MOV AX,2522H ;Set vector 22H + MOV DX,OFFSET DG:TERMINATE + INT 21H + MOV AL,23H ;Set vector 23H + MOV DX,OFFSET DG:ABORT + INT 21H + RET ;Back to resident code + +GETNUM: ;Get a number, DS:SI points to buffer, carry set if bad + XOR DX,DX + MOV CL,0 + LODSB +NUMLP: + SUB AL,"0" + JB NUMCHK + CMP AL,9 + JA NUMCHK + CMP DX,6553 + JAE BADNUM + MOV CL,1 + PUSH BX + MOV BX,DX + SHL DX,1 + SHL DX,1 + ADD DX,BX + SHL DX,1 + CBW + POP BX + ADD DX,AX + LODSB + JMP NUMLP +NUMCHK: + CMP CL,0 + JZ BADNUM + CMP BX,DX + JA BADNUM + CLC + RET +BADNUM: + STC + RET + +INBUF: ;Read in from console, SI points to start on exit + MOV AH,GETBUF + MOV DX,OFFSET DG:LINEBUF + INT 21H + MOV SI,2 + OFFSET DG:LINEBUF + MOV DI,OFFSET DG:BYTEBUF +CASECHK: + LODSB + CMP AL,'a' + JB NOCONV + CMP AL,'z' + JA NOCONV + ADD AL,"A"-"a" ;Convert to upper case +NOCONV: + STOSB + CMP AL,13 + JZ INDONE + CMP AL,'"' + JNZ QUOTSCAN + CMP AL,"'" + JNZ CASECHK +QUOTSCAN: + MOV AH,AL +KILLSTR: + LODSB + STOSB + CMP AL,13 + JZ INDONE + CMP AL,AH + JNZ KILLSTR + JMP SHORT CASECHK + +INDONE: + MOV SI,OFFSET DG:BYTEBUF + +;Output CR/LF + +CRLF: + MOV AL,13 + CALL OUT + MOV AL,10 + +OUT: + PUSH AX + PUSH DX + AND AL,7FH + XCHG AX,DX + MOV AH,OUTCH + INT 21H + POP DX + POP AX + RET + +SCANB: ;Scan to first non-blank + PUSH AX +SCANNEXT: + LODSB + CMP AL," " + JZ SCANNEXT + CMP AL,9 + JZ SCANNEXT + DEC SI + POP AX +EOLCHK: + CMP BYTE PTR[SI],13 + RET + +INIT ENDS + END START + \ No newline at end of file diff --git a/Disk04/PROFIL.OBJ b/Disk04/PROFIL.OBJ new file mode 100644 index 0000000..66946b3 Binary files /dev/null and b/Disk04/PROFIL.OBJ differ diff --git a/Disk04/PROHST.EXE b/Disk04/PROHST.EXE new file mode 100644 index 0000000..dfa8983 Binary files /dev/null and b/Disk04/PROHST.EXE differ diff --git a/Disk04/PROHST.HLP b/Disk04/PROHST.HLP new file mode 100644 index 0000000..13880e5 --- /dev/null +++ b/Disk04/PROHST.HLP @@ -0,0 +1,35 @@ +PROHST is a preliminary version of a utility to process the profile +file produced by the PROFIL utility of MSDOS. +Those of you familiar with MS-Pascal or MS-Fortran will have little +difficulty in understanding how the parameters work. There are three, +the .PRF filename, an optional histogram file (default extension .HST, +default name same as the .PRF file) and an optional link map. If the +link map was produced with the line number options PROHST will try +and relate buckets to line numbers. Otherwise, it will relate it to +module offsets. If you specify no map file (the default), addresses +relative to the start of the program will be used. The default extension +for the map file is .MAP. + +a:prohst f; + +this will produce a histogram for the file f.prf in f.hst and no map file +will be assumed. + +a:prohst f,,; + +this will produce a histogram for f.prf in f.hst and expects a f.map file. + +a:prohst f,g,k + +this produces a histogram for f.prf in g.hst and expects a map file k.map. + +Note that if you select the map option with line numbers, the program will +appear to be looping. Never fear, go and have lunch or some other time +consuming pastime, and you will be suprised how long it took to produce +such a small file. Also, some of the line number/bucket correspondances are +not what they might be. Future version shoudl fix this. If you make a better +version, be sure to let me have a copy. + +David Jones. + + \ No newline at end of file diff --git a/Disk04/PROHST.PAS b/Disk04/PROHST.PAS new file mode 100644 index 0000000..4ee13fc --- /dev/null +++ b/Disk04/PROHST.PAS @@ -0,0 +1,403 @@ +PROGRAM prohst(input,output); +{$debug- $line- $symtab+} + +{**********************************************************************} +{* *} +{* prohst *} +{* *} +{* This program produces a histogram from the profile file produced *} +{* by the MS-DOS profile utility. It optionally reads the map file *} +{* generated when the program being profiled was linked, and writes *} +{* either the module address or, if available, the line number as *} +{* a prefix to the line of the graph which describes a particular *} +{* bucket. *} +{* *} +{* After using filbm (derived from the Pascal and Fortran front end *} +{* command scanner) to parse its parameters, prohst opens the map *} +{* file if specified, searches for the heading line, and then reads *} +{* the lines giving the names and positions of the modules. It builds *} +{* a linked list of module names and start addresses. *} +{* *} +{* It then reads the bucket file header and and bucket array elements *} +{* into a variable created on the heap. It simultaneously calculates *} +{* a normalization factor. It writes the profile listing header and *} +{* starts to write the profile lines. For each bucket, the address *} +{* is calculated. The first entry in the address/name linked list *} +{* is the lowest addressed module. This is initially the 'current' *} +{* module. The bucket address is compared with the current module *} +{* address. When it becomes the greater, the module name is written *} +{* to the listing and the next entry in the address/name list becomes *} +{* the current module. If line numbers are available, the bucket *} +{* address is also compared to the current line/address. This is *} +{* read and calculated directly from the file. Since there may be *} +{* more than one line per bucket, several entries may be read until *} +{* the addresses compare within the span of addresses encompassed by *} +{* a bucket (its 'width'). Note that the idiosyncracies of Pascal i/o *} +{* make it necessary to continually check for the end of the map file *} +{* and the complexity of this code is mainly due to an attempt to *} +{* make it reasonably resilient to changes in the format of the map *} +{* file. *} +{* *} +{**********************************************************************} + + +CONST + max_file = 32; + + +TYPE + filenam = LSTRING (max_file); + sets = SET OF 0..31; + address_pointer = ^address_record; + address_record = RECORD + next: address_pointer; + name: STRING (15); + address: WORD; + END; + + + + + +VAR + + i: INTEGER; + bucket: FILE OF WORD; + hist: TEXT; + map: TEXT; + + first_address, + this_address: address_pointer; + current_base: WORD; + bucket_name, + hist_name, + map_name: filenam; + + switches: sets; + + line: LSTRING (100); + + map_avail: BOOLEAN; + line_nos_avail: BOOLEAN; + + norm: REAL; + per_cent: INTEGER; + real_bucket, + norm_bucket: REAL; + cum_per_cent, + real_per_cent: REAL; + + bucket_num, + clock_grain, + bucket_size, + prog_low_pa, + prog_high_pa, + dos_pa, + hit_io, + hit_dos, + hit_high: WORD; + + seg, + offset, + parcel: WORD; + + address: WORD; + new_line_no, + line_no: WORD; + + dummy : LSTRING (8); + name: LSTRING (20); + line_no_part: LSTRING (17); + start: LSTRING (6); + + buckets: ^SUPER ARRAY [1 .. *] OF REAL; + + this_bucket: WORD; + +LABEL 1; + + +PROCEDURE filbm (VAR prffil, hstfil, mapfil: filenam; + VAR switches: sets); EXTERN; + +FUNCTION realword (w: WORD): REAL; +BEGIN + IF ORD (w) < 0 THEN BEGIN + realword := FLOAT (maxint) + FLOAT (ORD (w - maxint)); + END + ELSE BEGIN + realword := FLOAT (ORD(w)); + END {IF}; +END {realword}; + + + +PROCEDURE skip_spaces; +BEGIN + WHILE NOT eof(map) AND THEN map^ = ' ' DO BEGIN + get (map); + END {WHILE}; +END {skip_spaces}; + + +FUNCTION hex_char (ch: CHAR): WORD; +BEGIN + IF ch >= '0' AND THEN ch <= '9' THEN BEGIN + hex_char := WRD (ch) - WRD ('0'); + END + ELSE IF ch >= 'A' AND THEN ch <= 'F' THEN BEGIN + hex_char := WRD (ch) - WRD ('A') + 10; + END + ELSE BEGIN + WRITELN ('Invalid hex character'); + hex_char := 0; + END {IF}; +END {hex_char}; + + +FUNCTION read_hex (i :WORD): WORD; +VAR + hex_val: WORD; +BEGIN + skip_spaces; + hex_val := 0; + WHILE NOT eof (map) AND THEN i <> 0 DO BEGIN + hex_val := hex_val * 16 + hex_char (map^); + GET (map); + i := i - 1; + END {WHILE}; + read_hex := hex_val; +END {read_hex}; + +FUNCTION read_h: WORD; +BEGIN + read_h := read_hex (4); + get (map); + get (map); +END; + +FUNCTION read_word: WORD; +VAR + int_value: WORD; +BEGIN + int_value := 0; + IF NOT EOF (map) THEN BEGIN + READ (map, int_value); + END {IF}; + read_word := int_value; +END {read_word}; + + +FUNCTION map_digit: BOOLEAN; +BEGIN + map_digit := (map^ >= '0') OR (map^ <= '9'); +END {map_digit}; + +BEGIN {prohst} + writeln (output, ' Profile Histogram Utility - Version 1.0'); + writeln (output); + writeln (output, ' Copyright - Microsoft, 1983'); + + start := ' '; + + filbm (bucket_name, hist_name, map_name, switches); + + IF 31 IN switches THEN BEGIN + ABORT ('Map file must not be terminal', 0, 0); + END {IF}; + + IF NOT (28 IN switches) THEN BEGIN + ABORT ('No histogram file specified', 0, 0); + END {IF}; + + ASSIGN (bucket, bucket_name); + reset (bucket); + ASSIGN (hist, hist_name); + rewrite (hist); + + map_avail := 29 IN switches; + line_nos_avail := FALSE; + + IF map_avail THEN BEGIN + ASSIGN (map, map_name); + RESET (map); + + WHILE NOT EOF (map) AND THEN start <> ' Start' DO BEGIN + READLN (map, start); + END {WHILE}; + + NEW (first_address); + this_address := NIL; + + WHILE NOT EOF(map) DO BEGIN + READLN (map, line); + IF line.len < 6 OR ELSE line [2] < '0' OR ELSE + line [2] > '9' THEN BEGIN + BREAK; + END {IF}; + + IF this_address <> NIL THEN BEGIN + NEW (this_address^.next); + this_address := this_address^.next; + END + ELSE BEGIN + this_address := first_address; + END {IF}; + this_address^.next := NIL; + + this_address^.address := (hex_char (line [2]) * 4096) + + (hex_char (line [3]) * 256) + + (hex_char (line [4]) * 16) + + hex_char (line [5]); + + FOR i := 1 TO 15 DO BEGIN + this_address^.name [i] := line [22 + i]; + END {FOR}; + + END {WHILE}; + + WHILE NOT EOF (map) DO BEGIN + READLN (map, line_no_part); + IF line_no_part = 'Line numbers for ' THEN BEGIN + line_nos_avail := TRUE; + BREAK; + END {IF}; + END {WHILE}; + + END {IF}; + + read (bucket, clock_grain, bucket_num, bucket_size, + prog_low_pa, prog_high_pa, dos_pa, hit_io, hit_dos, hit_high); + + NEW (buckets,ORD (bucket_num)); + + norm := 0.0; + norm_bucket := 0.0; + + FOR i := 1 TO ORD (bucket_num) DO BEGIN + read (bucket, this_bucket); + real_bucket := realword (this_bucket); + + IF real_bucket > norm_bucket THEN BEGIN + norm_bucket := real_bucket; + END {IF}; + + norm := norm + real_bucket; + buckets^[i] := real_bucket; + END {FOR}; + norm_bucket := 45.0/norm_bucket; + norm := 100.0/norm; + + WRITELN (hist, 'Microsoft Profiler Output Listing'); + + WRITELN (hist); + WRITELN (hist, ORD (bucket_num):6, bucket_size:4,'-byte buckets.'); + + WRITELN (hist); + WRITELN (hist, 'Profile taken between ', prog_low_pa*16::16, + ' and ', prog_high_pa*16::16, '.'); + + WRITELN (hist); + WRITELN (hist, 'DOS program address:', dos_pa::16); + + WRITELN (hist); + WRITELN (hist, 'Number of hits in DOS: ', hit_dos:5, + ' or ', realword (hit_dos) * norm:4:1, '%.'); + WRITELN (hist, 'Number of hits in I/O: ', hit_io:5, + ' or ', realword (hit_io) * norm:4:1, '%.'); + WRITELN (hist, 'Number of hits high : ', hit_high:5, + ' or ', realword (hit_high) * norm:4:1, '%.'); + WRITELN (hist); + WRITELN (hist, ' Hits Addr. Line/ Cumul. % 0.0 ', + ' ', + 1.0/norm:1:1); + + WRITELN (hist, ' Offset +----------------', + '----------------------------'); + WRITELN (hist, name); + i := 0; + parcel := 0; + current_base := 0; + line_no := 0; + new_line_no := 0; + cum_per_cent := 0.0; + + WHILE i < ORD (bucket_num) DO BEGIN + i := i + 1; + IF buckets^[i] < 0.9 THEN BEGIN + WRITELN (hist); + REPEAT + i := i + 1; + UNTIL (i = ORD (bucket_num)) OR ELSE buckets^[i] > 0.0; + END {IF}; + + address := bucket_size * (WRD (i) - 1); + + WHILE map_avail AND THEN + address >= first_address^.address DO BEGIN + WRITELN (hist, ' ', first_address^.name); + current_base := first_address^.address; + first_address := first_address^.next; + END {WHILE}; + + WHILE line_nos_avail AND THEN NOT eof (map) AND THEN + address >= parcel DO BEGIN + skip_spaces; + WHILE (map^ < '0') OR (map^ > '9') DO BEGIN + + IF EOF (map) THEN BEGIN + goto 1; + END {IF}; + READLN (map); + skip_spaces; + END {WHILE}; + + + line_no := new_line_no; + new_line_no := read_word; + seg := read_hex (4); + IF EOF (map) THEN BEGIN + GOTO 1; + END {IF}; + IF map^ <> ':' THEN BEGIN + WRITELN ('Invalid map file'); + END {IF}; + get (map); + IF EOF (map) THEN BEGIN + GOTO 1; + END {IF}; + offset := read_hex (3) + WRD (hex_char (map^) > 0); + get (map); + IF map^ <> 'H' THEN BEGIN + WRITELN ('Invalid map file'); + END {IF}; + IF EOF (map) THEN BEGIN + GOTO 1; + END {IF}; + get (map); + parcel := seg + offset; + END {WHILE}; +1: real_per_cent := buckets^[i] * norm; + cum_per_cent := cum_per_cent + real_per_cent; + per_cent := ROUND ( buckets^[i] * norm_bucket); + + WRITE (hist, buckets^ [i]:6:0, ' ', + address*16:6:16); + IF line_no <> 0 THEN BEGIN + WRITE (hist, line_no:6); + line_no := 0; + END + ELSE IF map_avail AND THEN first_address <> NIL THEN BEGIN + WRITE (hist, ' #', address - first_address^.address:4:16); + END + ELSE BEGIN + WRITE (hist, ' '); + END {IF}; + + WRITELN (hist, ' ', cum_per_cent:5:1, ' ', real_per_cent:4:1, ' |', + '*': per_cent); + END {WHILE}; + WRITELN (hist, ' +-----------------', + '------------------'); +END. + \ No newline at end of file diff --git a/Disk04/SKELIO.ASM b/Disk04/SKELIO.ASM new file mode 100644 index 0000000..b2ff8e3 --- /dev/null +++ b/Disk04/SKELIO.ASM @@ -0,0 +1,1377 @@ + TITLE IO.SYS for the ALTOS ACS-86C. + +; I/O system for Version 2.x of MSDOS. + +;This BIOS designed to be linked with the SYSINIT module provided by +;Microsoft + +BIOSIZ EQU 4096 ;Size of BIOS in bytes. +BIOSIZS EQU 100H ;Size of BIOS in Paragraphs. +ANSI EQU 0 ;Ansi switch. + +;Additional Information for the ALTOS machine. + +QSIZE EQU 100 ;Input queue size. +BIOSSEG EQU 0C0H ;I/O system segment. +MAX_MEM EQU 4000H ;Memory size in paragraphs. + +; Constants for commands in Altos ROM. + +ROM_CONSTA EQU 01 ;Return status AL of console selected in CX. +ROM_CONIN EQU 02 ;Get char. from console in CX to AL +ROM_CONOUT EQU 03 ;Write char. in DL to console in CX. +ROM_PMSG EQU 07 ;Write string ES:DX to console in CX. +ROM_DISKIO EQU 08 ;Perform disk I/O from IOPB in ES:CX. +ROM_INIT EQU 10 ;Returns boot console and top memory ES:DX. + +;Things needed to communicate with SYSINIT + +EXTRN SYSINIT:FAR ;The entry point of SYSINIT +EXTRN CURRENT_DOS_LOCATION:WORD ;Where the DOS is when SYSINIT called +EXTRN FINAL_DOS_LOCATION:WORD ;Where I want SYSINIT to put the DOS +EXTRN DEVICE_LIST:DWORD ;Pointer to the DEVICE list. +EXTRN MEMORY_SIZE:WORD ;Size in paragraphs of Physical memory. +EXTRN DEFAULT_DRIVE:BYTE ;Default Drive to use when system booted +EXTRN BUFFERS:BYTE ;Number of default buffers. + ; Leave as is and SYSINIT uses only 2. + +CODE SEGMENT +ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE + + ORG 0 ;Starts at an offset of zero. + +INIT: JMP HWINIT + + PAGE + + SUBTTL Device driver tables. + +;-----------------------------------------------+ +; DWORD pointer to next device | 1 word offset. +; (-1,-1 if last device) | 1 word segement. +;-----------------------------------------------+ +; Device attribute WORD ; 1 word. +; Bit 15 = 1 for chacter devices. ; +; 0 for Block devices. ; +; ; +; Charcter devices. (Bit 15=1) ; +; Bit 0 = 1 current sti device. ; +; Bit 1 = 1 current sto device. ; +; Bit 2 = 1 current NUL device. ; +; Bit 3 = 1 current Clock device. ; +; ; +; Bit 13 = 1 for non IBM machines. ; +; 0 for IBM machines only. ; +; Bit 14 = 1 IOCTL control bit. ; +;-----------------------------------------------+ +; Device strategy pointer. ; 1 word offset. +;-----------------------------------------------+ +; Device interrupt pointer. ; 1 word offset. +;-----------------------------------------------+ +; Device name field. ; 8 bytes. +; Character devices are any valid name ; +; left justified, in a space filled ; +; field. ; +; Block devices contain # of units in ; +; the first byte. ; +;-----------------------------------------------+ + +DEVSTART LABEL WORD +CONDEV: ;Header for device CON + DW AUXDEV,BIOSSEG ;Link to next device + DW 8003H ;Attributes - console input, output device + DW STRATEGY ;Srategy entry point + DW CON_INT ;Interrupt entry point + DB "CON " ;Device name + +AUXDEV: ;Header for device AUX + DW PRNDEV,BIOSSEG + DW 8000H + DW STRATEGY + DW AUX_INT + DB "AUX " + +PRNDEV: ;Header for device PRN + DW TIMDEV,BIOSSEG + DW 8000H + DW STRATEGY + DW PRN_INT + DB "PRN " + +TIMDEV: ;Header for device CLOCK + DW DSKDEV,BIOSSEG + DW 8008H + DW STRATEGY + DW TIM_INT + DB "CLOCK " + +DSKDEV: ;Header for disk devices + DW -1,-1 ;Last device + DW 2000H ;Is a block device + DW STRATEGY + DW DSK_INT +DRVMAX DB 1 ;Number of Units + DB 7 DUP (?) + + PAGE + SUBTTL Dispatch tables for each device. + +DSKTBL: DW DSK_INIT ;0 - Initialize Driver. + DW MEDIAC ;1 - Return current media code. + DW GET_BPB ;2 - Get Bios Parameter Block. + DW CMDERR ;3 - Reserved. (currently returns error) + DW DSK_RED ;4 - Block read. + DW BUS_EXIT ;5 - (Not used, return busy flag) + DW EXIT ;6 - Return status. (Not used) + DW EXIT ;7 - Flush input buffer. (Not used.) + DW DSK_WRT ;8 - Block write. + DW DSK_WRV ;9 - Block write with verify. + DW EXIT ;10 - Return output status. + DW EXIT ;11 - Flush output buffer. (Not used.) + DW EXIT ;12 - IO Control. + +CONTBL: DW EXIT ;0 - Init. (Not used) + DW EXIT ;1 - Media check (Not used) + DW EXIT ;2 - Get Bios Parameter Block (Not used) + DW CMDERR ;3 - Reserved. (Currently returns error) + DW CON_READ ;4 - Character read. (Destructive) + DW CON_RDND ;5 - Character read. (Non-destructive) + DW EXIT ;6 - Return status. (Not used) + DW CON_FLSH ;7 - Flush Input buffer. + DW CON_WRIT ;8 - Character write. + DW CON_WRIT ;9 - Character write with Verify. + DW CON_WRST ;10 - Character write status. + DW EXIT ;11 - Flush output buffer. (Not used.) + DW EXIT ;12 - IO Control. + +AUXTBL: DW EXIT ;0 - Init. (Not used) + DW EXIT ;1 - Media check (Not used) + DW EXIT ;2 - Get Bios Parameter Block (Not used) + DW CMDERR ;3 - Reserved. (Returns an error) + DW AUX_READ ;4 - Character read. (Destructive) + DW AUX_RDND ;5 - Character read. (Non-destructive) + DW EXIT ;6 - Return status. (Not used) + DW AUX_CLR ;7 - Flush Input buffer. + DW AUX_WRIT ;8 - Character write. + DW AUX_WRIT ;9 - Character write with verify. + DW AUX_WRST ;10 - Character write status. + DW EXIT ;11 - Flush output buffer. (Not used.) + DW EXIT ;12 - IO Control. + +TIMTBL: DW EXIT ;0 - Init. (Not used) + DW EXIT ;1 - Media check (Not used) + DW EXIT ;2 - Get Bios Parameter Block (Not used) + DW CMDERR ;3 - Reserved. (Currently returns an error) + DW TIM_RED ;4 - Character read. (Destructive) + DW BUS_EXIT ;5 - (Not used, returns busy flag.) + DW EXIT ;6 - Return status. (Not used) + DW EXIT ;7 - Flush Input buffer. (Not used) + DW TIM_WRT ;8 - Character write. + DW TIM_WRT ;9 - Character write with verify. + DW EXIT ;10 - Character write status. (Not used) + DW EXIT ;11 - Flush output buffer. (Not used) + DW EXIT ;12 - IO Control. + +PRNTBL: DW EXIT ;0 - (Not used) + DW EXIT ;1 - (Not used) + DW EXIT ;2 - Block (Not used) + DW CMDERR ;3 - Reserved. (currently returns error) + DW EXIT ;4 - (Not used) + DW BUS_EXIT ;5 - (Not used, returns busy flag.) + DW EXIT ;6 - (Not used) + DW EXIT ;7 - (Not used) + DW PRN_WRT ;8 - Character write. + DW PRN_WRT ;9 - Character write with verify. + DW PRN_STA ;10 - Character write status. + DW EXIT ;11 - (Not used.) + DW EXIT ;12 - IO Control. + + PAGE + SUBTTL Strategy and Software Interrupt routines. + +;Define offsets for io data packet + +IODAT STRUC +CMDLEN DB ? ;LENGTH OF THIS COMMAND +UNIT DB ? ;SUB UNIT SPECIFIER +CMD DB ? ;COMMAND CODE +STATUS DW ? ;STATUS + DB 8 DUP (?) +MEDIA DB ? ;MEDIA DESCRIPTOR +TRANS DD ? ;TRANSFER ADDRESS +COUNT DW ? ;COUNT OF BLOCKS OR CHARACTERS +START DW ? ;FIRST BLOCK TO TRANSFER +IODAT ENDS + +PTRSAV DD 0 ;Strategy pointer save. + +; +; Simplistic Strategy routine for non-multi-Tasking system. +; +; Currently just saves I/O packet pointers in PTRSAV for +; later processing by the individual interrupt routines. +; + +STRATP PROC FAR + +STRATEGY: + MOV WORD PTR CS:[PTRSAV],BX + MOV WORD PTR CS:[PTRSAV+2],ES + RET + +STRATP ENDP + +; +; Console interrupt routine for processing I/O packets. +; + +CON_INT: + PUSH SI + MOV SI,OFFSET CONTBL + JMP SHORT ENTRY + +; +; Auxilary interrupt routine for processing I/O packets. +; + +AUX_INT: + PUSH SI + MOV SI,OFFSET AUXTBL + JMP SHORT ENTRY + +; +; Printer interrupt routine for processing I/O packets. +; + +PRN_INT: + PUSH SI + MOV SI,OFFSET PRNTBL + JMP SHORT ENTRY + +; +; Clock interrupt routine for processing I/O packets. +; + +TIM_INT: + PUSH SI + MOV SI,OFFSET TIMTBL + JMP SHORT ENTRY + +; +; Disk interrupt routine for processing I/O packets. +; + +DSK_INT: + PUSH SI + MOV SI,OFFSET DSKTBL + +; +; Common program for handling the simplistic I/O packet +; processing scheme in MSDOS 2.0 +; + +ENTRY: PUSH AX ;Save all nessacary registers. + PUSH CX + PUSH DX + PUSH DI + PUSH BP + PUSH DS + PUSH ES + PUSH BX + + LDS BX,CS:[PTRSAV] ;Retrieve pointer to I/O Packet. + + MOV AL,[BX.UNIT] ;AL = Unit code. + MOV AH,[BX.MEDIA] ;AH = Media descriptor. + MOV CX,[BX.COUNT] ;CX = Contains byte/sector count. + MOV DX,[BX.START] ;DX = Starting Logical sector. + + XCHG DI,AX ;Move Unit & Media into DI temporarily. + MOV AL,[BX.CMD] ;Retrieve Command type. (1 => 11) + XOR AH,AH ;Clear upper half of AX for calculation. + ADD SI,AX ;Compute entry pointer in dispatch table. + ADD SI,AX + CMP AL,11 ;Verify that not more than 11 commands. + JA CMDERR ;Ah, well, error out. + XCHG AX,DI ;Move Unit & Media back where they belong. + LES DI,[BX.TRANS] ;DI contains addess of Transfer address. + ;ES contains segment. + PUSH CS + POP DS ;Data segment same as Code segment. + JMP [SI] ;Perform I/O packet command. + + PAGE + SUBTTL Common error and exit points. + +BUS_EXIT: ;Device busy exit. + MOV AH,00000011B ;Set busy and done bits. + JMP SHORT EXIT1 + +CMDERR: MOV AL,3 ;Set unknown command error #. + +; +; Common error processing routine. +; AL contains actual error code. +; +; Error # 0 = Write Protect violation. +; 1 = Unkown unit. +; 2 = Drive not ready. +; 3 = Unknown command in I/O packet. +; 4 = CRC error. +; 5 = Bad drive request structure length. +; 6 = Seek error. +; 7 = Unknown media discovered. +; 8 = Sector not found. +; 9 = Printer out of paper. +; 10 = Write fault. +; 11 = Read fault. +; 12 = General failure. +; + +ERR_EXIT: + MOV AH,10000001B ;Set error and done bits. + STC ;Set carry bit also. + JMP SHORT EXIT1 ;Quick way out. + +EXITP PROC FAR ;Normal exit for device drivers. + +EXIT: MOV AH,00000001B ;Set done bit for MSDOS. +EXIT1: LDS BX,CS:[PTRSAV] + MOV [BX.STATUS],AX ;Save operation compete and status. + + POP BX ;Restore registers. + POP ES + POP DS + POP BP + POP DI + POP DX + POP CX + POP AX + POP SI + RET ;RESTORE REGS AND RETURN +EXITP ENDP + + PAGE + SUBTTL Main console I/O section. + +MCON DW 0001H +PCON DW 0002H +ACON DW 0003H + +CHAR DB ? ;Small typeahead buffer for now. + +; +; Console keyboard handler. +; + +CISTAT: PUSH CX ;Save CX pair. + MOV AL,[CHAR] + OR AL,AL + JNZ CISTA9 ;Character still in buffer. +CISTA1: MOV BX,ROM_CONSTA + MOV CX,[MCON] + CALL ROM_CALL ;See if character waiting. + TEST AL,AL + JZ CISTA9 + MOV BX,ROM_CONIN + MOV CX,[MCON] + CALL ROM_CALL ;Get character from Rom. + OR AL,AL + JZ CISTA1 ;Got a null character. + MOV [CHAR],AL +CISTA9: POP CX ;Can't lose CX pair. + RET + +; +; Get a character from the buffer queue. +; + +CINP: CALL CISTAT ;Check for character ready in queue. + JZ CINP ;Cycle until one ready. + MOV [CHAR],0 ;We have character in AL, clear type a head. + RET + +; +; Console read non-destructive. +; + +CON_RDND: + CALL CISTAT ;See if character ready. + JZ CON_RDN2 ;No, return busy signal. +CON_RDN1: + LDS BX,CS:[PTRSAV] + MOV [BX.MEDIA],AL + JMP EXIT +CON_RDN2: + JMP BUS_EXIT + +; +; Console destructive read. +; + +CON_READ: + CALL CINP ;Get character. + STOSB ;Save it in users buffer. + LOOP CON_READ ;Loop until CX is exhausted. + JMP EXIT + +; +; Console flush routine. (ctrl-c, ctrl-f, or ctrl-s inspired) +; + +CON_FLSH: + MOV [CHAR],0 ;Clear small type a head buffer. + JMP EXIT + +; +; Console output status routine. +; + +CON_WRST: + JMP EXIT ;Yes, normal exit. + +; +; Console output routine. +; + +CON_WRIT: + MOV SI,DI ;Get destination to source. +CON_WRI1: + LODS BYTE PTR ES:[SI] + PUSH CX +IF ANSI + CALL CONOUT ;Call ansi driver. + ENDIF +IFE ANSI + CALL OUTCHR + ENDIF + POP CX + LOOP CON_WRI1 ;Keep going until user buffer through. + JMP EXIT + +; +; Console character output routine. +; + +OUTCHR: MOV BX,ROM_CONOUT + MOV CX,[MCON] ;Get current console port. + MOV DL,AL + CALL ROM_CALL + RET + + PAGE + +IF ANSI + + SUBTTL ANSI interface section. + +; +;ANSI Info and routines. ANSI driver implemented as a finite state automata +;This ANSI driver translates the ANSI standard escape sequences into the +; Zenith Escape sequences used on the Zenith(Heath) Z(H)-19 terminal. +;This is not a full implementation of ANSI, but rather a minimal implementation +; which implements all of the necessary ANSI functions. +; + +ESC EQU 1BH ;Escape character used in this implementation. +STATE DW ST1 ;Current ANSI character state. +PRMPNT DW PARMS ;Current parameter pointer. +PARMS DB 0,0,0,0,0,0,0 ;Allow for up to eight parameters. +LASTPRM DB 0 ;With this being the eight one. + +CMDTABL DB 'A' ;Cursor up. "esc","[",#,"A" + DW CUU + DB 'B' ;Cursor down. "esc","[",#,"B" + DW CUD + DB 'C' ;Cursor forward. "esc","[",#,"C" + DW CUF + DB 'D' ;Cursor back. "esc","[",#,"D" + DW CUB + DB 'H' ;Direct cursor posit. "esc","[",x,y,"H" + DW CUP + DB 'J' ;Erase. "esc","[",code,"J" + DW ED + DB 'K' ;Erase in line. "esc","[",code,"K" + DW EL + DB 'f' ;Direct cursor posit. "esc","[",x,y,"f" + DW CUP + DB 'm' ;Special video mode. "esc","[",code,"m" + DW SGR + DB 's' ;Save cursor posit. "esc","[","s" + DW PSCP + DB 'u' ;Move cursor to saved. "esc","[","u" + DW PRCP + DB 00 ;End of table. + +; +; ANSI console output driver. +; + +CONOUT: MOV DI,OFFSET STATE ;Retrieve current ansi state. + JMP [DI] ;Jump to it. + +; +; State one (1). +; Looks for an Escape character. +; + +ST1: CMP AL,ESC ;See if this the first character is ESC. + JNZ OUTCHR ;No, treat as regular character output. + MOV WORD PTR [DI],OFFSET ST2 ;Yes, setup state two. + RET + +; +; State two (2). +; Looks for the "[" character. +; + +ST2: CMP AL,'[' ;See if a valide state two. + JNZ OUTCHR ;No, treat as regular charcter + MOV BX,OFFSET PARMS ;Yes, get parameter pointer. + MOV WORD PTR [PRMPNT],BX ;Setup in pointer index. + MOV WORD PTR [BX],0 ;Clear first entry. + MOV WORD PTR [DI],OFFSET ST3;Setup for state three. + RET + +; +; State three (3). +; Entered one or more times for parameter passing. +; + +ST3: CMP AL,';' ;Look for decimal # seperator. + JNZ ST3A ;No check phase A. + INC WORD PTR [PRMPNT] ;Yes, incr. pointer to next param. + MOV AX,OFFSET LASTPRM ;Check for outside parameter list. + CMP [PRMPNT],AX + JBE RETST3 ;Yes, proceed with next parameter. + MOV [PRMPNT],AX ;No, treat as extentsion to old. +RETST3: MOV DI,[PRMPNT] ;Setup for next parameter. + MOV BYTE PTR [DI],0 ;Pre-Initialize it to zero. + RET + +; +; State three A (3A). +; Check for a ascii digit. +; + +ST3A: CMP AL,'0' ;Check for ASCII digit. + JB ST3B ;No, check for seconday command character. + CMP AL,'9' ;Still checking for ASCII digit. + JA ST3B ;No, it must be a secondary. + SUB AL,'0' ;Convert to binary. + MOV DI,[PRMPNT] ;Get the current parameter pointer. + XCHG [DI],AL ;Get existing #. + MOV AH,10 ;Scale by 10. + MUL AH + ADD [DI],AL ;Add to new digit. + RET + +; +; State three B (3B). +; Wasn't a ascii digit, so check for secondary command. +; + +ST3B: MOV [DI],OFFSET ST1 ;Preset STATE to state 1 just in case. + MOV DI,OFFSET PARMS-1 ;Get pointer to start of parameters. + MOV [PRMPNT],DI ;Save it in Parameter pointer. + MOV DI,OFFSET CMDTABL-3 ;Get start of Secondary command table. + +ST3B1: ADD DI,3 ;Update Command table pointer. + CMP BYTE PTR [DI],0 ;Check for end of table. + JNZ ST3B2 ;No, continue processing. + JMP OUTCHR ;Yes, treat as regular character. +ST3B2: CMP AL,[DI] ;Check for valid. command. + JNZ ST3B1 ;No, keep checking. + JMP [DI+1] ;Yes, transfer to that secondary command. + +; +; Get binary parameter from storage and return a one if = 0 +; + +GETONE: CALL GETPARM ;Get parameter form list. + OR AL,AL ;Verify for non-zero. + JNZ GETRET ;Good, then return to caller. + INC AL ;Bad, make it at least a one. +GETRET: CBW ;Sign extend AL. + MOV CX,AX ;Copy of it to CX. + RET + +GETPARM:INC WORD PTR [PRMPNT] ;Increment parameter pointer. +GOTPARM:MOV DI,[PRMPNT] ;Get parameter pointer. + MOV AL,[DI] ;Get parameter value. + RET + +; +; Send escape, character sequence. +; + +OUTESC: MOV AL,ESC ;Send escape character. + CALL OUTCHR + MOV AL,BL ;Send follow character. + JMP OUTCHR + +; +; Cursor Positioning routines. +; + +CUU: MOV BL,'A' ;Cursor up. + JMP SHORT CURPOS +CUD: MOV BL,'B' ;Cursor down. + JMP SHORT CURPOS +CUF: MOV BL,'C' ;Cursor forward. + JMP SHORT CURPOS +CUB: MOV BL,'D' ;Cursor back. + +CURPOS: CALL GETONE ;Get number of positions to move into CX. +MOVCUR: CALL OUTESC ;Send escape, command characters. + LOOP MOVCUR ;Keep moving until done. + RET + +; +; Direct cursor positioning routine. +; + +CUP: CALL GETONE ;Get X position. + MOV DX,AX ;Save in DX. + CALL GETONE ;Get Y position. + MOV BL,'Y' + CALL OUTESC ;Send escape, "Y" sequence. + MOV AL,DL + ADD AL,' '-1 ;Convert binary to Character. + CALL OUTCHR ;Send X posit. + MOV AL,CL + ADD AL,' '-1 ;Convert binary to Character. + JMP OUTCHR ;Send Y posit. + +; +; Erase all/part of screen. +; + +ED: CALL GETPARM ;Get trinary command type. + MOV BL,'b' + DEC AL ;See if erase from begining of screen. + JZ ED1 ;Yes, perform ZDS function. + MOV BL,'E' + DEC AL ;See if erase from end of screen. + JZ ED1 ;Yes, perform ZDS function. + MOV BL,'J' ;Now we assume erase whole screen. +ED1: JMP OUTESC + +; +; Erase all/part of a line. +; + +EL: CALL GETPARM ;Get trinary command type. + MOV BL,'o' + DEC AL ;See if erase from begining of line. + JZ EL1 ;Yes, perform ZDS function. + MOV BL,'l' + DEC AL ;See if erase whole line. + JZ EL1 ;Yes, perform ZDS function. + MOV BL,'K' ;Now we assume erase to end of line. +EL1: JMP OUTESC + +; +; Special video modes. +; + +SGR: CALL GETPARM ;Get trinary command type. + MOV BL,'p' + CMP AL,7 ;See if enter reverse video mode. + JZ SGR2 ;Yes, perform ZDS function. + MOV BL,'q' + OR AL,AL ;See if exit reverse video mode. + JNZ SGR3 ;No, ignore. +SGR2: CALL OUTESC +SGR3: RET + +; +; Save / restore cursor position. +; + +PSCP: MOV BL,'j' ;Set save cursor posit. mode. + JMP OUTESC + +PRCP: MOV BL,'k' ;Restore last cursor save. + JMP OUTESC + + ENDIF + + + PAGE + SUBTTL Printer buffer handler. + +; +; Printer status routine. +; + +PRN_STA: + JMP EXIT + +; +; Printer write routine. +; + +PRN_WRT:MOV SI,DI ;Set source = destination index. + +PRN_WR1:LODS BYTE PTR ES:[SI];Get a data byte. + PUSH CX + MOV CX,[PCON] + MOV BX,ROM_CONOUT + MOV DL,AL + CALL ROM_CALL + POP CX + LOOP PRN_WR1 + RET + + PAGE + SUBTTL Auxilary I/O routines. + +AUXCHAR DB 0 ;Temporary AUX ahead storage. + +; +; Status routine for Auxilary port. +; + +AISTAT: MOV AL,[AUXCHAR] + TEST AL,AL + JNZ AISTA9 ;Character already waiting. + MOV CX,[ACON] + MOV BX,ROM_CONSTA + CALL ROM_CALL + TEST AL,AL + JZ AISTA9 ;Still none waiting. + MOV CX,[ACON] + MOV BX,ROM_CONIN + CALL ROM_CALL +AISTA9: MOV [AUXCHAR],AL + RET + +; +; Auxilary port read. +; + +AIN: CALL AISTAT ;Get status and/or char. + JZ AIN ;Cycle until one is ready. + MOV [AUXCHAR],0 + RET + +; +; Write routine for Auxilary port. +; + +AOUT: MOV CX,[ACON] + MOV BX,ROM_CONOUT + MOV DL,AL + CALL ROM_CALL + RET + +; +; Non-Destructive Auxilary read routine. +; + +AUX_RDND: + CALL AISTAT ;Get status and copy of char. waiting if any. + JZ AUX_RDN2 ;No character waiting, exit. + JMP CON_RDN1 +AUX_RDN2: + JMP BUS_EXIT + +; +; Destructive Auxilary read routine. +; + +AUX_READ: + CALL AIN ;Get data character. + STOSB ;Save it through DI. + LOOP AUX_READ ;Cycle until user buffer full. + JMP EXIT + +; +; Auxilary clear type a head. +; + +AUX_CLR: + MOV [AUXCHAR],0 + JMP EXIT + +; +; Auxilary write port status. +; + +AUX_WRST: + JMP EXIT + +; +; Auxilary write. +; + +AUX_WRIT: + MOV SI,DI +AUX_WRI1: + LODS BYTE PTR ES:[SI] ;Get char. from users buffer. + CALL AOUT ;Send it to device. + LOOP AUX_WRI1 ;Cycle until all done. + JMP EXIT + + PAGE + SUBTTL Date/Time Routines. + +TIM_DAYS: DB 2 DUP (?) ;Number of days since 1-1-80. +TIM_MINS: DB ? ;Minutes. +TIM_HRS: DB ? ;Hours. +TIM_HSEC: DB ? ;Hundreths of a second. +TIM_SECS: DB ? ;Seconds. + +; +; Time write routine. +; + +TIM_WRT: + MOV SI,OFFSET TIM_DAYS + XCHG SI,DI + PUSH ES + MOV AX,DS + POP DS + MOV ES,AX + MOV CX,6 + REP MOVSB + MOV AL,0 + JMP EXIT + +; +; Time read routine. +; + +TIM_RED: + MOV SI,OFFSET TIM_DAYS + MOV CX,6 + REP MOVSB + MOV AL,0 + JMP EXIT + + PAGE + SUBTTL 8089 Monitor structure. + +; +; Structure to reference 8089 and ROM command table. +; + +SIOPB STRUC + DB 4 DUP (?) ;Monitor Use Only +OPCODE DB ? ;I/O operation code. +DRIVE DB ? ;Logical drive spec. +TRACK DW ? ;Logical track number. +HEAD DB ? ;Logical head number. +SECTOR DB ? ;Logical sector to start with. +SCOUNT DB ? ;Number of logical sectors in buffer. +RETCODE DB ? ;Error code after masking. +RETMASK DB ? ;Error mask. +RETRIES DB ? ;Number of retries before error exit. +DMAOFF DW ? ;Buffer offset address. +DMASEG DW ? ;Buffer segment. +SECLENG DW ? ;Sector Length. + DB 6 DUP (?) ;8089 use only. +SIOPB ENDS + +IOPB SIOPB <,00H,0,0,0,0,0,0,000H,0,0,0,0,> + + PAGE + SUBTTL Drive Tables. + + +; +; MSDOS drive initialization tables and other what not. +; +; Drive 0 is: +; Single sided, Single density, 77 track with 26 +; 128 byte sectors per track. One sector for +; boot and header. (256,128 bytes free, old style). +; or +; Single sided, Single density, 77 track with 26 +; 128 byte sectors per track. Four sectors for +; boot and header. (255,744 bytes free). +; or +; Single sided, Double Density, 75 track with 12 +; 512 byte sectors per track. +; (460,800 bytes) +; Two hidden single density tracks. +; + +DBP STRUC + +JMPNEAR DB 3 DUP (?) ;Jmp Near xxxx for boot. +NAMEVER DB 8 DUP (?) ;Name / Version of OS. + +;------- Start of Drive Parameter Block. + +SECSIZE DW ? ;Sector size in bytes. (dpb) +ALLOC DB ? ;Number of sectors per alloc. block. (dpb) +RESSEC DW ? ;Reserved sectors. (dpb) +FATS DB ? ;Number of FAT's. (dpb) +MAXDIR DW ? ;Number of root directory entries. (dpb) +SECTORS DW ? ;Number of sectors per diskette. (dpb) +MEDIAID DB ? ;Media byte ID. (dpb) +FATSEC DW ? ;Number of FAT Sectors. (dpb) + +;------- End of Drive Parameter Block. + +SECTRK DW ? ;Number of Sectors per track. + +DBP ENDS + +LSDRIV1 DBP <,,128,4,1,2,68,2002,0FEH,6,26> + +LSDRIV2 DBP <,,128,4,4,2,68,2002,0FDH,6,26> + +LDDRIV1 DBP <,,512,1,24,2,128,924,0F8H,3,12> + +LDDRIV2 DBP <,,1024,1,16,2,128,616,0F9H,1,8> + +DSK_INIT: + MOV AX,1 + MOV SI,OFFSET INITTAB + JMP GET_BP5 + +INITTAB: + DW LDDRIV2.SECSIZE + +DSTAT EQU 41H ;1793 status port. +DTRACK EQU 43H ;1793 track port. +DSECTOR EQU 45H ;1793 sector port. +DDATA EQU 47H ;1793 data I/O port. + +DDENS EQU 55H ;Density select port. +DDBIT EQU 04H ;Density select bit. +DSELECT EQU 53H ;Drive select port. + +CURDRV DB 0 +DRVTAB DB 0EH,0DH,0BH,07H +TRKPT DB 0,1,2,3 +TRKTAB DB -1,-1,-1,-1 +PREDENS DB 0,0,0,0 + + PAGE + SUBTTL Media check routine + +; +; Media check routine. +; On entry: +; AL = disk unit number. +; AH = media byte +; On exit: +; +; [MEDIA FLAG] = -1 (FF hex) if disk is changed. +; [MEDIA FLAG] = 0 if don't know. +; [MEDIA FLAG] = 1 if not changed. +; +; [MEDIA] = 0FEH for Standard single density. +; [MEDIA] = 0FDH for Altos single density. +; [MEDIA] = 0F4H for Altos double density. +; + +MEDIAS STRUC + DB 13 DUP(?) ;Static request header. +MEDIAS1 DB ? ;Media byte. +MEDIAS2 DB ? ;Media status byte flag. +MEDIAS ENDS + +MEDIAC: + AND AL,03H ;Clear any extraneous bits. + PUSH AX ;Save drive number requested. + MOV AL,0D0H ;Terminate with no interrupt. + CALL DCOM + AND AL,20H ;See if head load bit set. + POP AX + JZ MEDIA2 ;Head not loaded, so see if media changed. + MOV AH,1 ; AH = 1, disk not changed. + JMP SHORT MEDIA1 + +MEDIA1A:MOV [PREDENS],DL ;Save last density used for read. + +MEDIA1: LDS BX,[PTRSAV] ;Udate media section of data block. + MOV [BX.MEDIAS2],AH + MOV AL,0 + JMP EXIT + +MEDIA2: CALL MEDIA4 ;Unload head if selecting new drive. + MOV CX,2 ;Try each density once. + MOV BX,OFFSET DRVTAB + XLAT ;Convert from drive # to select code. + OUT DSELECT,AL ;Select disk + MOV AH,0 ;Assume that we don't know. + MOV DL,[PREDENS] ;Get last density. + AND DL,DDBIT ;Be sure only Density bit set/clr. +MEDIA3: IN AL,DDENS + AND AL,0FBH ;Clear density bit. + OR AL,DL ;Set/clear density bit. + OUT DDENS,AL ;Select density. + MOV AL,0C4H ;READ ADDRESS command + CALL DCOM + AND AL,98H + IN AL,DDATA ;Eat last byte to reset DRQ + JZ MEDIA1A ;Jump if no error in reading address. + MOV AH,0FFH ; AH = -1 (disk changed) if new density works. + XOR DL,DDBIT ;Flip density bit. + LOOP MEDIA3 + MOV AX,2 ;Couldn't read disk at all, AH = 0 for don't + JMP ERR_EXIT ; know if disk changed, AL = error code 2 - + +MEDIA4: MOV AH,AL ;Save disk drive number in AH. + XCHG AL,[CURDRV] ;make new drive current, AL = previous + CMP AL,AH ;Changing drives? + JZ MEDIA5 ;No, return to caller. +; +; If changing drives, unload head so the head load delay one-shot +; will fire again. Do it by seeking to same track with the H bit reset. +; + IN AL,DTRACK ;Get current track number + OUT DDATA,AL ;Make it the track to seek to + MOV AL,10H ;Seek and unload head + CALL DCOM + MOV AL,AH ;Restore current drive number +MEDIA5: RET + +; +; Short routine to send a command to 1793 diskette controller chip and +; wait for 1793 to complete the command. +; + +DCOM: OUT 41H,AL ;Send command to 1793. + MOV CX,10H +DCOM1: LOOP DCOM1 ;Wait a short time for 1793 to digest it. + +DCOM2: IN AL,41H ;Get 1793's status. + AND AL,1 ;See if busy. + JNZ DCOM2 ;Yes, keep checking. + IN AL,41H ;Get 1793's status for return + RET + + PAGE + SUBTTL Build and return Bios Parameter Block for a diskette. + +; +; Build Bios Parameter Blocks. +; +; On entry: ES:DI contains the address of a scratch sector buffer. +; AL = Unit number. +; AH = Current media byte. +; +; On exit: Return a DWORD pointer to the associated BPB +; in the Request packet. +; + +BPBS STRUC + DB 13 DUP(?) ;Static request header. +BPB1 DB ? ;Media byte. +BPB2 DW ? ;DWORD transfer address. + DW ? +BPB3 DW ? ;DWORD pointer to BPB + DW ? +BPBS ENDS + +GET_BPB: + PUSH ES + PUSH DI + MOV [IOPB.DMASEG],ES + MOV [IOPB.DMAOFF],DI + MOV BYTE PTR[IOPB.SECTOR],1 + MOV BYTE PTR[IOPB.SCOUNT],1 + MOV BYTE PTR[IOPB.OPCODE],088H + MOV BYTE PTR[IOPB.RETRIES],1 + MOV BYTE PTR[IOPB.DRIVE],0 + MOV [IOPB.TRACK],0 + MOV BYTE PTR[IOPB.HEAD],1 + MOV BYTE PTR[IOPB.RETMASK],0DCH + MOV [IOPB.SECLENG],128 + MOV BX,ROM_DISKIO + MOV CX,OFFSET IOPB + PUSH CS + POP ES + CALL ROM_CALL ;Read sector zero for information. + PUSH CS + POP DS + POP DI + POP ES + MOV AH,[IOPB.RETCODE] + OR AH,AH + JNZ GET_BP3 ;Disk error, assume old single density. + +GET_BP1:MOV AL,ES:[DI.MEDIAID] ;Get diskettes media ID. + MOV SI,OFFSET LSDRIV2 + CMP AL,[SI.MEDIAID] + JZ GET_BP4 + MOV SI,OFFSET LDDRIV1 + CMP AL,[SI.MEDIAID] + JZ GET_BP4 + MOV SI,OFFSET LDDRIV2 + CMP AL,[SI.MEDIAID] + JZ GET_BP4 + +GET_BP3:MOV SI,OFFSET LSDRIV1 ;No compares, assume old style for now. + +GET_BP4:MOV AL,[SI.MEDIAID] + ADD SI,11 ;Convert to DPB pointer + +GET_BP5:LDS BX,[PTRSAV] ;Update I/O data packet. + MOV [BX.BPB1],AL ;Media byte. + MOV [BX.BPB3],SI ;DPB pointer. + MOV [BX.BPB3+2],CS ;Code segment. + OR AH,AH + JNZ GET_BP6 + MOV AL,0 + JMP EXIT +GET_BP6:MOV AX,7 + JMP ERR_EXIT + + PAGE + + SUBTTL Disk I/O equates. + +; Floppy drives + +; -------------------------- +; Hardware command def. +; -------------------------- +; +; Read command = 88 hex. +; Write command = A8 hex. +; Format command = F0 hex. +; Seek command = 1E hex. +; Recal command = 0A hex. +; Set DD mode = 80 hex. +; +; -------------------------- +; Status bits: +; -------------------------- +; +; Busy = 01 hex. +; (not used) = 02 hex. +; TK0(seek) = 04 hex. +; Lost Data = 04 hex. +; CRC error = 08 hex. +; Seek error = 10 hex. +; Not found = 10 hex. +; Write fault = 20 hex. +; Write protect = 40 hex. +; Not ready = 80 hex. +; +; -------------------------- + +F_READ EQU 088H ;Floppy read command. +F_WRIT EQU 0A8H ;Floppy write command. +F_FMT EQU 0F0H ;Floppy format command. +F_SEEK EQU 01EH ;Floppy seek command. +F_RECAL EQU 00AH ;Floppy recal. command. +F_DD EQU 080H ;Set Drive double density bit. + + PAGE + SUBTTL MSDOS 2.x Disk I/O drivers. + +; +; Disk READ/WRITE functions. +; +; On entry: +; AL = Disk I/O driver number +; AH = Media byte. +; ES = Disk transfer segment. +; DI = Disk transfer offset in ES. +; CX = Number of sectors to transfer +; DX = Logical starting sector. +; +; On exit: +; Normal exit through common exit routine. +; +; Abnormal exit through common error routine. +; + +DSK_RED: + MOV BX,0DC88H ;Set read mode and Error mask. + JMP SHORT DSK_COM +DSK_WRV: +DSK_WRT:MOV BX,0FCA8H ;Set write mode and Error mask. + +DSK_COM:MOV SI,OFFSET LSDRIV1 + CMP AH,[SI.MEDIAID] + JE DSK_CO3 + MOV SI,OFFSET LSDRIV2 + CMP AH,[SI.MEDIAID] + JE DSK_CO3 + MOV SI,OFFSET LDDRIV1 + CMP AH,[SI.MEDIAID] + JE DSK_CO2 + MOV SI,OFFSET LDDRIV2 + CMP AH,[SI.MEDIAID] + JE DSK_CO2 + MOV AL,7 + JMP ERR_EXIT + +DSK_CO2:OR AL,F_DD ;Set double density mode. + +DSK_CO3:MOV [IOPB.DMASEG],ES ;Setup Buffer segment. + MOV [IOPB.DMAOFF],DI ;Setup buffer offset. + MOV DI,[SI.SECSIZE] ;Get sector size. + MOV [IOPB.SECLENG],DI + MOV [IOPB.RETRIES],1 ;Setup number of retries. + MOV [IOPB.RETMASK],BH ;Operation error mask. + MOV [IOPB.OPCODE],BL ;R/W opcode. + MOV [IOPB.DRIVE],AL ;Drive with density select. + MOV [IOPB.HEAD],1 ;Only one head on floppy drive. + MOV BP,CX ;Save number of sectors to R/W +DSK_CO4:PUSH DX ;Save starting sector. + MOV AX,DX + MOV DX,0 ;32 bit divide coming up. + MOV CX,[SI.SECTRK] + DIV CX ;Get track+head and start sector. + INC DL + MOV [IOPB.SECTOR],DL ;Starting sector. + MOV BL,DL ;Save starting sector for later. + MOV [IOPB.TRACK],AX ;Track to read/write. + MOV AX,[SI.SECTRK] ;Now see how many sectors + INC AL ; we can burst read. + SUB AL,BL ;BL is the starting sector. + MOV AH,0 + POP DX ;Retrieve logical sector start. + CMP AX,BP ;See if on last partial track+head. + JG DSK_CO5 ;Yes, on last track+head. + SUB BP,AX ;No, update number of sectors left. + ADD DX,AX ;Update next starting sector. + JMP SHORT DSK_CO6 +DSK_CO5:MOV AX,BP ;Only read enough of sector + MOV BP,0 ;to finish buffer and clear # left. +DSK_CO6:MOV [IOPB.SCOUNT],AL + MOV DI,AX ;Save number sectors for later. + MOV BX,ROM_DISKIO + MOV CX,OFFSET IOPB + PUSH CS + POP ES + CALL ROM_CALL ;Do disk operation. + MOV AL,[IOPB.RETCODE] ;Get error code. + OR AL,AL + JNZ DERROR + MOV AX,DI ;Retrieve number of sectors read. + MOV CX,[SI.SECSIZE] ;Number of bytes per sector. + PUSH DX + MUL CX + POP DX + TEST AL,0FH ;Make sure no strange sizes. + JNZ DSK_CO7 ;Illegal sector size found. + MOV CL,4 + SHR AX,CL ;Convert number of bytes to para. + ADD AX,[IOPB.DMASEG] + MOV [IOPB.DMASEG],AX + OR BP,BP + JNZ DSK_CO4 ;Still more to do. + MOV AL,0 + JMP EXIT ;All done. +DSK_CO7:MOV AL,12 + JMP ERR_EXIT + + PAGE + SUBTTL Disk Error processing. + +; +; Disk error routine. +; + +DERROR: LDS BX,CS:[PTRSAV] + MOV [BX.COUNT],0 + PUSH CS + POP DS + + MOV BL,-1 + MOV AH,AL + MOV BH,14 ;Lenght of table. + MOV SI,OFFSET DERRTAB +DERROR2:INC BL ;Increment to next error code. + LODS BYTE PTR CS:[SI] + CMP AH,AL ;See if error code matches disk status. + JZ DERROR3 ;Got the right error, exit. + DEC BH + JNZ DERROR2 ;Keep checking table. + MOV BL,12 ;Set general type of error. +DERROR3:MOV AL,BL ;Now we've got the code. + RET + +DERRTAB DB 40H ; 0. Write protect error + DB 00H ; 1. Unknown unit. + DB 80H ; 2. Not ready error. + DB 0FFH ; 3. Unknown command. + DB 08H ; 4. CRC error + DB 00H ; 5. Bad drive request. + DB 02H ; 6. Seek error + DB 00H ; 7. Unknown media. + DB 10H ; 8. Sector not found + DB 00H ; 9. (Not used.) + DB 20H ;10. Write fault. + DB 04H ;11. Read fault. + DB 07H ;12. General type of failure. + + PAGE + SUBTTL Common ROM call routine. + +; +; Save all registers except CX, BX and AX. + +ROMRTN DD 0FE000000H ;Main ROM entry point. + +ROM_CALL: + PUSH DI + PUSH SI + PUSH BP + PUSH DX + PUSH ES + CALL CS:DWORD PTR [ROMRTN] + POP ES + POP DX + POP BP + POP SI + POP DI + RET + + PAGE + SUBTTL Initalization code and temporary work areas. + +; +; Overlayed by MSDOS by SYSINIT. +; + +WRKSTK LABEL WORD + DB 100 DUP (?) + + +HWINIT: XOR BP,BP + MOV SS,BP + MOV SP,OFFSET WRKSTK+98 ;Some nice area for stack. + + PUSH CS + POP ES + + MOV BX,ROM_INIT + CALL ROM_CALL + MOV AH,0 + MOV MCON,AX + + MOV AX,SEG SYSINIT + MOV DS,AX + +ASSUME DS:SEG SYSINIT + + MOV AX,CS + ADD AX,BIOSIZS + MOV DS:[CURRENT_DOS_LOCATION],AX + MOV DS:[MEMORY_SIZE],MAX_MEM + MOV AX,CS + MOV WORD PTR DS:[DEVICE_LIST+2],AX + MOV WORD PTR DS:[DEVICE_LIST],OFFSET DEVSTART + MOV AX,CS + ADD AX,((OFFSET WRKSTK - OFFSET INIT)+50) /16 + MOV DS:[FINAL_DOS_LOCATION],AX + JMP SYSINIT + +DOSSPOT LABEL WORD + +CODE ENDS + + END + \ No newline at end of file diff --git a/Disk04/SYSIMES.OBJ b/Disk04/SYSIMES.OBJ new file mode 100644 index 0000000..3172652 Binary files /dev/null and b/Disk04/SYSIMES.OBJ differ diff --git a/Disk04/SYSINIT.OBJ b/Disk04/SYSINIT.OBJ new file mode 100644 index 0000000..3dc2c13 Binary files /dev/null and b/Disk04/SYSINIT.OBJ differ diff --git a/Disk05.img b/Disk05.img new file mode 100644 index 0000000..7394542 Binary files /dev/null and b/Disk05.img differ diff --git a/Disk05/ANSI.DOC b/Disk05/ANSI.DOC new file mode 100644 index 0000000..040d9d2 Binary files /dev/null and b/Disk05/ANSI.DOC differ diff --git a/Disk05/CONFIG.DOC b/Disk05/CONFIG.DOC new file mode 100644 index 0000000..bfb1985 Binary files /dev/null and b/Disk05/CONFIG.DOC differ diff --git a/Disk05/DEVDRIV.DOC b/Disk05/DEVDRIV.DOC new file mode 100644 index 0000000..3c82793 --- /dev/null +++ b/Disk05/DEVDRIV.DOC @@ -0,0 +1,802 @@ + MS-DOS 2.0 Device Drivers + +INTRODUCTION + + In the past, DOS-device driver (BIOS for those who are +familiar with CP/M) communication has been mediated with +registers and a fixed-address jump-table. This approach +has suffered heavily from the following two observations: + + o The old jump-table ideas of the past are fixed in + scope and allow no extensibility. + + o The past device driver interfaces have been written + without regard for the true power of the hardware. + When a multitasking system or interrupt driven + hardware is installed a new BIOS must be written + largely from scratch. + + In MSDOS 2.0, the DOS-device driver interface has changed +from the old jump-table style to one in which the device +drivers are linked together in a list. This allows new +drivers for optional hardware to be installed (and even +written) in the field by other vendors or the user himself. +This flexibility is one of the major new features of MS-DOS +2.0. + + Each driver in the chain defines two entry points; the +strategy routine and the interrupt routine. The 2.0 DOS +does not really make use of two entry points (it simply calls +strategy, then immediately calls interrupt). This dual entry +point scheme is designed to facilitate future multi-tasking +versions of MS-DOS. In multi-tasking environments I/O must +be asynchronous, to accomplish this the strategy routine +will be called to queue (internally) a request and return +quickly. It is then the responsibility of the interrupt +routine to perform the actual I/O at interrupt time by picking +requests off the internal queue (set up by the strategy +routine), and process them. When a request is complete, +it is flagged as "done" by the interrupt routine. The DOS +periodically scans the list of requests looking for ones +flagged as done, and "wakes up" the process waiting for the +completion of the request. + + In order for requests to be queued as above it is no +longer sufficient to pass I/O information in registers, since +many requests may be pending at any one time. Therefore +the new device interface uses data "packets" to pass request +information. A device is called with a pointer to a packet, +this packet is linked into a global chain of all pending +I/O requests maintained by the DOS. The device then links +the packet into its own local chain of requests for this +particular device. The device interrupt routine picks +requests of the local chain for processing. The DOS scans +the global chain looking for completed requests. These +packets are composed of two pieces, a static piece which +has the same format for all requests (called the static +request header), which is followed by information specific +to the request. Thus packets have a variable size and format. + + At this points it should be emphasized that MS-DOS 2.0 +does not implement most of these features, as future versions +will. There is no global or local queue. Only one request +is pending at any one time, and the DOS waits for this current +request to be completed. For 2.0 it is sufficient for the +strategy routine to simply store the address of the packet +at a fixed location, and for the interrupt routine to then +process this packet by doing the request and returning. +Remember: the DOS just calls the strategy routine and then +immediately calls the interrupt routine, it is assumed that +the request is completed when the interrupt routine returns. +This additional functionality is defined at this time so +that people will be aware and thinking about the future. + + +FORMAT OF A DEVICE DRIVER + + A device driver is simply a relocatable memory image +with all of the code in it to implement the device (like +a .COM file, but not ORGed at 100 Hex). In addition it has +a special header at the front of it which identifies it as +a device, defines the strategy and interrupt entry points, +and defines various attributes. It should also be noted +that there are two basic types of devices. + + The first is character devices. These are devices which +are designed to do character I/O in a serial manner like +CON, AUX, and PRN. These devices are named (ie. CON, AUX, +CLOCK, etc.), and users may open channels (FCBs) to do I/O +to them. + + The second class of devices is block devices. These +devices are the "disk drives" on the system, they can do +random I/O in pieces called blocks (usually the physical +sector size) and hence the name. These devices are not +"named" as the character devices are, and therefore cannot +be "opened" directly. Instead they are "mapped" via the +drive letters (A,B,C, etc.). + + Block devices also have units. In other words a single +driver may be responsible for one or more disk drives. For +instance block device driver ALPHA (please note that we cannot +actually refer to block devices by a name!) may be +responsible for drives A,B,C and D, this simply means that +it has four units (0-3) defined and therefore takes up four +drive letters. Which units correspond to which drive letters +is determined by the position of the driver in the chain +of all drivers: if driver ALPHA is the first block driver +in the device chain, and it defines 4 units (0-3), then they +will be A,B,C and D. If BETA is the second block driver +and defines three units (0-2), then they will be E,F and +G and so on. MS-DOS 2.0 is not limited to 16 block device +units, as previous versions were. The theoretical limit +is 63 (2^6 - 1), but it should be noted that after 26 the +drive letters get a little strange (like ] \ and ^). NOTE: +Character devices cannot define multiple units (this because +they have only one name). + + +Here is what that special device header looks like: + + +--------------------------------------+ + | DWORD Pointer to next device | + | (Must be set to -1) | + +--------------------------------------+ + | WORD Attributes | + | Bit 15 = 1 if char device 0 if blk | + | if bit 15 is 1 | + | Bit 0 = 1 if Current sti device | + | Bit 1 = 1 if Current sto output | + | Bit 2 = 1 if Current NUL device | + | Bit 3 = 1 if Current CLOCK dev | + | Bit 4 = 1 if SPECIAL | + | Bit 14 is the IOCTL bit (see below) | + | Bit 13 is the NON IBM FORMAT bit | + +--------------------------------------+ + | WORD Pointer to Device strategy | + | entry point | + +--------------------------------------+ + | WORD Pointer to Device interrupt | + | entry point | + +--------------------------------------+ + | 8-BYTE character device name field | + | Character devices set a device name | + | For block devices the first byte is | + | The number of units | + +--------------------------------------+ + + Note that the device entry points are words. They must +be offsets from the same segment number used to point to +this table. Ie. if XXX.YYY points to the start of this +table, then XXX.strategy and XXX.interrupt are the entry +points. + + A word about the Attribute field. This field is used +most importantly to tell the system whether this device is +a block or character device (bit 15). Most of other bits +are used to give selected character devices certain special +treatment (NOTE: these bits mean nothing on a block device). +Let's say a user has a new device driver which he wants to +be the standard input and output. Besides just installing +the driver he needs to tell SYSINIT (and the DOS) that he +wishes his new driver to override the current sti and sto +(the "CON" device). This is accomplished by setting the +attributes to the desired characteristics, so he would set +Bits 0 and 1 to 1 (note that they are separate!!). Similarly +a new CLOCK device could be installed by setting that +attribute, see the section at the end on the CLOCK device. +NOTE: that although there is a NUL device attribute, the +NUL device cannot be re-assigned. This attribute exists +for the DOS so that it can tell if the NUL device is being +used. + + The NON IBM FORMAT bit applies only to block devices +and effects the operation of the get BPB device call (see +below). + + The other bit of interest is the IOCTL bit which has +meaning on character or block devices. This bit tells the +DOS whether this device can handle control strings (via the +IOCTL system call). + + If a driver cannot process control strings, it should +initially set this bit to 0. This tells the DOS to return +an error if an attempt is made (via IOCTL system call) to +send or receive control strings to this device. A device +which can process control strings should initialize it to +1. For drivers of this type, the DOS will make calls to +the IOCTL INPUT and OUTPUT device functions to send and +receive IOCTL strings (see IOCTL in the SYSTEM-CALLS +document). + + The IOCTL functions allow data to be sent and received +by the device itself for its own use (to set baud rate, stop +bits, form length etc., etc.), instead of passing data over +the device channel as a normal read or write does. The +interpretation of the passed information is up to the device, +but it MUST NOT simply be treated as a normal I/O. + + The SPECIAL bit applies only to character drivers and +more particularly to CON drivers. The new 2.0 interface +is a much more general and consistent interface than the +old 1.25 DOS interface. It allows for a number of additional +features of 2.0. It is also slower than 1.25 if old style +"single byte" system calls are made. To make most efficient +use of the interface all applications should block their +I/O as much as possible. This means make one XENIX style +system call to output X bytes rather than X system calls +to output one byte each. Also putting a device channel in +RAW mode (see IOCTL) provides a means of putting out +characters even FASTER than 1.25. To help alleviate the +CON output speed problem for older programs which use the +1 - 12 system calls to output large amounts of data the +SPECIAL bit has been implemented. If this bit is 1 it means +the device is the CON output device, and has implemented +an interrupt 29 Hex handler, where the 29 Hex handler is +defined as follows: + + Interrupt 29h handlers + + Input: + Character in AL + + Function: + output the character in al to the user + screen. + Output: + None + Registers: + all registers except bx must be preserved. + No registers except for al have a known or + consistent value. + + If a character device implements the SPECIAL bit, it +is the responsibility of the driver to install an address +at the correct location in the interrupt table for interrupt +29 Hex as part of its INIT code. IMPLICATION: There can +be only one device driver with the SPECIAL bit set in the +system. There is no check to insure this state. + +WARNING: THIS FEATURE WILL NOT BE SUPPORTED IN FUTURE VERSIONS + OF THE OPERATING SYSTEM. IMPLICATION: Any application + (not device driver) which uses INT 29H directly will + not work on future versions, YOU HAVE BEEN WARNED. + + In order to "make" a device driver that SYSINIT can +install, a memory image or .EXE (non-IBM only) format file +must be created with the above header at the start. The +link field should be initialized to -1 (SYSINIT fills it +in). The attribute field and entry points must be set +correctly, and if the device is a character device, the name +field must be filled in with the name (if a block device +SYSINIT will fill in the correct unit count). This name +can be any 8 character "legal" file name. In fact SYSINIT +always installs character devices at the start of the device +list, so if you want to install a new CON device all you +have to do is name it "CON". The new one is ahead of the +old one in the list and thus preempts the old one as the +search for devices stops on the first match. Be sure to +set the sti and sto bits on a new CON device! + +NOTE: Since SYSINIT may install the driver anywhere, you + must be very careful about FAR memory references. You + should NOT expect that your driver will go in the same + place every time (The default BIOS drivers are exempted + from this of course). + + +INSTALLATION OF DEVICE DRIVERS + + Unlike past versions MS-DOS 2.0 allows new device drivers +to be installed dynamically at boot time. This is +accomplished by the new SYSINIT module supplied by Microsoft, +which reads and processes the CONFIG.SYS file. This module +is linked together with the OEM default BIOS in a similar +manner to the way FORMAT is built. + + One of the functions defined for each device is INIT. +This routine is called once when the device is installed, +and never again. The only thing returned by the init routine +is a location (DS:DX) which is a pointer to the first free +byte of memory after the device driver, (like a terminate +and stay resident). This pointer method can be used to "throw +away" initialization code that is only needed once, saving +on space. + + Block devices are installed the same way and also return +a first free byte pointer as above, additional information +is also returned: + + o The number of units is returned, this determines + logical device names. If the current maximum logical + device letter is F at the time of the install call, + and the init routine returns 4 as the number of units, + then they will have logical names G, H, I and J. + This mapping is determined by by the position of + the driver in the device list and the number of units + on the device (stored in the first byte of the device + name field). + + o A pointer to a BPB (Bios Parameter Block) pointer + array is also returned. This will be similar to + the INIT table used in previous versions, but will + have more information in it. There is one table + for each unit defined. These blocks will be used + to build a DPB (Drive Parameter Block) for each of + the units. The pointer passed to the DOS from the + driver points to an array of n word pointers to BPBs + where n is the number of units defined. In this + way if all units are the same, all of the pointers + can point to the same BPB, saving space. NOTE: this + array must be protected (below the free pointer set + by the return) since the DPB will be built starting + at the byte pointed to by the free pointer. The + sector size defined must be less than or equal to + the maximum sector size defined at default BIOS init + time. If it isn't the install will fail. One new + piece of DPB info set from this table will be a "media + descriptor byte". This byte means nothing to the + DOS, but is passed to devices so that they know what + form of a DPB the DOS is currently using for a + particular Drive-Unit. + + Block devices may take several approaches; they may be +dumb or smart. A dumb device would define a unit (and +therefore a DPB) for each possible media drive combination. +Unit 0 = drive 0 single side, unit 1 = drive 0 double side, +etc. For this approach media descriptor bytes would mean +nothing. A smart device would allow multiple media per unit, +in this case the BPB table returned at init must define space +large enough to accommodate the largest possible media +supported. Smart drivers will use the "media byte" to pass +around info about what media is currently in a unit. NOTE: +If the DPB is a "hybrid" made to get the right sizes, it +should give an invalid "media byte" back to the DOS. + + The BOOT (default BIOS) drivers are installed pretty +much as above. The preset device list is scanned. If block +drivers are encountered they are installed as above (with +the exception that the break is not moved since the drivers +are already resident in the BIOS). Note that the logical +drive letters are assigned in list order, thus the driver +which is to have logical A must be the first unit of the +first block device in the list. The order of character +devices is also important. There must be at least 4 character +devices defined at boot which must be the first four devices +(of either type), the first will become standard input, +standard output, and standard error output. The second will +become standard auxiliary input and output, the third will +become standard list output, and the forth will become the +date/time (CLOCK) device. Thus the BIOS device list must +look like this: + +->CON->AUX->PRN->CLOCK->any other block or character devices + +THE DRIVER + + A device driver will define the following functions: + + Command Function + Code + + 0 INIT + 1 MEDIA CHECK (Block only, NOP for character) + 2 BUILD BPB " " " " " + 3 IOCTL INPUT (Only called if device has IOCTL) + 4 INPUT (read) + 5 NON-DESTRUCTIVE INPUT NO WAIT (Char devs only) + 6 INPUT STATUS " " " + 7 INPUT FLUSH " " " + 8 OUTPUT (write) + 9 OUTPUT (Write) with verify + 10 OUTPUT STATUS " " " + 11 OUTPUT FLUSH " " " + 12 IOCTL OUTPUT (Only called if device has IOCTL) + + As mentioned before, the first entry point is the strategy +routine which is called with a pointer to a data block. This +call does not perform the request, all it does is queue it +(save the data block pointer). The second interrupt entry +point is called immediately after the strategy call. The +"interrupt" routine is called with no parameters, its primary +function is to perform the operation based on the queued +data block and set up any returns. + + The "BUILD BPB" and "MEDIA CHECK" are the interesting +new ones, these are explained by examining the sequence of +events in the DOS which occurs when a drive access call (other +than read or write) is made: + + I. Turn drive letter into DPB pointer by looking + for DPB with correct driver-unit number. + + II. Call device driver and request media check for + Drive-Unit. DOS passes its current Media + descriptor byte (from DPB). Call returns: + + Media Not Changed + Media Changed + Not Sure + Error + + Error - If an error occurs the error code should + be set accordingly. + + Media Not changed - Current DPB and media byte + are OK, done. + + Media Changed - Current DPB and media are wrong, + invalidate any buffers for this unit, and + goto III. + + Not Sure - If there are dirty buffers for this + unit, assume DPB and media byte are OK and + done. If nothing dirty, assume media changed, + invalidate any buffers for unit, and goto + III. + + NOTE: If a hybrid DPB was built at init and + an invalid Media byte was set, the driver + should return media changed when this invalid + media byte is encountered. + + III. Call device driver to build BPB with media byte + and buffer. + + What the driver must do at step III is determine the +correct media that is currently in the unit, and return a +pointer to a BPB table (same as for the install call). This +table will be used as at init to build a correct DPB for +the unit If the determined media descriptor byte in the table +turns out to be the same as the one passed in, then the DOS +will not build a new table, but rather just use the old one. +Therefore in this case the driver doesn't have to correctly +fill in the other entries if desired. + + The build BPB call also gets a pointer to a one sector +buffer. What this buffer contains is determined by the NON +IBM FORMAT bit in the attribute field. If the bit is zero +(device is IBM format compatible) then the buffer contains +the first sector of the first FAT, in particular the FAT +ID byte is the first byte of this buffer. NOTE: It must +be true that the BPB is the same, as far as location of the +FAT is concerned, for all possible media. This is because +this first FAT sector must be read BEFORE the actual BPB +is returned. If the NON IBM FORMAT bit is set then the +pointer points to one sector of scratch space which may be +used for anything. + +CALL FORMAT + + When the DOS calls a device driver to perform a finction, +it passes a structure (Drive Request Structure) in ES:BX +to perform operations and does a long call to the driver's +strategy entry point. This structure is a fixed length header +(Static Request Header) followed by data pertinent to the +operation being performed. NOTE: It is the drivers +responsibility to preserve machine state. + +STATIC REQUEST HEADER -> + +-----------------------------+ + | BYTE length of record | + | Length in bytes of this | + | Drive Request Structure | + +-----------------------------+ + | BYTE unit code | + | The subunit the operation | + | is for (minor device) | + | (no meaning on character | + | devices) | + +-----------------------------+ + | BYTE command code | + +-----------------------------+ + | WORD Status | + +-----------------------------+ + | 8 bytes reserved here for | + | two DWORD links. One will | + | be a link for the DOS queue | + | The other for the device | + | queue | + +-----------------------------+ + +STATUS WORD + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ + | E | | B | D | | + | R | RESERVED | U | O | ERROR CODE (bit 15 on)| + | R | | I | N | | + +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ + + The status word is zero on entry and is set by the driver +interrupt routine on return. + + Bit 8 is the done bit, it means the operation is complete. +For the moment the Driver just sets it to one when it exits, +in the future this will be set by the interrupt routine to +tell the DOS the operation is complete. + + Bit 15 is the error bit, if it is set then the low 8 +bits indicate the error: + + 0 Write Protect violation + (NEW) 1 Unknown Unit + 2 Drive not ready + (NEW) 3 Unknown command + 4 CRC error + (NEW) 5 Bad Drive Request Structure length + 6 Seek error + (NEW) 7 Unknown media + 8 Sector not found + (NEW) 9 Printer out of paper + A Write Fault + (NEW) B Read Fault + C General Failure + +Bit 9 is the busy bit which is set only by status calls (see +STATUS CALL below). + + + Here is the data block format for each function: + +READ or WRITE - ES:BX (Including IOCTL) -> + +------------------------------------+ + | 13-BYTE Static Request Header | + +------------------------------------+ + | BYTE Media descriptor from DPB | + +------------------------------------+ + | DWORD transfer address | + +------------------------------------+ + | WORD byte/sector Count | + ---+------------------------------------+--- + | WORD starting sector number | + | (ignored on Char Devs) | + +------------------------------------+ + + In addition to setting the status word, the driver must +set the Sector count to the actual number of sectors (or +bytes) transferred. NOTE: No error check is performed on +an IOCTL I/O call, driver MUST correctly set the return sector +(byte) count to the actual number of bytes transferred, +however. + +NOTE: THE FOLLOWING APPLIES TO BLOCK DEVICE DRIVERS. + + Under certain circumstances the BIOS may be asked to +do a write operation of 64K bytes which seems to be a "wrap +around" of the transfer address in the BIOS I/O packet. This +arises due to an optimization added to the write code in +MS-DOS. It will only manifest on user WRITEs which are within +a sector size of 64K bytes on files which are "growing" past +the current EOF. IT IS ALLOWABLE FOR THE BIOS TO IGNORE +THE BALANCE OF THE WRITE WHICH "WRAPS AROUND" IF IT SO +CHOOSES. For instance a WRITE of 10000H bytes worth of +sectors with a transfer address of XXX:1 could ignore the +last two bytes (remember that a user program can never request +an I/O of more than FFFFH bytes and cannot wrap around (even +to 0) in his transfer segment, so in this case the last two +bytes can be ignored). + + +NON DESRUCTIVE READ NO WAIT - ES:BX -> + +------------------------------------+ + | 13-BYTE Static Request Header | + +------------------------------------+ + | BYTE read from device | + +------------------------------------+ + + This call is analogous to the console input status call +on MS-DOS 1.25. If the character device returns Busy bit += 0 (characters in buffer), then the next character that +would be read is returned. This character is NOT removed +from the input buffer (hence the term Non Destructive Read). +In essence this call allows the DOS to look ahead one input +character. + + +MEDIA CHECK - ES:BX -> + +------------------------------------+ + | 13-BYTE Static Request Header | + +------------------------------------+ + | BYTE Media Descriptor from DPB | + +------------------------------------+ + | BYTE returned | + +------------------------------------+ + + In addition to setting status word, driver must set the +return byte. + + Return Byte : + -1 Media has been changed + 0 Don't know if media has been changed + 1 Media has not been changed + + If the driver can return -1 or 1 (by having a door-lock +or other interlock mechanism) the performance of MSDOS 2.0 +is enhanced as the DOS need not reread the FAT for each +directory access. + + +BUILD BPB - ES:BX -> + +------------------------------------+ + | 13-BYTE Static Request Header | + +------------------------------------+ + | BYTE Media Descriptor from DPB | + +------------------------------------+ + | DWORD Transfer Address | + | (points to one sectors worth of | + | scratch space or first sector | + | of FAT depending on the value | + | of the NON IBM FORMAT bit) | + +------------------------------------+ + | DWORD Pointer to BPB | + +------------------------------------+ + + If the NON IBM FORMAT bit of the device is set, then +the DWORD Transfer Address points to a one sector buffer +which can be used for any purpose. If the NON IBM FORMAT +bit is 0, then this buffer contains the first sector of the +FAT; in this case the driver must not alter this buffer (this +mode is useful if all that is desired is to read the FAT +ID byte). + + If IBM compatible format is used (NON IBM FORMAT BIT += 0), then it must be true that the first sector of the first +FAT is located at the same sector on all possible media. +This is because the FAT sector will be read BEFORE the media +is actually determined. + + In addition to setting status word, driver must set the +Pointer to the BPB on return. + + + In order to allow for many different OEMs to read each +other's disks, the following standard is suggested: The +information relating to the BPB for a particular piece of +media is kept in the boot sector for the media. In +particular, the format of the boot sector is: + + +------------------------------------+ + | 3 BYTE near JUMP to boot code | + +------------------------------------+ + | 8 BYTES OEM name and version | + ---+------------------------------------+--- + B | WORD bytes per sector | + P +------------------------------------+ + B | BYTE sectors per allocation unit | + +------------------------------------+ + | | WORD reserved sectors | + V +------------------------------------+ + | BYTE number of FATs | + +------------------------------------+ + | WORD number of root dir entries | + +------------------------------------+ + | WORD number of sectors in logical | + ^ | image | + | +------------------------------------+ + B | BYTE media descriptor | + P +------------------------------------+ + B | WORD number of FAT sectors | + ---+------------------------------------+--- + | WORD sectors per track | + +------------------------------------+ + | WORD number of heads | + +------------------------------------+ + | WORD number of hidden sectors | + +------------------------------------+ + + The three words at the end are optional, the DOS doesn't +care about them (since they are not part of the BPB). They +are intended to help the BIOS understand the media. Sectors +per track may be redundant (could be figured out from total +size of the disk). Number of heads is useful for supporting +different multi-head drives which have the same storage +capacity, but a different number of surfaces. Number of +hidden sectors is useful for supporting drive partitioning +schemes. + + + Currently, the media descriptor byte has been defined +for a small range of media: + + 5 1/4" diskettes: + + Flag bits: + 01h - on -> 2 double sided + + All other bits must be on. + + 8" disks: + FEh - IBM 3740 format, singled-sided, single-density, + 128 bytes per sector, soft sectored, 4 sectors + per allocation unit, 1 reserved sector, 2 FATs, + 68 directory entries, 77*26 sectors + + FDh - 8" IBM 3740 format, singled-sided, + single-density, 128 bytes per sector, soft + sectored, 4 sectors per allocation unit, 4 + reserved sectors, 2 FATs, 68 directory entries, + 77*26 sectors + + FEh - 8" Double-sided, double-density, 1024 bytes + per sector, soft sectored, 1 sector per allocation + unit, 1 reserved sector, 2 FATs, 192 directory + entries, 77*8*2 sectors + + +STATUS Calls - ES:BX -> + +------------------------------------+ + | 13-BYTE Static Request Header | + +------------------------------------+ + + All driver must do is set status word accordingly and +set the busy bit as follows: + + o For output on character devices: If it is 1 on + return, a write request (if made) would wait for + completion of a current request. If it is 0, there + is no current request and a write request (if made) + would start immediately. + + o For input on character devices with a buffer a return + of 1 means, a read request (if made) would go to + the physical device. If it is 0 on return, then + there are characters in the devices buffer and a + read would return quickly, it also indicates that + the user has typed something. The DOS assumes all + character devices have an input type ahead buffer. + Devices which don't have them should always return + busy = 0 so that the DOS won't hang waiting for + something to get into a buffer which doesn't exist. + + +FLUSH Calls - ES:BX -> + +------------------------------------+ + | 13-BYTE Static Request Header | + +------------------------------------+ + + This call tells the driver to flush (terminate) all +pending requests that it has knowledge of. Its primary use +is to flush the input queue on character devices. + + +INIT - ES:BX -> + +------------------------------------+ + | 13-BYTE Static Request Header | + +------------------------------------+ + | BYTE # of units | + +------------------------------------+ + | DWORD Break Address | + ---+------------------------------------+--- + | DWORD Pointer to BPB array | + | (not set by Character devices) | + +------------------------------------+ + + The number of units, break address, and BPB pointer are +set by the driver. + + +FORMAT OF BPB (Bios Parameter Block) - + + +------------------------------------+ + | WORD Sector size in Bytes | + | Must be at least 32 | + +------------------------------------+ + | BYTE Sectors/Allocation unit | + | Must be a power of 2 | + +------------------------------------+ + | WORD Number of reserved sectors | + | May be zero | + +------------------------------------+ + | BYTE Number of FATS | + +------------------------------------+ + | WORD Number of directory entries | + +------------------------------------+ + | WORD Total number of sectors | + +------------------------------------+ + | BYTE Media descriptor | + +------------------------------------+ + | WORD Number of sectors occupied by | + | FAT | + +------------------------------------+ + + +THE CLOCK DEVICE + + One of the most popular add on boards seems to be "Real +Time CLOCK Boards". To allow these boards to be integrated +into the system for TIME and DATE, there is a special device +(determined by the attribute word) which is the CLOCK device. +In all respects this device defines and performs functions +like any other character device (most functions will be "set +done bit, reset error bit, return). When a read or write +to this device occurs, exactly 6 bytes are transferred. This +I/O can be thought of as transferring 3 words which correspond +exactly to the values of AX, CX and DX which were used in +the old 1.25 DOS date and time routines. Thus the first +two bytes are a word which is the count of days since 1-1-80. +The third byte is minutes, the fourth hours, the fifth +hundredths of seconds, and the sixth seconds. Reading the +CLOCK device gets the date and time, writing to it sets the +date and time. + \ No newline at end of file diff --git a/Disk05/INCOMP.DOC b/Disk05/INCOMP.DOC new file mode 100644 index 0000000..6c187b6 Binary files /dev/null and b/Disk05/INCOMP.DOC differ diff --git a/Disk05/INT24.DOC b/Disk05/INT24.DOC new file mode 100644 index 0000000..d38d6fa Binary files /dev/null and b/Disk05/INT24.DOC differ diff --git a/Disk05/PROFILE.DOC b/Disk05/PROFILE.DOC new file mode 100644 index 0000000..2d50631 Binary files /dev/null and b/Disk05/PROFILE.DOC differ diff --git a/Disk05/QUICK.DOC b/Disk05/QUICK.DOC new file mode 100644 index 0000000..d443b8e Binary files /dev/null and b/Disk05/QUICK.DOC differ diff --git a/Disk05/SYSCALL.DOC b/Disk05/SYSCALL.DOC new file mode 100644 index 0000000..26d4729 --- /dev/null +++ b/Disk05/SYSCALL.DOC @@ -0,0 +1,1657 @@ + + + + + + + + + + + + + + + + + + + MS-DOS 2.0 + + System Calls Reference + + + + + + + + + + + + ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +| | +| 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 | +| | ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + + + + + + + + + + + + + + + + + + Section 1 + + Extensions to existing call structure + + + Name: * Alloc - allocate memory + + Assembler usage: + MOV BX,size + MOV AH,Alloc + INT 21h + ; AX:0 is pointer to allocated memory + ; if alloc fails, BX is the largest block available + + Description: + Alloc returns a pointer to a free block of memory + that has the requested size in paragraphs. + + Error return: + AX = error_not_enough_memory + The largest available free block is smaller + than that requested or there is no free block. + = error_arena_trashed + The internal consistency of the memory arena + has been destroyed. This is due to a user + program changing memory that does not belong + to it. + + + Name: * CharOper - change incompatible configuration + parameters + + Assembler usage: + MOV AH, CharOper + MOV AL, func + MOV DL, data + INT 21h + ; on read functions, data is returned in DL + + Description: + CharOper allows a program to change system + parameters to allow for switch indicators and whether + devices are available at every level of the directory + tree. + + A function code is passed in AL: + + AL Function + -- -------- + 0 DL, on return, will contain the DOS switch + character. On most systems this will default to + '-'. + 1 Set the switch character to the character in DL. + 2 Read the device availability byte into DL. If + this byte is 0, then devices must be accessed in + file I/O calls by /dev/device. If this byte is + non-zero, then the devices are available at every + node of the directory tree (i.e. CON is the + console device not the file CON). This byte is + generally 0. + 3 Set the device availability byte to the value in + DL. + + Error returns: + AL = FF + The function code specified in AL is not in + the range 0:3 + + + Name: * CurrentDir - return text of current directory + + Assembler usage: + MOV AH,CurrentDir + LDS SI,area + MOV DL,drive + INT 21h + ; DS:SI is a pointer to 64 byte area that contains + ; drive current directory. + + Description: + CurrentDir returns the current directory for a + particular drive. The directory is root-relative and + does not contain the drive specifier. The drive code + passed in DL is 0=default, 1=A, 2=B, etc. + + Error returns: + AX = error_invalid_drive + The drive specified in DL was invalid. + + + Name: * Dealloc - free allocated memory + + Assembler usage: + MOV ES,block + MOV AH,dealloc + INT 21h + + Description: + Dealloc returns a piece of memory to the system + pool that was allocated by alloc. + + Error return: + AX = error_invalid_block + The block passed in ES is not one allocated + via Alloc. + = error_arena_trashed + The internal consistency of the memory arena + has been destroyed. This is due to a user + program changing memory that does not belong + to it. + + + Name: * FileTimes - get/set the write times of a + handle + + Assembler usage: + MOV AH, FileTimes + MOV AL, func + MOV BX, handle + ; if AL = 1 then then next two are mandatory + MOV CX, time + MOV DX, date + INT 21h + ; if AL = 0 then CX/DX has the last write time/date + ; for the handle. + + Description: + FileTimes returns or sets the last-write time for + a handle. These times are not recorded until the file + is closed. + + A function code is passed in AL: + + AL Function + -- -------- + 0 Return the time/date of the handle in CX/DX + 1 Set the time/date of the handle to CX/DX + + Error returns: + AX = error_invalid_function + The function passed in AL was not in the range + 0:1. + = error_invalid_handle + The handle passed in BX was not currently + open. + + + Name: * FindFirst - find matching file + + Assembler usage: + MOV AH, FindFirst + LDS DX, pathname + MOV CX, attr + INT 21h + ; DMA address has datablock + + Description: + FindFirst takes a pathname with wildcards in the + last component (passed in DS:DX), a set of attributes + (passed in CX) and attempts to find all files that + match the pathname and have a subset of the required + attributes. A datablock at the current DMA is written + that contains information in the following form: + + find_buf STRUC ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +| C A V E A T P R O G R A M M E R | +| | + find_buf_sattr DB ? ; attribute of search + find_buf_drive DB ? ; drive of search + find_buf_name DB 11 DUP (?); search name + find_buf_LastEnt DW ? ; LastEnt + find_buf_ThisDPB DD ? ; This DPB + find_buf_DirStart DW ? ; DirStart +| | +| 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 + + To obtain the subsequent matches of the pathname, + see the description of FindNext + + Error Returns: + AX = error_file_not_found + The path specified in DS:DX was an invalid + path. + = error_no_more_files + There were no files matching this + specification. + + + Name: * FindNext - step through a directory matching + files + + Assembler usage: + ; DMA points at area returned by find_first + MOV AH, findnext + INT 21h + ; next entry is at dma + + Description: + FindNext finds the next matching entry in a + directory. The current DMA address must point at a + block returned by FindFirst (see FindFirst). + + Error Returns: + AX = error_no_more_files + There are no more files matching this pattern. + + + Name: * GetDMA - get current DMA transfer address + + Assembler usage: + MOV AH,GetDMA + INT 21h + ; ES:BX has current DMA transfer address + + Description: + Return DMA transfer address. + + Error returns: + None. + ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +| C A V E A T P R O G R A M M E R | +| | + + Name: * GetDSKPT(DL) - get pointer to drive parameter + block + + Assembler usage: + MOV AH,GetDSKPT + 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,GetDSKPTDL + 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 | ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + + Name: * GetFreespace - get Disk free space + + Assembler usage: + MOV AH,GetFreespace + MOV DL,Drive ;0 = default, A = 1 + INT 21h + ; BX = Number of free allocation units on drive + ; DX = Total number of allocation units on drive + ; CX = Bytes per sector + ; AX = Sectors per allocation unit + + Description: + Return Free space on disk along with additional + information about the disk. + + Error returns: + AX = FFFF + The drive number given in DL was invalid. + + NOTE: This call returns the same information in the same + registers (except for the FAT pointer) as the get FAT + pointer calls did in previous versions of the DOS. + + + Name: * GetInDOSF - get DOS critical-section flag + + Assembler usage: + MOV AH,GetInDOSF + INT 21h + ; ES:BX has location of the flag + MOV CritSEG, ES + MOV CritOFF, BX + ... + IntVec: + MOV AX, DWORD PTR Crit + CMP AX,0 + JZ DoFunc + IRET + DoFunc: ... + + Description: + Return location of indos flag. On return ES:BX is + the address of a byte memory cell inside the DOS. If + used in an interrupt service routine, it indicates + whether or not the DOS was interrupted in a critical + section. If the cell was zero, then the DOS was not + in a critical section and thus can be called by the + interrupt routine. If the cell was non-zero, the DOS + should be considered to be in an uninterruptable state + and for reliability, no DOS calls should be given. + + Error returns: + None. + + + Name: * GetVector - get interrupt vector + + Assembler usage: + MOV AH,GetVector + MOV AL,interrupt + INT 21h + ; ES:BX now has long pointer to interrupt routine + + Description: + Return interrupt vector associated with an + interrupt. + + Error returns: + None. + + + Name: * GetVerifyFlag - return current setting of the + verify after write flag. + + Assembler usage: + MOV AH,GetVerifyFlag + INT 21h + ; AL is the current verify flag value + + Description: + The current value of the verify flag is returned + in AL. + + Error returns: + None. + + + Name: * GetVersion - get DOS version number + + Assembler usage: + MOV AH,GetVersion + INT 21h + ; AL is the major version number + ; AH is the minor version number + ; BH is the OEM number + ; BL:CX is the (24 bit) user number + + Description: + Return MS-DOS version number. On return AL.AH + will be the two part version designation, ie. for + MS-DOS 1.28 AL would be 1 and AH would be 28. For pre + 1.28 DOS AL = 0. Note that version 1.1 is the same as + 1.10, not the same as 1.01. + + Error returns: + None. + + + Name: * International - return country dependent + information + + Assembler usage: + LDS DX, blk + MOV AH, International + MOV AL, func + INT 21h + + Description: + This call returns in the block of memory pointed + to by DS:DX, the following information pertinent to + international applications: + + +---------------------------+ + | WORD Date/time format | + +---------------------------+ + | BYTE ASCIZ string | + | currency symbol | + +---------------------------+ + | BYTE ASCIZ string | + | thousands separator | + +---------------------------+ + | BYTE ASCIZ string decimal | + | separator | + +---------------------------+ + + The date/time format has the following values and + meanings: + + 0 - USA standard h:m:s m/d/y + 1 - Europe standard h:m:s d/m/y + 2 - Japan standard y/m/d h:m:s + + The value passed in AL is either 0 (for current + country) or a country code (to be defined later. + Currently the country code must be zero). + + Error returns: + AX = error_invalid_function + The function passed in AL was not 0 + (currently). + + + Name: * KeepProcess - terminate process and remain + resident + + Assembler usage: + MOV AL, exitcode + MOV DX, parasize + MOV AH, KeepProcess + INT 21h + + Description: + This call terminates the current process and + attempts to set the initial allocation block to a + specific size in paragraphs. It will not free up any + other allocation blocks belonging to that process. + The exit code passed in AX is retrievable by the + parent via Wait. + + Error Returns: + None. + + + Name: * Rename - move a directory entry + + Assembler usage: + LDS DX, source + LES DI, dest + MOV AH, Rename + INT 21h + + Description: + Rename will attempt to rename a file into another + path. The paths must be on the same device. + + Error returns: + AX = error_file_not_found + The file name specifed by DS:DX was not found. + = error_not_same_device + The source and destination are on different + drives. + = error_access_denied + The path specified in DS:DX was a directory or + the file specified by ES:DI exists or the + destination directory entry could not be + created. + + + Name: * SetBlock - modify allocated blocks + + Assembler usage: + MOV ES,block + MOV BX,newsize + MOV AH,setblock + INT 21h + ; if setblock fails for growing, BX will have the + ; maximum size possible + + Description: + Setblock will attempt to grow/shrink an allocated + block of memory. + + Error return: + AX = error_invalid_block + The block passed in ES is not one allocated + via Alloc. + = error_arena_trashed + The internal consistency of the memory arena + has been destroyed. This is due to a user + program changing memory that does not belong + to it. + = error_not_enough_memory + There was not enough free memory after the + specified block to satisfy the grow request. + + + Name: * SetCtrlCTrapping - turn on/off broad ^C + checking + + Assembler usage: + MOV DL,val + MOV AH,SetCtrlCTrapping + MOV AL,func + INT 21h + ; If AL was 0, then DL has the current value of the + ; ^C check + + Description: + MSDOS ordinarily checks for a ^C on the + controlling device only when doing a function 1-12 + operation to that device. SetCtrlCTrapping allows the + user to expand this checking to include any system + call. For example, with the ^C trapping off, all disk + I/O will proceed without interruption while with ^C + trapping on, the ^C interrupt is given at the system + call that initiates the disk operation. + + Error return: + AL = FF + The function passed in AL was not in the range + 0:1. + ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +| C A V E A T P R O G R A M M E R | +| | + + Name: * Set_OEM_Handler - set handler for OEM + specific INT 21H calls. + + Assembler usage: + LDS DX,handler_address + MOV AH,Set_OEM_Handler + INT 21H + + Description: + Set handler address for 0F9H-0FFH INT 21H system + calls to DS:DX. To return the 0F9H-0FFH calls to + the uninitialized state, give DS=DX=-1. + + Error returns: + None. + + Handler entry: + All registers as user set them when INT 21H + issued (including SS:SP). INT 21 return is on + stack, so the correct method for the OEM handler + to return to the user is to give an IRET. The + OEM handler is free to make any INT 21H system + call (including the 0F9H- 0FFH group if the OEM + handler is re-entrant). + + + The AH INT 21H function codes 0F8H through 0FFH are + reserved for OEM extensions to the INT 21H calling + convention. These calls have two states, initialized + and uninitialized. There will be one handler for all 7 + (0F9-0FFH) functions. When the DOS is first + initialized, these calls are uninitialized. The AH=0F8H + call is the call which will set the handler address for + the 0F9-0FFH calls. If the 0F9-0FFH calls are + uninitialized, an attempt to call them results in the + normal invalid system call number return. + OEMs should NOT document the 0F8 call. +| | +| C A V E A T P R O G R A M M E R | ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + + + + + + + + + + + + + + + + + + Section 2 + + XENIX-compatible system calls + + + + Previous to version 2.0, MSDOS had a simple single + directory structure that sufficed for small (160k to 320K) + diskettes. As the need for hard disk support grows, and + as MSDOS 2.0 will support a wide variety of hard disks, + the need for better disk organization also grows. Merely + expanding the directory is not an effective solution; + doing a 'DIR' on a directory with 1000 files is not a + user-friendly characteristic. + + People, by nature, think in hierarchical terms: + organization charts and family trees, for example. It + would be nice to allow users to organize their files on + disk in a similar manner. Consider the following: + + In a particular business, both sales and accounting + share a computer with a large disk and the individual + employees use it for preparation of reports and + maintaining accounting information. One would naturally + view the organization of files on the disk in this + fashion: + + +-disk-+ + / \ + / \ + / \ + sales accounting + / | | \ + / | | \ + / | | \ + John Mary Steve Sue + / | (A) | | | \ + / | | | | \ + / | | | | \ + report accts. report accts. report report + receiv. receiv + + In MSDOS 2.0 the user can arrange his files in such a + manner that files that are not part of his current task do + not interfere with that task. Pre-2.0 versions of MSDOS + has a single directory that contains files. MSDOS extends + this concept to allow a directory to contain both files + and directories and to introduce the notion of the + 'current' directory. + + To specify a filename, the user could use one of two + methods, either specify a path from the root node to the + file, or specify a path from the current node to the file. + A path is a series of directory names separated by '/' and + ending with a filename. A path that starts at the root + begins with a '/'. + + There is a special directory entry in each directory, + denoted by '..' that is the parent of the directory. The + root directory's parent is itself (who created God?). + + Using a directory structure like the hierarchy above, + and assuming that the current directory is at point (D), + to reference the report under John, the following are all + equivalent: + + report + /sales/John/report + ../John/report + + To refer to the report under Mary, the following are + all equivalent: + + ../Mary/report + /sales/Mary/report + + To refer to the report under Sue, the following are + all equivalent. + + ../../accounting/Sue/report + /accounting/Sue/report + + There is no restriction in MSDOS 2.0 on the depth of a + tree (the length of the longest path from root to leaf) + except in the number of allocation units available. The + root directory will have a fixed number of entries, 64 for + the single sided diskettes to XXX for a large hard disk. + For non-root directories, there is no limit to the number + of files per directory excepting in the number of + allocation units available. + + Old (pre-2.0) disks will appear to MSDOS 2.0 as having + only a root directory with files in it and no + subdirectories whatever. + + Implementation of the tree-structure is simple. The + root directory is the pre-2.0 directory. Subdirectories + of the root have a special attribute set indicating that + they are directories. The subdirectories themselves are + files, linked through the FAT as usual. Their contents + are identical in character to the contents of the root + directory. + + Pre-2.0 programs that use system calls not described + below will not be able to make use of files in other + directories. They will only be able to access files in + the current directory. This is no great loss of + functionality as users will aggregate their files into + sub-directories on basis of functionality; the files that + are being used will be found in the current directory. + Those that are not necessary for the current task will be + placed in other directories. Out of sight, out of mind. + + There are also new attributes in 2.0. These and the + old attributes apply to the tree structured directories in + the following manner: + + Attribute Meaning/Function Meaning/Function + for files for directories + + volume_id Present at the root. Meaningless. + Only one file may have + this set. + + directory Meaningless. Indicates that the + directory entry is a + directory. Cannot be + changed with ChMod. + + read_only Old fcb-create, new Meaningless. + Creat, new open (for + write or read/write) + will fail. + + archive Set when file is Meaningless. + written. Set/reset via + ChMod. + + hidden/ Prevents file from Prevents directory + system being found in search entry from being + first/search next. found. ChDir to + New open will fail. directory will still + work. + + + Name: * ChDir - Change the current directory + + Assembler usage: + LDS DX, name + MOV AH, ChDir + INT 21h + + Description: + ChDir is given the ASCIZ name of the directory + which is to become the current directory. If any + member of the specified pathname does not exist, then + the current directory is unchanged. Otherwise, the + current directory is set to the string. + + Error returns: + AX = error_path_not_found + The path specified in DS:DX either indicated a + file or the path was invalid. + + + Name: * ChMod - change write protection + + Assembler usage: + LDS DX, name + MOV CX, attribute + MOV AL, func + MOV AH, ChMod + INT 21h + + Description: + Given an ASCIZ name, ChMod will set/get the + attributes of the file to those given in CX. + + A function code is passed in AL: + + AL Function + -- -------- + 0 Return the attributes of the file in CX + 1 Set the attributes of the file to those in CX + + Error returns: + AX = error_path_not_found + The path specified was invalid. + = error_access_denied + The attributes specified in CX contained one + that could not be changed (directory, volume + ID). + = error_invalid_function + The function passed in AL was not in the range + 0:1. + + + Name: * Close - close a file handle + + Assembler usage: + MOV BX, handle + MOV AH, Close + INT 21h + + Description: + In BX is passed a file handle (like that returned + by Open, Creat or Dup); the Close call will close the + associated file. Internal buffers are flushed. + + Error return: + AX = error_invalid_handle + The handle passed in BX was not currently + open. + + + Name: * Creat - create a file + + Assembler usage: + LDS DX, name + MOV AH, Creat + MOV CX, attribute + INT 21h + ; AX now has the handle + + Description: + Creat creates a new file or truncates an old file + to zero length in preparation for writing. If the + file did not exist, then the file is created in the + appropriate directory and the file is given the + read/write protection code of access. + + CX contains the default attributes to be set for + the file. Currently, the read-only bit must be off. + + Error returns: + AX = error_access_denied + The attributes specified in CX contained one + that could not be created (directory, volume + ID), a file already existed with a more + inclusive set of attributes, or a directory + existed with the same name. + = error_path_not_found + The path specified was invalid. + = error_too_many_open_files + The file was created with the specified + attributes, but there were no free handles + available for the process or that the internal + system tables were full. + + + Name: * Dup - duplicate a file handle + + Assembler usage: + MOV BX, fh + MOV AH, Dup + INT 21h + ; AX has the returned handle + + Description: + Dup takes an already opened file handle and + returns a new handle that refers to the same file at + the same position. + + Error returns: + AX = error_invalid_handle + The handle passed in BX was not currently + open. + = error_too_many_open_files + There were no free handles available in the + current process or the internal system tables + were full. + + + Name: * Dup2 - force a duplicate of a handle + + Assembler usage: + MOV BX, fh + MOV CX, newfh + MOV AH, Dup2 + INT 21h + + Description: + Dup2 will cause newfh to refer to the same stream + as fh. If there was an open file on newfh, then it is + closed first. + + Error returns: + AX = error_invalid_handle + The handle passed in BX was not currently + open. + + + Name: * Exec - load / execute a program + + Assembler usage: + LDS DX, name + LES BX, blk + MOV AH, Exec + MOV AL, func + INT 21h + + Description: + This call allows a program to load another program + into memory and (default) begin execution of it. + DS:DX points to the ASCIZ name of the file to be + loaded. ES:BX points to a parameter block for the + load. + + A function code is passed in AL: + + AL Function + -- -------- + 0 Load and execute the program. A program header is + established for the program and the terminate and + ^C addresses are set to the instruction after the + EXEC system call. + + NOTE: When control is returned, via a ^C or + terminate, from the program being EXECed ALL + registers are altered including the stack. + This is because control is returned from the + EXECed program, not the system. To regain + your stack, store an SS:SP value in a data + location reachable from your CS. + ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +| C A V E A T P R O G R A M M E R | +| | + 1 Load, create the program header but do not begin + execution. The CS:IP/SS:SP of the program are + returned in the area provided by the user. +| | +| C A V E A T P R O G R A M M E R | ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + 3 Load, do not create the program header, and do not + begin execution. This is useful in loading + program overlays. + + For each value of AL, the block has the following + format: + + AL = 0 -> load/execute program + + +---------------------------+ + | WORD segment address of | + | environment. | + +---------------------------+ + | DWORD pointer to command | + | line at 80h | + +---------------------------+ + | DWORD pointer to default | + | FCB to be passed at 5Ch | + +---------------------------+ + | DWORD pointer to default | + | FCB to be passed at 6Ch | + +---------------------------+ + ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +| C A V E A T P R O G R A M M E R | +| | + AL = 1 -> load program + + +---------------------------+ + | WORD segment address of | + | environment. | + +---------------------------+ + | DWORD pointer to command | + | line at 80h | + +---------------------------+ + | DWORD pointer to default | + | FCB to be passed at 5Ch | + +---------------------------+ + | DWORD pointer to default | + | FCB to be passed at 6Ch | + +---------------------------+ + | DWORD returned value of | + | SS:SP | + +---------------------------+ + | DWORD returned value of | + | CS:IP | + +---------------------------+ +| | +| C A V E A T P R O G R A M M E R | ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + AL = 3 -> load overlay + + +---------------------------+ + | WORD segment address where| + | file will be loaded. | + +---------------------------+ + | WORD relocation factor to | + | be applied to the image. | + +---------------------------+ + + Note that all open files of a process are + duplicated in the child process after an Exec. This + is extremely powerful; the parent process has control + over the meanings of stdin, stdout, stderr, stdaux and + stdprn. The parent could, for example, write a series + of records to a file, open the file as standard input, + open a listing file as standard output and then Exec a + sort program that takes its input from stdin and + writes to stdout. + + Also inherited (or passed from the parent) is an + 'environment'. This is a block of text strings (less + than 32K bytes total) that convey various + configurations parameters. The format of the + environment is as follows: + + (paragraph boundary) + +---------------------------+ + | BYTE asciz string 1 | + +---------------------------+ + | BYTE asciz string 2 | + +---------------------------+ + | ... | + +---------------------------+ + | BYTE asciz string n | + +---------------------------+ + | BYTE of zero | + +---------------------------+ + + Typically the environment strings have the form: + + parameter=value + + for example, COMMAND.COM always passes its execution + search path as: + + PATH=A:/BIN;B:/BASIC/LIB + + A zero value of the environment address will cause the + child process to inherit the parent's environment + unchanged. + + Note that on a successful return from EXEC, all + registers, except for CS:IP, are changed. + + Error return: + AX = error_invalid_function + The function passed in AL was not 0, 1 or 3. + = error_bad_environment + The environment was larger than 32Kb. + = error_bad_format + The file pointed to by DS:DX was an EXE format + file and contained information that was + internally inconsistent. + = error_not_enough_memory + There was not enough memory for the process to + be created. + = error_file_not_found + The path specified was invalid or not found. + + + Name: * Exit - terminate a process + + Assembler usage: + MOV AL, code + MOV AH, Exit + INT 21h + + Description: + Exit will terminate the current process, + transferring control to the invoking process. In + addition, a return code may be sent. All files open + at the time are closed. + + Error returns: + None. + + + Name: * Ioctl - I/O control for devices + + Assembler usage: + MOV BX, Handle + + (or MOV BL, drive for calls AL=4,5 + 0=default,A=1...) + + MOV DX, Data + + (or LDS DX, buf and + MOV CX, count for calls AL=2,3,4,5) + + MOV AH, Ioctl + MOV AL, func + INT 21h + ; For calls AL=2,3,4,5 AX is the number of bytes + ; transferred (same as READ and WRITE). + ; For calls AL=6,7 AL is status returned, AL=0 if + ; status is not ready, AL=0FFH otherwise. + + Description: + Set or Get device information associated with open + Handle, or send/receive control string to device + Handle or device. + + The following values are allowed for func: + + Request Function + ------ -------- + 0 Get device information (returned in DX) + 1 Set device information (as determined by DX) + 2 Read CX number of bytes into DS:DX from device + control channel. + 3 Write CX number of bytes from DS:DX to device + control channel. + 4 Same as 2 only drive number in BL + 0=default,A=1,B=2,... + 5 Same as 3 only drive number in BL + 0=default,A=1,B=2,... + 6 Get input status + 7 Get output status + + Ioctl can be used to get information about device + channels. It is ok to make Ioctl calls on regular + files but only calls 0,6 and 7 are defined in that + case (AL=0,6,7), all other calls return an + error_invalid_function error. + + CALLS AL=0 and AL=1 + + The bits of DX are defined as follows for calls + AL=0 and AL=1. Note that the upper byte MUST be zero + on a set call. + + | + 15 14 13 12 11 10 9 8|7 6 5 4 3 2 1 0 + +--+--+--+--+--+--+-+-+-+-+-+-+-+-+-+-+ + | R| C| |I|E|R|S|I|I|I|I| + | e| T| |S|O|A|P|S|S|S|S| + | s| R| Reserved |D|F|W|E|C|N|C|C| + | | L| |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 (Bits 8-15 = + 0 in this case) + + 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 + SPECL = 1 if this device is special + + CTRL = 0 if this device can NOT do control strings + via calls AL=2 and AL=3. + CTRL = 1 if this device can process control + strings via calls AL=2 and AL=3. + NOTE that this bit cannot be set. + + 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, ...) + + Bits 15,8-13,4 are reserved and should not be altered. + + Calls 2..5: + These four calls allow arbitrary control strings to be + sent or received from a device. The Call syntax is + the same as the READ and WRITE calls, except for 4 and + 5 which take a drive number in BL instead of a handle + in BX. + + An error_invalid_function error is returned if the + CTRL bit (see above) is 0. + + An error_access_denied is returned by calls AL=4,5 if + the drive number is invalid. + + Calls 6,7: + These two calls allow the user to check if a file + handle is ready for input or output. Status of + handles open to a device is the intended use of these + calls, but status of a handle open to a disk file is + OK and is defined as follows: + + Input: + Always ready (AL=FF) until EOF reached, then + always not ready (AL=0) unless current + position changed via LSEEK. + Output: + Always ready (even if disk full). + + IMPORTANT NOTE: + The status is defined at the time the system is + CALLED. On future versions, by the time control is + returned to the user from the system, the status + returned may NOT correctly reflect the true current + state of the device or file. + + Error returns: + AX = error_invalid_handle + The handle passed in BX was not currently + open. + = error_invalid_function + The function passed in AL was not in the range + 0:7. + = error_invalid_data + = error_access_denied (calls AL=4..7) + + + Name: * LSeek - move file read/write pointer + + Assembler usage: + MOV DX, offsetlow + MOV CX, offsethigh + MOV AL, method + MOV BX, handle + MOV AH, LSeek + INT 21h + ; DX:AX has the new location of the pointer + + Description: + LSeek moves the read/write pointer according to + method: + + Method Function + ------ -------- + 0 The pointer is moved to offset bytes from the + beginning of the file. + 1 The pointer is moved to the current location + plus offset. + 2 The pointer is moved to the end of file plus + offset. + + Offset should be regarded as a 32-bit integer with + CX occupying the most significant 16 bits. + + Error returns: + AX = error_invalid_handle + The handle passed in BX was not currently + open. + = error_invalid_function + The function passed in AL was not in the range + 0:2. + + + Name: * MkDir - Create a directory entry + + Assembler usage: + LDS DX, name + MOV AH, MkDir + INT 21h + + Description: + Given a pointer to an ASCIZ name, create a new + directory entry at the end. + + Error returns: + AX = error_path_not_found + The path specified was invalid or not found. + = error_access_denied + The directory could not be created (no room in + parent directory), the directory/file already + existed or a device name was specified. + + + Name: * Open - access a file + + Assembler usage: + LDS DX, name + MOV AH, Open + MOV AL, access + INT 21h + ; AX has error or file handle + ; If successful open + + Description: + Open associates a 16-bit file handle with a file. + + The following values are allowed for access: + + ACCESS Function + ------ -------- + 0 file is opened for reading + 1 file is opened for writing + 2 file is opened for both reading and writing. + + DS:DX point to an ASCIZ name of the file to be + opened. + + The read/write pointer is set at the first byte of + the file and the record size of the file is 1 byte. + The returned file handle must be used for subsequent + I/O to the file. + + The DOS, on initialization, will have a maximum + number of files. See the configuration file document + for information on changing this default. + + Error returns: + AX = error_invalid_access + The access specified in AL was not in the + range 0:2. + = error_file_not_found + The path specified was invalid or not found. + = error_access_denied + The user attempted to open a directory or + volume-id, or open a read-only file for + writing. + = error_too_many_open_files + There were no free handles available in the + current process or the internal system tables + were full. + + + Name: * Read - Do file/device I/O + + Assembler usage: + LDS DX, buf + MOV CX, count + MOV BX, handle + MOV AH, Read + INT 21h + ; AX has number of bytes read + + Description: + Read transfers count bytes from a file into a + buffer location. It is not guaranteed that all count + bytes will be read; for example, reading from the + keyboard will read at most one line of text. If the + returned value is zero, then the program has tried to + read from the end of file. + + All I/O is done using normalized pointers; no + segment wraparound will occur. + + Error returns: + AX = error_invalid_handle + The handle passed in BX was not currently + open. + = error_access_denied + The handle passed in BX was opened in a mode + that did not allow reading. + + + Name: * RmDir - Remove a directory entry + + Assembler usage: + LDS DX, name + MOV AH, RmDir + INT 21h + + Description: + RmDir is given an asciz name of a directory. That + directory is removed from its parent + + Error returns: + AX = error_path_not_found + The path specified was invalid or not found. + = error_access_denied + The path specified was not empty, not a + directory, the root directory or contained + invalid information. + = error_current_directory + The path specified was the current directory + on a drive. + + + Name: * Unlink - delete a directory entry + + Assembler usage: + LDS DX, name + MOV AH, Unlink + INT 21h + + Description: + Unlink removes a directory entry associated with a + filename. If the file is currently open on another + handle, then no removal will take place. + + Error returns: + AX = error_file_not_found + The path specified was invalid or not found. + = error_access_denied + The path specified was a directory or + read-only. + + + Name: * Wait - retrieve the return code of a child + + Assembler usage: + MOV AH, Wait + INT 21h + ; AX has the exit code + + Description: + Wait will return the Exit code specified by a + child process. It will return this Exit code only + once. The low byte of this code is that sent by the + Exit routine. The high byte is one of the following: + + 0 - terminate/abort + 1 - ^C + 2 - Hard error + 3 - Terminate and stay resident + + Error returns: + None. + + + Name: * Write - write to a file + + Assembler usage: + LDS DX, buf + MOV CX, count + MOV BX, handle + MOV AH, Write + INT 21h + ; AX has number of bytes written + + Description: + Write transfers count bytes from a buffer into + a file. It should be regarded as an error if the + number of bytes written is not the same as the number + requested. + + It is important to note that the write system + call with a count of zero (CX = 0) will truncate + the file at the current position. + + All I/O is done using normalized pointers; no + segment wraparound will occur. + + Error Returns: + AX = error_invalid_handle + The handle passed in BX was not currently + open. + = error_access_denied + The handle was not opened in a mode that + allowed writing. + + +The following XENIX convention is followed for the new 2.0 +system calls: + + o If no error occurred, then the carry flag will be + reset and register AX will contain the appropriate + information. + + o If an error occurred, then the carry flag will be + set and register AX will contain the error code. + +The following code sample illustrates the recommended method +of detecting these errors: + + ... + MOV errno,0 + INT 21h + JNC continue + MOV errno,AX +continue: + ... + +The word variable errno will now have the correct error code +for that system call. + +The current equates for the error codes are: + +no_error_occurred EQU 0 + +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 +error_invalid_drive EQU 15 +error_current_directory EQU 16 +error_not_same_device EQU 17 +error_no_more_files EQU 18 + + +System call assignments: + +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 +; XENIX CALLS +; 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 + \ No newline at end of file diff --git a/Disk05/SYSINIT.DOC b/Disk05/SYSINIT.DOC new file mode 100644 index 0000000..fa20d08 Binary files /dev/null and b/Disk05/SYSINIT.DOC differ diff --git a/Disk05/UTILITY.DOC b/Disk05/UTILITY.DOC new file mode 100644 index 0000000..a63793c --- /dev/null +++ b/Disk05/UTILITY.DOC @@ -0,0 +1,813 @@ + + + + + + + + + + + + + + + + + + + MS-DOS 2.0 + + Utility Extensions + + + + + + + + + The following notation is used below: + + [item] item is optional. + item* item is repeated 0 or more times. + item+ item is repeated 1 or more times. + {item1 | item2} + item1 is present or item 2 is present but + not both. + indicates a syntactic variable. + + +COMMAND invokation + +COMMAND [[:]] [] [-D] [-P] [-C ] + + -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. + +COMMAND extensions + +IF + + where is one of the following: + + ERRORLEVEL + true if and only if the previous program EXECed by + COMMAND had an exit code of or higher. + + == + true if and only if and are + identical after parameter substitution. Strings + may not have embedded delimiters. + + EXIST + true if and only if exists. + + NOT + true if and only if is false. + + The IF statement allows conditional execution of commands. + When the is true, then the is + executed otherwise, the is skipped. + + Examples: + + IF not exist /tmp/foo ECHO Can't find file /tmp/foo + + IF $1x == x ECHO Need at least one parameter + + IF NOT ERRORLEVEL 3 LINK $1,,; + + +FOR %% IN DO + + can be any character but 0,1,2,3,..,9 (so there is no + confusion with the %0 - %9 batch parameters). + + is ( * ) + + The %% variable is sequentially set to each member of + and then is evaluated. If a member of + is an expression involving * and/or ?, then the + variable is set to each matching pattern from disk. In + this case only one such may be in the set, any + s after the first are ignored. + + Example: + + FOR %%f IN ( *.ASM ) DO MASM %%f; + + for %%f in (FOO BAR BLECH) do REM %%f to you + + NOTE: The '%%' is needed so that after Batch parameter + (%0 - %9) processing is done, there is one '%' left. + If only '%f' were there, the batch parameter processor + would see the '%' then look at 'f', decide that '%f' + was an error (bad parameter reference) and throw out + the '%f' so that FOR would never see it. If the FOR + is NOT in a batch file, then only ONE '%' should be + used. + + +SHIFT + + Currently, command files are limited to handling 10 + parameters: %0 through %9. To allow access to more than + these, the command SHIFT will perform a 'pop' of the + command line parameters: + + if %0 = "foo" + %1 = "bar" + %2 = "blech" + %3...%9 are empty + + then a SHIFT will result in the following: + + %0 = "bar" + %1 = "blech" + %2...%9 are empty + + If there are more than 10 parameters given on a command + line, then the those that appear after the 10th (%9) will + be shifted one at a time into %9 by successive shifts. + +: