From 50868cd2d277149c3733f051facfa3c67568700c Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 17 May 2020 10:49:37 -0700 Subject: [PATCH] inital commit --- AG.DOC | 7051 ++++++++++++++++++++++++++++ PROGREF/0_CONTS.A | 227 + PROGREF/0_FRONT.A | 34 + PROGREF/1A_CALLS.A | 3175 +++++++++++++ PROGREF/1B_CALLS.A | 2688 +++++++++++ PROGREF/1C_CALLS.A | 3520 ++++++++++++++ PROGREF/1D_CALLS.A | 3710 +++++++++++++++ PROGREF/1E_CALLS.A | 3533 ++++++++++++++ PROGREF/2_DEVDR.A | 3558 ++++++++++++++ PROGREF/3_TECH.A | 623 +++ PROGREF/4_CTRLB.A | 393 ++ PROGREF/5_NLS.A | 360 ++ PROGREF/6_EXE.A | 203 + PROGREF/7_OMF.A | 2555 ++++++++++ PROGREF/8_HINTS.A | 440 ++ PROGREF/INDEX.A | 1203 +++++ README.BF | 238 + README.DIS | 776 +++ SRC/BIOS/BIOMES.INC | 31 + SRC/BIOS/BIOSTRUC.INC | 87 + SRC/BIOS/CLOCKSUB.INC | 76 + SRC/BIOS/CMOSEQU.INC | 50 + SRC/BIOS/DSKPRM.INC | 22 + SRC/BIOS/JUMPMAC.INC | 32 + SRC/BIOS/LOCSCR | 1 + SRC/BIOS/MAKEFILE | 107 + SRC/BIOS/MS96TPI.INC | 494 ++ SRC/BIOS/MSAUX.ASM | 281 ++ SRC/BIOS/MSAUX.OBJ | Bin 0 -> 470 bytes SRC/BIOS/MSBDS.INC | 118 + SRC/BIOS/MSBIO.LNK | 5 + SRC/BIOS/MSBIO1.ASM | 693 +++ SRC/BIOS/MSBIO1.OBJ | Bin 0 -> 4091 bytes SRC/BIOS/MSBIO2.ASM | 650 +++ SRC/BIOS/MSBIO2.OBJ | Bin 0 -> 4164 bytes SRC/BIOS/MSCLOCK.ASM | 295 ++ SRC/BIOS/MSCLOCK.OBJ | Bin 0 -> 616 bytes SRC/BIOS/MSCON.ASM | 216 + SRC/BIOS/MSCON.OBJ | Bin 0 -> 470 bytes SRC/BIOS/MSDATA.INC | 882 ++++ SRC/BIOS/MSDISK.ASM | 2408 ++++++++++ SRC/BIOS/MSDISK.OBJ | Bin 0 -> 7139 bytes SRC/BIOS/MSEQU.INC | 65 + SRC/BIOS/MSEXTRN.INC | 72 + SRC/BIOS/MSGROUP.INC | 46 + SRC/BIOS/MSHARD.ASM | 418 ++ SRC/BIOS/MSHARD.OBJ | Bin 0 -> 679 bytes SRC/BIOS/MSINIT.ASM | 2213 +++++++++ SRC/BIOS/MSINIT.OBJ | Bin 0 -> 6639 bytes SRC/BIOS/MSIOCTL.INC | 1036 ++++ SRC/BIOS/MSLOAD.ASM | 767 +++ SRC/BIOS/MSLOAD.INC | 52 + SRC/BIOS/MSLOAD.OBJ | Bin 0 -> 754 bytes SRC/BIOS/MSLPT.ASM | 274 ++ SRC/BIOS/MSLPT.OBJ | Bin 0 -> 535 bytes SRC/BIOS/MSMACRO.INC | 192 + SRC/BIOS/MSSTACK.INC | 306 ++ SRC/BIOS/MSVOLID.INC | 297 ++ SRC/BIOS/PUSHPOP.INC | 20 + SRC/BIOS/READCLOC.INC | 162 + SRC/BIOS/STKINIT.INC | 270 ++ SRC/BIOS/STKMES.INC | 6 + SRC/BIOS/SYSCONF.ASM | 868 ++++ SRC/BIOS/SYSCONF.OBJ | Bin 0 -> 3281 bytes SRC/BIOS/SYSIMES.ASM | 18 + SRC/BIOS/SYSIMES.INC | 68 + SRC/BIOS/SYSIMES.OBJ | Bin 0 -> 673 bytes SRC/BIOS/SYSINIT1.ASM | 1084 +++++ SRC/BIOS/SYSINIT1.OBJ | Bin 0 -> 8616 bytes SRC/BIOS/SYSINIT2.ASM | 1256 +++++ SRC/BIOS/SYSINIT2.OBJ | Bin 0 -> 3549 bytes SRC/BOOT/BOOT11.INC | 64 + SRC/BOOT/MAKEFILE | 38 + SRC/BOOT/MESSAGES.INC | 7 + SRC/BOOT/MSBOOT.ASM | 386 ++ SRC/BUGFIX/BIOS/MSBIO2.ASM | 650 +++ SRC/BUGFIX/CMD/COMMAND/COMMAND.COM | Bin 0 -> 25276 bytes SRC/BUGFIX/CMD/FDISK/FDISK.COM | Bin 0 -> 48919 bytes SRC/BUGFIX/CMD/FORMAT/FORMAT.ASM | 3032 ++++++++++++ SRC/BUGFIX/CMD/FORMAT/MESSAGES.ASM | 68 + SRC/BUGFIX/CMD/FORMAT/MESSAGES.INC | 139 + SRC/BUGFIX/DOS/HANDLE.OBJ | Bin 0 -> 1642 bytes SRC/CMD/FORMAT/BOOTMES.INC | 9 + SRC/CMD/FORMAT/FILESIZE.INC | 6 + SRC/CMD/FORMAT/FORMAT.ASM | 3032 ++++++++++++ SRC/CMD/FORMAT/FORMAT.LNK | 2 + SRC/CMD/FORMAT/FORPROC.ASM | 141 + SRC/CMD/FORMAT/MAKEFILE | 58 + SRC/CMD/FORMAT/MAKE_INC.BAS | Bin 0 -> 1072 bytes SRC/CMD/FORMAT/MESSAGES.ASM | 68 + SRC/CMD/FORMAT/MESSAGES.INC | 139 + SRC/CMD/FORMAT/OEMFOR.ASM | 1204 +++++ SRC/CMD/MAKEFILE | 14 + SRC/CMD/PRINT/MAKEFILE | 61 + SRC/CMD/PRINT/NPRINTF.ASM | 386 ++ SRC/CMD/PRINT/PRIDEFS.INC | 213 + SRC/CMD/PRINT/PRINT.LNK | 2 + SRC/CMD/PRINT/PRINT_R.ASM | 2189 +++++++++ SRC/CMD/PRINT/PRINT_RM.ASM | 34 + SRC/CMD/PRINT/PRINT_RM.INC | 34 + SRC/CMD/PRINT/PRINT_T.ASM | 1434 ++++++ SRC/CMD/PRINT/PRINT_TM.ASM | 42 + SRC/CMD/PRINT/PRINT_TM.INC | 53 + SRC/CMD/SORT/MAKEFILE | 42 + SRC/CMD/SORT/MESSAGES.ASM | 91 + SRC/CMD/SORT/MESSAGES.INC | 10 + SRC/CMD/SORT/SORT.ASM | 470 ++ SRC/CMD/SORT/SORT.LNK | 2 + SRC/CMD/SYS/MAKEFILE | 52 + SRC/CMD/SYS/MESSAGES.ASM | 95 + SRC/CMD/SYS/MESSAGES.INC | 48 + SRC/CMD/SYS/SYS.ASM | 1168 +++++ SRC/CMD/SYS/SYS.LNK | 3 + SRC/DOS/ABORT.OBJ | Bin 0 -> 452 bytes SRC/DOS/ALLOC.OBJ | Bin 0 -> 1226 bytes SRC/DOS/ARENA.INC | 27 + SRC/DOS/BPB.INC | 39 + SRC/DOS/BUF.OBJ | Bin 0 -> 1364 bytes SRC/DOS/BUFFER.INC | 61 + SRC/DOS/CLOSE.OBJ | Bin 0 -> 1157 bytes SRC/DOS/CONST2.OBJ | Bin 0 -> 1913 bytes SRC/DOS/CPMFCB.INC | 124 + SRC/DOS/CPMIO.OBJ | Bin 0 -> 2230 bytes SRC/DOS/CPMIO2.OBJ | Bin 0 -> 1099 bytes SRC/DOS/CREATE.OBJ | Bin 0 -> 808 bytes SRC/DOS/CRIT.OBJ | Bin 0 -> 367 bytes SRC/DOS/CURDIR.INC | 41 + SRC/DOS/DELETE.OBJ | Bin 0 -> 1480 bytes SRC/DOS/DEV.OBJ | Bin 0 -> 1640 bytes SRC/DOS/DEVSYM.INC | 162 + SRC/DOS/DINFO.OBJ | Bin 0 -> 467 bytes SRC/DOS/DIR.OBJ | Bin 0 -> 1335 bytes SRC/DOS/DIR2.OBJ | Bin 0 -> 3188 bytes SRC/DOS/DIRCALL.OBJ | Bin 0 -> 1572 bytes SRC/DOS/DIRENT.INC | 58 + SRC/DOS/DISK.OBJ | Bin 0 -> 2701 bytes SRC/DOS/DISK2.OBJ | Bin 0 -> 2180 bytes SRC/DOS/DISK3.OBJ | Bin 0 -> 1815 bytes SRC/DOS/DIVMES.INC | 12 + SRC/DOS/DOSCNTRY.INC | 86 + SRC/DOS/DOSMAC.INC | 630 +++ SRC/DOS/DOSMES.INC | 485 ++ SRC/DOS/DOSSEG.INC | 25 + SRC/DOS/DOSSYM.INC | 155 + SRC/DOS/DPB.INC | 34 + SRC/DOS/DPL.INC | 15 + SRC/DOS/DUP.OBJ | Bin 0 -> 302 bytes SRC/DOS/ERROR.INC | 151 + SRC/DOS/EXE.INC | 78 + SRC/DOS/FAT.OBJ | Bin 0 -> 2083 bytes SRC/DOS/FCB.OBJ | Bin 0 -> 1060 bytes SRC/DOS/FCBIO.OBJ | Bin 0 -> 2763 bytes SRC/DOS/FCBIO2.OBJ | Bin 0 -> 1971 bytes SRC/DOS/FILE.OBJ | Bin 0 -> 1850 bytes SRC/DOS/FILEMODE.INC | 25 + SRC/DOS/FIND.INC | 25 + SRC/DOS/FINFO.OBJ | Bin 0 -> 777 bytes SRC/DOS/GETSET.OBJ | Bin 0 -> 1810 bytes SRC/DOS/HANDLE.OBJ | Bin 0 -> 1642 bytes SRC/DOS/INTNAT.INC | 39 + SRC/DOS/IOCTL.INC | 169 + SRC/DOS/IOCTL.OBJ | Bin 0 -> 1814 bytes SRC/DOS/ISEARCH.OBJ | Bin 0 -> 1127 bytes SRC/DOS/LOCK.OBJ | Bin 0 -> 669 bytes SRC/DOS/MACRO.OBJ | Bin 0 -> 1002 bytes SRC/DOS/MACRO2.OBJ | Bin 0 -> 2725 bytes SRC/DOS/MAKEFILE | 49 + SRC/DOS/MI.INC | 19 + SRC/DOS/MISC.OBJ | Bin 0 -> 1575 bytes SRC/DOS/MISC2.OBJ | Bin 0 -> 1225 bytes SRC/DOS/MKNODE.OBJ | Bin 0 -> 2351 bytes SRC/DOS/MSDOS.LNK | 13 + SRC/DOS/MULT.INC | 158 + SRC/DOS/NIBDOS.OBJ | Bin 0 -> 1035 bytes SRC/DOS/OPEN.OBJ | Bin 0 -> 1071 bytes SRC/DOS/PARSE.OBJ | Bin 0 -> 267 bytes SRC/DOS/PATH.OBJ | Bin 0 -> 1196 bytes SRC/DOS/PDB.INC | 47 + SRC/DOS/PROC.OBJ | Bin 0 -> 2861 bytes SRC/DOS/RENAME.OBJ | Bin 0 -> 1687 bytes SRC/DOS/ROM.OBJ | Bin 0 -> 1600 bytes SRC/DOS/SEARCH.OBJ | Bin 0 -> 1384 bytes SRC/DOS/SF.INC | 158 + SRC/DOS/SHARE.OBJ | Bin 0 -> 499 bytes SRC/DOS/SMDOSSYM.INC | 156 + SRC/DOS/SRVCALL.OBJ | Bin 0 -> 1264 bytes SRC/DOS/STDCODE.OBJ | Bin 0 -> 1748 bytes SRC/DOS/STDCTRLC.OBJ | Bin 0 -> 2964 bytes SRC/DOS/STDDATA.OBJ | Bin 0 -> 3519 bytes SRC/DOS/STDDISP.OBJ | Bin 0 -> 1442 bytes SRC/DOS/STDDOSME.ASM | 16 + SRC/DOS/STDSW.INC | 33 + SRC/DOS/STDTABLE.OBJ | Bin 0 -> 6374 bytes SRC/DOS/SYSCALL.INC | 160 + SRC/DOS/SYSVAR.INC | 24 + SRC/DOS/TIME.OBJ | Bin 0 -> 1332 bytes SRC/DOS/UTIL.OBJ | Bin 0 -> 546 bytes SRC/DOS/VECTOR.INC | 72 + SRC/INC/MACRO.INC | 19 + SRC/INC/STRUC.INC | 573 +++ SRC/INC/VERSION.INC | 92 + SRC/INC/VERSIONA.INC | 19 + SRC/LIBC/CDS.C | 129 + SRC/LIBC/DPB.C | 37 + SRC/LIBC/ERRTST.C | 271 ++ SRC/LIBC/ITOUPPER.ASM | 34 + SRC/LIBC/JOIN.C | 253 + SRC/LIBC/KSTRING.C | 118 + SRC/LIBC/PRINTF.ASM | 414 ++ SRC/LIBC/PRINTF.OBJ | Bin 0 -> 1159 bytes SRC/LIBC/STRING.C | 94 + SRC/LIBC/SYSVAR.C | 48 + SRC/MAKEFILE | 13 + SRC/TOOLS/CONVERT.EXE | Bin 0 -> 16340 bytes SRC/TOOLS/DBOF.EXE | Bin 0 -> 10262 bytes SRC/TOOLS/EXE2BIN.EXE | Bin 0 -> 3050 bytes SRC/TOOLS/EXEFIX.EXE | Bin 0 -> 11776 bytes SRC/TOOLS/LINK.EXE | Bin 0 -> 47547 bytes SRC/TOOLS/MASM.EXE | Bin 0 -> 85566 bytes SRC/TOOLS/MASM401.EXE | Bin 0 -> 102120 bytes SRC/TOOLS/MSMAKE.EXE | Bin 0 -> 24300 bytes UPDSRC/BIOS/MSBIO2.ASM | 649 +++ UPDSRC/BIOS/MSDISK.ASM | 2410 ++++++++++ UPDSRC/BIOS/MSINIT.ASM | 2228 +++++++++ UPDSRC/BIOS/MSIOCTL.INC | 1039 ++++ UPDSRC/BIOS/MSSTACK.INC | 306 ++ UPDSRC/BIOS/SYSINIT2.ASM | 1276 +++++ UPDSRC/CMD/PRINT/PRINT_R.ASM | 2192 +++++++++ UPDSRC/DOS/DISK2.OBJ | Bin 0 -> 2182 bytes 229 files changed, 81271 insertions(+) create mode 100644 AG.DOC create mode 100644 PROGREF/0_CONTS.A create mode 100644 PROGREF/0_FRONT.A create mode 100644 PROGREF/1A_CALLS.A create mode 100644 PROGREF/1B_CALLS.A create mode 100644 PROGREF/1C_CALLS.A create mode 100644 PROGREF/1D_CALLS.A create mode 100644 PROGREF/1E_CALLS.A create mode 100644 PROGREF/2_DEVDR.A create mode 100644 PROGREF/3_TECH.A create mode 100644 PROGREF/4_CTRLB.A create mode 100644 PROGREF/5_NLS.A create mode 100644 PROGREF/6_EXE.A create mode 100644 PROGREF/7_OMF.A create mode 100644 PROGREF/8_HINTS.A create mode 100644 PROGREF/INDEX.A create mode 100644 README.BF create mode 100644 README.DIS create mode 100644 SRC/BIOS/BIOMES.INC create mode 100644 SRC/BIOS/BIOSTRUC.INC create mode 100644 SRC/BIOS/CLOCKSUB.INC create mode 100644 SRC/BIOS/CMOSEQU.INC create mode 100644 SRC/BIOS/DSKPRM.INC create mode 100644 SRC/BIOS/JUMPMAC.INC create mode 100644 SRC/BIOS/LOCSCR create mode 100644 SRC/BIOS/MAKEFILE create mode 100644 SRC/BIOS/MS96TPI.INC create mode 100644 SRC/BIOS/MSAUX.ASM create mode 100644 SRC/BIOS/MSAUX.OBJ create mode 100644 SRC/BIOS/MSBDS.INC create mode 100644 SRC/BIOS/MSBIO.LNK create mode 100644 SRC/BIOS/MSBIO1.ASM create mode 100644 SRC/BIOS/MSBIO1.OBJ create mode 100644 SRC/BIOS/MSBIO2.ASM create mode 100644 SRC/BIOS/MSBIO2.OBJ create mode 100644 SRC/BIOS/MSCLOCK.ASM create mode 100644 SRC/BIOS/MSCLOCK.OBJ create mode 100644 SRC/BIOS/MSCON.ASM create mode 100644 SRC/BIOS/MSCON.OBJ create mode 100644 SRC/BIOS/MSDATA.INC create mode 100644 SRC/BIOS/MSDISK.ASM create mode 100644 SRC/BIOS/MSDISK.OBJ create mode 100644 SRC/BIOS/MSEQU.INC create mode 100644 SRC/BIOS/MSEXTRN.INC create mode 100644 SRC/BIOS/MSGROUP.INC create mode 100644 SRC/BIOS/MSHARD.ASM create mode 100644 SRC/BIOS/MSHARD.OBJ create mode 100644 SRC/BIOS/MSINIT.ASM create mode 100644 SRC/BIOS/MSINIT.OBJ create mode 100644 SRC/BIOS/MSIOCTL.INC create mode 100644 SRC/BIOS/MSLOAD.ASM create mode 100644 SRC/BIOS/MSLOAD.INC create mode 100644 SRC/BIOS/MSLOAD.OBJ create mode 100644 SRC/BIOS/MSLPT.ASM create mode 100644 SRC/BIOS/MSLPT.OBJ create mode 100644 SRC/BIOS/MSMACRO.INC create mode 100644 SRC/BIOS/MSSTACK.INC create mode 100644 SRC/BIOS/MSVOLID.INC create mode 100644 SRC/BIOS/PUSHPOP.INC create mode 100644 SRC/BIOS/READCLOC.INC create mode 100644 SRC/BIOS/STKINIT.INC create mode 100644 SRC/BIOS/STKMES.INC create mode 100644 SRC/BIOS/SYSCONF.ASM create mode 100644 SRC/BIOS/SYSCONF.OBJ create mode 100644 SRC/BIOS/SYSIMES.ASM create mode 100644 SRC/BIOS/SYSIMES.INC create mode 100644 SRC/BIOS/SYSIMES.OBJ create mode 100644 SRC/BIOS/SYSINIT1.ASM create mode 100644 SRC/BIOS/SYSINIT1.OBJ create mode 100644 SRC/BIOS/SYSINIT2.ASM create mode 100644 SRC/BIOS/SYSINIT2.OBJ create mode 100644 SRC/BOOT/BOOT11.INC create mode 100644 SRC/BOOT/MAKEFILE create mode 100644 SRC/BOOT/MESSAGES.INC create mode 100644 SRC/BOOT/MSBOOT.ASM create mode 100644 SRC/BUGFIX/BIOS/MSBIO2.ASM create mode 100644 SRC/BUGFIX/CMD/COMMAND/COMMAND.COM create mode 100644 SRC/BUGFIX/CMD/FDISK/FDISK.COM create mode 100644 SRC/BUGFIX/CMD/FORMAT/FORMAT.ASM create mode 100644 SRC/BUGFIX/CMD/FORMAT/MESSAGES.ASM create mode 100644 SRC/BUGFIX/CMD/FORMAT/MESSAGES.INC create mode 100644 SRC/BUGFIX/DOS/HANDLE.OBJ create mode 100644 SRC/CMD/FORMAT/BOOTMES.INC create mode 100644 SRC/CMD/FORMAT/FILESIZE.INC create mode 100644 SRC/CMD/FORMAT/FORMAT.ASM create mode 100644 SRC/CMD/FORMAT/FORMAT.LNK create mode 100644 SRC/CMD/FORMAT/FORPROC.ASM create mode 100644 SRC/CMD/FORMAT/MAKEFILE create mode 100644 SRC/CMD/FORMAT/MAKE_INC.BAS create mode 100644 SRC/CMD/FORMAT/MESSAGES.ASM create mode 100644 SRC/CMD/FORMAT/MESSAGES.INC create mode 100644 SRC/CMD/FORMAT/OEMFOR.ASM create mode 100644 SRC/CMD/MAKEFILE create mode 100644 SRC/CMD/PRINT/MAKEFILE create mode 100644 SRC/CMD/PRINT/NPRINTF.ASM create mode 100644 SRC/CMD/PRINT/PRIDEFS.INC create mode 100644 SRC/CMD/PRINT/PRINT.LNK create mode 100644 SRC/CMD/PRINT/PRINT_R.ASM create mode 100644 SRC/CMD/PRINT/PRINT_RM.ASM create mode 100644 SRC/CMD/PRINT/PRINT_RM.INC create mode 100644 SRC/CMD/PRINT/PRINT_T.ASM create mode 100644 SRC/CMD/PRINT/PRINT_TM.ASM create mode 100644 SRC/CMD/PRINT/PRINT_TM.INC create mode 100644 SRC/CMD/SORT/MAKEFILE create mode 100644 SRC/CMD/SORT/MESSAGES.ASM create mode 100644 SRC/CMD/SORT/MESSAGES.INC create mode 100644 SRC/CMD/SORT/SORT.ASM create mode 100644 SRC/CMD/SORT/SORT.LNK create mode 100644 SRC/CMD/SYS/MAKEFILE create mode 100644 SRC/CMD/SYS/MESSAGES.ASM create mode 100644 SRC/CMD/SYS/MESSAGES.INC create mode 100644 SRC/CMD/SYS/SYS.ASM create mode 100644 SRC/CMD/SYS/SYS.LNK create mode 100644 SRC/DOS/ABORT.OBJ create mode 100644 SRC/DOS/ALLOC.OBJ create mode 100644 SRC/DOS/ARENA.INC create mode 100644 SRC/DOS/BPB.INC create mode 100644 SRC/DOS/BUF.OBJ create mode 100644 SRC/DOS/BUFFER.INC create mode 100644 SRC/DOS/CLOSE.OBJ create mode 100644 SRC/DOS/CONST2.OBJ create mode 100644 SRC/DOS/CPMFCB.INC create mode 100644 SRC/DOS/CPMIO.OBJ create mode 100644 SRC/DOS/CPMIO2.OBJ create mode 100644 SRC/DOS/CREATE.OBJ create mode 100644 SRC/DOS/CRIT.OBJ create mode 100644 SRC/DOS/CURDIR.INC create mode 100644 SRC/DOS/DELETE.OBJ create mode 100644 SRC/DOS/DEV.OBJ create mode 100644 SRC/DOS/DEVSYM.INC create mode 100644 SRC/DOS/DINFO.OBJ create mode 100644 SRC/DOS/DIR.OBJ create mode 100644 SRC/DOS/DIR2.OBJ create mode 100644 SRC/DOS/DIRCALL.OBJ create mode 100644 SRC/DOS/DIRENT.INC create mode 100644 SRC/DOS/DISK.OBJ create mode 100644 SRC/DOS/DISK2.OBJ create mode 100644 SRC/DOS/DISK3.OBJ create mode 100644 SRC/DOS/DIVMES.INC create mode 100644 SRC/DOS/DOSCNTRY.INC create mode 100644 SRC/DOS/DOSMAC.INC create mode 100644 SRC/DOS/DOSMES.INC create mode 100644 SRC/DOS/DOSSEG.INC create mode 100644 SRC/DOS/DOSSYM.INC create mode 100644 SRC/DOS/DPB.INC create mode 100644 SRC/DOS/DPL.INC create mode 100644 SRC/DOS/DUP.OBJ create mode 100644 SRC/DOS/ERROR.INC create mode 100644 SRC/DOS/EXE.INC create mode 100644 SRC/DOS/FAT.OBJ create mode 100644 SRC/DOS/FCB.OBJ create mode 100644 SRC/DOS/FCBIO.OBJ create mode 100644 SRC/DOS/FCBIO2.OBJ create mode 100644 SRC/DOS/FILE.OBJ create mode 100644 SRC/DOS/FILEMODE.INC create mode 100644 SRC/DOS/FIND.INC create mode 100644 SRC/DOS/FINFO.OBJ create mode 100644 SRC/DOS/GETSET.OBJ create mode 100644 SRC/DOS/HANDLE.OBJ create mode 100644 SRC/DOS/INTNAT.INC create mode 100644 SRC/DOS/IOCTL.INC create mode 100644 SRC/DOS/IOCTL.OBJ create mode 100644 SRC/DOS/ISEARCH.OBJ create mode 100644 SRC/DOS/LOCK.OBJ create mode 100644 SRC/DOS/MACRO.OBJ create mode 100644 SRC/DOS/MACRO2.OBJ create mode 100644 SRC/DOS/MAKEFILE create mode 100644 SRC/DOS/MI.INC create mode 100644 SRC/DOS/MISC.OBJ create mode 100644 SRC/DOS/MISC2.OBJ create mode 100644 SRC/DOS/MKNODE.OBJ create mode 100644 SRC/DOS/MSDOS.LNK create mode 100644 SRC/DOS/MULT.INC create mode 100644 SRC/DOS/NIBDOS.OBJ create mode 100644 SRC/DOS/OPEN.OBJ create mode 100644 SRC/DOS/PARSE.OBJ create mode 100644 SRC/DOS/PATH.OBJ create mode 100644 SRC/DOS/PDB.INC create mode 100644 SRC/DOS/PROC.OBJ create mode 100644 SRC/DOS/RENAME.OBJ create mode 100644 SRC/DOS/ROM.OBJ create mode 100644 SRC/DOS/SEARCH.OBJ create mode 100644 SRC/DOS/SF.INC create mode 100644 SRC/DOS/SHARE.OBJ create mode 100644 SRC/DOS/SMDOSSYM.INC create mode 100644 SRC/DOS/SRVCALL.OBJ create mode 100644 SRC/DOS/STDCODE.OBJ create mode 100644 SRC/DOS/STDCTRLC.OBJ create mode 100644 SRC/DOS/STDDATA.OBJ create mode 100644 SRC/DOS/STDDISP.OBJ create mode 100644 SRC/DOS/STDDOSME.ASM create mode 100644 SRC/DOS/STDSW.INC create mode 100644 SRC/DOS/STDTABLE.OBJ create mode 100644 SRC/DOS/SYSCALL.INC create mode 100644 SRC/DOS/SYSVAR.INC create mode 100644 SRC/DOS/TIME.OBJ create mode 100644 SRC/DOS/UTIL.OBJ create mode 100644 SRC/DOS/VECTOR.INC create mode 100644 SRC/INC/MACRO.INC create mode 100644 SRC/INC/STRUC.INC create mode 100644 SRC/INC/VERSION.INC create mode 100644 SRC/INC/VERSIONA.INC create mode 100644 SRC/LIBC/CDS.C create mode 100644 SRC/LIBC/DPB.C create mode 100644 SRC/LIBC/ERRTST.C create mode 100644 SRC/LIBC/ITOUPPER.ASM create mode 100644 SRC/LIBC/JOIN.C create mode 100644 SRC/LIBC/KSTRING.C create mode 100644 SRC/LIBC/PRINTF.ASM create mode 100644 SRC/LIBC/PRINTF.OBJ create mode 100644 SRC/LIBC/STRING.C create mode 100644 SRC/LIBC/SYSVAR.C create mode 100644 SRC/MAKEFILE create mode 100644 SRC/TOOLS/CONVERT.EXE create mode 100644 SRC/TOOLS/DBOF.EXE create mode 100644 SRC/TOOLS/EXE2BIN.EXE create mode 100644 SRC/TOOLS/EXEFIX.EXE create mode 100644 SRC/TOOLS/LINK.EXE create mode 100644 SRC/TOOLS/MASM.EXE create mode 100644 SRC/TOOLS/MASM401.EXE create mode 100644 SRC/TOOLS/MSMAKE.EXE create mode 100644 UPDSRC/BIOS/MSBIO2.ASM create mode 100644 UPDSRC/BIOS/MSDISK.ASM create mode 100644 UPDSRC/BIOS/MSINIT.ASM create mode 100644 UPDSRC/BIOS/MSIOCTL.INC create mode 100644 UPDSRC/BIOS/MSSTACK.INC create mode 100644 UPDSRC/BIOS/SYSINIT2.ASM create mode 100644 UPDSRC/CMD/PRINT/PRINT_R.ASM create mode 100644 UPDSRC/DOS/DISK2.OBJ diff --git a/AG.DOC b/AG.DOC new file mode 100644 index 0000000..668588a --- /dev/null +++ b/AG.DOC @@ -0,0 +1,7051 @@ + + + + + + +MICROSOFT(R) + +MS(tm)-DOS + +Adaptation Guide + +Last Updated on JULY 24, 1987 +in conjunction with the MS-DOS 3.30 FINAL RELEASE + + + + + + + + + + + + + +Microsoft Corporation + + +Information in this document is subject to change without +notice and does not represent a commitment on the part of +Microsoft Corporation. The software described in this +document is furnished under a license agreement or +non-disclosure agreement. The software may be used or +copied only in accordance with the terms of that agreement. +It is against the law to copy the MS-DOS Disk Operating +System on magnetic tape, disk, or any other medium for any +purpose other than the purchaser's personal use. + + + +Copyright (C) Microsoft Corporation, 1982, 1983, 1984, 1985, 1986 + + + + + + + + + +INTEL is a registered trademark of Intel Corporation. + +IBM is a registered trademark of International Business +Machines Corporation. + +Microsoft, the Microsoft logo, and MS-DOS are registered +trademarks of Microsoft Corporation. + +XENIX is a trademark of Microsoft Corporation. + + + + + TABLE OF CONTENTS + + + +CHAPTER 1 MS-DOS INSTALLATION KIT + + 1.1 README.DOC File 1-1 + +CHAPTER 2 MS-DOS DEVELOPMENT TOOLS + +CHAPTER 3 INSTALLING MS-DOS + +CHAPTER 4 DISK STRUCTURE AND BOOTSTRAP LOADING + +CHAPTER 5 RESIDENT DEVICE DRIVERS + +CHAPTER 6 SYSINIT AND MS-DOS INITIALIZATION + +CHAPTER 7 WRITING THE FORMAT MODULE + +CHAPTER 8 TROUBLE SHOOTING + +APPENDIX A CUSTOMIZATION OF MS-DOS AND + INTERNATIONALIZATION + + A.1 Customizing MS-DOS A-1 + A.2 ECS Considerations -- MS-DOS 2.25 A-2 + A.3 Input A-3 + A.4 Output A-3 + +APPENDIX B HOW TO UPGRADE A 2.X BIOS TO 3.X + +APPENDIX C HOW TO UPGRADE A 3.1 BIOS TO 3.2 + +APPENDIX D DEVICE DRIVERS - CHAPTER 2 MS-DOS 3.20 PROGRAMMER'S REFERENCE + +APPENDIX E MS-DOS 2.25 DEVICE DRIVER EXTENSIONS + +APPENDIX F MS-DOS 2.25 APPLICATION LEVEL INTERFACE EXTENSION + +APPENDIX G SPECIAL DOC + +APPENDIX H PROGRAMMING RECOMMENDATIONS - CHAPTER 7 MS-DOS 3.20 + PROGRAMMER'S REFERENCE + +GLOSSARY OF MS-DOS TERMS + + + + + CONTENTS + +CHAPTER 1 MS-DOS INSTALLATION KIT + + 1.1 README.DOC File 1-1 + + 1.2 Contents 1-1 + + 1.3 Common Questions and Answers 1-2 + + 1.4 MS-DOS Hardware Requirements 1-3 + + 1.5 MS-DOS Overview 1-5 + + + + + + CHAPTER 1 + + MS-DOS INSTALLATION KIT + + + +1.1 README.DOC FILE + +Check the README.DOC file on DISTRIBUTION DISKETTES for +version specific information and any addenda to this document. + + + +1.2 CONTENTS + +The MS-DOS 3.21 Installation Kit is provided on 5-1/4" high capacity +1.2 Megabyte disks. It consists of the MS-DOS DISTRIBUTION +DISKETTES that include files formerly found +version. + +Included with the kit is a Sample MS-DOS 2.XX/3.XX Implementation. +The sample implementation runs on all members of the IBM PC family and +is intended to be functionally equivalent to the IBM implementation. +The purpose of this sample is to assist Microsoft OEMs with their +MS-DOS installations, but can also be used directly as part of the OEMs +product. IO.SYS, the BIOS, has been intended to be self documenting and +Microsoft will support services for it as it run on IBM PCs. + +Included in the kit is a copy of the current Microsoft(R) Macro Assembler +featuring SYMDEB, the symbolic debugger. The full MASM retail package is +no longer provided. + +The installation kit also includes four manuals: + + MS-DOS User's Guide. This is an introduction to ______ ______ _____ + MS-DOS, including how to start the system and use + applications. + + MS-DOS User's Reference Manual. This manual ______ ______ _________ ______ + explains hierarchical directories, the MS-DOS file + structure, and MS-DOS commands and utilities. This + manual is new in 3.XX. + + MS-DOS Programmer's Reference Manual. This manual ______ ____________ _________ ______ + includes a summary of all published system calls + and MS-DOS structures. + + MS-DOS Adaptation Guide. This manual describes how ______ __________ _____ + to implement MS-DOS on OEM machines. This guide is + available on diskette only and is the text you are + now reading. + + MS-DOS INSTALLATION KIT Page 1-2 + + +1.3 COMMON QUESTIONS AND ANSWERS + +Q. What kind of development machine do you recommend? + +A. Microsoft recommends that an MS-DOS machine be used as a + development tool in preparing software for your target + machine. Using an MS-DOS machine avoids problems with + incompatible assemblers and object module formats. You + may want to read standard MS-DOS disk formats. Using + the development machine to build a system disk for the + target machine simplifies the implementation process. + +Q. Are sources available? + +A. Sources for MS-DOS are not available (except for the sample + BIOS implementation). + +Q. What language is MS-DOS written in? + +A. The source code for MS-DOS and most utilities is written + in 8086 assembler code. It is compatible with the macro + facility found in Microsoft Macro Assembler for the + MS-DOS operating system. The format of the object + modules provided is a subset of the INTEL(R) format, and + may not be compatible with non-Microsoft linkers. + +Q. What does an MS-DOS implementor need to know? + +A. To install MS-DOS, you will need to be familiar with + systems programming in 8086 assembler language. This + means you should have experience in writing device + drivers for disk drives, keyboards, printers, and other + peripherals. + +Q. How long does it take to install MS-DOS? + +A. This depends on whether the low-level I/O routines are + already written. The record time for getting MS-DOS up + and running on a new machine is one weekend. In this + case, all of the low-level routines were in ROM. + Typically, a complete customer-ready MS-DOS + implementation takes two or more months. + + MS-DOS INSTALLATION KIT Page 1-3 + + +Q. Are there any consultants who do MS-DOS implementations? + +A. Microsoft can supply a list of consultants who have done + MS-DOS implementations. Microsoft cannot make any + recommendations regarding the competence of these + consultants. + +Q. Do you recommend that we have an In Circuit Emulator + (ICE) for our machine? + +A. Yes. Since there are no MS-DOS debugging tools that can + be used to debug the boot sequence, an ICE is very + helpful. + + + +1.4 MS-DOS HARDWARE REQUIREMENTS + +To be compatible with the MS-DOS operating system, a machine +must conform to certain hardware characteristics. These +characteristics are as follows: + + + o The processor must be INTEL 8086 compatible. + + o The Interrupt vector locations 20H through 3FH must + be reserved for MS-DOS. + + o Four character device drivers and one block device + driver are required. They must recognize the + MS-DOS device driver call format. + + o An ANSI terminal driver must be implemented. + (MS-DOS sends an ANSI escape sequence to clear the + console.) + + o A logical disk, as described in this document, must + be available to MS-DOS. A disk format table, as + described in this document, should be present in + the first logical sector of each disk. Logical + sectors must be a multiple of 64 bytes in size. + + o Random Access Memory (RAM) should be contiguous + from the point where MS-DOS is located through top + of memory. + + o MS-DOS requires a minimum of 128K of RAM (depending + on IO.SYS size). Microsoft recommends a minimum + configuration of 128K non-video RAM and 192K for + future products. + +The sample BIOS that is provided has been designed to only run on +a machine with the exact architecture of IBM PC family. +If MS-DOS can run on the OEMs hardware using the sample BIOS, then +the hardware is compatible with the IBM PC family architecture. + + MS-DOS INSTALLATION KIT Page 1-4 + +In addition to these minimum requirements, the following +hardware features are recommended for optimum performance as +well as compatibility with new Microsoft products. Features +recommended for performance on 2.0 and higher systems are +starred. + + + o *An interrupt-driven keyboard with a type-ahead + buffer (Interrupt-driven I/O for all devices). + + o *Direct memory access. + + o *Non-interlaced disks. + + o *Disk door locks or a detection mechanism to check + if disks have been changed. + + o Support of standard MS-DOS disk formats. + + o User-addressable bit-mapped video display with + minimum resolution of 640 by 200 pixels. + + o Programmable interval timer. + + o Mouse support. + + o RS-232 and printer interfaces. + + o Minimum 192K RAM memory. + + o A Scroll Lock/Break key that puts a Control-S and + Control-C at the beginning of the keyboard + type-ahead buffer when pressed. + + MS-DOS INSTALLATION KIT Page 1-5 + + +1.5 MS-DOS OVERVIEW + +An MS-DOS implementation requires seven components: + + + 1. The resident device drivers (the IO.SYS file), a + collection of hardware-specific device drivers that + must be written by the OEM. The resident device + drivers are called by MS-DOS to handle I/O + requests. These device drivers may be partly ROM + resident or may be completely RAM resident. + + + 2. The SYSINIT Module(s), (SYSINIT1.OBJ and SYSINIT2.OBJ + in 3.xx and only SYSINIT.OBJ in 2.xx) and SYSIMES.OBJ, + Microsoft-supplied modules which are linked to the + resident device drivers and initialize the system. + The file that contains these device drivers is + named IO.SYS (on the IBM(R) PC, this file is named + IBMBIO.COM). + + + 3. MSDOS.SYS, the hardware-independent disk operating + system supplied by Microsoft. (On the IBM PC, this + file is named IBMDOS.COM.) + + + 4. COMMAND.COM, the command interpreter program that + reads and interprets keyboard input, executes + "built-in" commands like DIR, and initiates + external programs. + + + 5. Bootstrap loader, the OEM-supplied module that + loads the IO.SYS and MSDOS.SYS files into memory. + MSDOS.SYS may optionally be loaded by IO.SYS. + A sample bootstrap loader has been provided with + the OEM kit. This sample bootstrap loader is + compatible with the IBM PC family. + + + 6. A system ROM which may optionally perform + diagnostics on power-up or reset. The system ROM + loads the boot sector into RAM and transfers + control to it. + + + 7. MS-DOS utilities, including FORMAT, for which + Microsoft modules are provided and a + hardware-specific section must be written by the + OEM. NOTE: Refer to the MS-DOS 3.3 specific portions + for use of the hardware independent FORMAT utility. + + + MS-DOS INSTALLATION KIT + + + CONTENTS + +CHAPTER 2 MS-DOS DEVELOPMENT TOOLS + + EDLIN Text Editor 2-1 + + Microsoft Macro Assembler 2-1 + + Microsoft Linker (MS-LINK) 2-2 + + MS-DEBUG 2-2 + + EXE2BIN 2-2 + + FORMAT 2-2 + + + + + + + + + + + + + + CHAPTER 2 + + MS-DOS DEVELOPMENT TOOLS + + + +An assembler, text editor, linker, and other utilities are +required for completing an MS-DOS implementation. We assume +that your development machine has the following standard +utilities: + +EDLIN Text Editor + + The EDLIN text editor provided with MS-DOS for your + development machine may be used to prepare assembler + source files. The version of EDLIN on MS-DOS 2.x and + 3.x release disks is for versions 2.x and 3.x only, and + will not run under MS-DOS 1.x. A third party full screen + text editor (not a word processor) may be more efficient + for manipulating source files. + +Microsoft Macro Assembler + + A complimentary copy of the current Microsoft Macro Assembler + is provided with the MS-DOS installation kit. + The assembler is not actually a part of MS-DOS; it must be + licensed separately if you wish to ship it to your + customers. The Cross-Reference Utility (MS-CREF), + included with Microsoft Macro Assembler, can be used to + make cross-reference listings of assembler programs. + The Microsoft Macro Assembler package will only run + under MS-DOS 2.XX and later operating systems. The + output of the assembler is a relocatable object module + (.OBJ file type) which conforms to a subset of the + INTEL MCS 86 object module format description. Refer + to the MS-DOS Programmer's Reference Manual for ______ ____________ _________ ______ + information on the INTEL MCS 86 object module format + description. + + MS-DOS DEVELOPMENT TOOLS Page 2-2 + + +Microsoft Linker (MS-LINK) + + Your MS-DOS development machine should include a linker + named LINK.EXE. Use LINK.EXE for linking object + modules (.OBJ files) produced by the Microsoft Macro + Assembler. The output of the Linker is a file with an + .EXE format. This is an executable program requiring a + special loader that is part of MS-DOS. Refer to the + MS-DOS Programmer's Reference Manual for details on ______ ____________ _________ ______ + .EXE formats. + +SYMDEB + + SYMDEB.EXE is the MS-DOS symbolic debugger. The debugger + can do absolute disk reads and writes. You may use this + facility to write your bootstrap loader program into + the boot sector. Note that since MS-DOS is not + reentrant, this debugger may not be used to set break + points within the DOS or device drivers. + + +EXE2BIN + + The EXE2BIN.EXE utility supplied with your MS-DOS + development machine must be used for converting output + from the Linker (.EXE files) to a pure binary (core + image) format not requiring a special loader. Note + that only .COM files may execute out of ROM. + +FORMAT + + The FORMAT program (FORMAT.EXE) supplied with your + MS-DOS development machine may be used to format a boot + disk for the target machine, assuming both machines + have compatible media. + +EXEFIX + + EXEFIX is a special purpose utility used for building + SORT. It sets the maximum memory allocation. + + MS-DOS DEVELOPMENT TOOLS + + + CONTENTS + + +CHAPTER 3 INSTALLING MS-DOS + + + + + + CHAPTER 3 + + INSTALLING MS-DOS + + + +If you are using an MS-DOS machine for development and your +target machine will read MS-DOS standard disk formats, +follow these steps to implement MS-DOS. + +NOTE: The steps involved in developing IO.SYS are not necessary + if the sample BIOS provided with the OEM kit is used. + This sample can also be used for technical reference. + + 1. Using a text editor on your development machine, + write the 8086 assembler source code for the + resident device drivers. The resident device + drivers are the hardware-specific routines that + will be accessed by MS-DOS to perform I/O. There + must be a minimum of five device drivers: four ____ + character drivers and one block device driver (the + disk drive on most systems). In addition to the + device drivers, you may want to include some code + for hardware initialization. The source file + should be named IO.ASM and must not contain a STACK + segment. + + For more information, see: + MS-DOS Programmer's Reference Manual ______ ____________ _________ ______ + IO.ASM on the distribution disk + The resident device driver section of this manual + + 2. Use MASM.EXE, the macro assembler provided with + your MS-DOS installation kit to assemble your + device driver code. MASM will create a file called + IO.OBJ, which is in a special object module format + (a subset of INTEL's object module format). + + For more information, see: + Microsoft Macro Assembler Manual (Macro Assembler _________ _____ _________ ______ + section) + + 3. Use LINK.EXE, the Microsoft Linker, to link your + IO.OBJ module to appropriate SYSINIT.OBJ module(s)and the + appropriate SYSIMES.OBJ module. The + modules must be linked in this order: + + 2.xx IO.OBJ+SYSINIT.OBJ+SYSIMES.OBJ + + 3.XX IO.OBJ+SYSINIT1.OBJ+SYSINIT2.OBJ+SYSIMES.OBJ + + The output file should be named IO.EXE. You + INSTALLING MS-DOS Page 3-2 + + + may get the message "Warning, no STACK segment" while + linking the module. This is a warning message and + is normal with some versions of the linker. + + For more information, see: + Microsoft Macro Assembler Manual (Chapter 3 LINK: _________ _____ _________ ______ + A Linker) + + 4. The file created in step 3 is an .EXE file which is + in a special format recognized by the .EXE loader. + Since the .EXE loader is not available at boot + time, the IO.EXE file must be converted to a pure + binary core image file. This is done with the + EXE2BIN utility provided with the MS-DOS release on + your development machine. The EXE2BIN utility must + know exactly where the code will reside in memory + to resolve any FAR references. You will be + prompted for the base address, the absolute segment + address where the code will begin. The resultant + file must be named IO.SYS. EXE2BIN will change the + name when you type the following command line: + + EXE2BIN IO.EXE IO.SYS + +------------------------------------------------------------ +| | +| Note | +| | +| It is the responsibility of the bootstrap loader to | +| locate IO.SYS at the location you specified as the base | +| address. The location itself is arbitrary, since one | +| of the parameters that the resident device driver code | +| passes to SYSINIT is the location of the first device | +| driver. | +| | +|__________________________________________________________| + + For more information, see: + MS-DOS User's Reference Manual (Chapter 3) ______ ______ _________ ______ + + 5. Customize the function key table in DOSMES.ASM. + + 6. Use MSDOSBLD.BAT on the distribution disk to assemble + appropriate object modules and link them with those + already provided to form MSDOS.SYS. + + 7. Write a bootstrap loader program using the text + editor. This step is not necessary if the sample + bootstrap loader included in the OEM kit is used. + The sample bootstrap loader can also be used for + technical reference. + Name this file BOOT.ASM. We assume that you have + a system ROM which will load the first sector of + the system disk into memory when you turn + on or reset the compter. Ideally, the bootstrap + loader fits into the first sector of the boot disk. + In addition to the loader, information relating to + the BIOS Parameter Block (BPB) should be kept in the + boot sector of the disk. The format of the boot + INSTALLING MS-DOS Page 3-3 + + + sector is described in Chapter 4. + + The bootstrap loader loads IO.SYS and MSDOS.SYS into + memory. MS-DOS can be located any place in memory + above IO.SYS. (IO.SYS can alternately be used to + load MSDOS.SYS.) Loading IO.SYS and MSDOS.SYS is + simple because these two files must always be the + first files on the disk. This means that a + bootstrap loader could simply load a series of + consecutive sectors into memory. Your bootstrap + loader may also read in the first sector of the + directory before it loads IO.SYS to verify that + these files are the first files on the disk. + + For more information, see: + MS-DOS Programmer's Reference Manual ______ ____________ _________ ______ + (Chapter 2) + MS-DOS Adaptation Guide (Chapter 4) ______ __________ _____ + + 8. Assemble, link, and convert to binary (using + EXE2BIN) the BOOT.ASM file to produce BOOT.BIN. + + 9. Format a non-system disk using your MS-DOS + development machine. + + 10. Using the MS-DOS Copy command, copy IO.SYS, + MSDOS.SYS, and appropriate version of + COMMAND.COM to the formatted disk. + + 11. Using DEBUG.COM on the development machine, load + BOOT.BIN and write it to the first sector of the + formatted disk. This can be done as follows: + + + DEBUG + -N BOOT.BIN + -L (loads BOOT.BIN) + -W 100 0 0 1 (writes BOOT.BIN to drive 0 + sector 0) + -Q + + Note: More operations may be required depending on + how your boot program is organized. + + For more information, see: + Microsoft Macro Assembler Manual (Chapter 4 SYMDEB: _________ _____ _________ ______ + A Symbolic Debug Utility + + The formatted disk should now be bootable by your + system. + INSTALLING MS-DOS Page 3-4 + + + 12. Write the source code for the hardware-specific part + of the FORMAT program. The MS-DOS 3.3 version of the + FORMAT utility has been structured so that the hardware + specific portions have been placed solely in IO.SYS. + Minimal work should be required for the OEM use of the + MS-DOS 3.2 FORMAT utility. + Assemble and link this to the FORMAT.OBJ and FORMES.OBJ + files supplied by Microsoft. The modules must be linked + in the following order: + + 2.XX: FORMAT.OBJ+FORMES.OBJ+OEMFOR.OBJ + + + where OEMFOR.OBJ is your hardware-specific module. + Use EXE2BIN to convert the OEMFOR.EXE file produced + to FORMAT.COM. + + 3.XX: FORMAT.OBJ+FORPROC.OBJ+FORMES.OBJ+OEMFOR.OBJ+PRINTF.OBJ + + + where OEMFOR is your hardware-specific module. + Although the PRINTF.OBJ module is the last module + specified, it does not follow the OEM module in the + memory image. + + For more information, see: + + MS-DOS Adaptation Guide (Chapter 7) ______ __________ _____ + OEMFOR.ASM Disk file of sample OEM FORMAT module + MS-DOS User's Reference Manual (Format Command, ______ ______ _________ ______ + Chapter 3) + MS-DOS Programmer's Reference Manual (Chapter 3) ______ ____________ _________ ______ + + 13. Install the MS-DOS OEM serial number. + + For information on how this is done, refer to the README.DOC + on the distribution diskette. + + 14. Modify SORTMES.ASM as appropriate. + + 15. Build SORT executable with SORTBLD.BAT. + + 16. Modify PRINT source modules as appropriate + + 17. Build PRINT executable with PRINTBLD.BAT + + + + INSTALLING MS-DOS + + + CONTENTS + +CHAPTER 4 DISK STRUCTURE AND BOOTSTRAP LOADING + + 4.1 Reserved Area 4-1 + + 4.2 File Allocation Table 4-2 + + 4.3 MS-DOS File System Limits 4-4 + + 4.3.1 Disk Format Identification 4-6 + + 4.4 The role of the Boot Sector 4-7 + + + + + + + + + + + + + + + CHAPTER 4 + + DISK STRUCTURE AND BOOTSTRAP LOADING + + + +MS-DOS disks are divided into four logical data areas. + + 1. Reserved sectors (boot sector) + + 2. File Allocation Tables + + 3. Root directory + + 4. Data area which may include subdirectories + as well as program and data files + +When creating non-standard disks or non-removable media +(such as hard disks), the logical disk which your device _______ +driver presents to MS-DOS must conform to the above +standard. The physical layout may be completely different. ________ +For example, you may want to implement a partitioning scheme +on the hard disk so that it can be shared by multiple +operating systems. In this case, either the device driver +or firmware maps the physical structure into an MS-DOS +logical layout. The MS-DOS file system can even be +logically implemented within another operating system's file +structure. + + + +4.1 RESERVED AREA + + +The reserved area is the first part of the disk and is +typically used for boot purposes. Some machines not +specifically designed for MS-DOS may use track 0 for special +purposes (it may even have a different sector size than the +rest of the disk). In this case, the entire track should be +marked as reserved so that the device driver will map +MS-DOS's logical sector 0 to the beginning of track 1 +instead of track 0. + +It may be difficult to fit the required boot information +into a single sector. Note that disk formats using 128- or +256-byte sectors and without any firmware support may + DISK STRUCTURE AND BOOTSTRAP LOADING Page 4-2 + + +require several sectors. + + + + +4.2 FILE ALLOCATION TABLE + +The File Allocation Table (FAT) is the most important data +structure on the disk. Two copies are usually kept at the +OEM's option. (Two copies need not be kept for a virtual +RAM disk because, in this case, the media cannot be damaged.) +MS-DOS files are allocated in "allocation units" or "clusters". +Each cluster is some number of sectors. The number of sectors +per allocation unit must be a power of 2 which fits in a byte. +Thus, the complete list of possible values is: + 1, 2, 4, 8, 16, 32, 64, 128. + +The FAT is a physical map of the allocation units in the +data area of the disk. There is one FAT entry for each +allocation unit on the disk plus two reserved entries at the +beginning of the FAT. The entries serve as a linked list of +pointers. For a complete discussion of FAT structure, refer +to Chapter 3 of the MS-DOS Programmer's Reference Manual. ______ ____________ _________ ______ + +FAT size can be determined by the following formula: + + + FAT = Q * ( T - R - D + 2) + -------------------- + Q * N + ( A * S ) + + +FAT is the number of sectors needed for one FAT and will + usually not be an integer. It must be rounded up to + the next integer value. + +Q is the number 1.5 for 12-bit FAT entries and 2.0 + for 16-bit FAT entries. + +T is the total number of sectors on the disk. + +R is the number of reserved sectors. + +D is the number of root directory sectors (there must + be 32 bytes for each directory entry). + +A is the number of sectors per cluster or allocation + unit. + +N is the number of file allocation tables on the disk. + +S is the number of bytes per sector. + + +MS-DOS 3.x can use 16-bit FAT pointers whenever the total + DISK STRUCTURE AND BOOTSTRAP LOADING Page 4-3 + + +number of clusters on the disk exceeds 4085 (=4096-10; two +are reserved at the beginning, and eight are reserved at the +end). Although the FAT entries are 16 bits, the present +software only works with 15 bits (up to 32766 clusters). + +____________________________________________________________ +| | +| Important | +| | +| Be careful when reducing cluster size as it can cause | +| significant performance degradation. Reducing cluster | +| size results in increased fragmentation, a larger FAT | +| to buffer (increasing the number of disk accesses); and | +| increasing the FAT entries from 12 to 16-bit expands | +| the FAT size by 33%. | +| | +|__________________________________________________________| + +The FORMAT program will create a proper FAT. The FAT has an +entry for each allocation unit in the data area of the disk. +It also contains two extra entries at the beginning. These +represent reserved clusters. The first cluster of the data +region of the disk is cluster 2. + +The first (0th cluster) of these two reserved entries can be +used to indicate the format of the disk. Only the low 8 +bits are used, and this byte is often referred to as the +FATID byte. The high 4 bits (high byte if a 16-bit FAT) of +this first cluster are all set (=1). + +The FATID byte is restricted to be in the range 0F8H to +0FFH, inclusive (8 possible values). The FATID byte is also +an end-of-file (EOF) mark. If a FAT chain contains a zero +entry (which should never happen), it will point to this EOF +marker. The second (1st cluster) of these two reserved +entries is always 0FFFH (0FFFFH for a 16-bit FAT), which is +an end-of-file mark. + + DISK STRUCTURE AND BOOTSTRAP LOADING Page 4-4 + + +Figure 4.1 illustrates the first two clusters of a 12-bit +File Allocation Table. + + + FAT BYTE 00 01 02 03 + XXH XXH XXH XXH----->Byte 3 + || || || + Middle 4 bits | || High and middle 4 bits of + of cluster 0 | || cluster 1 (always F) + | | High 4 bits of + Low 4 bits of | cluster 0 (always F) + cluster 0 | + | | Low 4 bits of cluster + |------------------| 1 (always F) + | + FATID BYTE + + + +Figure 4.1. First Two Entries of the FAT (12-bit) + + + + + +4.3 MS-DOS FILE SYSTEM LIMITS + +The following figure shows the file storage limitations +within MS-DOS. + + | MS-DOS 2.x | Both | MS-DOS 3.x + _______________|______________|_____________|_______________ +|FAT entry size |12 bits | |12 or 16 bits | +|Sector size | |64b-32Kb | | +|No. of Sectors | |Max of 64K | | +|Cluster size | |1-128 sectors| | +|Max. disk size |4085 clusters |64K sectors |32766 clusters| +|Max. file size | |Disk size | | +________________|______________|_____________|______________| + +All ranges in the table are inclusive. As well as the above +limitations, there are also various limits as noted below: + + + 1. FAT entry size. + This is the only file storage limit difference + between MS-DOS 2.XX and 3.XX; it significantly + increases the maximum number of clusters and hence + the maximum disk size allowed. MS-DOS 3.x + determines whether a 12- or 16-bit FAT is in use by + calculating the number of disk clusters from the + BPB. If the number of clusters is less than or + equal to 4085, a 12-bit FAT is in use; otherwise, + a 16-bit FAT is assumed. A 16-bit FAT cannot be + used if the total number of clusters is less than + DISK STRUCTURE AND BOOTSTRAP LOADING Page 4-5 + + + or equal to 4085. + + Some existing MS-DOS applications (such as copy + protection schemes and disk maintenance utilities) + bypass MS-DOS and manipulate the FAT directly. + These existing applications will cause problems + with 16-bit FATs until the applications are updated + to recognize the 16-bit FATs. + + 2. Sector Size. + Must be a multiple of 64 bytes. + + 3. No. of Sectors. + The number of sectors is limited to 64K because + 16-bit sector numbers are passed to the device + drivers. + + 4. Cluster Size. + The cluster size (bytes/cluster = sectors/cluster * + bytes/sector) must be less than 64K because MS-DOS + uses 16-bit arithmetic. + + Sectors/Cluster must be a power of 2 in the range + 1-128. + + Excessively small cluster sizes can seriously + degrade performance. Refer to the MS-DOS ______ + Programmer's Reference Manual for sample disk ____________ _________ ______ + formats. + + 5. Max. Disk Size. + MS-DOS 2.XX: Lesser of 4085 clusters or 64K sectors + (For example, 64K*512 byte sectors = 32Mb disk). + MS-DOS 3.XX: Lesser of 32766 clusters or 64K + sectors. + + The total number of sectors is limited to 64K due + to the use of 16-bit arithmetic. + + The maximum number of possible clusters is + calculated by the following: + + FAT entry size + (2 -10 Reserved) + + Reserved: 8 FAT ID/EOF (F8-FF) + 2 RESERVED (0,1) + + ------------------------------------------------------------ + | | + | Note | + | | + | However, some MS-DOS utilities (such as Chkdsk and | + | Recover) restrict the total FAT size to 32K entries, | + DISK STRUCTURE AND BOOTSTRAP LOADING Page 4-6 + + + | hence the MS-DOS 3.x limit of 32,766 clusters and not | + | 65,525 (216-11). | + | | + |__________________________________________________________| + + There are 10 MS-DOS reserved FAT entries; two at + the front of the FAT, and eight at the end: + DISK STRUCTURE AND BOOTSTRAP LOADING Page 4-7 + + + 4086 = 4K -10 + 32766 = 32K -2 + + The 8 reserved clusters + are in the range 65528-65536. + + 6. Max. File Size. + Files cannot be split across disks; therefore, the + maximum file size is normally the maximum disk + size. The file size is also restricted by a 32-bit + file pointer. This means that the maximum possible + file size is 4 gigabytes: + + 32 + 4 million K, 2 -1 + + + + +4.3.1 Disk Format Identification + +Beginning with MS-DOS 2.0, Microsoft is promoting the use of +a media descriptor table in the boot sector. This table +contains both a physical description (number of sectors, +sides, tracks, etc.) and a logical description (number of +FATs, directory entries, etc.) of the disk layout. The +media description table allows MS-DOS to accommodate future +floppy disk formats, or formats defined by other +manufacturers but not generated by your FORMAT utility. +Your device driver should assume that the media description +table exists if the first byte of the boot sector is the +first byte of a 3-byte (near) jump or a 2-byte jump. + DISK STRUCTURE AND BOOTSTRAP LOADING Page 4-8 + + +4.4 THE ROLE OF THE BOOT SECTOR + +Typically, the system ROM will load the reserved (boot) +sector or sectors into memory at power-up or restart. We +recommend that the boot sector do the following: + + + 1. It should read the first sector of the directory + and verify that the first two files on the disk are + IO.SYS and MSDOS.SYS, in that order. + + You may choose to have your FORMAT utility generate + different boot sectors for each disk format. Or, + you may create a universal boot sector to read the + media description table and determine where to find + the first directory sector both logically and + physically. + + + 2. If the boot code does not find the MS-DOS files in + the directory, then the boot sector should prompt + the operator that an attempt has been made to boot + from a non-bootable disk. You determine how the + user should continue ("Strike any key" or "Turn + power off"). + + + 3. The boot sector must read in the IO.SYS and + MSDOS.SYS files. Alternatively, the boot sector may + read in only IO.SYS, and IO.SYS may then read in + MSDOS.SYS. Only IO.SYS needs to be contiguous on the + disk. + + The boot sector must know or calculate where those + files physically begin on the disk (right after the + last directory sector) and how long they are + (contained in directory entries). You must code + (or calculate) the location at which they should be + loaded into memory in the boot sector. + + + 4. The boot sector must transfer control to your entry + point in IO.SYS. + + The boot sector does not load COMMAND.COM, as it + will be loaded by SYSINIT. + + +The SYS command allows users to transfer the operating +system onto a formatted disk that contains no files or +contains an old version of the operating system of equal or +greater size. For the MS-DOS 2.XX version on the IBM PC, the +SYS command was modified to transfer MS-DOS 2.XX system files +onto old 1.XX disks. The new MSDOS.SYS can be placed on the +disk in a non-contiguous format. (IO.SYS is still +contiguous because the new IO.SYS is smaller than the + DISK STRUCTURE AND BOOTSTRAP LOADING Page 4-9 + + +combined sizes of the old IO.SYS and MSDOS.SYS.) The boot +sector is only responsible for loading IO.SYS, although it +must check that MSDOS.SYS is the second file on the disk. +Therefore, IO.SYS may load a non-contiguous MSDOS.SYS. + +The logic to facilitate checking through the FAT entries +must be added to IO.SYS because the logic normally resides +in the not-yet-loaded MSDOS.SYS. The logic resides in the +installation part of IO.SYS so that it will be overwritten +when MSDOS.SYS is loaded. This technique should only be +used to use the SYS command to transfer a new, bigger MS-DOS +onto an old disk. It is not useful if you do not have old +disks to support in the field. Note that the various FAT +entries for a non-contiguous MSDOS.SYS may reside in +different FAT sectors making it necessary to read more than +just the first FAT sector into memory. + +There is an example of a boot sector on the OEM Sample MS-DOS +Implementation Diskette. + DISK STRUCTURE AND BOOTSTRAP LOADING + + + CONTENTS + +CHAPTER 5 RESIDENT DEVICE DRIVERS + + 5.1 Introduction 5-1 + + 5.2 Bit 4 5-3 + + 5.3 Installation of Device Drivers 5-5 + + 5.4 The CLOCK Device 5-5 + + 5.5 INIT (Command Code 0) 5-6 + + 5.6 Media Check 5-7 + + 5.7 DMA Boundary Violation 5-9 + + + + + + + + + + + + + + CHAPTER 5 + + RESIDENT DEVICE DRIVERS + + + +------------------------------------------------------------ +| | +| Note | +| | +| Chapter 2, "Device Drivers," in the MS-DOS Programmer's | +| Reference Manual contains a description of MS-DOS | +| device drivers. Additional information applicable to | +| OEM is included here. | +| | +------------------------------------------------------------ + + + +5.1 INTRODUCTION + +The IO.SYS file is composed of the "resident" device +drivers. This forms the MS-DOS Basic Input Output System +(BIOS), and these drivers are called upon by MS-DOS to +handle I/O requests initiated by application programs. + +One of the most powerful features of MS-DOS is the ability +to add new devices such as printers, plotters, or mouse +input devices without rewriting the BIOS. The MS-DOS BIOS +is "configurable;" that is, new drivers can be added and +existing drivers can be pre-empted. Non-resident device +drivers may be easily added by a user at boot time via the +"DEVICE =" entry in the CONFIG.SYS file. In this section, +these non-resident drivers are called "installable" device +drivers to distinguish them from drivers in the IO.SYS file, +which are considered the resident drivers. + +At boot time, a minimum of five resident device drivers (four +character devices and one block device) must be present. +These drivers are in a linked list: the header +of each one contains a DWORD pointer to the next. The last +driver in the chain has an end-of-list marker of -1, -1 (all +bits on). + +Each driver in the chain has two entry points: the strategy +entry point and the interrupt entry point. MS-DOS 2.XX/3.XX +does not take advantage of the two entry points: it calls + RESIDENT DEVICE DRIVERS Page 5-2 + + +the strategy routine, then immediately calls the interrupt +routine. + +The dual entry points facilitate future multitasking +versions of MS-DOS. In multitasking environments, I/O must +be asynchronous; to accomplish this, the strategy routine +will be called to (internally) queue a request and return +quickly. It is then the responsibility of the interrupt +routine to perform the I/O at interrupt time by getting +requests from the internal queue and processing them. When +a request is completed, it is flagged as "done" by the +interrupt routine. MS-DOS periodically scans the list of +requests looking for those that are flagged as done, and +"wakes up" the process waiting for the completion of the +request. + +When requests are queued in this manner, it is no longer +sufficient to pass I/O information in registers, since many +requests may be pending at any time. Therefore, the MS-DOS +2.x/3.x device interface uses "packets" to pass request +information. These request packets are of variable size and +format, and are composed of two parts: + + + 1. The static request header, which has the same + format for all requests. + + 2. A section that has information specific to the type + of request. + + +A driver is called with a pointer to a packet. In +multitasking versions, this packet will be linked into a +global chain of all pending I/O requests maintained by +MS-DOS. + +The 2.XX and 3.XX versions of MS-DOS do not implement a +global or local queue. Only one request is pending at any +one time. The strategy routine must store the address of +the packet at a fixed location, and the interrupt routine +(which is called immediately after the strategy routine) +should process the packet by completing the request and +returning. It is assumed that the request is completed when +the interrupt routine returns. + +To make a device driver that SYSINIT can install, a .BIN +(core image) or .EXE format file must be created with the +device driver header at the beginning of the file. The link +field should be initialized to -1 (SYSINIT fills it in). +Device drivers that are part of the BIOS should have their +headers point to the next device in the list and the last +header should be initialized to -1,-1. The BIOS must be a +BIN (core image) format file produced by using the utility +EXE2BIN. + +.EXE format installable device drivers may be used in + RESIDENT DEVICE DRIVERS Page 5-3 + + +non-IBM versions of MS-DOS before 3.0. The reason for this +restriction is that on the IBM PC, the .EXE loader is located +in COMMAND.COM, which is not present at the time that installable +devices are being loaded. + +The attribute field and entry points must be set correctly. +If the device is a character device, the name field must be +filled in. (This name can be any 8-character legal +filename). If it is a block device, SYSINIT will fill in the +correct unit count. SYSINIT always installs character +devices at the start of the device list, so if you want to +install a new CON device, simply name it CON. The new one +will be placed ahead of the old one in the list and will +pre-empt the old one because the search for devices stops on +the first match. + +Be sure to set the standard input (sti) and standard output +(sto) bits on a new CON device. + +------------------------------------------------------------ +| | +| Note | +| | +| Since SYSINIT may install the driver anywhere, be | +| careful when coding FAR memory references. You | +| should NOT expect that your installable driver will be | +| located in the same place every time. This does not | +| apply for the resident device drivers. | +| | +|__________________________________________________________| + + + + +5.2 BIT 4 + +In the MS-DOS Programmer's Reference Manual, bit 4 of the ______ ____________ _________ ______ +device driver header format is defined as reserved. It +actually has special meaning. + +Bit 4, the special bit, applies to CON drivers. The new +interface supports many new features, but it is slower than +MS-DOS 1.x if old style "single-byte" system calls are made. +To make most efficient use of the interface, all +applications should block their I/O as much as possible. +For example, you should make one XENIX-style system call to +output x number of bytes rather than x system calls to +output one byte each. + + RESIDENT DEVICE DRIVERS Page 5-4 + + +Putting a device channel in raw mode provides an even faster +way to output characters. (See the Glossary for an +explanation of "raw" mode.) Bit 4, has been implemented to +alleviate the CON output speed problem for older programs +that use system calls 01H to 0BH to output large amounts of +data. If this bit is 1, the device is CON and an Interrupt +29H has been implemented, where the 29H handler is defined +as follows: + + CONSOLE OUTPUT via INT 29H handler + + Input: Character in AL + + Function: Output the character in AL + to the screen at the current + cursor location. + + Output: None + + Registers: All registers except BX must be + preserved. No registers except + AL have a known or consistent + value. + + +If a character device implements the special bit, the driver +must install an address at the correct location in the +interrupt table for Interrupt 29H. Only one device driver +can have the special bit set in the system. There is no +check to ensure this state. + +____________________________________________________________ +| | +| Warning | +| | +| This feature may not be supported in future versions of | +| MS-DOS. Any application (not device driver) that uses | +| Interrupt 29H directly will not work on future versions.| +| In addition, the console device driver must be tested | +| with bit 4 not set to ensure that it will work with such | +| future versions of MS-DOS. | +| | +____________________________________________________________ + +The headers of resident drivers should point to the next +device in the list and the last header should be initialized +to -1,-1. IO.SYS must be a .COM format file. + + RESIDENT DEVICE DRIVERS Page 5-5 + + +5.3 INSTALLATION OF DEVICE DRIVERS + + +MS-DOS 2.XX/3.XX allows new device drivers to be installed +dynamically at boot time. This is accomplished by the +SYSINIT module(s) supplied by Microsoft, which read(s) and +processes the CONFIG.SYS file. The resident driver source +file (IO.ASM) is assembled and linked to the appropriate SYSINIT +module(s) and SYSIMES.OBJ. The resultant .EXE file must +be converted via EXE2BIN to create the file IO.SYS. This +should be the first file that appears on the system disk. + +When block drivers are installed, the logical drive letters +are assigned in list order; thus, the driver that will have +logical A must be the first unit of the first block device +in the list. The order of character devices is also +important. There must be at least four character devices +defined at boot time. The first four character devices must +be as follows: + + + 1. Standard input, standard output, and standard error + output (CON) + + 2. Standard auxiliary input and output (AUX) + + 3. Standard list output (PRN) + + 4. Date/time (CLOCK) + +The linked list of device drivers must look like this: + + ->CON->AUX->PRN->CLOCK->any other block or + character devices + + + + +5.4 THE CLOCK DEVICE + + +The CLOCK device is used by MS-DOS 2.XX/3.XX for marking file +control blocks and directory entries with date and time as +well as providing date/time services to application +programs. It is unique in that MS-DOS will read or write a +6-byte sequence which encodes the date and time. A write to +this device will set the date and time and a read will get +the date and time. + +Figure 5.1 illustrates the binary date and time format used +by the CLOCK device. + RESIDENT DEVICE DRIVERS Page 5-6 + + + + + byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 ++--------+--------+---------+--------+--------+---------+ +| | | | | | | +|days since 1-1-80| minutes | hours | sec/100| seconds | +|low byte|hi byte | | | | | ++--------+--------+---------+--------+--------+---------+ + + Figure 5.1. CLOCK Device Format + + + +5.5 INIT (COMMAND CODE 0) + +One of the functions defined for each device is INIT. This +routine is called only when the device is installed. It is +used for initializing character and block devices. + +Figure 5.2 illustrates the format of INIT. + + + +------------------------------------+ + | 13-BYTE Request Header | + +------------------------------------+ + | BYTE # of units | + +------------------------------------+ + | DWORD Break Address | + +------------------------------------+ + | DWORD Pointer to BPB array | + | (not set by character devices) | + +------------------------------------+ + + Figure 5.2. INIT Format + + +For resident character devices:___ ________ _________ _______ + +No parameters are passed, and none are returned. + + +For resident block drivers:___ ________ _____ _______ + +Unlike character device drivers, block device drivers must +return a number of parameters. The following data are +returned: + + + 1. The number of units defined by this block device + driver. This is used to determine logical device + names. If the current maximum logical device + letter is F at the time of installation, and the + INIT routine returns 4 as the number of units, then + those units will have the logical names G, H, I and + J. This mapping is determined by the position of + RESIDENT DEVICE DRIVERS Page 5-7 + + + the driver in the device list and the number of + units defined by the device (stored in the first + byte of the device name field). You must return + this number at offset 13D in the INIT call, even + though the number of units is stored in the device + header. + + 2. A DWORD pointer to an array of WORD offsets to BPBs + (BIOS Parameter Blocks). There must be one entry + for each unit defined by the device driver. If the + device driver defines two units, then the DWORD + pointer points to the first of two one-word offsets + which, in turn, point to BPBs. If both BPBs are + the same, this will allow you to save space by + entering two offsets to the same location. + + +The BPB is used by MS-DOS to create an internal DOS +structure. The BPBs that are returned by the resident +device drivers are scanned to determine the largest sector +size. This number is used to set the cache buffer size. + +Installable block devices cannot have larger sector sizes +than those defined by the resident drivers. For this +reason, you may want to use dummy BPBs to reserve space. +Use an invalid media byte so that when you later report the +correct BPB for the unit. MS-DOS will build the correct +internal DOS structure for the particular drive unit. + + + +5.6 MEDIA CHECK + +The MEDIA CHECK function is called when there is a pending +drive access call other than a file read or write (i.e access +to the "FILENAME space" - Open, Close, Get_disk_size, INT 25H, +INT 26H, etc.). Its purpose is to determine whether the media +in the drive has been changed. Note that the previous media ID +byte is passed to the device driver. Although the old media ID +byte is the same as the new one, the disk may have been changed +and a new disk may be in the drive; therefore, the FAT, and +directory and data sectors for the unit are invalid. + +MS-DOS 3.XX imposes stricter conditions than MS-DOS 2.XX on +when media changes are allowed. This can lead to MEDIA +CHECK routines that seemed to work correctly under MS-DOS +2.XX causing problems under MS-DOS 3.XX. + +MS-DOS performance is greatly improved if MEDIA CHECK uses a +doorlock or some other detection method so that it can +guarantee that no disk change has occurred; then MS-DOS +does not have to reread the FAT before each directory +access. + +MEDIA CHECK can directly use the door-lock mechanism to +return "Disk not changed." However, the door-lock mechanism + + + + +RESIDENT DEVICE DRIVERS Page 5-8 + + +indicating that the door has been opened does not +necessarily mean that the disk has been changed, since the +user could have reinserted the same disk. MEDIA CHECK +routines that return "Disk has been changed" just because +the door has been opened will cause problems under MS-DOS +3.x, but not under MS-DOS 2.XX. + +The recommended behavior for MEDIA CHECK is to return as +follows: + + Disk has not been changed - whenever the door lock + indicates that the door + has not been opened + + Don't know - under all other + circumstances + +It is possible for MEDIA CHECK to try to determine whether a +disk has really been changed by checking the Volume ID; +however, many disks have no Volume ID. Therefore, it is +safer and quicker for MEDIA CHECK to simply return "Don't +know." The action that MS-DOS takes depends on the state of +its internal file storage buffers. In general, if "Don't +know" is returned when MS-DOS has data in its internal +buffers (data that needs to be written out), MS-DOS will +assume no disk change has occurred. Otherwise, with empty +buffers or all buffers "clean", MS-DOS assumes the disk has +been changed. + +The possible problems caused by an incorrect MEDIA CHECK +routine can be checked as follows: + + 1. Load MS-DOS 3.XX + 2. Ensure the disk is write-protected + 3. COPY FILE1 FILE2 + 4. Write Protect Error from MS-DOS + 5. Remove the write protection from the disk + 6. Reinsert the disk in the drive + 7. Press "R" to cause MS-DOS to retry + 8. Copy success message + +If an incorrect MEDIA CHECK routine is in use, the Dir +command will show FILE2 with a size of zero bytes, and +Chkdsk will report "lost clusters." Note that the copy +process always returns the success message even with an +incorrect MEDIA CHECK routine. + +The above test should also be repeated with a "Drive Not +Ready" error condition instead of the Write Protect error. +The same symptoms will be displayed. + +For more information on MEDIA CHECK, refer to the MS-DOS ______ +Programmer's Reference Manual.____________ _________ _______ + RESIDENT DEVICE DRIVERS Page 5-9 + +5.7 DMA BOUNDARY VIOLATIONS + +Some OEMs check for any DMA boundary violations on disk +operations. If a DMA boundary violation error is detected +then action is taken to prevent this error from being +reported to the DOS. The sample IO.SYS handles the problem in +the following way. The operation is tried and if a DMA boundary +violation is reported, then a flag (in this case bl) is set +to indicate that we need to do a memory swap to avoid the +boundary problem. The sector of data that causes the DMA +boundary violation is transfered into an internal buffer +that belongs to IO.SYS and then is copied into the buffer +specified in the original request. + +In other words, the request is broken into several pieces +consisting of a request for the data up to the DMA boundary +violation, then the one sector of data that causes the DMA boundary +violation (in the sample IO.SYS SwapMemory routine is responsible +for doing this), and then the rest of the request as specified +by the original disk operation. + +Applications do not depend on this feature in any direct way. +However, if you do not implement the DMA boundary checking then +it would be possible for an application to get an INT24 error because +of the DMA boundary problem and thus behave differently +depending on how the BIOS was implemented. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CHAPTER 6 SYSINIT AND MS-DOS INITIALIZATION + + 6.1 Introduction 6-1 + + 6.2 The Role of SYSINIT 6-3 + + 6.3 COMMAND.COM 6-5 + + + + + + + + + + + + + + CHAPTER 6 + + SYSINIT AND MS-DOS INITIALIZATION + + + +6.1 INTRODUCTION + + +In addition to implementing the resident drivers and +performing any hardware initialization, the IO.ASM code must +initialize certain external variables. These variables are +declared public in the SYSINIT module(s) to which the IO.OBJ +module is linked. The public variables and their functions +are described below. + +CURRENT_DOS_LOCATION WORD + +This is the paragraph location where the bootstrap loader +(or, optionally, IO.SYS) has loaded MSDOS.SYS into memory. +Typically, MSDOS.SYS is located immediately after IO.SYS. + +FINAL_DOS_LOCATION WORD + +Since SYSINIT immediately relocates itself to high memory, +there will be a hole right after the resident drivers. By +telling SYSINIT the paragraph where you want it to relocate +MSDOS.SYS, you can fill up this hole plus overlay any code +that IO.SYS used for hardware initialization at boot time. +SYSINIT will move MSDOS.SYS down to this location, +conserving space. This location also defines where memory +starts for MS-DOS. + +DEVICE_LIST DWORD + +IO.SYS must tell SYSINIT where the linked list of device +drivers begins. This is the location of the CON device +driver header; the information is passed to MS-DOS so that +the drivers can be accessed. + SYSINIT AND MS-DOS INITIALIZATION Page 6-2 + + +MEMORY_SIZE WORD + +This word is the paragraph number of the highest location in +RAM. If you do not initialize MEMORY_SIZE, SYSINIT will do +a memory scan to determine the amount of memory. It does +this by reading every 16 bytes starting at 32K, writing an +arbitrary pattern, reading it back for a match, and +returning the original value. It stops when it gets a +mismatch. If your system has parity memory, you must +declare this value, since writing to nonexistent memory will +cause a parity error. + +MS-DOS should be implemented in systems with contiguous +memory. + +DEFAULT_DRIVE BYTE + +If you can boot MS-DOS from several drives, you must tell +SYSINIT which drive you booted from so it can find +CONFIG.SYS and COMMAND.COM. This variable should be set as +follows: drive A = 1, drive B = 2, etc. If DEFAULT_DRIVE +is not set, the default drive (drive A) is assumed. + +BUFFERS BYTE + +This is the default number of sector buffers for the system. +The BUFFERS value may be overridden by the user in the +CONFIG.SYS file. On versions of MS-DOS up to 3.1, the default +number of buffers is 2. On versions of MS-DOS after 3.1, +3 buffers will be allocated if there is a floppy drive in the +hardware configuration with a capacity greater than 360KB. +Beginning with 3.3, if memory size is greater than 128K, then +5 buffers will be allocated, and if memory is greater than +256K 10 will be allocated; if memory is greater than 512K, 15 +buffers will be allocated. +The value specified for the number of buffers must be greater +than or equal to 1. + +FILES BYTE + +This is the default number of open files that system calls +2FH-62H can access. This value may be overridden by the +user in the CONFIG.SYS file. Its default setting in SYSINIT +is 8. Values of less than 5 are ignored. + +The entry point in SYSINIT should be defined as a FAR label +in IO.SYS as follows: + + EXTRN SYSINIT:FAR + +After IO.SYS code has performed any hardware initialization +and has set the above external variables, it should do a FAR +jump to this label. + + SYSINIT AND MS-DOS INITIALIZATION Page 6-3 + + +You must provide a FAR procedure in the IO.ASM code which is +not subject to being overlayed when SYSINIT relocates +MS-DOS. This procedure is called RE_INIT. It should be +declared as follows: + + + + RE_INIT: PROC FAR + ........ + ........ + RET + RE_INIT ENDP + + + +The RE_INIT procedure is called by SYSINIT after MS-DOS is +installed. On entry, DS:0 points to a 100H-byte program +segment prefix which represents the Program Segment Prefix +of SYSINIT and IO.SYS taken together. This is not a normal +program because no memory is allocated to it; therefore, if +you allocate and load or Exec, you may overlay this block. +SYSINIT is located in the top 10K of memory. Do not write __ ___ _____ +there. The space above the 100H byte header at DS:100 is_____ +available for temporary use during RE_INIT. + +The RE_INIT routine can be used to perform functions such as +to print headers and read files, and it is handy for IO.SYS +debugging. If you don't need to use this procedure, simply +do a return (RET). Note that starting with MS-DOS 3.XX, +RE_INIT may not use FCB system calls. + +------------------------------------------------------------ +| | +| Warning | +| | +| RE_INIT must not change any registers or flags. | +| | +|__________________________________________________________| + + +Beginning with MS-DOS 3.2, another FAR procedure must be provided in +IO.ASM. The name of this procedure is STACKINIT. +The purpose of this procedure is to initialize a hardware stack +switching algorithm. If some of the hardware interrupt handlers in the +ROM BIOS of the OEM hardware system are stack intensive, then +this initialization routine would be used to direct the processing +of the hardware interrupt handlers to another portion of code in +IO.ASM. This code will save the current stack setup and switch stacks to +an internal space on occurrence of a hardware interrupt. +When the stack has been switched the original interrupt handler +is called. The rest of the interrupt handling will use the internal +stack and not the stack that was in use when the interrupt occurred. +When the interrupt handler returns the stack is set to its original +state. +The advantage of this feature is that there is greater system reliability +since a dedicated stack space is being used for interrupt handling. +The OEM should determine which hardware interrupt handlers are stack +intensive and redirect only those interrupts to the stack switching code +in IO.ASM. +This procedure is similar to the FAR procedure RE_INIT in that the code +is not subject to being overlayed when SYSINIT relocates MS-DOS. +The procedure STACKINIT should be declared in the same fashion as RE_INIT. +After MS-DOS is installed, SYSINIT calls the procedure STACKINIT. If this +procedure is not going to be used, then simply do a return or the OEM +can assemble SYSINIT with the conditional STACKSW set to FALSE. On entry +to this routine, there are three data variables that are available. +These pieces of data reside in the SYSINIT segment. The following +declarations should be made in IO.ASM to access these variables. + + SYSINITSEG SEGMENT PUBLIC 'SYSTEM_INIT' + EXTRN STACK_ADDR:DWORD + EXTRN STACK_SIZE:WORD + EXTRN STACK_COUNT:WORD + SYSINITSEG ENDS + +These variables are set by SYSINIT and can be changed by using the +STACKS option in CONFIG.SYS. The full syntax of the STACKS option is: + + STACKS=STACK_COUNT,STACK_SIZE + + where + STACK_COUNT is the number of stacks + (range 8 to 64, default 9) + STACK_SIZE is the stack size + (range 32 to 512 bytes, default 128) + +The variable STACK_ADDR is the FAR address of the space that SYSINIT +has allocated for the internal stacks. + +Beginning with MS DOS 3.3, there is a special case for STACKS=0,0. +This will result in no dynamic stacks being provided. DOS will not +intercept any interrupts and will only use it own standard stack. + +____________________________________________________________ +| | +| Warning | +| | +| STACKINIT must not change any registers or flags. | +| | +------------------------------------------------------------ + +6.2 THE ROLE OF SYSINIT + +The following steps illustrate the role of SYSINIT in MS-DOS +initialization: + + + 1. When SYSINIT gains control from the IO.SYS + initialization code, it determines the size of + memory (performing a scan if requested, based on + value of MEMORY-SIZE) and, based on the highest + paragraph and the size of SYSINIT, it relocates + itself to high memory. + SYSINIT AND MS-DOS INITIALIZATION Page 6-4 + + + 2. Running in high memory, SYSINIT moves MSDOS.SYS + from the CURRENT_DOS_LOCATION to the + FINAL_DOS_LOCATION as specified by IO.SYS (see the + memory maps in Section 6.3, "COMMAND.COM"). + + 3. SYSINIT does a FAR call to MS-DOS. MS-DOS has + initialization code which steps through the linked + list of device drivers and performs the INIT call + to each. The copyright message is then printed out + on the screen. + + 4. After initializing the resident devices, building + drive parameter blocks for the resident block + devices, and installing a sector buffer, MS-DOS + does a FAR return to SYSINIT. + + During MS-DOS initialization, MS-DOS examines the + BIOS Parameter Blocks (BPBs) returned by the INIT + call to the block devices. It uses the largest + sector size it finds as the default buffer size for + all buffers. For this reason, the initial BPBs may + be used to reserve space for an installable device + with a larger sector size rather than reflecting + the format of the installed disk. In this case, + these dummy BPBs must have media bytes that do not + have the same value as those used in real BPBs. + + + 5. SYSINIT calls RE_INIT in IO.ASM to allow the OEM to + print headers or handle any other initialization. + +------------------------------------------------------------ +| | +| Warning | +| | +| Do not attempt to modify memory. | +| | +|__________________________________________________________| + + + 6. After IO.SYS returns control to SYSINIT, SYSINIT + attempts to open the CONFIG.SYS file. If found, + this file is loaded in memory and all characters + are turned to uppercase. It is then parsed looking + for keywords such as DEVICE, BUFFERS, and SHELL. + Any new devices are loaded, added to the linked + list, and installed via the INIT call. Character + devices are added to the front of the list, and new + block devices are added to the end. Thus, a new + CON device can supplant an existing resident CON + device. This provides the facility to reconfigure + IO.SYS except for the Resident Disk Block device + driver. + + SYSINIT AND MS-DOS INITIALIZATION Page 6-5 + + + 7. SYSINIT allocates all of the memory it needs to + protect the buffers, installed device driver code, + and IO.SYS. It sets the "owner" of the memory to a + special value to ensure that this block of memory + is never deallocated. + + 8. SYSINIT closes all file handles, and then reopens + CON, AUX, and PRN. This enables a new CON, AUX or + PRN device to replace the resident devices. + + 9. SYSINIT allocates memory for the buffers. + + 10. SYSINIT allocates memory for hardware stacks and + calls STACKINIT to initialize the hardware stack + switching algorithm (only in versions of DOS 3.2 + and later). + + 11. SYSINIT executes COMMAND.COM. + + 12. COMMAND.COM allocates memory for its transient portion + and moves it. + +MS-DOS is now up and running. + + + +6.3 COMMAND.COM + +During its initialization, COMMAND.COM allocates memory for +its transient part and reloads it. The transient part of +COMMAND, which contains the internal commands (Copy, Dir, +Date, Time, etc.), resides in unprotected memory when a +user's program is loaded into the Transient Program Area +(TPA). It will be overlaid by programs needing the space. +When a user program terminates to the COMMAND resident, the +transient is checked to see if reloading is necessary. + SYSINIT AND MS-DOS INITIALIZATION Page 6-6 + + +Each of the following memory maps represents a step in the +MS-DOS initialization process. + ++-----------------------------+ +| | High memory +| | +| | +| | ++-----------------------------+ Loaded at arbitrary +| Bootstrap loader | location by system ROM ++-----------------------------+ XX:00 +| | +| | +| | +| | +| | +| | +| | +| | +| | +| | +| | ++-----------------------------+ Segment 40H +| Interrupt Vector Table | ++-----------------------------+ -0:00 + +Memory organization in an MS-DOS +system after the system ROM +has loaded the boot sector. + SYSINIT AND MS-DOS INITIALIZATION Page 6-7 + + ++-----------------------------+ +| | High memory +| | +| | ++- - - - - - - - - - - - - - -+ +| Spent bootstrap loader | ++- - - - - - - - - - - - - - -+ +| | +| | +| | ++-----------------------------+ +| | MS-DOS disk operating +| MSDOS.SYS | system in temporary +| | location +| | ++-----------------------------+ Microsoft-supplied +| SYSINIT | system initialization ++- - - - - - - - - - - - - - -+ module (part of IO.SYS) +| | +| IO.SYS | IO.SYS (may begin at ++-----------------------------+ any location) +| Interrupt Vector Table | ++-----------------------------+ + +Memory after bootstrap loader +loads IO.SYS and MSDOS.SYS. + SYSINIT AND MS-DOS INITIALIZATION Page 6-8 + + ++-----------------------------+ +| SYSINIT | High memory +| relocates itself to highmem | ++-----------------------------+ +| | +| | +| | +| | +| | ++-----------------------------+ +| | +| MS-DOS structures, buffers, | SYSINIT loads installable +| hardware stack space, | drivers and buffers here +| and installable drivers | ++-----------------------------+ +| | +| MSDOS.SYS relocated by | SYSINIT moves MS-DOS +| SYSINIT to fill hole in | down to OEM-designated +| memory. | FINAL_DOS_LOCATION +| | ++-----------------------------+ +| IO.SYS | ++-----------------------------+ +| Interrupt Vector Table | ++-----------------------------+ + +Memory during system initialization +performed by SYSINIT module. + SYSINIT AND MS-DOS INITIALIZATION Page 6-9 + + ++-----------------------------+ +| COMMAND.COM | High memory +| (transient) | ++-----------------------------+ +| | Start of TPA will vary +| Transient Program Area | with # of drivers, +| (TPA) | buffers, etc. ++-----------------------------+ +| COMMAND.COM (resident) | COMMAND.COM loads its ++-----------------------------+ transient part into top +| | of largest available +| MS-DOS structures, buffers | memory +| hardware stack space, | +| and installable drivers | ++-----------------------------+ +| | +| | +| MSDOS.SYS | +| | +| | ++-----------------------------+ +| | +| IO.SYS | +| resident device drivers | ++-----------------------------+ +| Interrupt Vector Table | ++-----------------------------+ + +Memory after SYSINIT installs command interpreter. + +This represents the normal configuration +during MS-DOS operation. + SYSINIT AND MS-DOS INITIALIZATION + + + + + + + + + CONTENTS + + +CHAPTER 7A WRITING THE FORMAT MODULE FOR MS-DOS 3.20/3.21 + + 7.1 Introduction 7-1 + 7.2 Format Modules and the ES Register 7-9 + 7.3 Changing the Logical Format of Disks 7-9 + + + + + CHAPTER 7B + + WRITING THE FORMAT MODULE + MS-DOS 3.20/3.21 + + + +HIGHLIGHTS OF CHANGES IN 3.2X OVER PREVIOUS 2.XX FORMAT VERSION: + + + o FORMAT is now designed to be an .EXE file. + + o The FBIGFAT variable has been introduced for 16-bit + FAT support. + + o ALLOCATEFAT routine allows space for the FAT to be + dynamically allocated. + + o Hardware specific functionality assumed to be provided + by device drivers. + + +HIGHLIGHTS OF CHANGES IN 3.20 OVER PREVIOUS FORMAT VERSIONS: + + The intention of the MS-DOS 3.2 FORMAT utility is to + reduce the amount of OEM work and also move any machine + dependencies to the device drivers (software BIOS). + The following are the new features of the MS-DOS 3.2 + FORMAT utility: + + o FORMAT is now designed to be hardware independent. + The FORMAT utility no longer makes calls directly to + the ROM BIOS to perform the format operation. The direct + calls to the ROM BIOS have been replaced with MS-DOS + system calls (Generic IOCTL's) that perform the necessary + format functions. The responsibility for interacting + with the ROM BIOS to deal with the formating functions is now + placed in the OEM's device drivers. + + o The current head and cylinder being formated is displayed in the + layout: + Head: %d Cylinder: %d + + o Two new switches have been added to FORMAT. The new switches + are: + /N:xx - Specifies the number of sectors/cylinder + on the media. + + /T:yy - Specifies the number of tracks on the media. + + These two options will only be useful if the ROM BIOS has support + to deal with changing of the disk drive parameters. + + o FORMAT will no longer format the default drive if no drive was + specified on the command line. + + + +7.1 INTRODUCTION + +The MS-DOS Format command formats a new disk, clears the FAT +and directory, and optionally copies system files and +COMMAND.COM to the new disk. The 3.2X Format utility no +longer requires the hardware specific code supplied by the +OEM in previous versions. Instead, Format relies on the +drive device driver to provide the functionality required +to format a track on that drive. The Format utility uses a +GENERIC_IOCTL function request to access the drive device +driver to format a track on the drive. If the device driver +does not support a format track function the Format utility +will not be able to format the drive. + +FORMAT is shipped in two hardware-independent object +modules. These must be linked to a system configuration +dependant module written by the OEM. The following section +describes the routines required in this module. A sample +OEM format module is included on the MS-DOS release disks +to assist in writing these routines. + +The syntax for the Format command is: + + + Format drive: [/switch1][/switch2]...[/switch16] + + "drive:" is a legal drive specification. As many as 16 + legal switches can be included in the command line. + + +7.2 CODE AND DATA FROM THE OEM + + +As the OEM may need to tailor the FORMAT module for a particular +system configuration the OEM must supply the routines and data +items which are specific to that configuration. The OEM should +produce a module, eg. OEMFOR.ASM, which contains the following +(NEAR) data items; + + SWITCHLIST + DOSFILE + BIOSFILE + +and the following (NEAR) routines; + + OEMDONE + WRITEBOOTSECTOR + CHECKSWITCHES + LASTCHANCETOSAVEIT + + +The detailed description of the data items required to be declared +public in the OEM's module is as follows; + + +SWITCHLIST + + A string of bytes. The first byte is count + n, followed by n characters that are the + switches to be accepted by the command line + scanner. Alphabetic characters must be in + uppercase (the numeric characters 0-9 are + allowed). The last six switches, normally + "/N","/T","/C","/O", "/V" and "/S", have + predefined meanings. + + The "/S" switch is the switch that causes the + system files IO.SYS, MSDOS.SYS, and + COMMAND.COM to be transferred to the disk + after it is formatted, thus making a system + disk. The switch can be some letter other + than "S", but the last switch in the list is + assumed to have the meaning "transfer + system," regardless of what the particular + letter is. + + The second to the last switch, "/V", causes + FORMAT to prompt the user for a volume label + after the disk is formatted. As with "/S", + the particular letter is not important but + rather the position in the list. + + The third to the last switch, "/O", causes + FORMAT to produce an IBM Personal Computer + DOS version 1.x-compatible disk. Normally + FORMAT causes a 0 byte to be placed in the + first byte of each directory entry instead of + the 0E5H free entry designator. This + markedly increases the performance of a + directory search due to an optimization in + the DOS. Disks made with this switch cause + trouble on IBM PC DOS 1.x versions which did + not have this optimization. The 0 byte fools + IBM 1.x versions into thinking these entries + are allocated instead of free. Note that IBM + Personal Computer DOS version 2.10 and MS-DOS + version 1.25 have no trouble with these + disks, since they have the same optimization. + The "/O" switch causes FORMAT to redo the + directory with a 0E5H byte at the start of + each entry so that the disk may be used with + 1.x versions of IBM PC DOS, as well as with + MS-DOS 1.25/2.XX and IBM PC DOS 2.00/2.10. + This switch should only be given when needed + because it takes a fair amount of time for + FORMAT to perform the conversion, and it + noticeably decreases 1.25 and 2.x performance + on disks with few directory entries. + + A "/C" switch is specified for "Clear". This + switch should cause the formatting operation + to be bypassed (within DISKFORMAT or + BADSECTOR). This is provided as a + time-saving convenience to the user, who may + wish to "start fresh" on a previously + formatted and used disk. + + The "/T:" option is used to specify the + number of tracks that Format will place on + a floppy disk. + + The "/N:" option is used to specify the + number of sectors per track that Format will + use to format a floppy disk. + + +BIOSFILE & DOSFILE + + The BIOSFILE and DOSFILE data strings are used to + specify the filenames for the hidden BIOS and DOS + system files written to the formatted disk when + the /s option is selected. + The filename strings should be null terminated root + directory specifications commencing with a dummy + non-zero drive letter byte which will be modified + by the FORMAT module at run-time. + eg. + + BIOSFILE db "x:\IO.SYS",0 + DOSFILE db "x:\MSDOS.SYS",0 + + +The following data is declared PUBLIC in Microsoft's +FORMAT module and may be used by the OEM's module +as required. + +SWITCHMAP + + A WORD value with a bit vector indicating + which switches are included in the command + line. The correspondence of the bits to the + switches is determined by SWITCHLIST. The + extreme right (highest-addressed) switch in + SWITCHLIST (which must be the system transfer + switch, normally "/S") corresponds to bit 0, + the second from the right, normally "/V" to + bit 1, etc. For example, if SWITCHLIST is + the string "7,'AGI2OVS'", and the user + specifies "/G/S" on the command line, then + bit 6 will be 0 (/A not specified), bit 5 + will be 1 (/G specified), bits 4,3,2 and 1 + will be 0 (neither I,2,O or V specified), and + bit 0 will be 1 (/S specified). + + +FBIGFAT + + BYTE which takes on one of two possible + values, 0 or 0FFH. WARNING: Any value other + than 0 or 0FFH will cause FORMAT to do very + odd things. The value 0 indicates that the + disk being formatted will have a 12-bit FAT. + The value 0FFH means that the disk being + formatted will have a 16-bit FAT. + + +DRIVE + + A byte value containing the drive specified + in the command line. 0=A, 1=B, etc. + + +DRIVELETTER + + A byte value containing the ASCII value of + the drive letter specified in the command + line. + + +DEVICEPARAMETES + + A structue containing the device parameters of + the drive to be formatted. The format of the + DEVICEPARAMETERS data structure is as follows; + + DP_SpecialFunctions : BYTE + DP_DeviceType : BYTE + DP_DeviceAttributes : WORD + DP_Cylinders : WORD + DP_MediaType : BYTE + DP_BPB : BPB + DP_TrackTableEntries : WORD + DP_sectorTable : BYTE TABLE + +INBUFF + + A string buffer used to return a character + string entered from the keyboard in the + user_string routine in the FORMAT module. + +CURRENTHEAD + + A word value containing the drive head + which was being formatted when an error + occurred. + + +CURRENTCYLINDER + + A word value containing the drive cylinder + which was being formatted when an error + occured. + +FLASTCHANCE + + A byte value used to flag whether a format + message is to printed at the start of + a format attempt. + + +NUMSECTORS + + A word value containing the number of + sectors specified in the command line + with the /n switch. + + +TRACKCNT + + A word value containing the number of + sectors specified in the command line + with the /t switch. + + + +The detailed description of the routines required to be declared +public in the OEM's module is as follows; + + +OEMDONE + + This routine is called after the formatting has + been completed, the disk directory has been + initialized and the system has been transferred + if specified. It is called once for each disk to + be formatted. This gives the chance for any + finishing up operations, if needed. If the OEM + desires extra files to be put on the formatted + disk by default, or according to a switch, this + could be done in OEMDONE. + The OEMDONE routine should also check for the /b + switch and, if present, should notify the FORMAT + module of a non-standard system size by calling + the ADDTOSYSTEMSIZE routine in the FORMAT module. + + The following data items form the inputs to the + OEMDONE routine; + + SwitchMap : A WORD vaule indicating which + switches were selected. The + format of the SwitchMap is + as described previously. + + + The OEMDONE outputs should be; + + Carry Flag : Set on error, else clear. + If an error status is returned + by OEMDONE, the error message + "Format failure" and a prompt + for another disk will be + displayed. + +WRITEBOOTSECTOR + + This routine is called once for each disk formatted + after the format has occured but prior to installing + a system on the disk. + The routine writes the OEM specific boot sector(s) + to the disk. The first boot sector must be written + to the disk with an initialized BPB. The boot code + may be contained within the OEMFOR module and copied + to the boot sectors by this routine or may be + written to the boot sectors after the format using a + separate OEM utility as long as the BPB is written + in this routine. + The functionality of the code and data required in + the boot sector(s) is discussed in detail in + section 4.4 . + If an error occurs while writing the boot sector(s) + the routine should display an error message and + return with the carry flag set. + + +CHECKSWITCHES + + + This routine is called once before any disks have + been formatted. It is used to verify that the + switches selected are a legal combination for the + drive type to be formatted and to modify the drive + device parameters according to the selected switches + if they are valid. For example the valid swith + combinations for supported drive types could be; + + + Disk Type Valid switches + + 160/180KB /l /4 /8 /b /n /t /v /s + 320/360KB /l /4 /8 /b /n /t /v /s + 720KB /n /t /v /s + 1.2MB /n /t /v /s + Hard disk /v /s + + + The CHECKSWITCH routine is included in the OEMFOR + module so that the OEM may decide what action to + take for an OEM specific drive type with the switch + combination selected. + + The following data items form the inputs to the + CHECKSWITCHES routine; + + + deviceParameters : A data structure containing + the drive parameters for the + drive to be formatted. The + fields of this structure are + as descibed previously. + + SwitchMap : A WORD vaule indicating which + switches were selected. The + format of the SwitchMap is + as described previously. + + NumSectors : A WORD value containing the + number of sectors specified + with the /n switch if it was + present in the command line. + + NumTracks : A WORD value containing the + number of tracks specified + with the /t option if it was + present in the command line. + + The CHECKSWITCHES outputs should be; + + Carry Flag : Set on error, else clear. + + deviceParameters : Device parameters to use in + the format operation. Should + have been modified by + CHECKSWITCES if a legal switch + combination specifies parameter + modification. + + NumSectors : If the /n switch was not present + in the command line then the + CHECKSWITCHES routine should + initialize the NumSectors WORD + from the deviceParamaters + structure. + + Trackcnt : If the /t switch was not present + in the command line then the + CHECKSWITCHES routine should + initialize the Trackcnt WORD + from the deviceParamaters + structure. + +LASTCHANCETOSAVEIT + + This routine is called when an error, other + than a write protect or not ready error, + occurs during the disk format. It gives the + OEM a chance to modify the disk parameters + to be used in the format operation. The + format will then be tried with these parameters. + An example of when this could be used is if + the format fails on the second head (track + zero), the OEM may want to try formatting + the disk single sided. + + + The LASTCHANCETOSAVEIT inputs are: + + deviceParameters : A data structure containing + the drive parameters for the + drive being formatted when + the error occurred. The fields + of this structure are as + described previously. + + currentCylinder : A WORD value indicating the + drive cylinder on which the + error occurred. + + currentHead : A WORD value indicating the + drive head on which the error + occurred. + + The LASTCHANCETOSAVEIT outputs should are: + + Carry Flag : Set if the error was fatal and + no attempt is to be made to + re-format the drive, else clear. + + deviceParameters : Modified to contain the new + parameters for the re-format, + if a re-format attempt required. + + fLastChance : A BYTE value set to TRUE if an + attempt to re-format the drive + is required. This prevents + multiple format messages for + a single drive format. + + +The following routines are declared PUBLIC in Microsoft's +FORMAT module and may be used by the OEMFOR module +as required. + + +ADDTOSYSTEMSIZE + + Adds to the number of sectors reserved for the system. + + INPUTS : ax = size of system file in bytes. + + OUTPUTS : None. + + +PRINTSTRING + + Displays a character string. + + INPUTS : dx = near pointer to null terminated string. + + OUTPUTS : None. + + +STD_PRINTF + + Displays a character string. + + INPUTS : dx = near pointer to a near pointer to a + null terminated string. + + OUTPUTS : None. + + +CRLF + + Outputs a carriage return and linefeed to the console. + + INPUTS : None. + + OUTPUTS : None. + + +USER_STRING + + Get a string from the keyboard. + + INPUTS : None. + + OUTPUTS : Zero flag set if only was enterred. + String length in BYTE at offset INBUFF + 1. + Console input in INBUFF commencing at offset + INBUFF +2. + + + +Once the OEM-supplied module has been prepared, it must be +linked with Microsoft's FORMAT.OBJ module, and the +FORMES.OBJ module. In 3.XX, there are additional format +modules that must be linked in. If the OEM-supplied module +is called OEMFOR.OBJ, then use the following linker command; + + link format forproc formes oemfor printf; + +This command produces an executable file called FORMAT.EXE. +NOTE: The OEM's module CAN NOT make the assumption, as it +could in the previous versions, that it is at the "end" of +the memory image. It must use function 48h (allocate +memory) if required. + + + +7.3 FORMAT MODULES AND THE ES REGISTER + +If an OEM-written FORMAT module, such as OEMDONE, makes use of +the ES register, the value of ES should be established by the +OEM's code. The contents of the ES register cannot be assumed. + + + + + + + + + CONTENTS + + +CHAPTER 7B WRITING THE FORMAT MODULE FOR MS-DOS 2.25/3.10 + + 7.1 Introduction 7-1 + 7.2 Format Modules and the ES Register 7-9 + 7.3 Changing the Logical Format of Disks 7-9 + + + + + + + + + CHAPTER 7B + + WRITING THE FORMAT MODULE + MS-DOS 2.25/3.10 + + + +HIGHLIGHTS OF CHANGES IN 3.XX OVER PREVIOUS 2.XX FORMAT VERSION: + + + o FORMAT is now designed to be an .EXE file. + + o The FBIGFAT variable has been introduced for 16-bit + FAT support. + + o ALLOCATEFAT routine allows space for the FAT to be + dynamically allocated. + + + + +7.1 INTRODUCTION + +The MS-DOS Format command formats a new disk, clears the FAT +and directory, and optionally copies system files and +COMMAND.COM to the new disk. Since the Format command must +perform functions that have no equivalent in MS-DOS function +calls, FORMAT is shipped in two hardware-independent object +modules. These must be linked to a hardware-specific module +written by the OEM. The following section describes the +routines required in this module. A sample OEM format +module is included on the MS-DOS release disks to assist in +writing these routines. + +The syntax for the Format command is: + + + Format [drive:][/switch1][/switch2]...[/switch16] + + "drive:" is a legal drive specification. If it is + omitted, the default drive will be used. As many as 16 + legal switches can be included in the command line. + + WRITING THE FORMAT MODULE Page 7-2 + + +In 3.XX the OEM must supply six (NEAR) routines to the program along +with seven data items. In 2.XX the OEM must supply five (NEAR) routines +to the program along with six data items. The names of the routines are: + + ALLOCATEFAT + INIT + DISKFORMAT + BADSECTOR + WRTFAT + DONE + +ALLOCATEFAT is used only in 3.XX. + +Their flow of control (by the Microsoft module) is like +this: + + | + +-------------+ + | ALLOCATEFAT | + +-------------+ + | + +---------+ + | INIT | + +---------+ + | + |<------------------------------+ ++------------+ | +| DISKFORMAT | | ++------------+ | + |<-------+ | ++-----------+ |-This loop is done |- This loop is +| BADSECTOR | | for each group of | done once for ++-----------+ | bad sectors | each disk to be + |----->--+ | formatted. If + | | variable HARDFLAG ++----------+ | is set then the +| | | loop is only +| WRTFAT | | performed once. ++----------+ | + | | + +------+ | + | DONE | | + +------+ | + +---->--------------------------+ + +The ALLOCATEFAT, INIT, DISKFORMAT, and BADSECTOR routines +are free to use any MS-DOS system calls, except for calls +that cause disk accesses on the disk being formatted. DONE +may use any calls, since by the time it is called the new ___ +disk has been formatted. + WRITING THE FORMAT MODULE Page 7-3 + + +The following data must be declared PUBLIC in a module +provided by the OEM: + +SWITCHLIST + + A string of bytes. The first byte is count + n, followed by n characters that are the + switches to be accepted by the command line + scanner. Alphabetic characters must be in + uppercase (the numeric characters 0-9 are + allowed). The last three switches, normally + "/O", "/V" and "/S", have pre-defined + meanings. + + The "/S" switch is the switch that causes the + system files IO.SYS, MSDOS.SYS, and + COMMAND.COM to be transferred to the disk + after it is formatted, thus making a system + disk. The switch can be some letter other + than "S", but the last switch in the list is + assumed to have the meaning "transfer + system," regardless of what the particular + letter is. + + The second to the last switch, "/V", causes + FORMAT to prompt the user for a volume label + after the disk is formatted. As with "/S", + the particular letter is not important but + rather the position in the list. + + The third to the last switch, "/O", causes + FORMAT to produce an IBM Personal Computer + DOS version 1.x-compatible disk. Normally + FORMAT causes a 0 byte to be placed in the + first byte of each directory entry instead of + the 0E5H free entry designator. This + markedly increases the performance of a + directory search due to an optimization in + the DOS. Disks made with this switch cause + trouble on IBM PC DOS 1.x versions which did + not have this optimization. The 0 byte fools + IBM 1.x versions into thinking these entries + are allocated instead of free. Note that IBM + Personal Computer DOS version 2.10 and MS-DOS + version 1.25 have no trouble with these + disks, since they have the same optimization. + The "/O" switch causes FORMAT to redo the + directory with a 0E5H byte at the start of + each entry so that the disk may be used with + 1.x versions of IBM PC DOS, as well as with + MS-DOS 1.25/2.XX and IBM PC DOS 2.00/2.10. + This switch should only be given when needed + because it takes a fair amount of time for + WRITING THE FORMAT MODULE Page 7-4 + + + FORMAT to perform the conversion, and it + noticeably decreases 1.25 and 2.x performance + on disks with few directory entries. + + Up to 16 switches are permitted. Normally a + "/C" switch is specified for "Clear". This + switch should cause the formatting operation + to be bypassed (within DISKFORMAT or + BADSECTOR). This is provided as a + time-saving convenience to the user, who may + wish to "start fresh" on a previously + formatted and used disk. + +HARDFLAG + + BYTE location which specifies whether the OEM + routine is formatting a fixed disk or a drive + with removable media. A zero means removable + media; any other value indicates a fixed + disk. The status of this byte only affects + the messages printed by the main FORMAT + module. This value should be set or reset by + the OEM-supplied INIT routine. + +FATID + + BYTE location containing the value to be used + in the first byte of the FAT. Must be in the + range F8H to FFH. + +STARTSECTOR + + WORD location containing the sector number of + the first sector of the data area. + +FATSPACE + + WORD location containing the address of the + start of the FAT area. A FAT built in this + area will be written to disk using the + OEM-supplied WRTFAT subroutine. 6K is + sufficient to store any 12-bit FAT. This + area must not overlap the FREESPACE area. + +FREESPACE + + WORD location that contains the address of + the start of free memory space. This is + where the system will be loaded by the + Microsoft module for transferring to the + newly formatted disk. Memory should be + available from this address to the end of + memory, so it is typically the address of the + end of the OEM module. + WRITING THE FORMAT MODULE Page 7-5 + + +FBIGFAT + + BYTE which takes on one of two possible + values, 0 or 0FFH. WARNING: Any value other + than 0 or 0FFH will cause FORMAT to do very + odd things. The value 0 indicates that the + disk being formatted will have a 12-bit FAT. + The value 0FFH means that the disk being + formatted will have a 16-bit FAT. See + ALLOCATEFAT call, below, for details. + FBIGFAT is used only in 3.XX. + +The following routines must be declared PUBLIC in the +OEM-supplied module: + +ALLOCATEFAT + + ALLOCATEFAT is used only in 3.XX. It is + an initialization routine. This routine is + called once at the start of the FORMAT run + after the switches have been processed. This + routine must set the correct values of + FBIGFAT, FATSPACE, and FREESPACE. + + With only 12-bit FATs it was convenient to + allocate a FAT area of 6K (maximum size of a + 12-bit FAT) as part of the memory image of + FORMAT. With the advent of 16-bit FATs in + DOS 3.XX this is no longer convenient; the + maximum size of of a FAT is 32K. + + ALLOCATEFAT is a dynamic space allocator that + allocates enough memory to hold the FAT by setting + the values of FATSPACE and FREESPACE. + ALLOCATEFAT must also set FBIGFAT so that + FORMAT knows whether the disk has a 12 or a + 16-bit FAT. + + FBIGFAT must be set consistently with the + following FAT rule (see below). + + The 16-bit FAT rule: + + - Any disk with less than 4086 clusters has a ____ ____ + 12-bit FAT. + - Any disk with greater than or equal to 4086 _______ ____ __ _____ __ + clusters has a 16-bit FAT. + + The OEM FORMAT module cannot force a 16-bit + FAT if the total number of clusters is less + than 4086. Similarly, you cannot have a + 12-bit FAT on a disk with more than 4085 + clusters. If the OEM module does not set + FBIGFAT consistently with the 16-bit FAT + rule, the disk will not be formatted + correctly, and MS-DOS will not access the + disk in the proper manner. + WRITING THE FORMAT MODULE Page 7-6 + + + Currently, there is no error return from + ALLOCATEFAT. It should exit with CARRY + CLEAR, however, so that it is consistent with + the other routines. + + The Microsoft 3.XX FORMAT.OBJ is responsible for + checking that the memory needed for the FAT is + actually available to the system. It will + produce a "Insufficient memory for system transfer" + error when memory is inadequate. This error + is produced when memory is inadequate for both + "/S" and non "/S" procedures. + + +INIT + + An initialization routine. This routine is + called once at the start of the FORMAT run + after the switches have been processed. This + routine should perform any functions that + need to be done once per FORMAT run. An + example of what this routine might do is read + the boot sector into a buffer so that it can + be transferred to the new disks by + DISKFORMAT. If this routine returns with the + CARRY flag set, it indicates an error, and + FORMAT will print "Format failure" and quit. + This feature detects conflicting switches + (like specifying both single and double + density) and causes the FORMAT routine to + abort. + +DISKFORMAT + + Formats the disk according to the options + indicated by the switches and the value of + FATID must be defined when it returns + (although INIT may have already done it). + This routine is called once for each disk to + be formatted. If necessary, it must transfer + the bootstrap loader. If any error + conditions are detected, the carry flag is + set. FORMAT will report a "Format failure" + and prompt for another disk. (If you only + require a clear directory and FAT, all that + DISKFORMAT must do is set the appropriate + FATID, if this has not already been done by + INIT. + + + + + + + + + + + + +BADSECTOR + + Reports the sector number of any bad sectors + that may have been found during the + formatting of the disk. This routine is + called at least once for each disk to be + formatted, and is called repeatedly until the + AX register is zero or the carry flag is set. + The carry flag is used just as in DISKFORMAT + to indicate an error, and FORMAT handles it + in the same way. The first sector in the + data area must be in STARTSECTOR for the + returns from this routine to be interpreted + correctly. If there are bad sectors, + BADSECTOR must return a sector number in + WRITING THE FORMAT MODULE Page 7-7 + + + register BX, the number of consecutive bad + sectors in register AX, and clear the carry + flag. FORMAT will then process the bad + sectors and call BADSECTOR again. When + BADSECTOR returns with AX = 0, there are no + more bad sectors; FORMAT clears the + directory and goes on to DONE. For this last + return, BX need not contain anything + meaningful. + + FORMAT processes bad sectors by determining + their corresponding allocation unit and + marking that unit with an FF7H in the File + Allocation Table. CHKDSK understands the + FF7H mark as a flag for bad sectors and + accordingly reports the number of bytes + marked in this way. + + Actual formatting of the disk can be done in + BADSECTOR instead of DISKFORMAT on a "report + as you go" basis. Formatting continues until + a group of bad sectors is encountered; + BADSECTOR then reports them by returning with + AX and BX set. FORMAT will then call + BADSECTOR again and formatting can continue. + +WRTFAT + + This routine is called after the disk is + formatted and bad sectors have been reported. + It writes all copies of the FAT from the area + of memory referenced by FATSPACE to the drive + just formatted. It may be possible to use + INT 26H to perform the write, or a direct + BIOS call. Whether this is possible depends + on whether the FAT ID byte is used by the + BIOS to determine the media in the drive. If + it is, these methods will probably fail + because there is no FATID byte on the disk + yet (in this case WRTFAT's primary job is to + get the FATID byte out on the disk). + +DONE + + This routine is called after the formatting + has been completed, the disk directory has + been initialized, and the system has been + transferred if specified. It is called once + for each disk to be formatted. This gives + the chance for any finishing-up operations, + if needed. If the OEM desires extra files to + be put on the disk by default, or according + to a switch, this could be done in DONE. + WRITING THE FORMAT MODULE Page 7-8 + + + Again, as in BADSECTOR and DISKFORMAT, carry + flag set on return means an error has + occurred; "Format failure" will be printed + and FORMAT will prompt for another disk. + +The following data is declared PUBLIC in Microsoft's +FORMAT module: + +SWITCHMAP + + A WORD value with a bit vector indicating + which switches are included in the command + line. The correspondence of the bits to the + switches is determined by SWITCHLIST. The + extreme right (highest-addressed) switch in + SWITCHLIST (which must be the system transfer + switch, normally "/S") corresponds to bit 0, + the second from the right, normally "/V" to + bit 1, etc. For example, if SWITCHLIST is + the string "7,'AGI2OVS'", and the user + specifies "/G/S" on the command line, then + bit 6 will be 0 (/A not specified), bit 5 + will be 1 (/G specified), bits 4,3,2 and 1 + will be 0 (neither I,2,O or V specified), and + bit 0 will be 1 (/S specified). + + Bits 0,1 and 2 are the only switches used in + Microsoft's FORMAT module. These switches + are used 1) after INIT has been called to + determine if it must load the system; 2) + after the last BADSECTOR call to determine if + the system should be written, E5 directory + conversion should be done, and/or a volume + label should be asked for. INIT may force + these bits set or reset if desired (for + example, some drives may never be used as + system disk, such as hard disks). After + INIT, the "/S" bit may be turned off (but not + on, since the system was never read) if + something happens that means the system + should not be transferred. + + After INIT, a second copy of SWITCHMAP is + made internally.It is used to restore + SWITCHMAP for each disk to be formatted. + FORMAT will turn off the system bit if bad + sectors are reported in the system area; + DISKFORMAT and BADSECTOR are also allowed to + change the map. However, these changes + affect only the current disk being formatted, + since SWITCHMAP is restored after each disk. + (Changes made to SWITCHMAP by INIT affect all + disks.) + WRITING THE FORMAT MODULE Page 7-9 + + +DRIVE + + A byte value containing the drive specified + in the command line. 0=A, 1=B, etc. + +Once the OEM-supplied module has been prepared, it must +linked with Microsoft's FORMAT.OBJ module, and the +FORMES.OBJ module. In 3.XX, there are additional format +that must be linked in. If the OEM-supplied module is called +OEMFOR.OBJ, then use the appropriate linker command. + +2.XX LINK FORMAT.OBJ+FORMES.OBJ+OEMFOR.OBJ + +3.XX LINK FORMAT.OBJ+FORPROC.OBJ+FORMES.OBJ+OEMFOR.OBJ.PRINTF.OBJ + +For 3.XX, the command produces an executable file called +FORMAT.EXE. Note that although the PRINTF.OBJ module +is the last module specified, it does not follow the +OEMFOR module in the memory image. The OEMFOR module +can still make the assumption, as it has in the past, +that it is at the "end" of the memory image. + +For 2.XX, the command produces a FORMAT.EXE file which +must be changed to a simple binary. This should be done +with the following command. + + EXE2BIN FORMAT.EXE FORMAT.COM + +This produces the 2.XX file, FORMAT.COM. + + +7.2 FORMAT MODULES AND THE ES REGISTER + +If an OEM-written FORMAT module makes use of the ES +register, such as DISKFORMAT, the value of ES should be +established by the OEM's code. The contents of the ES +register cannot be assumed. + + + + + + + + + + + + + + + + + + + + + + + +WRITING THE FORMAT MODULE PAGE 7-10 + + +7.3 CHANGING THE LOGICAL FORMAT OF DISKS + +MS-DOS has an internal table which it builds from +information returned by the BIOS BUILDBPB routine. +There is a table maintained for each drive within the +system and it is updated to reflect the media type +whenever a new disk is loaded. Before any access to +the disk directory, MS-DOS calls the BIOS MEDIACHECK +routine. If a disk change is reported, MS-DOS calls +the BIOS BUILDBPB routine to get the new media +information and updates its internal table. It is +important to realize that MS-DOS operates with its own +table and not with any table within the BIOS. + +FORMAT can be used to physically reformat the disk from +single to double-sided use. Therefore, the WRTFAT +routine should ensure that the next call to the BIOS +MEDIA CHECK/BUILD BPB routines made by the DOS will set +the media type to the type just formatted. This is +because when the format operation is started, the DPB +(Drive Parameter Block) reflects the media that existed +before the format. This may need to be changed because +the disk media may have been changed due to the format +process. Since this is basically a communication +between the OEM part of the FORMAT utility and the OEM +BIOS, it is up to the OEM to determine the most +efficient and appropriate way to determine the correct +media type. As an example, the FORMAT utility can call +the BIOS and cause the BIOS to return "media changed" +on the next MEDIA CHECK call made by the DOS. The DOS +will then call the BUILDBPB BIOS routine; it must +return the correct BPB for the disk just formatted. + +Trying to determine media change externally with the +FORMAT utility calling the DOS will not work. You +must: + + + o Have the correct BPB in the BIOS, and your + FORMAT utility must communicate that + information down to your BIOS, or + + o Your BIOS must detect that the disk has been + changed when the FORMAT utility is used. + Then, the BIOS can look on the disk for the + BPB and tell the DOS what the new BPB is. + + +The OEM may decide how this can be structured. The +BIOS can be in control and inform FORMAT what was done, +or FORMAT can be in control and inform the BIOS that +the media has changed. + +There is an example of an OEM written FORMAT module on the +Sample MS-DOS Implementation Diskette. + + + + + + + + CONTENTS + +CHAPTER 8 TROUBLE-SHOOTING + + + + + + + + + + + + + + CHAPTER 8 + + TROUBLE-SHOOTING + + + +The following section addresses typical problems that you +may encounter when installing MS-DOS. + + +Problem: + + When I type "r" for Retry when a disk error occurs, the + system crashes. + + Typical Cause: + + When an error occurs during I/O, your device driver + must report the number of sectors or characters + correctly transferred. If you just set the error bit, + MS-DOS will assume that it was able to read all of the + sectors since the sector count will be the same as that + set by MS-DOS. + + Recommendation: + + Report the actual number of sectors/bytes transferred + in addition to reporting the error. + + +Problem: + + I am booting up MS-DOS. I see the MS-DOS copyright + message on the screen, but then I get the message "Bad + or missing command interpreter." + + Typical Cause: + + SYSINIT is executing COMMAND.COM. This is the + conclusion of MS-DOS initialization and is the first + time that the disk must be read successfully. (Failure + to find CONFIG.SYS is not an error.) Either COMMAND.COM + is not on the disk or an invalid Bios Parameter Block + (BPB) has been returned to MS-DOS so it does not + correctly understand the format of the disk. + TROUBLE-SHOOTING Page 8-2 + + + Recommendation: + + Check that the correct BPB is being returned and that + COMMAND.COM is on disk. Install debugging code in the + device driver to make sure requests to the device + driver make sense. + + +Problem: + + I am booting up MS-DOS. I get the MS-DOS copyright + message on the screen, but then I get the message "Bad + or missing /DEV/CON." + + Typical Cause: + + SYSINIT has closed all file handles and is now + reopening them. The first file it opens is /DEV/CON, + which is your console device. The system file table is + examined for this device. /DEV/CON should be present. + If it is not found, some of your IO.SYS code has + destroyed the system file table or MS-DOS itself. This + may happen if you have blown the MS-DOS stack, causing + MS-DOS to write over the file table. + + Recommendation: + + Use a local stack in your device drivers. + + +Problem: + + MS-DOS is trying to read some sectors starting at an + extremely large or invalid sector number. + + Typical Cause: + + The BPB that you returned for the drive is bad. + + Recommendation: + + The INIT and BUILD BPB device driver routines should be + checked. + + +Problem: + + After I jump to SYSINIT, control never comes back. + + Typical Cause 1: + + You may not have loaded MS-DOS correctly with your + bootstrap loader. SYSINIT must know exactly where + MS-DOS is. MS-DOS must be on a paragraph boundary and + CURRENT_DOS_LOCATION and FINAL_DOS_LOCATION must be + set up accordingly. + + TROUBLE-SHOOTING Page 8-3 + + + Recommendation: + + Check the location of MSDOS.SYS after bootstrap + loading. + + Typical Cause 2: + + You are incorrectly reporting the amount of memory in + the system or the memory scan is failing because of a + discontinuity. + + Recommendation: + + Don't move MS-DOS after bootstrap loading. Don't + request a memory scan. Make sure memory is contiguous. + + Typical Cause 3: + + MS-DOS can't find the beginning of the device list. + + Recommendation: + + Check the value passed to SYSINIT to make sure that it + is the correct value for the beginning of the list. + + Typical Cause 4: + + The driver attributes are wrong. MS-DOS will not look + for the end of list mark if the attributes are wrong. + + Recommendation: + + Check the device driver attribute words. + + Typical Cause 5: + + You do not have a driver in the linked list of device + drivers with the CLOCK attribute bit set. This is + necessary before SYSINIT will start looking for FFFF, + FFFF in the last device driver. + + Recommendation: + + Be sure you have a CLOCK device in your linked list + with its attribute word set properly. + + +Problem: + + Everything was working great, but when I tried to + install a new device, the system wouldn't boot. + + Typical Cause: + + You are failing to set the BREAK ADDRESS during the + TROUBLE-SHOOTING Page 8-4 + + + device INIT routine. This points to the first byte of + free memory after the device code and data. + + Recommendation: + + Set the break address. + +Problem: + + Everything works OK until I define a new drive in + IO.SYS. Then the system won't come up. + + Typical Cause: + + You are returning invalid data from the INIT call to + the block device driver. + + Recommendation: + + Examine the INIT call. This is probably not being + handled correctly. You should return a DWORD pointer + to an array of WORD POINTERS to BPBs. The array must be + below the 'break address' returned by INIT. There should + be one array element for each drive defined. The number + of subunits is also returned by the INIT call. + + +Problem: + + My device driver defines two drives, but when I try to + use drive B, I get an "Invalid drive specification" + message. + + Typical Cause: + + You are not handling the INIT call to the device driver + properly. + + Recommendation: + + The INIT call should return the value "2" at offset 13 + from the beginning of the static request header. + +Problem: + + When I have a single-sided disk in drive B and remove + it and install a double-sided disk, MS-DOS treats the + double-sided disk like a single-sided disk. I am + returning the correct BPB for the double-sided disk. + + Typical Cause: + + The media bytes in the BPBs are not unique. + + Recommendation: + TROUBLE-SHOOTING Page 8-5 + + + Each BPB has a unique media byte. MS-DOS will not + rebuild its internal DPB structure if the media byte + doesn't change. + +Problem: + + I have a one-drive system. When I type B:, I + get an "Invalid drive specification" message, but on + some single-drive machines, MS-DOS prompts me for the + "disk for drive B:." + + Typical Cause: + + The INIT call is only defining one disk drive and + support for swapping has not been implemented in + IO.SYS. + + Recommendation: + + Support for disk swapping is implemented at the IO.SYS + file level rather than at the MS-DOS level. The driver + reports two drives and when it sees a request for unit + 1 (the second drive), it prints the swap message + directly on the screen. + +Problem: + + Everything is running fine, but when I run Chkdsk I + find that I only have 60K bytes free, but I have a 128K + machine. I know that DOS and IO.SYS only take up 24K. + What is happening to the missing bytes? + + Typical Cause: + + The Block Device Driver INIT call is returning a bad + BPB pointer which reports an absurdly large sector + size. This sector size is used to make all of the + sector buffers, and consequently wastes thousands of + bytes. You could have incorrectly set FINAL_DOS_LOCATION + or installed a device driver that returned an 'absurdly + large' break address. + + Recommendation: + + Fix the block device driver INIT call. + + +Problem: + + Every time I try to do an Allocate Memory call + (Function 48H) or an EXEC call, I get a return code of + 8, "Not enough memory." + + Typical Cause: + + There is no free memory. + TROUBLE-SHOOTING Page 8-6 + + + Recommendation: + + Do a Set Block (Function 4AH) call to shrink the size + of the currently allocated block, freeing some memory. + See the section on arenas in the Glossary. + + +Problem: + + When running a program that opens a number of files via + Function Request 3DH, the file open fails even though + the file is present on the disk. + + Typical Cause: + + You have run out of entries in the system file table. + + Recommendation: + + Increase the "FILES = " entry in CONFIG.SYS and reboot. + + +Problem: + + Control-S, Control-P, and the other control characters + seem to be ignored by MS-DOS. + + Typical Cause: + + The non-destructive console read routine is not + implemented properly. + + Recommendation: + + Check the non-destructive read routine in the console + or other character driver where this problem is + occurring. + + +Problem: + + Sometimes when I am typing a long file to the screen + and press Control-S, the Control-S is ignored and + doesn't stop the scrolling of the file. I have the + same problem with Control-C. + + Typical Cause: + + Another character has been typed into the type-ahead + buffer first, and the nondestructive read keyboard + status check never sees the Control-S or the Control-C. + + Recommendation: + + Implement Scroll Lock and Break keys which flush the + TROUBLE-SHOOTING Page 8-7 + + + input queue and put the Control-S/Control-C at the + beginning of the type-ahead buffer. + + +Problem: + + I am trying to use EXE2BIN to convert IO.EXE to IO.SYS. + I get the message "File cannot be converted." + + Typical Cause: + + You have a "SEGMENT AT NNNN" statement and there is + code or initialized data in that segment. You may also + have a stack segment, which is not permitted. + + Recommendation: + + Remove the "SEGMENT AT" statement or remove code or + initialized data from the segment. + + It is possible, if your code contains FAR references, that + EXE2BIN may request a 'Fixup' address. If your IO.SYS will + always be loaded at the same place in memory, this may be + OK. Check your FAR references in any case. + + + + + + + + + + + + + + APPENDIX A + + CUSTOMIZATION OF MS-DOS AND INTERNATIONALIZATION + + + +A.1 CUSTOMIZING MS-DOS + +Many manufacturers find it necessary to customize MS-DOS (as +distinct from IO.SYS) to some degree. The function key +table and OEM serial number are often modified. The +function key table is found in the DOSMES.ASM file. Extensive +modification to this table may require modifying the line +input routines in STRIN.ASM, which is available to source +licensees only. + +OEM Serial Numbers: + +Each OEM is eligible for a unique OEM Serial Number. The Series +is 0 to FF (255). IBM is 00 and we are currently at about 50H +on list. + +These numbers are assigned sequentially by MS-DOS Product Marketing +as requested through the OEM's Account Manager. + +Once the OEM has this number they can modify the default FF +value in the file DOSMES.ASM that is part of the adaptation +kit. If this is done, when MSDOS.SYS file is built +it will the right value. + +It can be patched after they MSDOS.SYS is built by following +the instructions in the README.DOC on the MS-DOS DISTRIBUTION +DISKETTES. + +Function Request 30H - Get MS-DOS Version Number will +return the version of the DOS that is being run, the OEM +Serial number and the OEM user number. + +To implement OEM user number concept properly each individual +disk shipped should have to have a separate user number patched +in according to the directions in the README.DOC on the +MS-DOS DISTRIBUTION DISKETTES. + +The OEM serial number can, however, be used without using the +OEM User Number. + +With these numbers properly installed, an application program +could tell which version of MS-DOS was being run, which +OEM had sold it and which customer had bought it. + +Internationalization may also require customizing MS-DOS. +The file named DOSMES.ASM contains a case conversion routine +and a table used to translate foreign characters into their +uppercase equivalents. This routine defaults to no case +conversion, and a sample for the IBM PC character set is +included. Note that this table is country-dependent. You +should not translate a lowercase character available on the +keyboard into a uppercase equivalent that is not on the ___ +keyboard. For example, in France, translate lowercase c +cedilla into uppercase C (not C cedilla); in Germany, +translate lowercase "a umlaut" into uppercase A umlaut. + +DOSMES.ASM also contains country-dependent tables used by +the international system call (Function 38H). MS-DOS +utilities and COMMAND.COM make two system calls to determine +time and date formats and the location of the case +conversion routine. You may supply as many tables as you +wish; however, it is not necessary to supply tables for all +countries in all translations. You should include tables +for all countries into which a language translation is +distributed. For example, French might include tables for +France, Belgium, and Switzerland. All versions should +include a U.S. table as well. There is a pointer in +DOSMES.ASM to the table to which MS-DOS should default if +the user specifies no "COUNTRY =" parameter in CONFIG.SYS. +Country numbers follow the information telephone codes where +two-digit numbers are employed. + + CUSTOMIZATION OF MS-DOS AND INTERNATIONALIZATION Page A-2 + + +A non-ASCII character text is represented by variables +equated at the beginning of the file. These default to the +IBM PC character set. If your character set is different, +redefine the equates and reassemble, linking the message +file with the code files. + +The SORTMES.ASM file contains a table for collating +sequences. This defaults to no mapping; all uppercase +ASCII is sorted before all lowercase ASCII. A sample table +for the IBM PC character set is included. Note that there +is no capability for equating a single character to a +multiple character string or vice versa. Therefore, German +implementations cannot equate an umlaut to "ae", but may +choose to equate it to "a" or have it fall between "a" and +"b". + + + + + +A.2 EXTENDED CHARACTER SET (ECS) CONSIDERATIONS - MS-DOS 2.25 + +All ECS characters are two-byte quantities which also display as two +physical character positions (double-written) on the screen and +printer. This imposes some constraints on the IO.SYS keyboard and +screen drivers. MS-DOS ensures that 16-bit ECS characters are treated +as a single logical character from the user's standpoint, rather +than being confused for two characters. + CUSTOMIZATION OF MS-DOS AND INTERNATIONALIZATION Page A-3 + + +A.3 INPUT + +On input, it is the responsibility of IO.SYS to pass ECS +characters to MS-DOS. IO.SYS must handle all +Kata-kana-to-ECS conversion or any other method used to +enter ECS. IO.SYS always places both bytes of the ECS +character into its buffer at once; however, they are passed +to MS-DOS as if they are two separate single-byte +characters. Therefore, even non-interrupt-driven keyboards +should always have the second byte of the ECS character +waiting by the time the first byte is accepted by MS-DOS. +IO.SYS should never pass an invalid ECS sequence to +MS-DOS. + + + +A.4 OUTPUT + +On output, IO.SYS must identify the first byte of an ECS +character, set a flag, and wait for the second byte. Once +the entire ECS character has been received, IO.SYS indexes +into the font table. The font table may be in memory, on +disk, or in a combined memory-disk caching scheme. IO.SYS +may call MS-DOS to read font files stored on the disk in +MS-DOS format. These files should be opened in IO.SYS when +control is passed back to RE_INIT, after MS-DOS has been +initialized. + +IO.SYS performs error recovery in case the font files are on +a disk that has been removed. Door lock detection is most +helpful here. Files should be reopened whenever the +potential for a changed disk occurs. MS-DOS screen and +keyboard routines are not reentrant, and cannot be called +from within IO.SYS to facilitate recovery from this error. +A solution to the problem of missing font files is to +display all ECS characters for which no font is in memory +as double-width reverse video blanks. + +IO.SYS also must perform error handling in the data stream +where an invalid ECS sequence is sent. Although invalid +characters should never be input from the keyboard, they can +be output by several occurrences: + + + 1. The user can display a garbage file, such as a + binary executable file. + + 2. A program may have executed a file with bad ECS + data. + + 3. The manipulation of fixed length fields may have + split a ECS character between its two bytes. + + + CUSTOMIZATION OF MS-DOS AND INTERNATIONALIZATION Page A-4 + + +If any of these occur, the recommended procedure is to +display a double-width reverse video blank character +followed by the single-byte ASCII value for the character +outside of the valid second-byte range. This will help to +resynchronize the data stream as soon as possible. + +MS-DOS recognizes double-byte values, such as blank space, +over ECS in its line editing procedures. It also will +accept and display (if appropriate) the second byte where a +single-byte response is anticipated ("Strike any key"). + +IO.SYS should ensure that a ECS character is never split +across the last column of one physical line and the first +column of the next line. The entire ECS character must +start on the next line. IO.SYS must keep a flag for each +line to determine whether one or two logical backspace +operations should be performed. The "Backspace-Space- +Backspace" destructive operation issued by MS-DOS will work +properly. + +For example, starting with column 1, assume that text runs +up to and includes column 79. MS-DOS requests that a +double-byte ECS character be displayed. IO.SYS: + + + 1. Blanks column 80. + + 2. Sets a flag for that physical line. + + 3. Moves to the beginning of the next line. + + 4. Displays both bytes. + + +MS-DOS requests two backspaces over this ECS character. +If a third backspace is issued, IO.SYS must clear the flag +and perform an extra backspace, returning to column 79 +instead of 80. If a space is issued, column 79 will be +blanked. Remember that column 80 was originally blank, so +there is no need to reset it. + +If the ANSI screen driver is also implemented, the driver +should never allow only one-half of a ECS character to be +block transferred without blanking it in scrolling regions. +This rule also applies to both the region being moved and +the area into which it is being moved. + + + + + + + + + + + + + + APPENDIX B + + HOW TO UPGRADE A 2.XX BIOS TO 3.XX + + + +MS-DOS 3.XX provides very few new services that impact device +drivers. The basic BIOS mechanisms are identical to those +in MS-DOS 2.XX. The only changes are that a few new device +driver calls have been added. These calls are not required. ___ +There are new device attribute bits that indicate the +presence of these new functions. Old device drivers do not +have these bits set, and thus indicate that the functions +are not present. + +There are several new CONFIG.SYS commands. The code for +these is contained in the SYSINIT modules, and there are no +new PUBLICs in SYSINIT, or expected EXTERNs in the BIOS. + +First, to quickly bring up MS-DOS 3.XX with a 2.XX set of +device drivers, all that you need to do is build a new BIOS +with the new 3.XX SYSINIT and SYSIMES modules in the same way +that the 2.XX BIOS was built. This will produce a perfectly +functional BIOS, but none of the devices will have any of +the new 3.XX functions implemented. + +Since you have not modified your BIOS, you cannot support +the following features: + + + 1. The IOCTL is Changeable (Function 4408H) call. + This is useful for FORMAT and other programs that + want to prompt for a change of media. + + 2. The character device OPEN and CLOSE device driver + calls. These are useful for flushing + interrupt-driven I/O. + + 3. The background print utility spooling to a network + printer. + + 4. Output-until-busy device driver call for + PRINT/PSPRINT spool devices. + + + HOW TO UPGRADE A 2.XX BIOS TO 3.XX Page B-2 + + + 1. IOCTL Is Changeable Call + + The IOCTL Is Changeable (Function 4408H) call is + fairly easy to implement. Set the appropriate bit + in the device-attribute word for your block device + drivers, and add the necessary code to return the + particular value for your floppies and hard disks. + + + 2. OPEN and CLOSE calls + + OPEN and CLOSE device driver calls are needed only ____ + if you have interrupt-driven I/O. If you omitted + this feature, then you have nothing to do. If you + support interrupt-driven I/O, set the appropriate + bit in the attribute word for your character device + driver and add the necessary code to wait until + your buffers are empty. + +____________________________________________________________ +| | +| Note | +| | +| The same bit in the attribute word is used to indicate | +| that Is-Removable and OPEN/CLOSE is present. This | +| means that you must put in NO-OP stubs for those | +| functions you will not use (simply return with no error | +| for OPEN/CLOSE). MS-DOS assumes that all three of | +| these new functions exist if this attribute bit is set. | +| | +|__________________________________________________________| + + + 3. Background Print Utility + + The third feature (background print spooling to a + network printer) is difficult to implement. You + MAY need to add code to the output loop of the + character device driver that tells the network + portion of MS-DOS that you sent a character to a + particular device. You will also need to modify + the code in NETPS (part of the Redirector) to + receive this input. The skeleton code in NETPS is + for INT 17H (output-to-printer) on the IBM PC. So + there is NO SPECIAL CODE in the IBM PC printer + device drivers as everything is handled by INT 17H. + Your architecture may require a different mechanism. + You may wish to use the INT 2FH mechanism to achieve + this. + + If your architecture doesn't provide for Redirection + at the ROM BIOS entry level (INT 17H on the IBM PC), + your added code in the device driver will signal + the network piece that you have a character + destined for a particular device. The network + piece will decide whether or not that output should + be routed across the network. If so, it will + handle the character and return an indication that + the character was handled. Otherwise, it will + indicate that the device driver should take care of + HOW TO UPGRADE A 2.XX BIOS TO 3.XX Page B-3 + + + it. After this call in the device driver, the code + should examine the return to see if the device + driver should process the character or return. The + code required to do this is quite small, typically + less than 100 bytes. + + There is more information about how this is done + in the Redirector Adaptation Guide that is available + on the MS-NET distribution diskette. + + + + 4. Output-Until-Busy Call + + The fourth feature is a new device call that helps + the performance of the PRINT and PSPRINT + (networking print) utilities. Most printers have + RAM buffers which typically hold a line of + characters or some fixed amount of characters. + These buffers fill up without the printer going + busy. This yields a "burst" type of behavior. A + line of characters can be very quickly output to + the printer, then the printer goes busy for a long + time while the characters are being printed. This + new device call allows the background spooling + programs PRINT and PSPRINT to use this burst + behavior efficiently. Rather than take the + overhead of a device driver call for each + character, or risk getting "stuck" in the device + driver outputting a block of characters, this call + allows a burst of characters to be output without + getting stuck in the device driver waiting for the + device to come ready. + + + APPENDIX C + + HOW TO UPGRADE A 3.10 BIOS TO 3.20 + +The major change in the MS-DOS 3.2 BIOS is in the device drivers. +The device drivers provide the support for the new Generic IOCTL +requests. If some of the new MS-DOS 3.2 features are going to be +used, then the Generic IOCTL functions have to implemented in the +device drivers. For example, the new MS-DOS 3.2 FORMAT utility +has been designed to be hardware independent and uses Generic IOCTL's +extensively. If the Generic IOCTL's are implemented in the device +drivers, then the OEM will not have to modify the FORMAT utility. +Refer to the MS-DOS 3.2 Device Drivers Guide and the MS-DOS 3.2 +Technical Guide for a complete listing of the use of Generic IOCTL's. + +NOTE: Old device drivers will still work under MS-DOS 3.2 without +the Generic IOCTL's, but will not get the benefit of this feature. + +The MS-DOS 3.2 BIOS makes use of a new data structure called +the Block Data Structure (BDS). The BDS is listed in the file +MSBDS.ASM in the sample BIOS disk. This data structure describes +the characteristics of a physical block device. The BDS is filled +in at BIOS initialization time. The physical characteristics +within the BDS can be changed after initialization time by using the +DRVPARM option in the CONFIG.SYS file. Any block device drivers that +have the special MS-DOS 3.2 version bit set in the attribute word +must contain a BDS. The BDS in the device driver will be linked with +the other BDS's of the system at initialization time. +The BDS structure must be used if the Generic Device Driver (DRIVER.SYS) +is to used in the OEM's system. + +The MS-DOS 3.2 BIOS has extended the concept of logical drives. +There can now be more than one logical drive associated with each physical +drive. This logical drive mapping is achieved by using the Generic Device +Driver, DRIVER.SYS. +The extension of logical drives has prompted the idea of "Present Physical +Drive Owner". The Present Physical Drive Owner is the last logical drive +to have accessed a physical drive. This is an important concept because +when a reference is made to a logical drive that is NOT the Present +Physical Drive Owner, the BIOS displays the following message: + + Insert diskette for drive d: and strike + any key when ready + +where d: is the logical drive that was referenced. The Present Physical +Drive Owner is stored in the BDS for the particular physical drive. +Two new IOCTL calls have been introduced in connection with logical +drives. The new calls are GET/SET LOGICAL DRIVE MAP. These two IOCTL's +are important for applications that want to control the printing of the +message to swap disks. The message to swap disks will only be displayed +if the Present Physical Drive Owner is not the same as the logical drive +being referenced. Applications that want to control the printing of this +message (for example, full screen applications that want to display +the swap disk message in a dialogue box) would use these calls to get and +set the Present Physical Drive Owner. + + + + APPENDIX D + + +This material was taken from the MS-DOS 3.20 Programmer's Reference +Manual. It is intended be used with the MS-DOS 2.XX/3.XX Adaptation +Guide. + + + CHAPTER 2 + + MS-DOS DEVICE DRIVERS + + + +2.1 INTRODUCTION + +The IO.SYS file is composed of the "resident" device +drivers, and forms the MS-DOS BIOS. MS-DOS calls upon these +resident drivers to handle I/O requests initiated by +application programs. + +One of the most powerful features of MS-DOS is that it lets +you add new devices such as printers, plotters, or mouse +input devices without rewriting the BIOS. The MS-DOS BIOS +is "configurable;" that is, you can add and preempt new +drivers and existing drivers. You can also add non-resident +device drivers at boot time by using the "DEVICE =" entry in +the CONFIG.SYS file. In this section, these non-resident +drivers are referred to as "installable" to distinguish them +from drivers which, in the IO.SYS file, are considered as +the resident drivers. + +At boot time, a minimum of five resident device drivers must +be present. These drivers are in a linked list. The +"header" of each driver contains a DWORD pointer to the +next. The last driver in the chain has an end-of-list +marker of -1, -1 (all bits on). + +Each driver in the chain has two entry points--the strategy +entry point and the interrupt entry point. MS-DOS does not +take advantage of the two entry points. Instead, it first +calls the strategy routine, then immediately calls the +interrupt routine. + +The dual entry points are provided for future multitasking +versions of MS-DOS. In multitasking environments, I/O must +be asynchronous; to accomplish this, the strategy routine +will be called to (internally) queue a request and return +quickly. It is then the responsibility of the interrupt +routine to perform the I/O at interrupt time by getting +requests from the internal queue and processing them. When +a request is completed, the interrupt routine flags it as +"done." MS-DOS periodically scans the list of requests, +looking for those requests with done flags, and "wakes up" + MS-DOS DEVICE DRIVERS Page 2-2 + + +the process that is waiting for the completion of the +request. + +When requests are queued in this manner, it is no longer +sufficient to pass I/O information in registers, since many +requests may be pending at any one time. Therefore, the +MS-DOS device interface uses "packets" to pass request +information. These request packets vary in size and format +and are composed of two parts: + + + 1. The static request header section, which has the + same format for all requests. + + 2. A section that has information specific to the type + of request. + + +A driver is called with a pointer to a packet. In +multitasking versions, this packet will be linked into a +global chain of all pending I/O requests maintained by +MS-DOS. + +MS-DOS does not implement a global or local queue. Only one +request is pending at any one time. The strategy routine +must store the address of the packet at a fixed location, +and the interrupt routine, which is called immediately after +the strategy routine, should process the packet by +completing the request and returning. MS-DOS assumes that +the request is complete when the interrupt routine returns. + +To make a device driver that SYSINIT can install, you must +create a .BIN (core image) or .EXE format file that contains +the device driver header at the beginning of the file. The +link field should be initialized to -1 (SYSINIT fills it +in). Device drivers that are part of the BIOS should have +their headers point to the next device in the list and the +last header should be initialized to -1,-1. The BIOS must +be a .BIN (core image) format file. + +If you have a non-IBM compatible version of MS-DOS 2.x, you +can use installable device drivers that are in .EXE format. +On the IBM PC (or compatible) DOS 2.x versions, the .EXE +loader is located in COMMAND.COM, which is not present at +the time that MS-DOS is loading the installable devices. + + + +2.2 FORMAT OF A DEVICE DRIVER + +A device driver is a program segment responsible for +communication between DOS and the system hardware. It has a +special header at the beginning identifying it as a device +driver, defining its entry points, and describing its +various attributes. + MS-DOS DEVICE DRIVERS Page 2-3 + + + +------------------------------------------------------------ +| | +| Note | +| | +| For device drivers, the file must not use the ORG 100H | +| (like .COM files). Because it does not use the Program | +| Segment Prefix, the device driver is simply loaded; | +| therefore, the file must have an origin of zero (ORG 0 | +| or no ORG statement). | +| | +|__________________________________________________________| + +There are two kinds of device drivers: + + 1. Character device drivers + + 2. Block device drivers + +Character devices perform serial character I/O. Examples +are the console, communications port, and printer. These +devices have specific names (i.e., CON, AUX, CLOCK, etc.), +and programs may open channels (handles or FCBs) to send I/O +to them. + +Block devices are the "disk drives" on the system. They can +perform random I/O in structured pieces called blocks +(usually the physical sector size). These devices are not +named as the character devices are, and therefore cannot be +opened directly. Instead they have unit numbers and are +identified by drive letters such as A, B, and C. + +A single block device driver may be responsible for one or +more logically contiguous disk drives. For example, the +block device driver ALPHA may be responsible for drives A, +B, C, and D. This means that it has four units defined +(0-3). The position of the driver in the list of all +drivers determines which units correspond to which drive +letters. For example, if driver ALPHA is the first block +driver in the device list, and it defines 4 units (0-3), +then they will be A, B, C, and D. If BETA is the second +block driver and defines three units (0-2), then they will +be E, F, and G, and so on. The theoretical limit is 63, but +the device installation code does not allow the installation +of a device if it would result in a drive letter >`Z' (5AH). +All block device drivers present in the standard resident +BIOS are placed ahead of installable block-device drivers in +the list. + MS-DOS DEVICE DRIVERS Page 2-4 + + +------------------------------------------------------------ +| | +| Note | +| | +| Character devices cannot define multiple units | +| because they have only one name. | +| | +|__________________________________________________________| + + + +2.3 HOW TO CREATE A DEVICE DRIVER + +To create a device driver that MS-DOS can install, you must +create a binary file (.COM or .EXE format) with a device +header at its beginning. Device driver code should not +originate at 100H, but at 0. The device header contains a +link field (pointer to next device header) which should be +-1, unless there is more than one device driver in the file. + +You must also correctly set the attribute field and entry +points. The name field for a character device should +contain the name of that device. This name can be any legal +8-character filename. But if it is less than eight +characters, you should pad it out to eight by typing spaces +(20H). Note that device names do not include colons (:). +The fact that "CON" is the same as "CON:" is a property of +the default MS-DOS command interpreter (COMMAND.COM) and not +of the device driver or MS-DOS interface. All character +device names are handled in this way. + +MS-DOS always processes installable device drivers before +handling the default devices, so to install a new CON +device, simply name the device "CON". Remember to set the +standard input and standard output device bits in the +attribute word on a new CON device. The scan of the device +list stops on the first match, so the installable device +driver takes precedence. + +It is not possible to replace the "resident" disk block +device driver with an installable device driver as you would +replace other device drivers in the BIOS. Block drivers can +be used only for devices not supported directly by the +default disk drivers in IO.SYS. + +------------------------------------------------------------ +| | +| Note | +| | +| Because MS-DOS can install the driver anywhere in | +| memory, you must be careful when making far memory | +| references. You should not expect that your driver | +| will always be loaded in the same place every time. | +| | +|__________________________________________________________| + MS-DOS DEVICE DRIVERS Page 2-5 + + +2.3.1 Device Strategy Routine + + +This routine, which MS-DOS calls for each device driver +service request, is primarily responsible for queuing these +requests in the order in which they are to be processed by +the Device Interrupt Routine. Such queuing can be an +important performance feature in a multitasking environment, +or where asynchronous I/O is supported. Since MS-DOS does +not currently support these facilities, only one request +(usually a short one) can be serviced at a time. In the +coding examples in Section 2.12, each request is simply +stored in a single pointer area. + + + + +2.3.2 Device Interrupt Routine + + +This routine contains the code necessary for processing the +service request. It may interface to the hardware, or it +may use ROM BIOS calls. It usually consists of a series of +procedures, which handle the specific command codes to be +supported, as well as some exit and error-handling routines. +See the coding examples in Section 2.12. + + + + +2.4 INSTALLATION OF DEVICE DRIVERS + +MS-DOS allows new device drivers to be installed dynamically +at boot time. This is accomplished by IO.SYS initialization +code which reads and processes the CONFIG.SYS file. + +MS-DOS calls upon the device drivers to perform their +functions in the following manner: + + + 1. MS-DOS makes a far call to strategy entry. + + 2. MS-DOS passes device driver information in a + request header to the strategy routine. + + 3. MS-DOS then makes a far call to the interrupt + entry. + +This structure can be easily upgraded to support any future +multitasking environment. + MS-DOS DEVICE DRIVERS Page 2-6 + + +2.5 DEVICE HEADERS + +A device header, which is required at the beginning of every +device driver, looks like this: + + +--------------------------------------+ + | DWORD Pointer to next device | + | (Usually set to -1 if this driver | + | is the last or only driver in the | + | file) | + +--------------------------------------+ + | WORD Attributes | + +--------------------------------------+ + | WORD Pointer to device strategy | + | entry point | + +--------------------------------------+ + | WORD Pointer to device interrupt | + | entry point | + +--------------------------------------+ + | 8-BYTE Character device name field | + | Character devices set a device name. | + | For block devices the first byte is | + | the number of units. | + +--------------------------------------+ + + Figure 2.1. Sample Device Header + +Note that the device entry points are words. They must be +offsets from the same segment number used to point to this +table. For example, if XXX:YYY points to the start of this +table, then XXX:strategy and XXX:interrupt are the entry +points. + +The device header fields are described in the following +section. + + + +2.5.1 Pointer to Next Device Field + +This pointer is a double word field (offset followed by +segment). MS-DOS sets this field so that it points to the +next driver in the system list at the time the device driver +is loaded. Unless there is more than one device driver in +the file, it is important that you set this field to -1 +prior to loading (when it is on the disk as a file). If +there is more than one driver in the file, the first word of +the double word pointer should be the offset of the next +driver's device header. + MS-DOS DEVICE DRIVERS Page 2-7 + + + +------------------------------------------------------------ +| | +| Note | +| | +| If there is more than one device driver in the | +| file, the last driver in the file must have the pointer | +| to the next device header field set to -1. | +| | +|__________________________________________________________| + + + +2.5.2 Attribute Field + +The attribute field identifies the type of device this +driver is responsible for. In addition to distinguishing +between block and character devices, these bits give +selected character devices special treatment. (Note that if +a bit in the attribute word is defined only for one type of +device, a driver for the other type of device must set that +bit to 0.) + +For character devices: + + Bit Value Meaning + + 15 1 Character device + 14 1 Device supports + IOCTL control strings + 13 1 Device supports + Output Until Busy (OUB) + 12 RESERVED + 11 1 Device understands + OPEN/CLOSE + 10-7 RESERVED + 6 1 Device supports 3.2 functions + 5-4 RESERVED + 3 1 Device is CLOCK device + 2 1 Device is NUL device + 1 1 Device is console output (STO) + 0 1 Device is console input (STI) + +For Block Devices: + + Bit Value Meaning + + 15 0 Block device + 14 1 Device supports IOCTL control + strings + 13 1 Device determines the media by + examining the FATID byte. + 12 RESERVED + 11 1 Device understands + OPEN/CLOSE/Removable Media. + MS-DOS DEVICE DRIVERS Page 2-8 + + + 10-7 RESERVED + 6 1 Device supports 3.2 functions + 5-0 RESERVED + +For example, assume that you have a new device driver that +you want to use as the standard input and output. In +addition to installing the driver, you must tell MS-DOS that +you want this new driver to override the current standard +input and standard output (the CON device). You do this by +setting bits 0 and 1 to 1 (note that they are separate!). +Similarly, you could install a new CLOCK device by setting +the appropriate attribute. (Refer to Section 2.10, "The +CLOCK Device," in this chapter for more information.) +Although there is a NUL device attribute, you cannot +reassign the NUL device. This attribute exists so that +MS-DOS can determine whether the NUL device is being used. + +The IOCTL bit, bit 14, allows IOCTL functions to send and +receive data to character and block devices for their own +use. This allows them to set baud rate, stop bits, form +length, etc., instead of passing data over the device +channel as a normal read or write does. The interpretation +of the passed information is up to the device, but the +device must not treat this information as normal I/O. This +bit tells MS-DOS whether the device can handle control +strings via the IOCTL system call, Function 44H. + +If a driver cannot process control strings, it should set +this bit initially to 0. This tells MS-DOS to return an +error if an attempt is made (via Function 44H) to send or +receive control strings to this device. A device which can +process control strings should initialize the IOCTL bit to +1. For drivers of this type, MS-DOS makes calls to the +IOCTL INPUT and OUTPUT device functions to send and receive +IOCTL strings. + +For block devices, bit 13 affects the operation of the BUILD +BPB (BIOS Parameter Block) device call. If set, it requires +the first sector of the FAT to reside ALWAYS in the same +place. Bit 13 has a different meaning on character devices, +indicating that the device implements the OUTPUT UNTIL BUSY +device call. + +The OPEN/CLOSE/RM bit, bit 11, signals to MS-DOS 3.x, and +later versions, whether this driver supports additional +MS-DOS 3.0 functionality. But to support these old drivers, +it is necessary to detect them. Bit 11 was reserved in +MS-DOS 2.x, and is 0. All new devices, however, should +support the OPEN, CLOSE, and REMOVABLE MEDIA calls and set +this bit to 1. Since MS-DOS 2.x never makes these calls, +the driver will be backwardly compatible. + +The MS-DOS 3.2 bit, bit 6, signals whether the device +supports logical drive mapping via Function 440EH (Get +Logical Drive Map) and Function 440FH (Set Logical Drive + MS-DOS DEVICE DRIVERS Page 2-9 + + +Map). This bit also supports generic IOCTL functions via +Function 440C (Generic IOCTL for Handles) and Function 440D +(Generic IOCTL for Block Devices). + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +____________________________________________________________ +| C | I | O | | O | | | | | 3 | | | C | N | S | S | +| H | O | Y | | P | | | | | . | | | L | U | T | T | +| R | C | B | | N | | | | | 2 | | | K | L | O | I | +|___|___|___|___|___|___|__|__|__|___|__|__|___|___|___|___| + + Figure 2.? Attribute Word for character devices + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +____________________________________________________________ +| | I | F | | O | | | | | 3 | | | | | | | +| | O | A | | P | | | | | . | | | | | | | +| | C | T | | N | | | | | 2 | | | | | | | +|___|___|___|___|___|___|__|__|__|___|__|__|___|___|___|___| + + Figure 2.? Attribute Word for block devices + + + +2.5.3 Strategy And Interrupt Routines + +These two fields are the pointers to the entry points of the +strategy and interrupt routines. They are word values, so +they must be in the same segment as the device header. + + + +2.5.4 Name Field + +This is an 8-byte field that contains the name of a +character device or the number of units of a block device. +If it is a block device, the number of units can be put in +the first byte. This is optional, because MS-DOS fills in +this location with the value returned by the driver's INIT +code. Refer to Section 2.4, "Installation of Device +Drivers," for more information. + + + +2.6 REQUEST HEADER + +When MS-DOS calls a device driver to perform a function, it +passes a request header in ES:BX to the strategy entry +point. This is a fixed length header, followed by data +pertinent to the function being performed. Note that it is +the device driver's responsibility to preserve the machine +state (for example, save all registers including flags on +entry and restore them on exit). There is enough room on +the stack to do about 20 pushes, when MS-DOS calls either +the strategy or the interrupt routines. If more stack is + MS-DOS DEVICE DRIVERS Page 2-10 + + +needed, the driver should set up its own stack. + +The following figure illustrates a request header. + +REQUEST HEADER -> + +-----------------------------+ + | BYTE Length of record | + | Length in bytes of this | + | request header | + +-----------------------------+ + | BYTE Unit code | + | The subunit the operation | + | is for (minor device) | + | (no meaning on character | + | devices) | + +-----------------------------+ + | BYTE Command code | + +-----------------------------+ + | WORD Status | + +-----------------------------+ + | 8 BYTES Reserved | + | | + |-----------------------------| + + Figure 2.2. Request Header + +The request header fields are described below. + + + +2.6.1 Length of Record + +This field contains the length (in bytes) of the request +header. + + + +2.6.2 Unit Code Field + +The unit code field identifies which unit in your device +driver the request is for. For example, if your device +driver has 3 units defined, the possible values of the unit +code field would be 0, 1, and 2. + + + +2.6.3 Command Code Field + +The command code field in the request header can have the +following values: + + Command Function + Code + + 0 INIT + MS-DOS DEVICE DRIVERS Page 2-11 + + + 1 MEDIA CHECK (Block devices only) + 2 BUILD BPB (Block devices only) + 3 IOCTL INPUT (Only called if device has IOCTL) + 4 INPUT (read) + 5 NON-DESTRUCTIVE INPUT NO WAIT (Char devs only) + 6 INPUT STATUS (Char devs only) + 7 INPUT FLUSH (Char devs only) + 8 OUTPUT (write) + 9 OUTPUT (Write) with verify + 10 OUTPUT STATUS (Char devs only) + 11 OUTPUT FLUSH (Char devs only) + 12 IOCTL OUTPUT (Only called if device has IOCTL) + 13 DEVICE OPEN (Only called if OPEN/CLOSE/RM bit set) + 14 DEVICE CLOSE (Only called if OPEN/CLOSE/RM bit set) + 15 REMOVABLE MEDIA (Only called if OPEN/CLOSE/RM bit + set and device is block) + 16 OUTPUT UNTIL BUSY (Only called if bit 13 is set on + character devices) + 19 Generic IOCTL Request (Only called if bit 0 is set + for block devices) + 23 Get Drive Map (Only called if bit 6 is set on + block devices) + 24 Set Drive Map (Only called if bit 6 is set on + block devices) + +Unused command codes are reserved. + + + +2.6.4 Status Field + +The following figure illustrates the status field in the +request header. + + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ + | E | | B | D | | + | R | RESERVED | U | O | ERROR CODE (bit 15 on)| + | R | | S | N | | + | | | Y | E | | + +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ + +The status word is zero on entry and is set by the driver +interrupt routine on return. + +Bit 8 is the done bit. When set, it means the operation has +completed. The driver sets it to 1 when it exits. + +Bit 15 is the error bit. If it is set, the low 8 bits +indicate the error. The errors are: + + 0 Write protect violation + 1 Unknown unit + 2 Drive not ready + MS-DOS DEVICE DRIVERS Page 2-12 + + + 3 Unknown command + 4 CRC error + 5 Bad drive request structure length + 6 Seek error + 7 Unknown media + 8 Sector not found + 9 Printer out of paper + A Write fault + B Read fault + C General failure + D Reserved + E Reserved + F Invalid disk change + +Bit 9 is the busy bit, which is set only by status calls and +the removable media call. + + + +2.7 DEVICE DRIVER FUNCTIONS + +Device drivers may perform all or some of these nine general +functions. In some cases, these functions break down into +several command codes. Each is described in this section. + + + 1. INIT + + 2. MEDIA CHECK + + 3. BUILD BPB + + 4. READ or WRITE or WRITE TIL BUSY or Write with + Verify or Read IOCTL or Write IOCTL + + 5. NON DESTRUCTIVE READ NO WAIT + + 6. OPEN or CLOSE (3.x) + + 7. REMOVABLE MEDIA (3.x) + + 8. STATUS + + 9. FLUSH + + 10. Generic IOCTL + + 11. Get Logical Device + + 12. Set Logical Device + + +All strategy routines are called with ES:BX pointing to the +Request Header. The interrupt routines get the pointers to +the Request Header from the queue in which the strategy + MS-DOS DEVICE DRIVERS Page 2-13 + + +routines store them. The command code in the request header +tells the driver which function to perform and what data +follows the request header. + +------------------------------------------------------------ +| | +| Note | +| | +| All DWORD pointers are stored offset first, segment | +| second. | +| | +|__________________________________________________________| + + + +2.7.1 INIT + + +Command code = 0 + +INIT - ES:BX -> + +------------------------------------+ + | 13-BYTE Request header | + +------------------------------------+ + | BYTE Number of units | + +------------------------------------+ + | DWORD End Address | + +------------------------------------+ + | DWORD Pointer to BPB array | + | (Not set by character devices) | + +------------------------------------+ + | BYTE Block device number | + +------------------------------------+ + +One of the functions defined for each device driver is INIT. +This routine is called only once when the device is +installed. The INIT routine must return the END ADDRESS, +which is a DWORD pointer to the end of the resident portion +of the device driver. To save space you can use this +pointer method to delete init code that is needed only once. + +The driver sets the number of units, end address, and BPB +pointer. For installable block device drivers, the DWORD +pointer to BPB array now points to the first character after +the equal sign (=) on the line in CONFIG.SYS (the line that +caused this device to be loaded). This line is terminated +by a RETURN or a linefeed. This data is read-only and lets +the device driver scan the CONFIG.SYS line for arguments. + + device=\dev\vt52.sys /l + ^ + |_____BPB address points here + +Also, the block device driver defines the first unit and +assigns it to the drive number in the block device number + MS-DOS DEVICE DRIVERS Page 2-14 + + +field (for example, A=0). This field is also read-only. + +Installable character devices must return only the end +address parameter. This parameter is a pointer to the first +available byte of memory above the location of the driver +and which the driver may use to throw away initialization +code. + + +Block devices must return the following information: + + + 1. The number of units. MS-DOS uses this number to + determine logical device names. At the time of the + install call, if the current maximum logical device + letter is F, and the INIT routine returns 4 as the + number of units, these units will have logical + names G, H, I and J. This mapping is determined by + the position of the driver in the device list and + by the number of units on the device (stored in the + first byte of the device name field). + + + 2. A DWORD pointer to an array of one-word offsets + (pointers) to BPBs (BIOS Parameter Blocks). MS-DOS + creates an internal structure by using the BPBs + passed by the device driver. There must be one + entry in this array for each unit defined by the + device driver. In this way, if all units are the + same, all the pointers can point to the same BPB, + saving space. If the device driver defines two + units, the DWORD pointer points to the first of two + one-word offsets. In turn these offsets point to + BPBs. The format of the BPB is described later in + this chapter in Section 2.7.3, "BUILD BPB." + + Note that this array of one-word offsets must not + be above the free pointer set by the return, + because the device driver builds an internal DOS + structure, starting at the byte pointed to by the + free pointer. The defined sector size must be less + than or equal to the maximum sector size defined by + the resident device drivers (BIOS) during + initialization. If it isn't, the installation will + fail. + + 3. The media descriptor byte. This byte, which is the + last byte returned by INIT, means nothing to + MS-DOS, but is passed to devices so that they know + which parameters MS-DOS is currently using for a + particular drive unit. + + +Block devices may be either dumb or smart. A dumb device ____ _____ +defines a unit (and therefore an internal DOS structure) for + MS-DOS DEVICE DRIVERS Page 2-15 + + +each possible media-drive combination. For example, unit 0 += drive 0, single sided; unit 1 = drive 0, double sided. +For the "dumb device" approach, media descriptor bytes do +not mean anything. A smart device allows multiple media per +unit. In the case of a smart device, the BPB table returned +upon INIT must define sufficient space to accommodate the +largest possible media. Smart drivers use the media +descriptor byte to pass information about what media is +currently in a unit. + +For more information on the media descriptor byte, see +Section 2.8, "Media Descriptor Byte." + +------------------------------------------------------------ +| | +| Note | +| | +| If a file contains multiple device drivers, MS-DOS uses | +| the ending address returned by the last INIT called. | +| All the device drivers in a single file should return | +| the same ending address. The code to remain resident | +| for all the devices in a file should be grouped | +| together in low memory with the initialization code for | +| all devices following it. | +| | +|__________________________________________________________| + + + +2.7.2 MEDIA CHECK + + + +Command Code = 1 + +MEDIA CHECK - ES:BX -> + +------------------------------------+ + | 13-BYTE Request header | + +------------------------------------+ + | BYTE Media descriptor from BPB | + +------------------------------------+ + | BYTE Returned | + +------------------------------------+ + | Returned DWORD pointer to previous | + | Volume ID if bit 11 set and | + | Media Changed is returned | + +------------------------------------+ + + + +The MEDIA CHECK function is used with block devices only. +It is called when there is a pending drive access call other +than a file read or write, such as open, close, delete, or +rename. Its purpose is to determine whether the media in +the drive has been changed. If the driver can ensure that + MS-DOS DEVICE DRIVERS Page 2-16 + + +the media has not been changed (through a door-lock or other +interlock mechanism), MS-DOS does not need to reread the FAT +and invalidate in-memory buffers for each directory access. + +When such a disk access call to the DOS occurs (other than a +file read or write), the following sequence of events takes +place: + + + 1. The DOS converts the drive letter into the unit + number of a particular block device. + + 2. The device driver is then called to request a media + check on that subunit to see if the disk might have + been changed. MS-DOS passes the old media + descriptor byte. The driver returns: + + Media not changed...... (1) + Don't know if changed...(0) + Media changed...........(-1) + Error + + If the media has not been changed, MS-DOS proceeds + with the disk access. + + If the value returned is "Don't know," and if there + are any disk sectors that have been modified and + not yet written back to the disk for this unit, + MS-DOS assumes that the disk has not been changed + and proceeds. MS-DOS invalidates any other buffers + for the unit and does a BUILD BPB device call (see + step 3, below). + + If the media has been changed, MS-DOS invalidates + all buffers associated with this unit including + buffers with modified data that are waiting to be + written, and requests a new BIOS Parameter Block + via the BUILD BPB call (see step 3, below). + + + 3. Once the BPB has returned, MS-DOS corrects its + internal structure for the drive from the new BPB + and, after reading the directory and the FAT, + proceeds with the access. + + +Note that the previous media ID byte is passed to the device +driver. If the old media ID byte is the same as the new +one, the disk might have been changed and a new disk may be +in the drive. Therefore, all FAT, directory, and data +sectors that are buffered in memory for the unit are +considered invalid. + +If the driver has bit 11 of the device attribute word set to +1, and the driver returns -1, "Media Changed," it must set + MS-DOS DEVICE DRIVERS Page 2-17 + + +the DWORD pointer to the previous Volume ID field. If the +DOS determines that "Media Changed" is an error based on the +state of the DOS buffer cache, it generates a 0FH error on +behalf of the device. If the driver does not implement +Volume ID support, but has bit 11 set, it should set a +static pointer to the string, "NO NAME",0. + +It is not possible for a user to change a disk in less than +2 seconds. So when MEDIA CHECK occurs within 2 seconds of a +disk access, the driver reports "1," "Media not changed." +This action increases performance tremendously. + + +------------------------------------------------------------ +| | +| Note | +| | +| For MS-DOS versions before 3.2 if the media ID byte in | +| the returned BPB is the same as the previous media ID | +| byte, MS-DOS assumes that the format of the disk is the | +| same (even though the disk may have been changed) and | +| skips the step of updating its internal structure. All | +| BPBs, therefore, must have unique media bytes regardless| +| of FAT ID bytes. | +| | +|__________________________________________________________| + + + + +2.7.3 BUILD BPB (BIOS Parameter Block) + + +Command code = 2 + +BUILD BPB - ES:BX -> + +------------------------------------+ + | 13-BYTE Request header | + +------------------------------------+ + | BYTE Media descriptor from BPB | + +------------------------------------+ + | DWORD Transfer address | + | (Points to one sector worth of | + | scratch space or first sector | + | of FAT depending on the value | + | of Bit 13 in the device attribute | + | word.) | + +------------------------------------+ + | DWORD Pointer to BPB | + +------------------------------------+ + +The Build BPB function is used with block devices only. As +described in the MEDIA CHECK function, the BUILD BPB +function is called any time that a preceding MEDIA CHECK +call indicates that the disk has been, or might have been, + MS-DOS DEVICE DRIVERS Page 2-18 + + +changed. The device driver must return a pointer to a BPB. +This is different from the INIT call where the device driver +returns a pointer to an array of word offsets to BPBs. + +The BUILD BPB call gets a DWORD pointer to a one-sector +buffer. The contents of this buffer are determined by the +NON FAT ID bit (bit 13) in the attribute field. If the bit +is zero, the buffer contains the first sector of the first +FAT. The FAT ID byte is the first byte of this buffer, so +in this case, the driver must not alter the buffer. Note +that the location of the FAT must be the same as for all +possible media because the DOS must read this FAT sector +before the driver returns the BPB that the DOS called. If +the NON FAT ID bit is set, the pointer points to one sector +of scratch space (space which may be used for anything). +Refer to Section 2.8, "Media Descriptor Byte,"" and Section +2.9, "Format of a Media Descriptor Table," for information +on how to construct the BPB. + +MS-DOS 3.x includes additional support for devices that have +door-locks or some other means of telling when a disk has +been changed. Error 15, a new error that the device driver +can return, means "the disk has been changed when it +shouldn't have been." The user is prompted for the correct +disk using a Volume ID. The driver may generate this error +for READ or WRITE. The DOS may generate the error for MEDIA +CHECK if the driver reports media changed, and there are +buffers in the DOS buffer cache that need to be flushed to +the previous disk. + +For drivers that support this error, the BUILD BPB function +is a trigger that causes the driver to read a new Volume ID +from the disk. This action indicates that the disk has been +legally changed. The FORMAT or LABEL utility places a +Volume ID on the disk. This ID is simply an entry in the +root directory of the disk that has the Volume ID attribute. +The driver stores the Volume ID as an ASCIZ string. + +The requirement that the driver return a Volume ID does not +exclude some other Volume identifier scheme as long as the +scheme uses ASCIZ strings. A NUL (nonexistent or +unsupported) Volume ID is by convention the string: + + DB "NO NAME ",0 + + + + MS-DOS DEVICE DRIVERS Page 2-19 +2.7.4 READ or WRITE + + +Command codes = 3,4,8,9, 12, and 16 + +READ OR WRITE (Including IOCTL) or + OUTPUT UNTIL BUSY - ES:BX -> + +------------------------------------+ + | 13-BYTE Request header | + +------------------------------------+ + | BYTE Media descriptor from BPB | + +------------------------------------+ + | DWORD Transfer address | + +------------------------------------+ + | WORD Byte/sector count | + +------------------------------------+ + | WORD Starting sector number | + | (Ignored on character devices) | + +------------------------------------+ + | Returned DWORD pointer to requested| + | Volume ID if error 0FH | + +------------------------------------+ + + COMMAND CODE REQUEST + + 3 IOCTL READ + 4 READ (block or character) + 8 WRITE (block or character) + 9 WRITE WITH VERIFY + 12 IOCTL WRITE + 16 OUTPUT TIL BUSY (char devs only) + + +The driver must perform the READ or WRITE call depending on +which command code is set. Block devices read or write +sectors; character devices read or write bytes. + +When I/O completes, the device driver must set the status +word and report the number of sectors or bytes successfully +transferred, even if an error prevented the transfer from +being completed. Setting the error bit and error code alone _______ ___ _____ ___ ___ _____ ____ _____ +is not sufficient.__ ___ __________ + +In addition to setting the status word, the driver must set +the sector count to the actual number of sectors (or bytes) +transferred. No error check is performed on an IOCTL I/O +call. + +If the verify switch is on, the device driver is called with +command code 9 (WRITE WITH VERIFY). Your device driver is +then responsible for verifying the write. + +If the driver returns error code 0FH (Invalid disk change), +it must return a DWORD pointer to an ASCIZ string (which is +the correct Volume ID). The return of this error code +triggers the DOS to prompt the user to re-insert the disk. +The device driver should have read the Volume ID as a result +of the BUILD BPB function. + +Drivers may maintain a reference count of open files on the +disk by monitoring the OPEN and CLOSE functions. This +allows the driver to determine when to return error 0FH. If +there are no open files (reference count = 0), and the disk + MS-DOS DEVICE DRIVERS Page 2-20 + + +has been changed, the I/O is okay. If there are open files, +however, an 0FH error may exist. + +The OUTPUT UNTIL BUSY call is a speed optimization on +character devices only for print spoolers. The device +driver is expected to output all the characters possible +until the device returns busy. Under no circumstances +should the device driver block during this function. Note +that it is not an error if the device driver returns a +smaller number of bytes output than bytes requested. + +The OUTPUT UNTIL BUSY call allows spooler programs to take +advantage of the burst behavior of most printers. Many +printers have on-board RAM buffers which typically hold a +line or a fixed amount of characters. These buffers fill up +without making the printer "busy" between characters for a +relatively short time (or at least not for more than ten +instructions). The device driver can quickly output a line +of characters to the printer, which is then busy for a +comparatively longer time while it prints. This new device +call allows background spooling programs to use this burst +behavior efficiently. Rather than take the overhead of a +device driver call for each character, or risk getting stuck +in the device driver outputting a block of characters, this +call allows a burst of characters to be output without the +device driver having to wait until the device is ready. + +If the MS-DOS 3.2 bit is set, then MS-DOS can configure the +number of retries (allowed by the device driver) that the +printer can make before returning "busy." + +THE FOLLOWING APPLIES TO BLOCK DEVICE DRIVERS:___ _________ _______ __ _____ ______ _______ + +Under certain circumstances, the device driver may request +that the BIOS perform a write operation of 64K bytes, which +seems to be a "wrap around" of the transfer address in the +BIOS I/O packet. This request arises due to an optimization +added to the write code in MS-DOS. It will only manifest +itself on user writes within a sector size of 64K bytes to +files "growing" past the current EOF. The BIOS may ignore ___ ____ ___ ______ +the balance of the write that "wraps around," if it so___ _______ __ ___ _____ ____ ______ ________ __ __ __ +chooses. For example, a write of 10000H bytes worth of________ +sectors with a transfer address of XXX:1 could ignore the +last two bytes. A user program can never request an I/O of +more than FFFFH bytes and cannot wrap around (even to 0) in +the transfer segment. Therefore, in this case the BIOS +ignores the last two bytes. + +MS-DOS maintains two FATs. If the DOS has problems reading +the first, it automatically tries the second before +reporting the error. The BIOS is responsible for all +retries. + +Although the COMMAND.COM handler does no automatic retries, +there are applications that have their own Interrupt 24H + MS-DOS DEVICE DRIVERS Page 2-21 + + +handlers. These handles do automatic retries on certain +types of Interrupt 24H errors before reporting them. + + + + +2.7.5 NON DESTRUCTIVE READ NO WAIT + + +Command code = 5 + +NON DESTRUCTIVE READ NO WAIT - ES:BX -> + +------------------------------------+ + | 13-BYTE Request header | + +------------------------------------+ + | BYTE read from device | + +------------------------------------+ + +This call lets MS-DOS look ahead one input character. The +device sets the done bit in the status word. + +If the character device returns busy bit = 0, characters are +in the buffer and the next character that would be read is +returned. This character is not removed from the input ___ +buffer (hence the term "Non Destructive Read"). If the +character device returns busy bit = 1, there are no +characters in the buffer. + + + +2.7.6 OPEN or CLOSE + + +Command codes = 13 and 14 + +OPEN or CLOSE - ES:BX -> + +------------------------------------+ + | 13-BYTE Static request header | + +------------------------------------+ + +These functions are called by MS-DOS 3.x only if the device +driver sets the OPEN/CLOSE/RM attribute bit in the device +header. They are designed to inform the device about its +current file activity. On block devices, these functions +can manage local buffering, and the device can keep a +reference count. + +Every OPEN causes the device to increment the count, every +CLOSE to decrement. When the count goes to zero no open +files are on the device. Also, the device should flush any +buffers that it may have used in case the media has been +changed. + +Block devices can have problems with this mechanism because +programs that use FCB calls can open files without closing + MS-DOS DEVICE DRIVERS Page 2-22 + + +them. Therefore, when the media has been changed and the +BUILD BPB call has been made to the device, you should reset +the count to zero without flushing the buffers. + +These calls are more useful on character devices. For +example, the device could use the OPEN call to send a device +initialization string. For example, this string might set a +printer's default characteristics for font and page size. +Using IOCTL to set these pre- and post-strings provides a +flexible mechanism of serial I/O device stream control. A +driver could also use the reference count mechanism to +detect a simultaneous access error. You may not want to +allow more than one OPEN on a device at any given time, +since, in this case, a second OPEN would result in an error. + +Note that since all processes have access to stdin, stdout, +stderr, stdaux, and stdprn (handles 0,1,2,3,4), the CON, +AUX, and PRN devices are always open. ______ + + + +2.7.7 REMOVABLE MEDIA + + +Command code = 15 + +REMOVABLE MEDIA - ES:BX -> + +------------------------------------+ + | 13-BYTE Static request header | + +------------------------------------+ + +This function is called by MS-DOS 3.x only if the device +driver sets the OPEN/CLOSE/RM attribute bit in the device +header. Only a subfunction of the IOCTL system call can +issue this call to block devices. Sometimes it is necessary +for a utility to know whether it is using a non-removable +media drive (a hard disk), or a removable media drive (a +floppy). For example, the FORMAT utility prints different +prompts depending on the media. + +The information returns in the busy bit of the status word. +If the busy bit is 1, the media is non-removable, and if the +busy bit is 0, the media is removable. Note that the device +driver does not check the error bit; it just assumes that +this call always succeeds. + + + + MS-DOS DEVICE DRIVERS Page 2-23 +2.7.8 STATUS + + +Command codes = 6 and 10 + +STATUS Calls ES:BX -> + +------------------------------------+ + | 13-BYTE request header | + +------------------------------------+ + +This call returns information to the DOS to let it know if +data is waiting for input or output. All the driver must do +is set the status word and the busy bit as follows: + + For output on character devices: If the driver ___ ______ __ _________ _______ + sets bit 9 to 1 on return, it informs the DOS that + a write request (if made) would wait for completion + of a current request. If bit 9 is 0, there is no + current request and a write request (if made) would + start immediately. + + For input on character devices with a buffer: If ___ _____ __ _________ _______ ____ _ ______ + bit 9 equals 1 this implies that the buffer is + empty and that a read request (if made) would go to + the physical device. If bit 9 is 0 on return, + characters are in the device buffer and a read + request would start immediately. A return of 0 + implies that you have typed something. MS-DOS + assumes that all character devices have an input + type-ahead buffer; devices that do not should + always return busy = 0 so that the DOS does not + wait for you to put something into a non-existent + buffer. + + + + +2.7.9 FLUSH + + +Command codes = 7 and 11 + +FLUSH Calls - ES:BX -> + +------------------------------------+ + | 13-BYTE request header | + +------------------------------------+ + +The FLUSH call tells the driver to flush (terminate) all +pending requests. This call is used to flush the input +queue on character devices. The device driver performs the +flush function, sets the status word, and returns. + + + + MS-DOS DEVICE DRIVERS Page 2-24 +2.7.10 Generic IOCTL Request + + +Command code = 19 + +ES:BX --> +----------------------------------+ + | 13-BYTE Static Request Header | + +----------------------------------+ + | BYTE Category (Major) Code | + +----------------------------------+ + | BYTE Function (Minor) Code | + +----------------------------------+ + | WORD (SI) contents | + +----------------------------------+ + | WORD (DI) contents | + +----------------------------------+ + | DWORD pointer to data buffer | + +----------------------------------+ + +This function provides a generic, expandable IOCTL facility +that replaces and makes the Read IOCTL and Write IOCTL +device driver functions obsolete. The MS-DOS 2.0 IOCTL +functions remain to support existing uses of the IOCTL +system call (subfunctions 2, 3, 4 and 5), but new device +drivers should use this generic MS-DOS IOCTL facility. + +The generic IOCTL function contains both a category and +function code. The DOS examines the category field in order +to intercept and obey device commands that are actually +serviced by the DOS code; all other command categories are +forwarded to the device driver for servicing. + +For more information on these category and function codes, +refer to Functions 440CH (Generic IOCTL for handles) and +Function 440DH (Generic IOCTL for block devices) in Chapter +1, "System Calls." + + + +2.7.11 Get/Set Logical Drive Map + + +Command code = 23 (Get) or 24 (Set) + + +-------------------------------------------+ + | 13-byte Static Request Header | + +-------------------------------------------+ + | BYTE Input (unit code) | + +-------------------------------------------+ + | BYTE Output (last device referenced) | + +-------------------------------------------+ + | BYTE Command code | + +-------------------------------------------+ + | WORD Status | + +-------------------------------------------+ + | DWORD Reserved | + +-------------------------------------------+ + +This function is only called by MS-DOS if the device driver +sets the DOS 3.2 attribute bit in the device header. The +call is only issued to block devices by a subfunction of the +IOCTL system call. The logical drive is passed in the UNIT +field of the header to the device driver, which returns the + MS-DOS DEVICE DRIVERS Page 2-25 + + +current logical drive that is mapped on the physical drive +in the UNIT field of the header. + + + +2.8 MEDIA DESCRIPTOR BYTE + +In MS-DOS, the media descriptor byte informs the DOS that a +different type of media is present. The media descriptor +byte can be any value between 0 and FFH. It does not have +to be the same as the FAT ID byte. The FAT ID byte, which +is the first byte of the FAT, was used in MS-DOS 1.00 to +distinguish between different types of disk media. This +byte may also be used under 2.x and 3.x disk device drivers. +However, FAT ID bytes have significance only for block +device drivers where the NON FAT ID bit is not set (0). + +Values of the media descriptor byte or the FAT ID byte have +no significance to MS-DOS. They are passed directly to the +device driver so that programs can determine the media type. + + + +2.9 FORMAT OF A MEDIA DESCRIPTOR TABLE + +The MS-DOS file system uses a linked list of pointers (one +for each cluster or allocation unit) called the File +Allocation Table (FAT). Unused clusters are represented by +zero and end-of-file by FFF (or FFFF on units with 16-bit +FAT entries). No valid entry should ever point to a zero +entry, but if one does, the first FAT entry (which would be +pointed to by a zero entry) should be reserved and set to +end-of-chain. Eventually, several end-of-chain values can +be defined ([F]FF8-[F]FFF), and used to distinguish +different media types. + +A preferrable technique is to write a complete media +descriptor table in the boot sector and use it for media +identification. To ensure backward compatibility for +systems whose drivers do not set the NON FAT ID bit +(including the IBM PC implementation), it is necessary to +write the FAT ID bytes during the FORMAT process. + +In the future to allow more flexibile support for many +different disk formats, you should keep the information +relating to the BPB for a particular media in the boot +sector. Figure 2.3 shows the format of such a boot sector. + MS-DOS DEVICE DRIVERS Page 2-26 + + + + +------------------------------------+ + | 3 BYTE Near JUMP to boot code | + +------------------------------------+ + | 8 BYTES OEM name and version | + ---+------------------------------------+--- + B | WORD Bytes per sector | + P +------------------------------------+ + B | BYTE Sectors per allocation unit | + +------------------------------------+ + | | WORD Reserved sectors | + V +------------------------------------+ + | BYTE Number of FATs | + +------------------------------------+ + | WORD Number of root dir entries | + +------------------------------------+ + | WORD Number of sectors in logical | + ^ | image | + | +------------------------------------+ + B | BYTE Media descriptor | + P +------------------------------------+ + B | WORD Number of sectors per FAT | + ---+------------------------------------+--- + | WORD Sectors per track | + +------------------------------------+ + | WORD Number of heads | + +------------------------------------+ + | WORD Number of hidden sectors | + +------------------------------------+ + | WORD High order number of hidden | + | sectors | + +------------------------------------+ + | DWORD Number of logical sectors | + +------------------------------------+ + + Figure 2.3. Format of Boot Sector + +Although MS-DOS does not use the five fields that follow the +BPB, they may be used by a device driver to help it +understand the media. + +The "Sectors per track" and "Number of heads" fields are +useful for supporting different media which may have the +same logical layout, but a different physical layout (e.g., +40 track double-sided versus 80 track single-sided). +"Sectors per track" tells the device driver how the logical +disk format is laid out on the physical disk. + +The "Number of hidden sectors" and the "High order number of +hidden sectors" fields may be used to suport +drive-partitioning schemes. + +The "Number of logical sectors" field is not currently used +but will tell the device driver how many sectors to reserve +if the "Number of sectors in logical image" field is zero. + MS-DOS DEVICE DRIVERS Page 2-27 + + +(This is intended for supporting drives that access more +than 32 megabytes.) + +NON FAT ID format drivers should use the following procedure +to determine media type: + + + 1. Read the boot sector of the drive into the 1-sector + scratch space pointed to by the DWORD Transfer + address. + + 2. Determine whether the first byte of the boot sector + is either E9H (the first byte of a 3-byte NEAR or + 2-byte short jump) or EBH (the first byte of a + 2-byte jump followed by a NOP). If it is, return a + pointer to a BPB beginning at offset 3. + + + 3. If the boot sector does not have a BPB table, it is + probably a disk formatted under a 1.x version of + MS-DOS. Therefore, it probably uses a FAT ID byte + for determining media. + + As an option, the driver may attempt to read the + first sector of the FAT into the 1-sector scratch + space and then read the first byte to determine the + media type. Return a pointer to a hard-coded BPB. + + + + +2.10 THE CLOCK DEVICE + +MS-DOS assumes that some sort of clock is available in the +system. This clock may be either a CMOS real-time clock or +an interval timer which the user initializes at boot time. +The CLOCK device defines and performs functions like any +other character device except that the DOS identifies it by +a bit in the attribute word. Consequently this device may +take any name. The IBM version uses "$CLOCK" to avoid +conflict with existing files named "CLOCK." + +The CLOCK device is unique because MS-DOS reads or writes a +6-byte sequence that encodes the date and time. A write to +this device sets the date and time, and a read gets the date +and time. + +Figure 2.4 illustrates the binary time format which the +CLOCK device uses: + + + MS-DOS DEVICE DRIVERS Page 2-28 + + byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 ++--------+--------+---------+--------+--------+---------+ +| | | | | | | +|days since 1-1-80| minutes | hours | sec/100| seconds | +|low byte|hi byte | | | | | ++--------+--------+---------+--------+--------+---------+ + + Figure 2.4. CLOCK Device Format + + + +2.11 ANATOMY OF A DEVICE CALL + +The following steps illustrate what happens when MS-DOS +calls on a block device driver to perform a WRITE request: + + + 1. MS-DOS writes a request packet in a reserved area + of memory. + + + 2. It then calls the block device driver strategy + entry point. + + + 3. The device driver saves the ES and BX registers + (ES:BX points to the request packet) and does a FAR + return. + + + 4. MS-DOS calls the interrupt entry point. + + + 5. The device driver retrieves the pointer to the + request packet and reads the command code (offset + 2) to determine that this is a write request. The + device driver converts the command code for an + index into a dispatch table and passes control to + the disk write routine. + + + 6. The device driver reads the unit code (offset 1) to + determine which disk drive it should write to. + + + 7. Since the command is a disk write, the device + driver must get the transfer address (offset 14), + the sector count (offset 18), and the start sector + (offset 20) in the request packet. + + + 8. The device driver translates the first logical + sector number into a track, head, and sector + number. + + MS-DOS DEVICE DRIVERS Page 2-29 + + + 9. The device driver writes the specified number of + sectors, starting at the beginning sector on the + drive defined by the unit code (the subunit defined + by this device driver), and transfers data from the + address indicated in the request packet. Note that + this may involve multiple write commands to the + disk controller. + + + 10. After the transfer is complete, the device driver + must report the status of the request to MS-DOS by + setting the done bit in the status word (offset 3 + in the request packet). It reports the number of + sectors actually transferred in the sector count + area of the request packet. + + + 11. If an error occurs, the driver sets the done bit + and the error bit in the status word and fills in + the error code in the lower half of the status + word. The number of sectors actually transferred + must be written in the request header. It is not + sufficient just to set the error bit of the status + word. + + + 12. Finally, the device driver does a FAR return to + MS-DOS. + + +The device drivers should preserve the state of MS-DOS, +including all registers (and flags). In particular, the +direction flag and interrupt enable bits are critical. When +the interrupt entry point in the device driver is called, +MS-DOS has room for about 40 to 50 bytes on its internal +stack. Your device driver should switch to a local stack if +it uses extensive stack operations. + APPENDIX E + + + MSDOS 2.25 Device Driver Interface Extension. + + + MSDOS 2.25 is designed so as to be able to run with + CONSOLE DEVICE DRIVERS FROM PREVIOUS VERSIONS. If this is + the case then no interim character processing can be done, + and all character composition must be handled directly by + the console device driver. + + The MSDOS 2.25 BIOS interface (IO.SYS) has the + following differences from the standard MSDOS 2.11 BIOS. + These changes are extensions to the CON (Console) Device + driver for hardware which will be utilizing Interim + Character support. Consult the MSDOS Adapatation Guide + for overall description of device driver design and + funtionality + + 1) On the INPUT and NON-DESTRUCTIVE INPUT calls to the + device driver (DD) the DD must check bit 0 of the byte at + offset 14 in the request packet. If the bit is 0 then it + should return only final characters, if the bit is 1 then + the device driver should return interim as well as final + characters to the dos. + + Also on INPUT, if the request is for more than ONE byte + then the DD should return ONLY final characters, no matter + what the state of bit 0 in the byte at offset 14. + + 2) On return from INPUT, NON-DESTRUCTIVE INPUT and + INPUT STATUS calls, the device driver should return to the + dos with bit 10 of the status word SET if the character + read, or the character available is an interim character, or + the bit RESET if the character is a final character. (Pre + 2.25 DD's always return with this bit reset). If more than + one character is read on an INPUT call then bit 10 should be + RESET as all the characters returned should be final + characters (see above). + + 3) On Console WRITE function the device driver should + check bit 0 of the byte at offset 14 in the request packet. + If the bit is reset then the character should be output as a + regular character by printing the character and advancing + the cursor to the next position. If the bit is SET then the + character is an interim character and should be treated by + the device driver display routine accordingly. In most cases + the character should be displayed without advancing the + cursor to the next character position. When using interim 16 + bit characters that are output a byte at a time, then the + routine should handle this correctly, displaying the 16 bit + interim and not advancing the cursor to the next character + position. + + Special considerations / requirements. + + If a console device driver is going to return interim + characters then the device driver MUST be able to handle the + extension made to character WRITE (described above in 3). + + Device drivers should be able to support requests for + final / interim characters in any order. Application + programs may at any time change the way they want + characters, and device drivers should be capable of changing + without any other indication than the DD request itself. + + Device drivers should be capable of handling + composition somehow for those applications that do not do it + themselves. + + The keyboard typeahead buffer should be kept at the key + level, without further interpretation. All processing of + interims in case of an input request for a final character + is issued (and there are interims in the buffer that have to + be composed to obtain a final character), should be done at + the time the request is done to the device driver. + + + +Sample Device Driver for DOS 2.25 Interim Character Support +WARNING!! Not Assembleable. This code must be modified for +the OEM's own hardware and firmware. + + +PAGE + +CODE SEGMENT BYTE + + ASSUME CS:CODE,DS:NOTHING,ES:NOTHING +;---------------------------------------------------------------- +; +; C O N - CONSOLE DEVICE DRIVER +; + DW -1,-1 + DW 1000000000010011B ; CON IN AND CON OUT + Special bit + DW STRATEGY + DW ENTRY + DB 'CON ' + + +InterH db 0 ; Interim character flag +ALTAH DB 0 ; Special key handling + + +;---------------------------------------------------------------- +; +; COMMAND JUMP TABLES +CONTBL: + DW CON$INIT + DW EXIT + DW EXIT + DW CMDERR + DW CON$READ + DW CON$RDND + DW EXIT + DW CON$FLSH + DW CON$WRIT + DW CON$WRIT + DW EXIT + DW EXIT + + +PAGE +;---------------------------------------------------------------- +; +; Device entry point +; +CMDLEN = 0 ;LENGTH OF THIS COMMAND +UNIT = 1 ;SUB UNIT SPECIFIER +CMD = 2 ;COMMAND CODE +STATUS = 3 ;STATUS +MEDIA = 13 ;MEDIA DESCRIPTOR +TRANS = 14 ;TRANSFER ADDRESS +COUNT = 18 ;COUNT OF BLOCKS OR CHARACTERS +START = 20 ;FIRST BLOCK TO TRANSFER + +BRKADR = Oem_Brk ; Break Vector Address +CHROUT = 29H ; fast con int + + +PAGE +;---------------------------------------------------------------- +; +; Entry Procedures +; + +PTRSAV DD 0 + +STRATP PROC FAR + +STRATEGY: + MOV WORD PTR CS:[PTRSAV],BX + MOV WORD PTR CS:[PTRSAV+2],ES + RET + +STRATP ENDP + +ENTRY: + PUSH SI + PUSH AX + PUSH CX + PUSH DX + PUSH DI + PUSH BP + PUSH DS + PUSH ES + PUSH BX + + LDS BX,CS:[PTRSAV] ; DS:BX points to IO packet + + mov cx,word ptr ds:[bx].count ; CX = count + mov dl,byte ptr ds:[bx].media ; DL = input type flag + mov al,byte ptr ds:[bx].cmd ; AL = command code + cbw + MOV SI,OFFSET CONTBL ; command table + ADD SI,AX + ADD SI,AX + CMP AL,11 + JA CMDERR ; command code out of range + + LES DI,DWORD PTR DS:[BX].TRANS ; transfer address + PUSH CS + POP DS + ASSUME DS:CODE + + JMP WORD PTR [SI] ; GO DO COMMAND + + +PAGE +;---------------------------------------------------------------- +; +; EXIT - ALL ROUTINES RETURN THROUGH THIS PATH +; + +CMDERR: + MOV AL,3 ; Unknown Command Error +ERR$EXIT: + mov ah,10000001b ; Mark Error Return + jmp short err1 + +BUS$EXIT: + mov ah,00000011b ; Device Busy Exit + jmp short err1 + +HanExit: + mov [InterH],0 ; reset interim flag + mov ah,00000101b ; Bit 10 Set for interim chars + jmp short err1 + + +EXITP PROC FAR + +EXIT: MOV AH,00000001B +ERR1: LDS BX,CS:[PTRSAV] + MOV WORD PTR [BX].STATUS,AX ; Mark Operation Complete + + POP BX + POP ES + POP DS + POP BP + POP DI + POP DX + POP CX + POP AX + POP SI + RET ; RESTORE REGS AND RETURN +EXITP ENDP + + +PAGE +;---------------------------------------------------------------- +; +; BREAK KEY HANDLING +; +BREAK: + MOV CS:ALTAH,3 ; INDICATE BREAK KEY SET + IRET + + +;---------------------------------------------------------------- +; +; CHROUT - WRITE OUT CHAR IN AL USING CURRENT ATTRIBUTE +; +; CALLED VIA INT 29H +; + +OUTCHR: + INT OEM_Char_Output + RET + + +PAGE +;---------------------------------------------------------------- +; +; INPUT SINGLE CHAR INTO AL +; + +ChrIn: + xor ax,ax + xchg al,ALTAH ; Get Character & Zero ALTAH + or al,al + jnz sj3 + mov ah,Request_Interim ; assume interim char input + or dl,dl ; Interim chars wanted? + jnz sj0 + mov ah,Request_Char ; regular whole char input +sj0: + int OEM_Kybd_Input ; Get character + or ax,ax ; Check for non-key after BREAK + jz ChrIn + or al,al ; Special Case? + jnz ChkInter + mov ALTAH,ah ; Save Special Key +sj3: + mov [InterH],0 ; reset interim flag + ret + +ChkInter: + cmp ah,Hangeul_Interim ; a Hangeul interim? + jne sj3 + mov [InterH],1 ; yes flag it + ret + +PAGE +;---------------------------------------------------------------- +; +; CONSOLE READ ROUTINE +; +; Input: +; CX = transfer count +; DL = input type flag (0 = whole chars, 1 = interim allowed) +; ES:DI = transfer addess +; + +CON$READ: + JCXZ CON$EXIT +CON$LOOP: + CALL CHRIN ; GET CHAR IN AL + STOSB ; STORE CHAR AT ES:DI + LOOP CON$LOOP +CON$EXIT: + cmp [InterH],1 ; An Intermidiate Char? + jne ExVec ; no, regulear exit + JMP HanExit ; yes, reset flag and exit new way + + +PAGE +;---------------------------------------------------------------- +; +; KEYBOARD FLUSH ROUTINE +; + +CON$FLSH: + MOV [ALTAH],0 ; Clear out holding buffer + mov [InterH],0 + mov ah,Flush_Buffer + int OEM_Kybd_Input + JMP EXIT + +PAGE +;---------------------------------------------------------------- +; +; KEYBOARD NON DESTRUCTIVE READ, NO WAIT +; Input: +; DL = input type flag (0 = whole chars, 1 = interim allowed) +; + +EXVEC: JMP EXIT +CONBUS: JMP BUS$EXIT + +CON$RDND: + MOV AL,[ALTAH] + OR AL,AL + JNZ sj6 + MOV AH,Request_Interim_Status ;Assume interim allowed + or dl,dl ; check interim flag + jnz sj4 + mov ah,Requst_Std_Status ; regular status wanted +sj4: + INT OEM_Kybd_Input ; Get status + JZ CONBUS + OR AX,AX + JNZ sj6 ; CHECK FOR NULL AFTER BREAK + MOV AH,Request_Char + INT OEM_Kybd_Input ; READ THE NULL + JMP short CON$RDND ; AND GET A REAL STATUS +sj6: + MOV [InterH],0 ; not interim +sj7: + LDS BX,[PTRSAV] + MOV [BX].MEDIA,AL ; return the char to dos + cmp [InterH],0 + je EXVEC + jmp HanExit +sj8: + cmp ah,Interim_Char ; a Hangeul interim? + jne sj6 + mov [InterH],1 + jmp short sj7 + + + + +PAGE +;---------------------------------------------------------------- +; +; CONSOLE WRITE ROUTINE +; + +CON$WRIT: + JCXZ EXVEC + cmp dl,01h ; write and not ad cursor? + je CON$LP2 +CON$LP: MOV AL,ES:[DI] ; GET CHAR + INC DI + MOV AH,Output_Char + INT CHROUT ; OUTPUT CHAR + LOOP CON$LP ; REPEAT UNTIL ALL THROUGH + JMP EXIT + +CON$LP2: ; write but do not advance cursor + MOV AL,ES:[DI] ; GET CHAR + INC DI + MOV AH,Output_No_Advance + INT CHROUT + LOOP CON$LP2 ; REPEAT UNTIL ALL THROUGH + JMP EXIT + + +PAGE +;---------------------------------------------------------------- +; +; Initialization Code +; + +CON$INIT: + XOR BX,BX + MOV DS,BX + MOV BX,BRKADR + MOV WORD PTR [BX],OFFSET BREAK + MOV WORD PTR [BX+2],CS + + MOV BX,CHROUT*4 + MOV WORD PTR [BX],OFFSET OUTCHR + MOV WORD PTR [BX+2],CS + + LDS BX,CS:[PTRSAV] + MOV WORD PTR [BX].TRANS,OFFSET CON$INIT ; SET BREAK ADDRESS + MOV [BX].TRANS+2,CS + JMP EXIT + +CODE ENDS + END + + + APPENDIX F + + + + MSDOS 2.25 Application Level Interface Extension + + + + 1) System call 63H, get_lead_tbl. + + This call takes an argument in register AL. This + argument determines what function will this call execute. + Valid values for the function code are 0, 1 and 2. + + If AL = 0, then the call returns in DS:SI a pointer to + a table containing the lead byte ranges for the 16 bit + alphabet in question. The table consists of byte pairs that + are the boundaries for the lead bytes (both values + inclusive). The end of the table is marked by two zero byte + entries. + + Example, for japanese kanji the table would look like + + db 81H,9FH + db 0E0h,0FCh + db 0,0 + + Note that the values should be read as byte values not + as word values since otherwise the ranges would be + transposed due to the byte ordering in the 8086/88. + + This table is empty in the regular version of the dos + (as there are no 16 bit characters). The table if obtained + would point to a pair of zero bytes. + + If AL = 1 then the call will set (or reset) the interim + console flag in the dos depending on the value in DL. If DL + = 1, then the interim flag will be SET, and certain console + system calls will return interim characters if these are + available. If DL = 0 then the interim flag is RESET and only + final characters will be returned. The default value of the + flag is RESET. All application programs start with the flag + RESET. The flag is allways restored to the parents setting + when an application terminates. + + If AL = 2 then the dos will return in DL the current + value of the console interim flag (0 if RESET, 1 if SET). + + If an invalid code is used the call will reurn with + carry set and error code 0 (error_invalid_function). + + IMPORTANT NOTE: This system call unlike all other + system calls make NO GUARANTEE to preserve ANY registers + other than SS:SP upon return. So care should be taken to + save all relevant registers before issuing the call. It is + advisable that an application either copy the table to its + + + + + + + private data area or save the pointer to the table at + initialization time. This should save considerable execution + time as there is no need to reissue the call everytime a + check for 16 bit characters is necessary, and consequently + there is no need to save any registers before issuing the + call. + + 2) Console i/o system calls. + + Some console i/o system calls are capable of returning + interim character information to application programs. Only + those applications that have enabled the feature through the + 63H call (function 1) will receive interim characters on + these system calls, otherwise the dos will never return + interim characters and the system calls will work as in + previous versions of 2.00. + + * Call 01H, Read & Echo. + + This call never returns interim characters no matter + what mode the console is on. Composition if any will take + place at the cursor. It will return when the first byte of + the final character is obtained. + + + * Call 06H, Direct Console i/o. + + Always returns final characters, never interims. Only + returns character available when a final character is + available, not when interims are available. Composition if + any is handled as in call 01H. + + * Call 07H, Direct Console Input. + + Returns interim characters if one is available and the + console mode has been set to interim through the 63H call. + Interim characters are returned with the zero flag SET, + final characters have the flag RESET. In non interim support + (the default) the zero flag value is undefined. + + * Call 08H, Read Keyboard. + + Same as system call 07H. + + * Call 0AH, Buffered Keyboard input. + + Always returns a string of final characters, + composition if any, is handled by the dos. + + * Call 0BH, Check Keyboard Status. + + This call supports interim characters if the console + has been placed in interim mode through the ioctl call. If a + character is available (AL = 0FFH) then the zero flag will + + + + + + + be SET if the character is an interim, or RESET if the + character is a final character. The zero flag is undefined + if either there is no character available, or the console is + not in interim mode. + + * Call 0CH, Flush Buffer, Read Keyboard. + + This call will flush the type-ahead buffer and execute + the specified console i/o call. The con i/o call will work + as described above for each specific case. + + * Call 3FH, Xenix Read. + + This call always returns final characters, no matter + what the state of the dos. This call when directed to the + console it ends up in the buffered console input code, and + so it will act as that call (0AH) when used to read from the + console. + + APPENDIX G + + +This file is part of what was formerly supplied with MS-DOS 2.11 +as SPECIAL.DOC. It has information about undocumented COMMAND.COM +switches and the version dependent system call (GET_DPB) which +OEM's may use when writing format. + +The remaining portions of this file have been incorporated into +printed MS-DOS documentation. + + +COMMAND invocation + +COMMAND [[:]] [] [/D] [/P] [/C ] [/E:nnnn] + + /P If present COMMAND will be permanent, otherwise + this is a transient command. + + /D If present COMMAND will not prompt for DATE and + TIME when it comes up. + + d: Specifies device where command will look for + COMMAND.COM current default drive if absent. + + Specifies a directory on device d: root + directory if absent. + + Name of the CTTY device. \DEV\CON if absent + and command is permanent. The \DEV\ may be left + off if AVAILDEV is TRUE (see sysinit doc). + + /C If present /C must be the last switch. + This causes COMMAND to try to execute the string + as if the user had typed it at the standard input. + COMMAND executes this single command string and + then exits. If the /P switch is present it is + ignored (can't have a single command, permanent + COMMAND). NOTE: ALL of the text on the command + line after the /C is just passed on. It is not + processed for more arguments, this is why /C must + be last. + + /E:nnnn Set the environment size to nnnn (specified in + decimal bytes). The environment size can be between + 128 bytes and 32768 bytes. NOTE: This feature is only + available in versions of MS-DOS starting with 3.20. + + +GET_DPB UNDOCUMENTED SYSTEM CALL. THIS CALL MAY BE USED +TO GET A POINTER TO THE PHYSICAL LOCATION OF THE DISK DEVICE +DRIVER. CONSULT THE DBP STRUCTURE DOCUMENTED IN DOSSYM.ASM + + ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +| C A V E A T P R O G R A M M E R | +| | + + Name: * GET_DPB - get pointer to drive parameter + block + + Assembler usage: + MOV AH,GET_DPB + INT 21h + ; DS:BX has address of drive parameter block + + Description: + Return pointer to default drive parameter block. + + Error returns: + None. + + Assembler usage: + MOV DL,DrvNUM + MOV AH,32H + INT 21h + ; DS:BX has address of drive parameter block + + Description: + Return pointer to drive parameter block for drive + designated in DL (0=Default, A=1, B=2 ...) + + Error returns: + AL = FF + The drive given in DL is invalid. +| | +| C A V E A T P R O G R A M M E R | ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + + + APPENDIX H + + +This material was taken from the MS-DOS 3.10 Programmer's Reference +Manual. It is intended be used with the MS-DOS 2.XX/3.XX Adaptation +Guide. + +7.1 INTRODUCTION + +This chapter describes recommended MS-DOS 3.1 programming +procedures. By using these programming hints, you can +ensure compatibility with future versions of MS-DOS. + +The hints are organized into the following categories: + + Interrupts + + System Calls + + Device Management + + Memory Management + + Process Management + + File and Directory Management + + Miscellaneous + + + + + +7.2 INTERRUPTS + +Never explicitly issue Interrupt 22H (Terminate Process Exit +Address). + + This should only be done by the DOS. To change the + terminate address, use Function 35H (Get Interrupt + Vector) to get the current address and save it, then + use Function 25H (Set Interrupt Vector) to change + the Interrupt 22H entry in the vector table to point + to the new terminate address. + PROGRAMMING HINTS Page 7-2 + + +Use Interrupt 24H (Critical Error Handler Address) with +care. + + The Interrupt 24H handler must preserve the ES + register. + + Only system calls 01H-0CH can be made by an + Interrupt 24H handler. Making any other calls will + destroy the MS-DOS stack and prevent successful use + of the Retry or Ignore options. + + The registers SS, SP, DS, BX, CX, and DX must be + preserved when using the Retry or Ignore options. + +When an Interrupt 24H (Critical Error Handler Address) is +received, always IRET back to MS-DOS with one of the +standard responses. + + Programs that do not IRET from Interrupt 24H leave + the system in an unpredictable state until a + function call other than 01H-0CH is made. The + Ignore option may leave data in internal system + buffers that is incorrect or invalid. + +Avoid trapping Interrupt 23H (Control-C Handler Address) and +Interrupt 24H (Critical Error Handler Address). Don't rely +on trapping errors via Interrupt 24H as part of a copy +protection scheme. + + These might not be included in future releases of + the operating system. + +Interrupt 23H (Control-C Handler Address) must never be +issued by a user program. + + Interrupt 23H must be issued only by MS-DOS. + +Save any registers your program uses before issuing +Interrupt 25H (Absolute Disk Read) or Interrupt 26H +(Absolute Disk Write). + + These interrupts destroy all registers except for + the segment registers. + + Avoid writing or reading an interrupt vector + directly to or from memory. + +Use Functions 25H and 35H (Set Interrupt Vector and Get +Interrupt Vector) to set and get values in the interrupt +table. + + PROGRAMMING HINTS Page 7-3 + + +7.3 SYSTEM CALLS + +Use new system calls. + + Avoid using system calls that have been superseded + by new calls unless a program must maintain backward ____ + compatibility with pre-2.0 versions of MS-DOS. See + Section 1.8, "Old System Calls," of this manual for + a list of these new calls. + +Avoid using system calls 01H-0CH and 26H (Create New PSP). + + Use the new "tools" approach for reading and writing + on standard input and output. Use Function 4B00H + (Load and Execute Program) instead of 26H to execute + a child process. + +Use file-sharing calls if more than one process is in +effect. + + See "File Sharing," in Section 1.5.2, "File-Related + Function Requests" in Chapter 1 for more + information. + +Use networking calls where appropriate. + + Some forms of IOCTL can only be used with Microsoft + Networks. See Section 1.6, "Microsoft Networks," in + this manual for a list of these calls. + +When selecting a disk with Function 0EH (Select Disk), treat +the value returned in AL with care. + + The value in AL specifies the maximum number of + logical drives; it does not specify which drives + are valid. + + + + +7.4 DEVICE MANAGEMENT + +Use installable device drivers. + + MS-DOS provides a modular device driver structure + for the BIOS, allowing you to configure and install + device drivers at boot time. Block device drivers + transmit a block of data at a time, while character + device drivers transmit a byte of data at a time. + + Examples of both types of device drivers are given + in Chapter 2, "MS-DOS Device Drivers." + PROGRAMMING HINTS Page 7-4 + + +Use buffered I/O. + + The device drivers can handle streams of data up to + 64K. When sending a large amount of output to the + screen, you can send it with one system call. This + will increase performance. + +Programs that use direct console I/O via Function 06H and +07H (Direct Console I/O and Direct Console Input) and that +want to read Control-C as data should ensure that Control-C +checking is off. + + The program should ensure that Control-C checking is + off by using Function 33H (Control-C Check). + +Be compatible with international support. + + To provide support for international character sets, + MS-DOS recognizes all possible byte values as + significant characters in filenames and data + streams. Pre-2.x versions ignored the high bit in + the MS-DOS filename. + + + + +7.5 MEMORY MANAGEMENT + +Use memory management. + + MS-DOS keeps track of allocated memory by writing a + memory control block at the beginning of each area + of memory. Programs should use Functions 48H + (Allocate Memory), 49H (Free Allocated Memory), and + 4AH (Set Block) to release unneeded memory. + + This will allow for future compatibility. + + See Section 1.3, "Memory Management," for more + information. + +Only use allocated memory. + + Don't directly access memory that was not provided + as a result of a system call. Do not use fixed + addressing, use only relative references. + + A program that uses memory that has not been + allocated to it may destroy other memory control + blocks or cause other applications to fail. + + PROGRAMMING HINTS Page 7-5 + + +7.6 PROCESS MANAGEMENT + +Use the EXEC Function Call to load and execute programs. + + The EXEC Function (4B00H) is the preferred way to + load programs and program overlays. Using the EXEC + call instead of hard-coding information about how to + load an .EXE file (or always assuming that your file + is a .COM file) will isolate your program from + changes in future releases of MS-DOS and .EXE file + formats. + +Use Function 31H (Keep Process), instead of Interrupt 27H +(Terminate But Stay Resident). Function 31H allows programs +to terminate and stay resident that are greater than 64K. + +Programs should terminate using End Process (4CH). + +Programs that terminate by + - a long jump to offset 0 in the PSP, + - issuing an Interrupt 20H with CS:0 pointing at the PSP, + - issuing an Interrupt 21H with AH=0, CS:0 pointing at the + PSP, or + - a long call to location 50H in the PSP with AH=0 + +must ensure that the CS register contains the segment +address of the PSP. + + + + +7.7 FILE AND DIRECTORY MANAGEMENT + +Use the MS-DOS file management system. + + Using the MS-DOS file system will ensure program + compatibility with future MS-DOS versions through + compatible disk formats and consistent internal + storage. This will ensure compatibility with future + MS-DOS versions. + +Use file handles instead of FCBs. + + A handle is a 16-bit number that is returned by + MS-DOS when a file is opened or created using + Functions 3CH, 3DH, 5AH, or 5BH (Create Handle, Open + Handle, Create Temporary File, or Create New File). + The MS-DOS file-related function requests that use + handles are listed in Table 1.5 in Chapter 1, + "System Calls." + + These calls should be used instead of the old + file-related functions that use FCBs (file control + blocks). This is because a file operation can + simply pass its handle rather than having to + PROGRAMMING HINTS Page 7-6 + + + maintain FCB information. If FCBs must be used, be + sure the program closes them and does not move them + around in memory. + +Close all files that have changed in length before issuing +an Interrupt 20H (Program Terminate), Function 00H +(Terminate Program), Function 4CH (End Process), or Function +0DH (Reset Disk). + + If a changed file is not closed, its length will not + be recorded correctly in the directory. + +Close all files when they are no longer needed. + + Closing unneeded files will optimize performance in + a networking environment. + +Only change disks if all files on the disk are closed. + + Information in internal system buffers may be + written incorrectly to a changed disk. + + + + +7.7.1 Locking Files + +Programs should not rely on being denied access to a locked +region. + + Determine the status of the region by attempting to + lock it, and examine the error code. + +Programs should not close a file with a locked region or +terminate with an open file that contains a locked region. + + The result is undefined. Programs that might be + terminated by an Interrupt 23H or Interrupt 24H + (Control-C Handler Address or Critical Error Handler + Address) should trap these interrupts and unlock any + locked regions before exiting. + + + + +7.8 MISCELLANEOUS + +Avoid timing dependencies. + + Various machines use CPUs of different speeds. + Also, programs that rely upon the speed of the clock + for timing will not be dependable in a networking + environment. + PROGRAMMING HINTS Page 7-7 + + +Use the documented interface to the operating system. If +either the hardware or media change, the operating system +will be able to use the features without modification. + + Don't use the OEM (Original Equipment Manufacturer) + -provided ROM support. + + Don't directly address the video memory. + + Don't use undocumented function calls, interrupts, + or features. These items may change or not continue + to exist in future versions of MS-DOS. Use of these + features would make your program highly + non-portable. + +Use the .EXE format rather than the .COM format. + + .EXE files are relocatable and .COM files are direct + memory images that load at a specific place and have + no room for additional control information to be + placed in them. .EXE files have headers that can be + expanded for compatibility with future versions of + MS-DOS. + +Use the environment to pass information to applications. + + The environment allows a parent process to pass + information to a child process. COMMAND.COM is + usually the parent process to every application, so + default drive and path information can easily be + passed to the application. + + + + + + + GLOSSARY OF MS-DOS TERMS + + + +Allocation Unit + + (See Cluster) + + + +Arena + + MS-DOS uses a software memory management scheme. + Blocks in memory are either owned by processes or + are free. An owned block has an ID number, which + is the initial paragraph of the Program Segment + GLOSSARY OF MS-DOS TERMS + + + Prefix of a process in memory (your program). Each + block has a size as well. When your process is in + memory, there is a 16-byte arena block which + identifies it and specifies how much memory is + allocated. + + + +ASCIZ + + Any null (zero byte) terminated ASCII string. + + + +Cluster + + The storage unit that MS-DOS uses to allocate space + for files on a disk. All files are allocated in + multiples of clusters. A cluster must be a power + of two sectors (i.e., 1, 2, 4, 8 ... ). This term + is synonymous with allocation unit. + + Block device drivers perform I/O in + sectors, not clusters. + + + +Cooked/Raw Mode + + + Character devices have two modes that have + significance when performing I/O via the Read + Handle and Write Handle calls (Functions 3FH and + 40H). These are "raw" and "cooked" mode. A device + driver can be set to raw mode via the IOCTL + Function Request 44H. + + Cooked mode input is buffered input with echoing to + the screen (if console) and Control-C checking. + Cooked mode input of a certain number of characters + will return when the specified number of characters + is returned or a carriage return is typed. Cooked + mode output performs Control-C checking between + characters. + + Raw mode I/O is very fast. When raw mode I/O of + "n" characters is requested, MS-DOS passes the + request directly to the indicated device driver. + The device driver does not return to MS-DOS until + the I/O has completed. Characters are written or + read directly from the process buffer. No checking + of any kind is performed. No characters have any + significance, including Control-C. + + GLOSSARY OF MS-DOS TERMS + + + For example, if the requesting program puts a + device in raw mode and requests a write of 50,000 + characters to the AUX device, the device driver + will get a request from MS-DOS to write 50,000 + characters from the buffer located at the DWORD + transfer address. The driver will not return until + the request has completed. + + In cooked mode, MS-DOS performs a Control-C check + at the console after each single character write. + This is an overhead of 50,000 Control-C checks. + + + + +Environment + + The environment is a maximum of 32K data area which + consists of ASCIZ strings of the form: + AAAA=BBBBBBB. The end of the environment is marked + by two consecutive nulls. The word at 2CH in the + Program Segment Prefix points to the segment + containing the start of a program's environment. + New variables can be added to the environment by + using the MS-DOS Set command. Since nulls have + significance, the environment cannot be used for + storing binary data. + + When a parent process (such as COMMAND.COM) + executes a child process (any other program), the + child is given a copy of the parent's environment. + Parameters such as Prompt, which specifies the + style of prompt used by COMMAND.COM, are stored in + the environment. Application programs can use the + environment to find overlays or special files which + may not be located in the current directory. + COMMAND.COM uses this technique to examine the + elements of the Path looking for binaries and batch + files. Of course the application program must be + specifically coded to find the environment and + parse it for variables. + + + +FATID Byte + + The FATID byte is the first byte of the File + Allocation Table that starts at the sector + immediately after the reserved sectors of the disk. + The FATID byte was used by OEMs in MS-DOS 1.x for + identification of disk media. This byte should be + between F8H and FFH. To read MS-DOS 1.x disks, one + must read this byte, determine which of the four + predefined FATID bytes is present and return a + pointer to the appropriate BPB. This method of + GLOSSARY OF MS-DOS TERMS + + + determining media is less general and less + desirable than the BPB table method (see MEDIA ID + Byte). + + + +File Handle + + In versions of MS-DOS that are 2.0 and higher, + there is a system file table set up at boot time. + By the time COMMAND.COM gets control, all of the + character devices have been entered into the system + file table. The first five handles are initialized + as follows. + + + HANDLE XENIX NAME DEFAULT SETTING + + 0 Standard Input CON + 1 Standard Output CON + 2 Standard Error CON + 3 Standard AUX AUX + 4 Standard PRN PRN + + As new files are opened via XENIX-compatible calls, + they are assigned the first available numbers. + When COMMAND.COM executes a program, the child + process inherits all of the handles that + COMMAND.COM has open. Typing + + prog < infyle > outfyle + + on the command line means that you want PROG to + read its input from INFYLE and write its output to + OUTFYLE instead of to console out. COMMAND.COM + will close handle 0 and open INFYLE; it will DUP + handle 0. It will then close handle 1, standard + out, and open OUTFYLE (which is assigned to + standard out). COMMAND will exec PROG, which + inherits this environment. When PROG reads from + standard in, or writes to standard out, it reads + from and writes to INFYLE and OUTFYLE, + respectively. + + If a child is executed, it inherits the files of + its parent. The converse is not true. When a + child process which opens AUX as standard in and + PRN as standard out returns, the parent does not ___ + inherit the files of its child. + + + + + GLOSSARY OF MS-DOS TERMS + + +MEDIA ID Byte + + The MEDIA ID byte is the byte in the Bios Parameter + Block (BPB) located at offset 0AH. The MEDIA ID + byte may have any value between 0 and 0FFH. It may + or may not have the same value as the FATID byte. + The major significance of the MEDIA ID byte is that + there be a one-to-one relationship between unique + MEDIA ID bytes and disk formats. For disk + compatibility with other OEMs as well as with + future releases of MS-DOS, Microsoft recommends + that the BPB table be located at offset 0BH in the + first reserved (boot) sector. OEMs may register + their media byte/format combinations with OEM + Customer Support. The BPB technique of determining + disk format is much more general than the limited + FATID byte method and is the preferred method. + + The significance of the media byte and FATID byte + depends on whether you have decided to make your + block device driver IBM format-compatible. You + must indicate this by setting bit 13 in the device + driver header. This will alter the way MS-DOS + performs the GET BPB device call. With the NON + FATID bit set, you can support various media, + including IBM format media. If the device driver + is IBM-format compatible, use FATID bytes to + determine the media in the drive. The + correspondence between FATID bytes and various + media is defined in the MS-DOS Programmer's ______ ____________ + Reference Manual. _________ ______ + + If your system is not IBM Format-compatible, you + are given a pointer to a one-sector scratch buffer + when your block device gets called by MS-DOS to do + a BUILD BPB. Follow these steps: + + 1. Read the boot sector of the disk into that + buffer and check the first byte. If it is an + E9H, it is the first byte of a 3-byte JMP and + there is a BIOS Parameter Block table in the + boot sector. + + Alternately, EBH may be the first byte. This + is also a 3-byte JMP (actually, a 2-byte JMP + followed by a NOP). + GLOSSARY OF MS-DOS TERMS + + + 2. Return a pointer to the BPB. Set the status + word and return. If the first byte of the boot + sector is not an E9H, then there is not a BPB + table in the boot sector. You can assume that + the disk is an IBM format disk and the FAT + begins with the second sector of the disk. + Read the FAT into the scratch buffer and check + the first byte. Determine which one of the + four defined FATID bytes it is, and return a + pointer to the appropriate BPB. + + Refer to the MS-DOS Programmer's Reference ______ ____________ _________ + Manual for a list of valid FATID bytes. Any ______ + other media should be defined in the boot + sector and should use a FATID byte of FFH. + + + + +Paragraph + + Any location in the memory of the 8086 which has an + address that is a multiple of 16 (i.e., 0, 16, 32). + + + + diff --git a/PROGREF/0_CONTS.A b/PROGREF/0_CONTS.A new file mode 100644 index 0000000..70fd8c3 --- /dev/null +++ b/PROGREF/0_CONTS.A @@ -0,0 +1,227 @@ + +_ _ | | _ _ + + +Contents + +_ ________________________________________________________________ + +1 System Calls 1 + + 1.1 Introduction 3 + 1.2 Standard Character Device I/O 4 + 1.3 Memory Management 5 + 1.4 Process Management 7 + 1.5 File and Directory Management 9 + 1.6 Microsoft Networks 14 + 1.7 National Language Support 15 + 1.8 Miscellaneous System-Management Functions 16 + 1.9 Old System Calls 17 + 1.10 Using the System Calls 21 + 1.11 Interrupts 35 + 1.12 Function Requests 53 + +2 MS-DOS Device Drivers 323 + + 2.1 Introduction 325 + 2.2 Format of a Device Driver 326 + 2.3 How to Create a Device Driver 328 + 2.4 Installing Device Drivers 329 + 2.5 Device Headers 330 + 2.6 Request Header 334 + 2.7 Device Driver Functions 337 + 2.8 The Media Descriptor Byte 351 + 2.9 Format of a Media Descriptor Table 351 + 2.10 The CLOCK Device 353 + 2.11 Anatomy of a Device Call 354 + 2.12 Two Sample Device Drivers 355 + +3 MS-DOS Technical Information 383 + + 3.1 Introduction 385 + 3.2 MS-DOS Initialization 385 + 3.3 The Command Processor 386 + 3.4 MS-DOS Disk Allocation 387 + 3.5 MS-DOS Disk Directory 387 + 3.6 File Allocation Table (FAT) 390 + 3.7 MS-DOS Standard Disk Formats 392 + +4 MS-DOS Control Blocks + and Work Areas 395 + + iii + +_ _ | | _ _ + + +_ _ | | _ _ + +Contents + + 4.1 Introduction 397 + 4.2 Typical Contents of an MS-DOS Memory Map 397 + 4.3 MS-DOS Program Segment 398 + +5 National Language Support 403 + + 5.1 Introduction 405 + 5.2 National Language Support Calls 405 + 5.3 Font Files 406 + +6 .Exe File Structure and Loading 411 + + 6.1 Format of a File Header 413 + 6.2 The Relocation Table 414 + +7 Microsoft Relocatable + Object Module Formats 417 + + 7.1 Introduction 419 + 7.2 Module Identification and Attributes 423 + 7.3 Conceptual Framework for Fixups 425 + 7.4 Record Sequence 431 + 7.5 Introducing the Record Formats 433 + 7.6 Microsoft Type Representations + for Communal Variables 460 + +8 Programming Hints 463 + + 8.1 Introduction 465 + 8.2 Interrupts 465 + 8.3 System Calls 466 + 8.4 Device Management 467 + 8.5 Memory Management 468 + 8.6 Process Management 468 + 8.7 File and Directory Management 469 + 8.8 Miscellaneous 471 + + +iv + +_ _ | | _ _ + + +_ _ | | _ _ + + +Figures + +_ ________________________________________________________________ + +Figure 1.1 Example of the 8088 Registers 25 + +Figure 1.2 Sample Program with Common Skeleton 26 + +Figure 2.1 Sample Device Header 330 + +Figure 2.2 Attribute Word for Character Devices 333 + +Figure 2.3 Attribute Word for Block Devices 333 + +Figure 2.4 Request Header 335 + +Figure 2.5 Format of a Boot Sector 352 + +Figure 2.6 Format of a Clock Device 354 + +Figure 4.1 Program Segment Prefix 402 + +Figure 5.1 Font File Structure 407 + +Figure 7.1 Location Types 427 + + + + v + +_ _ | | _ _ + + +_ _ | | _ _ + + +Tables + +_ ________________________________________________________________ + +Table 1.1 Standard Character I/O Function Requests 4 + +Table 1.2 Memory Management Function Requests 5 + +Table 1.3 Process-Management Function Requests 7 + +Table 1.4 Predefined Device Handles 9 + +Table 1.5 File-Related Function Requests 10 + +Table 1.6 File-Sharing Function Requests 11 + +Table 1.7 Device-Related Function Requests 12 + +Table 1.8 Directory-Related Function Requests 12 + +Table 1.9 File Attributes 13 + +Table 1.10 Microsoft Networks Function Requests 14 + +Table 1.11 National Language-Support Function Requests 15 + +Table 1.12 Miscellaneous System-Management Function Requests 16 + +Table 1.13 Old System Calls and Their Replacements 17 + +Table 1.14 Format of the File Control Block (FCB) 18 + +Table 1.15 Error Codes Returned in AX 22 + +Table 1.16 MS-DOS Interrupts, Numeric Order 27 + +Table 1.17 MS-DOS Interrupts, Alphabetic Order 27 + +Table 1.18 MS-DOS Function Requests, Numeric Order 28 + +Table 1.19 MS-DOS Function Requests, Alphabetic Order 31 + +Table 1.20 Bit values for Function 29H 133 + +Table 1.21 Sharing Mode Bit Values 174 + +Table 1.22 Access Code Bit Values 175 + +Table 1.23 MS-DOS Data Bit Values 193 + +Table 1.24 Contents of the Parameter Block 239 + +Table 1.25 Contents of the Parameter Block 243 + +Table 1.26 250 + +Table 1.27 Allocation Strategy 263 + +Table 2.1 For Character Devices: 331 + +vi + +_ _ | | _ _ + + +_ _ | | _ _ + + Contents + +Table 2.2 For Block Devices: 331 + +Table 3.1 MS-DOS Standard Removable-Disk Formats 393 + +Table 3.2 MS-DOS Standard Removable Disk Formats (High-Density) 393 + +Table 7.1 Object Module Record Formats 419 + +Table 7.2 Combination Attribute Example 438 + + + + vii + +_ _ | | _ _ + diff --git a/PROGREF/0_FRONT.A b/PROGREF/0_FRONT.A new file mode 100644 index 0000000..7cfde16 --- /dev/null +++ b/PROGREF/0_FRONT.A @@ -0,0 +1,34 @@ + +_ _ | | _ _ + + +Microsoft (R) MS-DOS +Version 3.3 +_ ________________________________________________________________ + +Programmer's Reference + +Microsoft Corporation + +_ _ | | _ _ + + +_ _ | | _ _ + +All rights reserved. + +Simultaneously published in the United States and +Canada. + +Microsoft(R), the Microsoft logo, MS-DOS(R), and XENIX(R) are registered trademarks +of Microsoft Corporation. + +IBM(R), IBM Personal Computer(R), IBM PC(R), and PC-DOS(R) are registered trade- +marks of International Business Machines Corporation. + +INTEL(R) is a registered trademark of Intel Corporation. + +Document No. 410630014-330-R04-0787 + +_ _ | | _ _ + diff --git a/PROGREF/1A_CALLS.A b/PROGREF/1A_CALLS.A new file mode 100644 index 0000000..e5cc52a --- /dev/null +++ b/PROGREF/1A_CALLS.A @@ -0,0 +1,3175 @@ + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +1.1 Introduction + +The routines that MS-DOS uses to manage system operation and resources +can be called by any application program. Using these system calls makes +it easier to write machine-independent programs and increases the likeli- +hood that a program will be compatible with future versions of MS-DOS. +MS-DOS system calls fall into several categories: + + o Standard character device I/O + + o Memory management + + o Process management + + o File and directory management + + o Microsoft Network calls + + o National Language Support calls + + o Miscellaneous system functions + +Applications invoke MS-DOS services by using software interrupts. The +current range of interrupts used for MS-DOS is 20H-27H; 28H-40H are +reserved. Interrupt 21H is the function request service; it provides access +to a wide variety of MS-DOS services. In some cases, the full AX register +is used to specify the requested function. Each interrupt or function +request uses values in various registers to receive or return function- +specific information. + +1.1.1 System Calls That Have Been Superseded + +Many system calls introduced in versions of MS-DOS earlier than 2.0 have +been superseded by function requests that are more efficient and easier to +use. Although MS-DOS still includes these old system calls, they should +not be used unless it is imperative that a program maintain backward- +compatibility with versions of MS-DOS before 2.0. + +A table of the pre-2.0 system calls and a description of the File Control +Block (required by some of the old calls) appears in Section 1.8, "Old Sys- +tem Calls." + +The first part of this chapter explains how DOS manages its resources\(em +such as memory, files, and processes\(emand briefly describes the purpose of +most of the system calls. The remainder of the chapter describes each +interrupt and function request in detail. + +The system-call descriptions are in numeric order, interrupts followed by +function requests. These descriptions include further detail on how +MS-DOS manages its resources. + + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +Chapter 2 of this manual describes how to write an MS-DOS device driver. +Chapters 3, 4, and 5 contain more detailed information about MS-DOS, +including how it manages disk space, the control blocks it uses, and how it +loads and executes relocatable programs (files with an extension of .exe). +Chapter 6 describes the Intel object module format. Chapter 7 gives some +programming hints. + +1.2 Standard Character Device I/O + +The standard character function requests handle all input and output to +and from character devices such as consoles, printers, and serial ports. If a +program uses these function requests, its input and output can be +redirected. + +Table 1.1 lists the MS-DOS function requests for managing standard char- +acter input and output. + +Table 1.1 + +Standard Character I/O Function Requests + +_ _________________________________________________________________________ + +01H + + Read Keyboard and + Echo + + Gets a character from standard input and echoes + it to standard output + +02H Display Character Sends a character to standard output + +03H Auxiliary Input + + Gets a character from standard auxiliary + +04H Auxiliary Output + + Sends a character to standard auxiliary + +05H Print Character + + Sends a character to the standard printer + +06H Direct Console I/O + + Gets a character from standard input or sends a + character to standard output + +07H + + Direct Console Input + + Gets a character from standard input + +08H Read Keyboard + + Gets a character from standard input + +09H Display String Sends a string to standard output + +0AH Gets a string from standard input + + Buffered Keyboard + Input + +0BH + + Check Keyboard + Status + + Reports on the status of the standard input + buffer + +0CH + + Flush Buffer, Read + Keyboard + + Empties the standard input buffer and calls one + of the other standard character I/O function + requests + +_ _________________________________________________________________________ + +Although several of these standard character I/O function requests seem +to do the same thing, they are distinguished by whether they check for +control characters or echo characters from standard input to standard + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +output. The detailed descriptions later in this chapter point out the +differences. + +1.3 Memory Management + +MS-DOS keeps track of which areas of memory are allocated by writing a +memory control block at the beginning of each. This control block specifies +the size of the memory area; the name of the process, if any, that owns the +memory area; and a pointer to the next area of memory. If the memory +area is not owned, it is available. + +Table 1.2 lists the MS-DOS function requests for managing memory. + +Table 1.2 + +Memory Management Function Requests + +_ _________________________________________________________________________ + +48H Allocate Memory Requests a block of memory + +49H + + Free Allocated + Memory + + Frees a block of memory previously allocated with 48H + + +4AH Set Block + + Changes the size of an allocated memory block + +_ _________________________________________________________________________ + +When a process requests additional memory with Function 48H (Allocate +Memory), MS-DOS searches for a block of available memory large enough +to satisfy the request. If it finds such a block of memory, it changes the +memory control block to show the owning process. If the block of memory +is larger than the requested amount, MS-DOS changes the size field of the +memory control block to the requested amount, writes a new memory con- +trol block at the beginning of the unneeded portion showing that it is +available, and updates the pointers to add this memory to the chain of +memory control blocks. MS-DOS then returns the segment address of the +first byte of the allocated memory to the requesting process. + +When a process releases an allocated block of memory with Function 49H +(Free Allocated Memory), MS-DOS changes the memory control block to +show that it is available (not owned by any process). + +When a process uses Function 4AH (Set Block) to shrink an allocated +block of memory, MS-DOS builds a memory control block for the memory +being released and adds it to the chain of memory control blocks. When a +process tries to use Function 4AH (Set Block) to expand an allocated block +of memory, MS-DOS treats it as a request for additional memory rather +than returning the segment address of the additional memory to the +requesting process. However, MS-DOS simply chains the additional +memory to the existing memory block. + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +If MS-DOS can't find a block of available memory large enough to satisfy a +request for additional memory made with either Function 48H (Allocate +Memory) or Function 4AH (Set Block), MS-DOS returns an error code to +the requesting process. + +When a program receives control, it should call Function 4AH (Set Block) +to shrink its initial memory-allocation block (the block that begins with +its Program Segment Prefix) to the minimum it requires. This frees +unneeded memory and makes the best application design for portability to +future multitasking environments. + +When a program exits, MS-DOS automatically frees its initial memory- +allocation block before returning control to the calling program +(command.com is usually the calling program for application programs). +The DOS frees any memory owned by the exiting process. + +Any program that changes memory that is not allocated to it will most +likely destroy at least one memory-management control block. This +causes a memory-allocation error the next time MS-DOS tries to use the +chain of memory control blocks; the only cure is to restart the system. + +1.4 Process Management + +MS-DOS uses several function requests to load, execute, and terminate +programs. Application programs can use these same function requests to +manage other programs. + +Table 1.3 lists the MS-DOS function requests for managing processes. + +Table 1.3 + +Process-Management Function Requests + +_ _________________________________________________________________________ + +31H Keep Process + + Terminates a process and returns control to the + invoking process, but keeps the terminated + process in memory + +4BH Loads and executes a program + + Load and Execute + Program + +4B03H Load Overlay + + Loads a program overlay without executing it + +4CH End Process + + Returns control to the invoking process + +4DH + + Get Return Code of + Child Process + + Returns a code passed by an exiting child process + + +62H Get PSP + + Returns the segment address of the current + process's Program Segment Prefix + +_ _________________________________________________________________________ + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +1.4.1 Loading and Executing a Program + +When a program uses Function 4BH (Load and Execute Program) to load +and execute another program, MS-DOS allocates memory, writes a Pro- +gram Segment Prefix (PSP) for the new program at offset 0 of the allo- +cated memory, loads the new program, and passes control to it. When the +invoked program exits, control returns to the calling program. + +Command.com uses Function 4BH to load and execute command files. +Application programs have the same degree of control over process +management as does command.com. + +In addition to these common features, there are some differences in the +way MS-DOS loads .com and .exe files. + +Loading a .Com Program + +When command.com loads and executes a .com program, it allocates all +available memory to the application and sets the stack pointer 100H bytes +from the end of available memory. A .com program should set up its own +stack before shrinking its initial memory-allocation block with Function +4AH (Set Block) because the default stack is in the memory to be released. + +If a newly loaded program is allocated all of memory\(emas a .com program +is\(emor requests all of available memory by using Function 48H (Allocate +Memory), MS-DOS allocates to it the memory occupied by the transient +part of command.com. If the program changes this memory, MS-DOS +must reload the transient portion of command.com before it can continue. +If a program exits (via Function 31H, Keep Process) without releasing +enough memory, the system halts and must be reset. To minimize this pos- +sibility, a .com program should use Function 4AH (Set Block) to shrink its +initial allocation block before doing anything else, and before exiting, all +programs must release all memory they allocate by using Function 48H +(Allocate Memory). + +Loading an .Exe Program + +When command.com loads and executes an .exe program, it allocates the +size of the program's memory image plus either the value in the +MAX_ALLOC field (offset 0CH) of the file header (if that much memory is +available) or the value in the MIN_ALLOC field (offset 0AH). The linker +sets these fields. Before passing control to the .exe file, MS-DOS uses the +relocation information in the file header to calculate the correct relocation +addresses. + + + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +For a more detailed description of how MS-DOS loads .com and .exe files, +see Chapter 3, "MS-DOS Technical Information," and Chapter 4, "MS- +DOS Control Blocks and Work Areas." + +Executing a Program from Within Another Program + +Since command.com builds pathnames, searches directory paths for exe- +cutable files, and relocates .exe files, the simplest way to load and execute +a program is to load and execute an additional copy of command.com, +passing it a command line that includes the /C switch, which invokes the +.com or .exe file. The description of Function 4B00H (Load and Execute +Program) describes how to do this. + +1.4.2 Loading an Overlay + +When a program uses Function 4B03H (Load Overlay) to load an overlay, +it must pass MS-DOS the segment address at which the overlay is to be +loaded. The program must call the overlay, which then returns directly to +the calling program. The calling program is in complete control: MS-DOS +does not write a PSP for the overlay or intervene in any other way. + +MS-DOS does not check to see if the calling program owns the memory +where the overlay is to be loaded. If the calling program does not own the +memory, loading the overlay will most likely destroy a memory-control +block, causing an eventual memory-allocation error. + +Therefore, a program that loads an overlay must either allow room for the +overlay when it calls Function 4AH (Set Block) to shrink its initial +memory-allocation block, or shrink its initial memory-allocation block to +the minimum and then use Function 48H (Allocate Memory) to allocate +memory for the overlay. + +1.5 File and Directory Management + +The MS-DOS hierarchical (multilevel) file system is similar to that of the +XENIX operating system. For a description of the multilevel directory sys- +tem and how to use it, see the MS-DOS User's Reference. + +1.5.1 Handles + +To create or open a file, a program passes MS-DOS a pathname and the +attribute to be assigned to the file. MS-DOS returns a 16-bit number, +called a handle. For most subsequent actions, MS-DOS requires only this +handle to identify the file. + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +A handle can refer to either a file or a device. MS-DOS predefines five stan- +dard handles. These handles are always open, so you needn't open them +before you use them. Table 1.4 lists these predefined handles. + +Table 1.4 + +Predefined Device Handles + +_ _________________________________________________________________________ + +Handle Standard device Comment + +_ _________________________________________________________________________ + +0 Input Can be redirected from command line +1 Output Can be redirected from command line +2 Error +3 Auxiliary +4 Printer + +_ _________________________________________________________________________ + +When MS-DOS creates or opens a file, it assigns the first available handle. +Since a program can have 20 open handles, including the five predefined +handles, it typically can open 15 extra files. By using Function 46H (Force +Duplicate File Handle), MS-DOS can temporarily force any of the five +predefined handles to refer to an alternate file or device. For more infor- +mation about Function 46H, see its description later in this chapter. + +1.5.2 File-Related Function Requests + +MS-DOS treats a file as a string of bytes; it assumes no record structure or +access technique. An application program imposes whatever record struc- +ture it needs on this string of bytes. Reading from or writing to a file +requires only pointing to the data buffer and specifying the number of +bytes to read or write. + +Table 1.5 lists the MS-DOS function requests for managing files. + +Table 1.5 + +File-Related Function Requests + +_ _________________________________________________________________________ + +3CH Create Handle Creates a file + +3DH Open Handle Opens a file + +3EH Close Handle Closes a file + +3FH Read Handle Reads from a file + +40H Write Handle Writes to a file + +42H Move File Pointer Sets the read/write pointer in a file + +45H Duplicate File Handle + + Creates a new handle that refers to the same + file as an existing handle + + + + 9 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +46H Force Duplicate File Handle + + Makes an existing handle refer to the same file + as another existing handle + +5AH Create Temporary File Creates a file with a unique name + +5BH Create New File + + Attempts to create a file, but fails if a file with + the same name exists + +67H Set Handle Count + + Increases or decreases the number of files a + program can have open at one time + +68H Commit File + + Flushes buffered data for a file without closing + it to ensure the disk image of that file is + current + +_ _________________________________________________________________________ + + +File Sharing + +Version 3.1 of MS-DOS introduces file sharing, which lets more than one +process share access to a file. File sharing operates only after the share +command has been executed to load file-sharing support. That is, you +must use the share command to take advantage of file sharing. + +Table 1.6 lists the MS-DOS function requests for sharing files; if file shar- +ing is not in effect, these function requests cannot be used. Function 3DH +(Open Handle) can operate in several modes. Here it is referred to in the +file-sharing modes, which require file sharing to be in effect. (Compatibil- +ity mode is usable without file sharing in effect.) + +Table 1.6 + +File-Sharing Function Requests + +_ _________________________________________________________________________ + +3DH Open Handle + + Opens a file by using one of the file-sharing modes + +440BH IOCtl Retry + + (before Interrupt 24 is issued) Specifies how many + times to retry an I/O operation that fails due to a file- + sharing violation + +5C00H Lock Locks a region of a file + +5C01H Unlock Unlocks a region of a file + +_ _________________________________________________________________________ + + +1.5.3 Device-Related Function Requests + +I/O Control for devices is implemented with Function 44H (IOCtl), which +includes several subfunctions necessary to perform device-related tasks. +Some forms of the IOCtl function request require that the device driver be +written to support the IOCtl interface. Table 1.7 lists the MS-DOS func- +tion requests for managing devices. + +Table 1.7 + +Device-Related Function Requests + +10 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +_ _________________________________________________________________________ + +4400H,01H IOCtl Data Gets or sets device description + +4402H,03H IOCtl Character + + Gets or sets character-device control data + +4404H,05H IOCtl Block + + Gets or sets block-device control data + +4406H,07H IOCtl Status + + Checks device input or output status + +4408H IOCtl Is Changeable + + Checks whether block device contains + removable medium + +440CH Generic IOCtl (for handles) + + Sets Generic IOCtl for handles and + supports code pages for devices + +440DH Generic IOCtl (for devices) Sets Generic IOCtl for devices + +440E,0FH Get/Set IOCtl Drive Map Gets or sets logical drive map + +_ _________________________________________________________________________ + +Some forms of the IOCtl function request can be used only with Microsoft +Networks; these forms are listed in Section 1.6, "Microsoft Networks." + +1.5.4 Directory-Related Function Requests + +A directory entry is a 32-byte record that includes the file's name, exten- +sion, date and time of last change, and size. An entry in a subdirectory is +identical to an entry in the root directory. Directory entries are described +in detail in Chapter 3. + +The root directory on a disk has room for a fixed number of entries: 64 on +a standard single-sided disk, 112 on a standard double-sided disk. For +hard disks, the number of directories depends on the DOS partition size. +A subdirectory is simply a file with a unique attribute; there can be as +many subdirectories on a disk as space allows. The depth of a directory +structure, therefore, is limited only by the amount of storage on a disk and +the maximum pathname length of 64 characters. Pre-2.0 disks appear to +have only a root directory that contains files but no subdirectories. + +Table 1.8 lists the MS-DOS function requests for managing directories. + +Table 1.8 + +Directory-Related Function Requests + +_ _________________________________________________________________________ + +39H Create Directory Creates a subdirectory + +3AH Remove Directory Deletes a subdirectory + +3BH Change Current Directory Changes the current directory + +41H Delete Directory Entry (Unlink) Deletes a file + +43H Get/Set File Attributes (Chmod) + + Retrieves or changes the attributes of a file + +47H Get Current Directory + + Returns current directory for a given drive + + + + 11 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +4EH Find First File + + Searches a directory for the first entry that + matches a filename + +4FH Find Next File + + Searches a directory for the next entry that + matches a filename + +56H Change Directory Entry Renames a file + +57H Get/Set Date/Time of File + + Changes the time and date of last change in a + directory entry + +_ _________________________________________________________________________ + + +1.5.5 File Attributes + +Table 1.9 describes the file attributes and how they are represented in the +attribute byte of the directory entry (offset 0BH). The attributes can be +inspected or changed with Function 43H (Get/Set File Attributes +[Chmod]). + +Table 1.9 + +File Attributes + +_ _________________________________________________________________________ + +Code Description + +_ _________________________________________________________________________ + +00H + + Normal; can be read or written without restriction + +01H + + Read-only; cannot be opened for write; a file with the same name + cannot be created + +02H Hidden; not found by directory search + +04H System; not found by directory search + +08H + + VolumeID; only one file can have this attribute; it must be in the root + directory + +10H Subdirectory + +20H + + Archive; set whenever the file is changed, or cleared by the Backup + command + +_ _________________________________________________________________________ + +The VolumeID (08H) and Subdirectory (10H) attributes cannot be changed +with Function 43H (Get/Set File Attributes [Chmod]). + +1.6 Microsoft Networks + +Microsoft Networks consists of a server and one or more workstations. +MS-DOS maintains an assign list that keeps track of which workstation +drives and devices have been redirected to the server. For a description of +operation and use of the network, see the Microsoft Networks 1.0 +Manager's Guide and Microsoft Networks 1.0 User's Guide. + +12 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +Table 1.10 lists the MS-DOS function requests for managing a Microsoft +Networks workstation. + +Table 1.10 + +Microsoft Networks Function Requests + +_ _________________________________________________________________________ + +4409H + + IOCtl Is Redirected + Block + + Checks whether a drive letter refers to a local or + redirected drive + +440AH + + IOCtl Is Redirected + Handle + + Checks whether a device name refers to a local or + redirected device + +5E00H Get Machine Name Gets the network name of the workstation + +5E02H Printer Setup + + Defines a string of control characters to be added + at the beginning of each file that is sent to a + network printer + +5F02H + + Get Assign-List + Entry + + Gets an entry from the assign list, which shows + the workstation drive letter or device name and + the net name of the directory or device on the + server to which the entry is reassigned + +5F03H + + Make Assign-List + Entry + + Redirects a workstation drive or device to a + server directory or device + +5F04H + + Cancel Assign-List + Entry + + Cancels the redirection of a workstation drive or + device to a server directory or device + +_ _________________________________________________________________________ + + +1.7 National Language Support + +National language support for this version of MS-DOS includes these +major features: + + o Country-dependent information + + o Support for national keyboard layouts + + o Programming interfaces for national language support + + o Utility commands + +Country-dependent information is available on a per-country basis and +includes the following: + + o Time, date, and currency + + o Lowercase-to-uppercase character-conversion tables + + o Collating sequence for character sorting + + o Valid single-byte characters used in filenames + +Keyboard support for different keyboard layouts is provided and + + 13 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +selectable. + +Table 1.11 lists the MS-DOS national-language-support system calls that +allow applications to use the country-dependent information just +described. + +Table 1.11 + +National Language-Support Function Requests + +_ _________________________________________________________________________ + +65H Get Extended Country Information + + Returns standard country + information, pointer to uppercase + table, pointer to filename + uppercasing table, or pointer to + collating table + +66H Get/Set Global Code Page + + Gets or sets the code page used by + the kernel and all devices. + +_ _________________________________________________________________________ + + +1.8 Miscellaneous System-Management Func- +tions + +The remaining system calls manage other system functions and resources +such as drives, addresses, and the clock. Table 1.12 lists the MS-DOS func- +tion requests for managing miscellaneous system resources and operation. + +Table 1.12 + +Miscellaneous System-Management Function Requests + +_ _________________________________________________________________________ + +0DH Reset Disk Empties all file buffers + +0EH Select Disk Sets the default drive + +19H Get Current Disk Returns the default drive + +1AH Establishes the disk I/O buffer + + Set Disk Transfer + Address + +1BH Returns disk-format data + + Get Default Drive Data + +1CH Get Drive Data Returns disk-format data + +25H Set Interrupt Vector Sets interrupt-handler address + +29H Parse File Name Checks string for valid filename + +2AH Get Date Returns system date + +2BH Set Date Sets system date + +2CH Get Time Returns system time + +2DH Set Time Sets system time + +2EH Set/Reset Verify Flag Turns disk verify on or off + +14 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +2FH + + Get Disk Transfer + Address + + Returns system-disk-I/O-buffer address + + +30H Returns MS-DOS version number + + Get MS-DOS Version + Number + +33H CONTROL-C Check + + Returns CONTROL-C check status + +35H Get Interrupt Vector + + Returns address of interrupt handler + +36H Get Disk Free Space Returns disk-space data + +38H Get/Set Country Data + + Sets current country or retrieves country + information + +54H Get Verify State Returns status of disk verify + +_ _________________________________________________________________________ + + +1.9 Old System Calls + +Most of the superseded system calls deal with files. Table 1.13 lists these +old calls and the function requests that have superseded them. + +Although MS-DOS still includes these old system calls, they should not be +used unless a program must maintain backward-compatibility with earlier +versions of MS-DOS. + +Table 1.13 + +Old System Calls and Their Replacements + +_ _________________________________________________________________________ + +Old System Call Has Been Superseded By + +Code Function Code Function + +_ _________________________________________________________________________ + +00H Terminate Program 4CH End Process +0FH Open File 3DH Open Handle +10H Close File 3EH Close Handle +11H Search for First Entry 4EH Find First File +12H Search for Next Entry 4FH Find Next File +13H Delete File 41H Delete Directory Entry +14H Sequential Read 3FH Read Handle +15H Sequential Write 40H Write Handle +16H Create File 3CH Create Handle + 5AH Create Temporary File + 5BH Create New File +17H Rename File 56H Change Directory Entry +21H Random Read 3FH Read Handle +22H Random Write 40H Write Handle +23H Get File Size 42H Move File Pointer +24H Set Relative Record 42H Move File Pointer +26H Create New PSP 4BH Load and Execute Program +27H Random Block Read 42H Move File Pointer + 3FH Read Handle + + 15 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +28H Random Block Write 42H Move File Pointer + 40H Write Handle + +Code Interrupt Code Function + +_ _________________________________________________________________________ + +20H Program Terminate 4CH End Process +27H Terminate But Stay Resident 31H Keep Process + +_ _________________________________________________________________________ + + +1.9.1 File Control Block (FCB) + +The old file-related function requests require that a program maintain a +File Control Block (FCB) for each file; this control block contains such +information as a file's name, size, record length, and pointer to current +record. MS-DOS does most of this housekeeping for the newer, handle- +oriented function requests. + +Some descriptions of the old function requests refer to unopened and +opened FCBs. An unopened FCB contains only a drive specifier and +filename. An opened FCB contains all fields filled by Function 0FH (Open +File). + +The Program Segment Prefix (PSP) includes room for two FCBs at offsets +5CH and 6CH. For a description of how to use the PSP and FCB calls, see +Chapter 4, "MS-DOS Control Blocks and Work Areas," Table 1.14 +describes the FCB fields. + +Table 1.14 + +Format of the File Control Block (FCB) + +_ _________________________________________________________________________ + + Offset +Hex Dec Bytes Field + +_ _________________________________________________________________________ + +00H 0 1 Drive Number +01H 1 8 Filename +09H 9 3 Extension +0CH 12 2 Current Block + +0EH 14 2 Record Size +10H 16 4 File Size +14H 20 2 Date of Last Write +16H 22 2 Time of Last Write + +18H 24 8 Reserved +20H 32 1 Current Record +21H 33 4 Relative Record + +_ _________________________________________________________________________ + + + +16 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +Fields of the FCB + +Drive Number (offset 00H): Specifies the disk drive; 1 means drive A and 2 +means drive B. If you use the FCB to create or open a file, you can set this +field to 0 to specify the default drive; Function 0FH (Open File) sets the +field to the number of the default drive. + +Filename (offset 01H): Eight characters, left-aligned and padded (if neces- +sary) with blanks. If you specify a reserved device name (such as PRN), do +not put a colon at the end. + +Extension (offset 09H): Three characters, left-aligned and padded (if neces- +sary) with blanks. This field can be all blanks (no extension). + +Current Block (offset 0CH): Points to the block (group of 128 records) that +contains the current record. This field and the Current Record field (offset +1FH) make up the record pointer. This field is set to zero by the Open File +system call. + +Record Size (offset 0EH): The size of a logical record, in bytes. Set to 128 +by the Open File system call. If the record size is not 128 bytes, you must +set this field after opening the file. + +File Size (offset 0FH): The size of the file, in bytes. The first word of this +4-byte field is the low-order part of the size. + +Date of Last Write (offset 13H): The date the file was created or last +updated. The year, month, and day are mapped into two bytes as follows: + +Off set 14H Offset 13H +|Y|Y|Y|Y|Y|Y|Y|M| |M|M|M|D|D|D|D|D| +15 9 8 5 4 0 + +Time of Last Write (offset 15H): The time the file was created or last +updated. The hour, minutes, and seconds are mapped into two bytes as +follows: + +Offset 16H Offset 15H +|H|H|H|H|H|M|M|M| |M|M|M|S|S|S|S|S| +15 11 10 5 4 0 + +Reserved (offset 17H): These fields are reserved for use by MS-DOS. + +Current Record (offset 1FH): Points to one of the 128 records in the +current block. This field and the Current Block field (offset 0CH) make up +the record pointer. The Open File system call does not initialize this field. +You must set it before doing a sequential read or write to the file. + + + + 17 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +Relative Record (offset 20H): Points to the currently selected record, count- +ing from the beginning of the file (starting with 0). The Open File system +call does not initialize this field. You must set it before doing a random +read or write to the file. If the record size is less than 64 bytes, both words +of this field are used; if the record size is 64 bytes or more, only the first +three bytes are used. + +_ ________________________________________________________________ + +Note + + If you use the FCB at offset 5CH of the Program Segment Prefix, the + last byte of the Relative Record field is the first byte of the unformat- + ted parameter area that starts at offset 80H. This is the default Disk + Transfer Area. + +_ ________________________________________________________________ + + +Extended FCB + +The Extended File Control Block is used to create or search for directory +entries of files with special attributes. It adds the following 7-byte prefix to +the FCB: + +Name Bytes Offset + +_ ________________________________________________________________ + +Flag byte (FFH) 1 07H +Reserved 5 06H +Attribute byte 1 01H + +_ ________________________________________________________________ + +File attributes are described earlier in this chapter in Section 1.5.5, "File +Attributes." + +_ ________________________________________________________________ + +Note + + You must remember to point to the beginning of the extended FCB if + you are using Functions 0FH-16H with extended FCBs. + +_ ________________________________________________________________ + + + +18 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +1.10 Using the System Calls + +The remainder of this chapter describes how to use the system calls in +application programs, and it lists the calls in numeric and alphabetic +order, describing each call in detail. + +1.10.1 Issuing an Interrupt + +MS-DOS reserves Interrupts 28H through 3FH for its own use, and main- +tains the table of interrupt-handler addresses (the vector table) in loca- +tions 80H-FCH. Also, in case you need to write your own routines for +three particular MS-DOS interrupt handlers (Program Terminate, +CONTROL-C, and Critical Error), this chapter includes descriptions of each. +Function requests have superseded most of these interrupts. + +To issue an interrupt, move any required data into the registers and give +the INT instruction with the number of the interrupt you want. + +1.10.2 Calling a Function Request + +A function request is an MS-DOS routine for managing system resources. +Use the following procedure to call a function request: + + 1. Move any required data into the registers. + + 2. Move the function number into AH. + + 3. Move the action code, if required, into AL. + + 4. Issue Interrupt 21H. + + +1.10.3 Using the Calls from a High-Level Language + +The system calls can be executed from any high-level language whose +modules can be linked with assembly-language modules. In addition to this +linking technique, you can: + + o Use the DOSXQQ function of Pascal-86 to call a function request + directly. + + o Use the CALL statement or USER function to execute the required + assembly-language code from the BASIC interpreter. + + + + 19 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + + +1.10.4 Treatment of Registers + +When MS-DOS takes control after a function request, it switches to an +internal stack, and preserves any registers not used to return information +(except AX). The calling program's stack must be large enough to accom- +modate the interrupt system\(emat least 128 bytes in addition to other +needs. + +1.10.5 Handling Errors + +Most of the function requests introduced with version 2.0 or later set the +Carry flag if there is an error, identifying the specific error by returning a +number in the AX register. Table 1.15 lists these error codes and their +meanings. + +Table 1.15 + +Error Codes Returned in AX + +_ _________________________________________________________________________ + +Code Meaning + +_ _________________________________________________________________________ + + 1 Invalid function code + 2 File not found + 3 Path not found + 4 Too many open files (no open handles left) + 5 Access denied + 6 Invalid handle + 7 Memory control blocks destroyed + 8 Insufficient memory + 9 Invalid memory block address + +10 Invalid environment +11 Invalid format +12 Invalid access code +13 Invalid data +14 Reserved +15 Invalid drive +16 Attempt to remove the current directory +17 Not same device +18 No more files +19 Disk is write-protected + +20 Bad disk unit +21 Drive not ready +22 Invalid disk command +23 CRC error +24 Invalid length (disk operation) +25 Seek error +26 Not an MS-DOS disk +27 Sector not found +28 Out of paper +29 Write fault + +20 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +30 Read fault +31 General failure +32 Sharing violation +33 Lock violation +34 Wrong disk +35 FCB unavailable +36-49 Reserved + +50 Network request not supported +51 Remote computer not listening +52 Duplicate name on network +53 Network name not found +54 Network busy +55 Network device no longer exists +56 Net BIOS command limit exceeded +57 Network adapter hardware error +58 Incorrect response from network +59 Unexpected network error + +60 Incompatible remote adapter +61 Print queue full +62 Queue not full +63 Not enough space for print file +64 Network name was deleted +65 Access denied +66 Network device type incorrect +67 Network name not found +68 Network name limit exceeded +69 Net BIOS session limit exceeded + +70 Temporarily paused +71 Network request not accepted +72 Print or disk redirection is paused +73-79 Reserved + +80 File exists +81 Reserved +82 Cannot make +83 Interrupt 24 failure +84 Out of structures +85 Already assigned +86 Invalid password +87 Invalid parameter +88 Net write fault + +_ _________________________________________________________________________ + +To handle error conditions, put the following statement immediately after +calls that return errors: + +JC + + represents the label of an error-handling routine that gets the +specific error condition by checking the value in AX. This routine then + + 21 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +takes appropriate action. + +Some of the older system calls return a value in a register that specifies +whether the operation was successful. To handle such errors, check the +error code and take the appropriate action. + +Extended Error Codes + +Versions of MS-DOS after 2.0 have added new error messages. Any pro- +grams that use the older system calls cannot use these new error messages. +To avoid incompatibility, MS-DOS maps these new error codes to the old +error code that most closely matches the new one. + +Function 59H (Get Extended Error) has been added so that these new calls +can be used. It provides as much detail as possible about the most recent +error code returned by MS-DOS. The description of Function 59H lists the +new, more detailed error codes and shows how to use this function request. + +1.10.6 System Call Descriptions + +Most system calls require that you move information into one or more +registers before issuing the call that returns information in the registers. +The description of each system call in this chapter includes the following: + + o A diagram of the 8088 registers that shows their contents before + and after the system call + + o A more complete description of the register contents required + before the system call + + o A description of the processing performed + + o A more complete description of the register contents after the sys- + tem call + + o An example of how to use the system call + +The following figure is a sample illustration of the 8088 registers, showing +how the information is presented. Shaded areas indicate that the register +receives or returns information used by the call. + + _ _____________________ + + +22 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + _ _____________________ + + + Figure 1.1 Example of the 8088 Registers + + +1.10.6.1 Sample Programs + +The sample programs show only data declarations and the code that you +need to use the system calls. Unless stated otherwise, each example +assumes a common program skeleton that defines the segments and +returns control to MS-DOS. Each sample program is intended to be exe- +cuted as a .com file. Figure 1.2 shows a complete sample program. The +unshaded portion shows what appears in this chapter; the shaded portions +are the common skeleton. + +------------------------------------------------------------ +code segment + assume cs:code,ds:code,es:nothing,ss:nothing + org 100H +start: jmp begin +; +filename db "b:\textfile.asc",0 +buffer db 129 dup (?) +handle dw ? +; +begin: open_handle filename,0 ; Open the file + jc error_open ; Routine not shown + mov handle,ax ; Save handle +read_line: read_handle handle,buffer,128 ; Read 128 bytes + jc error_read ; Routine not shown + cmp ax,0 ; End of file? + je return ; Yes, go home + mov bx,ax ; No, AX bytes read + mov buffer[bx],"$" ; To terminate string + display buffer ; See Function 09H + jmp read_line ; Get next 128 bytes + +return: end_process 0 ; Return to MS-DOS +last_inst: ; To mark next byte +; +code ends + end start +------------------------------------------------------------ + + + Figure 1.2 Sample Program with Common Skeleton + +A macro has been defined for each system call to allow the examples to be +more complete programs, rather than isolated uses of the system calls. +These macros, plus some general-purpose ones, are used in the sample pro- +grams. For instance, the sample program in the preceding figure includes +four such macros: open_handle, read_handle, display, and end_process. + + 23 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +All the macro definitions are listed at the end of this chapter. + +The macros assume the environment for a .com program as described in +Chapter 4; in particular, they assume that all the segment registers con- +tain the same value. To conserve space, the macros generally leave error +checking to the main code and do not protect registers. This keeps the +macros short, yet useful. You may find that such macros are a convenient +way to include system calls in your assembly-language programs. + +1.10.6.2 Error Handling in Sample Programs + +Whenever a system call returns an error code, the sample program shows a +test for the error condition and a jump to an error routine. To conserve +space, the error routines themselves aren't shown. Some error routines +might simply display a message and continue processing. For more serious +errors, the routine might display a message and end the program (perform- +ing any required housekeeping, such as closing files). + +Tables 1.16 through 1.19 list the Interrupts and Function Requests in +numeric and alphabetic order. + +Table 1.16 + +MS-DOS Interrupts, Numeric Order + +_ _________________________________________________________________________ + +Interrupt Description + +_ _________________________________________________________________________ + +20H Program Terminate +21H Function Request +22H Terminate Process Exit Address +23H CONTROL-C Handler Address +24H Critical-Error-Handler Address +25H Absolute Disk Read +26H Absolute Disk Write +27H Terminate But Stay Resident +28H-3FH Reserved + +_ _________________________________________________________________________ + +Table 1.17 + +MS-DOS Interrupts, Alphabetic Order + +_ _________________________________________________________________________ + +Description Interrupt + +_ _________________________________________________________________________ + +Absolute Disk Read 25H +Absolute Disk Write 26H +CONTROL-C Handler Address 23H +Critical-Error-Handler Address 24H +Function Request 21H +Program Terminate 20H + +24 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +Reserved 28H-3FH +Terminate Process Exit Address 22H +Terminate But Stay Resident 27H + +_ _________________________________________________________________________ + +Table 1.18 + +MS-DOS Function Requests, Numeric Order + +_ _________________________________________________________________________ + +Function Description + +_ _________________________________________________________________________ + +00H Terminate Program + +01H Read Keyboard And Echo + +02H Display Character + +03H Auxiliary Input + +04H Auxiliary Output + +05H Print Character + +06H Direct Console I/O + +07H Direct Console Input + +08H Read Keyboard + +09H Display String + +0AH Buffered Keyboard Input + +0BH Check Keyboard Status + +0CH Flush Buffer, Read Keyboard + +0DH Reset Disk + +0EH Select Disk + +0FH Open File + +10H Close File + +11H Search For First Entry + +12H Search For Next Entry + +13H Delete File + +14H Sequential Read + +15H Sequential Write + +16H Create File + +17H Rename File + +18H Reserved + +19H Get Current Disk + +1AH Set Disk Transfer Address + +1BH Get Default Drive Data + +1CH Get Drive Data + +1DH-20H Reserved + +21H Random Read + + 25 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +22H Random Write + +23H Get File Size + +24H Set Relative Record + +25H Set Interrupt Vector + +26H Create New PSP + +27H Random Block Read + +28H Random Block Write + +29H Parse File Name + +2AH Get Date + +2BH Set Date + +2CH Get Time + +2DH Set Time + +2EH Set/Reset Verify Flag + +2FH Get Disk Transfer Address + +30H Get MS-DOS Version Number + +31H Keep Process + +32H Reserved + +33H CONTROL-C Check + +34H Reserved + +35H Get Interrupt Vector + +36H Get Disk Free Space + +37H Reserved + +38H Get/Set Country Data + +39H Create Directory + +3AH Remove Directory + +3BH Change Current Directory + +3CH Create Handle + +3DH Open Handle + +3EH Close Handle + +3FH Read Handle + +40H Write Handle + +41H Delete Directory Entry (Unlink) + +42H Move File Pointer + +43H Get/Set File Attributes (Chmod) + +4400H,4401H IOCtl Data + +4402H,4403H IOCtl Character + +4404H,4405H IOCtl Block + +4406H,4407H IOCtl Status + +4408H IOCtl Is Changeable + +4409H IOCtl Is Redirected Block + +26 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +440AH IOCtl Is Redirected Handle + +440BH IOCtl Retry + +440CH Generic IOCtl (for code page functions) + +440DH Generic IOCtl (for devices) + +440EH Get IOCtl Drive Map + +440FH Set IOCtl Drive Map + +45H Duplicate File Handle + +46H Force Duplicate File Handle + +47H Get Current Directory + +48H Allocate Memory + +49H Free Allocated Memory + +4AH Set Block + +4BH Load and Execute Program + +4B03H Load Overlay + +4CH End Process + +4DH Get Return Code of Child Process + +4EH Find First File + +4FH Find Next File + +50H-53H Reserved + +54H Get Verify State + +55H Reserved + +56H Change Directory Entry + +57H Get/Set Date/Time of File + +58H Get/Set Allocation Strategy + +59H Get Extended Error + +5AH Create Temporary File + +5BH Create New File + +5C00H Lock + +5C01H Unlock + +5DH Reserved + +5E00H Get Machine Name + +5E02H Printer Setup + +5F02H Get Assign-List Entry + +5F03H Make Assign-List Entry + +5F04H Cancel Assign-List Entry + +60H-61H Reserved + +62H Get PSP + +63H,64H Reserved + +65H Get Extended Country Information + +66H Get/Set Global Code Page + + 27 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +67H Set Handle Count + +68H Commit File + +69H-7FH Reserved + +_ _________________________________________________________________________ + +Table 1.19 + +MS-DOS Function Requests, Alphabetic Order + +_ _________________________________________________________________________ + +Description Interrupt + +_ _________________________________________________________________________ + +Allocate Memory 48H + +Auxiliary Input 03H + +Auxiliary Output 04H + +Buffered Keyboard Input 0AH + +Cancel Assign-List Entry 5F04H + +Change Current Directory 3BH + +Change Directory Entry 56H + +Check Keyboard Status 0BH + +Close File 10H + +Close Handle 3EH + +Commit FIle 68H + +CONTROL-C Check 33H + +Create Directory 39H + +Create File 16H + +Create Handle 3CH + +Create New File 5BH + +Create New PSP 26H + +Create Temporary File 5AH + +Delete Directory Entry (Unlink) 41H + +Delete File 13H + +Direct Console I/O 06H + +Direct Console Input 07H + +Display Character 02H + +Display String 09H + +Duplicate File Handle 45H + +End Process 4CH + +Find First File 4EH + +Find Next File 4FH + +Flush Buffer, Read Keyboard 0CH + +Force Duplicate File Handle 46H + + +28 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +Free Allocated Memory 49H + +Generic IOCtl (for devices) 440DH + +Generic IOCtl (for code page functions) 440CH + +Get Assign-List Entry 5F02H + +Get Current Directory 47H + +Get Current Disk 19H + +Get Date 2AH + +Get Default Drive Data 1BH + +Get Disk Free Space 36H + +Get Disk Transfer Address 2FH + +Get Drive Data 1CH + +Get Extended Country Information 65H + +Get Extended Error 59H + +Get File Size 23H + +Get Interrupt Vector 35H + +Get IOCtl Drive Map 440EH + +Get Machine Name 5E00H + +Get MS-DOS Version Number 30H + +Get PSP 62H + +Get Return Code of Child Process 4DH + +Get Time 2CH + +Get Verify State 54H + +Get/Set Allocation Strategy 58H + +Get/Set Country Data 38H + +Get/Set Date/Time Of File 57H + +Get/Set File Attributes (Chmod) 43H + +Get/Set Global Code Page 66H + +IOCtl Block 4404H,4405H + +IOCtl Character 4402H,4403H + +IOCtl Data 4400H,4401H + +IOCtl Is Changeable 4408H + +IOCtl Is Redirected Block 4409H + +IOCtl Is Redirected Handle 440AH + +IOCtl Retry 440BH + +IOCtl Status 4406H,4407H + +Keep Process 31H + +Load and Execute Program 4BH + +Load Overlay 4B03H + +Lock 5C00H + +Make Assign-List Entry 5F03H + + 29 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +Move File Pointer 42H + +Open File 0FH + +Open Handle 3DH + +Parse File Name 29H + +Print Character 05H + +Printer Setup 5E02H + +Random Block Read 27H + +Random Block Write 28H + +Random Read 21H + +Random Write 22H + +Read Handle 3FH + +Read Keyboard 08H + +Read Keyboard And Echo 01H + +Remove Directory 3AH + +Rename File 17H + +Reserved 18H + +Reserved 1DH-20H + +Reserved 32H + +Reserved 34H + +Reserved 37H + +Reserved 50H-53H + +Reserved 55H + +Reserved 5DH + +Reserved 60H-61H + +Reserved 63H, 64H + +Reserved 69H-7FH + +Reset Disk 0DH + +Search for First Entry 11H + +Search for Next Entry 12H + +Select Disk 0EH + +Sequential Read 14H + +Sequential Write 15H + +Set Block 4AH + +Set Date 2BH + +Set Disk Transfer Address 1AH + +Set Handle Count 67H + +Set Interrupt Vector 25H + +Set IOCtl Drive Map 440FH + +Set Relative Record 24H + +Set Time 2DH + +30 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +Set/Reset Verify Flag 2EH + +Terminate Program 00H + +Unlock 5C01H + +Write Handle 40H + +_ _________________________________________________________________________ + +A detailed description of each system call follows. These calls are listed in +numeric order, interrupts first, followed by function requests. + +_ ________________________________________________________________ + +Note + + Unless stated otherwise, in the system call descriptions\(emboth text and + code\(emall numbers are in hexadecimal. + +_ ________________________________________________________________ + + +1.11 Interrupts + +The following pages describe Interrupts 20H-27H. + + + 31 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + + +Program Terminate (Interrupt 20H) + + Call: + + CS + Segment address of Program Segment Prefix + + Return: + + None + + + +Comments: + +Interrupt 20H terminates the current process and returns control to its +parent process. It also closes all open file handles and clears the disk cache. +When this interrupt is issued, CS must contain the segment address of the +Program Segment Prefix. + +Interrupt 20H is provided only for compatibility with MS-DOS versions +prior to 2.0. New programs should use Function 4CH (End Process), +which permits returning a completion code to the parent process and does +not require CS to contain the segment address of the Program Segment +Prefix. + +The following exit addresses are restored from the Program Segment +Prefix: + +Offset + Exit Address +_ ________________________________________________________________ + +0AH Program terminate + +0EH CONTROL-C + +12H Critical error + +All file buffers are flushed to disk. + +_ ________________________________________________________________ + +32 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +Note + + You should close all files that have changed in length before issuing + this interrupt. If you do not close a changed file, its length may not be + recorded correctly in the directory. See Functions 10H and 3EH for a + description of the Close File system calls. If sharing is loaded, you + should remove all locks before using Interrupt 20H. See Function 5CH + (Lock) for more information. + +_ ________________________________________________________________ + + +Macro Definition: + + +terminate macro + int 20H + endm + + +Example: + +The following program displays a message and returns to MS-DOS. It uses +only the opening portion of the sample program skeleton shown in Figure +1.2: + +message db "displayed by INT20H example". 0DH, 0AH, "$" +; +begin: display message ;see Function 09H + terminate ;THIS INTERRUPT +code ends + end start + + + + 33 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + + +Function Request (Interrupt 21H) + + Call: + + AH + Function number + + Other registers + As specified in individual function + + Return: + + None. + + + +Comments: + +As specified in individual function. Interrupt 21H causes MS-DOS to carry +out the function request whose number is in AH. See Section 1.12, "Func- +tion Requests," for a description of the MS-DOS functions. + +Example: + +To call the Get Time function: + +mov ah,2CH ;Get Time is Function 2CH +int 21H ;MS-DOS function request + + + +34 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +Terminate Process Exit Address (Interrupt +22H) + +This interrupt may be issued only by MS-DOS; user programs must never +issue it. If you must write your own terminate interrupt handler, use +Function 35H (Get Interrupt Vector) to get the address of the standard +routine, save the address, then use Function 25H (Set Interrupt Vector) to +change the Interrupt 22H entry in the vector table so that it points to your +routine. + +When a program terminates, MS-DOS transfers control to the routine that +starts at the address in the Interrupt 22H entry in the vector table. When +MS-DOS creates a program segment, it copies this address into the Pro- +gram Segment Prefix, starting at offset 0AH. + + + 35 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + + +CONTROL-C Handler Address (Interrupt 23H) + +When you type CONTROL-C or CONTROL-BREAK (on IBM-compatibles), +MS-DOS transfers control as soon as possible to the routine that starts at +the address in the Interrupt 23H entry in the vector table. When MS-DOS +creates a program segment, it copies the address currently in the interrupt +table into the Program Segment Prefix, starting at offset 0EH. + +This interrupt may be issued only by MS-DOS; user programs must never +issue it. If you must write your own CONTROL-C interrupt handler, use +Function Request 35H (Get Interrupt Vector) to get the address of the +standard routine, save the address, then use Function Request 25H (Set +Interrupt Vector) to change the Interrupt 23H entry in the vector table to +point to your routine. + +If the CONTROL-C routine preserves all registers, it can end with an IRET +instruction (return from interrupt) to continue program execution. If a +user-written interrupt program returns with a long return, the program +uses the carry flag to determine whether or not the program will abort. If +the carry flag is set, it will abort; otherwise, execution will continue as +with a return by IRET. + +If a user-written CONTROL-BREAK routine interrupts function calls 09H, +0AH, or buffered I/O, and if it continues execution with an IRET, then +I/O continues from the start of the line. MS-DOS always outputs a +CONTROL-C to the screen when it issues an Interrupt 23H. There is no way +to turn this off. + +When the interrupt occurs, all registers are set to the value they had when +the original call to MS-DOS was made. There are no restrictions on what +a CONTROL-C handler can do\(emincluding calling MS-DOS functions\(emas +long as the program restores the registers. + +If a CONTROL-C interrupts Function 09H or 0AH (Display String or +Buffered Keyboard Input), the three-byte sequence 03H-0DH-0AH (usually +displayed as C followed by a carriage-return) is sent to the display and the +function resumes at the beginning of the next line. + +Suppose a program uses Function 4BH (Load and Execute Program) to +create a second Program Segment Prefix and execute a second program, +which then changes the CONTROL-C address in the vector table. MS-DOS +restores this CONTROL-C vector to its original value before returning con- +trol to the calling program. + + +36 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +Critical-Error-Handler Address (Interrupt 24H) + +If a critical error occurs during execution of an I/O function request (this +often means a fatal disk error), MS-DOS transfers control to the routine at +the address in the Interrupt 24H entry in the vector table. When MS-DOS +creates a program segment, it copies this address into the Program Seg- +ment Prefix, starting at offset 12H. + +This interrupt may be issued only by MS-DOS; user programs must never +issue it. If you must write your own critical-error interrupt handler, use +Function 35H (Get Interrupt Vector) to get the address of the standard +routine, save the address, then use Function 25H (Set Interrupt Vector) to +change the Interrupt 24H entry in the vector table to point to your rou- +tine. + +MS-DOS does not issue Interrupt 24H if a failure occurs during execution +of Interrupt 25H (Absolute Disk Read) or Interrupt 26H (Absolute Disk +Write). A command.com error routines handles these errors. This routine +retries the disk operation, then gives you the choice of aborting the opera- +tion, retrying it, allowing the system call to fail and the application pro- +cess to continue, or ignoring the error. + +The following topics describe the requirements of an Interrupt 24H rou- +tine, including the error codes, registers, and stack. + +1.11.1 Conditions upon Entry + +After retrying an I/O error five times, MS-DOS issues Interrupt 24H, +unless a File Allocation Table (FAT) or directory sector is involved. In +those cases, DOS performs three retries. The interrupt handler receives +control with interrupts disabled. AX and DI contain error codes, and BP +contains the offset (to the segment address in SI) of a Device Header con- +trol block that describes the device on which the error occurred. + +1.11.2 Requirements for an Interrupt 24H Handler + +To issue the "Abort, Retry, Fail or Ignore" prompt to a user, a user- +written critical-error handler should first push the flags and execute a FAR +call to the address of the standard Interrupt 24H handler (the user pro- +gram that changed the Interrupt 24H vector also should have saved this +address). After a user responds to the prompt, MS-DOS returns control to +the user-written routine. + +_ ________________________________________________________________ + +Note + + + 37 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + + There are source applications which will have trouble handling critical + errors, since this changes the stack frame. + +_ ________________________________________________________________ + +The error handler can then do its processing, but before it does anything +else it must preserve BX, CX, DX, DS, ES, SS, and SP. Also, the error +handler may use only function calls 01-0CH (inclusive) and 59H (if it uses +any others, the error handler destroys the MS-DOS stack and leaves +MS-DOS in an unstable state). The contents of the Device Header should +not be changed. + +It is recommended that Interrupt 24H routine fail critical errors and let +the application test for an extended error code when the Interrupt 21H +routine returns. + +User Stack + +This call uses the user stack that contains the following (starting with the +top of the stack): + +IP MS-DOS registers from issuing Interrupt 24H +CS +FLAGS + +AX User registers at time of original +BX INT 21H +CX +DX +SI +DI +BP +DS +ES + +IP From the original INT 21H +CS from the user to MS-DOS +FLAGS + +The registers are set such that if the user-written error handler issues an +IRET, MS-DOS responds according to the value in AL: + +AL + Action +_ ________________________________________________________________ + +0 Ignore the error. + +1 Retry the operation. + +2 Abort the program by issuing Interrupt 23H. + + + +38 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +3 Fail the system call that is in progress. + +Note that the ignore option may cause unexpected results, such as causing +MS-DOS to behave as if an operation had completed successfully. + +Disk Error Code in AX + +If bit 7 of AH is 0, the error occurred on a disk drive. AL contains the fail- +ing drive (0=A, 1=B, etc.). Bit 0 of AH specifies whether the error +occurred during a read or write operation (0=read, 1=write), and bits 1 +and 2 of AH identify the area of the disk where the error occurred: + +Bits 1-2 + Location of error +_ ________________________________________________________________ + +00 MS-DOS area + +01 File Allocation Table + +10 Directory + +11 Data area + +Bits 3-5 of AH specify valid responses to the error prompt: + +Bit Value Response + +_ ________________________________________________________________ + +3 0 Fail not allowed + 1 Fail allowed + +4 0 Retry not allowed + 1 Retry allowed + +5 0 Ignore not allowed + 1 Ignore allowed + +_ ________________________________________________________________ + +If you specify Retry but it isn't allowed, MS-DOS changes it to Fail. If you +specify Ignore but it isn't allowed, MS-DOS changes it to Fail. If you +specify Fail but it isn't allowed, MS-DOS changes it to Abort. The Abort +response is always allowed. + +Other Device Error Code in AX + +If bit 7 of AH is 1, either the memory image of the File Allocation Table +(FAT) is bad or an error occurred on a character device. The device header +pointed to by BP:SI contains a WORD of attribute bits that identify the +type of device and, therefore, the type of error. + + + + 39 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +The word of attribute bits is at offset 04H of the Device Header. Bit 15 +specifies the type of device (0=block, 1=character). + +If bit 15 is 0 (block device), the error was a bad memory image of the FAT. + +If bit 15 is 1 (character device), the error was on a character device. DI +contains the error code, the contents of AL are undefined, and bits 0-3 of +the attribute word have the following meaning: + +Bit + Meaning if Set +_ ________________________________________________________________ + +0 Current standard input + +1 Current standard output + +2 Current null device + +3 Current clock device + +See Chapter 2, "MS-DOS Device Drivers," for a complete description of +the Device Header control block. + +Error Code in DI + +The high byte of DI is undefined. The low byte contains the following error +codes: + +Error code + Description +_ ________________________________________________________________ + +0 Attempt to write on write-protected disk + +1 Unknown unit + +2 Drive not ready + +3 Unknown command + +4 CRC error in data + +5 Bad drive request structure length + +6 Seek error + +7 Unknown media type + +8 Sector not found + +9 Printer out of paper + +A Write fault + +B Read fault + +C General failure + +A user-written Interrupt 24H handler can use Function 59H (Get Extended + +40 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +Error) to get detailed information about the error that caused the inter- +rupt to be issued. + + + 41 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + + +Absolute Disk Read (Interrupt 25H) + + Call: + + AL + Drive number + DS:BX + Disk Transfer Address + CX + Number of sectors + DX + Beginning relative sector + + Return: + + AL + Error code if CF=1 + Flags + CF = 0 if successful + = 1 if not successful + + +Comments: + +The registers must contain the following: + +Register + Contents +_ ________________________________________________________________ + +AL Drive number (0=A, 1=B, etc.) + +BX Offset of Disk Transfer Address (from segment address in DS) + +CX Number of sectors to read + +DX Beginning relative sector + +_ ________________________________________________________________ + +Warning + + Avoid using this function unless absolutely necessary. Instead, you + should access files through normal MS-DOS function requests. There + is no guarantee of upward compatibility for the Absolute Disk I/O in + future releases of MS-DOS. + +_ ________________________________________________________________ + +Interrupt 25H transfers control to the device driver and reads from the +disk to the Disk-Transfer Address the number of sectors specified in CX. +The interrupt has the same requirements as and processes identically to + +42 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +Interrupt 26H (Absolute Disk Write), except that it reads data rather than +writes it. Also, since this interrupt does not check your input parameters +too closely, make sure they are reasonable. If you use unreasonable +parameters, you may get strange results or cause your system to crash. + +_ ________________________________________________________________ + +Note + + This call destroys all registers except the segment registers. So before + issuing the interrupt, save any registers that your program uses. + +_ ________________________________________________________________ + +The system pushes the flags at the time of the call; they are still there upon +return. To prevent uncontrolled growth, be sure to pop the stack upon +return. + +If the disk operation is successful, the Carry Flag (CF) is 0. If the disk +operation is not successful, CF is 1 and AL contains the MS-DOS error +code (see Interrupt 24H earlier in this section for the codes and their +meanings). + +Macro Definition: + + +abs_disk_read macro disk,buffer,num_sectors,first_sector + mov al,disk + mov bx,offset buffer + mov cx,num_sectors + mov dx,first_sector + int 25H + popf + endm + + +Example: + +The following program copies the contents of a single-sided disk in drive A +to the disk in drive B. + +prompt db "Source in A, target in B",0DH,0AH + db "Any key to start. $" +first dw 0 +buffer db 60 dup (512 dup (?)) ;60 sectors +; +begin: display prompt ;see Function 09H + read_kbd ;see Function 08H + mov cx,6 ;copy 6 groups of + ;60 sectors +copy: push cx ;save the loop counter + abs_disk_read 0,buffer,60,first ;THIS INTERRUPT + + 43 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + + abs_disk_write 1,buffer,60,first ;see INT 26H + add first,60 ;do the next 60 sectors + pop cx ;restore the loop counter + loop copy + + + +44 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +Absolute Disk Write (Interrupt 26H) + + Call: + + AL + Drive number + DS:BX + Disk Transfer Address + CX + Number of sectors + DX + Beginning relative sector + + Return: + + AL + Error code if CF = 1 + FLAGS + CF = 0 if successful + = 1 if not successful + + +Comments: + +_ ________________________________________________________________ + +Warning + + Avoid using this function unless absolutely necessary. Instead, you + should access files through normal MS-DOS function requests. There + is no guarantee of upward compatibility for the Absolute Disk I/O in + future releases of MS-DOS. + +_ ________________________________________________________________ + +The registers must contain the following: + +Register + Contents +_ ________________________________________________________________ + +AL Drive number (0=A, 1=B, etc.) + +BX Offset of Disk Transfer Address (from segment address in DS) + +CX Number of sectors to write + +DX Beginning relative sector + +This interrupt transfers control to MS-DOS. The number of sectors +specified in CX is written from the Disk Transfer Address to the disk. Its +requirements and processing are identical to Interrupt 25H (Absolute Disk + + 45 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + +Read), except data is written to the disk rather than read from it. Also, +since Interrupt 26H does not check your input parameters too closely, +make sure they are reasonable. If you use unreasonable parameters, you +may get strange results or cause your system to crash. + +_ ________________________________________________________________ + +Note + + This call destroys all registers except the segment registers. So before + issuing the interrupt, be sure to save any registers your program uses. + +_ ________________________________________________________________ + +The system pushes the flags at the time of the call; they are still there upon +return. To prevent uncontrolled growth, be sure to pop the stack upon +return. + +If the disk operation is successful, the Carry Flag (CF) is 0. If the disk +operation is not successful, CF is 1 and AL contains the MS-DOS error +code (see Interrupt 24H for the codes and their meanings). + +Macro Definition: + + +abs_disk_write macro disk,buffer,num_sectors,first_sector + mov al,disk + mov bx,offset buffer + mov cx,num_sectors + mov dx,first_sector + int 26H + popf + endm + + +Example: + +The following program copies the contents of a single-sided disk in drive A +to the disk in drive B, verifying each write. It uses a buffer of 32K bytes. + +off equ 0 +on equ 1 +; +prompt db "Source in A, target in B",0DH,0AH + db "Any key to start. $" +first dw 0 +buffer db 60 dup (512 dup (?)) ;60 sectors +; +begin: display prompt ;see Function 09H + read_kbd ;see Function 08H + verify on ;see Function 2EH + mov cx,6 ;copy 6 groups of 60 sectors + +46 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + +copy: push cx ;save the loop counter + abs_disk_read 0,buffer,60,first ;see INT 25H + abs_disk_write 1,buffer,60,first ;THIS INTERRUPT + add first,60 ;do the next 60 sectors + pop cx ;restore the loop counter + loop copy + verify off ;see Function 2EH + + + + 47 + +_ _ | | _ _ + + + + +_ _ | | _ _ + +Microsoft MS-DOS Programmer's Reference + +_ _________________________________________________ + + +Terminate But Stay Resident (Interrupt 27H) + + Call: + + CS:DX + Pointer to first byte following + last byte of code. + + Return: + + None + + + +Comments: + +This interrupt is provided only for compatibility with MS-DOS versions +prior to 2.0. Unless your resident program must be compatible with +MS-DOS versions before 2.0, you should use Function 31H (Keep Process) +to install it. Function 31H lets programs larger than 64K remain resident +and allows return information to be passed. + +However, Interrupt 27H, which is often used to install device-specific inter- +rupt handlers, forces programs that are up to 64K to remain resident after +they terminate. + +DX must contain the offset (from the segment address in CS) of the first +byte that follows the last byte of code in the program. When Interrupt +27H is executed, the program terminates and control returns to MS-DOS, +but the program is not overlaid by other programs. Files left open are not +closed. When the interrupt is called, CS must contain the segment +address of the Program Segment Prefix (the value of DS and ES when exe- +cution started). + +.Exe programs that are loaded into high memory must not use this inter- +rupt. Similarly, since it restores the Interrupt 22H, 23H, and 24H vectors, +you should not use Interrupt 27H to install new CONTROL-C or critical- +error handlers. + + +48 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + System Calls + + _ ________________________ + + +Macro Definition: + + +stay_resident macro last_instruc + mov dx,offset last_instruc + inc dx + int 27H + endm + + +Example: + +Since the most common use of Interrupt 27H is to install a machine- +specific routine, there is no general example that applies. The macro +definition, however, shows the calling syntax. + +1.12 Function Requests + +The following pages describe function calls 00H-68H. + + + 49 + +_ _ | | _ _ + + + diff --git a/PROGREF/1B_CALLS.A b/PROGREF/1B_CALLS.A new file mode 100644 index 0000000..aa93e56 --- /dev/null +++ b/PROGREF/1B_CALLS.A @@ -0,0 +1,2688 @@ + +_ _ | | _ _ + + + + _ ______________ + + +Terminate Program (Function 00H) + + Call: + + AH = 00H + CS + Segment address of + Program Segment Prefix + + Return: + + None + + + +Comments: + +Function 00H performs the same function as Interrupt 20H. It terminates +the current process and returns control to its parent process. It also closes +all open file handles and clears the disk cache. When this interrupt is +issued, CS must contain the segment address of the Program Segment +Prefix. + +The CS register must contain the segment address of the Program Seg- +ment Prefix before you call this interrupt. + +The following exit addresses are restored from the specified offsets in the +Program Segment Prefix: + +Offset + Exit Address +_ ________________________________________________________________ + +0AH Program terminate + +0EH CONTROL-C + +12H Critical error + +All file buffers are flushed to disk. + + + 1 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +_ ________________________________________________________________ + +Warning + + Close all files that have changed in length before calling this function. + If you do not close a changed file, its length is not correctly recorded in + the directory. See Function 10H for a description of the Close File sys- + tem call. + +_ ________________________________________________________________ + + +Macro Definition: + + +terminate_program macro + xor ah,ah + int 21H + endm + + +Example: + +The following program displays a message and returns to MS-DOS. It uses +only the opening portion of the sample program skeleton shown in Figure +1.2. + +message db "Displayed by FUNC00H example", 0DH,0AH,"$" +; +begin: display message ;see Function 09H + terminate_program ;THIS FUNCTION +code ends + end start + + + +2 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Read Keyboard and Echo (Function 01H) + + Call: + + AH = 01H + + Return: + + AL + Character typed + + + +Comments: + +Function 01H waits for a character to be read from standard input, then +echoes the character to standard output and returns it in AL. If the char- +acter is CONTROL-C, it executes Interrupt 23H. + +Macro Definition: + + +read_kbd_and_echo macro + mov ah, 01H + int 21H + endm + + +Example: + +The following program displays and prints characters as you type them. If +you press the RETURN key, the program sends a linefeed/carriage-return +sequence to both the display and the printer. + +begin: read_kbd_and_echo ;THIS FUNCTION + print_char al ;see Function 05H + cmp al,0DH ;is it a CR? + jne begin ;no, print it + print_char 0AH ;see Function 05H + display_char 0AH ;see Function 02H + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + jmp begin ;get another character + + + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Display Character (Function 02H) + + Call: + + AH = 02H + DL + Character to be displayed + + Return: + + None + + + +Comments: + +Function 02H sends the character in DL to standard output. If you press +CONTROL-C, it issues Interrupt 23H. + +Macro Definition: + + +display_char macro character + mov dl,character + mov ah,02H + int 21H + endm + + +Example: + +The following program converts lowercase characters to uppercase before +displaying them. + +begin: read_kbd ;see Function 08H + cmp al,"a" + jl uppercase ;don't convert + cmp al,"z" + jg uppercase ;don't convert + sub al,20H ;convert to ASCII code + ;for uppercase + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +uppercase: display_char al ;THIS FUNCTION + jmp begin: ;get another character + + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Auxiliary Input (Function 03H) + + Call: + + AH = 03H + + Return: + + AL + Character from auxiliary device + + + +Comments: + +Function 03H waits for a character from standard auxiliary devices (AUX, +COM1, COM2, COM3, COM4), then returns the character in AL. This +system call does not return a status or error code. + +If you press CONTROL-C, it issues Interrupt 23H. + +Macro Definition: + + +aux_input macro + mov ah,03H + int 21H + endm + + +Example: + +The following program prints characters as soon as it receives them from +the auxiliary device. It stops printing when it receives an end-of-file char- +acter (ASCII 26, or CONTROL-Z). + +begin: aux_input ;THIS FUNCTION + cmp al,1AH ;end of file? + je return ;yes, all done + print_char al ;see Function 05H + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + jmp begin ;get another character + + + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Auxiliary Output (Function 04H) + + Call: + + AH = 04H + DL + Character for auxiliary device + + Return: + + None + + + +Comments: + +Function 04H sends the character in DL to standard auxiliary. This sys- +tem call does not return a status or error code. + +If you press CONTROL-C, it issues Interrupt 23H. + +Macro Definition: + + +aux_output macro character + mov dl,character + mov ah,04H + int 21H + endm + + +Example: + +The following program gets a series of strings of up to 80 bytes from the +keyboard and sends each string to the auxiliary device. It stops when you +type a null string (carriage-return only). + +string db 81 dup(?) ;see Function 0AH +; +begin: get_string 80,string ;see Function 0AH + cmp string[1],0 ;null string? + + 9 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + je return ;yes, all done + mov cx, word ptr string[1] ;get string length + mov bx,0 ;set index to 0 +send_it: aux_output string[bx+2] ;THIS FUNCTION + inc bx ;bump index + loop send_it ;send another character + jmp begin ;get another string + + + +10 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Print Character (Function 05H) + + Call: + + AH = 05H + DL + Character for printer + + Return: + + None + + + +Comments: + +Function 05H sends the character in DL to the standard printer. If you +press CONTROL-C, it issues Interrupt 23H. This function does not return a +status or error code. + +Macro Definition: + + +print_char macro character + mov dl,character + mov ah,05H + int 21H + endm + + +Example: + +The following program prints a walking test pattern on the printer. It +stops if you press CONTROL-C. + +line_num db 0 +; +begin: mov cx,60 ;print 60 lines +start_line: mov bl,33 ;first printable ASCII + ;character (!) + add bl,line_num ;to offset one character + + 11 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + push cx ;save number-of-lines counter + mov cx,80 ;loop counter for line +print_it: print_char bl ;THIS FUNCTION + inc bl ;move to next ASCII character + cmp bl,126 ;last printable ASCII + ;character (~) + jl no_reset ;not there yet + mov bl,33 ;start over with (!) +no_reset: loop print_it ;print another character + print_char 0DH ;carriage return + print_char 0AH ;linefeed + inc line_num ;to offset 1st char. of line + pop cx ;restore #-of-lines counter + loop start_line ;print another line + + + +12 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Direct Console I/O (Function 06H) + + Call: + + AH = 06H + DL + See text + + Return: + + AL + If DL = FFH before call, + then zero flag not set means AL + has character from standard input. + Zero flag set means there was not + a character to get, and AL = 0. + + + +Comments: + +The action of Function 06H depends on the value in DL when the function +is called: + +Value in DL + Action +_ ________________________________________________________________ + +FFH If a character has been read from standard input, it is + returned in AL and the zero flag is cleared (0); if a + character has not been read, the zero flag is set (1). + +Not FFH The character in DL is sent to standard output. + +This function does not check for CONTROL-C. + +Macro Definition: + + +dir_console_io macro switch + mov dl,switch + mov ah,06H + int 21H + endm + + + + 13 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program sets the system clock to 0 and displays the time +continuously. When you type any character, the display freezes; when you +type any character again, the clock is reset to 0 and the display starts +again. + +time db "00:00:00.00",0DH,0AH,"$" ;see Function 09H +; ;for explanation of $ +; +begin: set_time 0,0,0,0 ;see Function 2DH +read_clock: get_time ;see Function 2CH + CONVERT ch,time ;see end of chapter + CONVERT cl,time[3] ;see end of chapter + CONVERT dh,time[6] ;see end of chapter + CONVERT dl,time[9] ;see end of chapter + display time ;see Function 09H + dir_console_io FFH ;THIS FUNCTION + cmp al,0 ;character typed? + jne stop ;yes, stop timer + jmp read_clock ;no, keep timer + ;running +stop: read_kbd ;see Function 08H + jmp begin ;start over + + + +14 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Direct Console Input (Function 07H) + + Call: + + AH = 07H + + Return: + + AL + Character from keyboard + + + +Comments: + +Function 07H waits for a character to be read from standard input, then +returns it in AL. This function does not echo the character or check for +CONTROL-C. (For a keyboard input function that echoes or checks for +CONTROL-C, see Function 01H or 08H.) + +Macro Definition: + + +dir_console_input macro + mov ah,07H + int 21H + endm + + +Example: + +The following program prompts for a password (eight characters max- +imum) and places the characters into a string without echoing them. + +password db 8 dup(?) +prompt db "Password: $" ;see Function 09H for + ;explanation of $ +begin: display prompt ;see Function 09H + mov cx,8 ;maximum length of password + xor bx,bx ;so BL can be used as index + + 15 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +get_pass: dir_console_input ;THIS FUNCTION + cmp al,0DH ;was it a carriage return? + je return ;yes, all done + mov password[bx],al ;no, put character in string + inc bx ;bump index + loop get_pass ;get another character + + + +16 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Read Keyboard (Function 08H) + + Call: + + AH = 08H + + Return: + + AL + Character from keyboard + + + +Comments: + +Function 08H waits for a character to be read from standard input, then +returns it in AL. If you press CONTROL-C, it issues Interrupt 23H. This +function does not echo the character. (For a keyboard input function that +echoes the character or checks for CONTROL-C, see Function 01H.) + +Macro Definition: + + +read_kbd macro + mov ah,08H + int 21H + endm + + +Example: + +The following program prompts for a password (eight characters max- +imum) and places the characters into a string without echoing them. + +password db 8 dup(?) +prompt db "Password: $" ;see Function 09H + ;for explanation of $ +begin: display prompt ;see Function 09H + mov cx,8 ;maximum length of password + xor bx,bx ;BL can be an index + + 17 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +get_pass: read_kbd ;THIS FUNCTION + cmp al,0DH ;was it a carriage return? + je return ;yes, all done + mov password[bx],al ;no, put char. in string + inc bx ;bump index + loop get_pass ;get another character + + + +18 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Display String (Function 09H) + + Call: + + AH = 09H + DS:DX + Pointer to string to be displayed + + Return: + + None + + + +Comments: + +Function 09H sends to standard output a string that ends with "$" (the $ +is not displayed). + +The DX register must contain the offset (from the segment address in DS) +of the string. + +Macro Definition: + + +display macro string + mov dx,offset string + mov ah,09H + int 21H + endm + + +Example: + +The following program displays the hexadecimal code of the key that is +typed. + +table db "0123456789ABCDEF" +result db " - 00H",0DH,0AH,"$" ;see text for + ;explanation of $ +begin: read_kbd_and_echo ;see Function 01H + + 19 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + xor ah,ah ;clear upper byte + convert ax,16,result[3] ;see end of chapter + display result ;THIS FUNCTION + jmp begin ;do it again + + + +20 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Buffered Keyboard Input (Function 0AH) + + Call: + + AH = 0AH + DS:DX + Pointer to input buffer + + Return: + + None + + + +Comments: + +Function 0AH gets a string from standard input. DX must contain the +offset (from the segment address in DS) of an input buffer of the following +form: + +Byte + Contents +_ ________________________________________________________________ + +1 Maximum number of characters in buffer, including the carriage + return (you must set this value). + +2 Actual number of characters typed, not counting the carriage + return (the function sets this value). + +3-n Buffer; must be at least as long as the number in byte 1. + +Characters are read from standard input and placed in the buffer begin- +ning at the third byte until a RETURN character (ASCII 0DH) is read. If the +buffer fills to one less than the maximum, additional characters read are +ignored and ASCII 07H (Bel) is sent to standard output until a RETURN +character is read. If you type the string at the console, it can be edited as +it is being entered. If you press CONTROL-C, it issues Interrupt 23H. + +MS-DOS sets the second byte of the buffer to the number of characters +read (not counting the carriage return). + + + 21 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +get_string macro limit,string + mov dx,offset string + mov string,limit + mov ah,0AH + int 21H + endm + + +Example: + +The following program gets a 16-byte (maximum) string from the key- +board and fills a 24-line by 80-character screen with it. + +buffer label byte +max_length db ? ;maximum length +chars_entered db ? ;number of chars. +string db 17 dup (?) ;16 chars + CR +strings_per_line dw 0 ;how many strings + ;fit on line +crlf db 0DH,0AH +; +begin: get_string 17,buffer ;THIS FUNCTION + xor bx,bx ;so byte can be + ;used as index + mov bl,chars_entered ;get string length + mov buffer[bx+2],"$" ;see Function 09H + mov al,50H ;columns per line + cbw + div chars_entered ;times string fits + ;on line + xor ah,ah ;clear remainder + mov strings_per_line,ax ;save col. counter + mov cx,24 ;row counter +display_screen: push cx ;save it + mov cx,strings_per_line ;get col. counter +display_line: display string ;see Function 09H + loop display_line + display crlf ;see Function 09H + pop cx ;get line counter + loop display_screen ;display 1 more line + + + +22 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Check Keyboard Status (Function 0BH) + + Call: + + AH = 0BH + + Return: + + AL + 00H = no characters in type-ahead buffer + FFH = characters in type-ahead buffer + + + +Comments: + +Function 0BH checks whether characters are available from standard +input (if standard input has not been redirected, it checks the type-ahead +buffer). If characters are available, AL returns FFH; if not, AL returns 0. +If CONTROL-C is in the buffer, it issues Interrupt 23H. + +Macro Definition: + + +check_kbd_status macro + mov ah,0BH + int 21H + endm + + +Example: + +The following program displays the time continuously until you press any +key: + +time db "00:00:00.00",0DH,0AH,"$" + . + . +begin: get_time ;see Function 2CH + byte_to_dec ch,time ;see end of chapter + byte_to_dec cl,time[3] ;see end of chapter + + 23 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + byte_to_dec dh,time[6] ;see end of chapter + byte_to_dec dl,time[9] ;see end of chapter + display time ;see Function 09H + check_kbd_status ;THIS FUNCTION + cmp al,0FFH ;has a key been typed? + je return ;yes, go home + jmp begin ;no, keep displaying + ;time + + + +24 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Flush Buffer, Read Keyboard (Function 0CH) + + Call: + + AH = 0CH + AL + 1, 6, 7, 8, or 0AH = the + corresponding function + is called. + Any other value = no + further processing. + + Return: + + AL + 00H = Type-ahead buffer was + flushed; no other + processing performed. + + + +Comments: + +Function 0CH empties the standard input buffer (if standard input has not +been redirected, Function 0CH empties the type-ahead buffer). Further +processing depends on the value in AL when the function is called. + +AL + Action +_ ________________________________________________________________ + +1,6,7,8, or 0AH The corresponding MS-DOS function is executed. + +Any other value No further processing; AL returns 0. + + +Macro Definition: + + +flush_and_read_kbd macro switch + mov al,switch + mov ah,0CH + int 21H + endm + + + + 25 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program both displays and prints characters as you type +them. If you press the RETURN key, the program sends a carriage- +return/linefeed sequence to both the display and the printer. + +begin: flush_and_read_kbd 1 ;THIS FUNCTION + print_char al ;see Function 05H + cmp al,0DH ;is it a carriage return? + jne begin ;no, print it + print_char 0AH ;see Function 05H + display_char 0AH ;see Function 02H + jmp begin ;get another character + + + +26 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Reset Disk (Function 0DH) + + Call: + + AH = 0DH + + Return: + + None + + + +Comments: + +Function 0DH flushes all file buffers to ensure that the internal buffer +cache matches the disks in the drives. It writes out buffers that have been +modified, and marks all buffers in the internal cache as free. This function +request is normally used to force a known state of the system; CONTROL-C +interrupt handlers should call this function. + +This function does not update directory entries; you must close changed +files to update their directory entries (see Function 10H, Close File). + +Macro Definition: + + +reset_disk macro + mov ah,0DH + int 21H + endm + + + + 27 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program flushes all file buffers and selects disk A. + +begin: reset_disk + select_disk "A" + + + +28 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Select Disk (Function 0EH) + + Call: + + AH = 0EH + DL + Logical drive number + (0 = A, 1 = B, etc.) + + Return: + + AL + Number of logical drives + + + +Comments: + +Function 0EH selects the drive specified in DL (0=A, 1=B, etc.) as the +current logical drive. AL returns the number of logical drives. + +_ ________________________________________________________________ + +Note + + For future compatibility, treat the value returned in AL with care. + For example, if AL returns 5, it is not safe to assume that drives A, B, + C, D, and E are all valid drive designators. + +_ ________________________________________________________________ + + +Macro Definition: + + +select_disk macro disk + mov dl,disk[-64] + mov ah,0EH + int 21H + endm + + + + 29 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program toggles between drive A and drive B to select the +current drive (in a two-drive system). + +begin: current_disk ;see Function 19H + cmp al,00H ;drive A: selected? + je select_b ;yes, select B + select_disk "A" ;THIS FUNCTION + jmp return +select_b: select_disk "B" ;THIS FUNCTION + + + +30 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Open File (Function 0FH) + + Call: + + AH = 0FH + DS:DX + Pointer to unopened FCB + + Return: + + AL + 00H = Directory entry found + FFH = No directory entry found + + + +Comments: + +Function 0FH opens a file. DX must contain the offset (from the segment +address in DS) of an unopened File Control Block (FCB). This call +searches the disk directory for the named file. + +If the call finds a directory entry for the file, AL returns 0 and the FCB is +filled as follows: + + o If the drive code was 0 (current drive), it is changed to the actual + drive used (1=A, 2=B, etc.). This lets you change the current + drive without interfering with subsequent operations on this file. + + o Current Block (offset 0CH) is set to 0. + + o Record Size (offset 0EH) is set to the system default of 128. + + o File Size (offset 0FH), Date of Last Write (offset 13H), and Time of + Last Write (offset 15H) are set from the directory entry. + +Before performing a sequential disk operation on the file, you must set the +Current Record field (offset 1FH). Before performing a random disk opera- +tion on the file, you must set the Relative Record field (offset 20H). If the +default record size (128 bytes) is not correct, set it to the correct length. + +If the call doesn't find a directory entry for the file, or if the file has the +hidden or system attribute, AL returns 0FFH. + + + 31 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +open macro fcb + mov dx,offset fcb + mov ah,0FH + int 21H + endm + + +Example: + +The following program prints a file named textfile.asc that is on the disk in +drive B. If a partial record is in the buffer at end-of-file, the routine that +prints the partial record prints characters until it encounters an end-of-file +mark (ASCII 26, or CONTROL-Z). + +fcb db 2,"TEXTFILEASC" + db 26 dup (?) +buffer db 128 dup (?) +; +begin: set_dta buffer ;see Function 1AH + open fcb ;THIS FUNCTION +read_line: read_seq fcb ;see Function 14H + cmp al,02H ;end of file? + je all_done ;yes, go home + cmp al,00H ;more to come? + jg check_more ;no, check for partial + ;record + mov cx,80H ;yes, print the buffer + xor si,si ;set index to 0 +print_it: print_char buffer[si] ;see Function 05H + inc si ;bump index + loop print_it ;print next character + jmp read_line ;read another record +check_more: cmp al,03H ;part. record to print? + jne all_done ;no + mov cx,80H ;yes, print it + xor si,si ;set index to 0 +find_eof: cmp buffer[si],26 ;end-of-file mark? + je all_done ;yes + print_char buffer[si] ;see Function 05H + inc si ;bump index to next + ;character + loop find_eof +all_done: close fcb ;see Function 10H + + + +32 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Close File (Function 10H) + + Call: + + AH = 10H + DS:DX + Pointer to opened FCB + + Return: + + AL + 00H = Directory entry found + FFH = No directory entry found + + + +Comments: + +Function 10H closes a file. DX must contain the offset (to the segment +address in DS) of an opened FCB. This call searches the disk directory for +the file named in the FCB. If it finds a directory entry for the file, it com- +pares the location of the file with the corresponding entries in the FCB. +The call then updates the directory entry, if necessary, to match the FCB, +and AL returns 0. + +After you change a file, you must call this function to update the directory +entry. You should close any FCB (even one for a file that has not been +changed) when you no longer need access to a file. + +If this call doesn't find a directory entry for the file, AL returns FFH. + +Macro Definition: + + +close macro fcb + mov dx,offset fcb + mov ah,10H + int 21H + endm + + + + 33 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program checks the first byte of the file named mod1.bas in +drive B to see if it is FFH and, if it is, prints a message. + +message db "Not saved in ASCII format",0DH,0AH,"$" +fcb db 2,"MOD1 BAS" + db 26 dup (?) +buffer db 128 dup (?) +; +begin: set_dta buffer ;see Function 1AH + open fcb ;see Function 0FH + read_seq fcb ;see Function 14H + + cmp buffer,0FFH ;is first byte FFH? + jne all_done ;no + display message ;see Function 09H +all_done: close fcb ;THIS FUNCTION + + + +34 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Search for First Entry (Function 11H) + + Call: + + AH = 11H + DS:DX + Pointer to unopened FCB + + Return: + + AL + 00H = Directory entry found + FFH = No directory entry found + + + +Comments: + +Function 11H searches the disk directory for the first matching filename. +DX must contain the offset (from the segment address in DS) of an +unopened FCB. The filename in the FCB can include wildcard characters. +To search for hidden or system files, DX must point to the first byte of an +extended FCB prefix. + +If this call does not find a directory entry for the filename in the FCB, AL +returns FFH. + +But if the call does find a directory entry for the filename in the FCB, AL +returns 0 and the call creates an unopened FCB of the same type (normal +or extended) at the Disk Transfer Address as follows: + + 1. If the search FCB was normal, the first byte at the Disk Transfer + Address is set to the drive number used in the search (1=A, 2=B, + etc.) and the next 32 bytes contain the directory entry. + + 2. If the search FCB was extended, the first byte at the Disk Transfer + Address is set to FFH, the next 5 bytes are set to 00H, and the fol- + lowing byte is set to the value of the attribute byte in the search + FCB. The remaining 33 bytes are the same as the result of the nor- + mal FCB (drive number and 32 bytes of directory entry). + +If you use Function 12H (Search for Next Entry) to continue searching for +matching filenames, you must not alter or open the original FCB at +DS:DX. + + 35 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The attribute field is the last byte of the extended FCB fields that precede +the FCB (see earlier in this chapter). If the attribute field is zero, Function +11H searches only normal file entries. It does not search directory entries +for hidden files, system files, volume label, and subdirectories. + +If the attribute field is hidden file, system file, or subdirectory entry (02H, +04H, or 10H), or any combination of those values, this call also searches all +normal file entries. To search all directory entries except the volume label, +set the attribute byte to 16H (hidden file and system file and directory +entry). + +If the attribute field is Volume ID (08H), the call searches only the volume +label entry. + +Macro Definition: + + +search_first macro fcb + mov dx,offset fcb + mov ah,11H + int 21H + endm + + +Example: + +The following program verifies the existence of a file named report.asm on +the disk in drive B. + +yes db "FILE EXISTS.$" +no db "FILE DOES NOT EXIST.$" +crlf db 0DH,0AH,"$" +fcb db 2,"REPORT *ASM" + db 26 dup (?) +buffer db 128 dup (?) +; +begin: set_dta buffer ;see Function 1AH + search_first fcb ;THIS FUNCTION + cmp al,0FFH ;directory entry found? + je not_there ;no + display yes ;see Function 09H + jmp continue +not_there: display no ;see Function 09H +continue: display crlf ;see Function 09H + + + +36 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Search for Next Entry (Function 12H) + + Call: + + AH = 12H + DS:DX + Pointer to unopened FCB + + Return: + + AL + 00H = Directory entry found + FFH = No directory entry found + + + +Comments: + +After you use Function 11H (Search for First Entry), you can use Function +12H to find any additional directory entries that match a filename (con- +taining wildcard characters). Function 12H searches the disk directory for +the next matching name. DX must contain the offset (from the segment +address in DS) of an FCB specified in a previous call to Function 11H. To +search for hidden or system files, DX must point to the first byte of an +extended FCB prefix\(emone that includes the appropriate attribute value. + +If the call does not find a directory entry for the filename in the FCB, AL +returns FFH. + +But if the call does find a directory entry for the filename in the FCB, AL +returns 0 and the call creates an unopened FCB of the same type (normal +or extended) at the Disk Transfer Address (see Function 11H for a descrip- +tion of how the unopened FCB is formed). + +Macro Definition: + + +search_next macro fcb + mov dx,offset fcb + mov ah,12H + int 21H + endm + + + 37 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program displays the number of files on the disk in drive B. + +message db "No files",0DH,0AH,"$" +files db 0 +fcb db 2,"???????????" + db 26 dup (?) +buffer db 128 dup (?) +; +begin: set_dta buffer ;see Function 1AH + search_first fcb ;see Function 11H + cmp al,0FFH ;directory entry found? + je all_done ;no, no files on disk + inc files ;yes, increment file + ;counter +search_dir: search_next fcb ;THIS FUNCTION + cmp al,0FFH ;directory entry found? + je done ;no + inc files ;yes, increment file + ;counter + jmp search_dir ;check again +done: convert files,10,message ;see end of chapter +all_done: display message ;see Function 09H + + + +38 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Delete File (Function 13H) + + Call: + + AH = 13H + DS:DX + Pointer to unopened FCB + + Return: + + AL + 00H = Directory entry found + FFH = No directory entry found + + + +Comments: + +Function 13H deletes a file. DX must contain the offset (from the segment +address in DS) of an unopened FCB. This call searches the directory for a +matching filename. The filename in the FCB can contain wildcard charac- +ters. + +If the call does not find a matching directory entry, AL returns FFH. + +But if the call does find a matching directory entry, AL returns 0 and the +call deletes the entry from the directory. If the filename contains a wild- +card character, the call will delete all files which match. + +Do not delete open files. + +Macro Definition: + + +delete macro fcb + mov dx,offset fcb + mov ah,13H + int 21H + endm + + + + 39 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program deletes each file on the disk in drive B that was last +written before December 31, 1982. + +year dw 1982 +month db 12 +day db 31 +files db 0 +message db "No files deleted.",0DH,0AH,"$" +fcb db 2,"???????????" + db 26 dup (?) +buffer db 128 dup (?) +; +begin: set_dta buffer ;see Function 1AH + search_first fcb ;see Function 11H + cmp al,0FFH ;directory entry found? + jne compare ;yes + jmp all_done ;no, no files on disk +compare: convert_date buffer ;see end of chapter + cmp cx,year ;next several lines + jg next ;check date in directory + cmp dl,month ;entry against date + jg next ;above & check next file + cmp dh,day ;if date in directory + jge next ;entry isn't earlier. + delete buffer ;THIS FUNCTION + inc files ;bump deleted-files + ;counter +next: search_next fcb ;see Function 12H + cmp al,00H ;directory entry found? + je compare ;yes, check date + cmp files,0 ;any files deleted? + je all_done ;no, display No files + ;message. + convert files,10,message ;see end of chapter +all_done: display message ;see Function 09H + + + +40 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Sequential Read (Function 14H) + + Call: + + AH = 14H + DS:DX + Pointer to opened FCB + + Return: + + AL + 00H = Read completed successfully + 01H = EOF + 02H = DTA too small + 03H = EOF, partial record + + + +Comments: + +Function 14H reads a record from a specified file. DX must contain the +offset (from the segment address in DS) of an opened FCB. This call loads +the record pointed to by the Current Block field (offset 0CH) and Current +Record (offset 1FH) field at the Disk Transfer Address, then increments the +Current Block and Current Record fields. + +The length of the record is taken from the Record Size field (offset 0EH) of +the FCB. + +AL returns a code that describes the processing: + +Code + Meaning +_ ________________________________________________________________ + +0 Read completed successfully + +1 End-of-file; no data in the record + +2 Not enough room at the Disk Transfer Address to read one record; + read canceled + +3 End-of-file; a partial record was read and padded to the record + length with zeros + + + + 41 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +read_seq macro fcb + mov dx,offset fcb + mov ah,14H + int 21H + endm + + +Example: + +The following program displays a file named textfile.asc that is on the disk +in drive B; its function is similar to the MS-DOS type command. If a par- +tial record is in the buffer at end-of-file, the routine that displays the par- +tial record displays characters until it encounters an end-of-file mark (ASCII +26, or CONTROL-Z). + +fcb db 2,"TEXTFILEASC" + db 26 dup (?) +buffer db 128 dup (?),"$" +; +begin: set_dta buffer ;see Function 1AH + open fcb ;see Function 0FH +read_line: read_seq fcb ;THIS FUNCTION + cmp al,02H ;DTA too small? + je all_done ;yes + cmp al,00H ;end-of-file? + jg check_more ;yes + display buffer ;see Function 09H + jmp read_line ;get another record +check_more: cmp al,03H ;partial record in buffer? + jne all_done ;no, go home + xor si,si ;set index to 0 +find_eof: cmp buffer[si],26 ;is character EOF? + je all_done ;yes, no more to display + display_char buffer[si] ;see Function 02H + inc si ;bump index + jmp find_eof ;check next character +all_done: close fcb ;see Function 10H + + + +42 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Sequential Write (Function 15H) + + Call: + + AH = 15H + DS:DX + Pointer to opened FCB + + Return: + + AL + 00H = Write completed successfully + 01H = Disk full + 02H = DTA too small + + +Function 15H writes a record to a specified file. DX must contain the +offset (from the segment address in DS) of an opened FCB. This call +writes the record pointed to by the Current Block field (offset 0CH) and +Current Record field (offset 1FH) at the Disk Transfer Address, then incre- +ments the Current Block and Current Record fields. + +The record size is taken from the value of the Record Size field (offset 0EH) +of the FCB. If the record size is less than a sector, the call writes the data +at the Disk Transfer Address to an MS-DOS buffer; MS-DOS writes the +buffer to disk when it contains a full sector of data, when the file is closed, +or when Function 0DH (Reset Disk) is issued. + +AL returns a code that describes the processing: + +Code + Meaning +_ ________________________________________________________________ + +0 Write completed successfully + +1 Disk full; write canceled + +2 Not enough room at the Disk Transfer Address to write one record; + write canceled + + + + 43 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +write_seq macro fcb + mov dx,offset fcb + mov ah,15H + int 21H + endm + + +Example: + +The following program creates a file named dir.tmp on the disk in drive B, +containing the disk number (0=A, 1=B, etc.) and filename from each +directory entry on the disk. + +record_size equ 0EH ;offset of Record Size +; field in FCB +fcb1 db 2,"DIR TMP" + db 26 dup (?) +fcb2 db 2,"???????????" + db 26 dup (?) +buffer db 128 dup (?) +; +begin: set_dta buffer ;see Function 1AH + search_first fcb2 ;see Function 11H + cmp al,0FFH ;directory entry found? + je all_done ;no, no files on disk + create fcb1 ;see Function 16H + mov fcb1[record_size],12 + ;set record size to 12 +write_it: write_seq fcb1 ;THIS FUNCTION + cmp al,0 ;write successful? + jne all_done ;no, go home + search_next fcb2 ;see Function 12H + cmp al,FFH ;directory entry found? + je all_done ;no, go home + jmp write_it ;yes, write the record +all_done: close fcb1 ;see Function 10H + + + +44 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Create File (Function 16H) + + Call: + + AH = 16H + DS:DX + Pointer to unopened FCB + + Return: + + AL + 00H = Empty directory found + FFH = No empty directory available + + +Function 16H creates a file. DX must contain the offset (from the segment +address in DS) of an unopened FCB. MS-DOS searches the directory for +an entry that matches the specified filename or, if there is no matching +entry, an empty entry. + +If MS-DOS finds a matching entry, it opens the file and sets the length to +zero (in other words, if you try to create a file that already exists, MS-DOS +erases it and creates a new, empty file). If MS-DOS doesn't find a matching +entry but does find an empty directory entry, it opens the file and sets its +length to zero. In either case, the call creates the file, and AL returns 0. If +MS-DOS doesn't find a matching entry and there is no empty entry, the +call doesn't create the file, and AL returns FFH. + +You can assign an attribute to the file by using an extended FCB with the +attribute byte set to the appropriate value (see Extended FCB in Section +1.9.1). + +Macro Definition: + + +create macro fcb + mov dx,offset fcb + mov ah,16H + int 21H + endm + + + + 45 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program creates a file named dir.tmp on the disk in drive B, +containing the disk number (0 = A, 1 = B, etc.) and filename from each +directory entry on the disk. + +record_size equ 0EH ;offset of Record Size +; field of FCB +fcb1 db 2,"DIR TMP" + db 26 dup (?) +fcb2 db 2,"???????????" + db 26 dup (?) +buffer db 128 dup (?) +; +begin: set_dta buffer ;see Function 1AH + search_first fcb2 ;see Function 11H + cmp al,0FFH ;directory entry found? + je all_done ;no, no files on disk + create fcb1 ;THIS FUNCTION + mov fcb1[record_size],12 + ;set record size to 12 +write_it: write_seq fcb1 ;see Function 15H + cmp al,0 ;write successful + jne all_done ;no, go home + search_next fcb2 ;see Function 12H + cmp al,FFH ;directory entry found? + je all_done ;no, go home + jmp write_it ;yes, write the record +all_done: close fcb1 ;see Function 10H + + + +46 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Rename File (Function 17H) + + Call: + + AH = 17H + DS:DX + Pointer to modified FCB + + Return: + + AL + 00H = Directory entry found + FFH = No directory entry found + or destination already exists + + +Function 17H changes the name of an existing file. DX must contain the +offset (from the segment address in DS) of an FCB with the drive number +and filename filled in, followed by a second filename at offset 11H. DOS +searches the disk directory for an entry that matches the first filename. +This filename can contain wildcard characters. + +If MS-DOS finds a matching directory entry and there is no directory entry +that matches the second filename, it changes the filename in the directory +entry to match the second filename in the modified FCB. AL then returns +zero. If the second filename does contain a wildcard character, this call +does not change the corresponding characters in the filename of the direc- +tory entry. + +You cannot use this function request to rename a hidden file, a system file, +or a subdirectory. If MS-DOS does not find a matching directory entry or +if it finds an entry for the second filename, AL returns FFH. + +Macro Definition: + + +rename macro fcb,newname + mov dx,offset fcb + mov ah,17H + int 21H + endm + + + + 47 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program prompts for the name of a file and a new name; it +then renames the file. + +fcb db 37 dup (?) +prompt1 db "Filename: $" +prompt2 db "New name: $" +reply db 15 dup(?) +crlf db 0DH,0AH,"$" +; +begin: display prompt1 ;see Function 09H + get_string 15,reply ;see Function 0AH + display crlf ;see Function 09H + parse reply[2],fcb ;see Function 29H + display prompt2 ;see Function 09H + get_string 15,reply ;see Function 0AH + display crlf ;see Function 09H + parse reply[2],fcb[16] + ;see Function 29H + rename fcb ;THIS FUNCTION + + + +48 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Get Current Disk (Function 19H) + + Call: + + AH = 19H + + Return: + + AL + Currently selected drive + (0 = A, 1 = B, etc.) + + + +Comments: + +Function 19H returns the current drive in AL (0=A, 1=B, etc.). + +Macro Definition: + + +current_disk macro + mov ah,19H + int 21H + endm + + +Example: + +The following program displays the default drive in a two-drive system. + +message db "Current disk is $" +crlf db 0DH,OAH,"$" +; +begin: display message ;see Function 09H + current_disk ;THIS FUNCTION + cmp al,00H ;is it disk A? + jne disk_b ;no, it's disk B: + display_char "A" ;see Function 02H + jmp all_done +disk_b: display_char "B" ;see Function 02H +all_done: display crlf ;see Function 09H + + 49 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Set Disk Transfer Address (Function 1AH) + + Call: + + AH = 1AH + DS:DX + Disk Transfer Address + + Return: + + None + + + +Comments: + +Function 1AH sets the Disk Transfer Address. DX must contain the offset +(from the segment address in DS) of the Disk Transfer Address. Disk +transfers cannot wrap around from the end of the segment to the begin- +ning, nor can they overflow into another segment. + +If you do not set the Disk Transfer Address, MS-DOS defaults to offset +80H in the Program Segment Prefix. You can check the current Disk +Transfer Address with Function 2FH (Get Disk Transfer Address). + +Macro Definition: + + +set_dta macro buffer + mov dx,offset buffer + mov ah,1AH + int 21H + endm + + + +50 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program prompts for a letter, converts it to its alphabetic +sequence (A=1, B=2, etc.), then reads and displays the corresponding +record from a file named alphabet.dat that is on the disk in drive B. The +file contains 26 records, each 28 bytes long. + +record_size equ 0EH ;offset of Record Size + ;field of FCB +relative_record equ 21H ;offset of Relative Record +; field of FCB +fcb db 2,"ALPHABETDAT" + db 26 dup (?) +buffer db 28 dup(?),"$" +prompt db "Enter letter: $" +crlf db 0DH,0AH,"$" +; +begin: set_dta buffer ;THIS FUNCTION + open fcb ;see Function 0FH + mov fcb[record_size],28 ;set record size +get_char: display prompt ;see Function 09H + read_kbd_and_echo ;see Function 01H + cmp al,0DH ;just a CR? + je all_done ;yes, go home + sub al,41H ;convert ASCII + ;code to record # + mov fcb[relative_record],al + ;set relative record + display crlf ;see Function 09H + read_ran fcb ;see Function 21H + display buffer ;see Function 09H + display crlf ;see Function 09H + jmp get_char ;get another character +all_done: close fcb ;see Function 10H + + + + 51 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Default Drive Data (Function 1BH) + + Call: + + AH = 1BH + + Return: + + AL + Sectors per cluster + CX + Bytes per sector + DX + Clusters per drive + DS:BX + Pointer to FAT ID byte + + +Function 1BH retrieves data about the disk in the default drive. The data +returns in the following registers: + +Register + Contents +_ ________________________________________________________________ + +AL Number of sectors in a cluster (allocation unit) + +CX Number of bytes in a sector + +DX Number of clusters on the disk + +BX returns the offset (to the segment address in DS) of the first byte of the +File Allocation Table (FAT), which identifies the type of disk in the drive: + +Value + Type of Drive +_ ________________________________________________________________ + +FF Double-sided disk, 8 sectors per track, 40 tracks per side + +FE Single-sided disk, 8 sectors per track, 40 tracks per side + +FD Double-sided disk, 9 sectors per track, 40 tracks per side + +FC Single-sided disk, 9 sectors per track, 40 tracks per side + +F9 Double-sided disk, 15 sectors per track, 40 tracks per side + +F9 Double-sided disk, 9 sectors per track, 80 tracks per side + +F8 Fixed disk + +This call is similar to Function 36H (Get Disk Free Space), except that it + +52 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +returns the address of the FAT ID byte in BX instead of the number of +available clusters. It is also similar to Function 1CH (Get Drive Data), +except that it returns data on the disk in the default drive instead of on +the disk in a specified drive. For a description of how MS-DOS stores data +on a disk, including a description of the File Allocation Table, see Chapter +3, "MS-DOS Technical Information." + +_ ________________________________________________________________ + +Warning + + The FAT ID byte is no longer adequate to identify the type of drive + being used. See Chapter 2, "MS-DOS Device Drivers," for more + details. + +_ ________________________________________________________________ + + +Macro Definition: + + +def_drive_data macro + push ds + mov ah,1BH + int 21H + mov al,byte ptr[bx] + pop ds + endm + + +Example: + +The following program displays a message that tells whether the default +drive is a disk or a fixed disk drive. + +stdout equ 1 +; +msg db "Default drive is " +dskt db "disk." +fixed db "fixed." +crlf db ODH,OAH +; +begin: write_handle stdout,msg,17 ;display message + jc write_error ;routine not shown + def_drive_data ;THIS FUNCTION + cmp byte ptr [bx],0F8H ;check FAT ID byte + jne disk ;it's a disk + write_handle stdout,fixed,6 ;see Function 40H + jc write_error ;see Function 40H + jmp short all_done ;clean up & go home +disk: write_handle stdout,dskt,9 ;see Function 40H +all_done: write_handle stdout,crlf,2 ;see Function 40H + jc write_error ;routine not shown + + + 53 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Drive Data (Function 1CH) + + Call: + + AH = 1CH + DL + Drive (0=default, 1=A, etc.) + + + Return: + + AL + 0FFH if drive number is invalid; + otherwise, sectors per cluster + CX + Bytes per sector + DX + Clusters per drive + DS:BX + Pointer to FAT ID byte + + +Comments: + +Function 1CH retrieves data about the disk in the specified drive. DL must +contain the drive number (0=default, 1=A, etc.). The data returns in the +following registers: + +Register + Contents +_ ________________________________________________________________ + +AL Number of sectors in a cluster (allocation unit) + +CX Number of bytes in a sector + +DX Number of clusters on the disk + +BX returns the offset (to the segment address in DS) of the first byte of the +File Allocation Table (FAT), which identifies the type of disk in the drive: + +Value + Type of Drive +_ ________________________________________________________________ + +FF Double-sided disk, 8 sectors per track, 40 tracks per side + +FE Single-sided disk, 8 sectors per track, 40 tracks per side + +FD Double-sided disk, 9 sectors per track, 40 tracks per side + +FC Single-sided disk, 9 sectors per track, 40 tracks per side + + + +54 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +F9 Double-sided disk, 15 sectors per track, 40 tracks per side + +F9 Double-sided disk, 9 sectors per track, 80 tracks per side + +F8 Fixed disk + +If the drive number in DL is invalid, AL returns 0FFH. + +_ ________________________________________________________________ + +Warning + + The FAT ID byte is no longer adequate to identify the type of drive + being used. See Chapter 2, "MS-DOS Device Drivers" for more details. + +_ ________________________________________________________________ + +This call is similar to Function 36H (Get Disk Free Space), except that it +returns the address of the FAT ID byte in BX instead of the number of +available clusters. It is also similar to Function 1BH (Get Default Drive +Data), except that it returns data on the disk in the drive specified in DL +instead of the disk in the default drive. For a description of how MS-DOS +stores data on a disk, including a description of the File Allocation Table, +see Chapter 3, "MS-DOS Technical Information." + +Macro Definition: + + +drive_data macro drive + push ds + mov dl,drive + mov ah,1BH + int 21H + mov al, byte ptr[bx] + pop ds + endm + + +Example: + +The following program displays a message that tells whether drive B is a +disk or a fixed disk drive. + +stdout equ 1 +: +msg db "Drive B is " +dskt db "disk." +fixed db "fixed." +crlf db ODH,OAH +; +begin: write_handle stdout,msg,11 ;display message + jc write_error ;routine not shown + drive_data 2 ;THIS FUNCTION + + 55 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + cmp byte ptr [bx],0F8H ;check FAT ID byte + jne disk ;it's a disk + write_handle stdout,fixed,6 ;see Function 40H + jc write_error ;routine not shown + jmp all_done ;clean up & go home +disk: write_handle stdout,dskt,9 ;see Function 40H +all_done: write_handle stdout,crlf,2 ;see Function 40H + jc write_error ;routine not shown + + + +56 + +_ _ | | _ _ + + + diff --git a/PROGREF/1C_CALLS.A b/PROGREF/1C_CALLS.A new file mode 100644 index 0000000..7372f82 --- /dev/null +++ b/PROGREF/1C_CALLS.A @@ -0,0 +1,3520 @@ + +_ _ | | _ _ + + + + _ ______________ + + +Random Read (Function 21H) + + Call: + + AH = 21H + DS:DX + Pointer to opened FCB + + Return: + + AL + 0 = Read completed successfully + 1 = End of file, record empty + 2 = DTA too small + 3 = End of file, partial record + + + +Comments: + +Function 21H reads (into the Disk Transfer Address) the record pointed to +by the Relative Record field (offset 20H) of the FCB. DX must contain the +offset (from the segment address in DS) of an opened FCB. The Current +Block field (offset 0CH) and Current Record field (offset 1FH) are set to +agree with the Relative Record field (offset 20H). The record is then loaded +at the Disk Transfer Address. The record length is taken from the Record +Size field (offset 0EH) of the FCB. + +AL returns a code that describes the processing: + +Code + Meaning +_ ________________________________________________________________ + +0 Read completed successfully + +1 End-of-file; no data in the record + +2 Not enough room at the Disk Transfer Address to read one record; + read canceled + +3 End-of-file; a partial record was read and padded to the record + length with zeros + + + + 1 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +read_ran macro fcb + mov dx,offset fcb + mov ah,21H + int 21H + endm + + +Example: + +The following program prompts for a letter, converts it to its alphabetic +sequence (A = 1, B = 2, etc.), then reads and displays the corresponding +record from a file named alphabet.dat that is on the disk in drive B. The +file contains 26 records, each 28 bytes long. + +record_size equ 0EH ;offset of Record Size + ;field of FCB +relative_record equ 21H ;offset of Relative Record +; field of FCB +fcb db 2,"ALPHABETDAT" + db 26 dup (?) +buffer db 28 dup(?),"$" +prompt db "Enter letter: $" +crlf db 0DH,0AH,"$" +; +begin: set_dta buffer ;see Function 1AH + open fcb ;see Function 0FH + mov fcb[record_size],28 ;set record size +get_char: display prompt ;see Function 09H + read_kbd_and_echo ;see Function 01H + cmp al,0DH ;just a CR? + je all_done ;yes, go home + sub al,41H ;convert ASCII code + ;to record # + mov fcb[relative_record],al ;set relative + ;record + display crlf ;see Function 09H + read_ran fcb ;THIS FUNCTION + display buffer ;see Function 09H + display crlf ;see Function 09H + jmp get_char ;get another char. +all_done: close fcb ;see Function 10H + + + +2 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Random Write (Function 22H) + + Call: + + AH = 22H + DS:DX + Pointer to opened FCB + + Return: + + AL + 00H = Write completed successfully + 01H = Disk full + 02H = DTA too small + + + +Comments: + +Function 22H writes (from the Disk Transfer Address) the record pointed +to by the Relative Record field (offset 20H) of the FCB. DX must contain +the offset from the segment address in DS of an opened FCB. The Current +Block (offset 0CH) and Current Record (offset 1FH) fields are set to agree +with the Relative Record field (offset 20H). This record is then written +from the Disk Transfer Address. + +The record length is taken from the Record Size field (offset 0EH) of the +FCB. If the record size is less than a sector, the data at the Disk Transfer +Address is written to a buffer, the buffer is written to disk when it contains +a full sector of data; or when a program closes the file, or when it issues +Function 0DH (Reset Disk). + +AL returns a code that describes the processing: + +Code + Meaning +_ ________________________________________________________________ + +0 Write completed successfully + +1 Disk is full + +2 Not enough room at the Disk Transfer Address to write one record; + write canceled + + + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +write_ran macro fcb + mov dx,offset fcb + mov ah,22H + int 21H + endm + + +Example: + +The following program prompts for a letter, converts it to its alphabetic +sequence (A = 1, B = 2, etc.), then reads and displays the corresponding +record from a file named alphabet.dat that is on the disk in drive B. After +displaying the record, it prompts you to enter a changed record. If you +type a new record, it is written to the file, but if you just press the RETURN +key, the record is not replaced. The file contains 26 records, each 28 bytes +long. + +record_size equ 0EH ;offset of Record Size + ;field of FCB +relative_record equ 21H ;offset of Relative Record +; field of FCB +fcb db 2,"ALPHABETDAT" + db 26 dup (?) +buffer db 28 dup(?),0DH,0AH,"$" +prompt1 db "Enter letter: $" +prompt2 db "New record (RETURN for no change): $" +crlf db 0DH,0AH,"$" +reply db 28 dup (32) +blanks db 26 dup (32) +; +begin: set_dta buffer ;see Function 1AH + open fcb ;see Function 0FH + mov fcb[record_size],28 ;set record size +get_char: display prompt1 ;see Function 09H + read_kbd_and_echo ;see Function 01H + cmp al,0DH ;just a carriage return? + je all_done ;yes, go home + sub al,41H ;convert ASCII + ;code to record # + mov fcb[relative_record],al + ;set relative record + display crlf ;see Function 09H + read_ran fcb ;THIS FUNCTION + display buffer ;see Function 09H + display crlf ;see Function 09H + display prompt2 ;see Function 09H + get_string 27,reply ;see Function 0AH + display crlf ;see Function 09H + cmp reply[1],0 ;was anything typed + ;besides CR? + je get_char ;no + ;get another char. + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + xor bx,bx ;to load a byte + mov bl,reply[1] ;use reply length as + ;counter + move_string blanks,buffer,26 ;see chapter end + move_string reply[2],buffer,bx ;see chapter end + write_ran fcb ;THIS FUNCTION + jmp get_char ;get another character +all_done: close fcb ;see Function 10H + + + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get File Size (Function 23H) + + Call: + + AH = 23H + DS:DX + Pointer to unopened FCB + + Return: + + AL + 00H = Directory entry found + FFH = No directory entry found + + + +Comments: + +Function 23H returns the size of a specified file. DX must contain the +offset (from the segment address in DS) of an unopened FCB. + +If there is a directory entry that matches the specified file, MS-DOS divides +the File Size field (offset 1CH) of the directory entry by the Record Size +field (offset 0EH) of the FCB, puts the result in the Relative Record field +(offset 20H) of the FCB, and returns 00 in AL. + +You must set the Record Size field of the FCB to the correct value before +calling this function. If the Record Size field is not an even divisor of the +File Size field, the value set in the Relative Record field is rounded up, +yielding a value larger than the actual number of records. + +If this call does not find a matching directory, AL returns FFH. + +Macro Definition: + + +file_size macro fcb + mov dx,offset fcb + mov ah,23H + int 21H + endm + + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program prompts for the name of a file, opens the file to fill +in the Record Size field of the FCB, issues a File Size system call, and +displays the record length and number of records. + +fcb db 37 dup (?) +prompt db "File name: $" +msg1 db "Record length: ",0DH,0AH,"$" +msg2 db "Records: ",0DH,0AH,"$" +crlf db 0DH,0AH,"$" +reply db 17 dup(?) +; +begin: display prompt ;see Function 09H + get_string 17,reply ;see Function 0AH + cmp reply[1],0 ;just a CR? + jne get_length ;no, keep going + jmp all_done ;yes, go home +get_length: display crlf ;see Function 09H + parse reply[2],fcb ;see Function 29H + open fcb ;see Function 0FH + file_size fcb ;THIS FUNCTION + mov ax,word ptr fcb[33] ;get record length + convert ax,10,msg2[9] ;see end of chapter + mov ax,word ptr fcb[14] ; get record number + convert ax,10,msg1[15] ;see end of chapter + display msg1 ;see Function 09H + display msg2 ;see Function 09H +all_done: close fcb ;see Function 10H + + + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Set Relative Record (Function 24H) + + Call: + + AH = 24H + DS:DX + Pointer to opened FCB + + Return: + + None + + + +Comments: + +Function 24H sets the Relative Record field (offset 20H) to the file address +specified by the Current Block field (offset 0CH) and Current Record field +(offset 1FH). DX must contain the offset (from the segment address in DS) +of an opened FCB. You use this call to set the file pointer before a Ran- +dom Read or Write (Functions 21H, 22H, 27H, or 28H). + +Macro Definition: + + +set_relative_record macro fcb + mov dx,offset fcb + mov ah,24H + int 21H + endm + + +Example: + +The following program copies a file using the Random Block Read and +Random Block Write system calls. It speeds the copy by setting the record +length equal to the file size and the record count to 1, and by using a +buffer of 32K bytes. It positions the file pointer by setting the Current +Record field (offset 1FH) to 1 and using Function 24H (Set Relative +Record) to make the Relative Record field (offset 20H) point to the same +record that the combination of the Current Block field (offset 0CH) and + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +Current Record field (offset 1FH) points to. + +current_record equ 20H ;offset of Current Record + ;field of FCB +fil_size equ 10H ;offset of File Size +; field of FCB +fcb db 37 dup (?) +filename db 17 dup(?) +prompt1 db "File to copy: $" ;see Function 09H for +prompt2 db "Name of copy: $" ;explanation of $ +crlf db 0DH,0AH,"$" +file_length dw ? +buffer db 32767 dup(?) +; +begin: set_dta buffer ;see Function 1AH + display prompt1 ;see Function 09H + get_string 15,filename ;see Function 0AH + display crlf ;see Function 09H + parse filename[2],fcb ;see Function 29H + open fcb ;see Function 0FH + mov fcb[current_record],0 ;set Current Record + ;field + set_relative_record fcb ;THIS FUNCTION + mov ax,word ptr fcb[fil_size] ;get file size + mov file_length,ax ;save it for + ;ran_block_write + ran_block_read fcb,1,ax ;see Function 27H + display prompt2 ;see Function 09H + get_string 15,filename ;see Function 0AH + display crlf ;see Function 09H + parse filename[2],fcb ;see Function 29H + create fcb ;see Function 16H + mov fcb[current_record],0 ;set Current Record + ;field + set_relative_record fcb ;THIS FUNCTION + mov ax,file_length ;get original file + ran_block_write fcb,1,ax ;see Function 28H + close fcb ;see Function 10H + + + + 9 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Set Interrupt Vector (Function 25H) + + Call: + + AH = 25H + AL + Interrupt number + DS:DX + Pointer to interrupt-handling + routine + + Return: + + None + + + +Comments: + +Function 25H sets the address in the interrupt vector table for the +specified interrupt. + +AL must contain the number of the interrupt. DX must contain the offset +(to the segment address in DS) of the interrupt-handling routine. + +To avoid compatibility problems, programs should never set an interrupt +vector directly and should never use Interrupt 25H to read directly from +memory. To get a vector, use Function 35H (Get Interrupt Vector), and to +set a vector, use Function 25H, unless your program must be compatible +with MS-DOS versions earlier than 2.0. + +Macro Definition: + + +set_vector macro interrupt,handler_start + mov al,interrupt + mov dx,offset handler_start + mov ah,25H + endm + + + +10 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +Because interrupts tend to be machine-specific, no example is shown. + + + 11 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Create New PSP (Function 26H) + + Call: + + AH = 26H + DX + Segment address of new PSP + + Return: + + None + + + +Comments: + +This function request has been superseded. Use Function 4BH (Load and +Execute Program) to run a child process, unless your program must be +compatible with MS-DOS versions earlier than 2.0. + +Function 26H creates a new Program Segment Prefix. DX must contain the +segment address where the new PSP is to be created. + +Macro Definition: + + +create_psp macro seg_addr + mov dx,seg_addr + mov ah,26H + endm + + +Example: + +Because Function 4BH (Load and Execute Program) and 4B03H (Load +Overlay) have superseded this function request, no example is shown. + + +12 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Random Block Read (Function 27H) + + Call: + + AH = 27H + DS:DX + Pointer to opened FCB + CX + Number of blocks to read + + Return: + + AL + 0 = Read completed successfully + 1 = End of file, empty record + 2 = DTA too small + 3 = End of file, partial record + CX + Number of blocks read + + + +Comments: + +Function 27H reads one or more records from a specified file to the Disk +Transfer Address. DX must contain the offset (to the segment address in +DS) of an opened FCB. CX must contain the number of records to read. +Reading starts at the record specified by the Relative Record field (offset +20H); you must set this field with Function 24H (Set Relative Record) +before calling this function. + +DOS calculates the number of bytes to read by multiplying the value in +CX by the Record Size field (offset 0EH) of the FCB. + +CX returns the number of records read. The Current Block field (offset +0CH), Current Record field (offset 1FH), and Relative Record field (offset +20H) are set to address the next record. + +If you call this function with CX=0, no records are read. + +AL returns a code that describes the processing: + +Code + Meaning +_ ________________________________________________________________ + +0 Read completed successfully + + + + 13 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +1 End-of-file; no data in the record + +2 Not enough room at the Disk Transfer Address to read one record; + read canceled + +3 End-of-file; a partial record was read and padded to the record + length with zeros + + +Macro Definition: + + +ran_block_read macro fcb,count,rec_size + mov dx,offset fcb + mov cx,count + mov word ptr fcb[14],rec_size + mov ah,27H + int 21H + endm + + +Example: + +The following program copies a file by using Function 27H (Random Block +Read). This program speeds the copy process by specifying a record count +of 1 and a record length equal to the file size, and by using a buffer of 32K +bytes; the file is read as a single record (compare to the sample program +for Function 28H that specifies a record length of 1 and a record count +equal to the file size). + +current_record equ 20H ;offset of Current Record field +fil_size equ 10H ;offset of File Size field +; +fcb db 37 dup (?) +filename db 17 dup(?) +prompt1 db "File to copy: $" ;see Function 09H for +prompt2 db "Name of copy: $" ;explanation of $ +crlf db 0DH,0AH,"$" +file_length dw ? +buffer db 32767 dup(?) +; +begin: set_dta buffer ;see Function 1AH + display prompt1 ;see Function 09H + get_string 15,filename ;see Function 0AH + display crlf ;see Function 09H + parse filename[2],fcb ;see Function 29H + open fcb ;see Function 0FH + mov fcb[current_record],0 ;set Current + ;Record field + set_relative_record fcb ;see Function 24H + mov ax, word ptr fcb[fil_size] + ;get file size + mov file_length,ax ;save it + ran_block_read fcb,1,ax ;THIS FUNCTION + display prompt2 ;see Function 09H + +14 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + get_string 15,filename ;see Function 0AH + display crlf ;see Function 09H + parse filename[2],fcb ;see Function 29H + create fcb ;see Function 16H + mov fcb[current_record],0;set current + ;Record field + set_relative_record fcb ;see Function 24H + ran_block_write fcb,1,ax ;see Function 28H + close fcb ;see Function 10H + + + + 15 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Random Block Write (Function 28H) + + Call: + + AH = 28H + DS:DX + Pointer to opened FCB + CX + Number of blocks to write + (0 = set File Size field) + + Return: + + AL + 00H = Write completed successfully + 01H = Disk full + 02H = End of segment + CX + Number of blocks written + + + +Comments: + +Function 28H writes one or more records to a specified file from the Disk +Transfer Address. DX must contain the offset (to the segment address in +DS) of an opened FCB; CX must contain either the number of records to +write or 0. + +If CX is not 0, the specified number of records is written to the file, start- +ing at the record specified in the Relative Record field (offset 20H) of the +FCB. If CX is 0, no records are written, but MS-DOS sets the File Size +field (offset 1CH) of the directory entry to the value in the Relative Record +field (offset 20H) of the FCB. To satisfy this new file size, disk allocation +units are allocated or released, as required. + +MS-DOS calculates the number of bytes to write by multiplying the value +in CX by the Record Size field (offset 0EH) of the FCB. CX returns the +number of records written; the Current Block field (offset 0CH), Current +Record field (offset 1FH), and Relative Record (offset 20H) field are set to +address the next record. + +AL returns a code that describes the processing: + +Code + Meaning +_ ________________________________________________________________ + + + +16 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +0 Write completed successfully + +1 Disk full. No records written + +2 Not enough room at the Disk Transfer Address to write one record; + write canceled + + +Macro Definition: + + +ran_block_write macro fcb,count,rec_size + mov dx,offset fcb + mov cx,count + mov word ptr fcb[14],rec_size + mov ah,28H + int 21H + endm + + +Example: + +The following program copies a file using Function 27H (Random Block +Read) and Function 28H (Random Block Write). This program speeds the +copy process by specifying a record count equal to the file size and a record +length of 1, and by using a buffer of 32K bytes; the file is copied quickly +with one disk access each to read and write (compare to the sample pro- +gram of Function 27H, which specifies a record count of 1 and a record +length equal to file size). + +current_record equ 20H ;offset of Current Record field +fil_size equ 10H ;offset of File Size field +; +fcb db 37 dup (?) +filename db 17 dup(?) +prompt1 db "File to copy: $" ;see Function 09H for +prompt2 db "Name of copy: $" ;explanation of $ +crlf db 0DH,0AH,"$" +num_recs dw ? +buffer db 32767 dup(?) +; +begin: set_dta buffer ;see Function 1AH + display prompt1 ;see Function 09H + get_string 15,filename ;see Function 0AH + display crlf ;see Function 09H + parse filename[2],fcb ;see Function 29H + open fcb ;see Function 0FH + mov fcb[current_record],0;set Current + Record field + set_relative_record fcb ;see Function 24H + mov ax, word ptr fcb[fil_size] + ;get file size + mov num_recs,ax ;save it + ran_block_read fcb,num_recs,1 ;THIS FUNCTION + display prompt2 ;see Function 09H + + 17 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + get_string 15,filename ;see Function 0AH + display crlf ;see Function 09H + parse filename[2],fcb ;see Function 29H + create fcb ;see Function 16H + mov fcb[current_record],0 ;set Current + ;Record field + set_relative_record fcb ;see Function 24H + ran_block_write fcb,num_recs,1 ;see Function 28H + close fcb ;see Function 10H + + + +18 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Parse File Name (Function 29H) + + Call: + + AH = 29H + AL + Controls parsing (see text) + DS:SI + Pointer to string to parse + ES:DI + Pointer to buffer for unopened FCB + + Return: + + AL + 00H = No wildcard characters + 01H = Wildcard characters used + FFH = Drive letter invalid + DS:SI + Pointer to first byte past + string that was parsed + ES:DI + Pointer to unopened FCB + + +Comments: + +Function 29H parses a string for a filename of the form +drive:filename.extension. SI must contain the offset (to the segment +address in DS) of the string to parse; DI must contain the offset (to the +segment address in ES) of an area of memory large enough to hold an uno- +pened FCB. If the string contains a valid filename, this call creates a +corresponding unopened FCB at ES:DI. + +AL controls the parsing. Bits 4-7 must be 0; bits 0-3 have the following +meaning: + + +Table 0.1 + +Bit values for Function 29H + +_ _________________________________________________________________________ + +Bit Value Meaning + +_ _________________________________________________________________________ + + 0 0 Stop parsing if a file separator is encountered. + + 1 Ignore leading separators. + + 1 0 + + Set the drive number in the FCB to 0 (current drive) if the string + does not contain a drive number. + + + + 19 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + 1 + + Leave the drive number in the FCB unchanged if the string does + not contain a drive number. + + 2 0 + + Set the filename in the FCB to eight blanks if the string does not + contain a filename. + + 1 + + Leave the filename in the FCB unchanged if the string does not + contain a filename. + + 3 1 + + Leave the extension in the FCB unchanged if the string does not + contain an extension. + + 0 + + Set the extension in the FCB to three blanks if the string does not + contain an extension. + +_ _________________________________________________________________________ + +If the string contains a filename or extension that includes an asterisk (*), +all remaining characters in the name or extension are set to question +marks (?). + +Filename separators: + + : ; . , = + / " [ ] \ < > | space tab + +Filename terminators include all the filename separators, plus any control +character. A filename cannot contain a filename terminator, since if the +call encounters one, parsing stops. + +If the string contains a valid filename: + + o AL returns 1 if the filename or extension contains a wildcard char- + acter (* or ?); AL returns 0 if neither the filename nor extension + contains a wildcard character. + + o DS:SI points to the first character following the parsed string. + + o ES:DI points to the first byte of the unopened FCB. + +If the drive letter is invalid, AL returns FFH. If the string does not contain +a valid filename, ES:DI+1 points to a blank. + +Macro Definition: + + +parse macro string,fcb + mov si,offset string + mov di,offset fcb + push es + push ds + pop es + mov al,0FH ;bits 0-3 on + mov ah,29H + int 21H + +20 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + pop es + endm + + +Example: + +The following program verifies the existence of the file named in reply to +the prompt. + +fcb db 37 dup (?) +prompt db "Filename: $" +reply db 17 dup(?) +yes db "File exists",0DH,0AH,"$" +no db "File does not exist",0DH,0AH,"$" + crlf db 0DH,0AH,"$" +; +begin: display prompt ;see Function 09H + get_string 15,reply ;see Function 0AH + parse reply[2],fcb ;THIS FUNCTION + display crlf ;see Function 09H + search_first fcb ;see Function 11H + cmp al,0FFH ;dir. entry found? + je not_there ;no + display yes ;see Function 09H + jmp return +not_there: display no + + + + 21 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Date (Function 2AH) + + Call: + + AH = 2AH + + Return: + + CX + Year (1980-2099) + DH + Month (1-12) + DL + Day (1-31) + AL + Day of week (0=Sun., 6=Sat.) + + + +Comments: + +Function 2AH returns the current date set in the operating system as +binary numbers in CX and DX: + +Register + Contents +_ ________________________________________________________________ + +CX Year (1980-2099) + +DH Month (1=January, 2=February, etc.) + +DL Day of month (1-31) + +AL Day of week (0=Sunday, 1=Monday, etc.) + + +Macro Definition: + + +get_date macro + mov ah,2AH + int 21H + endm + + + +22 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program gets the date, increments the day, increments the +month or year, if necessary, and sets the new date. + +month db 31,28,31,30,31,30,31,31,30,31,30,31 +; +begin: get_date ;THIS FUNCTION + inc dl ;increment day + xor bx,bx ;so BL can be used as index + mov bl,dh ;move month to index register + dec bx ;month table starts with 0 + cmp dl,month[bx] ;past end of month? + jle month_ok ;no, set new date + mov dl,1 ;yes, set day to 1 + inc dh ;and increment month + cmp dh,12 ;past end of year? + jle month_ok ;no, set new date + mov dh,1 ;yes, set month to 1 + inc cx ;increment year +month_ok: set_date cx,dh,dl ;see Function 2AH + + + + 23 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Set Date (Function 2BH) + + Call: + + AH = 2BH + CX + Year (1980-2099) + DH + Month (1-12) + DL + Day (1-31) + + Return: + + AL + 00H = Date was valid + FFH = Date was invalid + + + +Comments: + +Function 2BH sets the date in the operating system (and in the CMOS +clock, if one exists). Registers CX and DX must contain a valid date in +binary: + +Register + Contents +_ ________________________________________________________________ + +CX Year (1980-2099) + +DH Month (1=January, 2=February, etc.) + +DL Day of month (1-31) + +If the date is valid, the call sets it and AL returns 0. If the date is not +valid, the function aborts and AL returns FFH. + +Macro Definition: + + +set_date macro year,month,day + mov cx,year + mov dh,month + mov dl,day + mov ah,2BH + int 21H + endm + + +24 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program gets the date, increments the day, increments the +month or year, if necessary, and sets the new date. + +month db 31,28,31,30,31,30,31,31,30,31,30,31 +; +begin: get_date ;see Function 2AH + inc dl ;increment day + xor bx,bx ;so BL can be used as index + mov bl,dh ;move month to index register + dec bx ;month table starts with 0 + cmp dl,month[bx] ;past end of month? + jle month_ok ;no, set the new date + mov dl,1 ;yes, set day to 1 + inc dh ;and increment month + cmp dh,12 ;past end of year? + jle month_ok ;no, set the new date + mov dh,1 ;yes, set the month to 1 + inc cx ;increment year +month_ok: set_date cx,dh,dl ;THIS FUNCTION + + + + 25 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Time (Function 2CH) + + Call: + + AH = 2CH + + Return: + + CH + Hour (0-23) + CL + Minutes (0-59) + DH + Seconds (0-59) + DL + Hundredths (0-99) + + + +Comments: + +Function 2CH returns the current time set in the operating system (and +sets the CMOS clock, if one exists) as binary numbers in CX and DX: + +Register + Contents +_ ________________________________________________________________ + +CH Hour (0-23) + +CL Minutes (0-59) + +DH Seconds (0-59) + +DL Hundredths of a second (0-99) + +Depending on how your hardware keeps time, some of these fields may be +irrelevant. As an example, many CMOS clock chips do not resolve more +than seconds. In such a case, the value in DL will probably always be 0. + +Macro Definition: + + +get_time macro + mov ah,2CH + int 21H + endm + + + +26 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program displays the time continuously until you press any +key. + +time db "00:00:00.00",0DH,"$" +; +begin: get_time ;THIS FUNCTION + byte_to_dec ch,time ;see end of chapter + byte_to_dec cl,time[3] ;see end of chapter + byte_to_dec dh,time[6] ;see end of chapter + byte_to_dec dl,time[9] ;see end of chapter + display time ;see Function 09H + check_kbd_status ;see Function 0BH + cmp al,0FFH ;has a key been pressed? + je return ;yes, terminate + jmp begin ;no, display time + + + + 27 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Set Time (Function 2DH) + + Call: + + AH = 2DH + CH + Hour (0-23) + CL + Minutes (0-59) + DH + Seconds (0-59) + DL + Hundredths (0-99) + + Return: + + AL + 00H = Time was valid + FFH = Time was invalid + + + +Comments: + +Function 2DH sets the time in the operating system. Registers CX and DX +must contain a valid time in binary: + +Register + Contents +_ ________________________________________________________________ + +CH Hour (0-23) + +CL Minutes (0-59) + +DH Seconds (0-59) + +DL Hundredths of a second (0-99) + +Depending on how your hardware keeps time, some of these fields may be +irrelevant. As an example, many CMOS clock chips do not resolve more +than seconds. In such a case, the value in DL will not be relevant. + +If the time is valid, the call sets it and AL returns 0. If the time is not +valid, the function aborts and AL returns FFH. + + +28 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +set_time macro hour,minutes,seconds,hundredths + mov ch,hour + mov cl,minutes + mov dh,seconds + mov dl,hundredths + mov ah,2DH + int 21H + endm + + +Example: + +The following program sets the system clock to 0 and displays the time +continuously. When you type a character, the display freezes; when you +type another character, the clock is reset to 0 and the display starts again. + +time db "00:00:00.00",0DH,0AH,"$" +; +begin: set_time 0,0,0,0 ;THIS FUNCTION +read_clock: get_time ;see Function 2CH + byte_to_dec ch,time ;see end of chapter + byte_to_dec cl,time[3] ;see end of chapter + byte_to_dec dh,time[6] ;see end of chapter + byte_to_dec dl,time[9] ;see end of chapter + display time ;see Function 09H + dir_console_io 0FFH ;see Function 06H + cmp al,00H ;was a char. typed? + jne stop ;yes, stop the timer + jmp read_clock ;no keep timer on +stop: read_kbd ;see Function 08H + jmp begin ;keep displaying time + + + + 29 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Set/Reset Verify Flag (Function 2EH) + + Call: + + AH = 2EH + AL + 0 = Do not verify + 1 = Verify + + Return: + + None + + + +Comments: + +Function 2EH tells MS-DOS whether to verify each disk write. If AL is 1, +verify is on; if AL is 0, verify is off. MS-DOS checks this flag each time it +writes to a disk. + +The flag is normally off; you may wish to turn it on when writing critical +data to disk. Because disk errors are rare and verification slows writing, +you will probably want to leave it off at other times. You can check the +setting with Function 54H (Get Verify State). + +Macro Definition: + + +verify macro switch + mov al,switch + mov ah,2EH + int 21H + endm + + + +30 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program copies the contents of a single-sided disk in drive A +to the disk in drive B, verifying each write. It uses a buffer of 32K bytes. + +on equ 1 +off equ 0 +; +prompt db "Source in A, target in B",0DH,0AH + db "Any key to start. $" +first dw 0 +buffer db 60 dup (512 dup(?)) ;60 sectors +; +begin: display prompt ;see Function 09H + read_kbd ;see Function 08H + verify on ;THIS FUNCTION + mov cx,6 ;copy 60 sectors + ;6 times +copy: push cx ;save counter + abs_disk_read 0,buffer,60,first ;see Int 25H + abs_disk_write 1,buffer,64,first ;see Int 26H + add first,60 ;do next 60 sectors + pop cx ;restore counter + loop copy ;do it again + verify off ;THIS FUNCTION + + + + 31 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Disk Transfer Address (Function 2FH) + + Call: + + AH = 2FH + + Return: + + ES:BX + Pointer to Disk Transfer Address + + + +Comments: + +Function 2FH returns the segment address of the current Disk Transfer +Address in ES and the offset in BX. + +Macro Definition: + + +get_dta macro + mov ah,2fH + int 21H + endm + + +Example: + +The following program displays the current Disk Transfer Address in the +form: segment:offset. + +message db "DTA -- : ",0DH,0AH,"$" +sixteen db 10H +temp db 2 dup (?) +; +begin: get_dta ;THIS FUNCTION + mov word ptr temp,ex ;To access each byte + convert temp[1],sixteen,message[07H] ;See end of + convert temp,sixteen,message[09H] ;chapter for + +32 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + convert bh,sixteen,message[0CH] ;description + convert bl,sixteen,message[0EH] ;of CONVERT + display message ;See Function 09H + + + + 33 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get MS-DOS Version Number (Function 30H) + + Call: + + AH = 30H + + Return: + + AL + Major version number + AH + Minor version number + BH + OEM serial number + BL:CX + 24-bit user (serial) number + + + +Comments: + +Function 30H returns the MS-DOS version number. AL returns the major +version number; AH returns the minor version number. (For example, +MS-DOS 3.0 returns 3 in AL and 0 in AH.) + +If AL returns 0, the MS-DOS version is earlier than 2.0. + +Macro Definition: + + +get_version macro + mov ah,30H + int 21H + endm + + +Example: + +The following program displays the MS-DOS version if it is 1.28 or +greater. + +message db "MS-DOS Version . ",0DH,0AH,"$" +ten db 0AH ;For CONVERT +; +begin: get_version ;THIS FUNCTION + cmp al,0 ;1.28 or later? + +34 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + jng return ;No, go home + convert al,ten,message[0FH] ;See end of chapter + convert ah,ten,message[12H] ;for description + display message ;See Function 9 + + + + 35 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Keep Process (Function 31H) + + Call: + + AH = 31H + AL + Return code + DX + Memory size, in paragraphs + + Return: + + None + + + +Comments: + +Function 31H makes a program remain resident after it terminates. You +can use it to install device-specific interrupt handlers. But unlike Interrupt +27H (Terminate But Stay Resident), this function request allows more +than 64K bytes to remain resident and does not require CS to contain the +segment address of the Program Segment Prefix. You should use Function +31H to install a resident program unless your program must be compatible +with MS-DOS versions earlier than 2.0. + +DX must contain the number of paragraphs of memory required by the +program (one paragraph = 16 bytes). AL contains an exit code. + +Be careful when using this function with .exe programs. The value in DX +must be the total size to remain resident, not just the size of the code seg- +ment which is to remain resident. A typical error is to forget about the +100H-byte program-header-prefix and give a value in DX that is 10H too +small. + +MS-DOS terminates the current process and tries to set the memory allo- +cation to the number of paragraphs in DX. No other allocation blocks +belonging to the process are released. + + + +36 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +By using Function 4DH (Get Return Code of Child Process), the parent +process can retrieve the process's exit code from AL. (You can test this +exit code by using the if command with errorlevel.) + +Macro Definition: + + +keep_process macro return_code,last_byte + mov al,return_code + mov dx,offset last_byte + mov cl,4 + shr dx,cl + inc dx + mov ah,31H + int 21H + endm + + +Example: + +Because the most common use of this call is to install a machine-specific +routine, an example is not shown. The macro definition, however, shows +the calling syntax. + + + 37 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +CONTROL-C Check (Function 33H) + + Call: + + AH = 33H + AL + 0 = Get state + 1 = Set state + DL (if AL=1) + 0 = Off + 1 = On + + Return: + + DL (if AL=0) + 0 = Off + 1 = On + AL + FFH = error (AL was neither 0 nor 1 + when call was made) + + +Comments: + +Function 33H gets or sets the state of CONTROL-C (or CONTROL-BREAK for +IBM compatibles) checking in MS-DOS. AL must contain a code that +specifies the requested action: + +Code + Meaning +_ ________________________________________________________________ + +0 Current state of CONTROL-C checking in DL + +1 Set state of CONTROL-C checking to the value in DL + +If AL is 0, DL returns the current state (0=off, 1=on). If AL is 1, the value +in DL specifies the state to be set (0=off, 1=on). If AL is neither 0 nor 1, +AL returns FFH and the state of CONTROL-C checking is unaffected. + +MS-DOS normally checks for CONTROL-C only when carrying out certain +function requests in the 01H through 0CH group (see the description of +specific calls for details). When CONTROL-C checking is on, MS-DOS checks +for CONTROL-C when carrying out any function request. For example, if +CONTROL-C checking is off, all disk I/O proceeds without interruption, but +if it is on, the CONTROL-C interrupt is issued at the function request that +initiates the disk operation. + +_ ________________________________________________________________ + +Note + +38 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + Programs that use Function 06H (Direct Console I/O) or 07H (Direct + Console Input) to read CONTROL-C as data must ensure that the + CONTROL-C checking is off. + +_ ________________________________________________________________ + + +Macro Definition: + + +ctrl_c_ck macro action,state + mov al,action + mov dl,state + mov ah,33H + int 21H + endm + + +Example: + +The following program displays a message that tells whether CONTROL-C +checking is on or off: + +message db "CONTROL-C checking ","$" +on db "on","$",0DH,0AH,"$" +off db "off","$",0DH,0AH,"$" +; +begin: display message ;See Function 09H + ctrl_c_ck 0 ;THIS FUNCTION + cmp dl,0 ;Is checking off? + jg ck_on ;No + display off ;See Function 09H + jmp return ;Go home +ck_on: display on ;See Function 09H + + + + 39 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Interrupt Vector (Function 35H) + + Call: + + AH = 35H + AL + Interrupt number + + Return: + + ES:BX + Pointer to interrupt routine + + + +Comments: + +Function 35H gets the address from the interrupt-vector table for the +specified interrupt. AL must contain the number of an interrupt. + +ES returns the segment address of the interrupt handler; BX returns the +offset. + +To avoid compatibility problems, programs should never read an interrupt +vector directly from memory, nor set an interrupt vector by writing it into +memory. Use this function request to get a vector and Function 25H (Set +Interrupt Vector) to set a vector, unless your program must be compatible +with MS-DOS versions earlier than 2.0. + +Macro Definition: + + +get_vector macro interrupt + mov al,interrupt + mov ah,35H + int 21H + endm + + + +40 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program displays the segment and offset (CS:IP) for the +handler for Interrupt 25H (Absolute Disk Read). + +message db "Interrupt 25H -- CS:0000 IP:0000" + db 0DH,0AH,"$" +vec_seg db 2 dup (?) +vec_off db 2 dup (?) +; +begin: push es ;save ES + get_vector 25H ;THIS FUNCTION + mov ax,es ;INT25H segment in AX + pop es ;save ES + convert ax,16,message[20] ;see end of chapter + convert bx,16,message[28] ;see end of chapter + display message ;See Function 9 + + + + 41 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Disk Free Space (Function 36H) + + Call: + + AH = 36H + DL + Drive (0=default, 1=A, etc.) + + Return: + + AX + 0FFFFH if drive number is invalid; + otherwise, sectors per cluster + BX + Available clusters + CX + Bytes per sector + DX + Clusters per drive + + + +Comments: + +Function 36H returns the number of clusters available on the disk in the +specified drive, and the information necessary to calculate the number of +bytes available on the disk. DL must contain a drive number (0=default, +1=A, etc.). If the drive number is valid, MS-DOS returns the information +in the following registers: + +Register + Contents +_ ________________________________________________________________ + +AX Sectors per cluster + +BX Available clusters + +CX Bytes per sector + +DX Total clusters + +If the drive number is invalid, AX returns 0FFFFH. + +This call supersedes Functions 1BH and 1CH in earlier MS-DOS versions. + + +42 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +get_disk_space macro drive + mov dl,drive + mov ah,36H + int 21H + endm + + +Example: + +The following program displays the space information for the disk in drive +B. + +message db " clusters on drive B.",0DH,0AH ;DX + db " clusters available.",0DH,0AH ;BX + db " sectors per cluster.",0DH,0AH ;AX + db " bytes per sector,",0DH,0AH,"$" ;CX +; +begin: get_disk_space 2 ;THIS FUNCTION + convert ax,10,message[55] ;see end of chapter + convert bx,10,message[28] ;see end of chapter + convert cx,10,message[83] ;see end of chapter + convert dx,10,message ;see end of chapter + display message ;See Function 09H + + + + 43 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Country Data (Function 38H) + + Call: + + AH = 38H + AL + 00H = Current country + 1-0FEH = Country code + 0FFH = BX contains country code + BX (if AL = 0FFH) + Country code 255 or higher + DS:DX + Pointer to 32-byte memory area + + Return: + + Carry set: + AX + 2 = Invalid country code + Carry not set: + BX + Country code + + +Comments: + +Function 38H gets the country-dependent information that MS-DOS uses +to control the keyboard and display, or it sets the currently defined coun- +try (to set the country code, see the next function request description, Set +Country Data). To get the information, DX must contain the offset (from +the segment address in DS) of a 32-byte memory area to which the country +data returns. AL specifies the country code: + +Value in AL + Meaning +_ ________________________________________________________________ + +00H Retrieve information about the country currently set. + +1 to 0FEH Retrieve information about the country identified by this + code. + +0FFH Retrieve information about the country identified by the + code in BX. + +BX must contain the country code if the code is 255 or greater. The coun- +try code is usually the international telephone-prefix code. + + + +44 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +The country-dependent information returns in the following form: + + Offset +Hex Decimal Field Name Length in bytes + +_ ________________________________________________________________ + +00H 0 Date format 2 (word) +02H 2 Currency symbol 5 (ASCIZ string) +07H 7 Thousands separator 2 (ASCIZ string) +09H 9 Decimal separator 2 (ASCIZ string) +0BH 11 Date separator 2 (ASCIZ string) +0DH 13 Time separator 2 (ASCIZ string) +0FH 15 Bit field 1 +10H 16 Currency places 1 +11H 17 Time format 1 +12H 18 Case-map call address 4 (DWORD) +16H 22 Data-list separator 2 (ASCIZ string) +18H 24 Reserved 10 + +_ ________________________________________________________________ + +Date Format: + +0 = USA (month/day/year) +1 = Europe (day/month/year) +2 = Japan (year/month/day) + + +Bit Field: + +Bit Value Meaning + +_ ________________________________________________________________ + +0 0 Currency symbol precedes amount + + 1 Currency symbol follows amount + +1 0 No space between symbol and amount + + 1 One space between symbol and amount + +_ ________________________________________________________________ + +All other bits are undefined. + +Time format: + +0 = 12-hour clock +1 = 24-hour clock + +Currency Places: + + + + 45 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +Specifies the number of places that appear after the decimal point on +currency amounts. + +Case-Mapping Call Address: + +Specifies the segment and offset of a FAR procedure that performs +country-specific lowercase-to-uppercase mapping on character values from +80H to 0FFH. You call it with the character to be mapped in AL. If there +is an uppercase code for the character, it is returned in AL; if there is not, +or if you call it with a value less than 80H in AL, AL returns unchanged. +AL and the FLAGS are the only altered registers. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +2 Invalid country code (no table for it). + + +Macro Definition: + + +get_country macro country,buffer + local gc_01 + mov dx,offset buffer + mov ax,country + cmp ax,OFFH + jl gc_01 + mov al,OFFh + mov bx,country +gc_01: mov ah,38h + int 21H + endm + + +Example: + +The following program displays the time and date in the format appropri- +ate to the current country code, and the number 999,999 and 99/100 as a +currency amount with the proper currency symbol and separators. + +time db " : : ",5 dup (20H),"$" +date db " / / ",5 dup (20H),"$" +number db "999?999?99",0DH,0AH,"$" +data_area db 32 dup (?) +; +begin: get_country 0,data_area ;THIS FUNCTION + get_time ;See Function 2CH + byte_to_dec ch,time ;See end of chapter + byte_to_dec cl,time[03H] ;for description of + byte_to_dec dh,time[06H] ;CONVERT macro + get_date ;See Function 2AH + +46 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + sub cx,1900 ;Want last 2 digits + byte_to_dec cl,date[06H] ;See end of chapter + cmp word ptr data_area,0 ;Check country code + jne not_usa ;It's not USA + byte_to_dec dh,date ;See end of chapter + byte_to_dec dl,date[03H] ;See end of chapter + jmp all_done ;Display data +not_usa: byte_to_dec dl,date ;See end of chapter + byte_to_dec dh,date[03H] ;See end of chapter +all_done: mov al,data_area[07H] ;Thousand separator + mov number[03H],al ;Put in NUMBER + mov al,data_area[09H] ;Decimal separator + mov number[07H],al ;Put in AMOUNT + display time ;See Function 09H + display date ;See Function 09H + display_char data_area[02H] ;See Function 02H + display number ;See Function 09H + + + + 47 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Set Country Data (Function 38H) + + Call: + + AH = 38H + DX = -1 (0FFFFH) + AL + Country code less than 255, or + 0FFH if the country code is in BX + BX (if AL=0FFH) + Country code 255 or higher + + Return: + + Carry set: + AX + 2 = Invalid country code + Carry not set: + No error + + + +Comments: + +Function 38H sets the country code that MS-DOS uses to control the key- +board and the display, or it retrieves the country-dependent information +(to get the country data, see the previous function request description, Get +Country Data). To set the information, DX must contain 0FFFFH. AL +must contain either the country code, if it is less than 255, or 255 to indi- +cate that the country code is in BX. If AL contains 0FFH, BX must con- +tain the country code. + +The country code is usually the international telephone prefix-code. See +"Get Country Data" for a description of the country data and how it is +used. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +2 Invalid country code (no table for it). + + + +48 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +set_country macro country + local sc_01 + mov dx,0FFFFH + mov ax,country + cmp ax,0FFH + jl sc_01 + mov bx,country + mov al,0ffh +sc_01: mov ah,38H + int 21H + endm + + +Example: + +The following program sets the country code to the United Kingdom (44). + +uk equ 44 +; +begin: set_country uk ;THIS FUNCTION + jc error ;routine not shown + + + + 49 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Create Directory (Function 39H) + + Call: + + AH = 39H + DS:DX + Pointer to pathname + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 5 = Access denied + Carry not set: + No error + + + +Comments: + +Function 39H creates a new subdirectory. DX must contain the offset +(from the segment address in DS) of an ASCIZ string that specifies the path- +name of the new subdirectory. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +2 File not found + +3 Path not found + +5 No room in the parent directory, a file with the same name exists + in the current directory, or the path specifies a device + + +Macro Definition: + + +make_dir macro path + mov dx,offset path + mov ah,39H + int 21H + endm + + +50 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program adds a subdirectory named new_dir to the root +directory on the disk in drive B and changes the current directory to +new_dir. The program then changes the current directory back to the ori- +ginal directory and then deletes new_dir. It displays the current directory +after each step to confirm the changes. + +old_path db "b: +new_path db "b:\new_dir",0 +buffer db "b: +; +begin: get_dir 2,old_path[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz old_path ;See end of chapter + make_dir new_path ;THIS FUNCTION + jc error_make ;Routine not shown + change_dir new_path ;See Function 3BH + jc error_change ;Routine not shown + get_dir 2,buffer[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz buffer ;See end of chapter + change_dir old_path ;See Function 3BH + jc error_change ;Routine not shown + rem_dir new_path ;See Function 3AH + jc error_rem ;Routine not shown + get_dir 2,buffer[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz buffer ;See end of chapter + + + + 51 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Remove Directory (Function 3AH) + + Call: + + AH = 3AH + DS:DX + Pointer to pathname + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 5 = Access denied + 16 = Current directory + Carry not set: + No error + + + +Comments: + +Function 3AH deletes a subdirectory. DX must contain the offset (from the +segment address in DS) of an ASCIZ string that specifies the pathname of +the subdirectory you want to delete. + +The subdirectory must not contain any files. You cannot erase the current +directory. If there is an error, the carry flag (CF) is set and the error code +returns in AX: + +Code + Meaning +_ ________________________________________________________________ + +2 File not found + +3 Path not found + +5 Directory not empty, or path doesn't specify a directory, or it + specifies the root directory, or it is invalid + +16 Path specifies current directory + + + +52 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +rem_dir macro path + mov dx,offset path + mov ah,3AH + int 21H + endm + + +Example: + +The following program adds a subdirectory named new_dir to the root +directory on the disk in drive B and changes the current directory to +new_dir. The program then changes the current directory back to the ori- +ginal directory and deletes new_dir. It displays the current directory after +each step to confirm the changes. + +old_path db "b: +new_path db "b:\new_dir",0 +buffer db "b: +; +begin: get_dir 2,old_path[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz old_path ;See end of chapter + make_dir new_path ;See Function 39H + jc error_make ;Routine not shown + change_dir new_path ;See Function 3BH + jc error_change ;Routine not shown + get_dir 2,buffer[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz buffer ;See end of chapter + change_dir old_path ;See Function 3BH + jc error_change ;Routine not shown + rem_dir new_path ;THIS FUNCTION + jc error_rem ;Routine not shown + get_dir 2,buffer[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz buffer ;See end of chapter + + + + 53 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Change Current Directory (Function 3BH) + + Call: + + AH = 3BH + DS:DX + Pointer to pathname + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + Carry not set: + No error + + + +Comments: + +Function 3BH changes the current directory. DX must contain the offset +(from the segment address in DS) of an ASCIZ string that specifies the path- +name of the new current directory. + +The directory string is limited to 64 characters. + +If any member of the path doesn't exist, the path is unchanged. If there is +an error, the carry flag (CF) is set and the error code returns in AX: + +Code + Meaning +_ ________________________________________________________________ + +2 File not found + +3 Path either doesn't exist or it specifies a file instead of a directory + + +Macro Definition: + + +change_dir macro path + mov dx,offset path + mov ah,3BH + int 21H + endm + + + +54 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program adds a subdirectory named new_dir to the root +directory that is on the disk in drive B and changes the current directory +to new_dir. The program then changes the current directory back to the +original directory and deletes new_dir. It displays the current directory +after each step to confirm the changes. + +old_path db "b: +new_path db "b:\new_dir",0 +buffer db "b: +; +begin: get_dir 2,old_path[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz old_path ;See end of chapter + make_dir new_path ;See Function 39H + jc error_make ;Routine not shown + change_dir new_path ;THIS FUNCTION + jc error_change ;Routine not shown + get_dir 2,buffer[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz buffer ;See end of chapter + change_dir old_path ;See Function 3BH + jc error_change ;Routine not shown + rem_dir new_path ;See Function 3AH + jc error_rem ;Routine not shown + get_dir 2,buffer[03H] ;See Function 47H + jc error_get ;Routine not shown + display_asciz buffer ;See end of chapter + + + + 55 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Create Handle (Function 3CH) + + Call: + + AH = 3CH + DS:DX + Pointer to pathname + CX + File attribute + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 4 = Too many open files + 5 = Access denied + Carry not set: + AX + Handle + + +Comments: + +Function 3CH creates a file and assigns it the first available handle. DX +must contain the offset (from the segment address in DS) of an ASCIZ string +that specifies the pathname of the file to be created. CX must contain the +attribute to be assigned to the file, as described under "File Attributes" +earlier in this chapter. + +If the specified file does not exist, this function creates it. But if the file +already exists, it is truncated to a length of 0. Function 3CH then assigns +the attribute in CX to the file and opens it for read/write. AX returns the +file handle. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +2 File not found + +3 Path is invalid + +4 Too many open files (no handle available) + +5 Directory is full, a directory with the same name exists, or a file + with the same name exists with more restrictive attributes + + +56 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +create_handle macro path,attrib + mov dx,offset path + mov cx,attrib + mov ah,3CH + int 21H + endm + + +Example: + +The following program creates a file named dir.tmp, containing the name +and extension of each file in the current directory, on the disk in drive B. + +srch_file db "b:*.*",0 +tmp_file db "b:dir.tmp",0 +buffer db 43 dup (?) +handle dw ? +; +begin: set_dta buffer ;See Function 1AH + find_first_file srch_file,16H ;See Function 4EH + cmp ax,12H ;Directory empty? + je all_done ;Yes, go home + create_handle tmp_file,0 ;THIS FUNCTION + jc error ;Routine not shown + mov handle,ax ;Save handle +write_it: write_handle handle,buffer[1EH],12 ;Function 40H + find_next_file ;See Function 4FH + cmp ax,12H ;Another entry? + je all_done ;No, go home + jmp write_it ;Yes, write record +all_done: close_handle handle ;See Function 3EH + + + + 57 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Open Handle (Function 3DH) + + Call: + + AH = 3DH + AL + Access code (see text) + DS:DX + Pointer to pathname + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 4 = Too many open files + 5 = Access denied + 12 = Invalid access + Carry not set: + No error + + +Comments: + +Function 3DH opens any file, including hidden and system files, for input +or output. DX contains the offset (from the segment address in DS) of an +ASCIZ string that specifies the pathname of the file to be opened. AL con- +tains a code that specifies how the file is to be opened. This code is +described later under "Controlling Access to the File." + +If there is no error, AX returns the file handle. MS-DOS sets the read/write +pointer to the first byte of the file. + + +58 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Controlling Access to the File + +The value in AL is made up of three parts that specify whether the file is +to be opened for read, write, or both (access code); what access other +processes have to the file (sharing mode); and whether a child process +inherits the file (inherit bit). + + |---|-----------|---------------| +Bit | 7 | 6 5 4 | 3 2 1 0 | + |---|---|---|---|---|---|---|---| + + \/ \________/ \____________/ + | | | + | | |--------> Access code + | | + | |-----------------------> Sharing mode + | + |-------------------------------> Inherit bit + + +Inherit Bit The high-order bit (bit 7) specifies whether the file is inherited +by a child process created with Function 4BH (Load and Execute Pro- +gram). If the bit is 0, the child process inherits the file; if the bit is 1, it +doesn't. + + + 59 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Sharing Mode + +The sharing mode bits (bits 4-6) specify what access, if any, other +processes have to the open file. It can have the following values: + + +Table 0.2 + +Sharing Mode Bit Values + +_ _________________________________________________________________________ + +Bits 4-6 Sharing Mode Description + +_ _________________________________________________________________________ + +000 Compatibility + + On a given machine, any process can open the file + any number of times with this mode. Fails if the file + has been opened with any of the other sharing + modes. + +001 Deny both + + Fails if the file has been opened in compatibility + mode or for read or write access, even if by the + current process. + +010 Deny write + + Fails if the file has been opened in compatibility + mode or for write access by any other process. + +011 Deny read + + Fails if the file has been opened in compatibility + mode or for read access by any other process. + +100 Deny none + + Fails if the file has been opened in compatibility + mode by any other process. + +_ _________________________________________________________________________ + + + +60 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Access Code + +The access code (bits 0-3) specifies how the file is to be used. It can have +the following values: + + +Table 0.3 + +Access Code Bit Values + +_ _________________________________________________________________________ + + Access +Bits 0-3 Allowed Description + +_ _________________________________________________________________________ + +0000 Read + + Fails if the file has been opened in deny read or deny both + sharing mode. + +0001 Write + + Fails if the file has been opened in deny write or deny both + sharing mode. + +0010 Both + + Fails if the file has been opened in deny read, deny write, or + deny both sharing mode. + +_ _________________________________________________________________________ + +If there is an error, the carry flag (CF) is set and the error code is returned +in AX: + +Code + Meaning +_ ________________________________________________________________ + +2 Specified file is invalid or doesn't exist + +3 Specified path is invalid or doesn't exist + +4 No handles are available in the current process or the internal sys- + tem tables are full + +5 Program attempted to open a directory or VolumeID, or tried to + open a read-only file for writing + +12 Access code (bits 0-3 of AL) not 0, 1, or 2 + +If this system call fails because of a file-sharing error, MS-DOS issues +Interrupt 24H with error code 2 (Drive Not Ready). A subsequent Function +59H (Get Extended Error) returns the extended error code that specifies a +sharing violation. + +When opening a file, it is important to inform MS-DOS of any operations +that other processes may perform on this file (sharing mode). The default +(compatibility mode) denies all other processes access to the file, unless +they also attempt to open the file in compatibility mode. + +The following table shows the effect of opening a file with compatibility +mode set: + + + + 61 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +Type of File Opening Read-Only File Not Read-Only + +_ ________________________________________________________________ + +First open for read, write, Succeeds Succeeds +or both by machine/process +"N" + +Subsequent opens by machine Succeeds Succeeds +or process +"N" + +An open by another machine Succeeds Fails +or process + +_ ________________________________________________________________ + +Files may be read-only with the MS-DOS attrib command or by a read-only +share over the network. + +It may be all right for other processes to continue to read the file while +your process is operating on it. In this case, you should specify "Deny +Write," which inhibits other processes from writing to your files but allows +them to read from these files. + +Similarly, it is important for you to specify what operations your process +will perform ("Access" mode). If another process has the file open with +any sharing mode other than "Deny" mode, then the default mode +("Read/write") causes the open request to fail. If you only want to read +the file, your open request succeeds unless all other processes have +specified "Deny" mode or "Deny write." + +Macro Definition: + + +open_handle macro path,access + mov dx, offset path + mov al, access + mov ah, 3DH + int 21H + endm + + +Example: + +The following program prints a file named textfile.asc that is on the disk in +drive B. + +file db "b:textfile.asc",0 +buffer db ? +handle dw ? +; +begin: open_handle file,0 ;THIS FUNCTION + mov handle,ax ;Save handle +read_char: read_handle handle,buffer,1 ;Read 1 character + +62 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + jc error_read ;Routine not shown + cmp ax,0 ;End of file? + je return ;Yes, go home + print_char buffer ;See Function 05H + jmp read_char ;Read another + + + + 63 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Close Handle (Function 3EH) + + Call: + + AH = 3EH + BX + Handle + + Return: + + Carry set: + AX + 6 = Invalid handle + Carry not set: + No error + + + +Comments: + +Function 3EH closes a file opened with Function 3DH (Open Handle) or +3CH (Create Handle). BX must contain the handle of the open file that you +want to close. + +If there is no error, MS-DOS closes the file and flushes all internal buffers. +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +6 Handle not open or invalid + + +Macro Definition: + + +close_handle macro handle + mov bx,handle + mov ah,3EH + int 21H + endm + + + +64 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program creates a file named dir.tmp, containing the +filename and extension of each file in the current directory, in the current +directory on the disk in drive B. + +srch_file db "b:*.*",0 +tmp_file db "b:dir.tmp",0 +buffer db 43 dup (?) +handle dw ? +; +begin: set_dta buffer ;See Function 1AH + find_first_file srch_file,16H ;See Function 4EH + cmp ax,12H ;Directory empty? + je all_done ;Yes, go home + create_handle tmp_file,0 ;See Function 3CH + jc error_create ;Routine not shown + mov handle,ax ;Save handle +write_it: write_handle handle,buffer[1EH],12 ;See Function + jc error_write ;40H + find_next_file ;See Function 4FH + cmp ax,12H ;Another entry? + je all_done ;No, go home + jmp write_it ;Yes, write record +all_done: close_handle handle ;See Function 3EH + jc error_close ;Routine not shown + + + + 65 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Read Handle (Function 3FH) + + Call: + + AH = 3FH + BX + Handle + CX + Bytes to read + DS:DX + Pointer to buffer + + Return: + + Carry set: + AX + 5 = Access denied + 6 = Invalid handle + Carry not set: + AX + Bytes read + + +Comments: + +Function 3FH reads from the file or device associated with the specified +handle. BX must contain the handle. CX must contain the number of +bytes to be read. DX must contain the offset (to the segment address in +DS) of the buffer. + +If there is no error, AX returns the number of bytes read; if you attempt to +read starting at end of file, AX returns 0. The number of bytes specified in +CX is not necessarily transferred to the buffer; if you use this call to read +from the keyboard, for example, it reads only up to the first carriage- +return. + +If you use this function request to read from standard input, you can +redirect the input. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +5 Handle not open for reading + +6 Handle not open or invalid + + + +66 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +read_handle macro handle,buffer,bytes + mov bx,handle + mov dx,offset buffer + mov cx,bytes + mov ah,3FH + int 21H + endm + + +Example: + +The following program displays a file named textfile.asc that is on the disk +in drive B. + +filename db "b:\textfile.asc",0 +buffer db 129 dup (?) +handle dw ? +; +begin: open_handle filename,0 ;See Function 3DH + jc error_open ;Routine not shown + mov handle,ax ;Save handle +read_file: read_handle buffer,file_handle,128 + jc error_open ;Routine not shown + cmp ax,0 ;End of file? + je return ;Yes, go home + mov bx,ax ;# of bytes read + mov buffer[bx],"$" ;Make a string + display buffer ;See Function 09H + jmp read_file ;Read more + + + + 67 + +_ _ | | _ _ + + + diff --git a/PROGREF/1D_CALLS.A b/PROGREF/1D_CALLS.A new file mode 100644 index 0000000..c4eaeb9 --- /dev/null +++ b/PROGREF/1D_CALLS.A @@ -0,0 +1,3710 @@ + +_ _ | | _ _ + + + + _ ______________ + + +Write Handle (Function 40H) + + Call: + + AH = 40H + BX + Handle + CX + Bytes to write + DS:DX + Pointer to buffer + + Return: + + Carry set: + AX + 5 = Access denied + 6 = Invalid handle + Carry not set: + AX + Bytes written + + +Comments: + +Function 40H writes to the file or device associated with the specified han- +dle. BX must contain the handle. CX must contain the number of bytes to +be written. DX must contain the offset (to the segment address in DS) of +the data to be written. + +If you set CX to zero, the file will be truncated at the current position of +the file pointer. MS-DOS will not perform the write if the handle is read- +only. + +If there is no error, AX returns the number of bytes written. Be sure to +check AX after performing a write. If its value is less than the number in +CX when the call was made, it indicates an error, even though the carry +flag isn't set. If AX contains 0, and if the target is a disk file, the disk is +full. + +If you use this function request to write to standard output, you can +redirect the output. If you call this request with CX=0, the file size is set +to the value of the read/write pointer. To satisfy the new file size, alloca- +tion units are allocated or released, as required. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + + 1 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + Meaning +_ ________________________________________________________________ + +5 Handle not open for writing + +6 Handle not open or invalid + + +Macro Definition: + + +write_handle macro handle,buffer,bytes + mov bx,handle + mov dx,offset buffer + mov cx,bytes + mov ah,40H + int 21H + endm + + +Example: + +The following program creates a file named dir.tmp, containing the +filename and extension of each file in the current directory, in the current +directory on the disk in drive B. + +srch_file db "b:*.*",0 +tmp_file db "b:dir.tmp",0 +buffer db 43 dup (?) +handle dw ? +; +begin: set_dta buffer ;See Function 1AH + find_first_file srch_file,16H ;Check directory + cmp ax,12H ;Directory empty? + je return ;Yes, go home + create_handle tmp_file,0 ;See Function 3CH + jc error_create ;Routine not shown + mov handle,ax ;Save handle +write_it: write_handle handle,buffer[1EH],12 ;THIS FUNCTION + jc error_write ;Routine not shown + find_next_file ;Check directory + cmp ax,12H ;Another entry? + je all_done ;No, go home + jmp write_it ;Yes, write record +all_done: close_handle handle ;See Function 3EH + jc error_close ;Routine not shown + + + +2 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Delete Directory Entry [Unlink] (Function 41H) + + Call: + + AH = 41H + DS:DX + Pointer to pathname + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 5 = Access denied + Carry not set: + No error + + + +Comments: + +Function 41H erases a file by deleting its directory entry. DX must con- +tain the offset (from the segment address in DS) of an ASCIZ string that +specifies the pathname of the file that you want to delete. You cannot use +wildcard characters. + +If the file exists and is not read-only, the call deletes it. If there is an error, +the call sets the carry flag (CF) and the error code returns in AX: + +Code + Meaning +_ ________________________________________________________________ + +2 File doesn't exist, or specifies a directory + +3 Path is invalid + +5 File is read-only + +To delete a file with the read-only attribute, first change its attribute to 0 +with Function 43H (Get/Set File Attribute). + + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +delete_entry macro path + mov dx,offset path + mov ah,41H + int 21H + endm + + +Example: + +The following program deletes all files, dated before December 31, 1986, +from the disk in drive B. + +year db 1986 +month db 12 +day db 31 +files db ? +message db "NO FILES DELETED.",0DH,0AH,"$" +path db "b:*.*", 0 +buffer db 43 dup (?) +; +begin: set_dta buffer ;See Function 1AH + select_disk "B" ;See Function 0EH + find_first_file path,0 ;See Function 4EH + jnc compare ;got one + jmp all_done ;no match, go home +compare: convert_date buffer[-1] ;See end of chapter + cmp cx,year ;After 1986? + jg next ;Yes, don't delete + cmp dl,month ;After December? + jg next ;Yes, don't delete + cmp dh,day ;31st or after? + jge next ;Yes, don't delete + delete_entry buffer[1EH] ;THIS FUNCTION + jc error_delete ;Routine not shown + inc files ;Bump file counter +next: find_next_file ;Check directory + jnc compare ;Go home if done +how_many: cmp files,0 ;Was directory empty? + je all_done ;Yes, go home + convert files,10,message ;See end of chapter +all_done: display message ;See Function 09H + select_disk "A" ;See Function 0EH + + + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Move File Pointer (Function 42H) + + Call: + + AH = 42H + AL + Method of moving + BX + Handle + CX:DX + Distance in bytes (offset) + + Return: + + Carry set: + AX + 1 = Invalid function + 6 = Invalid handle + Carry not set: + DX:AX + New read/write pointer location + + +Comments: + +Function 42H moves the read/write pointer of the file associated with the +specified handle. BX must contain the handle. CX and DX must contain a +32-bit offset (CX contains the most significant byte). AL must contain a +code that specifies how to move the pointer: + +Code + Cursor Moved to +_ ________________________________________________________________ + +0 Beginning of file plus the offset + +1 Current pointer location plus the offset + +2 End of file plus the offset + +DX and AX return the new location of the read/write pointer (a 32-bit +integer; DX contains the most significant byte). You can determine the +length of a file by setting CX:DX to 0, AL to 2, and calling this function. +DX:AX returns the offset of the byte following the last byte in the file (size +of the file in bytes). + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +1 AL not 0, 1, or 2 + +6 Handle not open + + +Macro Definition: + + +move_ptr macro handle,high,low,method + mov bx,handle + mov cx,high + mov dx,low + mov al,method + mov ah,42H + int 21H + endm + + +Example: + +The following program prompts for a letter, converts it to its alphabetic +sequence (A=1, B=2, etc.), then reads and displays the corresponding +record from the file named alphabet.dat that is in the current directory on +the disk in drive B. The file contains 26 records, each 28 bytes long. + +file db "b:alphabet.dat",0 +buffer db 28 dup (?),"$" +prompt db "Enter letter: $" +crlf db 0DH,0AH,"$" +handle db ? +record_length dw 28 +; +begin: open_handle file,0 ;See Function 3DH + jc error_open ;Routine not shown + mov handle,ax ;Save handle +get_char: display prompt ;See Function 09H + read_kbd_and_echo ;See Function 01H + sub al,41h ;Convert to sequence + mul byte ptr record_length ;Calculate offset + move_ptr handle,0,ax,0 ;THIS FUNCTION + jc error_move ;Routine not shown + read_handle handle,buffer,record_length + jc error_read ;Routine not shown + cmp ax,0 ;End of file? + je return ;Yes, go home + display crlf ;See Function 09H + display buffer ;See Function 09H + display crlf ;See Function 09H + jmp get_char ;Get another character + + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Get/Set File Attributes (Function 43H) + + Call: + + AH = 43H + AL + 0 = Get attributes + 1 = Set attributes + CX (if AL=1) + Attributes to be set + DS:DX + Pointer to pathname + + Return: + + Carry set: + AX + 1 = Invalid function + 2 = File not found + 3 = Path not found + 5 = Access denied + Carry not set: + CX + Attribute byte (if AL=0) + + +Comments: + +Function 43H gets or sets the attributes of a file. DX must contain the +offset (from the segment address in DS) of an ASCIZ string that specifies the +pathname of a file. AL must specify whether to get or set the attribute +(0=get, 1=set). + +If AL is 0 (get the attribute), the attribute byte returns in CX. If AL is 1 +(set the attribute), CX must contain the attributes to be set. The attri- +butes are described under "File Attributes" earlier in this chapter. + +You cannot change the VolumeID bit (08H) or the Subdirectory bit (10H) +of the attribute byte with this function. + + + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 AL not 0 or 1 + +2 File doesn't exist + +3 Path invalid + +5 Attribute in CX cannot be changed (Subdirectory or VolumeID). + + +Macro Definition: + + +change_attr macro path,action,attrib + mov dx,offset path + mov al,action + mov cx,attrib + mov ah,43H + int 21H + endm + + +Example: + +The following program displays the attributes assigned to the file named +report.asm that is in the current directory on the disk in drive B. + +header db 15 dup (20h),"Read-",0DH,0AH + db "Filename Only Hidden " + db "System Volume Sub-Dir Archive" + db 0DH,0AH,0DH,0AH,"$" +path db "b:report.asm",3 dup (0),"$" +attribute dw ? +blanks db 9 dup (20h),"$" +; +begin: change_attr path,0,0 ;THIS FUNCTION + jc error_mode ;Routine not shown + mov attribute,cx ;Save attribute byte + display header ;See Function 09H + display path ;See Function 09H + mov cx,6 ;Check 6 bits (0-5) + mov bx,1 ;Start with bit 0 +chk_bit: test attribute,bx ;Is the bit set? + jz no_attr ;No + display_char "X" ;See Function 02H + jmp short next_bit ;Done with this bit +no_attr: display_char 20h ;See Function 02H +next_bit: display blanks ;See Function 09H + shl bx,1 ;Move to next bit + loop chk_bit ;Check it + + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +IOCtl Data (Function 44H, Codes 0 and 1) + + Call: + + AH = 44H + AL + 0 = Get device data + 1 = Set device data + BX + Handle + DX + Device data (see text) + + Return: + + Carry set: + AX + 1 = Invalid function + 6 = Invalid handle + Carry not set: + DX + Device data + + +Comments: + +Function 44H, Codes 0 and 1, either gets or sets the data MS-DOS uses to +control the device. AL must contain 0 to get the data or 1 to set it. BX +must contain the handle. If AL is 1, DH must contain 0. + +The device-data word is specified or returned in DX. If bit 7 of the data is +1, the handle refers to a device and the other bits have the following mean- +ings: + + + 9 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +Table 0.1 + +MS-DOS Data Bit Values + +_ _________________________________________________________________________ + +Bit Value Meaning + +_ _________________________________________________________________________ + +0 1 Console input device +1 1 Console output device +2 1 Null device +3 1 Clock device +4 1 Reserved +5 1 Don't check for control characters + 0 Check for control characters +6 0 End of file on input +8-10 Reserved +11 1 Device understands open/close +12 Reserved +13 1 Device supports output until busy +14 1 + + Device can process control strings sent with Function 44H, Codes + 2 and 3 (IOCtl character); bit can be read only, but not set +15 Reserved + +_ _________________________________________________________________________ + +You must set the reserved bits to zero. + +The control characters referred to in the description of bit 5 are +CONTROL-C, CONTROL-P, CONTROL-S, and CONTROL-Z. To read these charac- +ters as data, instead of as control characters, you must set bit 5 and use +either Function 33H, CONTROL-C Check, or the MS-DOS break command +to turn off CONTROL-C checking. + +If bit 7 of DX is 0, the handle refers to a file and the other bits have the +following meanings: + +Bit Value Meaning + +_ ________________________________________________________________ + +0-5 Drive number (0=A, 1=B, etc.) +6 0 The file has been written +8-15 Reserved + +_ ________________________________________________________________ + + + +10 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 AL not 0 or 1, or AL is 1 but DH is not 0 + +6 Handle in BX not open or is invalid + + +Macro Definition: + + +ioctl_data macro code,handle + mov bx,handle + mov al,code + mov ah,44H + int 21H + endm + + +Example: + +The following program gets the device data for standard output, sets the +bit that specifies not to check for control characters (bit 5), and then +clears the bit. + +get equ 0 +set equ 1 +stdout equ 1 +; +begin: ioctl_data get,stdout ;THIS FUNCTION + jc error ;routine not shown + mov dh,0 ;clear DH + or dl,20H ;set bit 5 + ioctl_data set,stdout ;THIS FUNCTION + jc error ;routine not shown +; +; +; + ioctl_data get,stdout ;THIS FUNCTION + jc error ;routine not shown + mov dh,0 ;clear DH + and dl,0DFH ;clear bit 5 + ioctl_data set,stdout ;THIS FUNCTION +; +; +; + + + + 11 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +IOCtl Character (Function 44H, Codes 2 and 3) + + Call: + + AH = 44H + AL + 2 = Send control data + 3 = Receive control data + BX + Handle + CX + Bytes to read or write + DS:DX + Pointer to buffer + + Return: + + Carry set: + AX + 1 = Invalid function + 6 = Invalid handle + Carry not set: + AX + Bytes transferred + + +Comments: + +Function 44H, Codes 2 and 3, sends or receives control data to or from a +character device. AL must contain 2 to send data or 3 to receive. BX must +contain the handle of a character device, such as a printer or serial port. +CX must contain the number of bytes to be read or written. DX must con- +tain the offset (to the segment address in DS) of the data buffer. + +AX returns the number of bytes transferred. The device driver must sup- +port the IOCtl interface. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 AL not 2 or 3, or device cannot perform the specified function + +6 Handle in BX not open or doesn't exist + + + +12 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +ioctl_char macro code,handle,buffer + mov bx,handle + mov dx,offset buffer + mov al,code + mov ah,44H + int 21H + endm + + +Example: + +No general example is applicable, since processing of IOCtl control data +depends on the device being used, as well as the device driver. + + + 13 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +IOCtl Block (Function 44H, Codes 4 and 5) + + Call: + + AH = 44H + AL + 4 = Send control data + 5 = Receive control data + BL + Drive number (0=default, 1=A, etc.) + CX + Bytes to read or write + DS:DX + Pointer to buffer + + Return: + + Carry set: + AX + 1 = Invalid function + 5 = Invalid drive + Carry not set: + AX + Bytes transferred + + +Comments: + +Function 44H, Codes 4 and 5, sends or receives control data to or from a +block device. AL must contain 4 to send data or 5 to receive. BL must con- +tain the drive number (0=default, 1=A, etc.). CX must contain the +number of bytes to be read or written. DX must contain the offset (to the +segment address in DS) of the data buffer. + +AX returns the number of bytes transferred. The device driver must sup- +port the IOCtl interface. To determine whether it does, use Function 44H, +Code 0, to get the device data, and test bit 14; if the bit is set, the driver +supports IOCtl. + + + +14 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 AL not 4 or 5, or device cannot perform the specified function + +5 Number in BL not a valid drive number + + +Macro Definition: + + +ioctl_status macro code,drive,buffer + mov bl,drive + mov dx,offset buffer + mov al,code + mov ah,44H + int 21H + endm + + +Example: + +No general example is applicable, since processing of IOCtl control data +depends on the device being used, as well as the device driver. + + + 15 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +IOCtl Status (Function 44H, Codes 6 and 7) + + Call: + + AH = 44H + AL + 6 = Check input status + 7 = Check output status + BX + Handle + + Return: + + Carry set: + AX + 1 = Invalid function + 5 = Access denied + 6 = Invalid handle + 13 = Invalid data + Carry not set: + AL + 00H = Not ready + 0FFH= Ready + + +Comments: + +Function 44H, Codes 6 and 7, checks whether the file or device associated +with a handle is ready. AL must contain 6 to check whether the handle is +ready for input or 7 to check whether the handle is ready for output. BX +must contain the handle. + +AL returns the status: + + Meaning for Meaning for Meaning for +Value Device Input File Output File + +_ ________________________________________________________________ + +00H Not ready Pointer is at EOF Ready +0FFH Ready Ready Ready + +_ ________________________________________________________________ + +An output file always returns ready, even if the disk is full. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + + +16 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +1 AL not 6 or 7 + +5 Access denied + +6 Number in BX not a valid, open handle + +13 Invalid data + + +Macro Definition: + + +ioctl_status macro code,handle + mov bx,handle + mov al,code + mov ah,44H + int 21H + endm + + +Example: + +The following program displays a message that tells whether the file asso- +ciated with handle 6 is ready for input or whether it is at end-of-file. + +stdout equ 1 +; +message db "File is " +ready db "ready." +at_eof db "at EOF." +crlf db ODH,OAH +; +begin: write_handle stdout,message,8 ;display message + jc write_error ;routine not shown + ioctl_status 6 ;THIS FUNCTION + jc ioctl_error ;routine not shown + cmp al,0 ;check status code + jne not_eof ;file is ready + write_handle stdout,at_eof,7 ;see Function 40H + jc write_error ;routine not shown + jmp all_done ;clean up & go home +not_eof: write_handle stdout,ready,6 ;see Function 40H +all_done: write_handle stdout,crlf,2 ;see Function 40H + jc write_error ;routine not shown + + + + 17 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +IOCtl Is Changeable (Function 44H, Code 08H) + + Call: + + AH = 44H + AL = 08H + BL + Drive number (0=default, 1=A, etc.) + + Return: + + Carry set: + AX + 1 = Invalid function + 15 = Invalid drive + Carry not set: + AX + 0 = Changeable + 1 = Not changeable + + + +Comments: + +Function 44H, Code 08H, checks whether a drive contains a removable or +nonremovable disk. BL must contain the drive number (0=default, 1=A, +etc.). AX returns 0 if the disk can be changed, 1 if it cannot. + +This call lets a program determine whether to issue a message to change +disks. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX. + +Code + Meaning +_ ________________________________________________________________ + +1 Device does not support this call + +15 Number in BL not a valid drive number + +When the call returns error 1 (because the driver doesn't support it), the +caller asssumes that the driver cannot be changed. + + +18 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +ioctl_change macro drive + mov bl, drive + mov al, 08H + mov ah, 44H + int 21H + endm + + +Example: + +The following program checks whether the current drive contains a remov- +able disk. If not, processing continues; if so, the program prompts the user +to replace the disk in the current drive. + +stdout equ 1 +; +message db "Please replace disk in drive " +drives db "ABCD" +crlf db 0DH,0AH +; +begin: ioctl_change 0 ;THIS FUNCTION + jc ioctl_error ;routine not shown + cmp ax,0 ;current drive changeable? + jne continue ;no, continue processing + write_handle stdout,message,29 ;see Function 40H + jc write_error ;routine not shown + current_disk ;see Function 19H + xor bx,bx ;clear index + mov bl,al ;get current drive + display_char drives[bx] ;see Function 02H + write_handle stdout,crlf,2 ;see Function 40H + jc write_error ;routine not shown +continue: +; (Further processing here) + + + + 19 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +IOCtl Is Redirected Block (Function 44H, Code +09H) + + Call: + + AH = 44H + AL = 09H + BL + Drive number (0=default, 1=A, etc.) + + Return: + + Carry set: + AX + 1 = Invalid function code + 15 = Invalid drive number + Carry not set: + DX + Device-attribute bits + + + +Comments: + +Function 44H, Code 09H, checks whether a drive letter refers to a drive on +a Microsoft Networks workstation (local) or is redirected to a server +(remote). BL must contain the drive number (0=default, 1=A, etc.). + +If the block device is local, DX returns the attribute word from the device +header. If the block device is remote, only bit 12 (1000H) is set; the other +bits are 0 (reserved). + +An application program should not test bit 12, because applications +should not make distinctions between local and remote files (or devices). +Programs should be written so that they will be independent of the loca- +tion of a device that has been removed. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 File sharing must be loaded to use this system call + +15 Number in BL not a valid drive number + + + +20 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +ioctl_rblock macro drive + mov bl, drive + mov al, 09H + mov ah, 44H + int 21H + endm + + +Example: + +The following program checks whether drive B is local or remote and +displays the appropriate message. + +stdout equ 1 +; +message db "Drive B: is " +loc db "local." +rem db "remote." +crlf db 0DH,0AH +; +begin: write_handle stdout,message,12 ;display message + jc write_error ;routine not shown + ioctl_rblock 2 ;THIS FUNCTION + jc ioctl_error ;routine not shown + test dx,1000h ;bit 12 set? + jnz not_loc ;yes, it's remote + write_handle stdout,loc,6 ;see Function 40H + jc write_error ;routine not shown + jmp done +not_loc: write_handle stdout,rem,7 ;see Function 40H + jc write_error ;routine not shown +done: write_handle stdout,crlf,2 ;see Function 40H + jc write_error ;routine not shown + + + + 21 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +IOCtl Is Redirected Handle (Function 44H, +Code 0AH) + + Call: + + AH = 44H + AL = 0AH + BX + Handle + + Return: + + Carry set: + AX + 1 = Invalid function code + 6 = Invalid handle + Carry not set: + DX + IOCtl bit field + + + +Comments: + +Function 44H, Code 0AH, checks whether a handle refers to a file or a dev- +ice on a Microsoft Networks workstation (local) or is redirected to a server +(remote). BX must contain the file handle. DX returns the IOCtl bit field; +bit 15 is set if the handle refers to a remote file or device. + +An application program should not test bit 15, because applications +should not make distinctions between local and remote files (or devices). +Programs should be written so that they will be independent of the loca- +tion of a device that has been removed. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 Network must be loaded to use this system call + +6 Handle in BX not a valid, open handle + + + +22 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +ioctl_rhandle macro handle + mov bx, handle + mov al, 0AH + mov ah, 44H + int 21H + endm + + +Example: + +The following program checks whether handle 5 refers to a local or remote +file or a device and displays the appropriate message. + +stdout equ 1 +; +message db "Handle 5 is " +loc db "local." +rem db "remote." +crlf db 0DH,0AH +; +begin: write_handle stdout,message,12;display message + jc write_error ;routine not shown + ioctl_rhandle 5 ;THIS FUNCTION + jc ioctl_error ;routine not shown + test dx,8000h ;bit 15 set? + jnz not_loc ;yes, it's remote + write_handle stdout,loc,6 ;see Function 40H + jc write_error ;routine not shown + jmp done +not_loc: write_handle stdout,rem,7 ;see Function 40H + jc write_error ;routine not shown +done: write_handle stdout,crlf,2 ;see Function 40H + jc write_error ;routine not shown + + + + 23 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +IOCtl Retry (Function 44H, Code 0BH) + + Call: + + AH = 44H + AL = 0BH + DX + Number of retries + CX + Wait time + + Return: + + Carry set: + AX + 1 = Invalid function code + Carry not set: + No error + + + +Comments: + +Function 44H, Code 0BH, specifies how many times MS-DOS should retry +a disk operation that fails because of a file-sharing violation. DX must +contain the number of retries. CX controls the pause between retries. + +MS-DOS retries this type of disk operation three times, unless you use this +system call to specify a different number. After the specified number of +retries, MS-DOS issues Interrupt 24H (Critical-Error-Handler Address) for +the requesting process. + +The effect of the delay parameter in CX is machine-dependent because it +specifies how many times MS-DOS should execute an empty loop. The +actual time varies, depending on the processor and clock speed. You can +determine the effect on your machine by using debug. Set the number of +retries to 1 and then time several values of CX. + + + +24 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 File sharing must be loaded to use this system call + + +Macro Definition: + + +ioctl_retry macro retries, wait + mov dx, retries + mov cx, wait + mov al, 0BH + mov ah, 44H + int 21H + endm + + +Example: + +The following program sets the number of sharing retries to 10 and +specifies a delay of 1000 between retries. + +begin: ioctl_retry 10,1000 ;THIS FUNCTION + jc error ;routine not shown + + + + 25 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Generic IOCtl (for Handles) (Function 44H, +Code 0CH) + + Call: + + AH = 44H + AL = 0CH + BX + Handle + CH = 05H + Category code (printer device) + CL + Function (minor) code + DS:DX + Pointer to data buffer + + Return: + + Carry set: + AX + 1 = Invalid function code + Carry not set: + No error + + +Comments: + +This call loads and selects code pages for devices on a per-device basis. It +also sets or gets the output iteration count for a printer that supports +"PRINT 'TIL BUSY." + +The category code may be one of the following: + +Code + Meaning +_ ________________________________________________________________ + +00 Unknown device + +01 Serial printer + +03 Console device + +05 Parallel printer + +The function code may be one of the following: + +Code + Meaning +_ ________________________________________________________________ + + + +26 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +45H Sets iteration count for printer + +4AH Select code page + +4CH Start prepare list + +4DH End prepare list + +65H Gets iteration count for printer + +6AH Query code page selected + +6BH Query code page prepare list + +_ ________________________________________________________________ + +Note + + DS:DX points to a word that contains the new value for the total + number of output iterations performed before proceeding. Thus, + DS:DX points to a word that contains the character iteration count for + the "PRINT 'TIL BUSY" loop. This is the number of times the device + driver will wait for the device to signal "ready" before acknowledging + "Device busy." + +_ ________________________________________________________________ + + +Macro Definition: + + +ioctl_handles macro handle,function,category,buffer + mov ch,05H + mov cl,function + mov dx,offset buffer + mov bx,handle + mov ah,44H + mov al,0CH + int 21H + endm + + + + 27 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Generic IOCtl (for Devices) (Function 44H, +Code 0DH) + + Call: + + AH = 44H + AL = 0DH + BL + Drive number + (0 = default, 1 = A, etc.) + CH = 08H + Category (major) code + CL + Function (minor) code + DS:DX + Pointer to parameter block -1 + + Return: + + Carry set: + AX + 1 = Invalid function code + 2 = Invalid drive + Carry not set: + No error + + +Comments: + +The function code may be one of the following: + +Code + Meaning +_ ________________________________________________________________ + +40 Set device parameters + +41 Write track on logical device + +42 Format track on logical device + +60 Get device parameters + +61 Read track on logical device + +62 Verify track on logical device + +_ ________________________________________________________________ + +Note + + You must issue "Set Device Parameters" before you can read, write, + format, or verify a logical drive. + +28 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +_ ________________________________________________________________ + +You should use the following procedure when you want to read, write, for- +mat, or verify a logical drive: + + o Save drive parameters using "Get Device Parameters;" + + o Set desired drive parameters using "Set Device Parameters;" + + o Perform the I/O operation; + + o Restore the original drive parameters using "Set Device Parame- + ters." + + +Set Device Parameters (Function 44 0DH, CL=40H) + +When CL=40H, the parameter block has the following field format: + + -------------------------------------- + | BYTE Special Functions | + |------------------------------------| + | BYTE Device Type | + |------------------------------------| + | WORD Device Attributes | + |------------------------------------| + | WORD Number of Cylinders | + |------------------------------------| + | BYTE Media Type | + |------------------------------------| + | Device BPB | + |------------------------------------| + | Track Layout | + -------------------------------------- + +These fields have the following meanings: + +Special Functions + +Bit Value Meaning + +_ ________________________________________________________________ + + 0 0 + + The Device BPB (BIOS Parameter Block) field contains + the new default BPB for this device. If a previous "Set + Parameter Device" call set this bit, Build BPB returns + the actual media BPB; otherwise, it returns the default + BPB for the device. + + 1 + + All subsequent Build BPB requests return the device + BPB. + + 1 0 Read all fields of the parameter block. + + + + 29 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + 1 + + Ignore all fields of the parameter block except for the + Track Layout field. + + 2 0 + + The sectors in the track may not all be the same size. + (You should not use this setting.) + + 1 + + The sectors in the track are all the same size and the + sector numbers range between 1 and the total number of + sectors actually in the track. You should always set this + bit. + + 3-7 0 These bits must be zero. + +_ ________________________________________________________________ + + +Device Type + +This byte describes the physical device and is set by the device. When set, +it has the following meanings: + +Value + Meaning +_ ________________________________________________________________ + +0 320/360 KB + +1 1.2 MB + +2 720 KB + +3 8-inch, single-density + +4 8-inch, double-density + +5 Hard disk + +6 Tape drive + +7 Other + + +Device Attributes + +Bit Value Meaning + +_ ________________________________________________________________ + + 0 The media is removable. + + 0 1 The media is not removable. + + 1 0 + + Disk change-line is not + supported; (no door lock + support). + + 1 + + Disk change-line is + supported; (door lock + support). + + 2-7 0 These bits must be zero. + +_ ________________________________________________________________ + + +30 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Number of Cylinders + +This field indicates the maximum number of cylinders that the physical +device can support. This information is set by the device. + +Media Type + +For drives that may contain different media, this field (which is device- +dependent) indicates which media the drive expects. + +For a 1.2 MB disk, bit zero has the following meaning: + +Bit Value Meaning + +_ ________________________________________________________________ + + 0 0 Quad-density, 1.2 MB disk + + 1 Double-density, 320/360 KB disk + +_ ________________________________________________________________ + +The default media type is a quad-density 1.2 MB disk. + +Device BPB + +If bit 0 of the Special Functions field is clear, the BPB in this field is the +new default BPB for the device. + +If bit 0 of the Special Functions field is set, the device driver returns the +BPB from this field for subsequent Build BPB requests. + +Track Layout + +This field contains a table of variable length for each logical device and +indicates the expected layout of the sectors on the media track. The field +has the following format: + + ------------------------------------------------ + | WORD Sector Count -- total # of sectors | + |----------------------------------------------| + | WORD Sector Number -- sector #1 | + |----------------------------------------------| + | WORD Sector Size -- sector #1 | + |----------------------------------------------| + | WORD Sector Number -- sector #2 | + |----------------------------------------------| + | WORD Sector Size -- sector #2 | + ------------------------------------------------ + | + | + | + + 31 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + ------------------------------------------------ + | WORD Sector Number -- sector #n | + |----------------------------------------------| + | WORD Sector Size -- sector #n | + ------------------------------------------------ + +The Sector Count field indicates the total number of sectors. Each sector +number must be unique and in the range of 1 to sector count (n). + +If bit 2 of the Special Functions field is set, all sector sizes must be the +same. + +Get Device Parameters (Function 440DH, CL=60H) + +When CL=60H, the parameter block has the same field layout as for +CL=40H. However, some of the fields have different meanings. These are +described as follows: + +Special Functions + +Bit Value Meaning + +_ ________________________________________________________________ + + 0 0 Returns the default BPB for the device. + + 1 + + Returns the BPB that Build BPB + would return. + + 1-7 0 These bits must be zero. + +_ ________________________________________________________________ + + +Track Layout + +The "Get Device Parameters" call does not use this field. + +Read/Write Track on Logical Drive +(Function 440D, CL=61H/CL=41H) + +To write to a track on a logical drive, set CL=41H. To read a track on a +logical drive, set CL=61H. + +When CL=41H or 61H, the parameter block has the following format: + + -------------------------------- + | BYTE Special Functions | + |------------------------------| + | WORD Head | + |------------------------------| + | WORD Cylinder | + |------------------------------| + +32 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + | WORD First Sector | + |------------------------------| + | WORD Number of Sectors | + |------------------------------| + | DWORD Transfer Address | + -------------------------------- + +These fields are described as follows: + +Special Functions This byte must be zero. + +Head + +This field contains the number of the head on which you perform the write +or read. + +Cylinder + +This field contains the number of the cylinder on which you perform the +write or read. + +First Sector + +This field contains the number of the first sector on which you perform the +write or read. Sectors are numbered starting with zero, so the fourth sec- +tor is numbered 3. + +Number of Sectors + +This field contains the total number of sectors. + +Transfer Address + +This field contains the address for storing the data to be written or the +data just read. + +Format/Verify Track on Logical Drive +(Function 440DH, CL=42/CL=62) + +To format and verify a track on a logical drive, set CL=42H. To verify a +track on a logical drive, set CL=62H. + + + + 33 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +When CL=42H or 62H, the parameter block has the following format: + + -------------------------------- + | BYTE Special Functions | + |------------------------------| + | WORD Head | + |------------------------------| + | WORD Cylinder | + -------------------------------- + +These fields are described as follows: + +Special Functions + +This byte must be zero. + +Head + +This field contains the number of the head on which you perform the for- +mat or verify. + +Cylinder + +This field contains the number of the cylinder on which you perform the +format or verify. + + +34 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Get/Set IOCtl Drive Map (Function 44H, +Codes 0EH and 0FH) + + Call: + + AH = 44H + AL + OEH = Get logical drive map + OFH = Set logical drive map + BX + Drive number + (0 = default, 1 = A, etc.) + + Return: + + Carry set: + AX + 1 = Invalid function code + 5 = Invalid drive + Carry not set: + AL = Logical drive mapped onto physical drive + (= 0 if only one drive is + assigned to this physical drive) + + +Comments: + +MS-DOS 3.3 supports the mapping of multiple logical drives onto a single +physical block device. Get IOCtl Drive Map lets you query the DOS about +which logical drive is currently mapped onto the corresponding physical +device. Set IOCtl Drive Map alters the device that is currently mapped +onto the physical device. These functions are only useful if there is more +than one logical block device mapped onto a single physical device. + +A possible use for these functions is with applications that want to disable +the DOS prompt in order to place the correct floppy disk in the drive when +accessing the other logical drive. + +To detect whether a logical device currently owns the physical device it is +mapped to, a program needs to check the value in AL after calling Func- +tion 440EH or 440FH (Get/Set IOCtl Drive Map). + + + 35 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Duplicate File Handle (Function 45H) + + Call: + + AH = 45H + BX + Handle + + Return: + + Carry set: + AX + 4 = Too many open files + 6 = Invalid handle + Carry not set: + AX + New handle + + + +Comments: + +Function 45H creates an additional handle for a file. BX must contain the +handle of an open file. + +MS-DOS returns the new handle in AX. The new handle refers to the same +file as the handle in BX, with the file pointer at the same position. + +After you use this function request, moving the read/write pointer of +either handle also moves the pointer for the other handle. You usually use +this function request to redirect standard input (handle 0) and standard +output (handle 1). For a description of standard input, standard output, +and the advantages and techniques of manipulating them, see Software +Tools by Brian W. Kernighan and P.J. Plauger (Addison-Wesley Publish- +ing Co., 1976). + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +4 Too many open files (no handle available) + +6 Handle not open or is invalid + + + +36 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +xdup macro handle + mov bx,handle + mov ah,45H + int 21H + endm + + +Example: + +The following program redirects standard output (handle 1) to a file +named dirfile, invokes a second copy of command.com to list the directory +(which writes the directory to dirfile), and then restores standard input to +handle 1. + +pgm_file db "command.com",0 +cmd_line db 9,"/c dir /w",0dH +parm_blk db 14 dup (0) +path db "dirfile",0 +dir_file dw ? ; For handle +sav_stdout dw ? ; For handle +; +begin: set_block last_inst ; See Function 4AH + jc error_setblk ; Routine not shown + create_handle path,0 ; See Function 3CH + jc error_create ; Routine not shown + mov dir_file,ax ; Save handle + xdup 1 ; THIS FUNCTION + jc error_xdup ; Routine not shown + mov sav_stdout,ax ; Save handle + xdup2 dir_file,1 ; See Function 46H + jc error_xdup2 ; Routine not shown + exec pgm_file,cmd_line,parm_blk ; See Function + 4BH + jc error_exec ; Routine not shown + xdup2 sav_stdout,1 ; See Function 46H + jc error_xdup2 ; Routine not shown + close_handle sav_stdout ; See Function 3EH + jc error_close ; Routine not shown + close_handle dir_file ; See Function 3EH + jc error_close ; Routine not shown + + + + 37 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Force Duplicate File Handle (Function 46H) + + Call: + + AH = 46H + BX + Handle + CX + Second handle + + Return: + + Carry set: + AX + 4 = Too many open files + 6 = Invalid handle + Carry not set: + No error + + + +Comments: + +Function 46H forces a specified handle to refer to the same file as a second +handle already associated with an open file. BX must contain the handle +of the open file; CX must contain the second handle. + +On return, the handle in CX now refers to the same file at the same posi- +tion as the handle in BX. If the file referred to by the handle in CX was +open at the time of the call, this function closes it. + +After you use this call, moving the read/write pointer of either handle also +moves the pointer for the other handle. Normally, you would use this +function request to redirect standard input (handle 0) and standard out- +put (handle 1). For a description of standard input, standard output, and +the advantages and techniques of manipulating them, see Software Tools +by Brian W. Kernighan and P.J. Plauger (Addison-Wesley Publishing Co., +1976). + + + +38 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +4 Too many open files (no handle available) + +6 Handle not open or is invalid + + +Macro Definition: + + +xdup2 macro handle1,handle2 + mov bx,handle1 + mov cx,handle2 + mov ah,46H + int 21H + endm + + +Example: + +The following program redirects standard output (handle 1) to a file +named dirfile, invokes a second copy of command.com to list the directory +(which writes the directory to dirfile), and then restores standard input to +handle 1. + +pgm_file db "command.com",0 +cmd_line db 9,"/c dir /w",0dH +parm_blk db 14 dup (0) +path db "dirfile",0 +dir_file dw ? ; For handle +sav_stdout dw ? ; For handle +; +begin: set_block last_inst ; See Function 4AH + jc error_setblk ; Routine not shown + create_handle path,0 ; See Function 3CH + jc error_create ; Routine not shown + mov dir_file,ax ; Save handle + xdup 1 ; See Function 45H + jc error_xdup ; Routine not shown + mov sav_stdout,ax ; Save handle + xdup2 dir_file,1 ; + jc error_xdup2 ; Routine not shown + exec pgm_file,cmd_line,parm_blk ; See Function + 4BH + jc error_exec ; Routine not shown + xdup2 sav_stdout,1 ; THIS FUNCTION + jc error_xdup2 ; Routine not shown + close_handle sav_stdout ; See Function 3EH + jc error_close ; Routine not shown + close_handle dir_file ; See Function 3EH + jc error_close ; Routine not shown + + 39 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Current Directory (Function 47H) + + Call: + + AH = 47H + DS:SI + Pointer to 64-byte memory area + DL + Drive number + (0 = default, 1 = A) + + Return: + + Carry set: + AX + 15 = Invalid drive number + Carry not set: + No error + + + +Comments: + +Function 47H returns the pathname of the current directory on a specified +drive. DL must contain a drive number (0=default, 1=A, etc.). SI must +contain the offset (from the segment address in DS) of a 64-byte memory +area. + +MS-DOS places an ASCIZ string in the memory area, consisting of the path +(starting from the root directory) of the current directory for the drive +specified in DL. The string does not begin with a backslash and does not +include the drive letter. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +15 Number in DL not a valid drive number + + + +40 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +get_dir macro drive,buffer + mov dl,drive + mov si,offset buffer + mov ah,47H + int 21H + endm + + +Example: + +The following program displays the current directory that is on the disk in +drive B. + +disk db "b: +buffer db 64 dup (?) +; +begin: get_dir 2,buffer ;THIS FUNCTION + jc error_dir ;Routine not shown + display disk ;See Function 09H + display_asciz buffer ;See end of chapter + + + + 41 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Allocate Memory (Function 48H) + + Call: + + AH = 48H + BX + Paragraphs of memory requested + + Return: + + Carry set: + AX + 7 = Memory-control blocks damaged + 8 = Insufficient memory + BX + Paragraphs of memory available + Carry not set: + AX + Segment address of allocated memory + + + +Comments: + +Function 48H tries to allocate the specified amount of memory to the +current process. BX must contain the number of paragraphs of memory +(one paragraph is 16 bytes). + +If sufficient memory is available to satisfy the request, AX returns the seg- +ment address of the allocated memory (the offset is 0). If sufficient memory +is not available, BX returns the number of paragraphs of memory in the +largest available block. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +7 Memory-control blocks damaged (a user program changed memory + that doesn't belong to it) + +8 Not enough free memory to satisfy the request + + + +42 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +allocate_memory macro bytes + mov bx,bytes + mov cl,4 + shr bx,cl + inc bx + mov ah,48H + int 21H + endm + + +Example: + +The following program opens the file named textfile.asc, calculates its size +with Function 42H (Move File Pointer), allocates a block of memory the +size of the file, reads the file into the allocated memory block, and then +frees the allocated memory. + +path db "textfile.asc",0 +msg1 db "File loaded into allocated memory block.", + 0DH,0AH +msg2 db "Allocated memory now being freed + (deallocated).",0DH,0AH +handle dw ? +mem_seg dw ? +file_len dw ? +; +begin: open_handle path,0 + jc error_open ;Routine not shown + mov handle,ax ;Save handle + move_ptr handle,0,0,2 ;See Function 42H + jc error_move ;Routine not shown + mov file_len,ax ;Save file length + set_block last_inst ;See Function 4AH + jc error_setblk ;Routine not shown + allocate_memory file_len ;THIS FUNCTION + jc error_alloc ;Routine not shown + mov mem_seg,ax ;Save address of new memory + move_ptr handle,0,0,0 ;See Function 42H + jc error_move ;Routine not shown + push ds ;Save DS + mov ax,mem_seg ;Get segment of new memory + mov ds,ax ;Point DS at new memory + read_handle cs:handle,0,cs:file_len ;Read file into +; new memory + pop ds ;Restore DS + jc error_read ;Routine not shown +; (CODE TO PROCESS FILE GOES HERE) + write_handle stdout,msg1,42 ;See Function 40H + jc write_error ;Routine not shown + free_memory mem_seg ;See Function 49H + jc error_freemem ;Routine not shown + write_handle stdout,msg2,49 ;See Function 40H + + 43 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + jc write_error ;Routine not shown + + + +44 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Free Allocated Memory (Function 49H) + + Call: + + AH = 49H + ES + Segment address of memory to be + freed + + Return: + + Carry set: + AX + 7 = Memory-control blocks damaged + 9 = Incorrect segment + Carry not set: + No error + + + +Comments: + +Function 49H frees (makes available) a block of memory previously allo- +cated with Function 48H (Allocate Memory). ES must contain the segment +address of the memory block to be freed. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +7 Memory-control blocks damaged (a user program changed memory + that didn't belong to it) + +9 Memory pointed to by ES was not allocated with Function 48H + + +Macro Definition: + + +free_memory macro seg_addr + mov ax,seg_addr + mov es,ax + mov ah,49H + int 21H + endm + + + + 45 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program opens a file named textfile.asc, calculates its size +with Function 42H (Move File Pointer), allocates a block of memory the +size of the file, reads the file into the allocated memory block, and then +frees the allocated memory. + +path db "textfile.asc",0 +msg1 db "File loaded into allocated memory block.", + 0DH,0AH +msg2 db "Allocated memory now being freed + (deallocated).",0DH,0AH +handle dw ? +mem_seg dw ? +file_len dw ? +; +begin: open_handle path,0 + jc error_open ;Routine not shown + mov handle,ax ;Save handle + move_ptr handle,0,0,2 ;See Function 42H + jc error_move ;Routine not shown + mov file_len,ax ;Save file length + set_block last_inst ;See Function 4AH + jc error_setblk ;Routine not shown + allocate_memory file_len ;See Function 48H + jc error_alloc ;Routine not shown + mov mem_seg,ax ;Save address of new memory + mov_ptr handle,0,0,0 ;See Function 42H + jc error_move ;Routine not shown + push ds ;Save DS + mov ax,mem_seg ;Get segment of new memory + mov ds,ax ;Point DS at new memory + read_handle handle,code,file_len ;Read file into +; new memory + pop ds ;Restore DS + jc error_read ;Routine not shown +; (CODE TO PROCESS FILE GOES HERE) + write_handle stdout,msg1,42 ;See Function 40H + jc write_error ;Routine not shown + free_memory mem_seg ;THIS FUNCTION + jc error_freemem ;Routine not shown + write_handle stdout,msg2,49 ;See Function 40H + jc write_error ;Routine not shown + + + +46 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Set Block (Function 4AH) + + Call: + + AH = 4AH + BX + Paragraphs of memory + ES + Segment address of memory area + + Return: + + Carry set: + AX + 7 = Memory-control blocks damaged + 8 = Insufficient memory + 9 = Incorrect segment + BX + Paragraphs of memory available + Carry not set: + No error + + +Comments: + +Function 4AH changes the size of a memory-allocation block. ES must +contain the segment address of the memory block. BX must contain the +new size of the memory block, in paragraphs (one paragraph is 16 bytes). + +MS-DOS attempts to change the size of the memory block. If the call fails +on a request to increase memory, BX returns the maximum size (in para- +graphs) to which the block can be increased. + +Since MS-DOS allocates all available memory to a .com program, you +would use this call most often to reduce the size of a program's initial +memory-allocation block. + + + + 47 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +7 Memory-control blocks destroyed (a user program changed memory + that didn't belong to it) + +8 Not enough free memory to satisfy the request + +9 Wrong address in ES (the memory block it points to cannot be + modified with Set Block) + +The following macro shrinks the initial memory-allocation block of a .com +program. It takes as a parameter the offset of the first byte following the +last instruction of a program (LAST_INST in the sample programs), uses +it to calculate the number of paragraphs in the program, and then adds 17 +to the result: one to round up and 16 to set aside 256 bytes for a stack. It +then sets up SP and BP to point to this stack. + +Macro Definition: + + +set_block macro last_byte + mov bx,offset last_byte + mov cl,4 + shr bx,cl + add bx,17 + mov ah,4AH + int 21H + mov ax,bx + shl ax,cl + dec ax + mov sp,ax + mov bp,sp + endm + + +Example: + +The following program invokes a second copy of command.com and exe- +cutes a dir (directory) command. + +pgm_file db "command.com",0 +cmd_line db 9,"/c dir /w",0DH +parm_blk db 14 dup (?) +reg_save db 10 dup (?) +; +begin: set_block last_inst ;THIS FUNCTION + exec pgm_file,cmd_line,parm_blk,0 ;See Function + ;4BH + + + +48 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Load and Execute Program (Function 4BH, +Code 00H) + + Call: + + AH = 4BH + AL = 00H + DS:DX + Pointer to pathname + ES:BX + Pointer to parameter block + + Return: + + Carry set: + AX + 1 = Invalid function + 2 = File not found + 3 = Path not found + 4 = Too many open files + 5 = Access denied + 8 = Insufficient memory + 10 = Bad environment + 11 = Bad format + Carry not set: + No error + + +Comments: + +Function 4BH, Code 00H, loads and executes a program. DX must contain +the offset (from the segment address in DS) of an ASCIZ string that specifies +the drive and pathname of an executable program file. BX must contain +the offset (from the segment address in ES) of a parameter block. AL must +contain 0. + +There must be enough free memory for MS-DOS to load the program file. +MS-DOS allocates all available memory to a program when it loads it, so +you must free some memory with Function 4AH (Set Block) before using +this function request to load and execute another program. Unless you or +MS-DOS needs the memory for some other purpose, you should shrink the +memory to the minimum amount required by the current process before +issuing this request. + +MS-DOS creates a Program Segment Prefix for the program being loaded +and sets the terminate and CONTROL-C addresses to the instruction that +immediately follows the call to Function 4BH in the invoking program. + + + 49 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The parameter block consists of four addresses: + +Table 0.2 + +Contents of the Parameter Block + +_ _________________________________________________________________________ + +Offset Length +(Hex) (Bytes) Description + +_ _________________________________________________________________________ + +00 2 (word) + + Segment address of the environment to be passed; 00H + means copy the parent program's environment. + +02 4 (dword) + + Segment: Offset of command line to be placed at offset 80H + of the new Program Segment Prefix. Must be a correctly- + formed command line no longer than 128 bytes. + +06 4 (dword) + + Segment: Offset of FCB to be placed at offset 5CH of the + new Program Segment Prefix (the Program Segment Prefix + is described in Chapter 4, "MS-DOS Control Blocks and + Work Areas") + +0A 4 (dword) + + Segment: Offset of FCB to be placed at offset 6CH of the + new Program Segment Prefix + +_ _________________________________________________________________________ + +All open files of a program are available to the newly loaded program, giv- +ing the parent program control over the definition of standard input, out- +put, auxiliary, and printer devices. For example, a program could write a +series of records to a file, open the file as standard input, open a second file +as standard output, and then use Function 4BH, Code 00H (Load and Exe- +cute Program) to load and execute a program that takes its input from +standard input, sorts records, and writes to standard output. + +The loaded program also receives an environment, a series of ASCIZ strings +of the form parameter=value (for example, verify= on). The environment +must begin on a paragraph boundary, be less than 32K bytes long, and +end with a byte of 00H (that is, the final entry consists of an ASCIZ string +followed by two bytes of 00H). Following the last byte of zeros is a set of +initial arguments passed to a program containing a word count followed +by an ASCIZ string. If the call finds the file in the current directory, the +ASCIZ string contains the drive and pathname of the executable program as +passed to Function 4BH. If the call finds the file in the path, it concaten- +ates the filename with the path information. (A program may use this area +to determine whence it was loaded.) If the word-environment address is 0, +the loaded program either inherits a copy of the parent program's environ- +ment or receives a new environment built for it by the parent. + +Place the segment address of the environment at offset 2CH of the new +Program Segment Prefix. To build an environment for the loaded pro- +gram, put it on a paragraph boundary and place the segment address of +the environment in the first word of the parameter block. To pass a copy +of the parent's environment to the loaded program, put 00H in the first + +50 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +word of the parameter block. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 AL not 0 or 3 + +2 Program file not found + +3 Path invalid or not found + +4 Too many open files (no handle available) + +5 Directory full, a directory with the same name exists, or a file with + the same name exists + +8 Not enough memory to load the program + +10 Environment appears longer than 32K + +11 Program file is an .exe file that contains internally inconsistent + information + + +Executing Another Copy of Command.com + +Since command.com builds pathnames, searches command paths for pro- +gram files, and relocates .exe files, the simplest way to load and execute +another program is to load and execute an additional copy of +command.com, passing it a command line that includes the /c switch, +which invokes the .com or .exe file. + +This action requires 17K bytes of available memory, so a program that +does it should be sure to shrink its initial memory-allocation block with +Function 4AH (Set Block). The format of a command line that contains +the /c switch: + +length,/c command,0DH + +Length is the length of the command line, counting the length byte but not +the ending carriage-return (0DH). + +Command is any valid MS-DOS command. + +0DH is a carriage-return character. + +If a program executes another program directly\(emnaming it as the program +file to Function 4BH instead of command.com\(emit must perform all the +processing normally done by command.com. + + + 51 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +exec macro path,command,parms + mov dx,offset path + mov bx,offset parms + mov word ptr parms[02H],offset command + mov word ptr parms[04H],cs + mov word ptr parms[06H],5CH + mov word ptr parms[08H],es + mov word ptr parms[0AH],6CH + mov word ptr parms[0CH],es + mov al,0 + mov ah,4BH + int 21H + endm + + +Example: + +The following program invokes a second copy of command.com and exe- +cutes a dir (directory) command by using the /w (wide) switch: + +pgm_file db "command.com",0 +cmd_line db 9,"/c dir /w",0DH +parm_blk db 14 dup (?) +reg_save db 10 dup (?) +; +begin: + set_block last_inst ;See Function 4AH + exec pgm_file,cmd_line,parm_blk,0 ;THIS FUNCTION + + + +52 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Load Overlay (Function 4BH, Code 03H) + + Call: + + AH = 4BH + AL = 03H + DS:DX + Pointer to pathname + ES:BX + Pointer to parameter block + + Return: + + Carry set: + AX + 1 = Invalid function + 2 = File not found + 3 = Path not found + 4 = Too many open files + 5 = Access denied + 8 = Insufficient memory + 10 = Bad environment + Carry not set: + No error + + +Comments: + +Function 4BH, Code 03H, loads a program segment (overlay). DX must +contain the offset (from the segment address in DS) of an ASCIZ string that +specifies the drive and pathname of the program file. BX must contain the +offset (from the segment address in ES) of a parameter block. AL must +contain 3. + +MS-DOS assumes that since the invoking program is loading into its own +address space, it requires no free memory. This call does not create a Pro- +gram Segment Prefix. + + + + 53 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The parameter block is four bytes long: + + +Table 0.3 + +Contents of the Parameter Block + +_ _________________________________________________________________________ + +Offset Length +(Hex) (Bytes) Description + +_ _________________________________________________________________________ + +00 2 (word) Segment address where program is to be loaded + +02 2 (word) + + Relocation factor; usually the same as the first word of the + parameter block (for a description of an .exe file and of + relocation, see Chapter 6, ".Exe File Structure and + Loading.") + +_ _________________________________________________________________________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 AL not 00H or 03H + +2 Program file not found + +3 Path invalid or not found + +4 Too many open files (no handle available) + +5 Directory is full, a directory with the same name exists, or a file + with the same name exists + +8 Not enough memory to load the program + +10 Environment appears longer than 32K + + +Macro Definition: + + +exec_ovl macro path,parms,seg_addr + mov dx,offset path + mov bx,offset parms + mov parms,seg_addr + mov parms[02H],seg_addr + mov al,3 + mov ah,4BH + int 21H + endm + + + +54 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +The following program opens a file named textfile.asc, redirects standard +input to that file, loads more.com as an overlay, and calls an overlay +named bit.com, which reads textfile.asc as standard input. The overlay +must establish its own addressability and end with a FAR return. + +stdin equ 0 +; +file db "TEXTFILE.ASC",0 +cmd_file db "\bit.com",0 +parm_blk dw 4 dup (?) +overlay label dword + dw 0 +handle dw ? +new_mem dw ? +; +begin: set_block last_inst ;see Function 4AH + jc setblock_error ;routine not shown + allocate_memory 2000 ;see Function 48H + jc allocate_error ;routine not shown + mov new_mem,ax ;save seg of memory + open_handle file,0 ;see Function 3DH + jc open_error ;routine not shown + mov handle,ax ;save handle + xdup2 handle,stdin ;see Function 45H + jc dup2_error ;routine not shown + close_handle handle ;see Function 3EH + jc close_error ;routine not shown + mov ax,new_mem ;addr of new memory + exec_ovl cmd_file,parm_blk,ax ;THIS FUNCTION + jc exec_error ;routine not shown + call overlay ;call the overlay + free_memory new_mem ;see Function 49H + jc free_error ;routine not shown +; + + + + 55 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +End Process (Function 4CH) + + Call: + + AH = 4CH + AL + Return code + + Return: + + None + + + +Comments: + +Function 4CH terminates a process and returns to MS-DOS. AL contains a +return code that can be retrieved by the parent process with Function 4DH +(Get Return Code of Child Process) or the if command, using errorlevel. + +MS-DOS closes all open handles, ends the current process, and returns +control to the invoking process. + +This function request doesn't require CS to contain the segment address of +the Program Segment Prefix. You should use it to end a program (rather +than Interrupt 20H or a jump to location 0) unless your program must be +compatible with MS-DOS versions before 2.0. + +_ ________________________________________________________________ + +Note + + If you use file sharing, you must remove all locks issued by this process + or the DOS will be in an uncertain state. + +_ ________________________________________________________________ + + + +56 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +end_process macro return_code + mov al,return_code + mov ah,4CH + int 21H + endm + + +Example: + +The following program displays a message and returns to MS-DOS with a +return code of 8. It uses only the opening portion of the sample program +skeleton shown at the beginning of this chapter. + +message db "Displayed by FUNC_4CH example",0DH,0AH,"$" +; +begin: display message ;See Function 09H + end_process 8 ;THIS FUNCTION +code ends + end code + + + + 57 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Return Code of Child Process (Function +4DH) + + Call: + + AH = 4DH + + Return: + + AX + Return code + + + +Comments: + +Function 4DH retrieves the return code specified when a child process ter- +minates via either Function 31H (Keep Process) or Function 4CH (End +Process). The code returns in AL. AH returns a code that specifies why the +program ended: + +Code + Meaning +_ ________________________________________________________________ + +0 Normal termination + +1 Terminated by CONTROL-C + +2 Critical device error + +3 Function 31H (Keep Process) + +This call can retrieve the exit code only once. + +Macro Definition: + + +ret_code macro + mov ah,4DH + int 21H + endm + +58 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Example: + +No example is included for this function request, because the meaning of a +return code varies. + + + 59 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Find First File (Function 4EH) + + Call: + + AH = 4EH + DS:DX + Pointer to pathname + CX + Attributes to match + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 18 = No more files + Carry not set: + No error + + + +Comments: + +Function 4EH searches the current or specified directory for the first entry +that matches the specified pathname. DX must contain the offset (from the +segment address in DS) of an ASCIZ string that specifies the pathname, +which can contain wildcard characters. CX must contain the attribute to +be used in searching for the file, as described in Section 1.5.5, "File Attri- +butes," earlier in this chapter. + +If the attribute field is hidden file, system file, or subdirectory entry (02H, +04H, or 10H), or any combination of these values, all normal file entries +are also searched. To search all directory entries except the volume label, +set the attribute byte to 16H (hidden file, system file, and directory entry). + + + +60 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +If this function finds a directory entry that matches the name and attri- +bute, it fills the current DTA as follows: + + +Table 0.4 + + + +_ _________________________________________________________________________ + +Offset Length Description + +_ _________________________________________________________________________ + +00H 21 Reserved for subsequent Function 4FH (Find Next File) + +15H 1 Attribute found + +16H 2 Time file was last written + +18H 2 Date file was last written + +1AH 2 Low word of file size + +1CH 2 High word of file size + +1EH 13 + + Name and extension of the file, followed by 00H. All blanks + are removed; if there is an extension, it is preceded by a + period. (Volume labels include a period after the eighth + character.) + +_ _________________________________________________________________________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +2 Specified file invalid or doesn't exist + +3 Specified path invalid or doesn't exist + +18 No matching directory entry found + + +Macro Definition: + + +find_first_file macro path,attrib + mov dx,offset path + mov cx,attrib + mov ah,4EH + int 21H + endm + + + + 61 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program displays a message that specifies whether a file +named report.asm exists in the current directory on the disk in drive B. + +yes db "File exists.",0DH,0AH,"$" +no db "File does not exist.",0DH,0AH,"$" +path db "b:report.asm",0 +buffer db 43 dup (?) +; +begin: set_dta buffer ;See Function 1AH + find_first_file path,0 ;THIS FUNCTION + jc error_findfirst ;Routine not shown + cmp al,12H ;File found? + je not_there ;No + display yes ;See Function 09H + jmp return ;All done +not_there: display no ;See Function 09H + + + +62 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Find Next File (Function 4FH) + + Call: + + AH = 4FH + + Return: + + Carry set: + AX + 18 = No more files + Carry not set: + No error + + + +Comments: + +Function 4FH searches for the next directory entry that matches the name +and attributes specified in a previous Function 4EH (Find First File). The +current DTA must contain the information filled in by Function 4EH (Find +First File). + +If the function finds a matching entry, it fills the current DTA just as it +did for Find First File (see Function 4EH (Find First File)). + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +2 Specified path invalid or doesn't exist + +18 No matching directory entry found + + + + 63 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +find_next_file macro + mov ah,4FH + int 21H + endm + + +Example: + +The following program displays the number of files contained in the +current directory on the disk in drive B. + +message db "No files",0DH,0AH,"$" +files dw ? +path db "b:*.*",0 +buffer db 43 dup (?) +; +begin: set_dta buffer ;See Function 1AH + find_first_file path,0 ;See Function 4EH + jc error_findfirst ;Routine not shown + cmp al,12H ;Directory empty? + je all_done ;Yes, go home + inc files ;No, bump file counter +search_dir: find_next_file ;THIS FUNCTION + jc error_findnext ;Routine not shown + cmp al,12H ;Any more entries? + je done ;No, go home + inc files ;Yes, bump file counter + jmp search_dir ;And check again +done: convert files,10,message ;See end of chapter +all_done: display message ;See Function 09H + + + +64 + +_ _ | | _ _ + + + diff --git a/PROGREF/1E_CALLS.A b/PROGREF/1E_CALLS.A new file mode 100644 index 0000000..36e1cec --- /dev/null +++ b/PROGREF/1E_CALLS.A @@ -0,0 +1,3533 @@ + +_ _ | | _ _ + + + + _ ______________ + + +Get Verify State (Function 54H) + + Call: + + AH = 54H + + Return: + + AL + 0 = No verify after write + 1 = Verify after write + + + +Comments: + +Function 54H checks whether MS-DOS verifies write operations to disk +files. The status returns in AL: 0 if verify is off, 1 if verify is on. + +You can set the verify status with Function 2EH (Set/Reset Verify Flag). + +Macro Definition: + + +get_verify macro + mov ah,54H + int 21H + endm + + +Example: + +The following program displays the verify status: + +message db "Verify ","$" +on db "on.",0DH,0AH,"$" +off db "off.",0DH,0AH,"$" +; +begin: display message ;See Function 09H + get_verify ;THIS FUNCTION + cmp al,0 ;Is flag off? + + 1 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + jg ver_on ;No, it's on + display off ;See Function 09H + jmp return ;Go home +ver_on: display on ;See Function 09H + + + +2 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Change Directory Entry (Function 56H) + + Call: + + AH = 56H + DS:DX + Pointer to pathname + ES:DI + Pointer to second pathname + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 5 = Access denied + 17 = Not same device + Carry not set: + No error + + +Comments: + +Function 56H renames a file by changing its directory entry. DX must +contain the offset (from the segment address in DS) of an ASCIZ string that +contains the pathname of the entry to be changed. DI must contain the +offset (from the segment address in ES) of an ASCIZ string that contains a +second pathname to which the first is to be changed. + +If a directory entry for the first pathname exists, it is changed to the +second pathname. + +The directory paths need not be the same; in effect, you can move the file +to another directory by renaming it. You cannot use this function request +to copy a file to another drive, however; if the second pathname specifies a +drive, the first pathname must specify or default to the same drive. + +You cannot use this function request to rename an open file, a hidden file, +a system file, or a subdirectory, because it may corrupt your disk. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX. + +Code + Meaning +_ ________________________________________________________________ + +2 One of files is invalid or not open + + + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +3 One of paths is invalid or not open + +5 First pathname specifies a directory, second pathname specifies an + existing file; or second directory entry could not be opened + +17 Both files not on the same drive + + +Macro Definition: + + +rename_file macro old_path,new_path + mov dx,offset old_path + push ds + pop es + mov di,offset new_path + mov ah,56H + int 21H + endm + + +Example: + +The following program prompts for the name of a file and a new name, +then renames the file. + +prompt1 db "Filename: $" +prompt2 db "New name: $" +old_path db 15,?,15 dup (?) +new_path db 15,?,15 dup (?) +crlf db 0DH,0AH,"$" +; +begin: display prompt1 ;See Function 09H + get_string 15,old_path ;See Function 0AH + xor bx,bx ;To use BL as index + mov bl,old_path[1] ;Get string length + mov old_path[bx+2],0 ;Make an ASCIZ string + display crlf ;See Function 09H + display prompt2 ;See Function 09H + get_string 15,new_path ;See Function 0AH + xor bx,bx ;To use BL as index + mov bl,new_path[1] ;Get string length + mov new_path[bx+2],0 ;Make an ASCIZ string + display crlf ;See Function 09H + rename_file old_path[2],new_path[2];THIS FUNCTION + jc error_rename ;Routine not shown + + + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Get/Set Date/Time of File(Function 57H) + + Call: + + AH = 57H + AL = Function code + 0 = Get date and time + 1 = Set date and time + BX + Handle + CX (if AL = 1) + Time to be set + DX (if AL = 1) + Date to be set + + Return: + + Carry set: + AX + 1 = Invalid function + 6 = Invalid handle + Carry not set: + CX (if AL = 0) + Time file last written + DX (if AL = 0) + Date file last written + + +Comments: + +Function 57H gets or sets the time and date when a file was last written. +To get the time and date, AL must contain 0; the time and date return in +CX and DX. To set the time and date, AL must contain 1; CX and DX +must contain the time and date. BX must contain the file handle. The time +and date are in the form described in "Fields of the FCB" in Section 1.9.1. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 AL not 0 or 1 + +6 Handle in BX invalid or not open + + + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Macro Definition: + + +get_set_date_time macro handle,action,time,date + mov bx,handle + mov al,action + mov cx,word ptr time + mov dx,word ptr date + mov ah,57H + int 21H + endm + + +Example: + +The following program gets the date of a file named report.asm in the +current directory on the disk in drive B, increments the day, increments +the month and/or year, if necessary, and sets the new date of the file. + +month db 31,28,31,30,31,30,31,31,30,31,30,31 +path db "b:report.asm",0 +handle dw ? +time db 2 dup (?) +date db 2 dup (?) +; +begin: open_handle path,0 ;See Function 3DH + mov handle,ax ;Save handle + get_set_date_time handle,0,time,date ;THIS FUNCTION + jc error_time ;Routine not shown + mov word ptr time,cx ;Save time + mov word ptr date,dx ;Save date + convert_date date[-24] ;See end of chapter + inc dh ;Increment day + xor bx,bx ;To use BL as index + mov bl,dl ;Get month + cmp dh,month[bx-1] ;Past last day? + jle month_ok ;No, go home + mov dh,1 ;Yes, set day to 1 + inc dl ;Increment month + cmp dl,12 ;Is it past December? + jle month_ok ;No, go home + mov dl,1 ;Yes, set month to 1 + inc cx ;Increment year +month_ok: pack_date date ;See end of chapter + get_set_date_time handle,1,time,date ;THIS FUNCTION + jc error_time ;Routine not shown + close_handle handle ;See Function 3EH + jc error_close ;Routine not shown + + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Get/Set Allocation Strategy (Function 58H) + + Call: + + AH = 58H + AL + 0 = Get strategy + 1 = Set strategy + BX (AL = 1) + 0 = First fit + 1 = Best fit + 2 = Last fit + + Return: + + Carry set: + AX + 1 = Invalid function code + Carry not set: + AX (AL = 0) + 0 = First fit + 1 = Best fit + 2 = Last fit + + +Comments: + +Function 58H gets or sets the strategy that MS-DOS uses to allocate +memory when a process requests it. If AL contains 0, the strategy is +returned in AX. If AL contains 1, BX must contain the strategy. The three +possible strategies are: + + + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +Table 0.1 + +Allocation Strategy + +_ _________________________________________________________________________ + +Value Name Description + +_ _________________________________________________________________________ + +0 First fit + + MS-DOS starts searching at the lowest available block and + allocates the first block it finds (the allocated memory is the + lowest available block). This is the default strategy. + +1 Best fit + + MS-DOS searches each available block and allocates the + smallest available block that satisfies the request. + +2 Last fit + + MS-DOS starts searching at the highest available block and + allocates the first block it finds (the allocated memory is the + highest available block). + +_ _________________________________________________________________________ + +You can use this function request to control how MS-DOS uses its memory +resources. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 AL doesn't contain 0 or 1, or BX doesn't contain 0, 1, or 2. + + +Macro Definition: + + +alloc_strat macro code,strategy + mov bx,strategy + mov al,code + mov ah,58H + int 21H + endm + + +Example: + +The following program displays the memory-allocation strategy in effect, +then forces subsequent memory allocations to the top of memory by set- +ting the strategy to last fit (code 2). + +get equ 0 +set equ 1 +stdout equ 1 +last_fit equ 2 +; +first db "First fit ",0DH,0AH +best db "Best fit ",0DH,0AH +last db "Last fit ",0DH,0AH + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +; +begin: alloc_strat get ;THIS FUNCTION + jc alloc_error ;routine not shown + mov cl,4 ;multiply code by 16 + shl ax,cl ;to calculate offset + mov dx,offset first ;point to first msg + add dx,ax ;add to base address + mov bx,stdout ;handle for write + mov cs,16 ;write 16 bytes + mov ah,40h ;write handle + int 21H ;system call +; jc write_error ;routine not shown + alloc_strat set,last_fit ;THIS FUNCTION +; jc alloc_error ;routine not shown + + + + 9 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Extended Error (Function 59H) + + Call: + + AH = 59H + BX = 0 + + Return: + + AX + Extended-error code + BH + Error class (see text) + BL + Suggested action (see text) + CH + Locus (see text) + + CL, DX, SI, DI, DS, ES destroyed + + + +Comments: + +Function 59H retrieves an extended-error code for the preceding system +call. Each release of MS-DOS extends the error codes to cover new capabil- +ities. These new codes are mapped to a simpler set of error codes based on +MS-DOS Version 2.0, so that existing programs can continue to operate +correctly. Note that this call destroys all registers except CS:IP and +SS:SP. + +A user-written Interrupt 24H (Critical-Error Handler Address) can use +Function 59H to get detailed information about the error that caused the +interrupt to be issued. + +The input BX is a version indicator that specifies for what level of error +handling the application was written. The current level is 0. + +The extended-error code consists of four separate codes in AX, BH, BL, +and CH that give as much detail as possible about the error and suggest +how the issuing program should respond. + + +10 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +BH\(emError Class + +BH returns a code that describes the class of error that occurred: + +Class + Description +_ ________________________________________________________________ + +1 Out of a resource, such as storage or channels + +2 Not an error, but a temporary situation (such as a locked region in + a file) that is expected to end + +3 Authorization problem + +4 Internal error in system software + +5 Hardware failure + +6 System software failure not the fault of the active process (could be + caused by missing or incorrect configuration files, for example) + +7 Application program error + +8 File or item not found + +9 File or item of invalid format or type, or that is otherwise invalid + or unsuitable + +10 Interlocked file or item + +11 Wrong disk in drive, bad spot on disk, or other problem with + storage medium + +12 Other error + + + + 11 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +BL\(emSuggested Action + +BL returns a code that suggests how the issuing program can respond to +the error: + +Action + Description +_ ________________________________________________________________ + +1 Retry, then prompt user + +2 Retry after a Pause + +3 If user entered data such as drive letter or filename, prompt for it + again + +4 Terminate with cleanup + +5 Terminate immediately; system so unhealthy that program should + exit as soon as possible without taking time to close files and + update indexes + +6 Error is informational + +7 Prompt user to perform some action, such as changing disks, then + retry operation + + +CH\(emLocus + +CH returns a code that provides additional information to help locate the +area involved in the failure. This code is particularly useful for hardware +failures (BH=5). + +Locus + Description +_ ________________________________________________________________ + +1 Unknown + +2 Related to random-access block devices, such as a disk drive + +3 Related to Network + +4 Related to serial-access character devices, such as a printer + +5 Related to random-access memory + +Your programs should handle errors by noting the error return from the +original system call and then issuing this system call to get the extended- +error code. If the program does not recognize the extended-error code, it +should respond to the original error code. + +This system call is available during Interrupt 24H and may be used to +return network-related errors. + + +12 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +get_error macro + mov ah, 59H + int 21H + endm + + +Example: + +Since this function request provides such detailed information, a general +example is not practical. User programs can interpret the various codes to +determine what sort of messages or prompts should be displayed, what +action to take, and whether to terminate the program if recovery from the +errors isn't possible. + + + 13 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Create Temporary File (Function 5AH) + + Call: + + AH = 5AH + CX + Attribute + DS:DX + Pointer to pathname, followed by a + byte of 0, and then by 13 bytes of memory + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 4 = Too many open files + 5 = Access denied + Carry not set: + AX + Handle + + +Comments: + +Function 5AH creates a file with a unique name. DX must contain the +offset (from the segment address in DS) of an ASCIZ string that specifies a +pathname and 13 bytes of memory (to hold the filename). CX must con- +tain the attribute to be assigned to the file, as described in Section 1.5.5, +"File Attributes," earlier in this chapter. + +MS-DOS creates a unique filename and appends it to the pathname +pointed to by DS:DX, creates the file and opens it in compatibility mode, +then returns the file handle in AX. A program that needs a temporary file +should use this function request to avoid name conflicts. + +When the creating process exits, MS-DOS does not automatically delete a +file created with Function 5AH. When you no longer need the file you +should delete it. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +2 File is invalid or doesn't exist + + + +14 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +3 Directory pointed to by DS:DX is invalid or doesn't exist + +4 Too many open files (no handle available) + +5 Access denied + + +Macro Definition: + + +create_temp macro pathname,attrib + mov cx,attrib + mov dx,offset pathname + mov ah,5AH + int 21H + endm + + + + 15 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program creates a temporary file in the directory named +\wp\docs, copies a file named textfile.asc that is in the current directory +into the temporary file, and then closes both files. + +stdout equ 1 +; +file db "TEXTFILE.ASC",0 +path db "\WP\DOCS",0 +temp db 13 dup (0) +open_msg db " opened.",0DH,0AH +crl_msg db " created.",0DH,0AH +rd_msg db " read into buffer.",0DH,0AH +wr_msg db "Buffer written to " +cl_msg db "Files closed.",0DH,0AH +crlf db 0DH,0AH +handle1 dw ? +handle2 dw ? +buffer db 512 dup (?) +; +begin: open_handle file,0 ;see Function 3DH + jc open_error ;routine not shown + mov handle1,ax ;save handle + write_handle stdout,file,12 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,open_msg,10 ;see Function 40H + jc write_error ;routine not shown + create_temp path,0 ;THIS FUNCTION + jc create_error ;routine not shown + mov handle2,ax ;save handle + write_handle stdout,path,8 ;see Function 40H + jc write_error ;routine not shown + display_char " + write_handle stdout,temp,12 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,crl_msg,11 ;See Function 40H + jc write_error ;routine not shown + read_handle handle1,buffer,512 ;see Function 3FH + jc read_error ;routine not shown + write_handle stdout,file,12 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,rd_msg,20 ;see Function 40H + jc write_error ;routine not shown + write_handle handle2,buffer,512 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,wr_msg,18 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,temp,12 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,crlf,2 ;see Function 40H + jc write_error ;routine not shown + close_handle handle1 ;see Function 3EH + jc close_error ;routine not shown + close_handle handle2 ;see Function 3EH + +16 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + jc close_error ;routine not shown + write_handle stdout,cl_msg,15 ;see Function 40H + jc write_error ;routine not shown + + + + 17 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Create New File (Function 5BH) + + Call: + + AH = 5BH + CX + Attribute + DS:DX + Pointer to pathname + + Return: + + Carry set: + AX + 2 = File not found + 3 = Path not found + 4 = Too many open files + 5 = Access denied + 80 = File already exists + Carry not set: + AX + Handle + + +Comments: + +Function 5BH creates a new file. DX must contain the offset (from the seg- +ment address in DS) of an ASCIZ string that specifies a pathname. CX con- +tains the attribute to be assigned to the file, as described in Section 1.5.5, +"File Attributes." + +If there is no existing file with the same filename, MS-DOS creates the file, +opens it in compatibility mode, and returns the file handle in AX. + +This function request fails if the specified file exists, unlike Function 3CH +(Create Handle), which, under the same circumstances, truncates the file +to a length of 0. In a multitasking system, the existence of a file is used as +a semaphore; you can use this system call as a test-and-set semaphore. + + + +18 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +2 File is invalid or doesn't exist + +3 Directory pointed to by DS:DX is invalid or doesn't exist + +4 No free handles are available in the current process, or internal + system tables are full + +5 Access denied + +80 File with the same specification pointed to by DS:DX already exists + + +Macro Definition: + + +create_new macro pathname,attrib + mov cx, attrib + mov dx, offset pathname + mov ah, 5BH + int 21H + endm + + +Example: + +The following program attempts to create a new file named report.asm in +the current directory. If the file already exists, the program displays an +error message and returns to MS-DOS. If the file doesn't exist and there +are no other errors, the program saves the handle and continues process- +ing. + +err_msg db "FILE ALREADY EXISTS",0DH,0AH,"$" +path db "report.asm",0 +handle dw ? +; +begin: create_new path,0 ;THIS FUNCTION + jnc continue ;further processing + cmp ax,80 ;file already exist? + jne error ;routine not shown + display err_msg ;see Function 09H + jmp return ;return to MS-DOS +continue: mov handle,ax ;save handle +; +; (further processing here) + + + + 19 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Lock (Function 5CH, Code 00H) + + Call: + + AH = 5CH + AL = 00H + BX + Handle + CX:DX + Offset of region to be locked + SI:DI + Length of region to be locked + + Return: + + Carry set: + AX + 1 = Invalid function code + 6 = Invalid handle + 33 = Lock violation + 36 = Sharing buffer exceeded + Carry not set: + No error + + +Comments: + +Function 5CH, Code 00H, denies all access (read or write) by any other +process to the specified region of the file. BX must contain the handle of +the file that contains the region to be locked. CX:DX (a four-byte integer) +must contain the offset in the file of the beginning of the region. SI:DI (a +four-byte integer) must contain the length of the region. + +If another process attempts to use (read or write) a locked region, MS-DOS +retries three times; if the retries fail, MS-DOS issues Interrupt 24H for the +requesting process. You can change the number of retries with Function +44H, Code 0BH (IOCtl Retry). + +The locked region can be anywhere in the file. For instance, locking +beyond the end of the file is not an error. A region should be locked for +only a brief period, so if it is locked for more than ten seconds you should +consider it to be an error. + +Function 45H (Duplicate File Handle) and Function 46H (Force Duplicate +File Handle) duplicate access to any locked region. Passing an open file to +a child process with Function 4BH, Code 00H (Load and Execute Program) +does not duplicate access to locked regions. + +_ ________________________________________________________________ + +20 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +Warning + + If a program closes a file that contains a locked region or terminates + with an open file that contains a locked region, the result is undefined. + +_ ________________________________________________________________ + +Programs that might be terminated by Interrupt 23H (CONTROL-C Handler +Address) or Interrupt 24H (Critical-Error-Handler Address) should trap +these interrupts and unlock any locked regions before exiting. + +Programs should not rely on being denied access to a locked region. A +program can determine the status of a region (locked or unlocked) by +attempting to lock the region and examining the error code. + +If there is an error, the carry flag (CF) is set and the error code is returned +in AX: + +Code + Meaning +_ ________________________________________________________________ + +1 File sharing must be loaded to use this function request. + +6 The handle in BX is not a valid, open handle. + +33 All or part of the specified region is already locked. + +36 There is no more room for lock entries in the buffer. Refer to the + share command in the MS-DOS User's Reference for information + on allocating more lock entries. + + +Macro Definition: + + +lock macro handle,start,bytes + mov bx, handle + mov cx, word ptr start + mov dx, word ptr start+2 + mov si, word ptr bytes + mov di, word ptr bytes+2 + mov al, 0 + mov ah, 5CH + int 21H + endm + + + + 21 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program opens a file named finalrpt in "Deny None" mode +and locks two portions of it: the first 128 bytes and bytes 1024 through +5119. After some (unspecified) processing, it unlocks the same portions and +closes the file. + +stdout equ 1 +; +start1 dd 0 +lgth1 dd 128 +start2 dd 1023 +lgth2 dd 4096 +file db "FINALRPT",0 +op_msg db " opened.",0DH,0AH +11_msg db "First 128 bytes locked.",0DH,0AH +12_msg db "Bytes 1024-5119 locked.",0DH,0AH +u1_msg db "First 128 bytes unlocked.",0DH,0AH +u2_msg db "Bytes 1024-5119 unlocked.",0DH,0AH +cl_msg db " closed.:,0DH,0AH +handle dw ? +; +begin: open_handle file,01000010b ;see Function 3DH + jc open_error ;routine not shown + write_handle stdout,file,8 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,op_msg,10 ;see Function 40H + jc write_error ;routine not shown + mov handle,ax ;save handle + lock handle,start1,lgth1 ;THIS FUNCTION + jc lock_error ;routine not shown + write_handle stdout,11_msg,25 ;see Function 40H + jc write_error ;routine not shown + lock handle,start2,lgth2 ;THIS FUNCTION + jc lock_error ;routine not shown + write_handle stdout,12_msg,25 ;see Function 40H + jc write_error ;routine not shown +; +; ( Further processing here ) +; + unlock handle,start1,lgth1 ;See Function 5C01H + jc unlock_error ;routine not shown + write_handle stdout,ul_msg,27 ;see Function 40H + jc write_error ;routine not shown + unlock handle,start2,lgth2 ;See Function 5C01H + jc unlock_error ;routine not shown + write_handle stdout,u2_msg,27 ;See Function 40H + jc write_error ;routine not shown + close_handle handle ;See Function 3EH + jc close_error ;routine not shown + write_handle stdout,file,8 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,cl_msg,10 ;see Function 40H + jc write_error ;routine not shown + + +22 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Unlock (Function 5CH, Code 01H) + + Call: + + AH = 5CH + AL = 01H + BX + Handle + CX:DX + Offset of area to be unlocked + SI:DI + Length of area to be unlocked + + Return: + + Carry set: + AX + 1 = Invalid function code + 6 = Invalid handle + 33 = Lock violation + 36 = Sharing buffer exceeded + Carry not set: + No error + + +Comments: + +Function 5CH, Code 01H, unlocks a region previously locked by the same +process. BX must contain the handle of the file that contains the region to +be unlocked. CX:DX (a four-byte integer) must contain the offset in the file +of the beginning of the region. SI:DI (a four-byte integer) must contain the +length of the region. The offset and length must be exactly the same as the +offset and length specified in the previous Function 5CH, Code 00H (Lock). + +The description of Function 5CH, Code 00H (Lock) describes how to use +locked regions. + + + + 23 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 File sharing must be loaded to use this function request. + +6 The handle in BX is not a valid, open handle. + +33 The region specified is not identical to one that was previously + locked by the same process. + +36 There is no more room for lock entries in the buffer. Refer to the + share command in the MS-DOS User's Reference for information + on allocating more lock entries. + +You should issue Function 59H (Get Extended Error) to list the possible +errors returned by this function. + +Macro Definition: + + +unlock macro handle,start,bytes + mov bx, handle + mov cx, word ptr start + mov dx, word ptr start+2 + mov si, word ptr bytes + mov di, word ptr bytes+2 + mov al, 1 + mov ah, 5CH + int 21H + endm + + +Example: + +The following program opens a file named finalrpt in "Deny None" mode +and locks two portions of it: the first 128 bytes and bytes 1024 through +5119. After some (unspecified) processing, it unlocks the same portions and +closes the file. + +stdout equ 1 +; +start1 dd 0 +lgth1 dd 128 +start2 dd 1023 +lgth2 dd 4096 +file db "FINALRPT",0 +op_msg db " opened.",0DH,0AH +11_msg db "First 128 bytes locked.",0DH,0AH +12_msg db "Bytes 1024-5119 locked.",0DH,0AH +u1_msg db "First 128 bytes unlocked.",0DH,0AH +u2_msg db "Bytes 1024-5119 unlocked.",0DH,0AH + +24 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +cl_msg db " closed.",0DH,0AH +handle dw ? +; +begin: open_handle file,01000010b ;see Function 3DH + jc open_error ;routine not shown + write_handle stdout,file,8 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,op_msg,10 ;see Function 40H + jc write_error ;routine not shown + mov handle,ax ;save handle + lock handle,start1,lgth1 ;See Function 5C00H + jc lock_error ;routine not shown + write_handle stdout,11_msg,25 ;see Function 40H + jc write_error ;routine not shown + lock handle,start2,lgth2 ;See Function 5C00H + jc lock_error ;routine not shown + write_handle stdout,12_msg,25 ;see Function 40H + jc write_error ;routine not shown +; +; ( Further processing here ) +; + unlock handle,start1,lgth1 ;THIS FUNCTION + jc unlock_error ;routine not shown + write_handle stdout,u1_msg,27 ;see Function 40H + jc write_error ;routine not shown + unlock handle,start2,lgth2 ;THIS FUNCTION + jc unlock_error ;routine not shown + write_handle stdout,u2_msg,27 ;see Function 40H + jc write_error ;routine not shown + close_handle handle ;See Function 3EH + jc close_error ;routine not shown + write_handle stdout,file,8 ;see Function 40H + jc write_error ;routine not shown + write_handle stdout,cl_msg,10 ;see Function 40H + jc write_error ;routine not shown + + + + 25 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Machine Name (Function 5EH, Code 00H) + + Call: + + AH = 5EH + AL = 0 + DS:DX + Pointer to 16-byte buffer + + Return: + + Carry set: + AX + 1 = Invalid function code + Carry not set: + CX + Identification number of local + computer + + + +Comments: + +Function 5EH, Code 0, retrieves the net name of the local computer. DX +must contain the offset (to the segment address in DS) of a 16-byte buffer. +Microsoft Networks must be running. + +MS-DOS returns the local computer name (a 16-byte ASCIZ string, padded +with blanks) in the buffer pointed to by DS:DX. CX returns the +identification number of the local computer. If the network was never +installed, the CH register returns with zero and the value in the CL regis- +ter is invalid. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 Microsoft Networks must be running to use this function request. + + + +26 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +get_machine_name macro buffer + mov dx,offset buffer + mov al,0 + mov ah,5EH + int 21H + endm + + +Example: + +The following program displays the name of a Microsoft Networks work- +station. + +stdout equ 1 +; +msg db "Netname: " +mac_name db 16 dup (?),0DH,0AH +; +begin: get_machine_name mac_name ;THIS FUNCTION + jc name_error ;routine not shown + write_handle stdout,msg,27 ;see Function 40H + jc write_error ;routine not shown + + + + 27 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Printer Setup (Function 5EH, Code 02H) + + Call: + + AH = 5EH + AL = 02H + BX + Assign-list index + CX + Length of setup string + + DS:SI + Pointer to setup string + + Return: + + Carry set: + AX + 1 = Invalid function code + Carry not set: + No error + + +Comments: + +Function 5EH, Code 02H, defines a string of control characters that +MS-DOS adds to the beginning of each file sent to the network printer. BX +must contain the index into the assign list that identifies the printer (entry +0 is the first entry). CX must contain the length of the string. SI must con- +tain the offset (to the segment address in DS) of the string itself. Microsoft +Networks must be running. + +MS-DOS adds the setup string to the beginning of each file sent to the +printer, which is specified by the assign-list index in BX. This function +request lets each program that shares a printer have its own printer +configuration. You can use Function 5F02H (Get Assign-List Entry) to +determine which entry in the assign list refers to the printer. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 Microsoft Networks must be running to use this function request. + + + +28 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +printer_setup macro index,lgth,string + mov bx, index + mov cx, lgth + mov dx, offset string + mov al, 2 + mov ah, 5EH + int 21H + endm + + +Example: + +The following program defines a printer-setup string that consists of the +control character to print expanded type on Epson-compatible printers. +The printer cancels this mode at the first carriage return, so the effect is to +print the first line of each file sent to the network printer as a title in +expanded characters. The setup string is one character. This example +assumes that the printer is the entry number 3 (the fourth entry) in the +assign list. Use Function 5F02H (Get Assign-List Entry) to determine this +value. + +setup db 0EH +; +begin: printer_setup 3,1,setup ;THIS FUNCTION + jc error ;routine not shown + + + + 29 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Assign-List Entry (Function 5FH, Code +02H) + + Call: + + AH = 5FH + AL = 02H + BX + Assign-list index + DS:SI + Pointer to buffer for local name + ES:DI + Pointer to buffer for remote name + + Return: + + Carry set: + AX + 1 = Invalid function code + 18 = No more files + Carry not set: + BL + 3 = Printer + 4 = Drive + CX + Stored user value + + +Comments: + +Function 5FH, Code 02H, retrieves the specified entry from the network +list of assignments. BX must contain the assign-list index (entry 0 is the +first entry). SI must contain the offset (to the segment address in DS) of a +16-byte buffer for the local name. DI must contain the offset (to the seg- +ment address in ES) of a 128-byte buffer for the remote name. Microsoft +Networks must be running. + +MS-DOS puts the local name in the buffer pointed to by DS:SI and the +remote name in the buffer pointed to by ES:DI. The local name can be a +null ASCIZ string. BL returns 3 if the local device is a printer or 4 if the +local device is a drive. CX returns the stored user value set with Function +5F03H (Make Assign-List Entry). The contents of the assign list can +change between calls. + +You can use this function request to retrieve any entry, or to make a copy +of the complete list by stepping through the table. To detect the end of +the assign list, check for error code 18 (no more files), as you would when +stepping through a directory by using Functions 4EH (Find First File) and + +30 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +4FH (Find Next File). + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 Microsoft Networks must be running to use this function request. + +18 The index passed in BX is greater than the number of entries in the + assign list. + + +Macro Definition: + + +get_list macro index,local,remote + mov bx, index + mov si, offset local + mov di, offset remote + mov al,2 + mov ah, 5FH + int 21H + endm + + +Example: + +The following program displays the assign list on a Microsoft Networks +workstation, showing the local name, remote name, and device type (drive +or printer) for each entry. + +stdout equ 1 +printer equ 3 +; +local_nm db 16 dup (?),2 dup (20h) +remote_nm db 128 dup (?),2 dup (20h) +header db "Local name",8 dup (20h) + db "Remote name",7 dup (20h) + db "Device Type" +crlf db 0dh,0ah,0dh,0ah +drive_msg db "drive" +print_msg db "printer" +index dw ? +; +begin: write_handle stdout,header,51 ;see Function 40H + jc write_error ;routine not shown + mov index,0 ;assign list index +ck_list: get_list index,local_nm,remote_nm ;THIS FUNCTION + jnc got_one ;got an entry +error: cmp ax,18 + je last_one ;yes + jmp error ;routine not shown +got_one: push bx ;save device type + + 31 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + write_handle stdout,local_nm,148 ;see Function 40H + jc write_error ;routine not shown + pop bx ;get device type + cmp bl,printer ;is it a printer? + je prntr ;yes + write_handle stdout,drive_msg,5 ;see Function 40H + jc write_error ;routine not shown + jmp get_next ;finish message +prntr: write_handle stdout,print_msg,7 ;see Function 40H + jc write_error ;routine not shown +get_next: write_handle stdout,crlf,2 ;see Function 40H + jc write_error ;routine not shown + inc index ;bump index + jmp ck_list ;get next entry +last_one: write_handle stdout,crlf,4 ;see Function 40H + jc write_error ;routine not shown +; + + + +32 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Make Assign-List Entry (Function 5FH, Code +03H) + + Call: + + AH = 5FH + AL = 03H + BL + 3 = Printer + 4 = Drive + CX + User value + DS:SI + Pointer to name of source device + ES:DI + Pointer to name of destination + device + + Return: + + Carry set: + AX + 1 = Invalid function code + 5 = Access denied + 3 = Path not found + 8 = Insufficient memory + (Other errors particular to the + network may occur.) + Carry not set: + No error + + +Comments: + +Function 5FH, Code 03H, redirects a printer or disk drive (source device) +to a network directory (destination device). BL must contain 3 if the +source device is a printer or 4 if it is a disk drive. SI must contain the +offset (to the segment address in DS) of an ASCIZ string that specifies the +name of the printer, or a drive letter followed by a colon, or a null string +(one byte of 00H). DI must contain the offset (to the segment address in +ES) of an ASCIZ string that specifies the name of a network directory. CX +contains a user-specified 16-bit value that MS-DOS maintains. Microsoft +Networks must be running. + +The destination string must be an ASCIZ string of the following form: + +machine-name pathname 00H password 00H + + + 33 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +where: + +Machine-name is the net name of the server that contains the network +directory; + +Pathname is the alias of the network directory (not the directory path) to +which the source device is to be redirected; + +00H is a null byte; and + +Password is the password for access to the network directory. If no pass- +word is specified, both null bytes must immediately follow the pathname. + +If BL=3, the source string must be PRN, LPT1, LPT2, or LPT3. This +function buffers and sends all output for the named printer to the remote- +printer spooler named in the destination string. + +If BL=4, the source string can be either a drive letter followed by a colon, +or a null string. If the source string contains a valid drive letter and colon, +this call redirects all subsequent drive-letter references to the network +directory named in the destination string. If the source string is a null +string, MS-DOS attempts to grant access to the network directory with +the specified password. + +The maximum length of the destination string is 128 bytes. You can +retrieve the value in CX by using Function 5FH, Code 02H (Get Assign- +List Entry). + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + Meaning +_ ________________________________________________________________ + +1 Microsoft Networks must be running to use this function request; + the value in BX is not 1 to 4, the source string is in the wrong for- + mat; the destination string is in the wrong format; or the source + device is already redirected. + +3 The network directory path is invalid or doesn't exist. + +5 The network directory/password combination is not valid. This + does not mean that the password itself was invalid; the directory + might not exist on the server. + +8 There is not enough memory for string substitutions. + + + +34 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Macro Definition: + + +redir macro device,value,source,destination + mov bl, device + mov cx, value + mov si, offset source + mov es, seg destination + mov di, offset destination + mov al, 03H + mov ah, 5FH + int 21H + endm + + + + 35 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Example: + +The following program redirects two drives and a printer from a worksta- +tion to a server named harold. It assumes the machine name, directory +names, and driver letters shown: + +Local drive Netname +or printer on server Password + +E: WORD none +F: COMM fred +PRN: PRINTER quick + +printer equ 3 +drive equ 4 +; +local_1 db "e:",0 +local_2 db "f:",0 +local_3 db "prn",0 +remote_1 db "\harold\word",0,0 +remote_2 db "\harold\comm",0,"fred",0 +remote_3 db "\harold\printer",0,"quick",0 +; +begin: redir local_1,remote_1,drive,0 ;THIS FUNCTION + jc error ;routine not shown + redir local_2,remote_2,drive,0 ;THIS FUNCTION + jc error ;routine not shown + redir local_3,remote_3,printer,0 ;THIS FUNCTION + jc error ;routine not shown + + + +36 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Cancel Assign-List Entry (Function 5FH, Code +04H) + + Call: + + AH = 5FH + AL = 04H + DS:SI + Pointer to name of source device + + Return: + + Carry set: + AX + 1 = Invalid function code + 15 = Redirection paused on server + (Other errors particular to the network + may occur.) + Carry not set: + No error + + + +Comments: + +Function 5FH, Code 04H, cancels the redirection of a printer or disk drive +(source device) to a network directory (destination device) made with +Function 5FH, Code 03H (Make Assign-List Entry). SI must contain the +offset (to the segment address in DS) of an ASCIZ string that specifies the +name of the printer or drive whose redirection is to be canceled. Microsoft +Networks must be running. + +The ASCIZ string pointed to by DS:SI can contain one of three values: + + o The letter of a redirected drive, followed by a colon. Cancels the + redirection and restores the drive to its physical meaning. + + o The name of a redirected printer (PRN, LPT1, LPT2, LPT3, or + their machine-specific equivalents). Cancels the redirection and + restores the printer name to its physical meaning. + + o A string starting with \\ (2 backslashes). Terminates the connec- + tion between the local machine and the network directory. + +If there is an error, the carry flag (CF) is set and the error code returns in +AX: + +Code + + 37 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + Meaning +_ ________________________________________________________________ + +1 Microsoft Networks must be running to use this function request; + or the ASCIZ string names a nonexistent source device. + +15 Disk or printer redirection on the network server is paused. + + +Macro Definition: + + +cancel_redir macro local + mov si, offset local + mov al, 4 + mov ah, 5FH + int 21H + endm + + +Example: + +The following program cancels the redirection of drives E and F and the +printer (PRN) of a Microsoft Networks workstation. It assumes that these +local devices were redirected previously. + +local_1 db "e:",0 +local_2 db "f:",0 +local_3 db "prn",0 +; +begin: cancel_redir local_1 ;THIS FUNCTION + jc error ;routine not shown + cancel_redir local_2 ;THIS FUNCTION + jc error ;routine not shown + cancel_redir local_3 ;THIS FUNCTION + jc error ;routine not shown + + + +38 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Get PSP (Function 62H) + + Call: + + AH = 62H + + Return: + + BX + Segment address of the Program + Segment Prefix of the current process + + + +Comments: + +Function 62H retrieves the segment address of the currently active process +(the start of the Program Segment Prefix). The address returns in BX. + +Macro Definition: + + +get_psp macro + mov ah, 62H + int 21H + endm + + +Example: + +The following program displays the segment address of its Program Seg- +ment Prefix (PSP) in hexadecimal. + +msg db "PSP segment address: H",0DH,0AH,"$" +; +begin: get_psp ;THIS FUNCTION + convert bx,16,msg[21] ;see end of chapter + display msg ;see Function 09H + + + + 39 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Get Extended Country Information (Function +65H) + + Call: + + AH = 65H + AL + Function (minor) code + BX + Code page (-1 = active CON device) + CX + Amount of data to return + DX + Country ID for which information is to be returned + (-1=default country) + ES:DI + Address of country information buffer + + Return: + + 1 = Buffer has been filled + 2 = File not found + + +Comments: + +Function 65H retrieves standard country information. This information +includes country ID, code page, date and time format, currency symbol, +separators (for thousands, decimals, data list, date and time) currency for- +mat flags, digits in currency, and case-mapping information. + +The function code passed in AL may be one of the following: + +Code + Description +_ ________________________________________________________________ + +1 Return standard information + +2 Return pointer to uppercase table + +3 Return pointer to filename uppercase table + +4 Return pointer to collating table + +5 Reserved (no entry) + +6 Return pointer to collating sequence + + + +40 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +MS-DOS 3.3 provides more country-dependent information than previous +versions of MS-DOS. Only the information for the default country is kept +in the kernel. Country-dependent information for all other countries is +contained in the country.sys file. The MS-DOS nlsfunc command is used +to access the country-dependent information in country.sys using this call. +If the country code and code page number do not match, or if either is +invalid, error code 2 is returned to AX. If CX is less than 5, error code 1 is +returned. If the amount of information requested is greater than the value +of CX, only CX bytes are returned and no error is reported. + +If AL = 1, the buffer is filled with the following information: + +db 1 ; Information ID +dw ? ; Size (<=38) +dw ? ; Country ID +dw ? ; Code page + +If AL = 2, the buffer is filled with the following information: + +db 2 ; Information ID +dd ? ; Double-word pointer to uppercase table + +If AL = 4, the buffer is filled with the following information: + +db 4 ; Information ID +dd ? ; Double-word pointer to filename uppercase table + +Both of these tables consist of a length field (two bytes) followed by 128 +uppercase values for the upper 128 ASCII characters. The following for- +mula is used to compute the address of an uppercase equivalent in the +table: + +Address of outchar = inchar - (256-table_len) = table_start + +where: + +Parameter + Meaning +_ ________________________________________________________________ + +inchar Character to be generated + +table_len Length of list of uppercase values (two bytes) + +table_start Starting address of uppercase table + +outchar Uppercase value for inchar + +If inchar is greater than or equal to (256 - table_len), there is an uppercase +equivalent in the table; otherwise, there is not. + + + + 41 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +If AL = 6, the buffer is filled with the following information: + +db 6 ; Information ID +dd ? ; Double-word pointer to collating sequence + +The table is 258 bytes long. The first word is the length of the table. The +rest of the table is 256 ASCII values in the appropriate order. + + +42 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Get/Set Global Code Page (Function 66H) + + Call: + + AH = 66H + AL + Function (minor) code + BX + Code page to set (AL = 2) + + Return: + + Carry set: + AX + 02 = File not found + 65 = Device not selected + Carry not set: + No error + + + +Comments: + +Function 66H gets or sets the code page used by the kernel and all devices. +If no other code page has been set, this function gets the default code page +from DX. If another code page is set, this function retrieves the active +code page from BX. + +The MS-DOS nlsfunc command and country.sys must be on the system if +this function is to be used to change the global code page. + +The function code may be one of the following: + +Code + Description +_ ________________________________________________________________ + +1 Get code page + +2 Set code page + +MS-DOS gets the new code page from the country.sys file. Devices must be +prepared for code page switching before a code page can be selected. To +prepare a device, a device driver that supports code page switching must +be installed by using the device command in the config.sys file. The user + + 43 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +must also use the prepare keyword with the MS-DOS mode command to +prepare the device for code page switching. + +The code page selected must be compatible with the country code specified +in the config.sys file. If MS-DOS cannot read country.sys or other specified +country information file, error code 02 is returned to AX. + + +44 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Set Handle Count (Function 67H) + + Call: + + AH = 67H + BX + Number of allowed handles + + Return: + + Carry set: + AX + Carry not set: + No error + + + +Comments: + +Function 67H increases or decreases the number of files a program can +have open at one time. The maximum number of files handles is 64K. If +less than 20 are specified, the minimum handle number, 20, is assumed. If +this call is used to reduce the number of allowed handles, the new limit +does not take affect until any handles above the new limit are closed. + +The user should use Call 4AH (Set Block) to allocate memory for the +extended handle list if BX is greater than 255. The maximum number for +the value of the config.sys command files is 255. + + + 45 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Commit File (Function 68H) + + Call: + + AH = 68H + BX + File handle + + Return: + + Carry set: + AX = error + Carry not set + No error + + + +Comments: + +Function 68H flushes all buffered data for a file without closing it. Using +this call is more efficient than using the traditional close-open sequence, +and is more effective for network environments. This call makes sure that +the disk image of a file is current. + + +46 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +; Macro Definitions for MS-DOS System Call Examples +; +;******************* +; Interrupts +;******************* +; Interrupt 25H +ABS_DISK_READ macro disk,buffer,num_sectors,first_sector + mov al,disk + mov bx,offset buffer + mov cx,num_sectors + mov dx,first_sector + int 25H + popf + endm +; Interrupt 26H +ABS_DISK_WRITE macro disk,buffer,num_sectors,first_sector + mov al,disk + mov bx,offset buffer + mov cx,num_sectors + mov dx,first_sector + int 26H + popf + endm +; Interrupt 27H +STAY_RESIDENT macro last_instruc + mov dx,offset last_instruc + inc dx + int 27H + endm +; +; +;******************* +; Function Requests +;******************* +; Function Request 00H +TERMINATE_PROGRAM macro + xor ah,ah + int 21H + endm +; Function Request 01H +READ_KBD_AND_ECHO macro + mov ah,01H + int 21H + endm +; Function Request 02H +DISPLAY_CHAR macro character + mov dl,character + mov ah,02H + int 21H + endm +; Function Request 03H +AUX_INPUT macro + mov ah,03H + int 21H + endm +; Function Request 04H + + 47 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +AUX_OUTPUT macro + mov ah,04H + int 21H + endm +; Function Request 05H +PRINT_CHAR macro character + mov dl,character + mov ah,05H + int 21H + endm +; Function Request 06H +DIR_CONSOLE_IO macro switch + mov dl,switch + mov ah,06H + int 21H + endm +; Function Request 07H +DIR_CONSOLE_INPUT macro + mov ah,07H + int 21H + endm +; Function Request 08H +READ_KBD macro + mov ah,08H + int 21H + endm +; Function Request 09H +DISPLAY macro string + mov dx,offset string + mov ah,09H + int 21H + endm +; Function Request 0AH +GET_STRING macro limit,string + mov dx,offset string + mov string,limit + mov ah,0AH + int 21H + endm +; Function Request 0BH +CHECK_KBD_STATUS macro + mov ah,0BH + int 21H + endm +; Function Request 0CH +FLUSH_AND_READ_KBD macro switch + mov al,switch + mov ah,0CH + int 21H + endm +; Function Request 0DH +RESET_DISK macro + mov ah,0DH + int 21H + endm +; Function Request 0EH + +48 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +SELECT_DISK macro disk + mov dl,disk[-65] + mov ah,0EH + int 21H + endm +; Function Request 0FH +OPEN macro fcb + mov dx,offset fcb + mov ah,0FH + int 21H + endm +; Function Request 10H +CLOSE macro fcb + mov dx,offset fcb + mov ah,10H + int 21H + endm +; Function Request 11H +SEARCH_FIRST macro fcb + mov dx,offset fcb + mov ah,11H + int 21H + endm +; Function Request 12H +SEARCH_NEXT macro fcb + mov dx,offset fcb + mov ah,12H + int 21H + endm +; Function Request 13H +DELETE macro fcb + mov dx,offset fcb + mov ah,13H + int 21H + endm +; Function Request 14H +READ_SEQ macro fcb + mov dx,offset fcb + mov ah,14H + int 21H + endm +; Function Request 15H +WRITE_SEQ macro fcb + mov dx,offset fcb + mov ah,15H + int 21H + endm +; Function Request 16H +CREATE macro fcb + mov dx,offset fcb + mov ah,16H + int 21H + endm +; Function Request 17H +RENAME macro fcb,newname + mov dx,offset fcb + + 49 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + mov ah,17H + int 21H + endm +; Function Request 19H +CURRENT_DISK macro + mov ah,19H + int 21H + endm +; Function Request 1AH +SET_DTA macro buffer + mov dx,offset buffer + mov ah,1AH + endm +; Function Request 1BH +DEF_DRIVE_DATA macro + mov ah,1BH + int 21H + endm +; Function Request 1CH +DRIVE_DATA macro drive + mov dl,drive + mov ah,1CH + int 21H + endm +; Function Request 21H +READ_RAN macro fcb + mov dx,offset fcb + mov ah,21H + int 21H + endm +; Function Request 22H +WRITE_RAN macro fcb + mov dx,offset fcb + mov ah,22H + int 21H + endm +; Function Request 23H +FILE_SIZE macro fcb + mov dx,offset fcb + mov ah,23H + int 21H + endm +; Function Request 24H +SET_RELATIVE_RECORD macro fcb + mov dx,offset fcb + mov ah,24H + int 21H + endm +; Function Request 25H +SET_VECTOR macro interrupt,handler_start + mov al,interrupt + mov dx,offset handler_start + mov ah,25H + int 21H + endm +; Function Request 26H + +50 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +CREATE_PSP macro seg_addr + mov dx,offset seg_addr + mov ah,26H + int 21H + endm +; Function Request 27H +RAN_BLOCK_READ macro fcb,count,rec_size + mov dx,offset fcb + mov cx,count + mov word ptr fcb[14],rec_size + mov ah,27H + int 21H + endm +; Function Request 28H +RAN_BLOCK_WRITE macro fcb,count,rec_size + mov dx,offset fcb + mov cx,count + mov word ptr fcb[14],rec_size + mov ah,28H + int 21H + endm +; Function Request 29H +PARSE macro string,fcb + mov si,offset string + mov di,offset fcb + push es + push ds + pop es + mov al,0FH + mov ah,29H + int 21H + pop es + endm +; Function Request 2AH +GET_DATE macro + mov ah,2AH + int 21H + endm +; Function Request 2BH +SET_DATE macro year,month,day + mov cx,year + mov dh,month + mov dl,day + mov ah,2BH + int 21H + endm +; Function Request 2CH +GET_TIME macro + mov ah,2CH + int 21H + endm +; Function Request 2DH +SET_TIME macro hour,minutes,seconds,hundredths + mov ch,hour + mov cl,minutes + mov dh,seconds + + 51 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + mov dl,hundredths + mov ah,2DH + int 21H + endm +; Function Request 2EH +VERIFY macro switch + mov al,switch + mov ah,2EH + int 21H + endm +; Function Request 2FH +GET_DTA macro + mov ah,2FH + int 21H + endm +; Function Request 30H +GET_VERSION macro + mov ah,30H + int 21H + endm +; Function Request 31H +KEEP_PROCESS macro return_code,last_byte + mov al,return_code + mov dx,offset last_byte + mov cl,4 + shr dx,cl + inc dx + mov ah,31H + int 21H + endm +; Function Request 33H +CTRL_C_CK macro action,state + mov al,action + mov dl,state + mov ah,33H + int 21H + endm +; Function Request 35H +GET_VECTOR macro interrupt + mov al,interrupt + mov ah,35H + int 21H + endm +; Function Request 36H +GET_DISK_SPACE macro drive + mov dl,drive + mov ah,36H + int 21H + endm +; Function Request 38H +GET_COUNTRY macro country,buffer + local gc_01 + mov dx,offset buffer + mov ax,country + cmp ax,0FFH + jl gc_01 + +52 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + mov al,0ffh + mov bx,country +gc_01: mov ah,38H + int 21H + endm +; Function Request 38H +SET_COUNTRY macro country + local sc_01 + mov dx,0FFFFH + mov ax,country + cmp ax,0FFH + jl sc_01 + mov al,0ffh + mov bx,country +sc_01: mov ah,38H + int 21H + endm +; Function Request 39H +MAKE_DIR macro path + mov dx,offset path + mov ah,39H + int 21H + endm +; Function Request 3AH +REM_DIR macro path + mov dx,offset path + mov ah,3AH + int 21H + endm +; Function Request 3BH +CHANGE_DIR macro path + mov dx,offset path + mov ah,3BH + int 21H + endm +; Function Request 3CH +CREATE_HANDLE macro path,attrib + mov dx,offset path + mov cx,attrib + mov ah,3CH + int 21H + endm +; Function Request 3DH +OPEN_HANDLE macro path,access + mov dx,offset path + mov al,access + mov ah,3DH + int 21H + endm +; Function Request 3EH +CLOSE_HANDLE macro handle + mov bx,handle + mov ah,3EH + int 21H + endm +; Function Request 3FH + + 53 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +READ_HANDLE macro handle,buffer,bytes + mov bx,handle + mov dx,offset buffer + mov cx,bytes + mov ah,3FH + int 21H + endm +; Function Request 40H +WRITE_HANDLE macro handle,buffer,bytes + mov bx,handle + mov dx,offset buffer + mov cx,bytes + mov ah,40H + int 21H + endm +; Function Request 41H +DELETE_ENTRY macro path + mov dx,offset path + mov ah,41H + int 21H + endm +; Function Request 42H +MOVE_PTR macro handle,high,low,method + mov bx,handle + mov cx,high + mov dx,low + mov al,method + mov ah,42H + int 21H + endm +; Function Request 43H +CHANGE_MODE macro path,action,attrib + mov dx,offset path + mov al,action + mov cx,attrib + mov ah,43H + int 21H + endm +; Function Request 4400H,01H +IOCTL_DATA macro code,handle + mov bx,handle + mov al,code + mov ah,44H + int 21H + endm +; Function Request 4402H,03H +IOCTL_CHAR macro code,handle,buffer + mov bx,handle + mov dx,offset buffer + mov al,code + mov ah,44H + int 21H + endm +; Function Request 4404H,05H +IOCTL_STATUS macro code,drive,buffer + mov bl,drive + +54 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + mov dx,offset buffer + mov al,code + mov ah,44H + int 21H + endm +; Function Request 4406H,07H +IOCTL_STATUS macro code,handle + mov bx,handle + mov al,code + mov ah,44H + int 21H + endm +; Function Request 4408H +IOCTL_CHANGE macro drive + mov bl,drive + mov al,08H + mov ah,44H + int 21H + endm +; Function Request 4409H +IOCTL_RBLOCK macro drive + mov bl,drive + mov al,09H + mov ah,44H + int 21H + endm +; Function Request 440AH +IOCTL_RHANDLE macro handle + mov bx,handle + mov al,0AH + mov ah,44H + int 21H + endm +; Function Request 440BH +IOCTL_RETRY macro retries,wait + mov dx,retries + mov cx,wait + mov al,0BH + mov ah,44H + int 21H + endm +; Function Request 440CH +GENERIC_IOCTL_HANDLES macro handle,function,category,buffer + mov ch,05H + mov cl,function + mov dx,offset buffer + mov bx,handle + mov ah,44H + mov al,0CH + int 21H + endm +; Function Request 440DH +GENERIC_IOCTL_BLOCK macro drive_num,function,category,parm_blk + mov ch,08H + mov cl,function + mov dx,offset parm_blk - 1 + + 55 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + mov bx,drive_num + mov ah,44H + mov al,0DH + int 21H + endm +; Function Request 440EH +IOCTL_GET_DRIVE_MAP macro logical_drv + mov bx,logical_drv + mov ah,44H + mov al,0EH + int 21H + endm +; Function Request 440FH +IOCTL_SET_DRIVE_MAP macro logical_drv + mov bx,logical_drv + mov ah,44H + mov al,0FH + int 21H + endm +; Function Request 45H +XDUP macro handle + mov bx,handle + mov ah,45H + int 21H + endm +; Function Request 46H +XDUP2 macro handle1,handle2 + mov bx,handle1 + mov cx,handle2 + mov ah,46H + int 21H + endm +; Function Request 47H +GET_DIR macro drive,buffer + mov dl,drive + mov si,offset buffer + mov ah,47H + int 21H + endm +; Function Request 48H +ALLOCATE_MEMORY macro bytes + mov bx,bytes + mov cl,4 + shr bx,cl + inc bx + mov ah,48H + int 21H + endm +; Function Request 49H +FREE_MEMORY macro seg_addr + mov ax,seg_addr + mov es,ax + mov ah,49H + int 21H + endm +; Function Request 4AH + +56 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + +SET_BLOCK macro last_byte + mov bx,offset last_byte + mov cl,4 + shr bx,cl + add bx,17 + mov ah,4AH + int 21H + mov ax,bx + shl ax,cl + dec ax + mov sp,ax + mov bp,sp + endm +; Function Request 4B00H +EXEC macro path,command,parms + mov dx,offset path + mov bx,offset parms + mov word ptr parms[02h],offset command + mov word ptr parms[04h],cs + mov word ptr parms[06h],5ch + mov word ptr parms[08h],es + mov word ptr parms[0ah],6ch + mov word ptr parms[0ch],es + mov al,0 + mov ah,4BH + int 21H + endm +; Function Request 4B03H +EXEC_OVL macro path,parms,seg_addr + mov dx,offset path + mov bx,offset parms + mov parms,seg_addr + mov parms[02H],seg_addr + mov al,3 + mov ah,4BH + int 21H + endm +; Function Request 4CH +END_PROCESS macro return_code + mov al,return_code + mov ah,4CH + int 21H + endm +; Function Request 4DH +RET_CODE macro + mov ah,4DH + int 21H + endm +; Function Request 4EH +FIND_FIRST_FILE macro path,attrib + mov dx,offset path + mov cx,attrib + mov ah,4EH + int 21H + endm +; Function Request 4FH + + 57 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +FIND_NEXT_FILE macro + mov ah,4FH + int 21H + endm +; Function Request 54H +GET_VERIFY macro + mov ah,54H + int 21H + endm +; Function Request 56H +RENAME_FILE macro old_path,new_path + mov dx,offset old_path + push ds + pop es + mov di,offset new_path + mov ah,56H + int 21H + endm +; Function Request 57H +GET_SET_DATE_TIME macro handle,action,time,date + mov bx,handle + mov al,action + mov cx,word ptr time + mov dx,word ptr date + mov ah,57H + int 21H + endm +; Function Request 58H +ALLOC_STRAT macro code,strategy + mov bx,strategy + mov al,code + mov ah,58H + int 21H + endm +; Function Request 59H +GET_ERROR macro + mov ah,59 + int 21H + endm +; Function Request 5AH +CREATE_TEMP macro pathname,attrib + mov cx,attrib + mov dx,offset pathname + mov ah,5AH + int 21H + endm +; Function Request 5BH +CREATE_NEW macro pathname,attrib + mov cx,attrib + mov dx,offset pathname + mov ah,5BH + int 21H + endm +; Function Request 5C00H +LOCK macro handle,start,bytes + mov bx,handle + +58 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + mov cx,word ptr start + mov dx,word ptr start+2 + mov si,word ptr bytes + mov di,word ptr bytes+2 + mov al,0 + mov ah,5CH + int 21H + endm +; Function Request 5C01H +UNLOCK macro handle,start,bytes + mov bx,handle + mov cx,word ptr start + mov dx,word ptr start+2 + mov si,word ptr bytes + mov di,word ptr bytes+2 + mov al,1 + mov ah,5CH + int 21H + endm +; Function Request 5E00H +GET_MACHINE_NAME macro buffer + mov dx,offset buffer + mov al,0 + mov ah,5EH + int 21H + endm +; Function Request 5E02H +PRINTER_SETUP macro index,lgth,string + mov bx,index + mov cx,lgth + mov dx,offset string + mov al,2 + mov ah,5EH + int 21H + endm +; Function Request 5F02H +GET_LIST macro index,local,remote + mov bx,index + mov si,offset local + mov di,offset remote + mov al,2 + mov ah,5FH + int 21H + endm +; Function Request 5F03H +REDIR macro device,value,source,destination + mov bl,device + mov cx,value + mov si,offset source + mov es,seg destination + mov di,offset destination + mov al,03H + mov ah,5FH + int 21H + endm +; Function Request 5F04H + + 59 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +CANCEL_REDIR macro local + mov si,offset local + mov al,4 + mov ah,5FH + int 21H + endm +; Function Request 62H +GET_PSP macro + mov ah,62H + int 21H + endm +; +; +;******************* +; General +;******************* +; +DISPLAY_ASCIIZ macro asciiz_string + local search,found_it + mov bx,offset asciiz_string + +search: + cmp byte ptr [bx],0 + je found_it + inc bx + jmp short search + +found_it: + mov byte ptr [bx],"$" + display asciiz_string + mov byte ptr [bx],0 + display_char 0DH + display_char 0AH + endm +; +MOVE_STRING macro source,destination,count + push es + push ds + pop es + assume es:code + mov si,offset source + mov di,offset destination + mov cx,count + rep movs es:destination,source + assume es:nothing + pop es + endm +; +CONVERT macro value,base,destination + local table,start + jmp start +table db "0123456789ABCDEF" + +start: + push ax + push bx + +60 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + push dx + mov al,value + xor ah,ah + xor bx,bx + div base + mov bl,al + mov al,cs:table[bx] + mov destination,al + mov bl,ah + mov al,cs:table[bx] + mov destination[1],al + pop dx + pop bx + pop ax + endm +; +CONVERT_TO_BINARY macro string,number,value + local ten,start,calc,mult,no_mult + jmp start +ten db 10 + +start: + mov value,0 + xor cx,cx + mov cl,number + xor si,si + +calc: + xor ax,ax + mov al,string[si] + sub al,48 + cmp cx,2 + jl no_mult + push cx + dec cx + +mult: + mul cs:ten + loop mult + pop cx + +no_mult: + add value,ax + inc si + loop calc + endm +; +CONVERT_DATE macro dir_entry + mov dx,word ptr dir_entry[24] + mov cl,5 + shr dl,cl + mov dh,dir_entry[24] + and dh,1FH + xor cx,cx + mov cl,dir_entry[25] + shr cl,1 + + 61 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + add cx,1980 + endm +; +PACK_DATE macro date + local set_bit +; +; On entry: DH=day, DL=month, CX=(year-1980) +; + sub cx,1980 + push cx + mov date,dh + mov cl,5 + shl dl,cl + pop cx + jnc set_bit + or cl,80h + +set_bit: + or date,dl + rol cl,1 + mov date[1],cl + endm +; + + + +62 + +_ _ | | _ _ + + + diff --git a/PROGREF/2_DEVDR.A b/PROGREF/2_DEVDR.A new file mode 100644 index 0000000..337f098 --- /dev/null +++ b/PROGREF/2_DEVDR.A @@ -0,0 +1,3558 @@ + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + +2.1 Introduction + +The io.sys file comprises the "resident" device drivers, which form the +MS-DOS BIOS. These drivers are called upon by MS-DOS to handle +input/output (I/O) requests initiated by application programs. + +One of the most powerful features of MS-DOS is the ability to add new +devices such as printers, plotters, and mouse input devices without rewrit- +ing the BIOS. The MS-DOS BIOS is configurable; that is, new drivers can +be added and existing drivers can be preempted. Nonresident, or install- +able, device drivers may be easily added at boot time by including a +device command line in the config.sys file. + +At boot time, a minimum of five resident device drivers must be present. +These drivers are in a linked list: the header of each one contains a +DWORD pointer to the next. The last driver in the chain has an end-of-list +marker of -1, -1 (all bits on). + +Each driver in the chain has two entry points: the strategy entry point and +the interrupt entry point. MS-DOS does not take advantage of the two +entry points: it calls the strategy routine, then immediately calls the inter- +rupt routine. + +The dual entry points will accomodate future multitasking versions of +MS-DOS and MS OS/2 operating systems. In multitasking environments, +I/O must be asynchronous; to accomplish this, the strategy routine will be +called to (internally) queue a request and return quickly. It is then the +responsibility of the interrupt routine to perform the I/O at interrupt time +by getting requests from the internal queue and processing them. When a +request is completed, it is flagged as "done" by the interrupt routine. +MS-DOS periodically scans the list of requests looking for those that are +flagged as done, and "wakes up" the process waiting for the completion of +the request. + +When requests are queued in this manner, it is no longer sufficient to pass +I/O information in registers, since many requests may be pending at any +time. Therefore, the MS-DOS device interface uses "packets" to pass +request information. These request packets are of variable size and for- +mat, and are composed of two parts: + + 1. The static request header section, which has the same format for + all requests + + 2. A section which has information specific to the type of request + +A driver is called with a pointer to a packet. In multitasking versions, this +packet will be linked into a global chain of all pending I/O requests main- +tained by MS-DOS. + + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +MS-DOS does not implement a global or local queue. Only one request is +pending at any one time. The strategy routine must store the address of +the packet at a fixed location, and the interrupt routine, which is called +immediately after the strategy routine, should process the packet by com- +pleting the request and returning. It is assumed that the request is com- +pleted when the interrupt routine returns. + +To make a device driver that sysinit can install, a .bin (core image) or .exe +format file must be created with the device driver header at the beginning +of the file. The link field should be initialized to -1 (sysinit fills it in). Dev- +ice drivers which are part of the BIOS should have their headers point to +the next device in the list and the last header should be initialized to +-1,-1. The BIOS must be a .bin (core image) format file. + +The .exe format installable device drivers may be used in non-IBM versions +of MS-DOS. On the IBM Personal Computer, the .exe loader is located in +command.com which is not present at the time that installable devices are +being loaded. + +2.2 Format of a Device Driver + +A device driver is a program segment responsible for communication +between DOS and the system hardware. It has a special header at the +beginning identifying it as a device driver, defining entry points, and +describing various attributes of the device. + +_ ________________________________________________________________ + +Note + + For device drivers, the file must not use the ORG 100H (like .com files). + Because it does not use the Program Segment Prefix (PSP), the device + driver is simply loaded; therefore, the file must have an origin of zero + (ORG 0 or no ORG statement). + +_ ________________________________________________________________ + +There are two kinds of device drivers: + + o Character device drivers + + o Block device drivers + +Character devices perform serial character I/O. Examples are the console, +communications port and printer. These devices are named (i.e., CON, +AUX, CLOCK, etc.), and programs may open channels (handles or file +control blocks) to do I/O to them. + + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +Block devices include all the disk drives on the system. They can perform +random I/O in structured pieces called blocks (usually the physical sector +size). These devices are not named as the character devices are, and there- +fore cannot be opened directly. Instead they have unit numbers and are +identified by drive letters such as A, B, and C. + +A single block device driver may be responsible for one or more logically +contiguous disk drives. For example, block device driver ALPHA may be +responsible for drives A, B, C, and D. This means that it has four units +defined (0-3), and therefore, takes up four drive letters. The position of +the driver in the list of all drivers determines which units correspond to +which driver letters. If driver ALPHA is the first block driver in the device +list, and it defines four units (0-3), then they will be A, B, C, and D. If +BETA is the second block driver and defines three units (0-2), then they +will be E, F, and G, and so on. The theoretical limit is 63, but it should be +noted that the device installation code will not allow the installation of a +device if it would result in a drive letter greater than Z (5AH). All block +device drivers present in the standard resident BIOS will be placed ahead +of installable block device drivers in the list. + +_ ________________________________________________________________ + +Note + + Because they have only one name, character devices cannot define mul- + tiple units. + +_ ________________________________________________________________ + + +2.3 How to Create a Device Driver + +To create a device driver that MS-DOS can install, you must create a +binary file (.com or .exe format) with a device header at the beginning of +the file. Note that for device drivers, the code should not be originated at +100H, but at 0. The device header contains a link field (a pointer to the +next device header) which should be -1, unless there is more than one dev- +ice driver in the file. The attribute field and entry points must be set +correctly. + +If it is a character device, the name field should be filled in with the name +of that character device. The name can be any legal eight-character +filename. If the name is less than eight characters, it should be padded out +to eight characters with spaces (20H). Note that device names do not +include colons (:). The fact that CON is the same as CON: is a property of +the default MS-DOS command interpreter (command.com) and not of the +device driver or the MS-DOS interface. All character device names are +handled in this way. + + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +MS-DOS always processes installable device drivers before handling the +default devices, so to install a new CON device, simply name the device +CON. Remember to set the standard input device and standard output +device bits in the attribute word on a new CON device. The scan of the +device list stops on the first match, so the installable device driver takes +precedence. + +It is not possible to replace the resident disk block device driver with an +installable device driver the same way you can replace the other device +drivers in the BIOS. Block drivers can be used only for devices not directly +supported by the default disk drivers in the io.sys file. + +_ ________________________________________________________________ + +Note + + Because MS-DOS can install the driver anywhere in memory, care must + be taken when making far memory references. You should not expect + that your driver will always be loaded in the same place every time. + +_ ________________________________________________________________ + + +2.3.1 Device Strategy Routine + +The device strategy routine, which is called by MS-DOS for each device +driver service request, is primarily responsible for queuing these requests in +the order in which they are to be processed by the device interrupt rou- +tine. Such queuing can be a very important performance feature in a mul- +titasking environment, or where asynchronous I/O is supported. As +MS-DOS does not currently support these facilities, only one request can +be serviced at a time, and this routine is usually very short. In the coding +examples in Section 2.12, "Two Sample Device Drivers," each request is +simply stored in a single pointer area. + +2.3.2 Device Interrupt Routine + +The device interrupt routine contains the code necessary to process the +service request. It may interface to the hardware, or it may use ROM +BIOS calls. It usually consists of a series of procedures that handle the +specific command codes to be supported as well as some exit and error- +handling routines. See the coding examples in Section 2.12, "Two Sample +Device Drivers." + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + +2.4 Installing Device Drivers + +MS-DOS allows new device drivers to be installed dynamically at boot +time. This is accomplished by initialization code in the io.sys file that +reads and processes the config.sys file. + +MS-DOS calls upon the device drivers to perform their function in the fol- +lowing manner: + + 1. MS-DOS makes a FAR call to the strategy entry. + + 2. MS-DOS passes device driver information in a request header to + the strategy routine. + + 3. MS-DOS makes a FAR call to the interrupt entry. + +This calling structure is designed to be easily upgraded to support any +future multitasking environment. + + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +2.5 Device Headers + +A device header is required at the beginning of a device driver. A device +header looks like this: + + +--------------------------------------+ + | DWORD Pointer to next device | + | (Usually set to -1 if this driver | + | is the last or only driver in the | + | file) | + +--------------------------------------+ + | WORD Attributes | + +--------------------------------------+ + | WORD Pointer to device strategy | + | entry point | + +--------------------------------------+ + | WORD Pointer to device interrupt | + | entry point | + +--------------------------------------+ + | 8-BYTE Character device name field | + | Character devices set a device name. | + | For block devices the first byte is | + | the number of units. | + +--------------------------------------+ + + + + Figure 2.1 Sample Device Header + +Note that the device entry points are words. They must be offsets from the +same segment number used to point to this table. For example, if xxx:yyy +points to the start of this table, then xxx:strategy and xxx:interrupt are the +entry points. + +The device header fields are described in the following section. + +2.5.1 Pointer to Next Device Field + +The pointer to the next device header field is a double-word field (offset +followed by segment) that is set by MS-DOS to point at the next driver in +the system list at the time the device driver is loaded. It is important that +this field be set to -1 prior to load (when it is on the disk as a file) unless +there is more than one device driver in the file. If there is more than one +driver in the file, the first word of the double-word pointer should be the +offset of the next driver's device header. + +_ ________________________________________________________________ + +Note + + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + If there is more than one device driver in the file, the last driver in the + file must have the pointer to the next device header field set to -1. + +_ ________________________________________________________________ + + +2.5.2 Attribute Field + +The attribute field is used to identify the type of device for which this +driver is responsible. In addition to distinguishing between block and +character devices, these bits are used to give selected character devices +special treatment. (Note that if a bit in the attribute word is defined only +for one type of device, a driver for the other type of device must set that +bit to 0.) + + +Table 2.1 + +For Character Devices: + +_ _________________________________________________________________________ + +Bit Value Meaning + +_ _________________________________________________________________________ + +0 1 Device is console input (sti) device +1 1 Device is console output (sto) device +2 1 Device is nul device +3 1 Device is clock device +4-5 Reserved (must be 0) +6 1 Device supports 3.2 functions +7-10 Reserved (must be 0) +11 1 Device understands Open/Close +12 Reserved (must be 0) +13 1 Device supports Output Until Busy (OUB) +14 1 Device supports IOCtl control strings +15 1 Character device + +_ _________________________________________________________________________ + +Table 2.2 + +For Block Devices: + +_ _________________________________________________________________________ + +Bit Value Meaning + +_ _________________________________________________________________________ + +0-5 Reserved (must be 0) +6 1 Device supports 3.2 functions and Generic IOCtl function calls +7-10 Reserved (must be 0) +11 1 Device understands Open/Close/Removable Media +12 Reserved (must be 0) +13 1 Device determines the media by examining the FATID byte +14 1 Device supports IOCtl control strings +15 0 Block device + +_ _________________________________________________________________________ + + + 9 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +For example, assume that you have a new device driver that you want to +use as the standard input and output. In addition to installing the driver, +you must tell MS-DOS that you want the new driver to override the +current standard input and standard output (the CON device). This is +accomplished by setting the attributes to the desired characteristics, so +you would set bits 0 and 1 to 1 (note that they are separate). Similarly, a +new CLOCK device could be installed by setting that attribute. (Refer to +Section 2.10, "The Clock Device," in this chapter for more information.) +Although there is a NUL device attribute, the NUL device cannot be reas- +signed. This attribute exists so that MS-DOS can determine if the NUL +device is being used. + +Bit 13 for block devices affects the operation of the Build BPB (BIOS +Parameter Block) device call. If set, it requires the first sector of the FAT +always to reside in the same place. This bit has a different meaning on +character devices. It indicates that the device implements the Output +Until Busy device call. + +The IOCtl bit (bit 14) has meaning on character and block devices. The +IOCtl functions allow data to be sent and received by the device for its +own use (to set baud rate, stop bits, form length, etc.) instead of passing +data over the device channel as a normal read or write does. The interpre- +tation of the passed information is up to the device but it must not be +treated as normal I/O. This bit tells MS-DOS whether the device can han- +dle control strings by using the IOCtl system call, Function 44H. + +If a driver cannot process control strings, it should initially set this bit to +0. This tells MS-DOS to return an error if an attempt is made (via Func- +tion 44H) to send or receive control strings to this device. A device which +can process control strings should initialize the IOCtl bit to 1. For drivers +of this type, MS-DOS will make calls to the IOCtl input and output device +functions to send and receive IOCtl strings. + +The IOCtl functions allow data to be sent and received by the device for +its own use (for example, to set baud rate, stop bits, and form length), +instead of passing data over the device channel as does a normal read or +write. The interpretation of the passed information is up to the device, but +it must not be treated as a normal I/O request. + +The Open/Close/Removable Media bit (bit 11) signals to MS-DOS 3.x +and later versions whether this driver supports additional MS-DOS 3.x +functionality. To support these old drivers, it is necessary to detect them. +This bit was reserved in MS-DOS 2.x, and is 0. All new devices should +support the Open, Close, and Removable Media calls and set this bit +to 1. Since MS-DOS 2.x never makes these calls, the driver will be +backward-compatible. + + + +10 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +The MS-DOS 3.2 bit (bit 6) signals whether the device supports logical +drive mapping via Function 440EH (Get Logical Drive Map) and Function +440FH (Set Logical Drive Map). This bit also supports generic IOCtl func- +tions via Function 440CH (Generic IOCtl for Handles) and Function +440DH (Generic IOCtl for Block Devices). + + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ++---------------------------------------------------------------+ +| C | I | | | O | | | | | 3 | | | C | N | S | S | +| H | O | | | P | | | | | . | | | L | U | T | T | +| R | C | | | N | | | | | 2 | | | K | L | O | I | ++---------------------------------------------------------------+ + + + Figure 2.2 Attribute Word for Character Devices + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ++---------------------------------------------------------------+ +| | I | F | | O | | | | | 3 | | | | | | | +| | O | A | | P | | | | | . | | | | | | | +| | C | T | | N | | | | | 2 | | | | | | | ++---------------------------------------------------------------+ + + + Figure 2.3 Attribute Word for Block Devices + + +2.5.3 Strategy and Interrupt Routines + +These two fields are the pointers to the entry points of the strategy and +interrupt routines. They are word values, so they must be in the same seg- +ment as the device header. + +2.5.4 Name Field + +This is an eight-byte field that contains the name of a character device or +the number of units of a block device. If the field refers to a block device, +the number of units can be put in the first byte. This is optional, because +MS-DOS will fill in this location with the value returned by the driver's +Init code. For more information, see Section 2.4, "Installing Device +Drivers." + +2.6 Request Header + +When MS-DOS calls a device driver to perform a function, it passes a +request header in ES:BX to the strategy entry point. This is a fixed length +header, followed by data pertinent to the operation being performed. +Note that it is the device driver's responsibility to preserve the machine + + 11 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +state (for example, save all registers, including flags, on entry, and restore +them on exit). There is enough room on the stack when the strategy or +interrupt routine is called to do about 20 pushes. If more room on the +stack is needed, the driver should set up its own stack. + +The following figure illustrates a request header. + +REQUEST HEADER -> + +-----------------------------+ + | BYTE Length of record | + | Length in bytes of this | + | request header | + +-----------------------------+ + | BYTE Unit code | + | The subunit the operation | + | is for (minor device) | + | (no meaning on character | + | devices) | + +-----------------------------+ + | BYTE Command code | + +-----------------------------+ + | WORD Status | + +-----------------------------+ + | 8 BYTES Reserved | + | | + |-----------------------------| + + + Figure 2.4 Request Header + +The request header fields are described below. + +2.6.1 Length of Record + +This field contains the length (in bytes) of the request header. + +2.6.2 Unit Code Field + +The unit code field identifies which unit in your device driver the request is +for. For example, if your device driver has three units defined, then the +possible values of the unit code field would be 0, 1, and 2. + +2.6.3 Command Code Field + +The command code field in the request header can have the following +values: + +Code + Function +_ ________________________________________________________________ + +12 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +0 Init + +1 Media Check (Block devices only) + +2 Build BPB (Block devices only) + +3 IOCtl Input (Only called if device has IOCtl) + +4 Input (Read) + +5 Non-destructive Read, No Wait (Character devices only) + +6 Input Status (Character devices only) + +7 Input Flush (Character devices only) + +8 Output (Write) + +9 Output (Write) with Verify + +10 Output Status (Character devices only) + +11 Output Flush (Character devices only) + +12 IOCtl Output (Only called if device has IOCtl) + +13 Device Open (Only called if Open/Close/Removable Media + bit set) + +14 Device Close (Only called if Open/Close/Removable Media + bit set) + +15 Removable Media (Only called if Open/Close/Removable + Media bit set and device is block) + +16 Output Until Busy (Only called if bit 13 is set on character dev- + ices) + +19 Generic IOCtl Request + +23 Get Logical Device + +24 Set Logical Device + + +2.6.4 Status Field + +The following figure illustrates the status field in the request header. + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ + | E | | B | D | | + | R | Reserved | U | O | Error code (bit 15 on)| + | R | | S | N | | + | | | Y | E | | + +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ + +The status word is zero on entry and is set by the driver interrupt routine +on return. + + + 13 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +Bit 8 is the done bit. When set, it means the operation has completed. The +driver sets it to 1 when it exits. + +Bit 15 is the error bit. If it is set, then the low eight bits indicate the +error. The errors are as follows: + +Error + Meaning +_ ________________________________________________________________ + +0 Write protect violation + +1 Unknown unit + +2 Drive not ready + +3 Unknown command + +4 CRC error + +5 Bad drive request structure length + +6 Seek error + +7 Unknown media + +8 Sector not found + +9 Printer out of paper + +A Write fault + +B Read fault + +C General failure + +D Reserved + +E Reserved + +F Invalid disk change + +Bit 9 is the busy bit, which is set only by Status calls and the +Removable Media call. + +2.7 Device Driver Functions + +Device drivers may perform all or some of these general functions. In some +cases, these functions break down into several command codes, for specific +cases. Each of the following general functions is described in this section. + + o Init + + o Media Check + + + +14 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + o Build BPB + + o Read, or Write, or Write Until Busy, or Write with Verify, or + Read IOCtl, or Write IOCtl + + o Non-destructive Read, No Wait + + o Open or Close (3.x) + + o Removable Media (3.x) + + o Status + + o Flush + + o Generic IOCtl + + o Get or Set Logical Device + +All strategy routines are called with ES:BX pointing to the request header. +The interrupt routines get the pointers to the request header from the +queue that the strategy routines store them in. The command code in the +request header tells the driver which function to perform and what data +follows the request header. + +_ ________________________________________________________________ + +Note + + All DWORD pointers are stored offset first, then segment. + +_ ________________________________________________________________ + + +2.7.1 The Init Function + +Command code = 0 + +INIT - ES:BX -> ++------------------------------------+ +| 13-BYTE Request header | ++------------------------------------+ +| BYTE Number of units | ++------------------------------------+ +| DWORD End Address | ++------------------------------------+ +| DWORD Pointer to BPB array | +| (Not set by character devices) | ++------------------------------------+ +| BYTE Block device number | ++------------------------------------+ + +One of the functions defined for each device driver is Init. This routine is +called only once when the device is installed. The Init routine must return +the end address, which is a DWORD pointer to the end of the portion of +the device driver to remain resident. To save space, you can use this + + 15 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +pointer method to delete initialization code that is needed only once. + +The number of units, end address, and BPB pointer are to be set by the +driver. However, on entry for installable device drivers, the DWORD that +is to be set by the driver to the BPB array (on block devices) points to the +character after the "=" on the line in config.sys that caused this device +driver to be loaded. This allows drivers to scan the config.sys invocation +line for parameters that might be passed to the driver. This line is ter- +minated by a RETURN or a linefeed character. This data is read-only and +allows the device to scan the config.sys command line for arguments. + + device=\dev\vt52.sys /l + | + |_____BPB address points here + +Also, for block devices only, the drive number assigned to the first unit +defined by this driver (A=0) as contained in the block device number field. +This is also read-only. + +_ ________________________________________________________________ + +Note + + The Init routine can issue only Functions 01H-0CH, 25H, 30H, and + 35H. + +_ ________________________________________________________________ + +For installable character devices, the end address parameter must be +returned. This is a pointer to the first available byte of memory above the +driver and may be used to throw away initialization code. + +Block devices must return the following information: + + 1. The number of units must be returned. MS-DOS uses this number + to determine logical device names. If the current maximum logical + device letter is F at the time of the install call, and the Init routine + returns 4 as the number of units, then they will have logical names + G, H, I, and J. This mapping is determined by the position of the + driver in the device list, and by the number of units on the device + (stored in the first byte of the device name field). + + 2. A DWORD pointer to an array of word offsets (pointers) to BPBs + (BIOS Parameter Blocks) must be returned. The BPBs passed by + the device driver are used by MS-DOS to create an internal struc- + ture. There must be one entry in this array for each unit defined + by the device driver. In this way, if all units are the same, all the + pointers can point to the same BPB, saving space. If the device + driver defines two units, then the DWORD pointer points to the + first of two one-word offsets which in turn point to BPBs. The for- + mat of the BPB is described later in this chapter in Section 2.7.3, + +16 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + "The Build BPB Function." + + Note that this array of word offsets must be protected (below the + free pointer set by the return), since an internal DOS structure will + be built starting at the byte pointed to by the free pointer. The + defined sector size must be less than or equal to the maximum sec- + tor size defined by the resident device drivers (BIOS) during initial- + ization. If it isn't, the installation will fail. + + 3. The last thing that the Init function of a block device must pass + back is the media descriptor byte. This byte means nothing to + MS-DOS, but is passed to devices so that they know what parame- + ters MS-DOS is currently using for a particular drive. + +_ ________________________________________________________________ + +Note + + If there are multiple device drivers in a single file, MS-DOS uses the + ending address returned by the last Init function called. All device + drivers in a single file should return the same ending address. All dev- + ices in a single file should be grouped together low in memory with the + initialization code for all devices following it in memory. + +_ ________________________________________________________________ + + +2.7.2 The Media Check Function + +Command Code = 1 + +MEDIA CHECK - ES:BX -> ++------------------------------------+ +| 13-BYTE Request header | ++------------------------------------+ +| BYTE Media descriptor from BPB | ++------------------------------------+ +| BYTE Returned | ++------------------------------------+ +| Returned DWORD pointer to previous | +| Volume ID if bit 11 set and | +| Disk Changed is returned | ++------------------------------------+ + +The Media Check function is used only with block devices. It is called +when there is a pending drive-access call other than a file read or write, +such as Open, Close, delete, and rename. Its purpose is to determine +whether the media in the drive has been changed. If the driver can assure +that the media has not been changed (through a door-lock or other inter- +lock mechanism), MS-DOS performance is enhanced, because MS-DOS +does not need to reread the FAT and invalidate in-memory buffers for each +directory access. + + + 17 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +When a disk-access call to the DOS occurs (other than a file read or write), +the following sequence of events takes place: + + 1. The DOS converts the drive letter into a unit number of a particu- + lar block device. + + 2. The device driver is then called to request a media check on that + subunit to see if the disk might have been changed. MS-DOS + passes the old media descriptor byte. The driver returns one of the + following: + + + Return + Meaning + _ _________________________________________________________ + + (1) Media not changed + + (0) Don't know if changed + + (-1) Media changed + + value Error (value is a standard error code value) + + If the media has not been changed, MS-DOS proceeds with the disk + access. + + If the value returned is -1, then if there are any disk sectors that + have been modified and not written back out to the disk for this + unit, MS-DOS assumes that the disk has not been changed and + proceeds. MS-DOS invalidates any other buffers for the unit and + does a Build BPB call (see Step 3, following). + + If the media has been changed, MS-DOS invalidates all buffers + associated with this unit including buffers with modified data that + are waiting to be written, and requests a new BIOS Parameter + Block via the Build BPB call (see Step 3). + + 3. Once the BPB has been returned, MS-DOS corrects its internal + structure for the drive from the new BPB and proceeds with the + access after reading the directory and the FAT. + +Note that the previous media ID byte is passed to the device driver. If the +old media ID byte is the same as the new one, the disk might have been +changed and a new disk may be in the drive; therefore, all FAT, directory, +and data sectors that are buffered in memory for the drive are considered +invalid. + +If the driver has bit 11 of the device attribute word set to 1, and the driver +returns -1 (Media Changed) the driver must set the DWORD pointer to +the previous Volume ID field. If the DOS determines that "Media changed" +is an error based on the state of the DOS buffer cache, the DOS will gen- +erate a 0FH error on behalf of the device. If the driver does not implement +volume ID support, but has bit 11 set, (it should set a static pointer to the +string "NO NAME" ,0.) + + + +18 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +It is not possible for a user to change a disk in less than two seconds. So +when Media Check occurs within two seconds of a disk access, the driver +reports "Media not changed (1)." This improves performance tremen- +dously. + +_ ________________________________________________________________ + +Note + + If the media ID byte in the returned BPB is the same as the previous + media ID byte, MS-DOS will assume that the format of the disk is the + same (even though the disk may have been changed) and will skip the + step of updating its internal structure. Therefore, all BPBs must have + unique media bytes regardless of FAT ID bytes. + +_ ________________________________________________________________ + + +2.7.3 The Build BPB Function + +Command code = 2 + +BUILD BPB - ES:BX -> ++------------------------------------+ +| 13-BYTE Request header | ++------------------------------------+ +| BYTE Media descriptor from BPB | ++------------------------------------+ +| DWORD Transfer address | +| (Points to one sector worth of | +| scratch space or first sector | +| of FAT depending on the value | +| of Bit 13 in the device attribute | +| word.) | ++------------------------------------+ +| DWORD Pointer to BPB | ++------------------------------------+ + +The Build BPB function is used with block devices only. As described in +the Media Check function, the Build BPB function will be called any +time that a preceding Media Check call indicates that the disk has been +or might have been changed. The device driver must return a pointer to a +BPB. This is different from the Init call where the device driver returns a +pointer to an array of word offsets to BPBs. + +The Build BPB call gets a DWORD pointer to a one-sector buffer. The +contents of this buffer are determined by the non-FAT ID bit (bit 13) in +the attribute field. If the bit is zero, then the buffer contains the first sec- +tor of the first FAT. The FAT ID byte is the first byte of this buffer. In +this case, the driver must not alter this buffer. Note that the location of +the FAT must be the same for all possible media because this first FAT +sector must be read before the actual BPB is returned. If the non-FAT ID + + 19 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +bit is set, the pointer points to one sector of scratch space (which may be +used for anything). For information on how to construct the BPB, see Sec- +tion 2.8, "The Media Descriptor Byte," and Section 2.9, "Format of a +Media Descriptor Table." + +MS-DOS 3.x includes additional support for devices that have door-locks +or some other means of telling when a disk has been changed. There is a +new error that can be returned from the device driver (error 15). The +error means "the disk has been changed when it shouldn't have been," and +the user is prompted for the correct disk using a volume ID. The driver +may generate this error on read or write. The DOS may generate the error +on Media Check calls if the driver reports media changed, and there are +buffers in the DOS buffer cache that need to be flushed to the previous +disk. + +For drivers that support this error, the Build BPB function is a trigger +that causes a new volume ID to be read off the disk. This action indicates +that the disk has been legally changed. A volume ID is placed on a disk by +the format command, and is simply an entry in the root directory of the +disk that has the Volume ID attribute. It is stored by the driver as an +ASCIZ string. + +The requirement that the driver return a volume ID does not exclude some +other volume identifier scheme as long as the scheme uses ASCIZ strings. A +NUL (nonexistent or unsupported) volume ID is by convention the follow- +ing string: + +DB "NO NAME ",0 + + +2.7.4 The Read or Write Function + +Command codes = 3,4,8,9,12, and 16 + +READ OR WRITE (Including IOCtl) or + OUTPUT UNTIL BUSY - ES:BX -> ++------------------------------------+ +| 13-BYTE Request header | ++------------------------------------+ +| BYTE Media descriptor from BPB | ++------------------------------------+ +| DWORD Transfer address | ++------------------------------------+ +| WORD Byte/sector count | ++------------------------------------+ +| WORD Starting sector number | +| (Ignored on character devices) | ++------------------------------------+ +| Returned DWORD pointer to requested| +| Volume ID if error 0FH | ++------------------------------------+ + + +20 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +Command +code + Request +_ ________________________________________________________________ + +3 IOCtl read + +4 Read (block or character device) + +8 Write (block or character device) + +9 Write with Verify + +12 IOCtl Write + +16 Output Until Busy (character device only) + +The driver must perform the Read or Write call depending on which +command code is set. Block devices read or write sectors; character devices +read or write bytes. + +When I/O completes, the device driver must set the status word and +report the number of sectors or bytes successfully transferred. This should +be done even if an error prevented the transfer from being completed. Set- +ting the error bit and error code alone is not sufficient. + +In addition to setting the status word, the driver must set the sector count +to the actual number of sectors (or bytes) transferred. No error check is +performed on an IOCtl I/O call. The device driver must always set the +return byte/sector count to the actual number of bytes/sectors success- +fully transferred. + +If the verify switch is on, the device driver will be called with command +code 9 (Write with Verify). Your device driver will be responsible for +verifying the write. + +If the driver returns error code 0FH (Invalid disk change), it must return a +DWORD pointer to an ASCIZ string (which is the correct volume ID). +Returning this error code triggers the DOS to prompt the user to re-insert +the disk. The device driver should have read the volume ID as a result of +the Build BPB function. + +Drivers may maintain a reference count of open files on the disk by moni- +toring the Open and Close functions. This allows the driver to determine +when to return error 0FH. If there are no open files (reference count = 0), +and the disk has been changed, the I/O is okay. If there are open files, +however, an 0FH error may exist. + +The Output Until Busy call is a speed optimization on character devices +only for print spoolers. The device driver is expected to output all the +characters possible until the device returns busy. Under no circumstances +should the device driver block during this function. Note that it is not an +error for the device driver to return the number of bytes output as being +less than the number of bytes requested (or = 0). + + 21 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The Output Until Busy call allows spooler programs to take advantage +of the "burst" behavior of most printers. Many printers have on-board +RAM buffers that typically hold a line or a fixed amount of characters. +These buffers fill up without the printer going busy, or going busy for a +short period (less than ten instructions) between characters. A line of +characters can be quickly output to the printer, after which the printer is +busy for a long time while the characters are being printed. This new dev- +ice call allows background spooling programs to use this burst behavior +efficiently. Rather than take the overhead of a device driver call for each +character, or risk getting stuck in the device driver outputting a block of +characters, this call allows a burst of characters to be output without the +device driver having to wait for the device to be ready. + +The Following Applies to Block Device Drivers: + +Under certain circumstances, the BIOS may be asked to perform a write +operation of 64K bytes, which seems to be a "wrap-around" of the transfer +address in the BIOS I/O packet. This request, which arises due to an +optimization added to the write code in MS-DOS, will manifest itself only +on user writes that are within a sector size of 64K bytes on files "growing" +past the current end-of-file (EOF) mark. It is allowable for the BIOS to +ignore the balance of the write that "wraps around" if it so chooses. For +example, a write of 10000H bytes worth of sectors with a transfer address +of xxx:1 could ignore the last two bytes. A user program can never request +an I/O of more than FFFFH bytes and cannot wrap around (even to 0) in +the transfer segment. Therefore, in this case, the last two bytes can be +ignored. + +MS-DOS maintains two FATs. If the DOS has problems reading the first, +it automatically tries the second before reporting the error. The BIOS is +responsible for all retries. + +Although the command.com handler does no automatic retries, there are +applications that have their own Interrupt 24H handlers that do +automatic retries on certain types of Interrupt 24H errors before reporting +them. + +2.7.5 The Non-destructive Read, No Wait Function + +Command code = 5 + +NON-DESTRUCTIVE READ NO WAIT - ES:BX -> ++------------------------------------+ +| 13-BYTE Request header | ++------------------------------------+ +| BYTE Read from device | ++------------------------------------+ + +The Non-destructive Read, No Wait function allows MS-DOS to look + +22 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +ahead one input character. The device sets the done bit in the status +word. + +If the character device returns busy bit = 0 (there are characters in the +buffer), then the next character that would be read is returned. This char- +acter is not removed from the input buffer (hence the term "Non- +destructive Read"). If the character device returns busy bit = 1, there are +no characters in the buffer. + +2.7.6 The Open or Close Function + +Command codes = 13 and 14 + +OPEN or CLOSE - ES:BX -> ++------------------------------------+ +| 13-BYTE Static request header | ++------------------------------------+ + +The Open and Close functions are called by MS-DOS 3.x only if the dev- +ice driver sets the Open/Close/Removable Media attribute bit in the +device header. They are designed to inform the device about current file +activity on the device. On block devices, they can be used to manage local +buffering. The device can keep a reference count. Every Open causes the +device to increment the count, every Close to decrement. When the count +goes to zero, it means there are no open files on the device, and the device +should flush any buffers that have been written to that may have been +used inside the device, because it is now "legal" for the user to change the +media on a removable media drive. + +There are problems with this mechanism on block devices because pro- +grams that use FCB calls can open files without closing them. It is there- +fore advisable to reset the count to zero without flushing the buffers when +the answer to "Has the media been changed?" is yes, and the Build BPB +call is made to the device. + +These calls are more useful on character devices. The Open call, for +instance, can be used to send a device initialization string. On a printer, +this could cause a string for setting font and page size characteristics to be +sent to the printer so that it would always be in a known state at the start +of an I/O stream. Using IOCtl to set these pre- and post- strings provides +a flexible mechanism of serial I/O device stream control. The reference +count mechanism can also be used to detect a simultaneous access error. It +may be desirable to disallow more than one Open on a device at any given +time. In this case, a second Open would result in an error. + +Note that since all processes have access to stdin, stdout, stderr, stdaux, +and stdprn (handles 0,1,2,3,4), the CON, AUX, and PRN devices are +always open. + + + 23 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +2.7.7 The Removable Media Function + +Command code = 15 + +REMOVABLE MEDIA - ES:BX -> ++------------------------------------+ +| 13-BYTE Static request header | ++------------------------------------+ + +The Removable Media function is called by MS-DOS 3.x only if the dev- +ice driver sets the Open/Close/Removable Media attribute bit in the +device header. This call is given only to block devices by a subfunction of +the IOCtl system call. It is sometimes desirable for a utility to know +whether it is dealing with a nonremovable media drive (such as a hard +disk), or a removable media drive (like a floppy). An example is the +format command, which prints different versions of some of the prompts. + +The information is returned in the busy bit of the status word. If the busy +bit is 1, then the media is nonremovable. If the busy bit is 0, then the +media is removable. Note that the error bit is not checked. It is assumed +that this call always succeeds. + +2.7.8 The Status Function + +Command codes = 6 and 10 + +STATUS Calls ES:BX -> ++------------------------------------+ +| 13-BYTE Request header | ++------------------------------------+ + +The Status function returns information to the DOS as to whether data is +waiting for input or output. All the driver must do is set the status word +and the busy bit as follows: + + o For output on character devices \(em if the driver sets bit 9 to 1 on + return, it informs the DOS that a write request (if made) would + wait for completion of a current request. If it is 0, there is no + current request, and a write request (if made) would start immedi- + ately. + + o For input on character devices with a buffer \(em A return of 1 implies + that no characters are buffered and that a read request (if made) + would go to the physical device. If it is 0 on return, then there are + characters in the device buffer and a read would not be blocked. A + return of 0 implies that the user has typed something. MS-DOS + assumes that all character devices have an input type-ahead buffer. + +Devices that do not have a type-ahead buffer should always return busy = +0 so that the DOS will not "hang" waiting for something to get into a + +24 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +non-existent buffer. + +2.7.9 The Flush Function + +Command codes = 7 and 11 + +FLUSH Calls - ES:BX -> ++------------------------------------+ +| 13-BYTE Request header | ++------------------------------------+ + +The Flush function tells the driver to flush (terminate) all pending +requests. This call is used to flush the input queue on character devices. + +The device driver performs the flush function, sets the status word, and +returns. + +2.7.10 The Generic IOCtl Function + +Command code = 19 + +ES:BX -> ++------------------------------------+ +| 13-BYTE Static request header | ++------------------------------------+ +| BYTE Category (Major) code | ++------------------------------------+ +| BYTE Function (Minor) code | ++------------------------------------+ +| WORD (SI) Contents | ++------------------------------------+ +| WORD (DI) Contents | ++------------------------------------+ +| DWORD Pointer to data buffer | ++------------------------------------+ + +The Generic IOCtl function provides a generic, expandable IOCtl facility +that replaces and makes the Read IOCtl and Write IOCtl device driver +functions obsolete. The MS-DOS 2.0 IOCtl functions remain to support +existing uses of the IOCtl system call (Subfunctions 2, 3, 4, and 5), but +new device drivers should use this generic MS-DOS IOCtl facility. + +The Generic IOCtl function contains both a category and function code. +The DOS examines the category field in order to intercept and obey device +commands that are actually serviced by the DOS code; all other command +categories are forwarded to the device driver for servicing. + + + + 25 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +For more information on these category and function codes, refer to Func- +tion 440CH (Generic IOCtl for Handles) and Function 440DH (Generic +IOCtl for Block Devices) in Chapter 1, "System Calls." + +2.7.11 The Get/Set Logical Drive Map Function + +Command codes = 23 (Get) or 24 (Set) + + +----------------------------------------+ + | 13-BYTE Static request header | + +----------------------------------------+ + | BYTE Input (unit code) | + +----------------------------------------+ + | BYTE Output (last device referenced)| + +----------------------------------------+ + | BYTE Command code | + +----------------------------------------+ + | WORD Status | + +----------------------------------------+ + | DWORD Reserved | + +----------------------------------------+ + +The Get/Set Logical Drive Map function is called by MS-DOS only if +the device driver sets the DOS 3.2 attribute bit in the device header. The +call is issued only to block devices by the subfunction of the IOCtl system +call. The logical drive to be mapped is passed in the Unit field of the +header to the device driver. The device driver returns the current logical +drive owner of the physical device that maps to the requested physical +drive. To detect whether a logical device currently owns the physical dev- +ice to which it is mapped, a program needs to verify that, after a call of +Function 440EH or 440FH (Get/Set Logical Drive Map), the value of +the Unit field is unchanged. + +2.8 The Media Descriptor Byte + +In MS-DOS, the media descriptor byte is used to inform the DOS that a +different type of media is present. The media descriptor byte can be any +value between 0 and FFH. It does not have to be the same as the FAT ID +byte. The FAT ID byte, which is the first byte of the FAT, was used in +MS-DOS 1.00 to distinguish between different types of disk media, and +may be used as well under 2.x and 3.x disk device drivers. However, FAT +ID bytes have significance only for block device drivers where the +non-FAT ID bit is not set (0). + + + +26 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +Values of the media descriptor byte or the FAT ID byte have no +significance to MS-DOS. They are passed to the device driver so that pro- +grams can determine the media type. + +2.9 Format of a Media Descriptor Table + +The MS-DOS file system uses a linked list of pointers (one for each cluster +or allocation unit) called the File Allocation Table (FAT). Unused clusters +are represented by zero and end-of-file by FFFH (or FFFFH on units with +16-bit FAT entries). No valid entry should ever point to a zero entry, but +if one does, the first FAT entry (which would be pointed to by a zero +entry) was reserved and set to end of chain. Eventually, several end of +chain values were defined ([F]FF8-[F]FFFH), and these were used to dis- +tinguish different types of media. + +A preferable technique is to write a complete media descriptor table in the +boot sector and use it for media identification. To ensure backward com- +patibility for systems whose drivers do not set the non-FAT ID bit +(including the IBM PC implementation), it is necessary also to write the +FAT ID bytes during the format process. + +To allow more flexibility for supporting many different disk formats in the +future, it is recommended that the information relating to the BPB for a +particular piece of media be kept in the boot sector. Figure 2.3 shows the +format of such a boot sector. + + +------------------------------------+ + | 3 BYTE Near JUMP to boot code | + +------------------------------------+ + | 8 BYTES OEM name and version | + ---+------------------------------------+--- + B | WORD Bytes per sector | + P +------------------------------------+ + B | BYTE Sectors per allocation unit | + +------------------------------------+ + | | WORD Reserved sectors | + V +------------------------------------+ + | BYTE Number of FATs | + +------------------------------------+ + | WORD Number of root dir entries | + +------------------------------------+ + | WORD Number of sectors in logical | + ^ | image | + | +------------------------------------+ + B | BYTE Media descriptor | + P +------------------------------------+ + B | WORD Number of FAT sectors | + ---+------------------------------------+--- + | WORD Sectors per track | + + 27 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +------------------------------------+ + | WORD Number of heads | + +------------------------------------+ + | WORD Number of hidden sectors | + +------------------------------------+ + | WORD High order number of hidden | + | sectors | + +------------------------------------+ + | DWORD Number of logical sectors | + +------------------------------------+ + + + Figure 2.5 Format of a Boot Sector + +Although MS-DOS does not use the five fields that follow the BPB, these +fields may be used by a device driver to help it understand the media. + +The "Sectors per track" and "Number of heads" fields are useful for sup- +porting different media which may have the same logical layout , but a +different physical layout (for example, 40-track, double-sided versus 80- +track, single-sided). "Sectors per track" tells the device driver how the log- +ical disk format is laid out on the physical disk. + +The "Number of hidden sectors" and "High order number of hidden sec- +tors" fields may be used to support drive-partitioning schemes. + +The "Number of logical sectors" field is not currently used, but will tell +the device driver how many sectors to reserve if the "Number of sectors in +logical image" field is zero. (Note that this is intended for supporting dev- +ices that access more than 32 megabytes.) + +The following procedure is recommended for media determination by NON +FAT ID format drivers: + + 1. Read the boot sector of the drive into the one-sector scratch space + pointed to by the DWORD transfer address. + + 2. Determine if the first byte of the boot sector is an E9H or EBIT + (the first byte of a 3-byte NEAR or 2-byte SHORT jump) or an + EBH (the first byte of a 2-byte jump followed by an NOP). If so, a + BPB is located beginning at offset 3. Return a pointer to it. + + 3. If the boot sector does not have a BPB table, it is probably a disk + formatted under a 1.x version of MS-DOS and probably uses a FAT + ID byte for determining media. + + The driver may optionally attempt to read the first sector of the + FAT into the one-sector scratch area and read the first byte to + determine media type based upon whatever FAT ID bytes may + have been used on disks that are expected to be read by this sys- + tem. Return a pointer to a hard-coded BPB. + + + +28 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + +2.10 The CLOCK Device + +MS-DOS assumes that some sort of clock is available in the system. This +may either be a CMOS real-time clock or an interval timer that is initial- +ized at boot time by the user. The CLOCK device defines and performs +functions like any other character device, except that it is identified by a +bit in the attribute word. The DOS uses this bit to identify it; conse- +quently, the CLOCK device may take any name. The IBM implementation +uses the name $CLOCK so as not to conflict with existing files named +clock. + +The CLOCK device is unique in that MS-DOS will read or write a 6-byte +sequence that encodes the date and time. A write to this device will set +the date and time; a read will get the date and time. + +Figure 2.6 illustrates the binary time format used by the CLOCK device: + + byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 ++--------+--------+---------+--------+--------+---------+ +| | | | | | | +|days since 1-1-80| minutes | hours | sec/100| seconds | +|low byte|hi byte | | | | | ++--------+--------+---------+--------+--------+---------+ + + + Figure 2.6 Format of a Clock Device + + +2.11 Anatomy of a Device Call + +The following steps illustrate what happens when MS-DOS calls on a block +device driver to perform a Write request: + + 1. MS-DOS writes a request packet in a reserved area of memory. + + 2. MS-DOS calls the strategy entry point of the block device driver. + + 3. The device driver saves the ES and BX registers (ES:BX points to + the request packet) and does a FAR return. + + 4. MS-DOS calls the interrupt entry point. + + 5. The device driver retrieves the pointer to the request packet and + reads the command code (offset 2) to determine that this is a + Write request. The device driver converts the command code to + an index into a dispatch table and control passes to the Write rou- + tine. + + + + 29 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + 6. The device driver reads the unit code (offset 1) to determine which + disk drive it is supposed to write to. + + 7. Since the command is a disk Write, the device driver must get the + transfer address (offset 14), the sector count (offset 18), and the + start sector (offset 20) in the request packet. + + 8. The device driver translates the first logical sector number into a + track, head, and sector number. + + 9. The device driver writes the specified number of sectors, starting at + the beginning sector on the drive defined by the unit code (the + subunit defined by this device driver), and transfers data from the + transfer address indicated in the request packet. Note that this + may involve multiple Write commands to the disk controller. + + 10. After the transfer is complete, the device driver must report the + status of the request to MS-DOS by setting the done bit in the + status word (offset 3 in the request packet). It reports the number + of sectors actually transferred in the sector count area of the + request packet. + + 11. If an error occurs, the driver sets the done bit and the error bit in + the status word and fills in the error code in the lower half of the + status word. The number of sectors actually transferred must be + written in the request header. It is not sufficient just to set the + error bit of the status word. + + 12. The device driver does a FAR return to MS-DOS. + +The device drivers should preserve the state of MS-DOS. This means that +all registers (including flags) should be preserved. The direction flag and +interrupt enable bits are critical. When the interrupt entry point in the +device driver is called, MS-DOS has room for about 40 to 50 bytes on its +internal stack. Your device driver should switch to a local stack if it uses +extensive stack operations. + +2.12 Two Sample Device Drivers + +The following two examples illustrate a block device driver and a charac- +ter device driver program. These examples are provided as guides for writ- +ing your own device drivers. However, since device drivers are hardware- +dependent, your device drivers will differ. + + +30 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + +Block Device Driver + + +;********************* A Block Device ******************* + + Title 5.25-inch Disk Driver + +;This driver is intended to drive up to four 5.25-inch +;drives hooked to a single disk controller. All standard +;IBM PC formats are supported. + + +FALSE EQU 0 +TRUE EQU NOT FALSE + +;The I/O port address of the disk controller +DISK EQU 0E0H +;DISK+0 +; 1793 Command/Status +;DISK+1 +; 1793 Track +;DISK+2 +; 1793 Sector +;DISK+3 +; 1793 Data +;DISK+4 +; Aux Command/Status +;DISK+5 +; Wait Sync + +;Back side select bit +BACKBIT EQU 04H +;5 1/4" select bit +SMALBIT EQU 10H +;Double Density bit +DDBIT EQU 08H + +;Done bit in status register +DONEBIT EQU 01H + +;Use table below to select head step speed. +;Step times for 5" drives +;are double that shown in the table. +; +;Step value 1771 1793 +; +; 0 6ms 3ms +; 1 6ms 6ms +; 2 10ms 10ms +; 3 20ms 15ms +; +STPSPD EQU 1 + +NUMERR EQU ERROUT-ERRIN + +CR EQU 0DH +LF EQU 0AH + + 31 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +CODE SEGMENT +ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING +;----------------------------------------------------- +; +; Device Header +; +DRVDEV LABEL WORD + DW -1,-1 + DW 0000 ;IBM format-compatible, Block + DW STRATEGY + DW DRV$IN +DRVMAX DB 4 + +DRVTBL LABEL WORD + DW DRV$INIT + DW MEDIA$CHK + DW GET$BPB + DW CMDERR + DW DRV$READ + DW EXIT + DW EXIT + DW EXIT + DW DRV$WRIT + DW DRV$WRIT + DW EXIT + DW EXIT + DW EXIT + +;------------------------------------ +; +; Strategy + +PTRSAV DD 0 + +STRATP PROC FAR +STRATEGY: + MOV WORD PTR [PTRSAV],BX + MOV WORD PTR [PTRSAV+2],ES + RET +STRATP ENDP + +;-------------------------------------- +; +; Main Entry + + +CMDLEN = 0 ;Length of this command +UNIT = 1 ;Subunit specified +CMDC = 2 ;Command Code +STATUS = 3 ;Status +MEDIA = 13 ;Media Descriptor +TRANS = 14 ;Transfer Address +COUNT = 18 ;Count of blocks or characters +START = 20 ;First block to transfer + +DRV$IN: + +32 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + PUSH SI + PUSH AX + PUSH CX + PUSH DX + PUSH DI + PUSH BP + PUSH DS + PUSH ES + PUSH BX + + LDS BX,[PTRSAV] ;Get pointer to I/O packet + + MOV AL,BYTE PTR [BX].UNIT ;AL = Unit Code + MOV AH,BYTE PTR [BX].MEDIA ;AH = Media Descrip + MOV CX,WORD PTR [BX].COUNT ;CX = Count + MOV DX,WORD PTR [BX].START ;DX = Start Sector + PUSH AX + MOV AL,BYTE PTR [BX].CMDC ;Command code + CMP AL,15 + JA CMDERRP ;Bad command + CBW + SHL AX,1 ;2 times command = + ;word table index + MOV SI,OFFSET DRVTBL + ADD SI,AX ;Index into table + POP AX ;Get back media + ;and unit + + LES DI,DWORD PTR [BX].TRANS ;ES:DI = Transfer + ;Address + + PUSH CS + POP DS + +ASSUME DS:CODE + + JMP WORD PTR [SI] ;GO DO COMMAND + +;---------------------------------------------------------- +; +; EXIT - All Routines return through this path +; +ASSUME DS:NOTHING +CMDERRP: + POP AX ;Clean stack +CMDERR: + MOV AL,3 ;Unknown command error + JMP SHORT ERR$EXIT + +ERR$CNT:LDS BX,[PTRSAV] + SUB WORD PTR [BX].COUNT,CX ;# OF SUCCESS. I/Os + +ERR$EXIT: +;AL has error code + MOV AH,10000001B ;Mark error return + JMP SHORT ERR1 + + 33 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +EXITP PROC FAR + +EXIT: MOV AH,00000001B +ERR1: LDS BX,[PTRSAV] + MOV WORD PTR [BX].STATUS,AX + ;Mark Operation +CompleteE + + POP BX + POP ES + POP DS + POP BP + POP DI + POP DX + POP CX + POP AX + POP SI + RET ;Restore REGS and return +EXITP ENDP + +CURDRV DB -1 + +TRKTAB DB -1,-1,-1,-1 + +SECCNT DW 0 + +DRVLIM = 8 ;Number of sectors on device +SECLIM = 13 ;Maximum Sector +HDLIM = 15 ;Maximum Head + +;WARNING - preserve order of drive and curhd! + +DRIVE DB 0 ;Physical Drive Code +CURHD DB 0 ;Current Head +CURSEC DB 0 ;Current Sector +CURTRK DW 0 ;Current Track + + +; +MEDIA$CHK: ;Always indicates Don't know +ASSUME DS:CODE + TEST AH,00000100B ;Test if Media Removable + JZ MEDIA$EXT + XOR DI,DI ;Say I Don't know +MEDIA$EXT: + LDS BX,[PTRSAV] + MOV WORD PTR [BX].TRANS,DI + JMP EXIT + +BUILD$BPB: +ASSUME DS:CODE + MOV AH,BYTE PTR ES:[DI] ;Get FAT ID Byte + CALL BUILDBP ;Translate +SETBPB: LDS BX,[PTRSAV] + MOV [BX].MEDIA,AH + MOV [BX].COUNT,DI + +34 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + MOV [BX].COUNT+2,CS + JMP EXIT + +BUILDBP: +ASSUME DS:NOTHING +;AH is media byte on entry +;DI points to correct BPB on return + PUSH AX + PUSH CX + PUSH DX + PUSH BX + MOV CL,AH ;Save Media + AND CL,0F8H ;Normalize + CMP CL,0F8H ;Compare with Good Media Byte + JZ GOODID + MOV AH,0FEH ;Default to 8-sector, + ;Single-sided +GOODID: + MOV AL,1 ;Set number of FAT sectors + MOV BX,64*256+8 ;Set Dir Entries and Sector Max + MOV CX,40*8 ;Set Size of Drive + MOV DX,01*256+1 ;Set Head Limit & Sec/All Unit + MOV DI,OFFSET DRVBPB + TEST AH,00000010B ;Test for 8 OR 9 Sectors + JNZ HAS8 ;NZ = has 8 sectors + INC AL ;Inc Number of FAT sectors + INC BL ;Inc Sector Max + ADD CX,40 ;Increase Size +HAS8: TEST AH,00000001B ;Test for 1 or 2 Heads + JZ HAS1 ;Z = 1 Head + ADD CX,CX ;Double Size of Disk + MOV BH,112 ;Increase # of Dir Entries + INC DH ;Inc Sec/All Unit + INC DL ;Inc Head Limit +HAS1: MOV BYTE PTR [DI].2,DH + MOV BYTE PTR [DI].6,BH + MOV WORD PTR [DI].8,CX + MOV BYTE PTR [DI].10,AH + MOV BYTE PTR [DI].11,AL + MOV BYTE PTR [DI].13,BL + MOV BYTE PTR [DI].15,DL + POP BX + POP DX + POP CX + POP AX + RET + + +;---------------------------------------------------------- +; +; Disk I/O Handlers +; +;ENTRY: +; AL = Drive Number (0-3) +; AH = Media Descriptor +; CX = Sector Count + + 35 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +; DX = First Sector +; DS = CS +; ES:DI = Transfer Address +;EXIT: +; IF Successful Carry Flag = 0 +; ELSE CF=1 AND AL contains (MS-DOS) Error Code, + CX # sectors NOT transferred + +DRV$READ: +ASSUME DS:CODE + JCXZ DSKOK + CALL SETUP + JC DSK$IO + CALL DISKRD + JMP SHORT DSK$IO + +DRV$WRIT: +ASSUME DS:CODE + JCXZ DSKOK + CALL SETUP + JC DSK$IO + CALL DISKWRT +ASSUME DS:NOTHING +DSK$IO: JNC DSKOK + JMP ERR$CNT +DSKOK: JMP EXIT + + +SETUP: +ASSUME DS:CODE +;Input same as above +;On output +; ES:DI = Trans addr +; DS:BX Points to BPB +; Carry set if error (AL is error code (MS-DOS)) +; else +; [DRIVE] = Drive number (0-3) +; [SECCNT] = Sectors to transfer +; [CURSEC] = Sector number of start of I/O +; [CURHD] = Head number of start of I/O ;Set +; [CURTRK] = Track # of start of I/O ;Seek performed +; All other registers destroyed + + XCHG BX,DI ;ES:BX = Transfer Address + CALL BUILDBP ;DS:DI = PTR to B.P.B + MOV SI,CX + ADD SI,DX + CMP SI,WORD PTR [DI].DRVLIM + ;Compare Against Drive Max + JBE INRANGE + MOV AL,8 + STC + RET + +INRANGE: + MOV [DRIVE],AL + +36 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + MOV [SECCNT],CX ;Save Sector Count + XCHG AX,DX ;Set Up Logical Sector + ;For Divide + XOR DX,DX + DIV WORD PTR [DI].SECLIM ;Divide by Sec per Track + INC DL + MOV [CURSEC],DL ;Save Current Sector + MOV CX,WORD PTR [DI].HDLIM ;Get Number of Heads + XOR DX,DX ;Divide Tracks by Heads per Cylinder + DIV CX + MOV [CURHD],DL ;Save Current Head + MOV [CURTRK],AX ;Save Current Track +SEEK: + PUSH BX ;Xaddr + PUSH DI ;BPB pointer + CALL CHKNEW ;Unload head if change drives + CALL DRIVESEL + MOV BL,[DRIVE] + XOR BH,BH ;BX drive index + ADD BX,OFFSET TRKTAB ;Get current track + MOV AX,[CURTRK] + MOV DL,AL ;Save desired track + XCHG AL,DS:[BX] ;Make desired track current + OUT DISK+1,AL ;Tell Controller current track + CMP AL,DL ;At correct track? + JZ SEEKRET ;Done if yes + MOV BH,2 ;Seek retry count + CMP AL,-1 ;Position Known? + JNZ NOHOME ;If not home head +TRYSK: + CALL HOME + JC SEEKERR +NOHOME: + MOV AL,DL + OUT DISK+3,AL ;Desired track + MOV AL,1CH+STPSPD ;Seek + CALL DCOM + AND AL,98H ;Accept not rdy, seek, & CRC errors + JZ SEEKRET + JS SEEKERR ;No retries if not ready + DEC BH + JNZ TRYSK +SEEKERR: + MOV BL,[DRIVE] + XOR BH,BH ;BX drive index + ADD BX,OFFSET TRKTAB ;Get current track + MOV BYTE PTR DS:[BX],-1 ;Make current track + ;unknown + CALL GETERRCD + MOV CX,[SECCNT] ;Nothing transferred + POP BX ;BPB pointer + POP DI ;Xaddr + RET + +SEEKRET: + POP BX ;BPB pointer + + 37 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + POP DI ;Xaddr + CLC + RET + +;--------------------------------------------- +; +; Read +; + +DISKRD: +ASSUME DS:CODE + MOV CX,[SECCNT] +RDLP: + CALL PRESET + PUSH BX + MOV BL,10 ;Retry count + MOV DX,DISK+3 ;Data port +RDAGN: + MOV AL,80H ;Read command + CLI ;Disable for 1793 + OUT DISK,AL ;Output read command + MOV BP,DI ;Save address for retry + JMP SHORT RLOOPENTRY +RLOOP: + STOSB +RLOOPENTRY: + IN AL,DISK+5 ;Wait for DRQ or INTRQ + SHR AL,1 + IN AL,DX ;Read data + JNC RLOOP + STI ;Ints OK now + CALL GETSTAT + AND AL,9CH + JZ RDPOP ;Ok + MOV DI,BP ;Get back transfer + DEC BL + JNZ RDAGN + CMP AL,10H ;Record not found? + JNZ GOT_CODE ;No + MOV AL,1 ;Map it +GOT_CODE: + CALL GETERRCD + POP BX + RET + +RDPOP: + POP BX + LOOP RDLP + CLC + RET + + +;--------------------------------------------- +; +; Write +; + +38 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +DISKWRT: +ASSUME DS:CODE + MOV CX,[SECCNT] + MOV SI,DI + PUSH ES + POP DS +ASSUME DS:NOTHING +WRLP: + CALL PRESET + PUSH BX + MOV BL,10 ;Retry count + MOV DX,DISK+3 ;Data port +WRAGN: + MOV AL,0A0H ;Write command + CLI ;Disable for 1793 + OUT DISK,AL ;Output write command + MOV BP,SI ;Save address for retry +WRLOOP: + IN AL,DISK+5 + SHR AL,1 + LODSB ;Get data + OUT DX,AL ;Write data + JNC WRLOOP + STI ;Ints OK now + DEC SI + CALL GETSTAT + AND AL,0FCH + JZ WRPOP ;Ok + MOV SI,BP ;Get back transfer + DEC BL + JNZ WRAGN + CALL GETERRCD + POP BX + RET + +WRPOP: + POP BX + LOOP WRLP + CLC + RET + + +PRESET: +ASSUME DS:NOTHING + MOV AL,[CURSEC] + CMP AL,CS:[BX].SECLIM + JBE GOTSEC + MOV DH,[CURHD] + INC DH + CMP DH,CS:[BX].HDLIM + JB SETHEAD ;Select new head + CALL STEP ;Go on to next track + XOR DH,DH ;Select head zero +SETHEAD: + MOV [CURHD],DH + CALL DRIVESEL + + 39 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + MOV AL,1 ;First sector + MOV [CURSEC],AL ;Reset CURSEC +GOTSEC: + OUT DISK+2,AL ;Tell controller which sector + INC [CURSEC] ;We go on to next sector + RET + +STEP: +ASSUME DS:NOTHING + MOV AL,58H+STPSPD ;Step in w/ update, no verify + CALL DCOM + PUSH BX + MOV BL,[DRIVE] + XOR BH,BH ;BX drive index + ADD BX,OFFSET TRKTAB ;Get current track + INC BYTE PTR CS:[BX] ;Next track + POP BX + RET + +HOME: +ASSUME DS:NOTHING + MOV BL,3 +TRYHOM: + MOV AL,0CH+STPSPD ;Restore with verify + CALL DCOM + AND AL,98H + JZ RET3 + JS HOMERR ;No retries if not ready + PUSH AX ;Save real error code + MOV AL,58H+STPSPD ;Step in w/ update no verify + CALL DCOM + DEC BL + POP AX ;Get back real error code + JNZ TRYHOM +HOMERR: + STC +RET3: RET + + +CHKNEW: +ASSUME DS:NOTHING + MOV AL,[DRIVE] ;Get disk drive number + MOV AH,AL + XCHG AL,[CURDRV] ;Make new drive current. + CMP AL,AH ;Changing drives? + JZ RET1 ;No +; If changing drives, unload head so the head load delay +;one-shot will fire again. Do it by seeking to the same +;track with the H bit reset. +; + IN AL,DISK+1 ;Get current track number + OUT DISK+3,AL ;Make it the track to seek + MOV AL,10H ;Seek and unload head + +DCOM: +ASSUME DS:NOTHING + +40 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + OUT DISK,AL + PUSH AX + AAM ;Delay 10 microseconds + POP AX +GETSTAT: + IN AL,DISK+4 + TEST AL,DONEBIT + JZ GETSTAT + IN AL,DISK +RET1: RET + +DRIVESEL: +ASSUME DS:NOTHING +;Select the drive based on current info +;Only AL altered + MOV AL,[DRIVE] + OR AL,SMALBIT + DDBIT ;5 1/4" IBM PC disks + CMP [CURHD],0 + JZ GOTHEAD + OR AL,BACKBIT ;Select side 1 +GOTHEAD: + OUT DISK+4,AL ;Select drive and side + RET + +GETERRCD: +ASSUME DS:NOTHING + PUSH CX + PUSH ES + PUSH DI + PUSH CS + POP ES ;Make ES the local segment + MOV CS:[LSTERR],AL ;Terminate list w/ error code + MOV CX,NUMERR ;Number of error conditions + MOV DI,OFFSET ERRIN ;Point to error conditions + REPNE SCASB + MOV AL,NUMERR-1[DI] ;Get translation + STC ;Flag error condition + POP DI + POP ES + POP CX + RET ;and return + +;********************************************************* +; BPB for an IBM floppy disk, Various parameters are +; patched by BUILDBP to reflect the type of Media +; inserted +; This is a 9-sector, single-side BPB +DRVBPB: + DW 512 ;Physical sector size in bytes + DB 1 ;Sectors/allocation unit + DW 1 ;Reserved sectors for DOS + DB 2 ;# of allocation tables + DW 64 ;Number directory entries + DW 9*40 ;Number 512-byte sectors + DB 11111100B ;Media descriptor + DW 2 ;Number of FAT sectors + + 41 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + DW 9 ;Sector limit + DW 1 ;Head limit + + +INITAB DW DRVBPB ;Up to four units + DW DRVBPB + DW DRVBPB + DW DRVBPB + +ERRIN: ;DISK ERRORS RETURNED FROM THE CONTROLLER + DB 80H ;No response + DB 40H ;Write protect + DB 20H ;Write Fault + DB 10H ;SEEK error + DB 8 ;CRC error + DB 1 ;Mapped from 10H + ;(record not found) on Read +LSTERR DB 0 ;All other errors + +ERROUT: ;RETURNED ERROR CODES CORRESPONDING TO ABOVE + DB 2 ;No response + DB 0 ;Write Attempt + ;On Write-protected disk + DB 0AH ;Write fault + DB 6 ;SEEK Failure + DB 4 ;Bad CRC + DB 8 ;Sector not found + DB 12 ;General error + + +DRV$INIT: +; +; Determine number of physical drives by reading config.sys +; +ASSUME DS:CODE + PUSH DS + LDS SI,[PTRSAV] +ASSUME DS:NOTHING + LDS SI,DWORD PTR [SI.COUNT] ;DS:SI points to + ;config.sys +SCAN_LOOP: + CALL SCAN_SWITCH + MOV AL,CL + OR AL,AL + JZ SCAN4 + CMP AL,"s" + JZ SCAN4 + +WERROR: POP DS +ASSUME DS:CODE + MOV DX,OFFSET ERRMSG2 +WERROR2: MOV AH,9 + INT 21H + XOR AX,AX + PUSH AX ;No units + JMP SHORT ABORT + +42 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + +BADNDRV: + POP DS + MOV DX,OFFSET ERRMSG1 + JMP WERROR2 + +SCAN4: +ASSUME DS:NOTHING +;BX is number of floppies + OR BX,BX + JZ BADNDRV ;User error + CMP BX,4 + JA BADNDRV ;User error + POP DS +ASSUME DS:CODE + PUSH BX ;Save unit count +ABORT: LDS BX,[PTRSAV] +ASSUME DS:NOTHING + POP AX + MOV BYTE PTR [BX].MEDIA,AL ;Unit count + MOV [DRVMAX],AL + MOV WORD PTR [BX].TRANS,OFFSET DRV$INIT ;SET + ;BREAK ADDRESS + MOV [BX].TRANS+2,CS + MOV WORD PTR [BX].COUNT,OFFSET INITAB + ;SET POINTER TO BPB ARRAY + MOV [BX].ceOUNT+2,CS + JMP EXIT +; +; Put switch in CL, value in BX +; +SCAN_SWITCH: + XOR BX,BX + MOV CX,BX + LODSB + CMP AL,10 + JZ NUMRET + CMP AL,"-" + JZ GOT_SWITCH + CMP AL,"/" + JNZ SCAN_SWITCH +GOT_SWITCH: + CMP BYTE PTR [SI+1],":" + JNZ TERROR + LODSB + OR AL,20H ; Convert to lowercase + MOV CL,AL ; Get switch + LODSB ; Skip ":" +; +; Get number pointed to by [SI] +; +; Wipes out AX,DX only BX returns number +; +GETNUM1:LODSB + SUB AL,"0" + JB CHKRET + CMP AL,9 + + 43 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + JA CHKRET + CBW + XCHG AX,BX + MOV DX,10 + MUL DX + ADD BX,AX + JMP GETNUM1 + +CHKRET: ADD AL,"0" + CMP AL," " + JBE NUMRET + CMP AL,"-" + JZ NUMRET + CMP AL,"/" + JZ NUMRET +TERROR: + POP DS ; Get rid of return address + JMP WERROR +NUMRET: DEC SI + RET + +ERRMSG1 DB "SMLDRV: Bad number of drives",13,10,"$" +ERRMSG2 DB "SMLDRV: Invalid parameter",13,10,"$" +CODE ENDS + END + + + +44 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + +Character Device Driver + +The following program illustrates a character device driver program. + + +;******************** A Character Device ******************* + +Title VT52 Console for 2.0 (IBM) + +;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +; IBM Addresses for I/O +; +;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + CR=13 ;Carriage-Return + BACKSP=8 ;BACKSPACE + ESC=1BH + BRKADR=6CH ;006C Break vector address + ASNMAX=200 ;Size of key assignment buffer + +CODE SEGMENT BYTE + + ASSUME CS:CODE,DS:NOTHING,ES:NOTHING +;---------------------------------------------------------- +; +; C O N - Console Device Driver +; +CONDEV: ;Header for device "CON" + DW -1,-1 + DW 1000000000010011B ;CON IN AND CON OUT + DW STRATEGY + DW ENTRY + DB 'CON ' + +;----------------------------------------------------------- +; +; Command JUMP Tables +CONTBL: + DW CON$INIT + DW EXIT + DW EXIT + DW CMDERR + DW CON$READ + DW CON$RDND + DW EXIT + DW CON$FLSH + DW CON$WRIT + DW CON$WRIT + DW EXIT + DW EXIT + +CMDTABL DB 'A' + DW CUU ;cursor up + DB 'B' + DW CUD ;cursor down + + 45 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + DB 'C' + DW CUF ;cursor forward + DB 'D' + DW CUB ;cursor back + DB 'H' + DW CUH ;cursor position + DB 'J' + DW ED ;erase display + DB 'K' + DW EL ;erase line + DB 'Y' + DW CUP ;cursor position + DB 'j' + DW PSCP ;save cursor position + DB 'k' + DW PRCP ;restore cursor position + DB 'y' + DW RM ;reset mode + DB 'x' + DW SM ;set mode + DB 00 + +PAGE +;--------------------------------------------------- +; +; Device entry point +; +CMDLEN = 0 ;Length of this command +UNIT = 1 ;Subunit Specified +CMD = 2 ;Command Code +STATUS = 3 ;Status +MEDIA = 13 ;Media Descriptor +TRANS = 14 ;Transfer Address +COUNT = 18 ;Count of blocks or characters +START = 20 ;First block to transfer + +PTRSAV DD 0 + +STRATP PROC FAR + +STRATEGY: + MOV WORD PTR CS:[PTRSAV],BX + MOV WORD PTR CS:[PTRSAV+2],ES + RET + +STRATP ENDP + +ENTRY: + PUSH SI + PUSH AX + PUSH CX + PUSH DX + PUSH DI + PUSH BP + PUSH DS + PUSH ES + +46 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + PUSH BX + + LDS BX,CS:[PTRSAV] ;GET POINTER TO I/O PACKET + + MOV CX,WORD PTR DS:[BX].COUNT ;CX = COUNT + + MOV AL,BYTE PTR DS:[BX].CMD + CBW + MOV SI,OFFSET CONTBL + ADD SI,AX + ADD SI,AX + CMP AL,11 + JA CMDERR + + LES DI,DWORD PTR DS:[BX].TRANS + + PUSH CS + POP DS + + ASSUME DS:CODE + + JMP WORD PTR [SI] ;GO DO COMMAND + +PAGE +;===================================================== +;= +;= Subroutines Shared by Multiple Devices +;= +;===================================================== +;----------------------------------------------------- +; +; EXIT - All routines return through this path +; +BUS$EXIT: ;Device Busy Exit + MOV AH,00000011B + JMP SHORT ERR1 + +CMDERR: + MOV AL,3 ;Unknown command error + +ERR$EXIT: + MOV AH,10000001B ;Mark error Return + JMP SHORT ERR1 + +EXITP PROC FAR + +EXIT: MOV AH,00000001B +ERR1: LDS BX,CS:[PTRSAV] + MOV WORD PTR [BX].STATUS,AX ;Mark + ;Operation Complete + + POP BX + POP ES + POP DS + POP BP + POP DI + + 47 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + POP DX + POP CX + POP AX + POP SI + RET ;Restore REGS and Return +EXITP ENDP +;----------------------------------------------- +; +; BREAK Key Handling +; +BREAK: + MOV CS:ALTAH,3 ;Indicate BREAK key Set +INTRET: IRET + +PAGE +; +; WARNING - Variables are very order dependent, + so be careful when adding new ones! +; +WRAP DB 0 ; 0 = WRAP, 1 = NO WRAP +STATE DW S1 +MODE DB 3 +MAXCOL DB 79 +COL DB 0 +ROW DB 0 +SAVCR DW 0 +ALTAH DB 0 ;Special key handling + +;------------------------------------------------------- +; +; CHROUT - Write out Char in AL using current attribute +; +ATTRW LABEL WORD +ATTR DB 00000111B ;Character Attribute +BPAGE DB 0 ;Base Page +base dw 0b800h + +chrout: cmp al,13 + jnz trylf + mov [col],0 + jmp short setit + +trylf: cmp al,10 + jz lf + cmp al,7 + jnz tryback +torom: + mov bx,[attrw] + and bl,7 + mov ah,14 + int 10h +ret5: ret + +tryback: + cmp al,8 + jnz outchr + +48 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + cmp [col],0 + jz ret5 + dec [col] + jmp short setit + +outchr: + mov bx,[attrw] + mov cx,1 + mov ah,9 + int 10h + inc [col] + mov al,[col] + cmp al,[maxcol] + jbe setit + cmp [wrap],0 + jz outchr1 + dec [col] + ret +outchr1: + mov [col],0 +lf: inc [row] + cmp [row],24 + jb setit + mov [row],23 + call scroll + +setit: mov dh,row + mov dl,col + xor bh,bh + mov ah,2 + int 10h + ret + +scroll: call getmod + cmp al,2 + jz myscroll + cmp al,3 + jz myscroll + mov al,10 + jmp torom +myscroll: + mov bh,[attr] + mov bl,' ' + mov bp,80 + mov ax,[base] + mov es,ax + mov ds,ax + xor di,di + mov si,160 + mov cx,23*80 + cld + cmp ax,0b800h + jz colorcard + + rep movsw + mov ax,bx + + 49 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + mov cx,bp + rep stosw +sret: push cs + pop ds + ret + +colorcard: + mov dx,3dah +wait2: in al,dx + test al,8 + jz wait2 + mov al,25h + mov dx,3d8h + out dx,al ;turn off video + rep movsw + mov ax,bx + mov cx,bp + rep stosw + mov al,29h + mov dx,3d8h + out dx,al ;turn on video + jmp sret + +GETMOD: MOV AH,15 + INT 16 ;get column information + MOV BPAGE,BH + DEC AH + MOV WORD PTR MODE,AX + RET +;------------------------------------------------------ +; +; Console Read Routine +; +CON$READ: + JCXZ CON$EXIT +CON$LOOP: + PUSH CX ;Save Count + CALL CHRIN ;Get Char in AL + POP CX + STOSB ;Store Char at ES:DI + LOOP CON$LOOP +CON$EXIT: + JMP EXIT +;--------------------------------------------------------- +; +; Input Single Char into AL +; +CHRIN: XOR AX,AX + XCHG AL,ALTAH ;Get Character & Zero ALTAH + OR AL,AL + JNZ KEYRET + +INAGN: XOR AH,AH + INT 22 +ALT10: + OR AX,AX ;Check for non-key after BREAK + +50 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + JZ INAGN + OR AL,AL ;Special case? + JNZ KEYRET + MOV ALTAH,AH ;Store special key +KEYRET: RET +;---------------------------------------------------------- +; +; Keyboard Non-descructive Read, No Wait +; +CON$RDND: + MOV AL,[ALTAH] + OR AL,AL + JNZ RDEXIT + +RD1: MOV AH,1 + INT 22 + JZ CONBUS + OR AX,AX + JNZ RDEXIT + MOV AH,0 + INT 22 + JMP CON$RDND + +RDEXIT: LDS BX,[PTRSAV] + MOV [BX].MEDIA,AL +EXVEC: JMP EXIT +CONBUS: JMP BUS$EXIT +;---------------------------------------------------------- +; +; Keyboard Flush Routine +; +CON$FLSH: + MOV [ALTAH],0 ;Clear out holding buffer + + PUSH DS + XOR BP,BP + MOV DS,BP ;Select segment 0 + MOV DS:BYTE PTR 41AH,1EH ;Reset KB queue head + ;pointer + MOV DS:BYTE PTR 41CH,1EH ;Reset tail pointer + POP DS + JMP EXVEC +;---------------------------------------------------------- +; +; Console Write Routine +; +CON$WRIT: + JCXZ EXVEC + PUSH CX + MOV AH,3 ;Set current cursor position + XOR BX,BX + INT 16 + MOV WORD PTR [COL],DX + POP CX + +CON$LP: MOV AL,ES:[DI] ;Get Char + + 51 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + INC DI + CALL OUTC ;Output Char + LOOP CON$LP ;Repeat until all through + JMP EXVEC + +COUT: STI + PUSH DS + PUSH CS + POP DS + CALL OUTC + POP DS + IRET + +OUTC: PUSH AX + PUSH CX + PUSH DX + PUSH SI + PUSH DI + PUSH ES + PUSH BP + CALL VIDEO + POP BP + POP ES + POP DI + POP SI + POP DX + POP CX + POP AX + RET + + +;---------------------------------------------------------- +; +; Output Single Char in AL to Video Device +; +VIDEO: MOV SI,OFFSET STATE + JMP [SI] + +S1: CMP AL,ESC ;Escape sequence? + JNZ S1B + MOV WORD PTR [SI],OFFSET S2 + RET + +S1B: CALL CHROUT +S1A: MOV WORD PTR [STATE],OFFSET S1 + RET + + +S2: PUSH AX + CALL GETMOD + POP AX + MOV BX,OFFSET CMDTABL-3 +S7A: ADD BX,3 + CMP BYTE PTR [BX],0 + JZ S1A + CMP BYTE PTR [BX],AL + +52 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Device Drivers + + _ _________________________________ + + JNZ S7A + JMP WORD PTR [BX+1] + + +MOVCUR: CMP BYTE PTR [BX],AH + JZ SETCUR + ADD BYTE PTR [BX],AL +SETCUR: MOV DX,WORD PTR COL + XOR BX,BX + MOV AH,2 + INT 16 + JMP S1A + + +CUP: MOV WORD PTR [SI],OFFSET CUP1 + RET +CUP1: SUB AL,32 + MOV BYTE PTR [ROW],AL + MOV WORD PTR [SI],OFFSET CUP2 + RET +CUP2: SUB AL,32 + MOV BYTE PTR [COL],AL + JMP SETCUR + +SM: MOV WORD PTR [SI],OFFSET S1A + RET + + +CUH: MOV WORD PTR COL,0 + JMP SETCUR + +CUF: MOV AH,MAXCOL + MOV AL,1 +CUF1: MOV BX,OFFSET COL + JMP MOVCUR + +CUB: MOV AX,00FFH + JMP CUF1 + +CUU: MOV AX,00FFH +CUU1: MOV BX,OFFSET ROW + JMP MOVCUR + +CUD: MOV AX,23*256+1 + JMP CUU1 + +PSCP: MOV AX,WORD PTR COL + MOV SAVCR,AX + JMP SETCUR + +PRCP: MOV AX,SAVCR + MOV WORD PTR COL,AX + JMP SETCUR + +ED: CMP BYTE PTR [ROW],24 + JAE EL1 + + 53 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + MOV CX,WORD PTR COL + MOV DH,24 + JMP ERASE + +EL1: MOV BYTE PTR [COL],0 +EL: MOV CX,WORD PTR [COL] +EL2: MOV DH,CH +ERASE: MOV DL,MAXCOL + MOV BH,ATTR + MOV AX,0600H + INT 16 +ED3: JMP SETCUR + + +RM: MOV WORD PTR [SI],OFFSET RM1 + RET +RM1: XOR CX,CX + MOV CH,24 + JMP EL2 + +CON$INIT: + int 11h + and al,00110000b + cmp al,00110000b + jnz iscolor + mov [base],0b000h ;look for bw card +iscolor: + cmp al,00010000b ;look for 40 col mode + ja setbrk + mov [mode],0 + mov [maxcol],39 + +setbrk: + XOR BX,BX + MOV DS,BX + MOV BX,BRKADR + MOV WORD PTR [BX],OFFSET BREAK + MOV WORD PTR [BX+2],CS + + MOV BX,29H*4 + MOV WORD PTR [BX],OFFSET COUT + MOV WORD PTR [BX+2],CS + + LDS BX,CS:[PTRSAV] + MOV WORD PTR [BX].TRANS,OFFSET CON$INIT + ;SET BREAK ADDRESS + MOV [BX].TRANS+2,CS + JMP EXIT + +CODE ENDS + END + + + +54 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Chapter 2 + +MS-DOS Device Drivers + +_ ________________________________________________________________ + +2.1 Introduction 3 + +2.2 Format of a Device Driver 4 + +2.3 How to Create a Device Driver 5 + +2.3.1 Device Strategy Routine 6 + +2.3.2 Device Interrupt Routine 6 + +2.4 Installing Device Drivers 7 + +2.5 Device Headers 8 + +2.5.1 Pointer to Next Device Field 8 + +2.5.2 Attribute Field 9 + +2.5.3 Strategy and Interrupt Routines 11 + +2.5.4 Name Field 11 + +2.6 Request Header 11 + +2.6.1 Length of Record 12 + +2.6.2 Unit Code Field 12 + +2.6.3 Command Code Field 12 + +2.6.4 Status Field 13 + +2.7 Device Driver Functions 14 + +2.7.1 The Init Function 15 + +2.7.2 The Media Check Function 17 + +2.7.3 The Build BPB Function 19 + +2.7.4 The Read or Write Function 20 + +2.7.5 The Non-destructive Read, No Wait Function 22 + +2.7.6 The Open or Close Function 23 + +2.7.7 The Removable Media Function 24 + +2.7.8 The Status Function 24 + +2.7.9 The Flush Function 25 + + 1 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +2.7.10 The Generic IOCtl Function 25 + +2.7.11 The Get/Set Logical Drive Map Function 26 + +2.8 The Media Descriptor Byte 26 + +2.9 Format of a Media Descriptor Table 27 + +2.10 The CLOCK Device 29 + +2.11 Anatomy of a Device Call 29 + +2.12 Two Sample Device Drivers 30 + + + +2 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +54 + +_ _ | | _ _ + + + diff --git a/PROGREF/3_TECH.A b/PROGREF/3_TECH.A new file mode 100644 index 0000000..803a2a3 --- /dev/null +++ b/PROGREF/3_TECH.A @@ -0,0 +1,623 @@ + +_ _ | | _ _ + + MS-DOS Technical Information + + _ _______________________________________ + + +3.1 Introduction + +This chapter describes how MS-DOS initializes and how it allocates disk +space for the root directory, the File Allocation Tables (FAT), and the +data area. For programmers writing installable device drivers, this +chapter explains MS-DOS disk directory entries and File Allocation +Tables. At the end of the chapter, Tables 3.1 and 3.2 describe MS-DOS +standard formats for floppy disks. + +3.2 MS-DOS Initialization + +MS-DOS initialization consists of several steps. When you reset your com- +puter or turn on its power, the ROM (Read Only Memory) BIOS is invoked +and performs hardware checks and initialization. The ROM BIOS then +examines drive A for the boot sector. If it locates a boot sector, the ROM +BIOS reads it into low memory and gives it control. If it doesn't find the +boot sector, the ROM BIOS then looks in the active partition of the hard +disk. If it still doesn't find the boot sector, the ROM BIOS then invokes +ROM BASIC. + +On a removable disk (3.5-inch, 5.25-inch, or 8-inch disk), the boot sector +sector is always located on track 0, sector 1, side 0 of the disk. On a hard +disk, the boot sector begins on the first sector of the MS-DOS partition. +The hard disk boot sector also includes a partition table. This table +identifies the active MS-DOS partition and any other partitions, such as +an extended MS-DOS partition, on the hard disk. Note that extended +MS-DOS partitions are not bootable. + +The boot sector then reads the following files, in the order listed: + +io.sys +msdos.sys + +_ ________________________________________________________________ + +Note + + Versions of MS-DOS prior to 3.3 required the io.sys file to be contigu- + ous. This is no longer a requirement. + +_ ________________________________________________________________ + +Next, the system initialization routine SYSINIT loads all of the resident +device drivers. Then, it searches for a config.sys file on the boot disk. +SYSINIT allocates memory for buffers and files, based on settings in the +config.sys file, or system default settings. If the config.sys file specifies any + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +installable device drivers, these are installed next. + +Finally, SYSINIT executes the MS-DOS command processor, +command.com. + +3.3 The Command Processor + +The command processor command.com consists of three parts: + + o A resident part resides in memory immediately following msdos.sys + and its data area. This part contains routines to process Inter- + rupts 22H (Terminate Process Exit Address), 23H (CONTROL-C Exit + Address), and 24H (Critical-Error-Handler Address), as well as a + routine to reload the transient part, if needed. All standard + MS-DOS error handling is done within this part of command.com. + This includes displaying error messages and processing the Abort, + Retry, Fail, or Ignore messages. + + o An initialization part follows the resident part. During startup, the + initialization part is given control; it contains the processor setup + routine in the autoexec.bat file. The initialization part determines + the segment address at which programs can be loaded, and because + it is no longer needed, is overlaid by the first program that + command.com loads. + + o A transient part is loaded at the high end of memory. This part + contains all the internal command processors and the batch file + processor. + + The transient part of the command processor produces the system + prompt (A>, for example), reads commands from the keyboard (or + from batch files), and causes them to be executed. For external + commands, the transient part builds a command line and issues + Function 4BH (Load and Execute Program) to load and transfer + control to the program. + + +3.4 MS-DOS Disk Allocation + +The area on a disk partitioned for use by MS-DOS is formatted as follows: + + 1. Reserved area\(emvariable size + + 2. First copy of File Allocation Table\(emvariable size + + + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Technical Information + + _ _______________________________________ + + 3. Additional copies of File Allocation Table\(emvariable size (optional) + + 4. Root directory\(emvariable size + + 5. File data area + +Space for a file in the data area is not preallocated. The space is allocated +one cluster at a time. A cluster consists of one or more consecutive sectors +(the number of sectors in a cluster must be a power of 2); the cluster size is +determined at format time. All the clusters for a file are "chained" +together in the File Allocation Table, discussed in greater detail in Section +3.5, "File Allocation Table (FAT)." MS-DOS normally keeps a second copy +of the FAT for consistency, except in the case of reliable storage such as a +virtual RAM disk. Should the disk develop a bad sector in the middle of +the first FAT, MS-DOS can use the second. This avoids loss of data due to +an unreadable FAT. + +3.5 MS-DOS Disk Directory + +The format utility builds the root directory for all disks. This directory's +location on the disk and the maximum number of entries are dependent on +the media. Specifications for standard removable-disk formats are outlined +later in this chapter. Note, however, that MS-DOS regards directories, +other than the root directory, as files, so there is no limit to the number of +files that the subdirectories under the root directory may contain. + +All directory entries are 32 bytes in length and are in the following format +(note that byte offsets are in hexadecimal): + +Byte + Function +_ ________________________________________________________________ + + +0-7 Filename. Eight characters, left-aligned and padded, if neces- + sary, with blanks. The first byte of this field indicates the file + status as follows: + _ _____________________________________________________ + + 00H The directory entry has never been used. This is used + to limit the length of directory searches, for perfor- + mance reasons. + + 05H The first character of the filename contains an E5H + character. + + 2EH The entry is for a directory. If the second byte is also + 2EH, the cluster field contains the cluster number of + this directory's parent directory (0000H if the parent + directory is the root directory). Otherwise, bytes 01H + through 0AH are all spaces, and the cluster field con- + tains the cluster number of this directory. + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + E5H The file was used, but it has since been erased. + + Any other character is the first character of a filename. + +8-0A Filename extension. + +0B File attribute. The attribute byte is mapped as follows + (values are in hexadecimal): + + + Byte + Contents + _ _____________________________________________________ + + 01H File is marked read-only. An attempt to open the file + for writing using Function 3DH (Open Handle) results + in an error code being returned. This value can be + used in programs along with the other attributes in + this list. Attempts to delete the file with Function + 13H (Delete File) or Function 41H (Delete Directory + Entry) will also fail. + + 02H Hidden file. The file is excluded from normal directory + searches. + + 04H System file. The file is excluded from normal directory + searches. + + 08H The entry contains the volume label in the first 11 + bytes. The entry contains no other usable information + (except date and time of creation), and may exist only + in the root directory. + + 10H The entry defines a subdirectory, and is excluded from + normal directory searches. + + 20H Archive bit. The bit is set to "on" whenever the file + has been written to and closed. + + Note: The system files (io.sys and msdos.sys) are + marked as read-only, hidden, and system files. Files + can be marked hidden when they are created. Also, + you may change the read-only, hidden, system, and + archive attributes through Function 43H (Get/Set File + Attributes). + +0C-15 Reserved. + +16-17 Time the file was created or last updated. The hour, minutes, + and seconds are mapped into two bytes as follows (bit 7 on + the left, 0 on the right): + + Offset 17H + | H | H | H | H | H | M | M | M | + + Offset 16H + | M | M | M | S | S | S | S | S | + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Technical Information + + _ _______________________________________ + + where: + + H is the binary number of hours (0-23). + M is the binary number of minutes (0-59). + S is the binary number of two-second increments. + + +18-19 Date the file was created or last updated. The year, month, + and day are mapped into two bytes as follows: + + Offset 19H + | Y | Y | Y | Y | Y | Y | Y | M | + + Offset 18H + | M | M | M | D | D | D | D | D | + + where: + + Y is the year, 0-119 (1980-2099). + M is the month (1-12). + D is the day of the month (1-31). + + +1A-1B Starting cluster; the number of the first cluster in the file. + + o Note that the first cluster for data space on all disks is + cluster 002. + + o The cluster number is stored with the least significant + byte first. + + o For details about converting cluster numbers to logical + sector numbers, see Sections 3.5.1 and 3.5.2. + + +1C-1F File size in bytes. The first word of this four-byte field is the + low-order part of the size. + + +3.6 File Allocation Table (FAT) + +This section explains how MS-DOS allocates disk space in the data area +for a file by using the File Allocation Table to convert the clusters of a file +to logical sector numbers. The device driver is then responsible for locat- +ing the logical sector on the disk. Programs should use the MS-DOS file +management function calls for accessing files. Programs that access the +FAT are not guaranteed to be upwardly-compatible with future releases of +MS-DOS. The following information is useful to system programmers who +wish to write installable device drivers. + +The File Allocation Table is an array of 12-bit entries (1.5 bytes) for each +cluster on the disk. For disks containing more than 4085 clusters, a 16-bit +FAT entry is used. + + + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The first two FAT entries are reserved; however, the device driver may use +the first byte as a FAT ID byte for determining media. For hard disks, the +value of this byte is F8H. See Tables 3.1 and 3.2 for the media byte +descriptors used for 8-inch, 5.25-inch, and 3.5-inch disks. + +The third FAT entry, which starts at byte offset 4, begins the mapping of +the data area (cluster 002). The operating system does not always sequen- +tially write (to the disk) files in the data area. Instead, the system allo- +cates the data area one cluster at a time, skipping over clusters it has +already allocated. The first free cluster following the last cluster allocated +for that file is the next cluster allocated, regardless of its physical location +on the disk. This permits the most efficient use of disk space, since if you +erase old files, you can free clusters, which the operating system can then +allocate for new files. + +Each FAT entry contains three or four hexadecimal characters, depending +on whether it is a 12-bit or 16-bit entry: + +_ ________________________________________________________________ + +(0)000 If the cluster is unused and available. + +(F)FF7 The cluster has a bad sector in it if it is not part of any + cluster chain. MS-DOS will not allocate such a cluster. So + for its report, the chkdsk command counts the number of + bad clusters, which are not part of any allocation chain. + +(F)FF8-FFF The last cluster of a file. + +(X)XXX Any other characters that are the cluster number of the + next cluster in the file. The number of the first cluster in + the file is in the file's directory entry. + +The File Allocation Table always begins on the first sector after the +reserved sectors. If the FAT is larger than one sector, the sectors are con- +tiguous. The operating system usually writes two copies of the FAT to +preserve data integrity. MS-DOS reads the FAT into one of its buffers, +whenever needed (open, read, write, etc.). The operating system also gives +this buffer a high priority to keep it in memory as long as possible. + +3.6.1 How to Use the FAT (12-Bit FAT Entries) + +To get the starting cluster of a file, examine its directory entry (in the +FAT). Then, to locate each subsequent cluster of the file, follow these +steps: + + 1. Multiply the cluster number just used by 1.5 (each FAT entry is + 1.5 bytes in length). + + 2. The whole part of the product is an offset into the FAT, pointing + to the entry that maps the cluster just used. That entry contains + the cluster number of the next cluster of the file. + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Technical Information + + _ _______________________________________ + + 3. Use a MOV instruction to move the word at the calculated FAT + offset into a register. + + 4. If the last cluster used was an even number, keep the low-order 12 + bits of the register by using the AND operator with 0FFFH and the + register. If the last cluster used was an odd number, keep the + high-order 12 bits by using the SHR instruction to shift the register + right four bits. + + 5. If the resultant 12 bits are 0FF8H-0FFFH, the file contains no + more clusters. Otherwise, the 12 bits contain the number of the + next cluster in the file. + +To convert the cluster to a logical sector number (relative sector, such as +that used by Interrupts 25H and 26H (Absolute Disk Read/Write) and by +debug), follow these steps: + + 1. Subtract two from the cluster number. + + 2. Multiply the result by the number of sectors per cluster. + + 3. To this result, add the logical sector number of the beginning of + the data area. + + +3.6.2 How to Use the FAT (16-Bit FAT Entries) + +To get the starting cluster of a file, examine its directory entry (in the +FAT). Then, to find the next file cluster, follow these steps: + + 1. Multiply the cluster number last used by 2 (each FAT entry is 2 + bytes). + + 2. Use a MOV WORD instruction to move the word at the calculated + FAT offset into a register. + + 3. If the resultant 16 bits are 0FFF8-0FFFH, no more clusters are in + the file. Otherwise, the 16 bits contain the number of the next + cluster in the file. + + +3.7 MS-DOS Standard Disk Formats + +MS-DOS arranges data clusters on a disk to minimize head movement. +MS-DOS then allocates all the space on one track (or cylinder) before mov- +ing to the next. It uses the sequential sectors on the lowest-numbered +head, then all the sectors on the next head, and so on, until it has used all +the sectors on all the heads of the track. + + + + 9 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The size of the MS-DOS partition on a hard disk determines the size of the +FAT and root directory. Likewise, the type of floppy disk (tracks per side, +sectors per track, etc.) determines how MS-DOS uses the disk. The remov- +able disk formats listed in Tables 3.1 and 3.2 are standard and should be +readable in the appropriate standard drive. + + +10 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Technical Information + + _ _______________________________________ + +Table 3.1 + +MS-DOS Standard Removable-Disk Formats + +_ _________________________________________________________________________ + +Disk Size in inches 5.25 8 + +_ _________________________________________________________________________ + +WORD no. heads 1 1 2 2 1 2 1 + +Tracks/side 40 40 40 40 77 77 77 + +WORD sectors/track 8 9 8 9 26 26 8 + +WORD bytes/sector 512 512 512 512 128 128 024 + +BYTE sectors/ cluster 1 1 2 2 4 4 1 + +WORD reserved sectors 1 1 1 1 1 4 1 + +Byte no. FATs 2 2 2 2 2 2 2 + +WORD root directory entries 64 64 112 112 68 68 192 + +WORD no. sectors 320 360 640 720 2002 2002 616 + +BYTE media descriptor FE FC FF FD *FE FD *FE + +WORD sectors/FAT 1 2 1 2 6 6 2 + +WORD no. hidden sectors 0 0 0 0 0 0 0 + +_ _________________________________________________________________________ + +*The two media descriptor bytes are the same for 8" disks (FEH). This is not a misprint. To +establish whether a disk is single- or double-density, try a read of a single-density address +mark. If an error occurs, the media is double-density. + +Table 3.2 + +MS-DOS Standard Removable Disk Formats (High-Density) + +_ _________________________________________________________________________ + +Disk Size in inches 3.5 or 5.25 3.5 5.25 + +_ _________________________________________________________________________ + +WORD no. heads 1 2 2 2 2 2 + +Tracks/side 80 80 80 80 80 80 + +WORD sectors/track 8 9 8 9 18 15 + +WORD bytes/sector 512 512 512 512 512 512 + +BYTE sectors/cluster 2 2 2 2 1 1 + +WORD reserved sectors 1 1 1 1 1 1 + +BYTE no. FATs 2 2 2 2 2 2 + +WORD root dir entries 112 112 112 112 224 224 + +WORD no. sectors 640 720 1280 1440 2880 2400 + +BYTE media descriptor* FA FC FB F9 F0 F9 + +WORD sectors/FAT 1 2 2 3 9 7 + +WORD no. hidden sectors 0 0 0 0 0 0 + +_ _________________________________________________________________________ + +*The value F0H in the media descriptor byte may be used to describe other media types. + + + 11 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +Chapter 3 + +MS-DOS Technical Information + +_ ________________________________________________________________ + +3.1 Introduction 3 + +3.2 MS-DOS Initialization 3 + +3.3 The Command Processor 4 + +3.4 MS-DOS Disk Allocation 4 + +3.5 MS-DOS Disk Directory 5 + +3.6 File Allocation Table (FAT) 7 + +3.6.1 How to Use the FAT (12-Bit FAT Entries) 8 + +3.6.2 How to Use the FAT (16-Bit FAT Entries) 9 + +3.7 MS-DOS Standard Disk Formats 9 + + + +12 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +12 + +_ _ | | _ _ + + + diff --git a/PROGREF/4_CTRLB.A b/PROGREF/4_CTRLB.A new file mode 100644 index 0000000..863ab36 --- /dev/null +++ b/PROGREF/4_CTRLB.A @@ -0,0 +1,393 @@ + +_ _ | | _ _ + + MS-DOS Control Blocks and Work Areas + + _ ______________________________________________ + + +4.1 Introduction + +This chapter describes a typical MS-DOS memory map and explains how a +program is loaded into memory. It also describes the structure of an +MS-DOS program segment and the contents of register segments for .exe +and .com program files. + +4.2 Typical Contents of an MS-DOS Memory +Map + +A typical MS-DOS memory map contains the following information: + + + +-----------------------------------------------------+ + | ROM and Video Buffers | + +-----------------------------------------------------+ + | Transient Part of COMMAND.COM | + +-----------------------------------------------------+ + | | + | | + | | + | | + | Transient Program Area | + |- - - - - - - - - - - - - - - - - - - - - - - - - - -| + | | + | | + | | + | | + | External Commands and Utilities | + | | + +-----------------------------------------------------+ + | Resident Part of COMMAND.COM | + +-----------------------------------------------------+ + | MS-DOS buffers, control areas, & installed drivers | + +-----------------------------------------------------+ + | | + | MSDOS.SYS | + +-----------------------------------------------------+ + | IO.SYS and resident device drivers | + +-----------------------------------------------------+ + | Interrupt Vectors | + 0 +-----------------------------------------------------+ + +During system initialization, MS-DOS loads the io.sys and msdos.sys files +into low memory (Note that in MS-DOS 3.3, these files are not required to +be written contiguously to the disk). The io.sys system file is the MS-DOS +interface to hardware. The msdos.sys system file includes MS-DOS inter- +rupt handlers, service routines (Interrupt 21H functions). + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +Next, the system initialization routine loads the resident and installable +device drivers. Above the installable device drivers, MS-DOS writes the +resident part of command.com. This part includes interrupt handlers for +Interrupts 22H (Terminate Process Exit Address), 23H (CONTROL-C +Handler Address), 24H (Critical-Error-Handler Address) and code to reload +the transient part. The transient part of command.com is reloaded into +high memory. It includes the command interpreter, the internal MS-DOS +commands, and the batch processor. + +External command and utility (.com and .exe) files are loaded into the +transient program area. MS-DOS also allocates 256 bytes for user stack +used with .com files. User memory is allocated from the lowest end of +available memory that fulfills the allocation request. + +4.3 MS-DOS Program Segment + +When you type an external command or execute a program through Func- +tion 4BH (Load and Execute Program, also called EXEC), MS-DOS deter- +mines the lowest available free memory address to use as the start of the +program. The memory starting at this address is called the Program Seg- +ment. + +The EXEC system call sets up the first 256 bytes of the Program Segment +for the program being loaded into memory. The program is then loaded +following this block. An .exe file with minalloc and maxalloc both set to +zero is loaded as high as possible. + +At offset 0 within the Program Segment, MS-DOS builds the Program Seg- +ment Prefix control block. The program returns from EXEC by one of five +methods: + + o By issuing an Interrupt 21H with AH=4CH + + o By issuing an Interrupt 21H with AH=31H (Keep Process) + + o By a long jump to offset 0 in the Program Segment Prefix + + o By issuing an Interrupt 20H with CS:0 pointing at the PSP + + o By issuing an Interrupt 21H with register AH=0 and with CS:0 + pointing at the PSP + +_ ________________________________________________________________ + +Note + + The first two methods are preferred for functionality, compatibility, + and efficiency in future versions of MS-DOS. + +_ ________________________________________________________________ + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Control Blocks and Work Areas + + _ ______________________________________________ + +All five methods transfer control to the program that issued the EXEC +call. The first two methods return a completion code. They also restore +the addresses of Interrupts 22H, 23H, and 24H (Terminate Process Exit +Address, CONTROL-C Handler Address, and Critical-Error-Handler Address) +from the values saved in the Program Segment Prefix of the terminating +program. Control then passes to the terminate address. + +If a program returns to command.com, control transfers to the resident +portion. If the program is a batch file (in process), it continues. Other- +wise, command.com performs a checksum on the transient part, reloads it +if necessary, issues the system prompt, and waits for you to type another +command. + +When a program receives control, the following conditions are in effect: + +For all programs: + + o The segment address of the passed environment is at offset 2CH in + the Program Segment Prefix. + + o The environment is a series of ASCII strings (totaling less than 32K) + in the form: + + NAME=parameter + + o A byte of zeros terminates each string, and another byte of zeros + terminates the set of strings. + + Following the last byte of zeros is a set of initial arguments that + the operating system passes to a program. This set of arguments + contains a word count followed by an ASCII string. If the file is in + the current directory, the ASCII string contains the drive and path- + name of the executable program as passed to the EXEC function + call. If the file is not in the current directory, EXEC concatenates + the name of the file with the name of the path. Programs may use + this area to determine where the program was loaded. + + o The environment built by the command processor contains at least + a comspec= string (the parameters on comspec define the path + that MS-DOS uses to locate command.com on disk). The last path + and prompt commands issued are also in the environment, along + with any environment strings you have defined with the MS-DOS + set command. + + o EXEC passes a copy of the invoking process environment. If your + application uses a "keep process" concept, you should be aware + that the copy of the environment passed to you is static. That is, + it will not change even if you issue subsequent set, path, or + prompt commands. Conversely, any modification of the passed + environment by the application is not reflected in the parent pro- + cess environment. For instance, a program cannot change the + MS-DOS environment values as the set command does. + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + o The Disk Transfer Address (DTA) is set to 80H (default DTA in the + Program Segment Prefix). The Program Segment Prefix contains + file control blocks at 5CH and 6CH. MS-DOS formats these blocks + using the first two parameters that you typed when entering the + command. If either parameter contained a pathname, then the + corresponding FCB contains only the valid drive number. The + filename field is not valid. + + o An unformatted parameter area at 81H contains all the characters + typed after the command (including leading and embedded delim- + iters), with the byte at 80H set to the number of characters. If you + type <, >, or parameters on the command line, they do not + appear in this area (nor the filenames associated with them). + Redirection of standard input and output is transparent to appli- + cations. + + o Offset 6 (one word) contains the number of bytes available in the + segment. + + o Register AX indicates whether the drive specifiers (entered with the + first two parameters) are valid, as follows: + + AL=FF if the first parameter contained an invalid drive specifier + (otherwise AL=00) + + AH=FF if the second parameter contained an invalid drive + specifier (otherwise AH=00) + + o Offset 2 (one word) contains the segment address of the first byte + of unavailable memory. Programs must not modify addresses + beyond this point unless these addresses were obtained by allocat- + ing memory via Function 48H (Allocate Memory). + + +For Executable (.exe) Programs: + + o DS and ES registers point to the Program Segment Prefix. + + o CS,IP,SS, and SP registers contain the values that Microsoft link + sets in the .exe image. + + +For Executable (.com) Programs: + + o All four segment registers contain the segment address of the ini- + tial allocation block that starts with the Program Segment Prefix + control block. + + o .com programs allocate all of user memory. If the program invokes + another program through Function 4BH (EXEC), it must first free + some memory through Function 4AH (Set Block) to provide space + for the program being executed. + + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + MS-DOS Control Blocks and Work Areas + + _ ______________________________________________ + + o The Instruction Pointer (IP) is set to 100H. + + o The Stack Pointer register is set to the end of the program's seg- + ment. The segment size at offset 6 is reduced by 100H to allow for + a stack of that size. + + o A .com program places a word of zeros on top of the stack. Then + by doing a RET instruction last, your program can exit to + command.com. This method assumes, however, that you have + maintained your stack and code segments. + +Figure 4.1 illustrates the format of the Program Segment Prefix. All +offsets are in hexadecimal. + + (Offsets in Hex) +0 ----------------------------------------------------------- + | | End of | | + | INT 20H | alloc. | Reserved | + | | block | 04H | +8 ----------------------------------------------------------- + | | Terminate address | CONTROL-C exit | + | Reserved | (IP, CS) | address (IP) | + | | | | +10----------------------------------------------------------- + |CONTROL-C | Hard error exit address | | + |exit | (IP, CS) | | + |address (CS)| | | + ---------------------------------------- | + | | + | Used by MS-DOS | + | | + | 5CH | + | | + ----------------------------------------------------------- + | | + | Formatted Parameter Area 1 formatted as standard | + | unopened FCB 6CH | + ----------------------------------------------------------- + | | + | Formatted Parameter Area 2 formatted as standard | + | unopened FCB (overlaid if FCB at 5CH is opened) | +80----------------------------------------------------------- + | Unformatted Parameter Area | + | (default Disk Transfer Area) | + | Initially contains command invocation line. | + ----------------------------------------------------------- +100 + + + Figure 4.1 Program Segment Prefix + +_ ________________________________________________________________ + +Important + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + Programs must not alter any part of the Program Segment Prefix + below offset 5CH. + +_ ________________________________________________________________ + + + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Chapter 4 + +MS-DOS Control Blocks + +and Work Areas + +_ ________________________________________________________________ + +4.1 Introduction 3 + +4.2 Typical Contents of an MS-DOS Memory Map 3 + +4.3 MS-DOS Program Segment 4 + + + + 1 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +8 + +_ _ | | _ _ + + + diff --git a/PROGREF/5_NLS.A b/PROGREF/5_NLS.A new file mode 100644 index 0000000..6ae548f --- /dev/null +++ b/PROGREF/5_NLS.A @@ -0,0 +1,360 @@ + +_ _ | | _ _ + + National Language Support + + _ ____________________________________ + + +5.1 Introduction + +National language support for this version of MS-DOS 3.3 includes these +major features: + + o Country-dependent information + + o Support for national keyboard layouts + + o Programming interfaces for national language support + + o Utility commands + +Country-dependent information is available on a per-country basis and +includes the following: + + o Time, date, and currency + + o Lowercase-to-uppercase character-conversion tables + + o Collating sequence for character sorting + + o Valid single-byte characters used in filenames + +Selectable keyboard support for different keyboard layouts is provided. + +The MS-DOS 3.3 programming interfaces for national language support +allow applications to use the country-dependent information just +described. To access this information, applications do not need to change +the current country code of the system. + +Utility commands allow the user to select the keyboard layout and system +country code. + +This version of MS-DOS does not support right-to-left national languages. + +5.2 National Language Support Calls + +The following function calls allow an application to tailor its operation to +the current country code and to accept or change the current code page. +A country code defines the country in which you live or work. MS-DOS +uses this code to prepare and assign default code pages for your system. A +code page is a table that defines the character set you are using. A +character set is a country-specific or language-specific group of characters +that are translated from the code page table and displayed on your screen +or printer. Each code page character set contains 256 characters. + + + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The following function calls are also used by MS-DOS 3.3 to support the +National Language requirements: + + o Function 44H, Code 0CH (Generic IOCtl) \(em supports code page + switching on a per-device basis. + + o Function 65H (Get Extended Country Information) \(em returns + standard country information, and points to related case-map or + collating tables. + + o Function 66H (Get/Set Global Code Page) \(em gets or sets the code + page used by the kernel and by all devices. + +These functions support access to country-dependent information, all of +which resides in one file named country.sys. + +5.3 Font Files + +Font files, also called code page information files, contain the images of +code page character sets for use by console-screen or printer devices. +These font files are identified by a filename extension of .cpi. Four font +files are included with MS-DOS 3.3: + +Font file + Supported device +_ ________________________________________________________________ + +ega.cpi Color console used with an EGA card + +lcd.cpi Liquid crystal display + +4201.cpi IBM Proprinter + +5202.cpi Quietwriter III printer + + +5.3.1 Font File Structure + +The contents of printer or console-screen font files are structured as fol- +lows: + + +--------------------------------------+ + | 22-BYTE File Header | + +--------------------------------------+ + | WORD Information Header | + +--------------------------------------+ + | 13-BYTE Code Page Entry Header | + +--------------------------------------+ + | 6-BYTE Font Data Header | + +--------------------------------------+ + | Variable size Font Header(s) | + +--------------------------------------+ + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + National Language Support + + _ ____________________________________ + + + + + Figure 5.1 Font File Structure + +The font file fields are described in the following sections. + +5.3.1.1 File Header + +Each file must begin with a file header that includes the following: + +Length + Parameter +_ ________________________________________________________________ + +8 BYTES File tag + +8 BYTES Reserved + +WORD Number of pointers + +2 WORDS Offset + +where: + +File tag begins with the byte 0FFH and is followed by a string "font " +(seven characters). + +Reserved is eight bytes of zeros. + +Number of pointers is the number of pointers in the header. For MS-DOS +3.3, the value of this word should be 1. + +Offset is the two-word offset from the beginning of the file. + +5.3.1.2 Information Header + +Following the file header is a one-word information header: + +Length + Parameter +_ ________________________________________________________________ + +WORD Number of code pages + +where: + +Number of code pages is the number of code page entries in the file. + + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +5.3.1.3 Code Page Entry Header + +For each code page entry, a header in the following format is included in +the font file: + +Length + Parameter +_ ________________________________________________________________ + +WORD Length + +WORD Pointer + +WORD Device type + +8 BYTES Device subtype + +WORD Code page ID + +WORD Reserved + +2 WORDS Offset + +where: + +Length is the size of the code page entry header. + +Pointer points to the next code page entry header (last header=0, 0). + +Device type is 1 if the device is a console screen, or 2 if the device is a +printer. + +Device subtype names the type of console screen or printer. This field also +determines the name of the font file. For example, if the subtype is +"CGA," the font file name is cga.cpi + +Code page ID defines a valid three-digit code page identification number. +Valid code page numbers are 437, 850, 860, 863, and 865. + +Reserved is eight bytes of zeros. + +Offset is a pointer to the Font Data Header. + +5.3.1.4 Font Data Header + +The Font Data Header includes the following fields: + +Length + Parameter +_ ________________________________________________________________ + +WORD Reserved + +WORD Number of fonts + + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + National Language Support + + _ ____________________________________ + +WORD Length of font data + +where: + +Reserved must be 1. + +Number of fonts is equal to the number of fonts defined in the font file. + +Length of font data is equal to the size of the font-data portion of the font +file. + +5.3.1.5 Font Header + +The font-data portion of a font file will vary for each device. The struc- +ture of the font-data portion consists of a set of data for each font type. +The following illustrates the data portion of a font file for a console-screen +device: + +font_header: + db 16, 8 ; character pixels + ; (rows, columns) + db 0, 0 ; aspect ratio (unused) + dw 256 ; number of characters in set + + +len_data equ ($ - font_header) + + + + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Chapter 5 + +National Language Support + +_ ________________________________________________________________ + +5.1 Introduction 3 + +5.2 National Language Support Calls 3 + +5.3 Font Files 4 + +5.3.1 Font File Structure 4 + +5.3.1.1 File Header 5 + +5.3.1.2 Information Header 5 + +5.3.1.3 Code Page Entry Header 6 + +5.3.1.4 Font Data Header 6 + +5.3.1.5 Font Header 7 + + + + 1 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + + 7 + +_ _ | | _ _ + + + diff --git a/PROGREF/6_EXE.A b/PROGREF/6_EXE.A new file mode 100644 index 0000000..73a4433 --- /dev/null +++ b/PROGREF/6_EXE.A @@ -0,0 +1,203 @@ + +_ _ | | _ _ + + .Exe File Structure and Loading + + _ _______________________________________ + +_ ________________________________________________________________ + +Note + + This chapter describes .exe file structure and loading procedures for + systems that use a version of MS-DOS earlier than 2.0. For MS-DOS + versions 2.0 and later, use Function 4B00H (Load and Execute a Pro- + gram) to load (or load and execute) an .exe file. + +_ ________________________________________________________________ + +The .exe files produced by link consist of two parts: + + o Control and relocation information + + o The load module + +The control and relocation information is at the beginning of the file in an +area called the header. Immediately following this header is the load +module. + +6.1 Format of a File Header + +The header is formatted as follows (note that offsets are in hexadecimal): + +Offset + Contents +_ ________________________________________________________________ + +0-1 Must contain 4DH, 5AH. + +2-3 Number of bytes contained in last page; useful for reading + overlays. + +4-5 Size of the file in 512-byte pages, including the header. + +6-7 Number of relocation entries in table. + +8-9 Size of the header in 16-byte paragraphs. Used to locate the + beginning of the load module in the file. + +AH-BH Minimum number of 16-byte paragraphs required above the + end of the loaded program. + +CH-DH Maximum number of 16-byte paragraphs required above the + end of the loaded program. If both minalloc and maxalloc + are 0, the program is loaded as high as possible. + +EH-FH Initial value to be loaded into stack segment before starting + program execution. Must be adjusted by relocation. + + + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +10-11 Value to be loaded into the SP register before starting pro- + gram execution. + +12-13 Negative sum of all the words in the file. + +14-15 Initial value to be loaded into the IP register before starting + program execution. + +16-17 Initial value to be loaded into the CS register before starting + program execution. Must be adjusted by relocation. + +18-19 Relative byte offset from beginning of run file to relocation + table. + +1AH-1BH The number of the overlay as generated by link. + + +6.2 The Relocation Table + +The relocation table that follows the formatted area above, consists of a +variable number of relocation items. Each relocation item contains two +fields: a two-byte offset value, followed by a two-byte segment value. +These two fields contain the offset into a word's load module. This item +requires modification before the module is given control. The following +steps describe this process: + + 1. The formatted part of the header is read into memory. Its size is + 1BH. + + 2. MS-DOS allocates a portion of memory depending on the size of + the load module and the allocation numbers (AH-BH and CH-DH). + MS-DOS then attempts to allocate 0FFFH paragraphs. This + attempt always fails, and returns the size of the largest free block. + If this block is smaller than minalloc and loadsize, there is no + memory error. But if this block is larger than maxalloc and + loadsize, MS-DOS allocates (maxalloc + loadsize). Otherwise, it + allocates the largest free block of memory. + + 3. A Program Segment Prefix is built in the lowest part of the allo- + cated memory. + + 4. MS-DOS calculates the load module size (using offsets 4-5 and 8-9) + by subtracting the header size from the file size. The actual size is + adjusted down based on the contents of offsets 2-3. The operating + system determines (based on the setting of the high/low load + switch) an appropriate segment, called the start segment, where it + loads the load module. + + 5. The load module is read into memory beginning with the start seg- + ment. + + + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + .Exe File Structure and Loading + + _ _______________________________________ + + 6. The items in the relocation table are read into a work area. + + 7. MS-DOS adds the segment value of each relocation table item to + the start segment value. This calculated segment, plus value, + points to the module to which the start segment value is added. + The result is then placed back into the word in the load module. + + 8. Once all relocation items have been processed, the operating sys- + tem sets the SS and SP registers, using the values in the header. + MS-DOS then adds the start segment value to SS and sets the ES + and DS registers to the segment address of the Program Segment + Prefix. The start segment value is then added to the header CS + register value. The result, along with the header IP value, is the + initial CS:IP to transfer to before starting execution of the pro- + gram. + + + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + + _ ______________ + + +Chapter 6 + +.Exe File Structure and Loading + +_ ________________________________________________________________ + +6.1 Format of a File Header 3 + +6.2 The Relocation Table 4 + + + + 1 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + + 5 + +_ _ | | _ _ + + + diff --git a/PROGREF/7_OMF.A b/PROGREF/7_OMF.A new file mode 100644 index 0000000..cd3e50d --- /dev/null +++ b/PROGREF/7_OMF.A @@ -0,0 +1,2555 @@ + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + + +7.1 Introduction + +This chapter presents the object record formats that define the relocatable +object language for the 8086, 80186, and 80286 microprocessors. The 8086 +object language is the output of all language translators that have an 8086 +processor and that will be linked by the Microsoft linker. The 8086 object +language is used for input and output for object language processors such +as linkers and librarians, and is used in the XENIX, PC-DOS, and MS-DOS +operating systems. + +The 8086 object module formats let you specify relocatable memory +images that may be linked together. These formats also allow efficient use +of the memory mapping facilities of the 8086 family of microprocessors. + +The following table lists the record formats (each described in this +chapter) that Microsoft supports (the abbreviations appear in +parentheses): + +Table 7.1 + +Object Module Record Formats + +_ _________________________________________________________________________ + +Symbol Definition Records + +Public Names Definition Record (PUBDEF) +Communal Names Definition Record (COMDEF) +Local Symbols Record (LOCSYM) +External Names Definition Record (EXTDEF) +Line Numbers Record (LINNUM) + +Data Records + +Logical Enumerated Data Record (LEDATA) +Logical Iterated Data Record (LIDATA) + +T-Module Header Record (THEADR) +L-Module Header Record (LHEADR) +List of Names Record (LNAMES) +Segment Definition Record (SEGDEF) +Group Definition Record (GRPDEF) + +Fixup Record (FIXUPP) +Module End Record (MODEND) +Comment Record (COMENT) + +_ _________________________________________________________________________ + + + + 3 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +_ ________________________________________________________________ + +Note + + If an object module contains any undefined values, the behavior of the + Microsoft linker is undefined. All undefined values should be con- + sidered reserved by Microsoft for future use. + +_ ________________________________________________________________ + + +7.1.1 Definition of Terms + +The following terms are fundamental to 8086 relocation and linkage: + +OMF - Object Module Formats + + +MAS - Memory Address Space + +The 8086 MAS is one megabyte (1,048,576 bytes). Note that the MAS is +distinguished from actual memory, which may occupy only a portion of +the MAS. + +Module + +A module is an "inseparable" collection of object code and other informa- +tion produced by a translator. + +T-Module + +A T-module is a module created by a translator, such as Pascal or FOR- +TRAN. + +The following restrictions apply to object modules: + + o Every module should have a name. Translators provide default + names (possibly filenames or null names) for T-modules if neither + the source code nor the user specifies otherwise. + + o Every T-module in a collection of linked modules should have a + different name so that symbolic debugging systems can distinguish + the various line numbers and local symbols. The Microsoft linker + does not require or enforce this restriction. + + + +4 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + + +Frame + +A frame is a contiguous region of 64K of memory address space (MAS), +beginning on a paragraph boundary (i.e., on a multiple of 16 bytes) or on a +selector on the 80286 processor. This concept is useful because the con- +tents of the four 8086 segment registers define four (possibly overlapping) +frames; no 16-bit address in the 8086 code can access a memory location +outside the current four frames. + +LSEG (Logical Segment) + +A logical segment (LSEG) is a contiguous region of memory whose contents +are determined at translation time (except for address-binding). Neither +the size nor the location in MAS are necessarily determined during transla- +tion: the size, although partially fixed, may not be final because the linker +may combine the LSEG when linking with other LSEGs, forming a single +LSEG. So that it can fit in a frame, an LSEG must not be larger than +64K. Thus, a 16-bit offset, from the base of a frame that covers the LSEG, +may address any byte in that LSEG. + +PSEG (Physical Segment) + +This term is equivalent to frame. Some prefer "PSEG" to "frame" because +the terms PSEG and LSEG reflect the "physical" and "logical" nature of +the underlying segments. + +Frame Number + +Every frame begins on a paragraph boundary. The "paragraphs" in MAS +can be numbered from 0 through 65,535. These numbers, each of which +defines a frame, are called frame numbers. + +Group + +A group is a collection of LSEGs defined at translation time, whose final +locations in MAS have been constrained so that at least one frame exists +that covers (contains) every LSEG in the collection. + +The notation "Gr A(X,Y,Z,)" means that LSEGs X, Y, and Z form a group +named A. That X, Y, and Z are all LSEGs in the same group does not +imply any ordering of X, Y, and Z in MAS, nor does it imply any contiguity +between X, Y, and Z. + + + + 5 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The Microsoft linker does not currently allow an LSEG to be a member of +more than one group. + +Canonic + +On the 8086 processor, any location in MAS is contained in exactly 4096 +distinct frames, but one of these frames can be distinguished because it +has a higher frame number. This frame is called the canonic frame of the +location. In other words, the canonic frame of a given byte is the frame +chosen so that the byte's offset from that frame lies in the range 0 to 15 +(decimal). + +For example, suppose FOO is a symbol defining a memory location. You +would then refer to this frame as the "canonic frame of FOO." Similarly, if +S is any set of memory locations, then a unique frame exists that has the +lowest frame number in the set of canonic frames of the locations in S. +This unique frame is called the canonic frame of the set S. You might +refer similarly to the canonic frame of an LSEG or of a group of LSEGs. + +Segment Name + +LSEGs are assigned Segment Names at translation time. These names +serve two purposes: + + o During linking they play a role in determining which LSEGs are + combined with other LSEGs. + + o They are used in assembly source code to specify membership in + groups. + + +Class Name + +The translator may optionally assign class names to LSEGs during transla- +tion. Classes define a partition on LSEGs: two LSEGs are in the same +class if they have the same class name. + +The Microsoft linker applies the following semantics to class names: the +class name "CODE", or any class name whose suffix is "CODE", implies +that all segments of that class contain only code and may be considered +read-only. Such segments may be overlaid if you specify the module con- +taining the segment as part of an overlay. + + +6 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + + +Overlay Name + +The linker may optionally assign an overlay name to LSEGs. The overlay +name of an LSEG is ignored by Microsoft language linkers for version 3.00 +and later languages, but the standard MS-DOS linker supports it. + +Complete Name + +The complete name of an LSEG consists of the segment name, class name, +and overlay name. The linker combines LSEGs from different modules if +their complete names are identical. + +7.2 Module Identification and Attributes + +A module header record, which provides a module name, is always the first +record in a module. In addition to having a name, a module may represent +a main program and may have a specified starting address. When linking +multiple modules together, you should give only one module with the main +attribute. If more than one main module appears, the first takes +precedence. + +In summary, modules may or may not be main and may or may not have a +starting address. + +7.2.1 Segment Definition + +A module is a collection of object code defined by a sequence of records +that a translator produces. The object code represents contiguous regions +of memory whose contents the linker determines during translation. +These regions are LSEGs. A module defines the attributes of each LSEG. +The segment definition record (SEGDEF) is responsible for maintaining all +LSEG information (name, length, memory alignment, etc.). The linker +requires the LSEG information when you combine multiple LSEGs and +when it establishes segment addressability. The SEGDEF records must +follow the first header record. + +7.2.2 Addressing a Segment + +The 8086 addressing mechanism provides segment base registers from +which you may address a 64K-byte region of memory (a Frame). There is +one code segment base register (CS), two data segment base registers (DS, +ES), and one stack segment base register (SS). + + + + 7 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +The possible number of LSEGs that may make up a memory image far +exceeds the number of available base registers. Thus, base registers may +require frequent loading. This would be the case in a modular program +with many small data and/or code LSEGs. + +Since such frequent loading of base registers is undesirable, it is a good +strategy to collect many small LSEGs together into a single unit that will +fit in one memory frame. Then all the LSEGs may be addressed using the +same base register value. This addressable unit is a group and has been +defined earlier in Section 7.1.1, "Definition of Terms." + +To establish addressability of objects within a group, you must explicitly +define each group in the module. The group definition record (GRPDEF) +lists constituent segments by their segment names. + +The GRPDEF records within a module must follow all SEGDEF records +because GRPDEF records will reference SEGDEF records in defining a +Group. The GRPDEF records must also precede all other records except +header records, which the linker must process first. + +7.2.3 Symbol Definition + +The Microsoft linker supports three different types of records belonging to +the class of symbol definition records. The types are public names +definition records (PUBDEFs), communal names definition records (COM- +DEFs), and external names definition records (EXTDEFs). You use these +record types to define globally visible procedures and data items and to +resolve external references. + +7.2.4 Indices + +"Index" fields appear throughout this chapter. An index is an integer that +selects a particular item from a collection of items; for example: name +index, segment index, group index, external index, type index, etc. + +_ ________________________________________________________________ + +Note + + An index is normally a positive number. The index value zero is + reserved, and may carry a special meaning depending on the type of + index (for example, a segment index of zero specifies the "Unnamed" + absolute pseudo-segment; a type index of zero specifies the "Untyped + type.") + +_ ________________________________________________________________ + +In general, indices must assume values that are quite large (that is, much + +8 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + +larger than 255). Nevertheless, a great number of object files contain no +indices with values greater than 50 or 100. Therefore, indices are encoded +in one or two bytes, as required. + +The high-order (left-most) bit of the first (and possibly the only) byte +determines whether the index occupies one byte or two. If the bit is 0, the +index is a number between 0 and 127, occupying one byte. If the bit is 1, +the index is a number between 0 and 32K-1, occupying two bytes, and is +determined as follows: the low-order eight bits are in the second byte, and +the high-order seven bits are in the first byte. + +7.3 Conceptual Framework for Fixups + +A fixup is a modification to object code that achieves address binding that +a translator requested and a linker performed. + +_ ________________________________________________________________ + +Note + + This is the linker's definition of fixup. Nevertheless, the linker can + modify object code (make a "fixup") that does not conform to this + definition. For example, binding code to either hardware or software + floating-point subroutines is a modification to an operation code, + which is treated as an address. The previous definition of fixup is not + intended to disallow or discourage modifications to the object code. + +_ ________________________________________________________________ + +8086-family translators need four kinds of data to specify a fixup: + + o The place and type of a Location to be fixed up. + + o One of two possible fixup modes. + + o A target, which is the memory address that Location must refer to. + + o A frame that defines a context in which the reference takes place. + +Location \(em There are five types of Locations: a pointer, a base, an offset, a +hibyte, and a lobyte. + +The vertical alignment of the following figure illustrates four points +(remember that the high-order byte of a word in 8086 memory is the byte +with the higher address): + + o A base is the high-order word of a pointer (the linker doesn't care + whether the low-order word of the pointer is present). + + + 9 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + o An offset is the low-order word of a pointer (the linker doesn't care + whether the high-order word follows). + + o A hibyte is the high-order half of an offset (the linker doesn't care + whether the low-order half precedes). + + o A lobyte is the low-order half of an offset (the linker doesn't care + whether the high-order half follows). + + + +----+----+----+----+ +Pointer: | | + +----+----+----+----+ + + +----+----+ +Base: | | + +----+----+ + + +----+----+ +Offset: | | + +----+----+ + + +----+ +Hibyte: | | + +----+ + + +----+ +Lobyte: | | + +----+ + + + Figure 7.1 Location Types + +A Location is specified by two kinds of data: the Location type, and where +the Location is (the location of the Location?). + +The Location type is specified by the LOC field in the FIXUPP record's +LOCAT field; where the Location is is specified by the Data Record Offset +field in the same LOCAT field. + +Mode \(em The Microsoft linker supports two kinds of fixups: self-relative +and segment-relative. + +Self-relative fixups support the 8-bit and 16-bit offsets used in CALL, +JUMP, and SHORT-JUMP instructions. Segment-relative fixups support +all other addressing modes of the 8086. + +Target \(em The target is the location in MAS that the linker references. +(More explicitly, the linker considers the target the lowest byte in the +object that it is referencing.) The linker specifies a target by one of six +methods. There are three "primary" methods and three "secondary" ones. +Each primary method of specifying a target uses two kinds of data: an +index number X, and a displacement D. + + +10 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + +_ ________________________________________________________________ + +(T0) X is a segment index. The target is the Dth byte in the LSEG that + the segment index identifies. + +(T1) X is a group index. The target is the Dth byte in the LSEG that + the group index identifies. + +(T2) X is an external index. The external index identifies the external + name that (eventually) gives the address of a byte. The Dth byte + following this byte is the target. + +Each secondary method of specifying a target uses only one item of data +\(em the index number X; this assumes an implicit displacement equal to +zero. + +_ ________________________________________________________________ + +(T4) X is a segment index. The target is the 0th (first) byte in the + LSEG that the segment index identifies. + +(T5) X is a group index. The target is the 0th (first) byte in the LSEG + in the specified group located (eventually) lowest in MAS. + +(T6) X is an external index. The target is the byte whose address is the + external name that the external index identifies. + +The following nomenclature describes a target: + +_ ________________________________________________________________ + +Target: SI(segment name), displacement [T0] + +Target: GI(group name), displacement [T1] + +Target: EI(symbol name), displacement [T2] + +Target: SI (segment name) [T4] + +Target: GI (group name) [T5] + +Target: EI (symbol name) [T6] + +The following examples illustrate how this notation is used: + +_ ________________________________________________________________ + +Target: SI(CODE), 1024 The 1025th byte in the segment + CODE. + +Target: GI(DATAAREA) The location in MAS of a group + called DATAAREA. + +Target: EI(SIN) The address of the external subrou- + tine SIN. + +Target: EI(PAYSCHEDULE), 24 The 24th byte following the location + of an external data structure called + PAYSCHEDULE. + + 11 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + +Frame \(em Every 8086 memory reference is to a location contained within a +frame. This frame is designated by the content of a segment register. For +the linker to form a correct, usable memory reference, it must know what +the target is, and to which frame the reference is being made. Thus, every +fixup specifies such a frame, in one of six methods. Some methods use +data, X, which is in the index number. Other methods require no data. + +The five methods of specifying frames are as follows: + +_ ________________________________________________________________ + +(F0) X is a segment index. The frame is the canonic frame of the LSEG + that the segment index defines. + +(F1) X is a group index. The frame is the canonic frame defined by the + group (that is, the canonic frame defined by the LSEG in the group + located (eventually) lowest in MAS). + +(F2) X is an external index. The frame is determined when the linker + finds the external name's public definition. There are two cases: + + _ _________________________________________________________ + + (F2a) The linker defines the symbol relative to some LSEG, and + there is no associated group. The linker also specifies the + LSEG's canonic frame. + + (F2c) Regardless of how the linker defines the symbol, there is an + associated group. And the linker specifies the canonic + frame of the group. (The Group Index field of the PUBDEF + record specifies the group.) + +(F4) No X. The frame is the canonic frame of the LSEG that contains + Location. + +(F5) No X. The target determines the frame. There are three cases: + + _ _________________________________________________________ + + (F5a) The target specifies a segment index: in this case, the frame + is determined as in (F0). + + (F5b) The target specifies a group index: in this case, the frame is + determined as in (F1). + + (F5c) The target specifies an external index: in this case, the + frame is determined as in (F2). + + +The nomenclature that describes frames is similar to the above nomencla- +ture for targets. + +_ ________________________________________________________________ + +Frame: SI (segment name) [F0] + +Frame: GI (group name) [F1] + + + +12 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + +Frame: EI (symbol name) [F2] + +Frame: Location [F4] + +Frame: target [F5] + +Frame: None [F6] + +For an 8086 memory reference, the frame specified by a self-relative refer- +ence is usually the canonic frame of the LSEG that contains Location. +Also, the frame specified by a segment-relative reference is the canonic +frame of the LSEG that contains the target. + +7.3.1 Self-Relative Fixup + +A self-relative fixup works as follows: Location implicitly defines a +memory address\(emnamely, the address of the byte following Location +(because at the time of a self-relative reference, the 8086 IP (Instruction +Pointer) is pointing to the byte following the reference). + +For 8086 self-relative references, if either the Location or the target is out- +side the specified frame, the linker gives a warning. Otherwise, there is a +unique l6-bit displacement that, when added to the address implicitly +defined by Location, yields the relative position of the target in the frame. + + o If Location is an offset, the linker adds the displacement to Loca- + tion (modulo 65,536) and reports no errors. + + o If Location is a lobyte, the displacement must be within the range + {-128:127}; otherwise, the linker gives a warning. The linker adds + the displacement to Location (modulo 256). + + o If Location is a base, pointer, or hibyte, it is unclear what the + translator intended, so the linker's action is undefined. + + +7.3.2 Segment-Relative Fixup + +A segment-relative fixup operates as follows: a nonnegative 16-bit number, +FBVAL, is defined as the frame number of the frame or selector value that +the fixup specifies. A signed 20-bit number, FOVAL, is defined as the dis- +tance from the base of the frame to the target. If this signed 20-bit +number is less than 0 or greater than 65,535, the linker reports an error. +Otherwise, the linker uses FBVAL and FOVAL to fix up Location in the +following fashion: + + o If Location is a pointer, the linker adds FBVAL (modulo 65,536) to + the high-order word of pointer, and adds FOVAL (modulo 65,536) + to the low-order word of pointer. + + + + 13 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + o If Location is a base, the linker adds FBVAL (modulo 65,536) to + the base and ignores FOVAL. + + o If Location is an offset, the linker adds FOVAL (modulo 65,536) to + the offset and ignores FBVAL. + + o If Location is a hibyte, the linker adds (FOVAL/256) (modulo 256) + to the hibyte and ignores FBVAL. (The division indicated is + integer division; that is, the linker discards the remainder.) + + o If Location is a lobyte, the linker adds (FOVAL modulo 256) + (modulo 256) to the lobyte and ignores FBVAL. + + +7.4 Record Sequence + +A object code file must contain a sequence of (one or more) modules, or a +library containing zero or more modules. The following syntax shows the +valid record ordering necessary to form a module. In addition, the given +semantic rules provide information about how to interpret the record +sequence. + +_ ________________________________________________________________ + +Note + + The description language used in the following syntax is defined in + WIRTH: CACM, November 1977, vol. 20, no. 11, pp. 822-823. The + character strings represented by capital letters are not literals but + identifiers, and are further defined in the record format section. + +_ ________________________________________________________________ + +object file = tmodule + +tmodule = {THEADR | LHEADR} seg-grp {component} modtail + +seg_grp = {LNAMES} {SEGDEF} {EXTDEF | GRPDEF} + +component = data | debug_record + +data = content_def | thread_def | + PUBDEF | EXTDEF | COMDEF | LOCSYM + +debug_record = LINNUM + +content_def = data_record {FIXUPP} + +thread_def = FIXUPP (containing only Thread fields) + +data_record = LIDATA | LEDATA + + +14 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + +modtail = MODEND + +The following rules apply: + + o A FIXUPP record always refers to the previous data record. + + o All LNAMES, SEGDEF, GRPDEF, and EXTDEF records must pre- + cede all records that refer to them. + + o Comment records may appear anywhere in a file, except as the first + or last record in a file or module, or within a content_def. + + +7.5 Introducing the Record Formats + +The following pages present diagrams of record formats in schematic form. +Here is a sample record format that illustrates the various conventions: + +7.5.1 Sample Record Format (SAMREC) + + +-----------------------///---------||||----------- +| | | | | | +| REC | Record | Name | Number | CHK | +| TYP | Length | | | SUM | +| xxH | | | | | +| | | | | | +----------------------///----------||||----------- + | | + +----rpt-----+ + + +The Title and Official Abbreviation + +At the top of the figure is the name of the record format described, with +its official abbreviation. To promote uniformity among various programs, +including translators and debuggers, use the abbreviation in both code and +documentation. The abbreviation of the record format is always six +letters. + +The Boxes + +Each format is drawn with boxes of two sizes. The narrow boxes represent +single bytes. The wide boxes each represent two bytes. The wide boxes +with three slashes in the top and bottom represent a variable number of +bytes, one or more, depending upon content. The wide boxes with four +vertical bars in the top and bottom represent four-byte fields. + + + 15 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +RECTYP + +The first byte in each record contains a value between 0 and 255, indicat- +ing the record type. + +Record Length + +The second field in each record contains the number of bytes in the record, +exclusive of the first two fields, where a field is a 16-bit number\(ema low +byte followed by a high byte. + +Name + +Any field that indicates a name has the following internal structure: the +first byte contains a number between 0 and 127, inclusive, indicating the +number of remaining bytes in the field. The remaining bytes are inter- +preted as a byte string. + +Most translators constrain the character set to a subset of the ASCII char- +acter set. + +Number + +A four-byte number field represents a 32-bit unsigned integer, where the +first eight bits (least-significant) are stored in the first byte (lowest +address), the next eight bits are stored in the second byte, and so on. + +Repeated or Conditional Fields + +Some portions of a record format contain a field or series of fields that +may be repeated one or more times. Such portions are indicated by the +"repeated" or "rpt" brackets below the boxes. + +Similarly, some portions of a record format are present only if some given +condition is true; these fields are indicated by similar "conditional" or +"cond" brackets below the boxes. + +CHKSUM + +The last field in each record is a check sum, which contains the two's com- +plement of the sum (modulo 256) of all other bytes in the record. There- +fore, the sum (modulo 256) of all bytes in the record is zero. + + +16 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + + +Bit Fields + +Sometimes descriptions of contents of fields are at the bit level. Boxes +with vertical lines drawn through them represent bytes or words; the verti- +cal lines indicate bit boundaries. Thus, the following byte representation +has three bit fields of three, one, and four bits, respectively. + +--------------------------------- +| | | | | | | | | +| | | | +| | | | | | | | | +--------------------------------- + 3 1 4 + + +7.5.2 T-Module Header Record (THEADR) + + +-----------------------///----------- +| | | | | +| REC | Record | T- | CHK | +| TYP | Length | Module | SUM | +| 80H | | Name | | +| | | | | +----------------------///------------ + + +T-Module Name + +The T-Module Name field contains the name for the T-module. + +7.5.3 L-Module Header Record (LHEADR) + + +-----------------------///----------- +| | | | | +| REC | Record | L- | CHK | +| TYP | Length | Module | SUM | +| 82H | | Name | | +| | | | | +----------------------///------------ + + +L-Module Name + +The L-Module Name field contains the name for the L-module. + +Every module output from a translator must have a T-module or L-module +header record. The linker requires a THEADR or LHEADR record to come +first in the module and ignores any others. The LHEADR record is identi- +cal to the THEADR record, except it has a record type of 82H. + + + 17 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + + +_ ______________ + + +7.5.4 List of Names Record (LNAMES) + + +-----------------------///----------- +| | | | | +| REC | Record | Name | CHK | +| TYP | Length | | SUM | +| 96H | | | | +| | | | | +----------------------///------------ + | | + +----rpt-----+ + +The LNAMES record contains a list of names that the following SEGDEF +and GRPDEF records may use as the names of segments, classes, and/or +groups. + +The order of LNAMES records in a module and the order of names within +each LNAMES record imply a mapping of these names to numbers: 1, 2, 3, +etc. These numbers are used as "Name Indices" in the Segment Name +Index, Class Name Index, and Group Name Index fields of the SEGDEF +and GRPDEF records. + +Name + +This repeatable field provides a name, which may have zero length. + +7.5.5 Segment Definition Record (SEGDEF) + + +-----------------///-----------------///-----///---///------ +| | | | | | | | | +|REC| Record | Segment | Segment | Segment |Class|Over |CHK| +|TYP| Length | ATTR | Length | Name |Name |Lay |SUM| +|98H| | | | Index |Index|Name | | +| | | | | | |Index| | +-----------------///-----------------///-----///---///------ + +Segment index values 1 through 32,767, which are used in other record +types to refer to specific LSEGs, are defined implicitly by the sequence in +which SEGDEF records appear in the object file. + +SEG ATTR + +The SEG ATTR field provides information on various attributes of a seg- +ment, and has the following format: + +------------------------ +| | | | +| ACB | Frame | Off- | + +18 + +_ _ | | _ _ + + + + +_ _ | | _ _ + + Microsoft Relocatable Object Module Formats + + _ __________________________________________________ + +| P | Number | Set | +| | | | +| | | | +-------------r---------- + | | + +---conditional--+ + +The ACBP byte contains four numbers\(emthe A, C, B, and P attribute +specifications. This byte has the following format: + +--------------------------------- +| | | | | | | | | +| A | C | B | P | +| | | | | | | | | +--------------------------------- + +A (Alignment) is a 3-bit subfield that specifies the alignment attribute of +the LSEG. The semantics are defined as follows: + +_ ________________________________________________________________ + +A=0 SEGDEF describes an absolute LSEG. + +A=1 SEGDEF describes a relocatable, byte-aligned LSEG. + +A=2 SEGDEF describes a relocatable, word-aligned LSEG. + +A=3 SEGDEF describes a relocatable, paragraph-aligned LSEG. + +A=4 SEGDEF describes a relocatable, page(256-byte)-aligned LSEG. + +If A=0, the Frame Number and Offset fields are present. With the Micro- +soft linker, you may use absolute segments for addressing only; for exam- +ple, to define the starting address of a ROM and to define symbolic names +for addresses within the ROM. The linker ignores any data that belongs +to an absolute LSEG, and issues a warning if absolute segments are +defined for a program that runs in protected mode. + +C (Combination) is a 3-bit subfield that specifies the Combination attri- +bute of the LSEG. Absolute segments (A=0) must have combination zero +(C=0). For relocatable segments, the C field encodes a number +(0,1,2,3,4,5,6, or 7) that indicates how the segment can be combined. One +way to interpret this attribute is to consider how two LSEGs are com- +bined. + +For example, suppose that X and Y are LSEGs, and that Z is the LSEG +resulting from the combination of X and Y. Let LX and LY be the lengths +of X and Y, and let MXY denote the maximum of LX, LY. Now, to accom- +modate the alignment attribute of Y, let G be the length of any gap +required between the X and Y components of Z. Then, let LZ denote the +length of the (combined) LSEG, Z; let dx (0\(<=dx "=" hangs the system. + + Not only = in quotes but any delimitor causes problems. + + This comes from a basic lack of consistency in the treatment + of the role of the " character. In command line parsing anything + between " ----- " is not interpreted. But in forming filenames + a " is taken as a valid character. Once the '>' character is + reached the parser begins forming the filename and takes " as + the first character. The following = is taken as a delimitor and + the filename ended. When the filename is formed the processing + returns to the command line parsing main routine and sees the + next ". After this it just moves anything that comes along till + it meets the next quote and ends up destroying the stack. + + Solution: changed filename parsing code to test for quote and decrement + the number of quotes. File changed - tmisc1.asm + + + ************************************************************************ + + Problem: DOS FDISK creates partition which overlaps Xenix partition. + + Create bad track table (xenix) and then a xenix partition + which occupies whole disk. then boot dos and create partiton + asking it to use all of the space for dos. It just does that + overlapping the partition over the xenix partition. + + Problem: 3.3 fdisk was not handling the no space condition. + + Solution: + + added code to detect no space condition and report error on + such a condition. files changed fdisk.c and space.c. also + when dos tries to create primary partition with a space + requested from the user added error message when there is + no space. + + + ************************************************************************ + + Problem: + + The bug is that the routine make_partition had been checking for a free + "slot" in the Master Boot Record and aborting the menu if there was none. + This action is not desirable if the user wishes to create a Logical DOS + volume in an existing Extended DOS Partition. + + There are several circumstances where this problem becomes evident. + Probably the most common problem would be experienced on a large hard disk with several + DOS partitions defined on it (COMPAQ is not the only OEM to support + multiple DOS partitions on a hard disk...). + + Consider a disk with 4 DOS partitions defined on it and the user wants to + delete ONE of the DOS partitions so that an Extended DOS partition may be + defined. After doing this, the ext_create_partition routine allows the + user to define logical DOS volumes. + + The user decides that the Logical DOS Volumes he previously created are not + satisfactory after having left FDISK, perhaps he had previously defined + only one Logical DOS Volume and it did not use the entire Extended + Partition. + + This time FDISK will not allow the user to select the Create Logical + Volume menu option because there are no free "slots" in the Master Boot + Record although there may well be plenty of space within the Extended DOS + partition. + + NOTE: This problem also occurs with the OS/2 implementation of FDISK. + + + ************************************************************************* + + Problem: Extend file handle count is broken. + + Solution: The para calculation code in handle.asm to calculate the number + of paragraphs needed is coded wrongly. For handle values + less than a para away from the maximum this will cause a carry. + The subsequent rotate by 4 should shift the carry in. IBM 3.3 + doesn't use the appropriate rotate instruction. + + ************************************************************************** + + Problem: Disk info initialisation in extended volume wrongly done. + + The problem involves creation of Logical DOS Volumes in + an Extended DOS Partition. As you know, each Logical DOS Volume + has a "dummy" Master Boot Record which is necessary to define + the extent of its Logical Volume and to indicate the location of + the next Logical Volume (if one exists). The "dummy" Master + Boot Record for each Logical Volume (except the last one) + contains an entry with a system indicator byte with the value of + 5 - this is the pointer to the next volume. The END_HEAD number + of this type 5 record is ONE greater than the greatest physical + head number on the drive. + + + This occurs because the entries in the "max_head" array are + initialized to be one more than the greatest physical head + number in the routine "get_disk_info()" in the file INT13.C for + use in calculations. The routine "write_ext_boot_to_disk" in + the file DISKOUT.C does not subtract one from the max_head value + before placeing it into the extended boot record - which is what + results in the "End_Head" field being wrong for the type 5 + record. + + The line in "write_ext_boot_to_disk" where the subtraction + should take place is shown below... + + /* End head */ + boot_record[0x1D3] = max_head[disk]; + + Solution: As mentioned above the line given above should be + boot_record[0x1d3] = max_head[disk] - 1; diff --git a/README.DIS b/README.DIS new file mode 100644 index 0000000..707d8f6 --- /dev/null +++ b/README.DIS @@ -0,0 +1,776 @@ + SUPPLEMENT TO MS-DOS 2.XX/3.XX ADAPTATION GUIDE + + DOCUMENTATION FOR THE MS-DOS 3.30 DISTRIBUTION DISKETTES + +This documentation consists of release layout information, a diskette +directory, instructions for use, and a list of differences between the +CLONE VERSION and the MS VERSION. + +1. MS-DOS 3.30 RELEASE LAYOUT + +------------------------------------------------------------------------------ +| SOURCE CODE | +| | +| 10 96 TPI diskettes | +| readme.src | +| Not generally available to OEMS - For Customer Support/Maintenance | +------------------------------------------------------------------------------ + [] [] [] [] [] + [] [] [] [] [] + SWITCHES SET FOR SWITCHES SET FOR SWITCHES SET FOR + MS VERSION CLONE VERSION CLONE VERSION + [] [] [] [] [] + \[]/ [] \[]/ [] [] + \/ [] \/ [] BUGFIXES +------------------- [] ------------------- [] APPLIED +| | [] | | [] [] +| MS VERSION | [] | CLONE VERSION | [] [] +| SUPPLEMENTAL | [] | MESSAGE MODULES | [] [] +| MESSAGE MODULES | [] | | [] [] +| | [] | For all files | [] [] +| COMMAND.COM | [] | except for those| [] [] +| DEBUG.EXE | [] | with complete | [] [] +| MORE.COM | [] | source on the | [] [] +| RECOVER.EXE | [] | CLONE VERSION | [] [] +| SHARE.EXE | [] | DISTRIBUTION | [] [] +| MSDOS.SYS | [] | DISKETTES | [] [] +| | [] | readme.mes | [] [] +|1 96 TPI diskette| [] |1 96 TPI diskette| [] [] +|avail. on request| [] |avail. on request| [] [] +------------------- [] ------------------- [] [] + [] [] [] [] [] + \[]/ \[]/ \[]/ \[]/ \[]/ + \/ \/ \/ \/ \/ +------------------------ ------------------------- ------------------------- +| | | | | | +| MS VERSION | | CLONE VERSION | |MICROSOFT MS-DOS 3.30 | +| SUPPLEMENTAL | | DISTRIBUTION DISKETTES| | PACKAGED PRODUCT | +| DISTRIBUTION DISKETTE| | readme.dis | | | +| 1 96 TPI diskette | | 2 96 TPI diskettes | | 2 48 TPI DISKETTES | +| Available on request | | In OEM Adaptation Kit | | In OEM Adaptation Kit : +------------------------ ------------------------- ------------------------- + ------------------------- + | BUGFIX DISKETTE | + | FIXES THAT MAY BE | + |APPLIED TO MS-DOS 3.30 | + | readme.bf | + | 1 96 TPI diskette | + | In OEM Adaptation Kit | + ------------------------- + + + + Additional Materials that are part of the OEM Adaptation Kit: + + 2.XX/3.XX Adaptation Guide 1 96 TPI diskette + + Machine Readable Documentation + User's Guide/User's Reference 2 96 TPI diskette + Programmer's Reference + + Hard Copy Documentation + User's Guide + User's Reference + Programmer's Reference + + + Additional Material that is available on request through an OEM's + OEM Account Manager: + + 1. Undocumented System Calls Information + 2. Microsoft MASM 4.00 Retail Package + +(Most OEMS either already have these two items or do not have a use for them) + + +The CLONE VERSION DISTRIBUTION DISKETTES contain the files that were produced +from MS-DOS SOURCE CODE assembled with the IBMVER switch on but the +IBMCOPYRIGHT switch off. They contain full SOURCE CODE to IO.SYS, MSBOOT, +FORMAT.EXE, PRINT.EXE, SORT.EXE and partial source code to MSDOS.SYS to allow +for the customization of DOSMES.INC. MSDOS32101 is a bootable disk. + +The MS VERSION SUPPLEMENTAL DISKETTE contains files that were produced from +MS-DOS SOURCE CODE assembled with the MS-VER switch on and the IBMVER and +IBMCOPYRIGHT switch off. They contain the executables for the four files DEBUG, +MORE, RECOVER and SHARE as well as partial source for MSDOS.SYS to allow for +its customization. These are all the files with version switches in them except +for the files with complete source on the CLONE VERSION. + +The MS-DOS 3.30 PACKAGED PRODUCT contains file that were produced from MS-DOS +SOURCE CODE assembled with the IBMVER switch on but the IBMCOPYRIGHT +switch off. These two disks that are identical to the disks in the manufactured +packaged product. There is a boot disk and supplemental disk. + +The CLONE VERSION MESSAGE MODULES contain all the source code that must be +modified for translation to a language other than English. +These message source modules can be modified, then assembled and linked with the +object modules that are provided to make the executables. The object modules +in this release were made from MS-DOS SOURCE CODE assembled with IBMVER switch +on and the MSVER and IBMCOPYRIGHT switches off. Code is provided to make all +the executables on the CLONE VERSION DISTRIBUTION DISKETTES except for +the files that have complete source provided on the CLONE VERSION DISTRIBUTION +DISKETTES: IO.SYS, MSBOOT.BIN, FORMAT.EXE, PRINT.EXE, SORT.EXE, SYS.COM, and +MSDOS.SYS (partial source). + +Microsoft now offers complete translations including documentation for the +following languages: French, German, Spanish, Portuguese, Italian and Dutch. +OEMs who would like one or more of these translations added to their OEM +contract should contact their Microsoft OEM Account Manager. + +MS VERSION SUPPLEMENTAL MESSAGE MODULES contain all the source code that +must be modified for translation to a language other than English for the +six files: COMMMAND.COM, DEBUG.EXE, MORE.COM, RECOVER.EXE, SHARE.EXE and +MSDOS.SYS. They are used the same way as the CLONE VERSION MESSAGE MODULES, +except the the files they are linked to have been assembled with the +MSVER switch on. + +The MS-DOS CLONE VERSION DISTRIBUTION DISKETTES, and the PACKAGE PRODUCT +DISKETTES are provided as a part the MS-DOS 3.30 Standard OEM ADAPATION KIT. + +The CLONE VERSION MESSAGE MODULES, the MS VERSION SUPPLEMENTAL MESSAGE MODULES +and the MSVER SUPPLEMENTAL DISTRIBUTION DISKETTE, MODULES may be available to +an OEM under special conditions by request through their Microsoft OEM Account +Manager. + +The SOURCE CODE release is not generally available to OEMS, however, it is +archived for support purposes by OEM Customer Support. + +The BUGFIX DISKETTE contains code that fixes certain known problems in the +MS-DOS 3.30 Release. These fixes have been applied to the MS-DOS 3.30 +PACKAGED PRODUCT, but were not applied to the the MS-DOS 3.30 OEM Release +to maintain IBM COMPATIBILITY. An OEM can use this code to apply these +bugfixes to their product. The specific bugs are described in the release +notes and in the the README.BF file on the BUGFIX DISKETTE. + + + +2. Diskette Directories + +MS-DOS 3.20 CLONE VERSION DISTRIBUTION DISKETTES MS330DIS01 + +io.sys system file - BIOS +msdos.sys system file - DOS +command.com command interpreter + +distrib\bin + +append.com utility to set a search path for data files +assign.com utility to assign a drive letter to a different drive +attrib.exe utility to change or display a file's attribue (read/read only) +backup.com utility to backup one or more files from one disk to another +chkdsk.com utility to scan disks, check for allocation errors & repair them +debug.com utility for debugging +diskcomp.com utility to compare to contents of one disk with another +diskcopy.com utility to copy disks formatting when necessary +edlin.com line editor +exe2bin.exe utility to convert .EXE files to .COM files +fdisk.com utility to configure hard disk +find.exe filter to find text strings in files +format.com utility to format disks +graftabl.com graphic character generation driver +graphics.com utility to print a graphics display on a printer +join.exe utility to join a drive to a specific pathname +keyb.com utility to replace ROM resident english keyboard program with + non-english keyboard program +label.exe utility to change or create a disk volume ID +link.exe linker 2.40 (part of the MS-DOS 3.30) product +mode.com utility to configure parallel and serial ports +more.com utility to send output to the console one screen at a time +nlsfunc.exe utiltiy to provide support for extended country information +print.com utility to print text files on a line printer +recover.com utility to recover disk directory +replace.exe utility to update previous verison on files on a disk +restore.exe utility to restore files that were backed up with backup.exe +share.exe utility to install file sharing and locking +sort.exe utility to read standard input, sort data and write to a device +subst.exe utility to substitute a string alias for a pathname +sys.com utility to transfer msdos system files +tree.com utility to display the directory structure & contents of a drive +xcopy.exe utility to copy files, directories and lower level directories + + +dev + +ansi.sys installable console device driver +country.sys used to identify the date, time, collating sequence, + capitalization and folding format for a given country +display.sys allows use of code page switching for the display +driver.sys installable device driver to support external drives +keyboard.sys allows use of code page switch for the keyboard +printer.sys allows use of code page switching for the printer +ramdrive.sys installable RAM disk device driver +vdisk.sys installable RAM disk device driver + +src + +makefile builds all CLONE VERSION DISTRIBUTION buildables + +src\bios + +biomes.inc io.sys include file +biostruc.inc io.sys include file +clocksub.inc io.sys include file +cmosequ.inc io.sys include file +dskprm.inc io.sys include file +jumpmac.inc io.sys include file +locscr exe2bin location script +makefile io.sys link script +ms96tpi.inc io.sys include file +msaux.asm io.sys source file +msbds.inc io.sys include file +msbio.lnk msbio.link script +msbio1.asm io.sys source file +msbio2.asm io.sys source file +msclock.asm io.sys source file +mscon.asm io.sys source file +msdata.inc io.sys include file +msdisk.asm io.sys source file +msequ.inc io.sys include file +msextrn.inc io.sys include file +msgroup.inc io.sys include file +mshard.asm io.sys source file +msinit.asm io.sys source file +msioctl.inc io.sys include file +msload.asm io.sys source file +msload.inc io.sys include file +mslpt.asm io.sys source file +msmacro.inc io.sys include file +msstack.inc io.sys include file +msvolid.inc io.sys include file +pushpop.inc io.sys include file +readcloc.inc io.sys include file +stkinit.inc io.sys include file +stkmes.inc io.sys include file +sysconf.asm io.sys source file +sysimes.asm io.sys source file - message text +sysimes.inc io.sys include file +sysinit1.asm io.sys source file - system initialization +sysinit2.asm io.sys source file - system initialization + + + +src\boot + +boot.inc msboot include file +boot11.inc msboot include file +makefile msboot make file +messages.inc msboot message file +msboot.asm msboot source file +msboot.bin boot sector + + + +MS-DOS 3.20 CLONE VERSION DISTRIBUTION DISKETTES MS320DIS02 + +src\cmd\format + +bootmes.inc format include file +format.asm format generic source file +format.lnk format link script +forproc.asm format source file +make_inc.bas BASIC program to establish system size - makes filesize.inc +makefile makefile for format.com +messages.asm format message source file +messages.inc format include file +oemfor.asm format OEM specific source file + + +src\cmd\print + +makefile makefile for print.com +nprintf.asm print source file +pridefs.inc print include file +print.lnk print link script +print_r.asm print resident source code +print_rm.asm print resident message source code +print_rm.inc print resident include file +print_t.asm print transient source code +print_tm.asm print transient message source code +print_tm.inc print transient include file + + +src\cmd\sort + +makefile make file for sort.exe +messages.asm sort message file +sort.asm sort source file +sort.lnk sort link response file + + +src\cmd\sys + +build.bat batch file to build sys.exe +messages.asm sys message file +sys.asm sys source file +sys.lnk sys link response file + +src\dos + +abort.obj msdos.sys object module +alloc.obj msdos.sys object module +arena.inc msdos.sys include file +bpb.inc msdos.sys include file +buf.obj msdos.sys object module +buffer.inc msdos.sys include file +close.obj msdos.sys object module +const2.obj msdos.sys object module +cpmfcb.inc msdos.sys include file +cpmio.obj msdos.sys object module +cpmio2.obj msdos.sys object module +create.obj msdos.sys object module +crit.obj msdos.sys object module +curdir.obj msdos.sys object module +delete.obj msdos.sys object module +dev.obj msdos.sys object module +devsym.inc msdos.sys include file +dinfo.obj msdos.sys object module +dir.obj msdos.sys object module +dir2.obj msdos.sys object module +dircall.obj msdos.sys object module +dirent.inc msdos.sys include file +disk.obj msdos.sys object module +disk2.obj msdos.sys object module +disk3.obj msdos.sys object module +divmes.inc msdos.sys include file +doscntry.inc msdos.sys include file +dosmac.inc msdos.sys include file +dosseg.inc msdos.sys include file +dossym.inc msdos.sys include file +dpb.inc msdos.sys include file +dpl.inc msdos.sys include file +dup.obj msdos.sys object module +error.inc msdos.sys include file +exe.inc msdos.sys include file +fat.obj msdos.sys object module +fcb.obj msdos.sys object module +fcbio.obj msdos.sys object module +fcbio2.obj msdos.sys object module +file.obj msdos.sys object module +filemode.inc msdos.sys include file +find.inc msdos.sys include file +finfo.obj msdos.sys object module +getset.obj msdos.sys object module +handle.obj msdos.sys object module +intnat.inc msdos.sys include file +ioctl.inc msdos.sys include file +ioctl.obj msdos.sys object module +isearch.obj msdos.sys object module +lock.obj msdos.sys object module +macro.obj msdos.sys object module +macro2.obj msdos.sys object module +makefile msdos.sys makefile +mi.inc msdos.sys include file +misc.obj msdos.sys object module +misc2.obj msdos.sys object module +mknode.obj msdos.sys object module +msdos.lnk msdos.sys link script +mult.inc msdos.sys include file +nibdos.obj msdos.sys object module +open.obj msdos.sys object module +parse.obj msdos.sys object module +path.obj msdos.sys object module +pdb.inc msdos.sys include file +proc.obj msdos.sys object module +rename.obj msdos.sys object module +rom.obj msdos.sys object module +search.obj msdos.sys object module +sf.inc msdos.sys include file +share.obj msdos.sys object module +smdossym.inc msdos.sys include file +srvcall.obj msdos.sys object module +stdcode.obj msdos.sys object module +stdctrlc.obj msdos.sys object module +stddata.obj msdos.sys object module +stddisp.obj msdos.sys object module +stddosme.asm msdos.sys source file +stddosme.obj msdos.sys object module +stdsw.inc msdos.sys include file +stdtable.obj msdos.sys object module +syscall.inc msdos.sys include file +sysvar.inc msdos.sys include file +time.obj msdos.sys object module +util.obj msdos.sys object module +vector.inc msdos.sys include file + + + +src\inc + +macro.inc general msdos include file +struc.inc general msdos include file +version.inc general msdos include file +versiona.inc general msdos include file + + + +src\libc + +The files in this directory are needed when linking various msdos files. + +cds.obj +dpb.obj +errtst.obj +itoupper.obj +join.c +kstring.c +printf.asm +string.c +sysvar.c + + +tools + +The files in this directory are used to make the parts of the MSDOS product. +None of these files(except exe2bin.exe), however are part of the MS-DOS product +and they should not be supplied to an OEM's customers. + +convert.exe special file to change certain .EXE files to .COM files +dbof.exe used to insure that boot record is located proper on disk +exe2bin.exe same as exe2bin.exe in product - it is included here as + as a convenience +exefix.exe used by some makefiles to convert .EXE files to .COM files +gwbasic.exe same gwbasics as in packaged procduct. It is used by the + makefile in format - it is included here as a convenience +link.exe linker used to build msdos +masm.exe masm.exe from Retail Macro Assember 4.00 Product +masm401.exe special masm used to build IO.SYS +msmake.exe make utility - renamed msmake to distinquish it from XENIX make + +3. Instruction for use. + +The MS-DOS release installation procedure is described in Chapter 3 of +the MS-DOS 2.XX/3.XX adaptation guide. + +It is recommended that the DISTRIBUTION DISKETTES be copied over +to a hard disk with the XCOPY.EXE command. This will set up +a directory tree that the makefiles can use properly. All the +buildables on the DISTRIBUTION DISKETTES can be built by setting +the PATH to SRC\TOOLS and running the MAKEFILE in the SRC directory. +It is important that the file be built in the order that they are +by this makefile as there are some dependencies on former builds +having occurred. + +It is also recommended that MS-DOS 3.30 is installed on the build +machine and that the build occurs under MS-DOS 3.30. This will +insure that any version dependent tools will perform properly. MS-DOS +3.30 can be installed on the build machine by booting from the floppy +with the boot disk from either the DISTRIBUTION DISKETTES or the PACKAGED +PRODUCT and then using the SYS command or FORMAT /S to get the system to the +hard disk. + +System Filenames are MSDOS.SYS and IO.SYS in FORMAT and SYS. + +FORMAT.EXE and SYS.COM have the boot sector installed with INSBIN.EXE. + +The OEM NUMBER is FF. + +Build Scripts require that the files EXE2BIN.EXE and DEBUG.EXE be in the PATH. + +The 8-bit OEM Serial number may be installed with DEBUG by patching MSDOS.SYS +at location 355H (455 under DEBUG). + +The 24-bit OEM User number may be installed with DEBUG by patching MSDOS.SYS +at location 352H (452 under DEBUG). + +SYSINIT LINK REQUIREMENTS. + + SYSINIT1.obj now requires an external FAR routine called StackInit + to be linked. This routine has available to it the parameters + + STACK_ADDR: DWORD + STACK_SIZE: WORD + STACK_COUNT: WORD + + + StackInit initializes the Stack Heap and corresponding interrupt + vectors used to handle potential hardware driven stack overflows. + After completing its task, StackInit issues a RETF to return to + SYSINIT1. + To use the IBM compatible SYSINIT1, the OEM must + provide the FAR ROUTINE StackInit, whose only task is to issue a + RETF. + + +The CONVERT utility is provided in the TOOLS directory to +rename certain .EXE utilties as .COM files if desired. The CONVERT utility +is not part of the MS-DOS product and should be used only as +described as follows: + + +Documentation for CONVERT.EXE + +CONVERT is used by entering CONVERT and an .EXE file name (with the .EXE +extension). + +CONVERT FOO.EXE + + will build a FOO.COM file + + +CONVERT adds an .EXE loader onto the .EXE file image + +It should not be confused with EXE2BIN.EXE + +These are the differences: + +EXE2BIN + + - EXE2BIN is a utility for converting .EXE files to binary (.COM). + + - EXE2BIN produces a .COM file which is smaller than the .EXE file. + + - EXE2BIN may only convert files conforming to a certain documented set of + requirements. + + - EXE2BIN can only be used on a file written as .COM file (ORG 100h, not + stack segment). + + +CONVERT + + - CONVERT transforms an .EXE file into a .COM file by appending the + MS-DOS loader to the end of the file. + + - A CONVERTed file will be larger than an equivalent .EXE file. + + - CONVERT will convert ANY .EXE program. + + - CONVERT should only be used in UNUSUAL circumstances, such as when + an application program demands that a file have a .COM extension. + + + +4. Differences in the files in the MS VERSION and CLONE VERSION of MS-DOS + +This is a complete list of the differences between the MS VERSION and the +CLONE VERSION of MS-DOS at the 3.XX level. It is intended to illustrate how +few the differences actually are. These differences occur as a result of +conditional assemblies based on whether MSVER or IBMVER is TRUE at the time +of assembly. + + CLONE VERSION MS VERSION +DOS +================================================================== + +OEM_HANDLER OEM_HANDLER code OEM_HANDLER code + for call F8 NOT included for call F8 included + +DOS header IBM Text MSDOS text + +Print of DOS NO YES + version at + boot time + +INT 25,26 AH YES NO + error code + mapping + +International Large set US table only + tables + +Case map call IBM PC specific None + in internat + tables + +Function Key IBM PC Z-19 (Zenith terminal) + definition + +^N defined as NO YES + special char + equivalent + to ^P + +****************************************************************** + + CLONE VERSION MS VERSION +SHARE +================================================================== + + NOTE: The MS VERSION and CLONE VERSION do have minor + differences and will not file compare. The differences + have to do with the DOS data modules linked in with SHARE. + The CLONE VERSION SHARE, MSDOS and REDIR should be used only with + each other and the MS VERSION SHARE, MSDOS and REDIR should be + used only with each other. + +***************************************************************************** + + CLONE VERSION MS VERSION +COMMAND +================================================================== + +CLS Special IBM code to detect Assumes ANSI support, + if ANSI driver installed. outputs ANSI CLS sequence. + If no ANSI driver, CLS done + by direct calls to INT 10H + +ROM exec Special code for PC-Jr ROM No ROM exec code + cartridges. + + +***************************************************************************** + + CLONE VERSION MS VERSION +PRINT +================================================================== + INT 17,13,14,5,15 handlers No special handlers + + IBM specific timer int code No timer int code + + NOTE: SOURCE CODE FOR PRINT IS SENT SO THAT + OEMs CAN PORT THEM TO THEIR MACHINES. + + NOTE: SETTING THE IBM SWITCHES TO TRUE IN PRINT + WILL NOT YIELD A BINARY THAT IS THE SAME AS THE IBM + 3.2 . + + In PRINT's case this is due to some slight code + re-organization that was needed to get a valid + PRINT with the IBM switches set to FALSE. + + +***************************************************************************** + + CLONE VERSION MS VERSION +DEBUG +================================================================== +INT controler Contains code to twiddle No code included + one of the 8259 interrupt + controller registers to + fix the trace of the timer + int problems + +Screen Width Issues INT 10H to get Assumes screen is at + screen width. least 80 column + +***************************************************************************** + + CLONE VERSION MS VERSION +FORMAT +================================================================== + MS VERSION CLONE VERSION + ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +SYS +================================================================== + +Put Boot Contains Boot sector No put boot code + output code to put + correct boot sectors + on SYSed disks + +Check for valid Uses INT 25 to make sure Minimal checking of +destination that destination disk is MSDOS.SYS size + empty or has correct IBM + bootable disk format + +***************************************************************************** + + CLONE VERSION MS VERSION +RECOVER +================================================================== +ROM COM AREA Twiddles a byte in the ROM No code +TWIDDLE communication area on single + drive systems to indicate + drive changed. + +***************************************************************************** + + CLONE VERSION MS VERSION +EXE2BIN +================================================================== + MS VERSION CLONE VERSION + ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +CHKDSK +================================================================== + MS VERSION CLONE VERSION + ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +FIND +================================================================== + MS VERSION CLONE VERSION + ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +ASSIGN +================================================================== + MS VERSION CLONE VERSION + ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +ATTRIB +================================================================== + MS VERSION CLONE VERSION + ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +SUBST +================================================================== + MS VERSION CLONE VERSION +* ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +JOIN +================================================================== + MS VERSION CLONE VERSION + ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +EDLIN +================================================================== + MS VERSION CLONE VERSION + ARE IDENTICAL + +***************************************************************************** + + CLONE VERSION MS VERSION +MORE +================================================================== +Screen Width Issues INT 10H to get Assumes screen is + width of screen at least 80 column + +Non printing Assumes all chars < 20H Assumes chars < 20H +chars except for BELL (07) are are non printing and + printing characters which do not advance the + advance the cursor one cursor if output + position if output. + +***************************************************************************** + + CLONE VERSION MS VERSION +SORT +================================================================== +Internat chars Defines coalating sequence Chars > 7FH are sorted + for some chars > 7FH approp in value order + to IBM international char + sets + +***************************************************************************** + + CLONE VERSION MS VERSION +BIOS (SYSINIT) +================================================================== +MEM scan Mem scan code not included Includes memory scan + Assumes BIOS sets memory code if OEM BIOS + size variable always. does not set memory + size variable. diff --git a/SRC/BIOS/BIOMES.INC b/SRC/BIOS/BIOMES.INC new file mode 100644 index 0000000..06deb2a --- /dev/null +++ b/SRC/BIOS/BIOMES.INC @@ -0,0 +1,31 @@ + + ;;Rev 3.30 Modification +; SINGLE DRIVE MESSAGE FOR BIOS. NUL TERMINATED. +IFNDEF PATHSTART +PATHSTART MACRO INDEX,ABBR + IFDEF PATHGEN + PUBLIC ABBR&INDEX&S,ABBR&INDEX&E + ABBR&INDEX&S LABEL BYTE + ENDIF + ENDM +ENDIF + +IFNDEF PATHEND +PATHEND MACRO INDEX,ABBR + IFDEF PATHGEN + ABBR&INDEX&E LABEL BYTE + ENDIF + ENDM +ENDIF + + PATHSTART 001,BIOMS + +; +; Single drive message for msbio.com. Nul terminated. ;;End of Modification +; + +SNGMSG DB CR,LF,"Insert diskette for drive " +DRVLET DB "A: and strike",CR,LF,"any key when ready",CR,LF,LF,0 + + PATHEND 001,BIOMS + \ No newline at end of file diff --git a/SRC/BIOS/BIOSTRUC.INC b/SRC/BIOS/BIOSTRUC.INC new file mode 100644 index 0000000..25f73d2 --- /dev/null +++ b/SRC/BIOS/BIOSTRUC.INC @@ -0,0 +1,87 @@ + + + ;;Rev 3.30 Modification +; ROM BIOS CALL PACKET STRUCTURES + +;******************************* +;System Service call ( Int 15h ) +;******************************* +;Function AH = 0C0h, Return system configuration +;For PC and PCJR on return: +; (AH) = 80h +; (CY) = 1 +;For PCXT, PC PORTABLE and PCAT on return: +; (AH) = 86h +; (CY) = 1 +;For all others: +; (AH) = 0 +; (CY) = 0 +; (ES:BX) = pointer to system descriptor vector in ROS +; System descriptor : +; DW xxxx length of descriptor in bytes, +; minimum length = 8 +; DB xx model byte +; 0FFh = PC +; 0FEh = PC/XT, Portable +; 0FDh = PC/JR +; 0FCh = PC/AT +; 0F9h = Convertable +; 0F8h = Model 80 +; 0E0 thru 0EFh = reserved +; +; DB xx secondary model byte +; 000h = PC1 +; 000h = PC/XT, Portable +; 000h = PC/JR +; 000h = PC/AT +; 001h = PC/AT Model 339 +; 003h = PC/RT +; 000h = Convertable +; +; DB xx bios revision level +; 00 for first release, subsequent release +; of code with same model byte and +; secondary model byte require revison level +; to increase by one. +; +; DB xx feature information byte 1 +; X0000000 = 1, bios use DMA channel 3 +; = 0, DMA channel 3 not used +; +; 0X000000 = 1, 2nd Interrupt chip present +; = 0, 2nd Interrupt chip not present +; +; 00X00000 = 1, Real Time Clock present +; = 0, Real Time Clock not present +; +; 000X0000 = 1, Keyboard escape sequence(INT 15h) +; called in keyboard interrupt +; (Int 09h). +; = 0, Keyboard escape sequence not +; called. +; 0000XXXX reserved +; +; DB xx feature information byte 2 - reserved +; +; DB xx feature information byte 2 - reserved +; +; DB xx feature information byte 2 - reserved +; +; DB xx feature information byte 2 - reserved +; + +BIOS_SYSTEM_DESCRIPTOR struc +bios_SD_leng dw ? +bios_SD_modelbyte db ? +bios_SD_scnd_modelbyte db ? + db ? +bios_SD_featurebyte1 db ? + db 4 dup (?) +BIOS_SYSTEM_DESCRIPTOR ends + +;FeatureByte1 bit map equates +DMAchannel3 equ 10000000b +ScndIntController equ 01000000b +RealTimeClock equ 00100000b +KeyEscapeSeq equ 00010000b + ;;End of Modification diff --git a/SRC/BIOS/CLOCKSUB.INC b/SRC/BIOS/CLOCKSUB.INC new file mode 100644 index 0000000..e643d2c --- /dev/null +++ b/SRC/BIOS/CLOCKSUB.INC @@ -0,0 +1,76 @@ + +; +; date_verify loosely checks bcd date values to be in range in bin_date_time +; +date_verify: ; + cmp byte ptr bin_date_time+0,20h ; century check + ja date_error ; jmp error + jz century_20 ; jmp in 20th century + cmp byte ptr bin_date_time+0,19h ; century check + jb date_error ; jmp error + cmp byte ptr bin_date_time+1,80h ; year check + jb date_error ; jmp error +century_20: ; + cmp byte ptr bin_date_time+1,99h ; year check + ja date_error ; jmp error + cmp byte ptr bin_date_time+2,12h ; month check + ja date_error ; jmp error + cmp byte ptr bin_date_time+2,00h ; month check + jbe date_error ; jmp error + cmp byte ptr bin_date_time+3,31h ; day check + ja date_error ; jmp error + cmp byte ptr bin_date_time+3,00h ; day check + jbe date_error ; jmp error + clc ; set success flag + ret ; +date_error: ; + stc ; set error flag + ret ; + +; +; time_verify very loosely checks bcd date values to be in range in bin_date_time +; +time_verify: + cmp byte ptr bin_date_time+0,24H + ja time_error + cmp byte ptr bin_date_time+1,59H + ja time_error + cmp byte ptr bin_date_time+2,59H + ja time_error + clc + ret +time_error: + stc + ret + +; +; bcd_verify checks values in bin_date_time to be valid +; bcd numerals. carry set if any nibble out of range +; +bcd_verify: ; + mov cx,4 ; 4 bytes to check + mov bx,offset bin_date_time ; +bv_loop: ; + mov al,[bx] ; get a bcd number (0..99) + mov ah,al ; + and ax,0f00fh ; 10's place in high ah, 1's in al + cmp al,10 ; is 1's place in range? + ja bv_error ; jmp out of range + shr ah,1 ; swap nibbles + shr ah,1 ; ... + shr ah,1 ; ... + shr ah,1 ; ... + and ah,0fh ; get rid of any erroneous bits + cmp ah,10 ; is 10's place in range + ja bv_error ; jmp out of range + inc bx ; next byte + dec cx ; + jnz bv_loop ; + clc ; set success flag + ret ; +bv_error: ; + stc ; set error flag + ret ; +; +; Dos 3.30 - The real time clock structures were moved to msbio2.asm +; diff --git a/SRC/BIOS/CMOSEQU.INC b/SRC/BIOS/CMOSEQU.INC new file mode 100644 index 0000000..b52b259 --- /dev/null +++ b/SRC/BIOS/CMOSEQU.INC @@ -0,0 +1,50 @@ + ;;Rev 3.30 Modification +;Equates for CMOS. + +;---------------------------------------- +; CMOS EQUATES FOR THIS SYSTEM : +;------------------------------------------------------------------------------- +CMOS_PORT EQU 070H ; I/O ADDRESS OF CMOS ADDRESS PORT +CMOS_DATA EQU 071H ; I/O ADDRESS OF CMOS DATA PORT +NMI EQU 10000000B ; DISABLE NMI INTERRUPTS MASK - + ; HIGH BIT OF CMOS LOCATION ADDRESS + +;---------- CMOS TABLE LOCATION ADDRESS'S ## ----------------------------------- +CMOS_SECONDS EQU 000H ; SECONDS +CMOS_SEC_ALARM EQU 001H ; SECONDS ALARM ## NOTE: ALL LOCATIONS +CMOS_MINUTES EQU 002H ; MINUTES | IN THE CMOS AREA +CMOS_MIN_ALARM EQU 003H ; MINUTES ALARM | ARE IBM USE ONLY +CMOS_HOURS EQU 004H ; HOURS | AND SUBJECT TO +CMOS_HR_ALARM EQU 005H ; HOURS ALARM | CHANGE. ONLY THE +CMOS_DAY_WEEK EQU 006H ; DAY OF THE WEEK | POST & BIOS CODE +CMOS_DAY_MONTH EQU 007H ; DAY OF THE MONTH | SHOULD DIRECTLY +CMOS_MONTH EQU 008H ; MONTH | ACCESS LOCATIONS +CMOS_YEAR EQU 009H ; YEAR (TWO DIGITS) | IN CMOS STORAGE. +CMOS_REG_A EQU 00AH ; STATUS REGISTER A '----------------- +CMOS_REG_B EQU 00BH ; STATUS REGISTER B ALARM +CMOS_REG_C EQU 00CH ; STATUS REGISTER C FLAGS +CMOS_REG_D EQU 00DH ; STATUS REGISTER D BATTERY +CMOS_DIAG EQU 00EH ; POST DIAGNOSTIC STATUS RESULTS BYTE +CMOS_SHUT_DOWN EQU 00FH ; SHUTDOWN STATUS COMMAND BYTE +CMOS_DISKETTE EQU 010H ; DISKETTE DRIVE TYPE BYTE ; +; EQU 011H ; - RESERVED ;C +CMOS_DISK EQU 012H ; FIXED DISK TYPE BYTE ;H +; EQU 013H ; - RESERVED ;E +CMOS_EQUIP EQU 014H ; EQUIPMENT WORD LOW BYTE ;C +CMOS_B_M_S_LO EQU 015H ; BASE MEMORY SIZE - LOW BYTE (X1024) ;K +CMOS_B_M_S_HI EQU 016H ; BASE MEMORY SIZE - HIGH BYTE ;S +CMOS_E_M_S_LO EQU 017H ; EXPANSION MEMORY SIZE - LOW BYTE ;U +CMOS_E_M_S_HI EQU 018H ; EXPANSION MEMORY SIZE - HIGH BYTE ;M +CMOS_DISK_1 EQU 019H ; FIXED DISK TYPE - DRIVE C EXTENSION ;E +CMOS_DISK_2 EQU 01AH ; FIXED DISK TYPE - DRIVE D EXTENSION ;D +; EQU 01BH ; - 1BH THROUGH 2DH - RESERVED ; +CMOS_CKSUM_HI EQU 02EH ; CMOS CHECKSUM - HIGH BYTE ;* +CMOS_CKSUM_LO EQU 02FH ; CMOS CHECKSUM - LOW BYTE ;* +CMOS_U_M_S_LO EQU 030H ; USABLE MEMORY ABOVE 1 MEG - LOW BYTE +CMOS_U_M_S_HI EQU 031H ; USABLE MEMORY ABOVE 1 MEG - HIGH BYTE +CMOS_CENTURY EQU 032H ; DATE CENTURY BYTE (BCD) +CMOS_INFO128 EQU 033H ; 128KB INFORMATION STATUS FLAG BYTE +; EQU 034H ; - 34H THROUGH 3FH - RESERVED +; + ;;End of Modification + \ No newline at end of file diff --git a/SRC/BIOS/DSKPRM.INC b/SRC/BIOS/DSKPRM.INC new file mode 100644 index 0000000..6b24bff --- /dev/null +++ b/SRC/BIOS/DSKPRM.INC @@ -0,0 +1,22 @@ +; The following structure defines the disk parameter table +; pointed to by Interrupt vector 1EH (location 0:78H) + +DISK_PARMS STRUC +DISK_SPECIFY_1 DB ? +DISK_SPECIFY_2 DB ? +DISK_MOTOR_WAIT DB ? ; Wait till motor off +DISK_SECTOR_SIZ DB ? ; Bytes/Sector (2 = 512) +DISK_EOT DB ? ; Sectors per track (MAX) +DISK_RW_GAP DB ? ; Read Write Gap +DISK_DTL DB ? +DISK_FORMT_GAP DB ? ; Format Gap Length +DISK_FILL DB ? ; Format Fill Byte +DISK_HEAD_STTL DB ? ; Head Settle Time (MSec) +DISK_MOTOR_STRT DB ? ; Motor start delay +DISK_PARMS ENDS + +ROMStatus equ 1 +ROMRead equ 2 +ROMWrite equ 3 +ROMVerify equ 4 +ROMFormat equ 5 diff --git a/SRC/BIOS/JUMPMAC.INC b/SRC/BIOS/JUMPMAC.INC new file mode 100644 index 0000000..b13599e --- /dev/null +++ b/SRC/BIOS/JUMPMAC.INC @@ -0,0 +1,32 @@ + + ;;Rev 3.30 Modification +; +; given a label either 2 byte jump to another label _J +; if it is near enough or 3 byte jump to +; + +jump macro lbl + local a +.xcref + + ifndef lbl&_j ;; is this the first invocation +a: + JMP lbl + ELSE + IF (lbl&_J GE $) OR ($-lbl&_J GT 126) +a: + JMP lbl ;; is the jump too far away? + ELSE +a: + JMP lbl&_J ;; do the short one... + ENDIF + ENDIF +lbl&_j = a +.cref + endm +.xcref jump +;REDEFINE THE ABOVE MACRO TO ALWAYS TRY A 3 BYTE NEAR JUMP +JUMP MACRO LBL + JMP LBL + ENDM ;;End of Modification + \ No newline at end of file diff --git a/SRC/BIOS/LOCSCR b/SRC/BIOS/LOCSCR new file mode 100644 index 0000000..2bbd69c --- /dev/null +++ b/SRC/BIOS/LOCSCR @@ -0,0 +1 @@ +70 diff --git a/SRC/BIOS/MAKEFILE b/SRC/BIOS/MAKEFILE new file mode 100644 index 0000000..5d58d4a --- /dev/null +++ b/SRC/BIOS/MAKEFILE @@ -0,0 +1,107 @@ +#*** Makefile for BIOS + +DEST =io +MSG =messages +DOS =..\dos + +# Definitions for Assembler + +ASM =masm +AFLAGS =-Mx -t +AINC =-I. -I..\inc -I$(DOS) + +# Definitions for C compiler + +CC =cl +CFLAGS =-Ox -X -Zlp +CINC =-I. -I..\h + +# Definitions for Linker + +LINK =link + +# Built-in rules + +.asm.obj: + $(ASM) $(AFLAGS) $(AINC) $*.asm,$*.obj; + +.asm.lst: + $(ASM) -l $(AFLAGS) $(AINC) $*.asm; + +.c.obj: + $(CC) -c $(CFLAGS) $(CINC) -Fo$*.obj $*.c + +.c.lst: + $(CC) -c $(CFLAGS) $(CINC) -Fc$*.cod -Fo$*.obj $*.c + +.exe.com: + reloc $*.exe $*.com + +# Dependencies + +msload.obj: msload.asm msload.inc + +msload.com: msload.obj + LINK msload.obj,msload,,; + exe2bin msload.exe msload.com + del msload.exe + +msbio1.obj: msbio1.asm msdata.inc msgroup.inc jumpmac.inc pushpop.inc \ + $(DOS)\devsym.inc dskprm.inc msmacro.inc + + +mscon.obj: mscon.asm msgroup.inc jumpmac.inc msmacro.inc + +msaux.obj: msaux.asm msgroup.inc jumpmac.inc msmacro.inc + +mslpt.obj: mslpt.asm msgroup.inc msequ.inc msbds.inc msmacro.inc \ + $(dos)\devsym.inc $(dos)\ioctl.inc $(dos)\bpb.inc + +msclock.obj: msclock.asm msgroup.inc msmacro.inc + +msdisk.obj: msdisk.asm msgroup.inc msequ.inc msbds.inc pushpop.inc \ + msmacro.inc $(dos)\devsym.inc dskprm.inc msioctl.inc \ + $(dos)\ioctl.inc $(dos)\bpb.inc + +msinit.obj: msinit.asm msgroup.inc dskprm.inc msequ.inc msbds.inc \ + msmacro.inc readclock.inc clocksub.inc msextrn.inc + +sysinit1.obj: sysinit1.asm msstack.inc stkmes.inc stkinit.inc \ + $(dos)\devsym.inc $(dos)\ioctl.inc $(dos)\smdossym.inc \ + $(dos)\dosmac.inc $(dos)\bpb.inc $(dos)\buffer.inc \ + $(dos)\sysvar.inc $(dos)\vector.inc $(dos)\dirent.inc \ + $(dos)\dpb.inc $(dos)\curdir.inc $(dos)\pdb.inc $(dos)\exe.inc \ + $(dos)\sf.inc $(dos)\arena.inc $(dos)\intnat.inc $(dos)\mi.inc \ + $(dos)\syscall.inc + masm401 $(AFLAGS) $(AINC) sysinit1; + +sysconf.obj: sysconf.asm $(dos)\devsym.inc $(dos)\ioctl.inc \ + $(dos)\smdossym.inc $(dos)\dosmac.inc $(dos)\bpb.inc $(dos)\buffer.inc \ + $(dos)\sysvar.inc $(dos)\vector.inc $(dos)\dirent.inc \ + $(dos)\dpb.inc $(dos)\curdir.inc $(dos)\pdb.inc $(dos)\exe.inc \ + $(dos)\sf.inc $(dos)\arena.inc $(dos)\intnat.inc $(dos)\mi.inc \ + $(dos)\syscall.inc + +sysinit2.obj: sysinit2.asm $(dos)\devsym.inc $(dos)\ioctl.inc \ + $(dos)\smdossym.inc $(dos)\dosmac.inc $(dos)\bpb.inc $(dos)\buffer.inc \ + $(dos)\sysvar.inc $(dos)\vector.inc $(dos)\dirent.inc \ + $(dos)\dpb.inc $(dos)\curdir.inc \ + $(dos)\pdb.inc $(dos)\exe.inc $(dos)\sf.inc $(dos)\arena.inc \ + $(dos)\intnat.inc $(dos)\mi.inc $(dos)\syscall.inc + +sysimes.obj: sysimes.asm msmacro.inc sysimes.inc msequ.inc msbds.inc + +msbio2.obj: msbio2.asm msgroup.inc msequ.inc msbds.inc $(dos)\devsym.inc \ + pushpop.inc msmacro.inc biomes.inc ms96tpi.inc msvolid.inc + +mshard.obj: mshard.asm + +msbio.bin: msbio1.obj mscon.obj msaux.obj mslpt.obj msclock.obj \ + msdisk.obj msbio2.obj msinit.obj mshard.obj sysinit1.obj \ + sysconf.obj sysinit2.obj sysimes.obj + link @msbio.lnk + exe2bin msbio.exe msbio.bin < locscr + copy /b msload.com+msbio.bin io.sys + del msbio.bin + del msbio.exe + del msload.com diff --git a/SRC/BIOS/MS96TPI.INC b/SRC/BIOS/MS96TPI.INC new file mode 100644 index 0000000..c95f9f3 --- /dev/null +++ b/SRC/BIOS/MS96TPI.INC @@ -0,0 +1,494 @@ + +;------------------------------------------------------------------------ +; : +; File: ms96tpi.asm : +; : +; This file contains code to support the 96 tpi drives. The code : +; is included in the bio if the machine has at least one drive with : +; changeline support. If the machine has no changeline drives then : +; the code is not kept in the bio at system initialization time. : +; : +;------------------------------------------------------------------------ + + +;------------------------------------------------------------------------ +; : +; DISK OPEN/CLOSE ROUTINES : +; : +;------------------------------------------------------------------------ + +DSK$OPEN: + PUBLIC DSK$OPEN + Message fTestDisk,<"Disk Open "> ; print debug messages + MNUM fTestDisk,AX + Message fTestDisk, + ; AL is logical drive + call SetDrive ; Get BDS for drive + inc WORD PTR ds:[di].opcnt + jmp EXIT + +DSK$CLOSE: + PUBLIC DSK$CLOSE + Message fTestDisk,<"Disk Close "> ; print debug messages + MNUM fTestDisk,AX + Message fTestDisk, + ; AL is logical drive + call SetDrive ; Get BDS for drive + cmp WORD PTR ds:[di].opcnt,0 + jz EXITJX ; Watch out for wrap + dec WORD PTR ds:[di].opcnt +EXITJX: + jmp EXIT + +; +; ChkOpCnt checks the number of open files on drive. +; +; Input : DS:DI points to current BDS for drive. +; +; Return : zero set if no open files +; zero reset if open files +; + +ChkOpCnt: + Message fTest96,<"Check open count "> ; print debug messages + MNUM fTest96,AX + Message fTest96, + cmp WORD PTR ds:[di].opcnt,0 + ret + +; +; At media check time, we need to really get down and check what the change is. +; This is GUARANTEED to be expensive. +; +; On entry AL contains logical drive number +; + + public mediacheck +MediaCheck: + call CheckSingle ; make sure correct disk is in place + xor SI,SI + call HasChange + jz MediaRet + call CheckROMChange + jnz MediaDoVOLID + push AX + push DX + ; see if changeline has been triggered +;;Rev 3.30 Modification + mov DL, DS:[DI.drivenum] ; set logical drive number + mov AH, 16h ; get changeline status + int 13h ; call rom diskette routine +;;End of Modification + pop DX + pop AX + jc MediaDoVolid ; if changeline was triggered jmp + mov SI,1 ; else signal no change + + +; There are some drives with changeline that "lose" the changeline indication +; if a different drive is accessed after the current one. In order to avoid +; missing a media change, we return an "I don't know" to DOS if the changeline +; is not active AND we are accessing a different drive from the last one. +; If we are accessing the same drive, then we can safely rely on the changeline +; status. + + PUBLIC LOSECHNG +LOSECHNG: + mov bl,cs:[Tim_Drv] ; get last drive accessed + cmp byte ptr [di].DriveNum,bl + jz MediaRet +; Do the 2 second twiddle. If time >= 2 seconds, do a volid check. +; Otherwise return "I don't know" (Strictly speaking, we should return a +; "Not Changed" here since the 2 second test said no change.) - RS. + + SaveReg + call Check_Time_Of_Access + RestoreReg + or si,si + jz MediaDoVolid ; Check_Time says ">= 2 secs passed" + xor si,si ; return "I don't know" + Public MediaRet +MediaRet: + ret + + +; +; MediaDoVolid: if this is called somehow the media was changed. Look at +; VID to see. We do not look at FAT because this may be different since we +; only set MedByt when doing a READ or WRITE. +; + +MediaDoVolid: + call GETBP ; build a new BPB in current BDS + jc MediaRet + call Check_VID + jnc MediaRet + call MapError ; fix up AL for return to DOS + ret + +; +; Checklatchio: +; +; Simple, quick check of latched change. If no indication, then return +; otherwise do expensive check. If the expensive test fails, POP off the +; return and set AL = 15 (for invalid media change) which will be returned to +; DOS. +; + public checklatchio +CheckLatchIO: +; If returning fake BPB then assume the disk has not changed +; test word ptr ds:[di].flags, RETURN_FAKE_BPB +; jnz CheckRet +;;Rev 3.30 Modification + call HasChange ;change line supported? + jz CheckRet ;No. Just return +;;End of Modification + call ChkOpCnt + jnz CheckROM +CheckRet: + ret +; +; Check for past ROM indications. If no ROM change indicated, then return OK. +; + public checkrom +CheckROM: + call CheckROMChange + jz CheckRet ; no change +; +; We now see that a change line has been seen in the past. Let's do the +; expensive verification. +; + Message fTest96,<"CheckROMChange says yes...",CR,LF> + call GETBP ; build BPB in current BDS + jc Ret_No_Error_Map ; GETBP has already called MapError + call Check_VID + jc CheckLatchRet ; disk error trying to read in. + or SI,SI ; Is changed for sure? + jns CheckRet + call ReturnVid +CheckLatchRet: + call MapError ; fix up AL for return to DOS +Ret_No_Error_Map: + stc ; indicate an error + pop si ; pop off return address + ret + + + +; +; CheckFatVID: +; +; Check the FAT and the VID. Return in DI -1 or 0. Return with carry set +; ONLY if there was a disk error. Return that error code in AX. +; + public checkfatvid +CheckFATVID: + Message fTest96,<"Check FAT",CR,LF> + call FAT_Check + or SI,SI + js Changed_Drv +; +; The fat was the same. How about the volume ID? +; +Check_VID: + Message fTest96,<"Check VID",CR,LF> + call Read_volume_ID + jc CheckFatRet + call Check_Volume_id + or SI,SI + jnz Changed_Drv + Message fTest96,<"VID not changed",CR,LF> + call ResetChanged +CheckFatRet: + ret +Changed_Drv: + mov cs:[Tim_Drv],-1 ; Ensure that we ask ROM for media + ret ; check next time round + + + + +; +; CheckIO: At I/O time the rom-bios returned an error. We need to +; determine if the error is due to a media change. If error code is not +; change-line error (06h) we just return. We pop off the call and jmp to +; harderr if we see an error. +; +; On entry: AH contains error code returned from rom-bios. +; + + public checkio +CheckIO: + cmp AH,06 ; change line error? + jnz CheckFatRet ; no - just return + call ChkOpCnt + jz CheckFATRet ; no open files +; If returning fake BPB then ignore disk changes +; test word ptr ds:[di].flags, RETURN_FAKE_BPB +; jnz IgnoreChange + call GETBP ; build up a new BPB in current BDS + jc No_Error_Map ; GETBP has already called MapError + call CheckFATVID + jc CheckIORet ; disk error trying to read in. + or SI,SI ; Is changed for sure? + js CheckIOErr ; yes changed +IgnoreChange: + inc BP ; allow a retry + ret +CheckIOErr: + call ReturnVid +CheckIORet: + stc ; make sure carry gets passed through + jmp HardErr + +No_Error_Map: + jmp HardErr2 + + + + +; +; Return VID sets up the VID for a return to DOS. +; + + Public ReturnVID +ReturnVID: + Message fTest96,<"Return VID",cr,lf> + push DS ; save pointer to current BDS + push di + push cx + call init_vid_loop ; Sets ES:DI -> vid + lds BX,cs:[PTRSAV] + mov [BX.EXTRA],DI + mov [BX.EXTRA+2],ES + pop cx + pop di ; restore current BDS + pop DS +;; MOV AH,6 ; INVALID MEDIA CHANGE + mov AH, 0Fh ; set error as 'invalid media change' + stc ; indicate error by setting carry flag + ret + +; +; Media_Set_VID: +; +; Moves the pointer to the volid for the drive into the original request packet +; On entry, DS:BX points to the original packet. +; No attempt is made to preserve registers. +; + +MEDIA_SET_VID: + PUBLIC MEDIA_SET_VID ;;Rev 3.30 Modification + call init_vid_loop ; Sets ES:DI -> vid ;;End of Modification + lds bx,cs:[PtrSav] ; get pointer to packet + mov word ptr [BX.TRANS+1],DI + mov word ptr [BX.TRANS+3],ES + ret + + +; +; HiDensity - examine a drive/media descriptor to set the media type. If +; the media descriptor is NOT F9 (not 96tpi or 3 1/2), we return and let the +; caller do the rest. Otherwise, we pop off the return and jump to the tail +; of GETBP. For 3.5" media, we just return. +; +; Inputs: DS:DI point to correct BDS for this drive +; AH has media byte +; +; Outputs: Carry clear +; No registers modified +; Carry set +; AL = sectors/fat +; BH = number of root directory entries +; BL = sectors per track +; CX = number of sectors +; DH = sectors per allocation unit +; DL = number of heads +; +hidensity: + PUBLIC HIDENSITY ;;Rev 3.30 Modification + ;;End of Modification +; Check for correct drive +; + test word ptr ds:[di].flags,fChangeline ; is it special? + jz DoFloppy ; no, do normal floppy test +; +; We have a media byte that is pretty complex. Examine drive information +; table to see what kind it is. +; + cmp byte ptr ds:[di].FormFactor,ffSmall; Is it single-media? + jz DoFloppy ; yes, use fatid... +; +; 96 tpi drive +; + cmp AH,0F9h + jnz DoFloppy + mov al,7 ; seven sectors / fat + mov bx,224*256+0fh ; 224 root dir entries & 0f sector max + mov cx,80*15*2 ; 80 tracks, 15 sectors/track, 2 sides + mov dx,01*256+2 ; sectors/allocation unit & head max +popr: + add SP,2 ; pop off return address + jmp has1_res ; return to tail of GETBP + + +DoFloppy: + ret + + PATHSTART 001,TPI96 ;;Rev 3.30 Modification + ;;End of Modification +; +; Certain poorly designed programs avoid DOS altogether and use INT 13 directly. +; These programs even retry operations and, thus, will ignore the disk change +; logic. +; +; We hook INT 13 and note all errors. +; + assume ds:nothing,es:nothing,ss:nothing + + Public REAL13 +Real13 dd ? +OldInt dd ? +dmy dw ? + + PATHEND 001,TPI96 ;;Rev 3.30 Modification + ;;End of Modification + Public Int13 +Int13 proc FAR + pop word ptr OldInt + pop word ptr OldInt+2 + pop DMY + MESSAGE FTEST13,<"*"> ;;Rev 3.30 Modification + pushf ;;End of Modification + call REAL13 ; simulate another INT 13 + jc Err13 ; did an error occur? + jmp OldInt ; no, return and pop off flags +Err13: + MESSAGE FTEST13,<"INT 13 ERROR "> ;;Rev 3.30 Modification + MNUM FTEST13,AX + MESSAGE FTEST13, + pushf ; save state + cmp AH,06h ; is error a 'change' error? + jz GOTERR ; yes, jump down +B: popf ; no, some other error, ignore it ;;End of Modification + jmp OldInt ; return and pop off flags + + +GotErr: or DL,DL ; is this for the hard disk? + js B ; yes, ignore + mov word ptr cs:[FlagBits],fChanged + call Set_Changed_DL + jmp B +INT13 endp + + + +; +; Set_Changed_DL - Sets flag bits according to bits set in [FlagBits]. +; Essentially used to indicate Changeline, or Format. +; +; Inputs: DL contains physical drive number +; [FlagBits] contains bits to set in the flag field in the BDSs +; Outputs: None +; Registers modified: Flags +; + +Set_Changed_DL: + PUBLIC SET_CHANGED_DL ;;Rev 3.30 Modification + Message ftest96,<"Set Changed",cr,lf> ;;End of Modification + push BX + push DX + mov BL,DL +ALL_SET: + mov dx,cs:[FlagBits] ; get bits to set in flag field + xor BH,BH +; +; In the virtual drive system we *must* flag the other drives as being changed +; +; assume first BDS is in this segment + push ax + push ds ; save current BDS + push di + lds di,dword ptr cs:[Start_BDS] +Scan_BDS: + cmp di,-1 + jz SkipSet + cmp byte ptr [di].DriveNum,bl + jnz Get_Next_BDS +; +; Someone may complain, but this *always* must be done when a disk change is +; noted. There are *no* other compromising circumstances. +; +SetChanged: + or word ptr ds:[di].flags,dx ; signal change on other drive +Get_Next_BDS: + mov ax,word ptr [di].link+2 ; go to next BDS + mov di,word ptr [di].link + mov ds,ax + jmp short Scan_BDS +SkipSet: + pop di ; restore current BDS + pop ds + pop ax + pop DX + pop BX + ret + + + +; +; CheckROMChange - see if external program has diddled ROM change line. +; +; Inputs: DS:DI points to current BDS. +; Outputs: Zero set - no change +; Zero reset - change +; Registers modified: none + +CheckROMChange: + MESSAGE FTEST13,<"CHECKROM "> ;;Rev 3.30 Modification + MNUM FTEST13 + MESSAGE FTEST13, ;;End of Modification + test word ptr [di].flags,fChanged + ret + + + + +; +; ResetChanged - restore value of change line +; +; Inputs: DS:DI points to current BDS +; Outputs: none +; Registers modified: none + +ResetChanged: + MESSAGE FTEST13,<"RESETCHANGED "> ;;Rev 3.30 Modification + MNUM FTEST13 + MESSAGE FTEST13, ;;End of Modification + and word ptr ds:[di].flags,NOT fChanged + ret + + + +; +; HasChange - see if drive can supply change line +; +; Inputs: DS:DI points to current BDS +; Outputs: Zero set - no change line available +; Zero reset - change line available +; Registers modified: none + + PUBLIC HASCHANGE ;;Rev 3.30 Modification +HasChange: + MESSAGE FTEST13,<"HASCHANGE "> + MNUM FTEST13 + MESSAGE FTEST13, ;;End of Modification + test word ptr [di].flags,fChangeline + ret + + ASSUME DS:CODE + + include msvolid.inc + + Public End96tpi +End96tpi Label Byte diff --git a/SRC/BIOS/MSAUX.ASM b/SRC/BIOS/MSAUX.ASM new file mode 100644 index 0000000..5deac60 --- /dev/null +++ b/SRC/BIOS/MSAUX.ASM @@ -0,0 +1,281 @@ + TITLE MSAUX - DOS 3.3 +;---------------------------------------------------------------- +; : +; A U X - AUXILARY DEVICE DRIVER : +; : +; : +; This file contains the Auxilary Device Driver. The : +; auxilary driver handles calls to and from the RS-232 port. : +; Three devices uses this code: AUX, COM1, and COM2. AUX and : +; COM1 talk to the zero RS-232 card and COM2 talks to the : +; 'one' RS-232 card. The beginning of the interrupt entry : +; point for these devices sets the variable AUXNUM in the : +; msbio.asm module. If the value is 0 the routines in this : +; file will talk to the the 'zero' card. If the value in : +; AUXNUM is 1 the routines will talk to the 'one' card. : +; The procedure GETDX is called to put the value 0 or 1 in : +; the DX register depending on the value in AUXBUF. : +; : +; The routines in this files are: : +; : +; routine function : +; ------- -------- : +; AUX$READ Read characters from the : +; specified device. : +; AUX$RDND Non-desrucrtive read with : +; no waiting. : +; AUX$FLSH Flush specified device input : +; buffer. : +; AUX$WRIT Write characters to the : +; specified device. : +; AUX$WRST Get status of specified : +; device : +; : +; These routines are not called directly. Call are made via : +; the strategy and interrupt entry point (see Device Header). : +; : +; Data structure: : +; The Aux Device has a two byte buffer called AUXBUF. The : +; first byte is for the zero card, the second byte is for the : +; one card. A zero value in the byte indicates the buffer is : +; empty. The routines use GETBX to get the address of the : +; buffer. : +; : +;---------------------------------------------------------------- + +;;Ver 3.30 modification --------------------------- + test=0 + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + INCLUDE JUMPMAC.INC + INCLUDE MSMACRO.INC + + EXTRN ERR$CNT:NEAR ;MSBIO1 + EXTRN GETDX:NEAR ;MSBIO1 + EXTRN RDEXIT:NEAR ;MSCON + EXTRN EXIT:NEAR ;MSBIO1 + EXTRN BUS$EXIT:NEAR ;MSBIO1 + ;DATA + EXTRN AUXBUF:BYTE ;MSDATA + +; VALUES IN AH, REQUESTING FUNCTION OF INT 14H IN ROM BIOS +AUXFUNC_SEND EQU 1 ;TRANSMIT +AUXFUNC_RECEIVE EQU 2 ;READ +AUXFUNC_STATUS EQU 3 ;REQUEST STATUS + +; ERROR FLAGS, REPORTED BY INT 14H + +; THESE FLAGS REPORTED IN AH: +FLAG_DATA_READY EQU 01H ;DATA READY +FLAG_OVERRUN EQU 02H ;OVERRUN ERROR +FLAG_PARITY EQU 04H ;PARITY ERROR +FLAG_FRAME EQU 08H ;FRAMING ERROR +FLAG_BREAK EQU 10H ;BREAK DETECT +FLAG_TRANHOL_EMP EQU 20H ;TRANSMIT HOLDING REGISTER EMPTY +FLAG_TRANSHF_EMP EQU 40H ;TRANSMIT SHIFT REGISTER EMPTY +FLAG_TIMEOUT EQU 80H ;TIMEOUT + +; THESE FLAGS REPORTED IN AL: +FLAG_DELTA_CTS EQU 01H ;DELTA CLEAR TO SEND +FLAG_DELTA_DSR EQU 02H ;DELTA DATA SET READY +FLAG_TRAIL_RING EQU 04H ;TRAILING EDGE RING INDICATOR +FLAG_DELTA_SIG EQU 08H ;DELTA RECEIVE LINE SIGNAL DETECT +FLAG_CTS EQU 10H ;CLEAR TO SEND +FLAG_DSR EQU 20H ;DATA SET READY +FLAG_RING EQU 40H ;RING INDICATOR +FLAG_REC_SIG EQU 80H ;RECEIVE LINE SIGNAL DETECT +;;End of modification ------------------ + + +;---------------------------------------------------------------- +; : +; Read zero or more characters from Auxilary Device : +; : +; input:es:[di] points to area to receive aux data : +; cx has number of bytes to be read : +; "auxnum" first byte has number of aux device (rel 0): +; : +;---------------------------------------------------------------- + PUBLIC AUX$READ +AUX$READ PROC NEAR + ASSUME DS:CODE ; SET BY AUX DEVICE DRIVER ENTRY ROUTINE + jcxz EXVEC2 ; if no characters, get out + call GETBX ; put address of AUXBUF in BX + xor AX,AX ; clear AX register + xchg AL,[BX] ; Get character , if any, from + ; buffer and clear buffer + or AL,AL ; if AL is nonzero there was a + ; character in the buffer + jnz AUX2 ; if so skip AUXIN call +AUX1: ; + call AUXIN ; get character from port +AUX2: ; + stosb ; store character + loop AUX1 ; if more character, go around again +EXVEC2: ; + Jump EXIT ; all done, successful exit +AUX$READ ENDP + +; +; AUXIN: make a call on ROM BIOS to read character from +; the auxilary device, then do some error checking. +; If an error occurs then AUXIN jumps to ERR$CNT and +; does NOT return to where it was called from. +; + +AUXIN PROC NEAR + + mov ah,AUXFUNC_RECEIVE + call AUXOP + ;check for Frame, Parity, or Overrun errors + ;WARNING: these error bits are unpredictable + ; if timeout (bit 7) is set + test ah,FLAG_FRAME or FLAG_PARITY or FLAG_OVERRUN + jz AROK ;No error if all bits are clear + + ;Error getting character + add sp,+2 ;Remove rtn address (near call) + xor al,al + or al,FLAG_REC_SIG or FLAG_DSR or FLAG_CTS + + JUMP ERR$CNT +AROK: + RET ;CHAR JUST READ IS IN AL, STATUS IS IN AH +AUXIN ENDP + +;---------------------------------------------------------------- +; : +; Aux non-destructive read with no waiting : +; : +; input: es:[di] points to area to receive aux data : +; : +;---------------------------------------------------------------- +; + PUBLIC AUX$RDND +AUX$RDND PROC NEAR + ASSUME DS:CODE ; SET BY AUX DEVICE DRIVER ENTRY ROUTINE + call GETBX ; have BX point to AUXBUF + mov AL,[BX] ; copy contents of buffer to AL + or AL,AL ; if AL is non-zero (char in buffer) + jnz AUXRDX ; then return character + call AUXSTAT ; if not, get status of AUX device + TEST AH,FLAG_DATA_READY ;TEST DATA READY + jz AUXBUS ; then device is busy (not ready) + + TEST AL,FLAG_DSR ;TEST DATA SET READY + jz AUXBUS ; then device is busy (not ready) + call AUXIN ; else aux is ready, get character + call GETBX ; have bx point to AUXBUF + mov [BX],AL ; save character in buffer +AUXRDX: ; + Jump RDEXIT ; return character + +AUXBUS: ; + Jump BUS$EXIT ; jump to device busy exit +AUX$RDND ENDP + +;---------------------------------------------------------------- +; : +; Aux Output Status : +; : +;---------------------------------------------------------------- + PUBLIC AUX$WRST +AUX$WRST PROC NEAR + ASSUME DS:CODE ; SET BY AUX DEVICE DRIVER ENTRY ROUTINE + call AUXSTAT ; get status of AUX in AX + ; now test to see if device is busy + ; if this bit is not set, +;;Ver 3.30 modification ----------------------- + TEST AL,FLAG_DSR ;TEST DATA SET READY + jz AUXBUS ; then device is busy (not ready) + TEST AH,FLAG_TRANHOL_EMP ;TEST TRANSMIT HOLD REG EMPTY +;;End of modification ------------------------- + jz AUXBUS ; then device is busy (not ready) + Jump Exit + +AUX$WRST ENDP + +; +; AUXSTAT makes a call on the ROM-BIOS to determine the status +; of the auxilary device +; Outputs: +; AX is filled with status of port. +; DX is changes to specify which card - either 0, 1 (, 2, 3) ;ba +; NO other registers are modified +; + +AUXSTAT proc near + mov ah,AUXFUNC_STATUS + call AUXOP + ret +AUXSTAT endp + +AUXOP PROC NEAR + ;AH=FUNCTION CODE + ;0=INIT, 1=SEND, 2=RECEIVE, 3=STATUS + call GETDX ; have DX point to proper card + int 14h ; call rom-bios for status + ret +AUXOP ENDP + +;---------------------------------------------------------------- +; : +; Flush AUX Input buffer - set contents of AUXBUF to zero : +; : +;---------------------------------------------------------------- + PUBLIC AUX$FLSH +AUX$FLSH PROC NEAR + ASSUME DS:CODE ; SET BY AUX DEVICE DRIVER ENTRY ROUTINE + call GETBX ; get BX to point to AUXBUF + mov BYTE PTR [BX],0 ; zero out buffer + Jump Exit ; all done, successful return +AUX$FLSH ENDP + + + +;---------------------------------------------------------------- +; : +; Write to Auxilary Device : +; : +;---------------------------------------------------------------- + PUBLIC AUX$WRIT +AUX$WRIT PROC NEAR + ASSUME DS:CODE ; SET BY AUX DEVICE DRIVER ENTRY ROUTINE + jcxz EXVEC2 ; if CX is zero, no characters + ; to be written, jump to exit +AUX$LOOP: + mov AL,ES:[DI] ; get character to be written + inc DI ; move DI pointer to next character +;;Ver 3.30 modification --------------------------- + MOV AH,AUXFUNC_SEND ;VALUE=1, INDICATES A WRITE + CALL AUXOP ;SEND CHARACTER OVER AUX PORT + + TEST AH,FLAG_TIMEOUT ;CHECK FOR ERROR +;;End of modification --------------------------- + jz AWOK ; then no error + mov AL,10 ; else indicate write fault + Jump ERR$CNT ; call error routines + + ; if CX is non-zero, still more +AWOK: + loop AUX$LOOP ; more characrter to print + Jump Exit ; all done, successful return +AUX$WRIT ENDP + + +; +; GETBX puts the address of AUXBUF (the Auxilary Device buffer) +; in BX. After calling GETBX, a routine can get to AUXBUF +; with [BX]. +; +; NOTE: The getdx routine is in msbio1 and looks like: +; mov dx,word ptr cs:[auxnum] +; +GETBX PROC NEAR + call GETDX + mov BX,DX + add BX,OFFSET AUXBUF + ret +GETBX ENDP + +CODE ENDS + END diff --git a/SRC/BIOS/MSAUX.OBJ b/SRC/BIOS/MSAUX.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..23896367a740d0f6dfac1cbee237baf606af7d65 GIT binary patch literal 470 zcmYk2PfG$(6vfXQoi}2k1QN7!AraN4q7R_X_y z*kN-4oOYRN4v|dNN*T4H4b3pkRJLp*JRH@$Ve2(;Qy-4k54T{zVB!N<>YixP?tX~m zbN}}f=qMz8FXlv#J!P>w-X_)~Lk=}%u;VdNP zgY`1Cb%=D}(gRrJjEfRyil_wZHJRQZP3bMpRIw8ncO^dvctc)wB{(OCcf}cdx{L!X sLSLK8m8`-x&>j&}FY9x_&p%?MbpW#?vT7FXJ>cR$vFtK^ldAyEA75jA0RR91 literal 0 HcmV?d00001 diff --git a/SRC/BIOS/MSBDS.INC b/SRC/BIOS/MSBDS.INC new file mode 100644 index 0000000..a8f8f5e --- /dev/null +++ b/SRC/BIOS/MSBDS.INC @@ -0,0 +1,118 @@ +; +; BDS is the Bios Data Structure. +; +; There is one BDS for each logical drive in the system. All the BDS's +; are linked together in a list with the pointer to the first BDS being +; found in Start_BDS. The BDS hold various values important to the disk +; drive. For example there is a field for last time accesses. As actions +; take place in the system the BDS are update to reflect the actions. +; For example is there is a read to a disk the last access field for the +; BDS for that drive is update to the current time. +; +; Values for various flags in BDS.Flags. +; + +fNon_Removable equ 01H ;For non-removable media +fChangeline equ 02H ;If changeline supported on drive +RETURN_FAKE_BPB equ 04H ; When set, don't do a build BPB + ; just return the fake one +GOOD_TRACKLAYOUT equ 08H ; The track layout has no funny sectors +fI_Am_Mult equ 10H ;If more than one logical for this physical +fI_Own_Physical equ 20H ;Signify logical owner of this physical +fChanged equ 40H ;Indicates media changed +SET_DASD_true equ 80H ; Set DASD before next format +fChanged_by_format equ 100h + +; +; Various form factors to describe media +; + +ff48tpi equ 0 +ff96tpi equ 1 +ffSmall equ 2 +ffHardFile equ 5 +ffOther equ 7 + +BDS_Type struc +Link DD ? ; Link to next BDS +DriveNum DB ? ; Physical drive number +DriveLet DB ? ; DOS drive number +BytePerSec DW ? ; number of bytes/sec +SecPerClus DB ? ; sec per allocation unit +RESSEC DW ? ; number of reserved sectors +cFAT DB ? ; number of fats +cDir DW ? ; number of directory entries +DRVLIM DW ? ; number of sectors on medium +mediad DB ? ; media descriptor byte +cSecFat DW ? ; number of sectors/fat +SECLIM DW ? ; sectors per track +HDLIM DW ? ; max number of heads +HIDSEC DW ? ; number of hidden sectors +FatSiz DB ? ; flags... +Opcnt DW ? ; Open ref. count +Volid DB 12 dup (?) ; volume ID of medium +FormFactor DB ? ; form factor index +Flags DW ? ; various flags +cCyln DW ? ; max number of cylinders +RBytePerSec DW ? ; Recommended BPB +RSecPerClus DB ? +RRESSEC DW ? +RcFAT DB ? +RcDir DW ? +RDRVLIM DW ? +Rmediad DB ? +RcSecFat DW ? +RSECLIM DW ? +RHDLIM DW ? +RHIDSEC DW ? +RHHIDSEC DW ? +RLOGSEC DD ? +Reserve DB 6 dup (?) ; Reserved for future + ; changed to word -- kcd9:85 +Track DB ? ; last track accessed on drive +Tim_Lo DW ? ; Time of last access. Keep +Tim_Hi DW ? ; these contiguous. +BDS_Type ends + +BPBSize = Track - RBytePerSec ; size in bytes of RecBPB area in the BDS + + +;;Rev 3.30 Modification +;********************************************************************* +; BDS structure for mini disk +;********************************************************************* + +BDSM_type struc +mlink DW -1 ;Link to next structure + DW ? +mdriveNum DB 80 ;Int 13 Drive Number +mdriveLet DB 3 ;Logical Drive Number +mBytePerSec DW 512 +mSecPerClus DB 1 ;Sectors/allocation unit +mRESSEC DW 1 ;Reserved sectors for DOS +mcFAT DB 2 ;No. of allocation tables +mcDIR DW 16 ;Number of directory entries +mDRVLIM DW 0 ;Number of sectors (at 512 bytes each) +mMediad DB 11111000B ;Media descriptor +mcSecFat DW 1 ;Number of FAT sectors +mSECLIM DW 0 ;Sector limit +mHDLIM DW 0 ;Head limit +mHIDSEC DW 0 ;Hidden sector count +mFatSiz DB 0 ;TRUE => bigfat +mOPCNT DW 0 ;Open Ref. Count +mVOLID DB "NO NAME " ;Volume ID for this disk + DB 0 ;ASCIZII for "NO NAME " +mFormFactor DB 3 ;Form Factor +mFLAGS DW 0020H ;Various Flags +mcCyln dw 40 ;max number of cylinders +mRecBPB db 31 dup (0) ;Recommended BPB for drive +mTrack db -1 +IsMini dw 1 ;Overlapping TIM_LOH +Hidden_Trks dw 0 ;Overlapping TIM_HIH + +;TIM_LOH DW -1 ;Keep these two contiguous (?) +;TIM_HIH DW -1 +BDSM_type ENDS +;****************************************************************************** +Max_mini_dsk_num = 23 ; Max # of mini disk bios can support +;;End of Modification diff --git a/SRC/BIOS/MSBIO.LNK b/SRC/BIOS/MSBIO.LNK new file mode 100644 index 0000000..29a65f3 --- /dev/null +++ b/SRC/BIOS/MSBIO.LNK @@ -0,0 +1,5 @@ +msbio1+mscon+msaux+mslpt+msclock+msdisk+ +msbio2+mshard+msinit+sysinit1+sysconf+sysinit2+sysimes, +msbio, +msbio/m; + \ No newline at end of file diff --git a/SRC/BIOS/MSBIO1.ASM b/SRC/BIOS/MSBIO1.ASM new file mode 100644 index 0000000..84a1f29 --- /dev/null +++ b/SRC/BIOS/MSBIO1.ASM @@ -0,0 +1,693 @@ + TITLE MSBIO MS-DOS 3.30 + +;------------------------------------------------------------------------------- +; : +; Microsoft Bio : +; : +; The file msbio.asm is the main file in the Mircosoft bio. This file : +; includes the other main files in the bio. Most of the routines are : +; in these include files. The main files included are: : +; : +; File Contains : +; : +; msdisk.inc Disk device driver routines : +; ms96tpi.inc Routines for 96tpi drives : +; msaux.inc Device driver for the rs-232 serial ports : +; msclock.inc Device driver for "clock$" device : +; mscon.inc Device driver for "con" : +; mslpt.inc Device driver for the printers : +; : +; Each of these files contain a header section documenting the code : +; in that file. : +; Msbio also includes several files for equ's, structure definition, : +; macro definitions, etc. These are: : +; : +; msbiomes.inc msmacro.inc devsym.inc : +; dskprm.inc error.inc : +; : +; Each of these file contains explanitory notes. : +; : +; The actual code in msbio can be broken down into several piece: : +; : +; macro definitions Several marco are defined in msbio. They : +; are a few odds and end that did not fit : +; anywhere else. : +; : +; Command Jump Table List of entry points in the device drivers. : +; See notation below for full explination. : +; : +; Interrupt and Strategy : +; Entry points Calls on the device driver first come to here. : +; There is common code with pushes registers and : +; the like before jumping to routines in the : +; driver files. The common exit points are also : +; in this file. : +; : +; Miscellaneous Code There are several routines and data structure : +; declarations. See below for details. : +; : +;------------------------------------------------------------------------------- + + + +; +; If the variable TEST is non-zero then code for debugging is included. +; The extra code will make the binary file nuch larger. +; The symbol is also defined in msequ.inc. Both must be changed to +; turn debugging on or off. +; +; The level of the debugging is controled by the variable fTestBits in +; this file. See the comment preceeding the variable for more information. +; The actual routines which print the messages are in msmacro.inc +; See the header comment in this file for more information. +; +;***For testing purposes, set the TEST flag to 1. Otherwise reset it. + +TEST=0 + +PATHGEN = 1 + +.SALL +; +; This is a DOSMAC macro which is used in DEVSYM which is included later. +; + +BREAK MACRO subtitle + SUBTTL subtitle + PAGE + ENDM + +; +; Some old versions of the 80286 have a bug in the chip. The popf +; instruction will enable interrupts. Therefore in a section of code with +; interrupts disabled and you need a popf instruction use the 'popff' +; macro instead. +; + +POPFF macro + jmp $+3 + iret + push cs + call $-2 + endm + +;;Rev 3.30 modification ----------------------------- + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + +SYSINITSEG SEGMENT PUBLIC 'SYSTEM_INIT' +SYSINITSEG ENDS + + + INCLUDE JUMPMAC.INC +PATHSTART MACRO INDEX,ABBR + IFDEF PATHGEN + PUBLIC ABBR&INDEX&S,ABBR&INDEX&E + ABBR&INDEX&S LABEL BYTE + ENDIF + ENDM + +PATHEND MACRO INDEX,ABBR + IFDEF PATHGEN + ABBR&INDEX&E LABEL BYTE + ENDIF + ENDM + + INCLUDE PUSHPOP.INC + INCLUDE DEVSYM.INC ;MJB001 +;; End of Modification + +; +; Revision History +; +; REV 2.1 5/1/83 ARR added timer int handler and changed order of AUX +; PRN init for HAL0 +; +; REV 2.15 7/13/83 ARR Because of IBM design issues, and that BASCOM +; is ill behaved with respect to the 1CH timer interrupt, +; the timer handler has to be backed out! The intended +; code is commented out and has an ARR 2.15 annotation. +; This means the BIOS will go back to the multiple roll +; over bug. +; +; REV 2.20 8/5/83 ARR IBM makes hardware change. Now wants to use half +; height drives for HAL0, and back fit for PC/PC XT. Problem +; with head settle time. Previous drives got by on a 0 +; settle time, 1/2 hight drives need 15 head settle when +; doing WRITEs (0 ok on READ) if the head is being stepped. +; This requires a last track value to be kept so that BIOS +; knows when head is being moved. To help out +; programs that issue INT 13H directly, the head settle will +; normally be set to 15. It will be changed to 0 on READs, +; or on WRITEs which do not require head step. +; +; REV 2.21 8/11/83 MZ IBM wants write with verify to use head settle 0. +; Use same trick as above. +; +; REV 2.25 6/20/83 mjb001 added support for 96tpi and salmon +; +; REV 2.30 6/27/83 mjb002 added real-time clock +; +; REV 2.40 7/8/83 mjb003 added volume-id checking and int 2f macro +; definitions push* and pop* +; +; REV 2.41 7/12/83 ARR more 2.X enhancements. Open/Close media change +; +; REV 2.42 11/3/83 ARR more 2.X enhancements. Disk OPEN/CLOSE, FORMAT +; code and other misc hooked out to shrink BIOS. Code for +; Disk OPEN/CLOSE, FORMAT included only with 96tpi disks. +; +; Rev 2.43 12/6/83 MZ Examine boot sectors on hard disks for 16-bit fat +; check. Examine large fat bit in BPB for walk of media for +; DOS +; +; Rev 2.44 12/9/83 ARR Change to error reporting on INT 17H +; +; Rev 2.45 12/22/83 MZ Make head settle change only when disk parm is 0. +; +; Rev 3.21 3/20/87 SP Changed OUTCHR routine to always output to page 0. + +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +; IBM ADDRESSES FOR I/O +; +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +include dskprm.inc + + SYSIZE = 100H ; number of paragraphs in sysinit module + LF = 10 ; line feed + CR = 13 ; carriage return + BACKSP = 8 ; backspace + BRKADR = 1BH * 4 ; 006C 1Bh break vector address + TIMADR = 1CH * 4 ; 0070 1Ch timer interrupt + DSKADR = 1EH * 4 ; address of ptr to disk parameters + SEC9 = 522H ; address of disk parameters + HEADSETTLE = SEC9+9 ; address of head settle time + NORMSETTLE = 15 ; Normal head settle + SPEEDSETTLE = 0 ; Speed up settle time + INITSPOT = 534H ; IBM wants 4 zeros here + AKPORT = 20H + EOI = 20H + +;;Rev 3.30 modification ----------------------------- + ASSUME CS:CODE,DS:NOTHING,ES:NOTHING + + EXTRN MEDIA$CHK:NEAR + EXTRN GET$BPB:NEAR + EXTRN DSK$INIT:NEAR + EXTRN DSK$READ:NEAR + EXTRN DSK$WRIT:NEAR + EXTRN DSK$WRITV:NEAR + EXTRN DSK$OPEN:NEAR + EXTRN DSK$CLOSE:NEAR + EXTRN DSK$REM:NEAR + EXTRN GENERIC$IOCTL:NEAR + EXTRN IOCTL$GETOWN:NEAR + EXTRN IOCTL$SETOWN:NEAR + EXTRN CON$READ:NEAR + EXTRN CON$RDND:NEAR + EXTRN CON$FLSH:NEAR + EXTRN CON$WRIT:NEAR +; EXTRN CON$GENIOCTL:NEAR + EXTRN AUX$READ:NEAR + EXTRN AUX$WRIT:NEAR + EXTRN AUX$FLSH:NEAR + EXTRN AUX$RDND:NEAR + EXTRN AUX$WRST:NEAR + EXTRN TIM$READ:NEAR + EXTRN TIM$WRIT:NEAR + EXTRN PRN$WRIT:NEAR + EXTRN PRN$STAT:NEAR + EXTRN PRN$TILBUSY:NEAR + EXTRN PRN$GENIOCTL:NEAR + EXTRN WRMSG:NEAR +;DATA AREAS + INCLUDE MSDATA.INC +;;End of modification ----------------------------- + +; +; The following variables and two routines (MSGOUT and MSGNUM) are used +; with the debug routines to print numbers and messages on the screen. +; +; The variable fTestBits controls the level of debugging in the system. +; See the comments and "equ's" in msmacro.inc for an explination of +; how to control the level of debugging. In a nutshell, setting +; fTestBits to fTestALL prints all the debugging messages. Setting +; it to fTestDisk prints all disk related messages, etc. +; + +if test +Public MSGNUM +MSGNUM: + pushf + test fTestBits,AX + jz MRet + push SI + push BX + push CX + push ES + push DI + mov DI,OFFSET NUMBUF + push CS + pop ES + mov CX,4 +NUMLOOP: + push CX + mov CL,4 + rol BX,CL + pop CX + push BX + and BX,0Fh + mov AL,Digits[BX] + stosb + pop BX + loop NumLoop + pop DI + pop ES + pop CX + pop BX + mov SI,OFFSET NUMBUF + call MSGOUT + pop SI + popf + ret + +Public MSGOUT +MSGOUT: + pushf + test fTestBits,ax + jz MRet + push DS + push AX + push BX + push CS + pop DS + call WRMSG + pop BX + pop AX + pop DS +MRet: + popf + ret +;;Rev 3.30 modification ----------------------------- + PUBLIC DUMPBYTES +;Dumpbytes will dump the bytes in memory in hex. Space will be put in +;between the bytes and CR, LF will be put at the end. - J.K. +;Input: DS:SI -> buffer to dump in Hex. +; CX -> # of bytes (Length of the buffer) +; +DUMPBYTES proc near + pushf + push ax +dumploops: + lodsb + mov ah, al + shr ah, 1 + shr ah, 1 + shr ah, 1 + shr ah, 1 + call hex_to_ascii + push ax + mov al, ah + call outchar + pop ax + call outchar + mov al, ' ' + call outchar + loop dumploops + + mov al, 0dh + call outchar + mov al, 0ah + call outchar + + pop ax + popf + ret +DUMPBYTES endp + + PUBLIC Hex_to_ascii +Hex_to_ascii proc near + and ax, 0f0fh + add ah, 30h + cmp ah, 3ah + jb hta_$1 + add ah, 7 +hta_$1: + add al, 30h + cmp al, 3ah + jb hta_$2 + add al, 7 +hta_$2: + ret +Hex_to_ascii endp + + PUBLIC outchar +Outchar proc near + PUSH AX + PUSH SI + PUSH DI + PUSH BP + PUSH BX + MOV AH, 0Eh ;SET COMMAND TO WRITE A CHAR + MOV BL, 7 ;SET FOREGROUND COLOR + mov bh,0 ; + INT 10h ;CALL ROM-BIOS + POP BX + POP BP + POP DI + POP SI + POP AX + RET +Outchar endp + + ENDIF +;;End of modification ----------------------------- + +; +; end of routines for debugging +; + INCLUDE MSMACRO.INC + + + +; +; The next nine equ's describe the offset into the request header for +; different information. For example STATUS is in byte 3 of the request +; header (starting count at zero). +; + +CMDLEN = 0 ; length of this command +UNIT = 1 ; sub unit specifier +CMD = 2 ; command code +STATUS = 3 ; status +MEDIA = 13 ; media descriptor +TRANS = 14 ; transfer address +COUNT = 18 ; count of blocks or characters +START = 20 ; first block to transfer +EXTRA = 22 ; Usually pointer to Vol Id for error 15 + +; +; Strategy is the strategy entry point for all default bio device drivers. +; All that is done is to save the pointer to the request header in the +; variable PtrSav. +; + +PUBLIC STRATEGY +STRATEGY PROC FAR + mov word ptr CS:[PTRSAV],BX + mov word ptr CS:[PTRSAV+2],ES + ret + +STRATEGY ENDP + + +;------------------------------------------------------------------------------ +; +; Device entry point +; +; The following ten pieces of code are the interrupt entry points for the +; default device drivers. These small pieces of code have two jobs. +; +; 1) Make SI point to the beginning of the proper command jump table. +; SI must first be pushed to preserve original contents. +; 2) If the call is an AUX or a printer save the number of the +; request in AL. AL is moved to AUXNUM below. +; + +; +; Con device: +; + +;;Rev 3.30 modification ----------------------------- + PUBLIC CON$IN +CON$IN PROC FAR + PUSH SI + MOV SI,OFFSET CONTBL + JMP SHORT ENTRY +CON$IN ENDP + + PUBLIC AUX0$IN +AUX0$IN PROC FAR + PUSH SI + PUSH AX + XOR AL,AL + JMP SHORT AUXENT +AUX0$IN ENDP + + PUBLIC AUX1$IN +AUX1$IN PROC FAR + PUSH SI + PUSH AX + MOV AL,1 + JMP short AUXENT +AUX1$IN ENDP + + PUBLIC AUX2$IN +AUX2$IN proc far + push si + push ax + mov al,2 + jmp short AUXENT +AUX2$IN endp + + PUBLIC AUX3$IN +AUX3$IN proc far + push si + push ax + mov al,3 + jmp short AUXENT + +AUXENT: + MOV SI,OFFSET AUXTBL + JMP SHORT ENTRY1 +AUX3$IN ENDP + +PRN0$IN PROC FAR + PUBLIC PRN0$IN + + PUSH SI + PUSH AX + XOR AX,AX + JMP SHORT PRNENT +PRN0$IN ENDP + + PUBLIC PRN1$IN +PRN1$IN PROC FAR + PUSH SI + PUSH AX + XOR AL,AL + MOV AH,1 + JMP SHORT PRNENT +PRN1$IN ENDP + + PUBLIC PRN2$IN +PRN2$IN PROC FAR + PUSH SI + PUSH AX + MOV AL,1 + MOV AH,2 + JMP SHORT PRNENT +PRN2$IN ENDP + + PUBLIC PRN3$IN +PRN3$IN PROC FAR + PUSH SI + PUSH AX + MOV AL,2 + MOV AH,3 +PRNENT: + MOV SI,OFFSET PRNTBL + MOV CS:[PRINTDEV],AH ;SAVE INDEX TO ARRAY OF RETRY CNTS + JMP SHORT ENTRY1 +PRN3$IN ENDP + + PUBLIC TIM$IN +TIM$IN PROC FAR + PUSH SI + MOV SI,OFFSET TIMTBL + JMP SHORT ENTRY +TIM$IN ENDP + + PUBLIC DSK$IN +DSK$IN PROC FAR + push SI + mov SI,OFFSET DSKTBL +;;End of modification ----------------------------- + + + +; +; This section is the prolog to all default device drivers. All registers +; are saved, the registers are filled with information fromthe request header, +; and the routine from the jump table is called. Error checking is done +; to assure command code is valid. Before calling the routine in the +; jump table the register are: +; +; AH = Media Descriptor +; AL = Unit Code +; BX = offset to PTRSAV (request header is therefore at DS:BX) +; CX = count from request header +; DX = start sector +; ES:DI = tranfer address +; SI = points to jump table +; DS = points to this segment +; +; Once the routine finishes its job it jumps back to one of the eight +; pieces of code below labeled Exit Points. +; + +ENTRY: + push AX +ENTRY1: + push CX ; save all registers + push DX + push DI + push BP + push DS + push ES + push BX + + mov CS:[AUXNUM],AL ; save choice of AUX/PRN device + + lds BX,CS:[PTRSAV] ; get pointer to I/O packet + ASSUME DS:NOTHING + + mov AL,byte ptr DS:[BX].UNIT ;AL = UNIT CODE + mov AH,byte ptr DS:[BX].MEDIA ;AH = MEDIA DESCRIP + mov CX,word ptr DS:[BX].COUNT ;CX = COUNT + mov DX,word ptr DS:[BX].START ;DX = START SECTOR + + xchg DI,AX + mov AL,BYTE PTR DS:[BX].CMD + cmp AL,CS:[SI] ; is command code a valid number? + ja CMDERR ; no, jump to handle error + + cbw ; note that AL <= 15 means OK + shl AX,1 + add SI,AX ; get SI to point to address of routine + xchg AX,DI ; put proper value back into AX + ; get ES:DI to point to transfer address + les DI,DWORD PTR DS:[BX].TRANS + push CS ; get DS equal to CS + pop DS + + ASSUME DS:CODE + + cld ; clear the direction flag + jmp WORD PTR [SI+1] ; go to the command + +DSK$IN ENDP +PAGE +;===================================================== +;= +;= SUBROUTINES SHARED BY MULTIPLE DEVICES +;= +;===================================================== + + + +;---------------------------------------------------------- +; +; Exit Points +; +; All device driver call return through one of these eight +; pieces of code. The code set error and status conditions +; and then restores the registers. +; + +PUBLIC BUS$EXIT ; device busy exit +BUS$EXIT PROC FAR + ASSUME DS:NOTHING + mov AH,00000011B ; set error code + jmp SHORT ERR1 + +PUBLIC CMDERR +CMDERR: + mov AL,3 ; unknown command error + +PUBLIC ERR$CNT +ERR$CNT: + lds BX,CS:[PTRSAV] + ASSUME DS:NOTHING + sub WORD PTR [BX].COUNT,CX ;# of successful I/O's + +PUBLIC ERR$EXIT +ERR$EXIT: + mov AH,10000001B ; mark error and return + jmp SHORT ERR1 + +BUS$EXIT ENDP +EXITP proc FAR + ASSUME DS:CODE + +EXIT$ZER: + lds BX,[PTRSAV] + ASSUME DS:NOTHING + xor AX,AX + mov WORD PTR [BX].COUNT,AX ; indicate no character read + +Public EXIT +EXIT: + ASSUME DS:NOTHING + mov AH,00000001B +ERR1: + ASSUME DS:NOTHING + lds BX,CS:[PTRSAV] + mov WORD PTR [BX].STATUS,AX ; mark operation complete + + pop BX ; restore register and return + pop ES + pop DS + pop BP + pop DI + pop DX + pop CX + pop AX + pop SI + ret +EXITP endp + + +;------------------------------------------------------------- +; +; Chrout - write out character in AL using current attribute +; +; called via int 29h +; + PUBLIC CHROUT +CHROUT = 29H + + Public OUTCHR +OUTCHR PROC FAR + push AX ; preserve affect registers + push SI + push DI + push BP + push bx ; + mov AH, 0Eh ; set command to write a character + mov bh,0 ; + mov BL, 7 ; set foreground color + int 10h ; call rom-bios + pop bx ; + pop BP ; restore registers + pop DI + pop SI + pop AX + iret +OUTCHR ENDP + + +;---------------------------------------------- +; +; Fill DX register with value in AUXNUM +; + + PUBLIC GETDX +GETDX PROC NEAR + mov DX,WORD PTR CS:[AUXNUM] + ret +GETDX ENDP + page +CODE ENDS + END diff --git a/SRC/BIOS/MSBIO1.OBJ b/SRC/BIOS/MSBIO1.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..8177a31d58bfde9d554b5ad997c0d40b92a866c8 GIT binary patch literal 4091 zcmb_feQXrR6@N2#J3fD497BjnDOl+hg%r8=nYbZpD&NQY?&7=K&FVww6IGxk?NHqK+wtW9-mnqTYwTV-o{BrR9<4>u(UUo) z9z9tFv2%iRmPKg*z~g0qIr0Sa1=BtLu7n)}SF$3hNLkW@WhraL9pbWWJO#4<`&;2cHsE6eJm@o+8OoL#kA-r6-B{*H|TGU_n$*=~g`Kj~ihp z0aa1m@rTS1cwK)r@stzj%0=RKH`KWnel#$$sd>#Ntvabk;z55nhGwRfLZcM<^C``C zf)3Ow$%!XIX}cF(nkMeVlNg;!hLT)P%UVf03hxy!0|WRYKok7;znV`N@=1L4f3*J; zPkwamV;zCEfAjXaDZvjg!4^rcV6{>R_JH&W)+lR$u~8xG1Y02MQ63Vq0bx?eMuNqH zEtE?HYmiMuJV>w%0S7J@tWGuyRwEx0tX}%5b0xvU1dj-IpIl9H3qdPEK(PDe8o`#x z$B1~G;L8MGLBMBp3g(j`!K!40_%6YOj0sjPpHxkPSd+jaa0oI8=%Pn3k6b4hmm7%R zBp8#M1@p?MRnsS!CI_f%2f-l0E(CNiEZ8zRf-)v(jCytxj0^Tzxkok65ivoqpWpxj zj{hdYJ|PbxpodB7J3??&u+PYXYK{rERDOrp;{+!OUL=?zI3?JFvPkl2f-{0O$?uc= z1A>~c8p0??no{}xUH2` zVV_}cF(avpxki*!?Y_#Ss#YXB5n4s*NrX38o5-pfTXI0W>HdW?&ngiGLmYQKh#R+5jwcMK;#U< zN7|K=7i<1)qOK#%X{DQjEiTJ!sH!a3xyRx{kc6HJ`Gw>E*(1IgOo{mIF*i*<}BM!$#xb?BWxXQQq>n z_v?#JUc2S_;Dmg>zJA5sxjr`SnO%C;1Gl!y$)6At0MLp}QR&30z z>+RX}mYK<>?dke+@N(5J8rE;jZR+_|%i$#eukWAQ3R1)MJ`e7Gehnn1fqe@eR)ljJ*f4ARNK=7atFd7lS2qN{1m|t30@(%fiTF13yruGwZU*$x9zZzPB|ur zONBZlwP3;t#&7{v6zWl}!V|O=Z%DT__;!V8L*hdX4pxW&5+7->uR^pVF{iZxX7U}2k ze0fCL!r<|k`eH?QtnL9050D-S_J&gqR`+X#`_N-eWc%n&JHK^oXk?#?3-4ac6EU5q zIV>p;urkSD&kVzqxk;v*Y=?kvRCEmaRR-_TVBK&wb7-OoVM6@)xUUJgO^H;5O5|Pv zM=5?};;FB4*h%hC#jHMyXI-HdWAQ5ENdd>nUsuG6XY{s%Uij_3MBs)OChsNMS8LF5 zFR|u14gNsHw%C^4`L!LdGkAhxa*6KNwU-$Dm6)zXFdD)y2#dpcN_>}LC7m43ZIHv# zGDSCQ-MY-+8d1@pnKOe1Xl`f(1A z6c%Ap>yidmH{SUzCvC1*rQ&YEl%CC5M)C~?8)#%IKRy=NmTPN|acHFdfx(7!D`#}6 zEpidyyYssNJ1`1-E$*Rt8H0Uo?Pme!?N*I3vc12peH!59vYy5)S*HXpio3zgfoDf^ zk&)dO8Eh*vmY%`yBx?rX^YaXT>tJ%OX;_eFly(c!NSS9m@`8&I3rAiKVI`!{Nok{g}J@QLLWa0B*wE=-Aj`j$?H0 z3^5;A={+1mg{5fMh&o0ePNeZ;6lF~KQ4S8}A2-}cek`905B24*F!(*?7VF7L=(wLP zJ>_iRaF=!{(RRYfZshQ8`C;34^$+GHgGXtX*vYkls~UWZBDPJOzzz=ivawodKOR{x z(X!fOTSmrmp@^N}aFJ4rC1mCzR_5mn7S1zP(9xs4cvgDp6nBE5gihs+ubjV=Z}mkO zPqhj>lie(!j@dlJ;0|RMb>;Ud4%f>DRyUT)E)KOcyNvpB%?0uM5?{dUh|31!PR@N@ ZT-RVT1)a5=41NW7_2Npbp2Xu}?4N8%Yc2o) literal 0 HcmV?d00001 diff --git a/SRC/BIOS/MSBIO2.ASM b/SRC/BIOS/MSBIO2.ASM new file mode 100644 index 0000000..42bd7d6 --- /dev/null +++ b/SRC/BIOS/MSBIO2.ASM @@ -0,0 +1,650 @@ + TITLE MSBIO2 - DOS 3.3 + +;------------------------------------------------------------------------------- +; : +; Microsoft Bio : +; : +; The file msbio.asm is the main file in the Mircosoft bio. This file : +; includes the other main files in the bio. Most of the routines are : +; in these include files. The main files included are: : +; : +; File Contains : +; : +; msdisk.inc Disk device driver routines : +; ms96tpi.inc Routines for 96tpi drives : +; msaux.inc Device driver for the rs-232 serial ports : +; msclock.inc Device driver for "clock$" device : +; mscon.inc Device driver for "con" : +; mslpt.inc Device driver for the printers : +; : +; Each of these files contain a header section documenting the code : +; in that file. : +; Msbio also includes several files for equ's, structure definition, : +; macro definitions, etc. These are: : +; : +; msbiomes.inc msmacro.inc devsym.inc : +; dskprm.inc error.inc : +; : +; Each of these file contains explanitory notes. : +; : +; The actual code in msbio can be broken down into several piece: : +; : +; macro definitions Several marco are defined in msbio. They : +; are a few odds and end that did not fit : +; anywhere else. : +; : +; Command Jump Table List of entry points in the device drivers. : +; See notation below for full explination. : +; : +; Interrupt and Strategy : +; Entry points Calls on the device driver first come to here. : +; There is common code with pushes registers and : +; the like before jumping to routines in the : +; driver files. The common exit points are also : +; in this file. : +; : +; Miscellaneous Code There are several routines and data structure : +; declarations. See below for details. : +; : +;------------------------------------------------------------------------------- + + + +; +; If the variable TEST is non-zero then code for debugging is included. +; The extra code will make the binary file nuch larger. +; The symbol is also defined in msequ.inc. Both must be changed to +; turn debugging on or off. +; +; The level of the debugging is controled by the variable fTestBits in +; this file. See the comment preceeding the variable for more information. +; The actual routines which print the messages are in msmacro.inc +; See the header comment in this file for more information. +; + + +; +; Revision History +; +; REV 2.1 5/1/83 ARR added timer int handler and changed order of AUX +; PRN init for HAL0 +; +; REV 2.15 7/13/83 ARR Because of IBM design issues, and that BASCOM +; is ill behaved with respect to the 1CH timer interrupt, +; the timer handler has to be backed out! The intended +; code is commented out and has an ARR 2.15 annotation. +; This means the BIOS will go back to the multiple roll +; over bug. +; +; REV 2.20 8/5/83 ARR IBM makes hardware change. Now wants to use half +; height drives for HAL0, and back fit for PC/PC XT. Problem +; with head settle time. Previous drives got by on a 0 +; settle time, 1/2 hight drives need 15 head settle when +; doing WRITEs (0 ok on READ) if the head is being stepped. +; This requires a last track value to be kept so that BIOS +; knows when head is being moved. To help out +; programs that issue INT 13H directly, the head settle will +; normally be set to 15. It will be changed to 0 on READs, +; or on WRITEs which do not require head step. +; +; REV 2.21 8/11/83 MZ IBM wants write with verify to use head settle 0. +; Use same trick as above. +; +; REV 2.25 6/20/83 mjb001 added support for 96tpi and salmon +; +; REV 2.30 6/27/83 mjb002 added real-time clock +; +; REV 2.40 7/8/83 mjb003 added volume-id checking and int 2f macro +; definitions push* and pop* +; +; REV 2.41 7/12/83 ARR more 2.X enhancements. Open/Close media change +; +; REV 2.42 11/3/83 ARR more 2.X enhancements. Disk OPEN/CLOSE, FORMAT +; code and other misc hooked out to shrink BIOS. Code for +; Disk OPEN/CLOSE, FORMAT included only with 96tpi disks. +; +; Rev 2.43 12/6/83 MZ Examine boot sectors on hard disks for 16-bit fat +; check. Examine large fat bit in BPB for walk of media for +; DOS +; +; Rev 2.44 12/9/83 ARR Change to error reporting on INT 17H +; +; Rev 2.45 12/22/83 MZ Make head settle change only when disk parm is 0. + +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +; IBM ADDRESSES FOR I/O +; +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +;Below was moved from sysinit1 +ROMSEGMENT EQU 0F000H +MODELBYTE EQU DS:BYTE PTR [0FFFEH] +MODELPCJR EQU 0FDH + + test=0 +;;Rev 3.30 modification ---------------------------- + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + INCLUDE MSEQU.INC + INCLUDE DEVSYM.INC + INCLUDE PUSHPOP.INC + INCLUDE MSMACRO.INC + + ASSUME DS:NOTHING,ES:NOTHING + + EXTRN DSK$IN:NEAR + EXTRN SETPTRSAV:NEAR + EXTRN OUTCHR:NEAR + EXTRN SETDRIVE:NEAR + EXTRN FLUSH:NEAR + EXTRN HARDERR:NEAR + EXTRN HARDERR2:NEAR + EXTRN MAPERROR:NEAR + EXTRN GETBP:NEAR + EXTRN CHECKSINGLE:NEAR + EXTRN CHECK_TIME_OF_ACCESS:NEAR + EXTRN EXIT:NEAR + EXTRN HAS1:NEAR + EXTRN HAS1_res:NEAR + EXTRN READ_SECTOR:NEAR + EXTRN INT_2F_13:FAR + + EXTRN OLD13:DWORD + +;DATA + EXTRN PTRSAV:DWORD + EXTRN START_BDS:WORD + EXTRN FDRIVE1:WORD + EXTRN FDRIVE2:WORD + EXTRN FDRIVE3:WORD + EXTRN FDRIVE4:WORD + EXTRN FLAGBITS:WORD + EXTRN TIM_DRV:BYTE + EXTRN MEDBYT:BYTE + EXTRN DRVMAX:BYTE + + PATHSTART 005,DISK + EVENB + PUBLIC ORIG19 +ORIG19 DD ? + + PUBLIC INT19SEM +INT19SEM DB 0 ; INDICATE THAT ALL INT 19 + ; INITIALIZATION IS COMPLETE + + IRP AA,<02,08,09,0A,0B,0C,0D,0E,70,72,73,74,76,77> + public Int19OLD&AA +Int19OLD&AA dd -1 ;Orignal hw int. vec for INT 19h. + ENDM + + EVENB + PUBLIC DSKDRVS +DSKDRVS DW FDRIVE1 + DW FDRIVE2 + DW FDRIVE3 + DW FDRIVE4 + PUBLIC HDSKTAB +HDSKTAB DW HDRIVE + DW DRIVEX +;* Next area is reseved for mini disk BPB pointers *** 4/7/86 +;* Don't change this pos. Should be add. from DskDrvs *** 4/7/86 +MINI_DISK_BPB_PTRS DB 40 dup (?) ;4/7/86 - mem res for Mini disk. + + EVENB + PUBLIC INT_2F_NEXT +INT_2F_NEXT DD ? + +RET_ADDR DD ? + + PATHEND 005,DISK +;;End of modification ---------------------------- + +; INT19 +; +; We "hook" the INT_REBOOT vector, because contrary to IBM documentation, +; it does NOT "bootstrap" the machine. It leaves memory almost untouched. +; Since the BIOS_INIT code assumes that certain Interrupt Vectors point to +; the ROM_BIOS we must "unhook" them before issuing the actual INT_REBOOT. +; Currently the following vectors need to be unhooked: +; 02,08,09,0A,0B,0C,0D,0E,70,72,73,74,75,76,77 +; + +Public Int19 +Int19 proc FAR + xor AX,AX ; get data segment to + mov DS,AX ; point to the vector table + assume ds:nothing + assume es:nothing + les DI,Old13 ; get ES to point to this segment + mov DS:[13h*4],DI ; restore old int13 value + mov DS:[13h*4+2],ES + + cmp Byte ptr Int19Sem, 0 + jnz int19vecs + jmp doint19 + +;;Dos 3.30 Will not support the PC-Jr +;;Rev 3.30 modification ---------------------------- +; ON THE PCJR, DON'T REPLACE ANY VECTORS +; MODEL BYTE DEFINITIONS FROM MSSTACK.ASM +; MOV AX,ROMSEGMENT +; MOV DS,AX +; MOV AL,MODELPCJR +; +; CMP AL,MODELBYTE +; JNE INT19VECS +; JMP DOINT19 + + +;Stacks code has changed these hardware interrupt vectors +;STKINIT in SYSINIT1 will initialzie Int19hOLDxx values. +int19vecs: + +; +; we now need to unhook all the vector replace to prevent stack overflow +; + +;;Rev 3.30 modification ---------------------------- + XOR AX,AX + MOV DS,AX + + IRP AA,<02,08,09,0A,0B,0C,0D,0E,70,72,73,74,76,77> + + LES DI,Int19OLD&AA + + mov ax,es ; Put segment where we can compare it + cmp ax,-1 ; OPT 0ffffh is not likely + je skip_int&AA ; OPT could get away without checking + cmp di,-1 ; OPT offset here. + je skip_int&AA + + MOV DS:[AA&H*4],DI + MOV DS:[AA&H*4+2],ES +skip_int&AA: + ENDM +;;End of modification ---------------------------- + +doint19: + LES DI,Orig19 + MOV DS:[19h*4],DI + MOV DS:[19h*4+2],ES + + INT 19h +INT19 ENDP +ASSUME DS:CODE + +;***************************************************************************** +PUBLIC DSK$INIT +DSK$INIT PROC NEAR + PUSH CS + POP DS + MOV AH,BYTE PTR DRVMAX + MOV DI,OFFSET DskDrvs + JMP SetPTRSAV +DSK$INIT ENDP + + +; +; Int 2f handler for external block drivers to communicate with the internal +; block driver in msdisk. The multiplex number chosen is 8. The handler +; sets up the pointer to the request packet in [PTRSAV] and then jumps to +; DSK$IN, the entry point for all disk requests. +; On exit from this driver (at EXIT), we will return to the external driver +; that issued this Int 2F, and can then remove the flags from the stack. +; This scheme allows us to have a small external device driver, and makes +; the maintainance of the various drivers (DRIVER and msBIO) much easier, +; since we only need to make changes in one place (most of the time). +; +; AL contains the Int2F function: +; 0 - Check for installed handler - RESERVED +; 1 - Install the BDS into the linked list +; 2 - DOS request +; + +MYNUM EQU 8 + +Public Int2F_Disk +Int2F_Disk PROC FAR + cmp ah,MYNUM + je Mine + jmp cs:[Int_2F_Next] ; chain to next Int 2F handler +Mine: + cmp al,0F8H ; IRET on reserved functions + jb Do_Func + IRET +Do_Func: + or al,al ; A GET INSTALLED STATE request? + jne Disp_Func + mov al,0FFH + IRET +Disp_Func: + Message fTestInit,<"Int2F_disk",cr,lf> + cmp al,1 ; Request for installing BDS? + jne Do_DOS_Req + call Install_BDS + IRET + +Do_DOS_Req: +; Set up pointer to request packet + MOV WORD PTR CS:[PTRSAV],BX + MOV WORD PTR CS:[PTRSAV+2],ES + jmp DSK$IN + +Int2F_Disk ENDP + +; +; Install_BDS installs a BDS a location DS:DI into the current linked list of +; BDS maintained by this device driver. It places the BDS at the END of the +; list. +Public Install_BDS +INSTALL_BDS PROC NEAR + message ftestinit,<"Install BDS",cr,lf> +; ds:di point to BDS to be installed + les si,dword ptr cs:[Start_BDS] ; Start at beginning of list + push es ; Save pointer to current BDS + push si +; es:si now point to BDS in linked list +Loop_Next_BDS: + cmp si,-1 ; got to end of linked list? + jz Install_Ret +; If we have several logical drives using the same physical drive, we must +; set the I_Am_Mult flag in each of the appropriate BDSs. + mov al,byte ptr ds:[di].DriveNum + cmp byte ptr es:[si].DriveNum,al + jnz Next_BDS + message ftestinit,<"Logical Drives",cr,lf> + xor bx,bx + mov bl,fI_Am_Mult + or word ptr ds:[di].flags,bx ; set flags in both BDSs concerned + or word ptr es:[si].flags,bx + mov bl,fI_Own_Physical + xor bx,-1 + and word ptr ds:[di].flags,bx ; reset that flag for 'new' BDS +; We must also set the fChangeline bit correctly. + mov bx,word ptr es:[si].flags ; determine if changeline available + and bl,fChangeline + xor bh,bh + or word ptr ds:[di].flags,bx + +Next_BDS: +; Before moving to next BDS, preserve pointer to current one. This is needed at +; the end when the new BDS is linked into the list. + pop bx ; discard previous pointer to BDS + pop bx + push es + push si + mov bx,word ptr es:[si].link + 2 + mov si,word ptr es:[si].link + mov es,bx + jmp short Loop_Next_BDS + +Install_Ret: + pop si ; Retrieve pointer to last BDS + pop es ; in linked list. + mov ax,ds + mov word ptr es:[si].link+2,ax ; install BDS + mov word ptr es:[si].link,di + mov word ptr ds:[di].link,-1 ; set NEXT pointer to NULL + RET +INSTALL_BDS ENDP + +; +; RE_INIT installs the Int 2F vector that will handle communication between +; external block drivers and the internal driver. It also installs the +; Reset_Int_13 interface. It is called by SYSYINIT +; +PUBLIC RE_INIT +RE_INIT PROC FAR + Message ftestinit,<"REINIT",CR,LF> + PUSH AX + PUSH DS + PUSH DI + XOR DI,DI + MOV DS,DI + MOV DI,2FH*4 ; point it to Int 2F Vector + MOV AX,WORD PTR DS:[DI] + MOV WORD PTR CS:[INT_2F_NEXT],AX + MOV AX,WORD PTR DS:[DI+2] ; preserve old Int 2F vector + MOV WORD PTR CS:[INT_2F_NEXT+2],AX + +; INSTALL the Reset_Int_13 +; interface + + + CLI + MOV Word Ptr DS:[DI],Offset Int_2f_13 ; install new vectors + MOV Word Ptr DS:[DI+2],CS + STI + POP DI + POP DS + POP AX + RET + +RE_INIT ENDP + +;------------------------------------------------- +; +; Ask to swap the disk in drive A: +; Using a different drive in a one drive system so +; request the user to change disks +; +Public SWPDSK +SWPDSK PROC NEAR + mov al,byte ptr ds:[di].drivelet ; get the drive letter + add al,"A" + mov cs:DRVLET,AL + push ds ; preserve segment register + push cs + pop ds + mov SI,OFFSET SNGMSG ; ds:si -> message + push BX + call WRMSG ;Print disk change message + call FLUSH + ; wait for a keyboard character + xor AH, AH ; set command to read character + int 16h ; call rom-bios + POP BX + pop ds ; restore segment register +WRMRET: + ret +SWPDSK ENDP + +;---------------------------------------------- +; +; WrMsg writes out message pointed to by [SI] +; +Public WrMsg +WRMSG PROC NEAR + lodsb ; get the next character of the message + or AL,AL ; see fi end of message + jz WRMRET + pushf + push CS + call OUTCHR + jmp SHORT WRMSG +WRMSG ENDP + + INCLUDE BIOMES.INC + +; +; End of support for multiple floppies with no logical drives +; This is not 'special' any more because we now have the capability of +; defining logical drives in CONFIG.SYS. We therefore keep the code for +; swapping resident ALL the time. +; + +;;Rev 3.30 modification ---------------------------- +;Variables for Dynamic Relocatable modules +;These should be stay resident. + + public INT6C_RET_ADDR +INT6C_RET_ADDR DD ? ;ret add from INT 6C for P12 mach + + PATHSTART 001,CLK +; +; DATA STRUCTURES FOR REAL-TIME DATE AND TIME +; + public BIN_DATE_TIME + public MONTH_TABLE + public DAYCNT2 + public FEB29 +BIN_DATE_TIME: + DB 0 ; CENTURY (19 OR 20) OR HOURS (0-23) + DB 0 ; YEAR IN CENTURY (0-99) OR MINUTES (0-59) + DB 0 ; MONTH IN YEAR (1-12) OR SECONDS (0-59) + DB 0 ; DAY IN MONTH (1-31) +MONTH_TABLE: + DW 0 ;MJB002 JANUARY + DW 31 ;MJB002 FEBRUARY + DW 59 ;MJB002 + DW 90 ;MJB002 + DW 120 ;MJB002 + DW 151 ;MJB002 + DW 181 ;MJB002 + DW 212 ;MJB002 + DW 243 ;MJB002 + DW 273 ;MJB002 + DW 304 ;MJB002 + DW 334 ;MJB002 +DAYCNT2 DW 0000 ;MJB002 TEMP FOR CNT OF DAYS SINCE 1-1-80 +FEB29 DB 0 ;MJB002 FEBRUARY 29 IN A LEAP YEAR FLAG + PATHEND 001,CLK + +;;End of modification modification ---------------------------- + +Public EndFloppy +EndFloppy Label Byte +; +; End of code for virtual floppy drives +; +Public EndSwap +EndSwap Label Byte + + PATHSTART 004,BIO + +Public HNUM +HNUM DB 0 ; number of hardfile (hard drives) + +Public HardDrv +HARDDRV DB 80H ;Physical drive number of first hardfile + + +; +; "HDRIVE" is a hard disk with 512 byte sectors +; + + EVENB +Public BDSH +BDSH DW -1 ; Link to next structure + DW Code + DB 80h ; physical drive number + DB "C" ; Logical Drive Letter +Public HDRIVE +HDRIVE: + DW 512 + DB 1 ; Sectors/allocation unit + DW 1 ; Reserved sectors for DOS + DB 2 ; No. of allocation tables + DW 16 ; Number of directory entries + DW 0000 ; Number of sectors (at 512 bytes each) + DB 11111000B ; Media descriptor + DW 1 ; Number of FAT sectors + DW 00 ; Sector limit + DW 00 ; Head limit + DW 00 ; Hidden sector count + DB 0 ; TRUE => bigfat +OPCNTH DW 0 ; Open Ref. Count +VOLIDH DB "NO NAME ",0 ; Volume ID for this disk + DB 3 ; Form Factor +FLAGSH DW 0020H ; Various Flags + dw 40 ; number of cylinders +RecBPBH db 31 dup (?) ; Recommended BPB for drive +TRACKH DB -1 ; Last track accessed on this drive +TIM_LOH DW -1 ; Keep these two contiguous (?) +TIM_HIH DW -1 +; +; End of single hard disk section +; + + +Public EndOneHard +EndOneHard Label Byte + + + + +; +;"DRIVEX" is an extra type of drive usually reserved for an +; additional hard file +; + + EVENB +Public BDSX +BDSX DW -1 ; Link to next structure + DW Code + DB 81h ; physical drive number + DB "D" ; Logical Drive Letter +Public DRIVEX +DRIVEX: + DW 512 + DB 00 ; Sectors/allocation unit + DW 1 ; Reserved sectors for DOS + DB 2 ; No. of allocation tables + DW 0000 ; Number of directory entries + DW 0000 ; Number of sectors (at 512 bytes each) + DB 11111000B ; Media descriptor + DW 0000 ; Number of FAT sectors + DW 00 ; Sector limit + DW 00 ; Head limit + DW 00 ; Hidden sector count + DB 0 ; TRUE => bigfat +OPCNTD DW 0 ; Open Ref. Count +VOLIDD DB "NO NAME ",0 ; Volume ID for this disk + DB 3 ; Form Factor +FLAGSD DW 0020H ; Various Flags + dw 40 ; number of cylinders +RecBPBD db 31 dup (?) ; Recommended BPB for drive +TRACKD DB -1 ; Last track accessed on this drive +TIM_LOD DW -1 ; Keep these two contiguous +TIM_HID DW -1 + +; +; End of section for two hard disks +Public EndTwoHard +EndTwoHard Label Byte + + PATHEND 004,BIO + + +Public TwoHard +TWOHARD LABEL BYTE + +PAGE +include ms96tpi.inc + +;;Rev 3.30 modification ---------------------------- +;Memory allocation for BDSM table. + PUBLIC BDSMs +BDSMs BDSM_type Max_mini_dsk_num dup (<>) ;currently max. 23 + +;** End_of_BDSM defined in MSINIT.ASM will be used to set the appropriate +;** ending address of BDSM table. +;;End of modification ---------------------------- + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug005sp +; +;;3.3 BUG FIX -SUNILP ------------------------------ +;Paragraph buffer between the BDSMs and MSHARD +; +;The relocation code for MSHARD needs this. this cannot be used for +;anything. nothing can come before this or after this.....IMPORTANT!!!! +;don't get too smart and using this buffer for anything!!!!!! +; +; db 16 dup(0) +; +;end of bug fix buffer +;; +;;3.3 BUG FIX -SUNILP------------------------------ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug005sp +CODE ENDS + END diff --git a/SRC/BIOS/MSBIO2.OBJ b/SRC/BIOS/MSBIO2.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..c9733271fd13599ebb0d1a8b613ca36269b72d4a GIT binary patch literal 4164 zcmbVPeQ;FO6+icVZ8l531frmjRWL)Gx=pee2*s4mzL#WWKf=CENP=dYnx#ZAVKy%a zR%;j@)_e@Ejw5s?+Gy239RHy8YoZQ8_idoIsDo{XqOA%#71MEAu`wvq?eD!8zGD9B zo1ObR_jk@c_n!OCJ9}?`4oM-kHV~_8)rrRfAtfHEi~Ib3MO8_Xqs<{-3s7CZJP;;9X$i#0Q71?za~L%e%Q4nT z%xTmTV?o}K0Z;PGoI8mz|1gCe5KfQ2z_EMDdwAaok5NN3P!ptKDNLSzbf}L%Lzi^J zhi}bhwY)uOat3O0V3$kQpeq$_C~lZbu^fuhxfCm)xM?oM51{bOr6`A@axTS6D5~aC ztcGIET#CbNSbB@i5yw#|-kwYGM=0KzOYt5Q$LCUBJH@)3HVQ zC4;3z<3!l}{_{DS=*fDB)=nqcySaz^_=DMZ*Rnq0bE0=W151fK!;)p{F{+59<~{$- zYO4nop>(w@^trtsyjbYGqpZ|(Lpyy{!KIT)EFIX5?(4kHovVUx#SQd&mi)5^&Ns%(6}KAi?-Gl z*ObP4r_6!LZ_)Jr2aVa&L^OTO5=}+2z-%0@sa^ksfZw@xQ|Fr6S!gP9E!p}?(w+%? zAlY>Pd8zL#XzfeW;3~6m!kkmgap$mN{FZLqfQ~1FWeq$~JY0WGYrN#8f^(+D3|TN- zUzGkvDdR}HuK)fOoL1a_{#;+tLC5O_ACLXS`5MRe7#uvM5&6h*(j|#qqtBC=s27;h zwWhR8VoYCwxBd%JH`5|18nVQ$)guz)^xGviPwxQxb3xxMv8(jEY{MP^6ZAgIUccA0 zdcd}N2=I!a51Gb~K)z4X4**xRnSHrd!(5ZEbidQgnlg>GB=< zC8)56h{op8*=OP?X z$}tz_t33R?cM5S$Z)$CGq+2IXwzp4y4U=Xw{m!3#rnTJ>FG+*2`_EyW8hG<=Ya^{86<;~oF0}kJ0&(hGhk_+efmveBhuA`DvpZ7WwREL)nkojhw(PW zSsfHQm@!*#QK);ifz4SJaK-@j>@w9%&mKF|ab1=*mVeucJ*C?oy#f_@WeN-Ra^1Nlap%^}9omkrPEDY8 z+m}Ul^*k!jm#O)%nr9K)I9d(Z*6BYGb8xiq5))}u!q}pfGjpr!aimsJIli+^li#F?SujXO(uCCc-zS=?$T zQO_){8ZYIpS)31h)jo@>U5IPTEY81(C^n0emwbOM%JoFIU1_(f{KoH%T~%2|6rN@0 zy_qO5i(6SiB+ufiZXv3f#jUC)sAX, AX->DX, DX->CX + MUL BX ;MULTIPLY HIGH HALF + ADD AX,CX ;COMBINE OVERLAPPING PRODUCTS + ADC DX,0 + XCHG AX,DX ;AX:DX=TIME*59659 + MOV BX,5 + DIV BL ;DIVIDE HIGH HALF BY 5 + MOV CL,AL + MOV CH,0 + MOV AL,AH ;REMAINDER OF DIVIDE-BY-5 + CBW + XCHG AX,DX ;USE IT TO EXTEND LOW HALF + DIV BX ;DIVDE LOW HALF BY 5 + MOV DX,AX + ; CX:DX is now number of ticks in time + ret +TIME_TO_TICKS ENDP +;;End of Modification + + +; +; Gettime reads date and time +; and returns the following information: +; +; ES:[DI] =count of days since 1-1-80 +; ES:[DI+2]=hours +; ES:[DI+3]=minutes +; ES:[DI+4]=seconds +; ES:[DI+5]=hundredths of seconds +; + PUBLIC TIM$READ +TIM$READ PROC NEAR + ; read the clock + xor AH, AH ; set command to read clock + int 1Ah ; call rom-bios to get time + + or al,al ; check for a new day + jz noroll1 ; if al=0 then don't reset day count + INC [DAYCNT] ; CATCH ROLLOVE +noroll1: + MOV SI,[DAYCNT] + +; +; we now need to convert the time in tick to the time in 100th of +; seconds. The relation between tick and seconds is: +; +; 65536 seconds +; ---------------- +; 1,193,180 tick +; +; To get to 100th of second we need to multiply by 100. The equation is: +; +; Ticks from clock * 65536 * 100 +; --------------------------------- = time in 100th of seconds +; 1,193,180 +; +; Fortunately this fromula simplifies to: +; +; Ticks from clock * 5 * 65,536 +; --------------------------------- = time in 100th of seconds +; 59,659 +; +; The calculation is done by first multipling tick by 5. Next we divide by +; 59,659. In this division we multiply by 65,536 by shifting the dividend +; my 16 bits to the left. +; +; start with ticks in CX:DX +; multiply by 5 + MOV AX,CX + MOV BX,DX + SHL DX,1 + RCL CX,1 ;TIMES 2 + SHL DX,1 + RCL CX,1 ;TIMES 4 + ADD DX,BX + ADC AX,CX ;TIMES 5 + XCHG AX,DX + + +; now have ticks * 5 in DX:AX +; we now need to multiply by 65,536 and divide by 59659 d. + + mov CX,59659 ; get divisor + div CX + ; DX now has remainder + ; AX has high word of final quotient + mov BX,AX ; put high work if safe place + xor AX,AX ; this is the multiply by 65536 + div CX ; BX:AX now has time in 100th of seconds + +; +;Rounding based on the remainder may be added here +;The result in BX:AX is time in 1/100 second. + mov DX,BX + mov CX,200 ;Extract 1/100's +;Division by 200 is necessary to ensure no overflow--max result +;is number of seconds in a day/2 = 43200. + div CX + cmp DL,100 ;Remainder over 100? + jb NOADJ + sub DL,100 ;Keep 1/100's less than 100 +NOADJ: + cmc ;If we subtracted 100, carry is now set + mov BL,DL ;Save 1/100's +;To compensate for dividing by 200 instead of 100, we now multiply +;by two, shifting a one in if the remainder had exceeded 100. + rcl AX,1 + mov DL,0 + rcl DX,1 + mov CX,60 ;Divide out seconds + div CX + mov BH,DL ;Save the seconds + div CL ;Break into hours and minutes + xchg AL,AH + +;Time is now in AX:BX (hours, minutes, seconds, 1/100 sec) + + push AX + MOV AX,SI ; DAYCNT + stosw + pop AX + stosw + mov AX,BX + stosw + jmp EXIT + +TIM$READ ENDP +CODE ENDS + END diff --git a/SRC/BIOS/MSCLOCK.OBJ b/SRC/BIOS/MSCLOCK.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..7b0708ef01f749622551b4587cc139b99114bb54 GIT binary patch literal 616 zcmYL`PiPZC6vn^(lf<@`SmPgvVlT31QScx|XmjLYE{XARL?kjBQeUSJg?my6X1=Iu)Ve-!(nExQ6!-K2s_^U+UXwZ#}U}?Jc2ZgC!SQdq#Z` zhB;Si@3GaD^WPi(-ep}ppf2npof_M)HZ99O!n&_ks#1w2`*LBK;(E1?cC*k)=7hqp zJIR!IX zR=*X~<5L3g(kZA0LuV%f!%78s@Sj|p2&%_{U8jYb&ZJaLO(&*jXxd$;g-$T0Ycbu% K8gSR3DfNHMI?w?C literal 0 HcmV?d00001 diff --git a/SRC/BIOS/MSCON.ASM b/SRC/BIOS/MSCON.ASM new file mode 100644 index 0000000..fff22a5 --- /dev/null +++ b/SRC/BIOS/MSCON.ASM @@ -0,0 +1,216 @@ + TITLE MSCON - DOS 3.3 + +;---------------------------------------------------------------- +; : +; C O N - CONSOLE DEVICE DRIVER : +; : +; : +; This file contains the Console Device Driver. The : +; console device driver sends characters to the moniter and : +; gets characters from the keyboard. : +; : +;---------------------------------------------------------------- + +;;Rev 3.30 Modification + test=0 + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + INCLUDE JUMPMAC.INC + INCLUDE MSEQU.INC + INCLUDE MSMACRO.INC + + EXTRN EXIT:NEAR ;MSBIO1 + EXTRN BUS$EXIT:NEAR ;MSBIO1 + +;DATA + EXTRN PTRSAV:DWORD ;MSBIO1 + EXTRN FHAVEK09:BYTE ;MSDISK + EXTRN ALTAH:BYTE ;MSDATA +;;End of Modification + + +;---------------------------------------------------------------- +; : +; Console read routine : +; : +;---------------------------------------------------------------- +; + ASSUME DS:CODE ; THIS WAS SET BY THE CON DD ENTRY PT + PUBLIC CON$READ +CON$READ PROC NEAR + ; if CX is zero, no characters + jcxz CON$EXIT ; to be read -- just exit +CON$LOOP: + call CHRIN ; get char in AL + stosb ; store char at ES:DI, specified buffer + loop CON$LOOP ; if CX is non-zero more char to read +CON$EXIT: + Jump EXIT ; all done, successful return +CON$READ ENDP + + +;---------------------------------------------------------------- +; : +; Input single character into AL : +; : +;---------------------------------------------------------------- +CHRIN PROC NEAR + ; set command to read character + xor AX, AX ; and clear AL + xchg AL,ALTAH ; get character & zero ALTAH + or AL, AL ; see if buffer has a character + jnz KEYRET ; if so - return this character + ; if not - read single character + int 16h ; call ROM-Bios keyboard routine +ALT10: + or AX,AX ; Check for non-key after BREAK + jz CHRIN + cmp AX,7200h ; Check for CTRL-PRTSC + jnz ALT15 + mov AL,16 ; indicate prtsc +ALT15: + or AL,AL ; special case? + jnz KEYRET ; no, return with character + mov ALTAH, AH ; yes, store special key +KEYRET: + RET +CHRIN ENDP + +;---------------------------------------------------------------- +; : +; Keyboard non destructive read, no wait : +; : +; If bit 10 is set by the DOS in the status word of the request : +; packet, and there is no character in the input buffer, the : +; driver issues a system WAIT request to the ROM. On return : +; from the ROM, it returns a 'char-not-found' to the DOS. : +; : +;---------------------------------------------------------------- + +CONBUSJ: + ASSUME DS:NOTHING + JMP CONBUS + + ASSUME DS:CODE ; THIS WAS SET BY THE CON DD ENTRY PT + PUBLIC CON$RDND +CON$RDND: + mov AL,[ALTAH] ; first see if there is a + or AL,AL ; character in the buffer? + jz RD1 ; with debugging code it is + jmp RDEXIT ; too far for conditional jump + +RD1: + ; set command to 'see if + mov AH, 1 ; character available' + int 16h ; call ROM-BIOS keyboard routine + jz nochr ; with debugging code it is + jmp gotchr ; to far for conditional jump +nochr: + cmp fHaveK09, 0 + jz CONBUSJ + lds bx,[PTRSAV] ; get pointer to request header + ASSUME DS:NOTHING + test [bx].STATUS,0400H ; System WAIT enabled? + jz CONBUSJ ; no, get out + + message ftestcon,<"System WAIT stage",cr,lf> + + mov AX, 4100h ; set command for Wait on External + ; event and condition type to + ; any external event + xor BL,BL ; no timeout value + int 15h ; call rom-bios sleep function + message ftestcon,<"Out of wait. AX is "> + mnum ftestcon,ax + message ftestcon, + jmp CONBUS ; after wait exit to con busy + + ASSUME DS:CODE +gotchr: + or AX, AX ; check for null after break + JNZ NOTBRK ; no, skip down +; note: AH is already zero, no need to set command + int 16h ;SB ; yes, read the null + Jump CON$RDND ; and get a real status + +NOTBRK: + cmp AX, 7200H ; check for ctrl-prtsc + jnz RDEXIT ; no + mov AL, 16 ; yes, indicate ctrl-prtsc + + PUBLIC RDEXIT +RDEXIT: + lds BX, [PTRSAV] ; get pointer to request header + ASSUME DS:NOTHING + mov [BX].MEDIA, AL ; move character into req. header +EXVEC: + Jump EXIT ; all done -- successful return +CONBUS: + ASSUME DS:NOTHING + Jump BUS$EXIT ; done -- con device is busy + + +;---------------------------------------------------------------- +; : +; Keyboard flush routine : +; : +;---------------------------------------------------------------- + ASSUME DS:CODE ; THIS WAS SET BY THE CON DD ENTRY PT + PUBLIC CON$FLSH +CON$FLSH: + call FLUSH + Jump Exit + + +PUBLIC FLUSH +FLUSH: + mov [ALTAH], 0 ; clear out holding buffer + +FlLoop: +;;Rev 3.30 Modification + ; Is there a char there? + mov AH, 1 ; command code for check status + int 16h ; call rom-bios keyboard routine + ; if z flag is set then no character + jz FlDone ; is ready, buffer is empty -- get out + xor AH, AH ; if zf is nof set, get character + int 16h ; call rom-bios to get character + jmp FlLoop ; repeat until buffer is empty +FlDone: + ret +;;Rev 3.30 Modification + + +;---------------------------------------------------------------- +; : +; Console Write Routine : +; : +;---------------------------------------------------------------- + ASSUME DS:CODE ; THIS WAS SET BY THE CON DD ENTRY PT + PUBLIC CON$WRIT +CON$WRIT: + jcxz EXVEC ; if CX is zero, get out +CON$LP: + mov AL,ES:[DI] ; get character + inc DI ; point to next character + int CHROUT ; Output character + loop CON$LP ; repeat until all through + Jump Exit + + + +;----------------------------------------------- +; +; BREAK KEY HANDLING +; +Public CBREAK +CBREAK: + mov CS:ALTAH, 3 ; indicate break key set + + + +Public INTRET +INTRET: + IRET + +CODE ENDS + END diff --git a/SRC/BIOS/MSCON.OBJ b/SRC/BIOS/MSCON.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..79b498ea4d95697df88a88f2fbdeb5d449839314 GIT binary patch literal 470 zcmYjO&nrYx6#nk}ac3A}GqX@+Az^_?v7oMbZ{`hS=)LF1#(yA6PoiYhOOq^~jVvUJ z1q)eNSWX$r;$^FBG-E-tu~1|o=b@ukuBjhIpTX3?|LNZ>t*Soc|%S5t;KgLw+D6kHo7|o zR|aDdxD}kqg&NLSp(TKh0OFh}g(1$=!YqO7ki=c&Omdg0XBF;B(6dHLcQ=R*C=y;Z zz<7Mn)Wz@~5c6s%57T9v5^2j=0#5%JQ_E=Wz~?_k7aDEe`^QY0DSHc8@v3N!nn;gZ d#wsxVW0T6*rfwes#h={Nf?t^d8aE`m-WPj3egOag literal 0 HcmV?d00001 diff --git a/SRC/BIOS/MSDATA.INC b/SRC/BIOS/MSDATA.INC new file mode 100644 index 0000000..ebe3862 --- /dev/null +++ b/SRC/BIOS/MSDATA.INC @@ -0,0 +1,882 @@ +; +; After the boot sector reads in msbio it jumps to this location. Msbio +; immediately jumps to initialization code in msinit. +; + + EXTRN INIT:NEAR + +Public START$ +START$: + JMP INIT ; START$ patch by init to point to + ; hdrive BPB + + + PATHSTART 001,BIO + + +;---------------------------------------------------------------------------- +; +; Command Jump Tables +; +; These tables hold the entry points for the various service routines +; for the different drivers. The index in the table is the command code for +; that funcion plus two. For example the command code for Read (input) is 4, +; The 6th (4 plus 2) entry in the table DSKTBL is DSK$READ - the command to +; read a disk. Commands which do not exist for a device are filled with +; exit (e.g. MediaCheck for CONTBL). The first entry in the table is the +; largest command code implemented for that device. This value is used +; for error checking. If new command codes are added then the first entry +; in the table must be incremented. +; +; BEWARE - These tables overlap somewhat! -c.p. +; + +; +; Disk: +; + + ODD +DSKTBL LABEL BYTE + DB 24 ; This is the size of the table YUK!!!! + DW DSK$INIT ; Code 0: INIT + DW MEDIA$CHK ; code 1: Media Check + DW GET$BPB ; code 2: BUILD BPB + DW CMDERR ; code 3: IOCTL input + DW DSK$READ ; code 4: INPUT + DW BUS$EXIT ; code 5: NONDESTRUCITVE INPUT, NO WAIT + DW EXIT ; code 6: INPUT STATUS + DW EXIT ; code 7: INPUT FLUSH + DW DSK$WRIT ; code 8: OUTPUT + DW DSK$WRITV ; code 9: OUTPUT with verify + DW EXIT ; code 10: OUTPUT STATUS + DW EXIT ; code 11: OUTPUT FLUSH + DW CMDERR ; code 12: IOCTL output +Public TABLE_PATCH +TABLE_PATCH LABEL WORD ;ARR 2.42 + DW DSK$OPEN ; code 13: DEVICE OPEN + DW DSK$CLOSE ; code 14: DEVICE CLOSE + DW DSK$REM ; code 15: REMOVABLE MEDIA + dw exit + dw exit + dw exit + DW GENERIC$IOCTL + dw exit + dw exit + dw exit + dw IOCTL$GETOWN + dw IOCTL$SETOWN + +; +; Console: +; + + ODD +CONTBL LABEL BYTE + DB 10 + DW EXIT + DW EXIT + DW EXIT + DW CMDERR + DW CON$READ + DW CON$RDND + DW EXIT + DW CON$FLSH + DW CON$WRIT + DW CON$WRIT + DW EXIT + +; +; Auxilary: +; + + ODD +AUXTBL LABEL BYTE + DB 10 + DW EXIT + DW EXIT + DW EXIT + DW CMDERR + DW AUX$READ + DW AUX$RDND + DW EXIT + DW AUX$FLSH + DW AUX$WRIT + DW AUX$WRIT + DW AUX$WRST + +; +; Clock: +; + + ODD +TIMTBL LABEL BYTE + DB 9 + DW EXIT + DW EXIT + DW EXIT + DW CMDERR + DW TIM$READ + DW BUS$EXIT + DW EXIT + DW EXIT + DW TIM$WRIT + DW TIM$WRIT + +; +; Printer: +; + + ODD +PRNTBL LABEL BYTE + DB 24 + DW EXIT ;INIT + DW EXIT + DW EXIT + DW CMDERR + DW EXIT$ZER ;INDICATE ZERO CHARS READ + DW BUS$EXIT + DW EXIT + DW EXIT + DW PRN$WRIT + DW PRN$WRIT + DW PRN$STAT + DW EXIT + DW EXIT + DW EXIT + DW EXIT + DW EXIT + DW PRN$TilBusy + DW EXIT + DW EXIT + DW PRN$GenIOCTL + dw exit + dw exit + dw exit + dw CMDERR + dw CMDERR + + + EVENB +Public Old13 +OLD13 label DWORD + db '5986' ;Code for 3.30 + + +Public Orig13 +ORIG13 label DWORD + db '21',0,0 ;Code for 3.30 + + +; +; PTRSAV - pointer save +; +; This variable holds the pointer to the Request Header passed by a +; program wishing to use a device driver. When the strategy routine is +; called it puts the address of the Request header in this variable and +; returns. +; + + EVENB +PUBLIC PTRSAV +PTRSAV DD 0 + + +; +; Buffer for the AUX device driver +; + +;;Rev 3.30 Modification + PUBLIC AUXBUF +AUXBUF DB 0,0,0,0 ;SET OF 1 BYTE BUFFERS FOR COM 1,2,3, AND 4 + + + EVENB + PUBLIC PREVOPER,NUMBER_OF_SEC +;;End of Modification +PrevOper DW ? ; Holds ROM DISK INT request (i.e. Register AX). +Number_Of_Sec DB ? ; Holds number of sectors to read on an ECC error + + +;;Rev 3.30 Modification + IF ($-CODE) GT 100H + %OUT VDISK BUFFER NOT CORRECTLY LOCATED + ELSE + ORG 100H + ENDIF + PUBLIC VDISK_AREA +VDISK_AREA DB 108 DUP(0) ;FOR USE BY VDISK +;;End of Modification + + +; +; AUXNUM holds the number of the printer or AUX device requested. For +; example if printer 2 was called (PRN2$IN) AUXNUM is set to be one; with +; line printer 3 AUXNUM is set to 2. With this set the printer device driver +; can tell which printer to command applies to. +; +; WARNING!!! These are addressed together in GETDX +; + + EVENB +AUXNUM DB 0 + DB 0 + + +; +; Device Header for the CON Device Driver +; + + EVENB +PUBLIC CONHeader +CONHeader LABEL WORD + DD AUXDEV2 + DW 1000000000010011B ; Con in and con out + special + DW STRATEGY ; Strategy entry point + DW CON$IN ; interrupt entry point + DB 'CON ' ; device name + + +; +; Device Header for device "AUX" +; + + EVENB + PUBLIC AUXDEV2 +AUXDEV2 LABEL WORD ;HEADER FOR DEVICE "AUX" + DD PRNDEV2 + DW 1000000000000000B ; attribute word, character device + DW STRATEGY ; device strategy routine + DW AUX0$IN ; device interrupt routine + DB 'AUX ' ; device name + + +; +; Device Header for device PRN +; + + EVENB + PUBLIC PRNDEV2 +PRNDEV2 LABEL WORD ;HEADER FOR DEVICE "PRN" + DD TIMDEV + DW CharDev + OutTilBusy + Dev320 + DW STRATEGY + DW PRN0$IN + DB 'PRN ' + + +; +; Device Header for device CLOCK$ +; + + EVENB + PUBLIC TIMDEV +TIMDEV LABEL WORD + DD DSKDEV + DW 1000000000001000B + DW STRATEGY + DW TIM$IN + DB 'CLOCK$ ' + + +; +; Device Header for disk devices +; +; Device attribute bits: +; Bit 6 - DOS 3.2 Bit +; + + EVENB +PUBLIC DSKDEV +DSKDEV LABEL WORD + DD COM1DEV + DW 0000100001000000B ; DOS 3.2 + DW STRATEGY ; strategy routine + DW DSK$IN ; Interrupt entry point + + +; +; maximum number of drives +; + +DRVMAX DB 4 +Public DRVMAX + + +; +; Last drive accessed +; + + PUBLIC STEP_DRV +STEP_DRV DB -2 ; ARR 2.20 LAST DRIVE ACCESSED + +Public Phys_Drv +Phys_Drv DB 0 ; Used by setdrvie for getting + ; BDS for logical drive, or physical + ; drive. 0 => use logical + ; 1 => use physical + +Public fHave96 +fHave96 DB 0 ; Flag to indicate presence of + ; 96tpi support + +Public Single +Single DB 0 ; Used to detect single drive systems + +Public fHaveK09 +fHaveK09 DB 0 ;Indicates if this is a K09 or not + ; used by console driver. +Public NEW_ROM +NEW_ROM DB 0 ;Set to 1 if we have a ROM that can + ; handle strange media layouts. + + PUBLIC FSETOWNER +fSetOwner db ? ;=1 if we are setting the owner of a + ;drive. (Examined by CheckSingle). + public Secrete_Code +Secrete_Code dw 'jk' ;Code for 3.30. + + +; +; Device Header for device "COM1" +; + + EVENB +Public COM1DEV +COM1DEV LABEL WORD + DD LPT1DEV + DW 1000000000000000B ; attribute word, character device + DW STRATEGY ; device strategy routine + DW AUX0$IN ; device interrupt routine + DB 'COM1 ' ; device name + + +; +; Device Header for device LPT1 +; + + EVENB +Public LPT1DEV +LPT1DEV LABEL WORD + DD LPT2DEV + DW CharDev + OutTilBusy + Dev320 + DW STRATEGY + DW PRN1$IN + DB 'LPT1 ' + + +; +; Device Header for device LPT2 +; + + EVENB +Public Lpt2Dev +LPT2DEV LABEL WORD + DD LPT3DEV + DW CharDev + OutTilBusy + Dev320 + DW STRATEGY + DW PRN2$IN + DB 'LPT2 ' + +; +; Device Header for device LPT3 +; + + EVENB +Public Lpt3Dev +LPT3DEV LABEL WORD + DD COM2DEV + DW CharDev + OutTilBusy + Dev320 + DW STRATEGY + DW PRN3$IN + DB 'LPT3 ' + + +; +; Device Header for device "COM2" +; + + EVENB +Public Com2Dev +COM2DEV LABEL WORD + dd COM3DEV + DW 1000000000000000B ; attribute word, character device + DW STRATEGY ; device strategy routine + DW AUX1$IN ; device interrupt routine + DB 'COM2 ' ; device name + +;;Rev 3.30 Modification +; +; Device header for device "COM3" +; + EVENB + PUBLIC COM3DEV +COM3DEV LABEL WORD + dd COM4DEV + dw 1000000000000000b ; character device attribute + dw STRATEGY + dw AUX2$IN ; com3 == aux2 + db 'COM3 ' + +; +; Device header for device "COM4" +; + EVENB + PUBLIC COM4DEV +COM4DEV LABEL WORD + dw -1,CODE + dw 1000000000000000b ; character device attribute + dw STRATEGY + dw AUX3$IN ; com4 == aux3 + db 'COM4 ' + +;;End of Modification + + +; Hard-wire the link to the next Int2f handler. +;;Rev 3.30 Modification + EVENB +PUBLIC Next2f_13 +NEXT2F_13 LABEL WORD + EXTRN INT2F_DISK:FAR ;MSBIO2 + DD INT2F_DISK + + +; +; Start of linked list of BDS's +; + + EVENB +Public Start_BDS +START_BDS LABEL WORD + DD BDS1 ;START OF BDS LINKED LIST. +;;End of Modification + + +; +; Some floppy drives do not have changeline support. The result is a +; large amount of inefficiency in the code. A media-check always returns +; "I don`t know". This cause DOS to reread the FAT on every access and +; always discard any cached data. +; We get around this inefficiency by implementing a "Logical Door Latch". +; The following three items are used to do this. The logical door latch is +; based on the premise that it is not physically possible to change floppy +; disks in a drive in under two seconds (most people take about 10). The +; logical door latch is implemented by saving the time of the last successful +; disk operation (in the value TIM_DRV). When a new request is made the +; current time is compared to the saved time. If less than two seconds have +; passed then the value "No Change" is returned. If more than two seconds +; have passed the value "Don't Know" is returned. +; There is one complecation to this algorithm. Some programs change the +; value of the timer. In this unfortunate case we have an invalid timer. +; This possiblity is detected by counting the number of disk operations +; which occur without any time passing. If this count exceeds the value of +; "AccessMax" we assume the counter is invalid and always return "Don't +; Know". The variable "AccessCount" is used to keep track of the number +; of disk operation which occur without the time changing. +; + + PUBLIC ACCESSCOUNT +AccessCount db 0 ; number of times media check called + + PUBLIC TIM_DRV +TIM_DRV DB -1 ; time when last disk I/O was performed + + PUBLIC FLAGBITS +FlagBits dw 0 ; Bits to set in flag field when doing + ; a Set_Changed_DL + + PUBLIC MEDBYT +MedByt DB ? ; hold media byte from floppy + + EVENB + PUBLIC WRTVERIFY +WRTVERIFY LABEL WORD + + PUBLIC RFLAG +RFLAG DB ROMRead ;2 for read, 3 for write +VERIFY DB 0 ;1 if verify after write + + PUBLIC SECCNT +SECCNT DW 0 + + +Public HARDNUM +HARDNUM DB 99 ;logical drive number of first hardfile + +; +; Some of the older versions of the IBM rom-bios always assumed a seek would +; have to be made to read the diskette. Consequently a large head settle +; time was always used in the I/O operations. To get around this problem +; we need to continually adjust the head settle time. The following +; algorithm is used: +; +; Get the current head settle value. +; If it is 1, then +; set slow = 15 +; else +; set slow = value +; ... +; if we are seeking and writing then +; use slow +; else +; use fast +; ... +; restore current head settle value +; + + PUBLIC MOTORSTARTUP,SETTLECURRENT,SETTLESLOW +MotorStartup db ? ; value from table +SettleCurrent db ? ; value from table +SettleSlow db ? ; slow settle value + +NextSpeed DB ? ; value of speed to be used + + public save_head_sttl +Save_head_sttl db ? ;used by READ_SECTOR routine + + +Public EOT +EOT DB 9 + +; +; pointer to Disk Parameter Table +; + + EVENB + PUBLIC DPT +DPT DD ? + +; +; The following two sets of variables are used to hold values for +; disk I/O operations +; Keep the next two items contiguous - see IOCTL_Block for reason + + PUBLIC CURSEC,CURHD,CURTRK,SPSAV +CURSEC DB 0 ; current sector +CURHD DB 0 ; current head +CURTRK DW 0 ; current track +SPSAV DW 0 ; save the stack pointer + +; +; The following are used for IOCTL function calls +; + + PUBLIC FORMT_EOT,HDNUM,TRKNUM,GAP_PATCH +FORMT_EOT DB 8 ; EOT used for format +HDNUM DB 0 ; Head number +TRKNUM DW 0 ; Track being manipulated +GAP_PATCH DB 50h ; Format gap patched into DPT + +; +; Disk errors returned from the IBM rom +; + +Public ERRIN +ERRIN LABEL BYTE + DB 80H ; no response + DB 40H ; seek failure + DB 10H ; bad CRC + DB 8 ; DMA overrun + DB 6 ; media change + DB 4 ; sector not found + DB 3 ; write attempt to write-protect disk + PUBLIC LSTERR +LSTERR DB 0 ; all other errors + +; +; returned error code corresponding to above errors +; + +Public ERROUT +ERROUT LABEL BYTE + DB 2 ; no response + DB 6 ; seek failure + DB 4 ; bad CRC + DB 4 ; DMA overrun + DB 15 ; invalid media change + DB 8 ; sector not found + DB 0 ; write attempt on write-protect disk + DB 12 ; general error + + PUBLIC NUMERR +NUMERR = ERROUT-ERRIN + + +;------------------------------------------------------------- +; +; DiskSector is a 512 byte sector into which the boot sector +; is read. It is also used as read sector for DMA check for +; hard disk. + + +Public DiskSector +DiskSector db 11 dup(?) ; take care of 3 jump bytes plus OEM name. + PUBLIC BPB_IN_SECTOR +BPB_In_Sector dw ? + PUBLIC SECPERCLUSINSECTOR +SECPERCLUSINSECTOR DB ? + dw ? + db ? + dw ? + dw ? + PUBLIC MEDIABYTE +mediabyte db ? + dw ? + dw ? + dw ? + dw ? + db ? + db 512-($-DiskSector) dup (?) + +;--------------------------------------------------------------------- +; +; The "BDS"'s contain information for each drive in the system. +; There is one BDS for each logical drvie in the system. The BDS's +; are all linked together in a chain. The BDS contain various values +; important to the disk drive. Various values are updated whenever actions +; are performed. For example if a drive is read from the last time +; accessed fields are updated to the current time. +; Initial values: +; * Sectors/Alloc. unit in BPB initially set to -1 to signify that +; the BPB has not been filled. +; * Link is set to -1 to signify end of list. +; * number of cylinders in MaxParms initialized to -1 to indicate +; that the parameters have not been set. +; +; Start_BDS contains a pointer to the first BDS. It is through this +; pointer that routines find particular BDS (see SetDrive to see how +; this is done). +; + + EVENB +BDS1 LABEL WORD + DD BDS2 ;LINK TO NEXT STRUCTURE + DB 0 ;ROM DISK INT Drive Number + DB 0 ;Logical Drive Letter + PUBLIC FDRIVE1 +FDRIVE1 DW 512 ;Physical sector size in bytes + DB -1 ;Sectors/allocation unit + DW 1 ;Reserved sectors for DOS + DB 2 ;No. allocation tables + DW 64 ;Number directory entries + DW 9*40 ;Number sectors (at 512 bytes ea.) + DB 00000000B ;Media descriptor, initially 00H. + DW 2 ;Number of FAT sectors + DW 9 ;Sector limit + DW 1 ;Head limit + DW 0 ;Hidden sector count + DB 0 ; TRUE => Large fats +OPCNT1 DW 0 ;Open Ref. Count +VOLID1 DB "NO NAME ",0 ;Volume ID for this disk + DB 3 ;Form Factor +FLAGS1 DW 0020H ;Various Flags +; DB 9 dup (0) ;Reserved for future use + dw 40 ; number of cylinders +RecBPB1 DW 512 ;Physical sector size in bytes + DB 1 ;Sectors/allocation unit + DW 1 ;Reserved sectors for DOS + DB 2 ;No. allocation tables + DW 0E0H ;NUMBER DIRECTORY ENTRIES + DW 9*40 ;Number sectors (at 512 bytes ea.) + DB 0F0h ;Media descriptor, initially 00H. + DW 2 ;Number of FAT sectors + DW 9 ;Sector limit + DW 2 ;HEAD LIMIT + DW 0 ;Hidden sector count + DB 12 DUP (?) +TRACK1 DB -1 ;Last track accessed on this drive +TIM_LO1 DW -1 ;Keep these two contiguous (?) +TIM_HI1 DW -1 + + EVENB +BDS2 LABEL WORD + DD BDS3 ;LINK TO NEXT STRUCTURE + DB 0 ;INT 13 DRIVE NUMBER + DB 0 ;Logical Drive Letter + PUBLIC FDRIVE2 +FDRIVE2 DW 512 ;Physical sector size in bytes + DB -1 ;Sectors/allocation unit + DW 1 ;Reserved sectors for DOS + DB 2 ;No. allocation tables + DW 64 ;Number directory entries + DW 9*40 ;Number sectors (at 512 bytes ea.) + DB 00000000B ;Media descriptor, initially 00H. + DW 2 ;Number of FAT sectors + DW 9 ;Sector limit + DW 1 ;Head limit + DW 0 ;Hidden sector count + DB 0 ; TRUE => Large fats +OPCNT2 DW 0 ;Open Ref. Count +VOLID2 DB "NO NAME ",0 ;Volume ID for this disk + DB 3 ;Form Factor +FLAGS2 DW 0020H ;Various Flags +; DB 9 dup (0) ;Reserved for future use + dw 40 ; number of cylinders +RecBPB2 DW 512 ;Physical sector size in bytes + DB 1 ;Sectors/allocation unit + DW 1 ;Reserved sectors for DOS + DB 2 ;No. allocation tables + DW 0E0H ;NUMBER DIRECTORY ENTRIES + DW 9*40 ;Number sectors (at 512 bytes ea.) + DB 0F0h ;Media descriptor, initially 00H. + DW 2 ;Number of FAT sectors + DW 9 ;Sector limit + DW 2 ;HEAD LIMIT + DW 0 ;Hidden sector count + DB 12 DUP (?) +TRACK2 DB -1 ;Last track accessed on this drive +TIM_LO2 DW -1 ;Keep these two contiguous (?) +TIM_HI2 DW -1 + + EVENB +BDS3 LABEL WORD + DD BDS4 ;LINK TO NEXT STRUCTURE + DB 0 ;INT 13 DRIVE NUMBER + DB 0 ;Logical Drive Letter + PUBLIC FDRIVE3 +FDRIVE3 DW 512 ;Physical sector size in bytes + DB -1 ;Sectors/allocation unit + DW 1 ;Reserved sectors for DOS + DB 2 ;No. allocation tables + DW 64 ;Number directory entries + DW 9*40 ;Number sectors (at 512 bytes ea.) + DB 00000000B ;Media descriptor, initially 00H. + DW 2 ;Number of FAT sectors + DW 9 ;Sector limit + DW 1 ;Head limit + DW 0 ;Hidden sector count + DB 0 ; TRUE => Large fats +OPCNT3 DW 0 ;Open Ref. Count +VOLID3 DB "NO NAME ",0 ;Volume ID for this disk + DB 3 ;Form Factor +FLAGS3 DW 0020H ;Various Flags +; DB 9 dup (0) ;Reserved for future use + dw 40 ; number of cylinders +RecBPB3 DW 512 ;Physical sector size in bytes + DB 1 ;Sectors/allocation unit + DW 1 ;Reserved sectors for DOS + DB 2 ;No. allocation tables + DW 0E0H ;NUMBER DIRECTORY ENTRIES + DW 9*40 ;Number sectors (at 512 bytes ea.) + DB 0F0h ;Media descriptor, initially 00H. + DW 2 ;Number of FAT sectors + DW 9 ;Sector limit + DW 2 ;HEAD LIMIT + DW 0 ;Hidden sector count + DB 12 DUP (?) +TRACK3 DB -1 ;Last track accessed on this drive +TIM_LO3 DW -1 ;Keep these two contiguous (?) +TIM_HI3 DW -1 + + EVENB +BDS4 LABEL WORD + DW -1 ;Link to next structure + DW Code + DB 0 ;INT 13 DRIVE NUMBER + DB 0 ;Logical Drive Letter + PUBLIC FDRIVE4 +FDRIVE4 DW 512 ;Physical sector size in bytes + DB -1 ;Sectors/allocation unit + DW 1 ;Reserved sectors for DOS + DB 2 ;No. allocation tables + DW 64 ;Number directory entries + DW 9*40 ;Number sectors (at 512 bytes ea.) + DB 00000000B ;Media descriptor, initially 00H. + DW 2 ;Number of FAT sectors + DW 9 ;Sector limit + DW 1 ;Head limit + DW 0 ;Hidden sector count + DB 0 ; TRUE => Large fats +OPCNT4 DW 0 ;Open Ref. Count +VOLID4 DB "NO NAME ",0 ;Volume ID for this disk + DB 3 ;Form Factor +FLAGS4 DW 0020H ;Various Flags +; DB 9 dup (0) ;Reserved for future use + dw 40 ; number of cylinders +;;Rev 3.30 Modification +RECBPB4 DW 512 ;BYTES PER SECTOR + DB 1 ;SECTORS/ALLOCATION UNIT + DW 1 ;RESERVED SECTORS FOR DOS + DB 2 ;NO. ALLOCATION TABLES + DW 0E0H ;NUMBER DIRECTORY ENTRIES + DW 9*40 ;NUMBER SECTORS (AT 512 BYTES EA.) + DB 0F0H ;MEDIA DESCRIPTOR, INITIALLY F0H. + DW 2 ;NUMBER OF FAT SECTORS + DW 9 ;SECTOR LIMIT + DW 2 ;HEAD LIMIT + DW 0 ;HIDDEN SECTOR COUNT + DB 12 DUP (?) +;;End of Modification +TRACK4 DB -1 ;Last track accessed on this drive +TIM_LO4 DW -1 ;Keep these two contiguous (?) +TIM_HI4 DW -1 + + +bpbType struc +spf db ? +spt db ? +cdire db ? +csec dw ? +spa db ? +chead db ? +bpbType ends + PUBLIC SM92 +sm92 bpbType <3,9,70H,2*9*80,2,2> + + +; +; ALTAH is a single character buffer used to handle special keys. +; + + PUBLIC ALTAH +ALTAH DB 0 ;Special key handling + + +; +; The following variable can be modified via IOCTL sub-function 16. In this +; way, the wait can be set to suit the speed of the particular printer being +; used. One for each printer device. +; + + PUBLIC PRINTDEV +PRINTDEV DB 0 ; Index into following array + + EVENB + PUBLIC WAIT_COUNT +WAIT_COUNT DW 4 dup (50h) ; Array of Retry counts for printer + + +; +; DAYCNT is the number of days since 1-1-80. +; Each time the clock is read it is necessary to check if another day has +; passed. The ROM only returns the day rollover once so if it is missed +; the time will be off by a day. +; + + EVENB +Public DAYCNT +DAYCNT DW 0 + + +; +; The following variables and two routines (MSGOUT and MSGNUM) are used +; with the debug routines to print numbers and messages on the screen. +; +; The variable fTestBits controls the level of debugging in the system. +; See the comments and "equ's" in msmacro.inc for an explination of +; how to control the level of debugging. In a nutshell, setting +; fTestBits to fTestALL prints all the debugging messages. Setting +; it to fTestDisk prints all disk related messages, etc. +; + +if test +Public NumBuf +NumBuf DB 5 dup (?) +Public Digits +Digits DB "0123456789ABCDEF" +Public fTestBits +FTESTBITS DW fTestDISK +endif + + + PATHEND 001,BIO diff --git a/SRC/BIOS/MSDISK.ASM b/SRC/BIOS/MSDISK.ASM new file mode 100644 index 0000000..a3d21c8 --- /dev/null +++ b/SRC/BIOS/MSDISK.ASM @@ -0,0 +1,2408 @@ + TITLE MSDISK - DOS 3.3 +;------------------------------------------------------------------------ +; : +; DISK INTERFACE ROUTINES : +; : +; : +; This file contains the Disk Device Driver. : +; : +; The routines in this files are: : +; : +; routine function : +; ------- -------- : +; : +; MEDIA$CHK Determine if media in drive has changed : +; : +; GET$BPB Build a valid BPB for drive : +; : +; DSK$REM Determine if disk has removable media : +; : +; DSK$WRTV Disk write with verify : +; : +; DSK$WRT Disk write : +; : +; DSK$READ Read disk : +; : +; : +; These routines are not called directly. Call are made via : +; the strategy and interrupt entry point (see Device Header). : +; : +; Data structures: : +; There are two main types of data structures associated with : +; the disk drives. The first is the BDS. BDS is the Bios Data : +; structure. There is one BDS for each logical drive in the system. : +; All the BDS's are linked together in a list with the pointer to the : +; first BDS being found in Start_BDS. The BDS hold various values : +; important to the disk drive. For example there is a field for last : +; time accesses. As actions take place in the system the BDS are : +; update to reflect the actions. For example if there is a read to : +; a disk the last access field for the BDS for that drive is updated : +; to the current time. : +; The second data structure associated with disk drives is the : +; BPB. A BPB is a Bios Parameter Block. The BPB contains information : +; about the media inside a disk drive. Some on the fields in the BPB : +; are Sectors per track, number of FATs, and number of tracks. This : +; information is used to tell where sectors are on the disk. For : +; example, if we need to read logical sector 52: : +; : +; Diskette Track Sector Side : +; single density : +; eight sectors per track 6 5 0 : +; : +; double density : +; nine sectors per track 2 7 1 : +; : +; The BPB for the media in the drive is stored in the BDS for the : +; drive. If the user changes the floppy in the drive a call is : +; made to GET$BPB to build a new BPB in the BDS. See this routine : +; for the algorithm. : +; : +; : +;------------------------------------------------------------------------ +;;Rev 3.30 Modification +;for testing, set test to 1. So as MSBIO1.ASM. + test=0 + EXTRN NUMERR:ABS ;MSDATA + + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + INCLUDE MSEQU.INC + INCLUDE PUSHPOP.INC + INCLUDE MSMACRO.INC + INCLUDE DEVSYM.INC + INCLUDE DSKPRM.INC + + EXTRN INT2F_DISK:FAR ;MSBIO2 + EXTRN MEDIACHECK:NEAR ;96TPI + EXTRN HASCHANGE:NEAR ;96TPI + EXTRN MEDIA_SET_VID:NEAR ;96TPI + EXTRN HIDENSITY:NEAR ;96TPI + EXTRN CHECKLATCHIO:NEAR ;96TPI + EXTRN CHECKIO:NEAR ;96TPI + EXTRN SET_CHANGED_DL:NEAR ;96TPI + EXTRN SET_VOLUME_ID:NEAR ;MSVOLID + EXTRN SWPDSK:NEAR ;MSBIO2 + EXTRN CMDERR:NEAR ;MSBIO1 + EXTRN STRATEGY:NEAR ;MSBIO1 + EXTRN ERR$CNT:NEAR ;MSBIO1 + EXTRN DSK$IN:NEAR ;MSBIO1 + EXTRN EXIT:NEAR ;MSBIO1 + EXTRN BUS$EXIT:NEAR ;MSBIO1 + EXTRN ERR$EXIT:NEAR ;MSBIO1 + +;DATA + EXTRN OLD13:DWORD ;MSBIO2 + EXTRN PTRSAV:DWORD ;MSBIO1 + EXTRN COM1DEV:WORD ;MSAUX + EXTRN DAYCNT:WORD ;MSCLOCK + EXTRN TIM_DRV:BYTE ;MSDATA + EXTRN ACCESSCOUNT:BYTE ;MSDATA + EXTRN SM92:BYTE ;MSDATA + EXTRN DISKSECTOR:BYTE ;MSDATA + EXTRN MEDIABYTE:BYTE ;MSDATA + EXTRN SECPERCLUSINSECTOR:BYTE ;MSDATA + EXTRN BPB_IN_SECTOR:WORD ;MSDATA + EXTRN DISKSECTOR:BYTE ;MSDATA + EXTRN STEP_DRV:BYTE ;MSDATA + EXTRN START_BDS:WORD ;MSDATA + EXTRN PHYS_DRV:BYTE ;MSDATA + EXTRN WRTVERIFY:WORD ;MSDATA + EXTRN FSETOWNER:BYTE ;MSDATA + EXTRN SINGLE:BYTE ;MSDATA + EXTRN RFLAG:BYTE ;MSDATA + EXTRN MEDBYT:BYTE ;MSDATA + EXTRN SPSAV:WORD ;MSDATA + EXTRN SECCNT:WORD ;MSDATA + EXTRN DPT:DWORD ;MSDATA + EXTRN CURSEC:BYTE,CURHD:BYTE ;MSDATA + EXTRN CURTRK:WORD ;MSDATA + EXTRN EOT:BYTE ;MSDATA + EXTRN MOTORSTARTUP:BYTE,SETTLECURRENT:BYTE,SETTLESLOW:BYTE ;MSDATA + EXTRN CURHD:BYTE ;MSDATA + EXTRN LSTERR:BYTE ;MSDATA + EXTRN ERRIN:BYTE,ERROUT:BYTE ;MSDATA + EXTRN PREVOPER:WORD ;MSDATA + EXTRN ORIG13:DWORD ;MSDATA + EXTRN FLAGBITS:WORD ;MSDATA + EXTRN NUMBER_OF_SEC:BYTE ;MSDATA + EXTRN FHAVE96:BYTE ;MSDATA + EXTRN NEW_ROM:BYTE ;MSDATA + EXTRN FORMT_EOT:BYTE,HDNUM:BYTE,TRKNUM:WORD,GAP_PATCH:BYTE ;MSDATA + EXTRN NEXT2F_13:WORD ;MSDATA + extrn Save_head_sttl:byte ;MSdata + extrn Secrete_Code:word ;MSdata +;;Rev 3.30 Modification + + +; +; Maximum number of retries in case of error +; + +MAXERR = 5 +LSTDRV = 504H + + +; +; Some floppy drives do not have changeline support. The result is a +; large amount of inefficiency in the code. A media-check always returns +; "I don`t know". This cause DOS to reread the FAT on every access and +; always discard any cached data. +; We get around this inefficiency by implementing a "Logical Door Latch". +; The following three items are used to do this. The logical door latch is +; based on the premise that it is not physically possible to change floppy +; disks in a drive in under two seconds (most people take about 10). The +; logical door latch is implemented by saving the time of the last successful +; disk operation (in the value TIM_DRV). When a new request is made the +; current time is compared to the saved time. If less than two seconds have +; passed then the value "No Change" is returned. If more than two seconds +; have passed the value "Don't Know" is returned. +; There is one complecation to this algorithm. Some programs change the +; value of the timer. In this unfortunate case we have an invalid timer. +; This possiblity is detected by counting the number of disk operations +; which occur without any time passing. If this count exceeds the value of +; "AccessMax" we assume the counter is invalid and always return "Don't +; Know". The variable "AccessCount" is used to keep track of the number +; of disk operation which occur without the time changing. +; + +AccessMax = 5 + + +; +; Some of the older versions of the IBM rom-bios always assumed a seek would +; have to be made to read the diskette. Consequently a large head settle +; time was always used in the I/O operations. To get around this problem +; we need to continually adjust the head settle time. The following +; algorithm is used: +; +; Get the current head settle value. +; If it is 1, then +; set slow = 15 +; else +; set slow = value +; ... +; if we are seeking and writing then +; use slow +; else +; use fast +; ... +; restore current head settle value +; +; +; flags for size of FAT +; +fTOOBIG EQU 80h +fBIG EQU 40h + +error_unknown_media equ 7 ; for use in BUILD BPB call + +BPB_TYPE STRUC +SECSIZE DW ? +SECALL DB ? +RESNUM DW ? +FATNUM DB ? +DIRNUM DW ? +SECNUM DW ? +FATID DB ? +FATSIZE DW ? +SLIM DW ? +HLIM DW ? +HIDDEN DW ? +BPB_TYPE ENDS +;------------------------------------------------------------------------ +; : +; The next 100 or so lines of code do the Media Check. Media Check : +; determines if the diskette (media) in the drive has been changed. : +; : +; SI is used to hold media check code: : +; -1 media changed : +; 0 Don't know : +; 1 media has not been changed : +; : +; The algorithm used is a follows: : +; if (hard disk) : +; if (changed by format) : +; return (not changed) : +; if not (changed by format) : +; return (changed) : +; else we have a floppy : +; if floppy has change line support go ask the floppy : +; if floppy does not have change line do the following : +; read the time : +; if more than two second have passed return don't know : +; if no time has passed then might be unreliable : +; counter (some program fool with the counter when : +; they should not). See note below for procedure with : +; unreliable counter : +; if sometime has passed but not two second return : +; media has not changed. This is based on the : +; assumption that it is not physically possilbe to : +; change a disk in less the two seconds (most people : +; take about 10 seconds). : +; : +;------------------------------------------------------------------------ + + public media$chk +MEDIA$CHK PROC NEAR + Message ftestdisk,<"Disk Media Check "> + MNUM ftestdisk,AX + Message ftestdisk, + Call SetDrive ; point DS:DI to BDS for specified drive + + cmp cs:Secrete_Code, 'jk' ; Secrete code for + jne media$done ; DOS 3.3 MSBIO. +; +; For non-removable disks only return changed if changed by format, +; otherwise return 'not changed'. +; + + mov si,1 ; assume no change + test word ptr [di].flags,fChanged_By_Format + jz WeAreNotFakingIt + ; reset flag + and word ptr [di].flags,NOT fChanged_By_Format + +; +; If media has been changed by format, must use the ROM. +; Cannot rely on the 2 second time check. +; + mov cs:[TIM_DRV],-1 ; Ensure that we ask the ROM if media + ; has changed + test word ptr [di].flags,fNon_Removable + jz WeHaveAFloppy + mov SI,-1 ; Indicate media changed + jmp short Media$Done +; +; return 'not changed' if disk is a hard file. +; + +WeAreNotFakingIt: + test word ptr [di].flags,fNon_Removable + jnz Media$Done + +; +; If this code is reached disk is a diskette drive +; + +WeHaveAFloppy: + + xor si,si ; Presume "I don't know" + +; +; If drive is a floppy with changeline support the rom is called to +; determine if the media has changed. It is not necessary to do the 2 +; second check on these drives. +; +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in MSINIT ;| + Public Media_Patch ;| +Media_Patch: ;| + CALL MediaCheck ;| + jc Err$Exitj ;| + call HasChange ;| + jnz Media$Done ;| +;----------------------------------------| +; +; If this code is reached the drive is a floppy with no changeline support +; + MOV SI,1 ; PRESUME NO CHANGE + mov al,cs:[TIM_DRV] ; last drive accessed + ;is drive of last access the same? + CMP AL,byte ptr [di].DriveNum + JNZ Media$Unk ; no, then return don't know +; +; CHECK TO SEE IF THIS DRIVE HAS BEEN ACCESSED IN THE LAST 2 SECONDS. +; + call Check_Time_of_Access + jmp short Media$Done + + +Media$Unk: + DEC SI ; RETURN "I DON'T KNOW" + +; +; SI now contains the correct value for media change. Clean up the left overs +; +Media$Done: + les bx,cs:[ptrsav] ; get original packet + mov WORD PTR es:[BX].Trans,SI + or SI,SI + js Init_Patch + jmp EXIT + +MEDIA$CHK ENDP + +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| + Public Init_Patch ;| +INIT_PATCH PROC NEAR ;| + CALL Media_Set_VID ;| +;----------------------------------------| + mov cs:[Tim_Drv],-1 ; make sure we ask ROM for media check +VOLIDOK: + jmp EXIT +INIT_PATCH ENDP + + + +ERR$EXITJ PROC NEAR + + MESSAGE FTESTCOM,<"ERR$EXITJ: "> + MNUM FTESTCOM,AX + MESSAGE FTESTCOM,<" == "> + CALL MAPERROR + MNUM FTESTCOM,AX + MESSAGE FTESTCOM, + JMP ERR$EXIT +ERR$EXITJ ENDP + +; +; PERFORM A CHECK ON THE TIME PASSED SINCE THE LAST ACCESS FOR THIS +; PHYSICAL DRIVE. +; WE ARE ACCESSING THE SAME DRIVE. IF THE TIME OF LAST SUCCESSFUL ACCESS +; WAS LESS THAN 2 SECONDS AGO, THEN WE MAY PRESUME THAT THE DISK WAS NOT +; CHANGED +; RETURNS IN SI: +; 0 - IF TIME OF LAST ACCESS WAS >= 2 SECONDS +; 1 - IF TIME WAS < 2 SECONDS (I.E NO MEDIA CHANGE ASSUMED) +; REGISTERS AFFECTED AX,CX,DX, FLAGS. +; +CHECK_TIME_OF_ACCESS PROC NEAR + PUBLIC CHECK_TIME_OF_ACCESS + mov si,1 ; Presume no change +;;Rev 3.30 Modification + xor AH, AH ; set command to read time + int 1Ah ; call rom-bios clock routine + +; +; Once time is read, must make sure the date wrap is not lost. The ROM will +; return the value only once, it must check for day wrap on each call. +; + SHR AL,1 + ADC CS:[DAYCNT],0 ; ADD IT TO OUR SAVED DAY COUNT +; +; Compute elapsed time +; + MOV AX,WORD PTR DS:[DI].TIM_LO ; GET STORED TIME + SUB DX,AX + MOV AX,WORD PTR DS:[DI].TIM_HI + SBB CX,AX +;;End of Modification +; +; CX:DX is the elapsed time +; + JNZ TimeCheck_Unk ; CX <> 0 => > 1 hour + OR DX,DX ; did some time pass? + JNZ TimePassed ; yes, examine max value +; +; No noticeable time has passed. There are two possiblities. First there +; could be two driver calls with in one clock tick (55 milliseconds). The +; second possiblity is the program has reprogramed the counter -- this is +; the unreliable counter case. To distinguish between the case a count is +; kept of the number of calls that happen without a clock tick (the variable +; is AccessCount). If this count exceeds a set limit (MaxAccess) it is +; assumed the counter is unreliable and the value don't know is returned. +; If AccessCount is less than MaxAccess we assume the time is valid and +; therefor the media has not changed. +; + inc byte ptr cs:AccessCount + ; Exceeded threshold for count? + cmp byte ptr cs:AccessCount,AccessMax + jb TimeCheck_Ret ; no, return media unchanged + dec byte ptr cs:AccessCount ; don't let the count wrap + jmp short TimeCheck_Unk ; "I don't know" if media changed + + +; +; If this code is reached some time has passed. Need to determine if +; 2 seconds have passed. Note: 18.2 ticks per second. +; +TimePassed: + CMP DX,18 * 2 ; IF ( Time_passed <= 2secs ) + JBE TimeCheck_Ret ; presume no change + + +; Everything indicates that we do not know what has happened. +; +TimeCheck_Unk: + DEC SI ; Presume I don't know +TimeCheck_Ret: + RET + +CHECK_TIME_OF_ACCESS ENDP + +ERR$EXITJ2: JMP ERR$EXITJ + + +;------------------------------------------------------------------------ +; : +; Get Bios Parameter Block : +; : +; GET$BPB is called to build a valid BPB for the media in the disk : +; drive. A BPB (Bios Parameter Block) contains information about : +; the media which is currently in the drive. The values stored is : +; information like number of fat sectors, size of drive, 8 or 9 sectors,: +; etc. : +; : +; This routine is called by the device drive code. : +; : +; On entry AL contains the logical drive number which needs : +; the BPB built. : +; ES:[di] points to a buffer; the first byte of the buffer is a : +; media decriptor byte. : +; : +;------------------------------------------------------------------------ +; +; Build a valid BPB for the disk in the drive. +; + + public GET$BPB +GET$BPB PROC NEAR + Message fTestDisk,<"Disk Build BPB "> ; print debug messages + MNUM fTestDisk,AX + Message fTestDisk, + mov AH,byte ptr ES:[DI] ; get FAT IB byte read by DOS + call SetDrive ; get the correct BDS for the drv +;;Rev 3.30 Modification + TEST WORD PTR [DI].FLAGS,FNON_REMOVABLE + JNZ ALREADY_GOTBPB ; NO NEED TO BUILD FOR FIXED DISKS +;;End of Modification + call GETBP ; build a BPB if necessary. + jc Err$exitj2 ; if error exit +GET$BPB ENDP +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| + Public SET_PATCH ;| +SET_PATCH PROC NEAR ;| + CALL set_volume_id ;| +;----------------------------------------| + ; print debug messages + message ftestdisk,<"Set Volume ID"> + mnum ftestdisk,di + message ftestdisk,<" "> + mnum ftestdisk,ds + message ftestdisk, +ALREADY_GOTBPB: + add di,BytePerSec ; return the BPB that is in the current BDS + + PUBLIC SetPTRSAV +SetPTRSAV: ; return point for DSK$INIT + les BX,cs:[PTRSAV] + mov ES:[BX].MEDIA,AH + mov ES:[BX].COUNT,DI + mov ES:[BX].COUNT+2,DS + jmp EXIT +SET_PATCH ENDP + + + + +; +; +; GETBP fills the BDS with the BPB for the media currently in the drive. +; The following steps are followed: +; If the Return_Fake_BPB flag is set then the GETBP just returns. +; If the BDS is for a hard disk (non-removable) then GETBP returns since +; the BPB cannot change on a hard disk drive. +; For all other cases GETBP reads the boot sector and looks for a BPB +; in the boot sector. (All DOS 2.X and about disks should have a valid +; BPB in the boot sector.) +; If no valid BPB is found (DOS 1.X disk) then GETBP reads the FAT +; sector and gets the FAT ID byte. With this byte a valid BPB is build. +; +; Inputs: +; DS:DI points to correct BDS +; +; Outputs: +; Fills in BPB in current BDS if valid BPB or FAT ID on disk. +; Carry set, and AL=7 if invalid disk. +; Carry set and error code in AL if other error. +; + + Public GETBP +GETBP PROC NEAR + ; if non-removable or returning + ; fake BPB then return BPB as is. + TEST WORD PTR [DI].FLAGS,RETURN_FAKE_BPB OR FNON_REMOVABLE + jz GETBP1 + JMP GETRET_EXIT + + +GETBP1: + message ftestdisk,<"Building BPB from scratch",CR,LF> + SaveReg +; +; Attempt to read in boot sector and determine BPB. +; We assume that the 2.x and greater DOS disks all have a valid boot sector. +; +Rdboot: + call ReadBootSec + jnc NoRdErr + jmp GetBP_Err_Ret ; Carry set if there was error. +NoRdErr: + cmp bx,0 ; BX is 0 if boot sector is valid. + jnz DoFatBPB ; if not go read FAT + + call MovBPB ; Move BPB into registers. + jmp Has1 + +; +; At this point the drive contains a 1.X diskette. We read the FAT byte +; and fill in the BPB from there. +; + +DoFatBPB: + call ReadFat ; puts media descriptor byte in AH + jc GetBP_Err_Ret ; if carry set, there was error, get out + +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| +Public GETBP1_PATCH ;| +GETBP1_PATCH: ;| + call hidensity ;| +;----------------------------------------| +; Test for a valid 3.5" medium + cmp [di].FormFactor, ffsmall + jnz Is_Floppy + cmp ah,0F9H ; is it a valid fat ID byte for 3.5" ? + jnz Got_Unknown_Medium + mov bx,offset sm92 ; pointer to correct BPB + push cs + pop es +ASSUME ES:CODE + mov al,[bx.spf] + mov cx,[bx.csec] + mov dx,word ptr [bx.spa] + mov bx,word ptr [bx.spt] + jmp short HAS1_res ; Need to load reserved sectors +; +; must be a 5.25" floppy if we come here +; +Is_Floppy: + mov CL,AH ; save media + and CL,0F8H ; normalize + cmp CL,0F8H ; cmopare with good media byte + jnz Got_Unknown_Medium + +GOODID: mov AL,1 ; set number of FAT sectors + mov BX,64*256+8 ; set dir entries and sector max + mov CX,40*8 ; set size of drive + mov DX,01*256+1 ; set head limit and sec/all unit + test AH,00000010B ; test for 8 or 9 sectors + jnz HAS8 ; NZ = has 8 sectors + inc AL ; inc number of FAT sectors + inc BL ; inc sector max + add CX,40 ; increase size +HAS8: test AH,00000001B ; test for 1 or 2 heads + jz HAS1_res ; Z = 1 head + add CX,CX ; double size of disk + mov BH,112 ; increase number of directory entries + inc DH ; inc sec/all unit + inc DL ; inc head limit + +PUBLIC HAS1_res +HAS1_res: + mov si,word ptr ds:[di].RESSEC +PUBLIC HAS1 ; save values in BDS +HAS1: mov byte ptr ds:[DI].SecPerClus,DH + mov byte ptr ds:[DI].cDir,BH + mov word ptr ds:[DI].Drvlim,CX + mov byte ptr ds:[DI].Mediad,AH + mov byte ptr ds:[DI].csecFat,AL + mov byte ptr ds:[DI].SecLim,BL + mov byte ptr ds:[DI].HdLim,DL + mov word ptr ds:[DI].RESSEC,SI +GETRET: pop BX + RestoreReg +ASSUME ES:NOTHING +GETRET_Exit: + RET + +GetBP_Err_Ret: + CALL MapError + JMP SHORT GETRET + +; +; We have a 3.5" diskette for which we cannot build a BPB. We do not assume any +; type of BPB for this medium. +; +Got_Unknown_Medium: + mov al,error_unknown_media + stc + jmp short GETRET + +GETBP ENDP + +bpbType struc +spf db ? +spt db ? +cdire db ? +csec dw ? +spa db ? +chead db ? +bpbType ends + +; +; end of GET$BPB code +;------------------------------------------------- + +; +; Read in the boot sector. Set carry if error in reading sector. +; BX is set to 1 if the boot sector is invalid, otherwise it is 0. +; +READBOOTSEC PROC NEAR + mov CX, 0001h ; set track and sector number + xor DH, DH ; set head number for read_sector + call read_sector + jc Err_Ret ; error - get out + xor bx,bx ; assume valid boot sector. + + ; at this point the boot sector has been + ; read in from the disk. We now need to + ; determine if the boot sector contains + ; a valid BPB. Currently there are only + ; a few simple checks. Expanding the + ; number or types of checks would not be + ; a bad idea. +;******************************************************************************* +; Put a sanity check for the boot sector in here to detect boot sectors that +; do not have valid BPBs. +; We examine the first two bytes - they must contain a long jump or a short +; jump followed by a NOP. +; If this test is passed, we further check by examining the signature at +; the end of the boot sector for the word AA55H. +; If the signature is not present, we examine the media descriptor byte to +; see if it is valid. +;****************************************************************************** + cmp byte ptr cs:[DiskSector],069H ; Is it a direct jump? + JE Check_bpb_MediaByte ; DON'T NEED TO FIND A NOP + cmp byte ptr cs:[DiskSector],0E9H ; DOS 2.0 jump? + JE Check_bpb_MediaByte ; NO NEED FOR NOP + cmp byte ptr cs:[DiskSector],0EBH ; How about a short jump. + JNE INVALIDBOOTSEC + cmp byte ptr cs:[DiskSector]+2,090H ; Is next one a NOP? + JNE INVALIDBOOTSEC + + +; Don't have to perform the following signature check since +; we need to check the media byte even with the good signatured diskette. +;CHECK_SIGNATURE: +; CMP WORD PTR CS:[DISKSECTOR+1FEH],0AA55H ; SEE IF NON-IBM +; ; DISK OR 1.X MEDIA. +; JZ CHECKSINGLESIDED ; GO SEE IF SINGLE SIDED MEDIUM. +; ; MAY NEED SOME SPECIAL HANDLING +; +; CHECK FOR NON-IBM DISKS WHICH DO NOT HAVE THE SIGNATURE AA55 AT THE +; END OF THE BOOT SECTOR, BUT STILL HAVE A VALID BOOT SECTOR. THIS IS DONE +; BY EXAMINING THE MEDIA DESCRIPTOR IN THE BOOT SECTOR. +; + +;;Rev 3.30 Modification +Check_bpb_MediaByte: + + MOV AL,BYTE PTR CS:MEDIABYTE + AND AL,0F0H + CMP AL,0F0H ; ALLOW FOR STRANGE MEDIA + JNZ INVALIDBOOTSEC +; +; THERE WERE SOME (APPARENTLY A BUNCH) DISKETTES THAT HAD BEEN FORMATTED +; UNDER DOS 3.1 AND EARLIER VERSIONS WHICH HAVE INVALID BPBS IN THEIR BOOT +; SECTORS. THESE ARE SPECIFICALLY DISKETTES THAT WERE FORMATTED IN DRIVES +; WITH ONE HEAD, OR WHOSE SIDE 0 WAS BAD. THESE CONTAIN BPBS IN THE BOOT +; SECT THAT HAVE THE SEC/CLUS FIELD SET TO 2 INSTEAD OF 1, AS IS STANDARD +; IN DOS. TO SUPPORT THEM, WE HAVE TO INTRODUCE A "HACK" THAT WILL +; HELP OUR BUILD BPB ROUTINE TO RECOGNISE THESE SPECIFIC CASES, AND TO +; SET UP OUT COPY OF THE BPB ACCORDINGLY. +; WE DO THIS BY CHECKING TO SEE IF THE BOOT SECTOR IS OFF A DISKETTE THAT +; IS SINGLE-SIDED AND IS A PRE-DOS 3.20 DISKETTE. IF IT IS, WE SET THE +; SEC/CLUS FIELD TO 1. IF NOT, WE CARRY ON AS NORMAL. +CHECKSINGLESIDED: + MOV AL,BYTE PTR CS:MEDIABYTE + TEST AL,0001H ; IS LOW BIT SET? - INDICATES DOUBLE SIDED + JNZ GOODDSK + CMP WORD PTR CS:[DISKSECTOR+8],"." SHL 8 + "3" + JNZ MUSTBEEARLIER + CMP BYTE PTR CS:[DISKSECTOR+10],"2" + JAE GOODDSK + +; WE MUST HAVE A PRE-3.20 DISKETTE. SET THE SEC/CLUS FIELD TO 1 +MUSTBEEARLIER: + MOV BYTE PTR CS:[SECPERCLUSINSECTOR],1 + JMP SHORT GOODDSK + +INVALIDBOOTSEC: + INC BX ; SET THAT BOOT SECTOR INVALID +;;End of Modification + +GoodDsk: ; carry already reset + clc + ret + +Err_Ret: ; carry is already set on entry here + message ftestdisk,<"error in readboot",cr,lf> + ret + +READBOOTSEC ENDP + +; +; MovBPB moves the BPB read from the Boot sector into registers for use by +; GETBP routine at Has1 +; +MOVBPB PROC NEAR + SaveReg + push cs + pop ds + mov di,offset BPB_In_Sector + mov dh,Byte Ptr [di].secall ;sectors per unit + mov bh,Byte Ptr [di].dirnum ;number of directory entries + mov cx,Word Ptr [di].secnum ;size of drive + mov ah,Byte Ptr [di].fatid ;media descriptor + mov al,Byte Ptr [di].fatsize ;number of FAT sectors + mov bl,Byte Ptr [di].slim ;sectors per track + mov dl,Byte Ptr [di].hlim ;number of heads + mov si,word ptr [di].resnum ;reserved sectors + RestoreReg + ret +MOVBPB ENDP + + + +; +; Read in the FAT sector and get the Media Byte from it. +; Input : AL contains logical drive. +; Output: +; Carry set if an error occurs, AX contains error code. +; Otherwise, AH contains media byte on exit. AL is preserved. + +READFAT PROC NEAR + push ax ; preserve logical drive in AL + MOV DH,0 ; HEAD 0 + mov CX,0002 ; set track and sector number + call read_sector ; CS:BX points to fat sector + jc Bad_FAT_Ret ; error, get out + pop ax ; reset logical drive + mov ah,Byte Ptr CS:[BX] ; media byte + ret + +Bad_FAT_Ret: ; carry set on entry + message ftestdisk,<"error in FAT read",cr,lf> + pop cx ; clear stack + ret +READFAT ENDP + + + +; +; Read_sector reads a single sector into the tempory buffer 'DiskSector'. +; Up to three retries are done in case of error. +; +; Inputs: +; DS:DI points to BDS for drive +; CH - track number +; CL - sector number +; DH - head number +; +; Outputs: +; If carry is clear -- successful read +; CS:BX points to buffer holding sector +; AX, BX are not preserved, CX, DX, BP, and ES are preserved +; +; If carry is set -- error on read +; AX, BX, and DX are not preserved; CX, BP, and ES are preserved +; +; + +READ_SECTOR PROC NEAR + PUBLIC READ_SECTOR + push BP ; preserve BP register + mov BP,3 ; BP is retry count, set to 3 + push ES ; preserve ES also + mov DL, byte ptr [di].DriveNum + mov BX, offset DiskSector ; Get ES:BX to point to buffer + push CS ; get the segment right + pop ES ; now ES:BX is correct + +RD_RET: + ; set command to read (AH=2) and + mov AX, 0201h ; number of sectors to 1 (AL=1) + int 13h ; call rom-bios disk routines + + jnc OKRET2 ; if no carry then no error - done +Rd_rty: + call Again ; reset disk and decrement BP + jz Err_RD_RET + test word ptr ds:[di].flags,fNon_Removable + JNZ RD_RET +;;Rev 3.30 Modification ----------------------------------------- + push ds ; For retry, set head settle + push ax ; time to 0Fh. + lds si,cs:DPT + mov al, ds:[si].disk_head_sttl + mov cs:[save_head_sttl],al + mov byte ptr ds:[si].disk_head_sttl, NormSettle + pop ax + pop ds + ; SET CMD TO READ (AH=2) AND + MOV AX, 0201h ; NUM OF SECTORS TO 1 (AL=1) + INT 13h ; CALL ROM-BIOS DISK ROUTINES + push ds + push ax + lds si,cs:DPT + mov al, cs:[save_head_sttl] + mov byte ptr ds:[si].disk_head_sttl, al + pop ax + pop ds + jnc OKRET2 + jmp Rd_rty +ERR_RD_RET: + MOV DL,-1 ; MAKE SURE WE ASK ROM IF MEDIA CHANGED + STC ; RETURN ERROR +;;End of Modification ----------------------------------------- + + ; Update information pertaining to last drive + ; accessed, time of access, last track accessed + ; in that drive. +OKRET2: + ; set up for head settle logic in DISK + mov CS:[STEP_DRV],DL ; save last drive accessed + mov CS:[TIM_DRV],DL ; save the values + mov byte ptr [di].track,CH ; + pushf ; save the flags + call SET_TIM + popf ; restore flags + pop ES ; restore registers + pop BP + ret + +READ_SECTOR ENDP + + + +;------------------------------------------------------------------------ +; : +; Disk Removable Routine : +; : +; This routine determines if a particular logical drive has : +; removable media. : +; : +; Input : +; AL contains the logical drive number which the check is being : +; done. : +;------------------------------------------------------------------------ + +DSK$REM PROC NEAR ;ARR 2.41 + PUBLIC DSK$REM + Message fTestDisk,<"Disk Removable "> ; print debug messages + MNUM fTestDisk,AX + Message fTestDisk, + ; AL is logical unit number + call SetDrive ; get BDS for this drive + test word ptr [di].flags,fNon_Removable + jnz NON_REM + jmp EXIT + +NON_REM: ; if non removable set busy bit + jmp BUS$EXIT + +DSK$REM ENDP + + + +; +; SetDrive scans through the data structure of BDSs and returns a +; pointer to the BDS that belongs to the drive specified in AL. +; Carry is set if no BDS has a logical drive number which matches the +; value in AL. +; Input: +; AL contains the logical drive number +; Output: +; DS:DI points to correct BDS if Carry is clear. +; +; All register execpt DS and DI are preserved +; + + Public SetDrive +SETDRIVE PROC NEAR + message ftestdisk,<"SetDrive",cr,lf> ; print debug messages + push bx + push cs + pop ds + ; assume first BDS is in this segment + ASSUME DS:CODE + mov di,word ptr Start_BDS +Scan_Loop: +;;Rev 3.30 Modification ----------------------------------------- + CMP BYTE PTR CS:[PHYS_DRV],1 ; DOES AL HAVE PHYS DRV? + JB USE_LOGICAL_DRV + CMP BYTE PTR [DI].DRIVENUM,AL + JE SETDRV + JMP SHORT GET_NXT_BDS +USE_LOGICAL_DRV: + CMP BYTE PTR [DI].DRIVELET,AL + JE SETDRV +GET_NXT_BDS: + MOV BX,WORD PTR [DI].LINK+2 ; GO TO NEXT BDS + MOV DI,WORD PTR [DI].LINK + mov ds,bx + ASSUME DS:NOTHING +;;End of Modification ----------------------------------------- + + cmp di,-1 ; at end of list? + jnz Scan_Loop ; no, keep looking + stc ; yes, indicate error set carry +SetDrv: + pop bx ; restore bx + ret ; return + +SETDRIVE ENDP + + + +;------------------------------------------------------------------------ +; : +; DISK I/O ROUTINES : +; : +; On entry the register contain the following values: : +; : +; AH - Media Descriptor byte : +; AL - logical drive number : +; CX - count of sectors to be read or written : +; DX - start sector : +; DI - offset of destination buffer : +; : +;------------------------------------------------------------------------ + + +;------------------------------------------------------------------------ +; : +; Disk Write with Verify : +; : +; Input : +; See about header for register contents on entry. : +; : +;------------------------------------------------------------------------ + + +DSK$WRITV PROC NEAR + PUBLIC DSK$WRITV + Message fTestDisk,<"Disk Write with verify "> + MNUM fTestDisk,AX + Message fTestDisk,<" "> + MNUM fTestDisk,DX + Message fTestDisk,<" for "> + MNUM fTestDisk,CX + Message fTestDisk, + MOV CS:[WRTVERIFY],103H + JMP SHORT DSK$CL + +;------------------------------------------------------------------------ +; : +; Disk Write : +; : +; Input : +; See about header for register contents on entry. : +; : +;------------------------------------------------------------------------ + +DSK$WRIT: + PUBLIC DSK$WRIT + Message fTestDisk,<"Disk Write "> + MNUM fTestDisk,AX + Message fTestDisk,<" "> + MNUM fTestDisk,DX + Message fTestDisk,<" for "> + MNUM fTestDisk,CX + Message fTestDisk, + MOV CS:[WRTVERIFY],ROMWrite + +DSK$CL: + CALL DISKIO +DSK$IO: + JC DSKBad + JMP EXIT +DSKBad: + JMP ERR$CNT + +DSK$WRITV ENDP + + +;------------------------------------------------------------------------ +; : +; Disk Read : +; : +; Input : +; See about header for register contents on entry. : +; : +;------------------------------------------------------------------------ + +DSK$READ PROC NEAR + PUBLIC DSK$READ + Message fTestDisk,<"Disk Read "> + MNUM fTestDisk,AX + Message fTestDisk,<" "> + MNUM fTestDisk,DX + Message fTestDisk,<" for "> + MNUM fTestDisk,CX + Message fTestDisk, + CALL DISKRD + JMP DSK$IO +DSK$READ ENDP +; +; Miscellaneous odd jump routines. Moved out of mainline for speed. +; + + +; +; CheckSingle determines if the drive specified is a virtual drive (more +; than one logical drive associated with one physical drive). If this +; is the case we need to prompt the user to place the correct disk in +; the drive. +; +; Input: +; DS:DI pints to the BDS for the drive being checked. +; +; If there is a error the carry flag is set on return +; +; All registers are preserved. +; + +CHECKSINGLE PROC NEAR + PUBLIC CHECKSINGLE + push AX ; save affected registers + push BX + mov BX,word ptr ds:[di].flags + TEST BL,FNON_REMOVABLE OR FI_OWN_PHYSICAL ;Can't change disk + jnz SingleRet ; on hard drive so return + ; is there a drive sharing this + TEST BL,FI_AM_MULT ; physical drive? + jz SingleRet ; if not, then return + + ; At this point there is more than one + ; logical drive mapped to this physical drive. + ; But the drive being accessed is not the + ; owner of the physical drive. What needs to + ; be done is find the current owner BDS and + ; turn off the owner flag and then make current + ; BDS the owner of the drive. Then prompt the + ; user to change disks. + mov al,ds:[di].DriveNum ; get physical drive number + push ds ; preserve pointer to current BDS + push di + push cs + + pop ds ; Point to start of BDS linked list + ASSUME DS:CODE + + mov di,offset Start_BDS + +Scan_List: + mov bx,word ptr [di].link+2 ; go to next BDS + mov di,word ptr [di].link + mov ds,bx + ASSUME DS:NOTHING + + cmp di,-1 ; end of list? + jz single_err_ret ; if so there must be an error + ; same physical drive? + cmp byte ptr [di].DriveNum,al + jnz Scan_List ; no, keep looking + +Check_Own: ; yes, check to see if owner + mov bx,word ptr [di].flags + test bl,fI_Own_Physical + jz Scan_List ; not owner, keep looking + xor bl,fI_Own_Physical ; yes owner reset ownership flag + mov word ptr ds:[di].flags,bx + pop di ; Restore pointer to current BDS + pop ds + xor bx,bx + or bl,fI_Own_Physical ; establish current BDS as owner + or word ptr [di].flags,bx + + + ; + ; We examine the fSetOwner flag. If it is + ; set, then we are using the code in + ; CheckSingle to just set the owner of + ; a drive. We must not issue the prompt + ; in this case. + ; + + cmp byte ptr cs:[fSetOwner],1 + jz SingleRet + ; + ; To support "backward" compatibility with + ; IBM's "single drive status byte" we now + ; check to see if we are in a single drive + ; system and the Application has "cleverly" + ; diddled the SDSB (Single Drive Status Byte) + ; + + cmp cs:[single],2 ; single drive system? + jne short Ignore_SDSB ; no, jump down + + SaveReg ; yes... + mov al,ds:[di].DriveLet ; IF (Curr_drv == Req_drv) + mov ah,al + xor di,di + mov ds,di + xchg al,ds:byte ptr LSTDRV ; THEN swap(Curr_drv,Req_drv) + cmp ah,al ; ELSE + RestoreReg ; swap(Curr_drv,Req_drv) + je SingleRet ; Issue Swap_dsk_msg + +Ignore_SDSB: + call SWPDSK ; ask user for correct disk + +SingleRet: + pop BX ; restore registers + pop ax + ret ; return + +Single_Err_Ret: + stc ; set carry flage to indicate error + pop di ; restore current BDS + pop ds + jmp short SingleRet + + +; +; BadDrive is called when sector specified is greater than last +; sector on disk. +; or when BDS is not found for drive +; + +BadDrive: + mov AL,8 ; error code 'sector not found' + stc ; indicate error +IORET: ret ; return + + + +BogusSettle: + MOV AL,NormSettle ; someone has diddled the settle + JMP GotSlowSettle + +CHECKSINGLE ENDP + + + + +;------------------------------------------------------------ +; +; DISK I/O HANDLER +; +; On entry: +; AL = Drive Number (0-6) +; AH = media Descriptor +; CX = sector count +; DX = first sector +; DS = CS +; ES:DI = transfer address +; [RFLAG] = operation (2 for read, 3 for write) +; [VERIFY] = 1 for verity after write +; +; On exit: +; if successful carry flag = 0 +; else CF=1 and AL contains error code +; + + + Public DISKRD +DISKRD PROC NEAR + mov CS:[RFLAG],ROMRead ; set command to read + +DISKIO: + mov BX,DI ; ES:BX is transfer address + Call SetDrive ; map logical and physical + jc BadDrive ; carry means BDS not found + mov al,BYTE PTR DS:[DI].Mediad + mov cs:MedByt,al ; Preserve media byte for drive for use + ; in determining media change. + jcxz IORET + mov cs:[SPSAV],SP ; save the sp value +; +; Ensure that we are trying to access valid sectors on the drive +; + mov SI,DX ; start with first sector + add SI,CX ; add in sector count + add DX,WORD PTR [DI].HIDSEC ; add in the hidden sectors + cmp SI,WORD PTR [DI].DRVLIM ; compare against drive maximum + ja BADDRIVE ; if greater than max, error + mov cs:[SECCNT],CX ; save sector count +;;Rev 3.30 Modification ----------------------------------------- +; SET UP POINTER TO DISK BASE TABLE IN [DPT]. WE CANNOT ASSUME THAT IOSETUP +; WILL DO IT BECAUSE WE WILL SKIP THE SET UP STUFF WITH HARD DISKS. + PUSH DS + XOR AX,AX + MOV DS,AX + LDS SI,DWORD PTR DS:[DSKADR]; CURRENT DISK PARM TABLE + MOV WORD PTR CS:DPT,SI + MOV WORD PTR CS:DPT+2,DS + POP DS +;;End of Modification ----------------------------------------- +; +; For hard drives do not do media check or set DPT. +; + test word ptr [di].flags,fNon_Removable + jnz Skip_Setup + CALL CHECKSINGLE +; +; Check to see if we have previously noted a change line. The routine +; returns if everything is OK. Otherwise, it pops off the stack and returns +; the proper error code. +; +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| + Public DiskIO_Patch ;| +DiskIO_PATCH: ;| + CALL CheckLatchIO ;| +;----------------------------------------| +; +; Set up tables and variables for I/O + call IOSetUp +; +; Now the settle values are correct for the following code +; +Skip_Setup: + mov AX,DX ; setup locical sector for divide + xor DX,DX + div word ptr [DI].SECLIM ; divide by sectors per track + inc DL + mov cs:[CURSEC],DL ; save current sector + mov CX,word ptr [DI].HDLIM ; get number of heads + xor DX,DX ; divide tracks by heads per cylinder + div CX + mov cs:[CURHD],DL ; save current head + mov cs:[CURTRK],AX ; save current track +; +; We are now set up for the I/O. Normally, we consider the DMA boundary +; violations here. Not true. We perform the operation as if everything is +; symmetric; let the DISK INT handler worry about the DMA violations. +; + mov AX, cs:[SECCNT] + call BLOCK + call DONE + ret + +DISKRD ENDP + + + +; +; IOSetUp: +; +; IOSetUp does the following functions: +; * Set the drive-last-accessed flag (for diskette only). No need to +; update these flags for hard disks becuase we know a hard disk will +; not be removed. +; * Set the proper last sector number in the Disk Parameter Table (DPT) +; * Set the proper motor start up time in DPT +; * Set the proper head settle time in the DPT +; +; Input: +; DS:DI -> current BDS. +; Output: +; AX,CX,SI are destroyed. +; + public IOSetUp +IOSETUP PROC NEAR + MOV AL,[DI].DRIVENUM + MOV CS:[TIM_DRV],AL ; SAVE DRIVE LETTER +; +; determine proper head settle values +; + mov CX,DS + LDS SI,DWORD PTR CS:[DPT] ; GET POINTER TO DISK BASE TABLE + MOV AL,CS:[EOT] + mov [SI].DISK_EOT,AL ; bump for us + mov AL,[si].DISK_Motor_Strt ; preserve old motor start time + mov cs:MotorStartup,AL +; +; For 3.5" drives, both external as well as on the K09, we need to set the +; Motor Start Time to 4. This checking for every I/O is going to affect +; performance across the board, but is necessary!! +; + push es + mov es,cx ; ES:DI -> to current BDS + cmp byte ptr es:[di].FormFactor,ffsmall + jnz Motor_Start_OK + mov AL,4 + xchg AL,[si].DISK_MOTOR_STRT +Motor_Start_OK: + pop ES +; +; DS:SI now points to disk parameter table. Get current settle and set fast +; settle +; + + XOR AL,AL + INC AL ; IBM WANTS FAST SETTLE = 1 - RS + xchg AL,[SI].DISK_Head_Sttl ; get settle and set up for fast + mov cs:SettleCurrent,AL + MOV AL,NORMSETTLE ; SOMEONE HAS DIDDLED THE SETTLE +GotSlowSettle: + mov DS,CX + mov cs:SettleSlow,AL + ret + + + + +; +; Set time of last access, and reset default values in the DPT. +; +DONE: + test word ptr [di].Flags,fNon_Removable + jnz RETZ ; Do not set for non-removable Media + call SET_TIM ; set time of last access for drive +; +; Restore head settle and EOT values +; +DiddleBack: + push ax ; preserve AX + mov DX,DS ; save DS in DX + mov AL,cs:SettleCurrent ; get value in registers + mov AH,cs:MotorStartup + lds SI,cs:DPT ; get pointer to DPT + mov [SI].Disk_EOT,9 ; save values in DPT + mov [SI].Disk_Head_Sttl,AL + mov [si].Disk_Sector_Siz,2 + mov [si].Disk_Motor_Strt,AH + mov DS,DX ; restore DS + pop ax ; restore AX +RETZ: + ret + + + + + +; +; Block reads or writes the number of sectors specified in AX +; handling track boundaries. For example, on an 8 sector per track +; disk there might be a request to read 6 sectors starting at the 5th +; sector. Block breaks this request into a read of sectors 5-8 on +; the first track and a read of sectors 1-2 on the next track. Disk is +; called to do the actual read. +; +; Inputs: +; AX - number of sectors to be read +; DS:DI points to BDS for disk drive +; cs:CurSec - sector on track where read should start +; cs:CurTrk - track where read should start +; cs:CurHd - head for read +; ES:BX - transfer address +; AX, CX, and BL are not preserved +; + +BLOCK: + or AX,AX ; see if any sectors to read + jz RETZ ; if not, return +;;Rev 3.30 Modification ----------------------------------------- +; Fixed disk will not be restricted to the trk-by-trk basis. + test word ptr [di].Flags, fNon_Removable + jz BLOCK_FLOPPY + call DISK + xor ax,ax + RET +BLOCK_FLOPPY: +;;End of Modification ----------------------------------------- +; +; READ AT MOST 1 TRACK WORTH. PERFORM MINIMIZATION AT SECTOR / TRACK +; + mov CL,byte ptr [DI].SecLim ; get sectors per track + inc CL + sub CL,cs:CurSec ; set CX to number of sector after current + xor CH,CH ; sector on the current track + cmp AX,CX ; is all of request on current track? + jae GotMin ; no, jump down + mov CX,AX ; yes, set number of sector on this track to AX +GotMin: + ; now + ; AX is the requested number of sectors to read + ; CX is the number that we can do on this track + push AX + push CX + mov AX,CX ; AL is number of sectors to read + call Disk + pop CX + pop AX + + ; CX is the number of sectors just transferred + sub AX,CX ; reduce sectors-remaining by last I/O + shl CL,1 + add BH,CL ; adjust transfer address + jmp Block ; jump to do any remaining sectors + +IOSETUP ENDP + + + + + +; +; DISK: +; Disk is called to read or write one or more sectors on a track. +; Retries are make if an error occurs. +; +; Input: +; AL - number of sector to be read/written (they must all be on one track) +; DS:DI points to BDS for the drive +; ES:BX is transfer address (must not cross 64k physical boundry) +; [RFLAG] is 2 for read and 3 for write +; [VERIFY] is 0 for normal, 1 for verify after write +; [CurTrk] is track (cylinder) to be read/written. +; [CurHd] is head to be used in operation. +; [CurSec] is sector to start read on. +; +; The following are overwritten: BP, +; Output: +; [SECCNT] is decrement by the number of sectors read or written + + + public disk +DISK PROC NEAR + mov BP,MAXERR ; set up retry count + MOV AH,CS:RFLAG ;GET READ/WRITE INDICATOR + +RETRY: + ; AX is overwritten in int 13 call, so + ; to do a retry we need to save the + ; value by pushing on the stack + push AX + ; the next five lines of code put the + ; sector number in bit 5-0 of CL and the + ; cylinder number in CH and bits 7-6 of + ; CL. The register must be set up in this + ; way for the bios. + mov DX,cs:[CURTRK] ;Load current cylinder +;;Rev 3.30 Modification ----------------------------------------- + test word ptr [di].FLAGS, fNon_Removable ;Fixed disk + jz DISK_NOT_MINI ;no, skip this. + cmp [di].IsMini, 1 ;Is this a mini disk? + jnz DISK_NOT_MINI ;No. continue to next. + add dx, [di].Hidden_Trks ;else add hidden trks. +DISK_NOT_MINI: +;;End of Modification ----------------------------------------- + ror DH,1 ; get high two bits of cylinder in correct place + ror DH,1 + + or DH,cs:[CURSEC] ; get sector value + mov CX,DX ; put cylinder/sector values in correct register + ; get head value + xchg CH,CL ; put bytes in correct place + mov DH,byte ptr cs:[CurHD] + ; get drive number + mov DL,byte ptr [DI].DriveNum + + CMP BYTE PTR [DI].FORMFACTOR,FFHARDFILE + JZ DO_FAST ; HARD FILES USE FAST SPEED +; +; The registers are now all set up for call on rom-bios. +; The next dozen or so line determines whether we call Do_Fast or Do_Norm +; for the actual I/O read. Do_Fast calls FastSpeed for the actual I/O. +; Do_Norm calls NormSpeed. NormSpeed changes the value for the head settle +; time in the disk parameter table to a larger value and then calls FastSpeed +; to do the I/O. So Do_Fast just has a shorter head settle time. +; + CMP CS:[STEP_DRV],-1 + jz Do_Writej + + cmp AH,ROMRead ; For read... + je Do_Fast ; ... alway use fast + + cmp AH, ROMVerify ; For verify... + je Do_Fast ; ... alway use fast + +Do_Writej: + jmp DO_Write ; Jump down for write... + + +DO_Fast: + CALL FastSpeed ; do I/O carry set if error +TestErr: + jc DSKERR ; error -- get out +; SET DRIVE AND TRACK OF LAST ACCESS + mov cs:[STEP_DRV],DL ; save the last drive accessed + mov byte ptr [di].track,CH ; save in BDS + +NO_SET: + cmp CS:WRTVERIFY,103H ; Check for write and verify + jz DoVerify ; yes -- go do verify +NOVERIFY: + pop AX ; pop command and num sec. from stack + and CL,03FH ; Eliminate cylinder bits from sector + xor AH,AH + sub cs:[SECCNT],AX ; Reduce count of sectors to go + add CL,AL ; Next sector + mov cs:[CURSEC],CL + cmp CL,BYTE PTR [DI].SECLIM ; See if sector/track limit reached + jbe Disk_Ret ; yes, return +NextTrack: + mov cs:[CURSEC],1 ; Start with first sector of next track + mov DH,CS:[CURHD] + inc DH ; go to next head + cmp DH,BYTE PTR [DI].HDLIM ; at head limit? + jb NOXOR ; no, jump down + xor DH,DH ; at head limit, reset to head zero ... + inc cs:[CURTRK] ; and go to next head +NOXOR: + mov cs:[CURHD],DH ; save new head number +Disk_Ret: + clc ; successful return so clear error flag + ret ; all done +DISK ENDP +; +; The request is for write. Determine if we are talking about the same +; track and drive. If so, use the fast speed. +; +DO_WRITE PROC NEAR + cmp DL,cs:[STEP_DRV] ; same drive? + jnz DO_Norm ; no, do normal speed + cmp CH,byte ptr [di].track ; same track on drive + jz DO_Fast ; yes, do fast speed +DO_Norm: + call NormSpeed ; use larger head settle time + jmp SHORT TestErr ; test for error + +DO_WRITE ENDP + + +; +; we have a verify request also. Get state info and go verify +; + +DOVERIFY PROC NEAR + pop AX ; get number of sectors from stack + push AX ; in non-detructive fashion + MOV AH,ROMVERIFY ; REQUEST VERIFY + CALL FastSpeed ; MZ 2.21 change settle mode + JNC NoVerify +DOVERIFY ENDP + +; +; Need to special case the change-line error AH=06h. If we get this, we +; need to return it. +; +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| + Public DSKERR ;| +DSKERR PROC NEAR ;| + CALL CheckIO ;| +;---------------------------------------;| + + Call AGAIN ; reset the disk and decrement retry cnt + jz HARDERR ; if z flag set, did all retries-give up + cmp AH,80H ; timeout? + jz HARDERR ; yes, jump to hard error +DSKERR1: + pop AX ; Restore sector count + jmp RETRY ; and try again + +HARDERR: + PUBLIC HARDERR + CALL MapError + +HARDERR2: ; for routines that call MapError themselves + PUBLIC HARDERR2 + mov cs:[Tim_Drv],-1 ;Force a media check through ROM + mov CX,cs:SECCNT ;Get count of sectors to go + mov SP,cs:[SPSAV] ;Recover entry stack pointer +; +; Since we are performing a non-local goto, restore the disk parameters +; +MedByt_OK: + call DiddleBack + ret ;and return + +DSKERR ENDP + + +; +; change settle value from SettleCurrent to whatever is appropriate +; +NORMSPEED PROC NEAR + push DS ; save two registers + push AX + mov AL,cs:SettleSlow ; change value in current disk parm tbl + lds SI,cs:DPT ; current disk parm table + mov [SI].Disk_Head_Sttl,AL + pop AX ; restore command and sector count + pop DS + call FastSpeed ; do I/0 + push DS ; restore the value in disk parm table + lds SI,cs:DPT + mov [SI].Disk_Head_Sttl,1 ; 1 is fast settle + pop DS + ret + +NORMSPEED ENDP + + +FASTSPEED PROC NEAR +; +; If the drive has been marked as too big (i.e. starting sector of the +; partition is > 16 bits, then ALWAYS return drive not ready. +; + TEST BYTE PTR [DI].FatSiz,fTOOBIG + + + IF TEST + JZ Ready ; if debugging use jmp rather + JMP NotReady ; than local jnz +Ready: + else + JNZ NotReady + endif + + Message fTestINIT,<"<"> ; print debug messages + MNUM fTestINIT,AX + Message fTestINIT,<","> + MNUM fTestINIT,ES + Message fTestINIT,<":"> + MNUM fTestINIT + Message fTestINIT,<","> + MNUM fTestINIT,CX + Message fTestINIT,<","> + MNUM fTestINIT,DX + Message fTestINIT,<">"> + + int 13h ; call rom-bios disk routines + +Death: + ret +NotReady: + stc ; set carry to indicate error + mov AH,80h ; put error code in AH + jmp Death ; jump to ret + +FASTSPEED ENDP + + +; +; Map error returned by ROM into corresponding code to be returned to +; DOS in AL. +; +MAPERROR PROC NEAR + PUBLIC MAPERROR + push CX ; save cx + push CS + pop ES ; make ES the local segment + mov AL,AH ; move error code into AL + mov cs:[LSTERR],AL ; terminate list with error code + mov CX,NUMERR ; number of possible error conditions + mov DI,OFFSET ERRIN ; point to error conditions + repne SCASB + mov AL,cs:[DI + NUMERR - 1] ; get translation + pop cx ; restore cx + stc ; flag error condition + ret +MAPERROR ENDP + +; +; Set the time of last access for this drive. This is done only for removable +; media. +; + public SET_TIM +SET_TIM PROC NEAR + push ax + xor AH, AH ; set command to get time + int 1Ah ; call rom-bios timer function + or AL,AL ; is there 24 hour rollover? + jz NOROLL3 ; no, skip down + inc cs:[DayCnt] ; yes, then increment DayCnt +NOROLL3: +; We have the new time. If we see that the time has passed, then we reset +; the threshold counter... + cmp DX,word ptr [di].TIM_LO ; Did any time pass? + jnz SetAccess ; yes, update access time + cmp CX,word ptr [di].TIM_HI ; now look at the high bits + jz Done_Set ; if equal then no time passed +SetAccess: ; we get here if some time has passed + ; zero AccessCount to show time passage + mov byte ptr cs:[AccessCount],0 + MOV WORD PTR DS:[DI].TIM_LO,DX ; save low time bits + MOV WORD PTR DS:[DI].TIM_HI,CX ; save high time bit +Done_Set: + clc ; indicate no error + pop ax ; restore AX register + ret + +SET_TIM ENDP + ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING + +; +; This is the true DISK INT handler. We parse the request to see if there is +; a DMA violation. If so, depending on the function, we: +; READ/WRITE Break the request into three pieces and move the middle one +; into our internal buffer. +; FORMAT Copy the format table into the buffer +; VERIFY Point the transfer address into the buffer +; +; This is the biggest bogosity of all. The IBM controller does NOT handle +; operations that cross physical 64K boundaries. In these cases, we copy +; the offending sector into the buffer below and do the I/O from there. +; + +INT13FRAME STRUC +oldbp dw ? +oldax dw ? +oldbx dw ? +oldcx dw ? +olddx dw ? +olddd dd ? +oldf dw ? +INT13FRAME ENDS + +;;Rev 3.30 Modification ----------------------------------------- +;To handle the INT 13h, AH = 8 Problem. +;Save Registers here. +Save_AX DW ? +Save_BX DW ? +Save_CX DW ? +Save_DX DW ? +Save_DI DW ? +Save_SI DW ? +Save_BP DW ? +Save_DS DW ? +Save_ES DW ? +Prev_DX DW ? +Save_Flag DW ? +;;End of Modification ----------------------------------------- + + +; +; Block13: +; +; Entry conditions: +; AH = function +; AL = number of sectors +; ES:BX = DMA address +; CX = packed track and sector +; DX = head and drive +; Output conditions: +; NO DMA violation. +; + Public Block13 +Block13 PROC FAR +; +; Let the opperation proceed. If there is a DMA violation, then we do things. +; + mov cs:PrevOper,AX ; save request + pushf ; preserve the flags + cmp AH,ROMFormat ; format request? + jnz Not_Format ; no, skip down + +; Set changed by format bit for all logical drives using this physical drive +;---------------------------------------------------------| +; Warning: Do Not Change the following. | +; It gets patched in at INIT time | + Public Changed_Patch +Changed_Patch: + mov word ptr cs:[FlagBits],fChanged_By_Format+fChanged + call Set_Changed_DL ; Indicate that media changed by format +; | +;---------------------------------------------------------| + +Not_Format: +;;Rev 3.30 Modification ----------------------------------------- + cmp ah, 8 ; Read Driver Parm ? + je Bus_Problem + cmp ah, 15h + je Bus_Problem + CALL ORIG13 ; SIMULATE INT 13 + JC GOTERR13_br ; ERROR? + RET 2 ; NO, RETURN AND CLEAR FLAGS + +GOTERR13_br: jmp Goterr13 + +;Some machines have a problem with Int 13h function=8 +;This function does not reset the common buses after the execution. +;To solve this problem, when we detect AH=8h, then we will save the result +;and will issue AH=1 (Read Status) call to reset the buses. + +Bus_Problem: + mov cs:Prev_DX, DX ;save orignal drive number + call Orig13 ;Do "Read drive parm" + + mov cs:Save_AX, AX ;Save registers,flag + mov cs:Save_BX, BX + mov cs:Save_CX, CX + mov cs:Save_DX, DX + mov cs:Save_DI, DI + mov cs:Save_SI, SI + mov cs:Save_BP, BP + mov cs:Save_DS, DS + mov cs:Save_ES, ES + pushf + pop cs:Save_Flag + + mov dx, cs:Prev_DX ;restore orignal drive + pushf + mov ah, 1 ;Read Status. + call Orig13 ;Reset the bus as a side effect + + mov AX, cs:Save_AX ;restore registers,flag + mov BX, cs:Save_BX + mov CX, cs:Save_CX + mov DX, cs:Save_DX + mov DI, cs:Save_DI + mov SI, cs:Save_SI + mov BP, cs:Save_BP + mov DS, cs:Save_DS + mov ES, cs:Save_ES + push cs:Save_Flag + popf + jc GotErr13 ;AH=8 had been an error? + ret 2 +; +; Some kind of error occurred. See if it is DMA violation +; +GotErr13: + pushf + cmp AH, 09h ; is error DMA error code? + JNZ CHECK_ECC + JMP GOTDMAERR +CHECK_ECC: + CMP AH,11H + JZ OK11 + POPF + RET 2 +; +; We have an error status 11h. This indicates an ECC-corrected error. Note +; that this indicates that the data is PROBABLY correct but not CERTAINLY +; correct. The ROMs on PC-1s and PC_XTs have a 'bug' in that if an ECC error +; occurs for a multi-sector read, only the sectors up to the one where the +; error occurred are read in. We have no way of knowing how many were read in +; this case, so we redo the operation, reading one sector at a time. If we +; get an ECC error on reading one sector, we ignore the error because the +; sector has been read in. +; + PUBLIC OK11 +OK11: +; popf ; restore flags +;;Rev 3.30 Modification ----------------------------------------- +; Here, it is better reset the system. So, we are going to +; call Orig13 again + mov ah, 0 + call Orig13 ;reset. Don't care about result +;;End of Modification ----------------------------------------- + + mov ax,cs:[PrevOper] ; Retrieve request +; +; This will provide a termination point. +; + cmp AL,1 ; If request for one sector, assume OK + jnz ECC_Err_Handle ; more than one sector -- jump down + xor AH,AH ; clear carry too! + ret 2 + + Public ECC_Err_Handle +ECC_Err_Handle: + SAVEREG + mov cs:[Number_Of_Sec],AL +Loop_ECC: + mov AX,CS:[PrevOper] ; set command to previos command + mov AL,1 ; but request only one sector +; +; we do reads one sector at a time. this ensures that we will eventually +; finish the request since ecc errors on 1 sector do read in that sector. +; +; we need some "intelligence" in the ecc handler to handle reads +; that attempt to read more sectors than are available on a particular +; track. +; we call check_wrap to set up the sector #, head # and cylinder # for +; this request. +; at this point, all registers are set up for the call to orig13, except +; that there maybe a starting sector number that is bigger than the number +; of sectors on a track. +; + + CALL Check_Wrap ; see if wrapping around cylinder + + pushf ; save flags + call ORIG13 ; call original rom-bios code +;;Rev 3.30 Modification ------------------------------------------------------ + JNC OK11_OP + CMP AH,11H ; ONLY ALLOW ECC ERRORS + JNZ OK11_EXIT_err ; Other error? + mov ah, 0 ; ECC error. Reset it again. + pushf + call Orig13 +OK11_Op: + dec cs:[Number_of_Sec] ; adjust number of sectors for one read + jz OK11_Exit ; all done? + inc CL ; advance sector number + inc BH ; add 200H to address + inc BH + jmp short Loop_ECC ; and around for reading another sector + +OK11_EXIT_err: + stc ; Set carry bit again. +;;End of Modification ------------------------------------------------------ + +OK11_Exit: + RESTOREREG + Ret 2 + + + +; +; we truly have a DMA violation. Restore register AX and retry the +; operation as best we can. +; +GotDMAErr: + pop AX ; clean up stack + mov AX,cs:PrevOper ; restore command + sti ; restore interrupts + cmp AH,ROMRead ; determine the command + jb IntDone + cmp AH,ROMVerify + jz IntVerify + cmp AH,ROMFormat + jz IntFormat + ja IntDone +; +; We are doing a read/write call. Check for DMA problems +; + SaveReg ; save register we overwrite + push BP + mov BP,SP + mov DX,ES ; Check for 64k boundary error + + shl DX,1 + shl DX,1 + shl DX,1 + shl DX,1 ; Segment converted to absolute address + + add DX,BX ; Combine with offset + add DX,511 ; simulate a transfer +; +; If carry is set, then we are within 512 bytes of the end of the segment. +; We skip the first transfer and perform the remaining buffering and transfer +; + JNC NO_SKIP_FIRST + mov DH,byte ptr [bp.olddx+1] ; set correct head number + jmp Buffer + +NO_SKIP_FIRST: +; +; DX is the physical 16 bits of start of transfer. Compute remaining +; sectors in segment. +; + shr DH,1 ; DH = number of sectors before address + mov AH,128 ; AH = max number of sectors in segment + sub AH,DH +; +; AH is now the number of sectors that we can successfully write in this +; segment. If this number is above or equal to the requested number, then we +; continue the operation as normal. Otherwise, we break it into pieces. +; + cmp AH,AL ; can we fit it in? + jb DoBlock ; no, perform blocking. +; +; Yes, the request fits. Let it happen +; + MOV DH,BYTE PTR [BP.OLDDX+1] ; SET UP HEAD NUMBER + call DoInt + jmp Bad13 +; +; Verify the given sectors. Place the buffer pointer into our space. +; +IntVerify: + SaveReg + push CS + pop ES +DoSimple: + mov BX,OFFSET DiskSector + pushf + call Orig13 + RestoreReg + ret 2 + +; +; Format operation. Copy the parameter table into memory +; +IntFormat: + SaveReg + SaveReg + push ES + push CS + pop ES + pop DS + mov SI,BX + mov DI,OFFSET DiskSector + call Move + RestoreReg + jmp DoSimple +; +; Inline continuation of operation +; +IntDone: + jmp Orig13 +; +; We can't fit the request into the entire block. Perform the operation on +; the first block. +; +; +; DoBlock is modified to correctly handle multi-sector disk I/O. +; Old DoBlock had added the number of sectors I/Oed (Ah in Old DoBlock) after +; the DoInt call to CL. Observing only the lower 6 bits of CL(=max. 64) can +; represent a starting sector, if AH was big, then CL would be clobbered. +; By the way, we still are going to use CL for this purpose since Checkwrap +; routine will use it as an input. To prevent CL from being clobbered, a +; safe number of sectors should be calculated like "63 - # of sectors/track". +; DoBlock will handle the first block of requested sectors within the +; boundary of this safe value. + +;Try to get the # of sectors/track from BDS via Rom drive number. +;For any mini disks installed, here we have to pray that they have the +;same # of sector/track as the main DOS partition disk drive. + +DoBlock: +;;Rev 3.30 Modification ------------------------------------------------------ + Message ftestDisk,<"!!!DMA DoBlock!!!"> + + mov dx, word ptr [bp.olddx] ;set head # + push di + push ds + push ax ;AH=# of sectors before DMA err + ;AL - User requeseted # of sectors + mov byte ptr CS:[phys_drv],1 + mov al, dl + call SetDrive ;get BDS pointer for this DISK. + pop ax + mov byte ptr CS:[phys_drv],0 + test word ptr [DI].Flags, fNon_Removable ;don't have to worry + jnz DoBlockHard ;about floppies. They are track by + ;track operatiions + mov al, ah ;set al = ah for floppies + jmp short DoBlockCont +DoBlockHard: + push cx + xor cx, cx + mov cx, [DI].SecLim ;# of sectors/track + mov ch, 63 + sub ch, cl + mov al, ch + xchg ah, al ;now ah - safe # of sectors + ;al - # of sectors before DMA err + pop cx +DoBlockCont: + pop ds + pop di +DoBlockContinue: + Message ftestDisk,<"%%DMA DoBlock Loop%%"> + cmp ah, al ;if safe_# >= #_of_sectors_to_go_before DMA, + jae DoBlocklast ;then #_of_sectors_to_go as it is for DoInt. + push ax ;save AH, AL + mov al, ah ;Otherwise, set al to ah to operate. + jmp short DoBlockDoInt ;DoInt will set AH to a proper function in [BP.Oldax] +DoBlocklast: + mov ah, al + push ax ;save AH +DoBlockDoInt: ;let AH=AL=# of sectors this shot + CALL DoInt + JC BAD13 ;something happened, bye! + pop ax + SUB BYTE PTR [BP.oldax], AH ;decrement by the successful operation + ADD CL,AH ;advance sector number. Safety gauranteed. + ADD BH,AH ;advance DMA address + ADD BH,AH ;twice for 512 byte sectors. + cmp ah, al ;check the previous value + je Buffer ;if #_of_sectors_to_go < safe_#, then we are done already. + sub al, ah ;otherwise, #_sector_to_go = #_of_sector_to_go - safe_# + call Check_Wrap ;get new CX, DH for the next operation. + jmp short DoBlockContinue ;handles next sectors left. +;;End of Modification ------------------------------------------------------ +; +Buffer: + push BX + mov AH,BYTE PTR [BP.oldax+1] + cmp AH,ROMWrite + jnz DoRead +; +; Copy the offending sector into local buffer +; + SaveReg + push CS ; exchange segment registers + push ES + pop DS + pop ES + mov DI,OFFSET DiskSector ; where to move + push DI ; save it + mov SI,BX ; source + call Move + pop BX ; new transfer address + RestoreReg + mov AL,1 + mov DL,byte ptr [BP.olddx] ; set drive number + call Check_Wrap ; check for head or cylinder wrap + +; +; AH is function +; AL is 1 for single sector transfer +; ES:BX is local transfer addres +; CX is track/sector number +; DX is head/drive number +; SI,DI unchanged +; + CALL DoInt + RestoreReg + jc Bad13 ; go clean up + jmp SHORT DoTail +; +; Reading a sector. Do INT first, then move things around +; +DoRead: + SaveReg + push CS + pop ES + mov BX,OFFSET DiskSector + mov AL,1 + mov DL,byte ptr [BP.olddx] ; set drive number + call Check_Wrap ; check for head or cylinder wrap + +; +; AH = function +; AL = 1 for single sector +; ES:BX points to local buffer +; CX, DX are track/sector, head/drive +; + CALL DoInt + RestoreReg + jc Bad13 ; error => clean up + SaveReg + push CS + pop DS + mov DI,BX + mov SI,OFFSET DiskSector + call Move + RestoreReg +; +; Note the fact that we've done 1 more sector +; +DoTail: + pop BX ; retrieve new DMA area + add BH,2 ; advance over sector + inc CX + mov AL,BYTE PTR [BP.oldAX] + clc + dec AL + jz Bad13 ; no more I/O + mov DL,byte ptr [BP.olddx] ; set drive number + call Check_Wrap ; check for head or cylinder wrap + call DoInt +; +; We are done. AX has the final code; we throw away what we got before +; +Bad13: + mov SP,BP + RestoreReg + ret 2 +Block13 ENDP + + + + + PAGE + + include msioctl.inc + + PAGE +; +; Check_Wrap is a routine that adjusts the starting sector, starting head +; and starting cylinder for an Int 13 request that requests I/O of a lot +; of sectors. It only does this for fixed disks. It is used in the sections +; of code that handle ECC errors and DMA errors. It is necessary, because +; ordinarily the ROM would take care of wraps around heads and cylinders, +; but we break down a request when we get an ECC or DMA error into several +; I/O of one or more sectors. In this case, we may already be beyond the +; number of sectors on a track on the medium, and the request would fail. +; +; Input conditions: +; ALL registers set up for an Int 13 request. +; +; Output: +; - contains starting head number for request +; - contains starting sector and cylinder numbers +; (The above may or may not have been changed, and are 0-based) +; All other registers preserved. +; + public check_wrap +Check_Wrap: + Message ftestDisk,<"Entering Check_Wrap...",cr,lf> + SaveReg + mov byte ptr cs:[Phys_drv],1;Use phys. drive in AL to get BDS + mov al,dl ; put drive number in AL for get BDS + call SetDrive ; Get pointer to BDS for drive. + mov byte ptr cs:[phys_drv],0; Restore flag to use Logical Drive + jc No_wrap ; Do nothing if wrong phys. drive + + test word ptr [di].Flags,fNon_Removable + jz No_wrap ; No wrapping for removable media + MOV BX,[DI].SECLIM + MOV AX,CX + AND AX,003FH ; EXTRACT SECTOR NUMBER + cmp ax,bx ; If Wrap + jbe No_wrap + + div bl ; AH=new sector#, AL = # of head wraps + +; We need to be careful here. If the new sector number == 0, then we are +; on the last sector on that track + or ah,ah + jnz Not_on_Bound + + mov ah,bl ; set sector = SECLIM if on Bndry + dec al ; and decrement Num. head wraps + +Not_on_Bound: + and CL,0C0H ; zero out sector # + + or CL,ah ; OR in new sector # + xor ah,ah ; AX = # of head wraps + inc ax + add al,DH ; add in starting head # + adc ah,0 ; catch any carry + CMP AX,[DI].HDLIM ; are we going to wrap around a head? + jbe No_Wrap_Head ; Do not lose new head number!! + + push DX ; preserve drive number and head number + xor dx,dx + mov bx,[DI].HDLIM + div bx ; DX=new head #, AX=# of cylinder wraps +; Careful here! If new head # is 0, then we are on the last head. + or dx,dx + jnz No_Head_Bound + + mov dx,bx ; On boundary. Set to HDLIM +; If we had some cylinder wraps, we need to reduce them by one!! + or ax,ax + jz No_Head_Bound + + dec ax ; Reduce number of cylinder wraps +No_Head_Bound: + mov bh,dl ; bh has new head number + POP DX ; restore drive number and head number + + dec bh ; get it 0-based + mov DH,bh ; set up new head number in DH + + mov bh,CL + and bh,3FH ; preserve sector number + mov bl,6 + xchg cl,bl + shr bl,cl ; get ms cylinder bits to ls end + + ADD CH,AL ; ADD IN CYLINDER WRAP + adc bl,ah ; add in high byte + shl bl,cl ; move up to ms end + xchg bl,cl ; restore cylinder bits into CL + or CL,bh ; OR in sector number + +No_Wrap: + clc ; reset carry + RestoreReg + RET + +No_Wrap_Head: + mov DH,al ; Do not lose new head number + dec DH ; get it 0-based + jmp short No_Wrap + +; +; INT_2F_13: +; This code is chained into the INT_2F interrupt during bios +; initialization. It allows the user to change the ORIG13 int_13 vector + +; INT_2F_13: +; This code is chained into the INT_2F interrupt during bios +; initialization. It allows the user to change the ORIG13 int_13 vector +; after booting. This allows testing and implementation of custom int_13 +; handlers, without giving up MS-DOS error recovery +; +; Entry Conditions +; AH == RESET_Int_13 (13h) +; DS:DX == Address of New INT_13 Handler +; ES:BX == Address of New INT_13 vector used by WARM BOOT +; (INT 19) +; +; Exit Conditions +; Orig13 == Address of new Int_13 Handler +; DS:DX == Old ORIG13 value +; ES:BX == Old OLD13 value + + ASSUME CS:CODE,DS:Nothing,ES:nothing,SS:NOTHING + + Public INT_2F_13 +INT_2F_13 Proc Far + + cmp AH,13h ; IF (interrupt_value != Reset_Int_13) + je Chg_Orig13 + jmp CS:[Next2f_13] ; THEN Continue on Int_2F chain + +Chg_Orig13: ; ELSE + push word ptr cs:[Orig13] ; Save Old value of OLD13 and + push word ptr cs:[Orig13 + 2]; ORIG13 so that we can + + Push word ptr cs:[OLD13] ; Return them to caller + Push word ptr cs:[OLD13 + 2] + + mov Word Ptr CS:[Orig13],DX ; Orig13 := Addr. Of New INT_13 + ; Vector + mov Word Ptr CS:[Orig13+2],DS + + mov Word Ptr CS:[Old13],BX ; Old13 := Addr. Of New + ; Boot_13 vector + mov Word Ptr CS:[Old13+2],ES + + pop ES ; ES:BX := Old OLD13 vector + pop BX + + pop DS ; DS:DX := Old ORIG13 vector + pop DX + + iret ; END else + +Int_2F_13 ENDP + + + + + + +Move Proc Near + push CX + mov CX,512/2 + cld + rep MOVSW + pop CX + ret +Move Endp + + + + +DoINT proc NEAR + mov DL,byte ptr [BP.olddx] + xor AH,AH + or AL,AL + jz DoIntDone + mov AH,BYTE PTR [BP.oldax+1] + push [BP.oldf] + call Orig13 + pushf + pop [BP.oldf] +DoIntDone: + ret +DoInt endp + +CODE ENDS + END diff --git a/SRC/BIOS/MSDISK.OBJ b/SRC/BIOS/MSDISK.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..78bc3dd668f00ebf0c6aa7347f409bba9d572681 GIT binary patch literal 7139 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 literal 0 HcmV?d00001 diff --git a/SRC/BIOS/MSEQU.INC b/SRC/BIOS/MSEQU.INC new file mode 100644 index 0000000..122c139 --- /dev/null +++ b/SRC/BIOS/MSEQU.INC @@ -0,0 +1,65 @@ + +; file: msequ.asm contains various equ's used in the bio. The values +; are explained below. +; + +;IBMCOPYRIGHT EQU 0 +fTOOBIG EQU 80h +fBIG EQU 40h +ROMStatus EQU 1 +ROMRead EQU 2 +ROMWrite EQU 3 +ROMVerify EQU 4 +ROMFormat EQU 5 +vid_size EQU 12 + +include msbds.inc ; various equates for bds +include version.inc + + +IF IBMCOPYRIGHT +SYSIZE=200H ;NUMBER OF PARAGRAPHS IN SYSINIT MODULE ;;Rev 3.30 Modification +ELSE +SYSIZE=203H +ENDIF +RSINIT=0A3H ; RS-232 initialization ;;End of Modification +LF=10 ; line feed +CR=13 ; carriage return +BACKSP=8 ; backspace +BRKADR=1BH * 4 ; 006C 1BH break vector address +TIMADR=1CH * 4 ; 0070 1CH timer interrupt +DSKADR=1EH * 4 ; address of ptr to disk parameters +SEC9=522H ; address of disk parameters +HEADSETTLE=SEC9+9 ; address of head settle time +NORMSETTLE=15 ; Normal head settle +SPEEDSETTLE=0 ; Speed up settle time +INITSPOT=534H ; IBM wants 4 zeros here +AKPORT=20H +EOI=20H +CMDLEN = 0 ; length of this command +UNIT = 1 ; sub unit specifier +CMD = 2 ; command code +STATUS = 3 ; status +MEDIA = 13 ; media descriptor +TRANS = 14 ; transfer address +COUNT = 18 ; count of blocks or characters +START = 20 ; first block to transfer +EXTRA = 22 ; usually a pointer to Vol Id for error 15 +CHROUT = 29H +MAXERR = 5 +LSTDRV = 504H + + ; location of boot sector on startup +BootBias = 200h + +NotBusyStatus = 10000000B ; not busy +AckStatus = 01000000B ; acknowledge (for what?) +NoPaperStatus = 00100000B ; No more paper +SelectedStatus = 00010000B ; The printer said it was selected +IOErrStatus = 00001000B ; Some kinda error +RESERVED = 00000110B ; NOPs +TimeOutStatus = 00000001B ; time out. + +PATHGEN = 1 + + \ No newline at end of file diff --git a/SRC/BIOS/MSEXTRN.INC b/SRC/BIOS/MSEXTRN.INC new file mode 100644 index 0000000..67e3288 --- /dev/null +++ b/SRC/BIOS/MSEXTRN.INC @@ -0,0 +1,72 @@ + +; +; file: msextrn.asm +; +; This file list the external variable used in the bio. +; + + EXTRN ORIG13:DWORD,ORIG19:DWORD + EXTRN COM2DEV:WORD,COM1DEV:WORD + EXTRN COM4DEV:WORD,COM3DEV:WORD ;3.30 + EXTRN LPT3DEV:WORD,LPT2DEV:WORD,LPT1DEV:WORD + EXTRN HARDDRV:BYTE,HARDNUM:BYTE,DRVMAX:BYTE,HDSKTAB:WORD + EXTRN DSKDRVS:WORD,HNUM:BYTE,EOT:BYTE,FHAVE96:BYTE + EXTRN REAL13:DWORD,DAYCNT:WORD,CONHeader:WORD + EXTRN TWOHARD:BYTE,INT_2F_NEXT:DWORD + EXTRN BDSH:WORD,BDSX:WORD,START_BDS:DWORD + EXTRN FHAVEK09:BYTE, NEW_ROM:BYTE + EXTRN Single:BYTE + EXTRN BDSMs:BYTE ;for Mini Disk 4/7/86 ;3.30 + EXTRN HaveCMOSClock:byte ;set by MSINIT. Used by MSCLOCK.AS;3.30 M + EXTRN BinToBCD:word ;set by MSINIT. Used by MSCLOCK.AS;3.30 M + EXTRN DaycntToDay:word ;set by MSINIT. Used by MSCLOCK.AS;3.30 M + + if test + IFNDEF NUMBUF ;3.30 + EXTRN NUMBUF:BYTE,DIGITS:BYTE,FTESTBITS:WORD + ENDIF ;3.30 + endif + + EXTRN START$:NEAR,ERROUT:NEAR,BLOCK13:FAR,INT19:FAR + EXTRN INTRET:NEAR,HDRIVE:NEAR,DRIVEX:NEAR,INT13:FAR,CBREAK:NEAR,OUTCHR:NEAR + EXTRN DISKRD:NEAR,MEDIA_PATCH:NEAR,GETBP1_PATCH:NEAR + EXTRN SET_PATCH:NEAR,DISKIO_PATCH:NEAR,DSKERR:NEAR,INIT_PATCH:NEAR + EXTRN TABLE_PATCH:NEAR,EXIT:NEAR,CHANGED_PATCH:NEAR + EXTRN ERRIN:NEAR,GETBP:NEAR,SWPDSK:NEAR ;3.30 + EXTRN OUTCHR:NEAR,WRMSG:NEAR,time_to_ticks:near + EXTRN INT2F_DISK:NEAR,INSTALL_BDS:NEAR,SETDRIVE:NEAR + + if test + IFNDEF NUMBUF ;3.30 + EXTRN MSGNUM:NEAR,MSGOUT:NEAR,dumpbytes:near,hex_to_ascii:near ;3.30 + EXTRN outchar:near ;3.30 + ENDIF ;3.30 + endif + +SYSINITSEG SEGMENT PUBLIC 'SYSTEM_INIT' + ASSUME CS:SYSINITSEG + + EXTRN CURRENT_DOS_LOCATION:WORD + EXTRN FINAL_DOS_LOCATION:WORD + EXTRN DEVICE_LIST:DWORD + EXTRN MEMORY_SIZE:WORD + EXTRN DEFAULT_DRIVE:BYTE + EXTRN BUFFERS:WORD + EXTRN SYSINIT:FAR +SYSINITSEG ENDS + + ASSUME CS:CODE ;3.30 + +; +; End of disk modules for configuration +; + EXTRN End96tpi:byte + EXTRN EndTwoHard:byte + EXTRN EndOneHard:byte + EXTRN EndSwap:byte + EXTRN EndFloppy:byte +; +; IBM fixed up AT ROM +; + EXTRN IBM_DISK_IO:FAR + diff --git a/SRC/BIOS/MSGROUP.INC b/SRC/BIOS/MSGROUP.INC new file mode 100644 index 0000000..ac6202d --- /dev/null +++ b/SRC/BIOS/MSGROUP.INC @@ -0,0 +1,46 @@ +EVBOUND = 1 ;THIS VALUE BEING 0 DOES NO BOUNDARY ALLIGNMENT, VALUE 1 ;3.30 + ; ALIGNS TO EVEN ;3.30 +; : : : : : : : : : : : : : : ;3.30 + IF EVBOUND ;;IF EVEN (WORD) ALLIGNMENT IS REQUESTED, ;3.30 +; : : : : : : : : : : : : : : ;3.30 +EVENB MACRO ;3.30 + EVEN ;;ADJUST TO EVEN BOUNDARY ;3.30 + ENDM ;3.30 + ;3.30 +ODD MACRO ;3.30 +;;GENERATE BOUNDARY PADDING TO FORCE ODD OFFSET ;3.30 + IF (($-CODE) MOD 2) EQ 0 ;3.30 + DB ? ;3.30 + ENDIF ;3.30 + ENDM ;3.30 + ;3.30 +CODE_SEGMENT MACRO ;3.30 +;;ALLIGN THE SEGMENT ON WORD BOUNDARY TO ALLOW FOR EVEN ALLIGNMENT OF DATA;3.30 +CODE SEGMENT WORD PUBLIC 'CODE' ;3.30 ;3.30 + ENDM ;3.30 + ;3.30 +; : : : : : : : : : : : : : : ;3.30 + ELSE ;;SINCE EVEN ALLIGNMENT IS NOT DESIRED, JUST USE BYTE ALLI;3.30 GNMENT +; : : : : : : : : : : : : : : ;3.30 + ;3.30 +EVENB MACRO ;3.30 +;;REQUEST FOR WORD ALLIGNMENT DOES NOTHING ;3.30 + ENDM ;3.30 + ;3.30 +ODD MACRO ;3.30 +;;REQUEST FOR ODD ALLIGNMENT DOES NOTHING ;3.30 + ENDM ;3.30 + ;3.30 +CODE_SEGMENT MACRO ;3.30 +;;SEGMENT IS ALLIGNED ON BYTE BOUNDARY FOR MINIMUM SIZE OF GENERATION ;3.30 +CODE SEGMENT BYTE PUBLIC 'CODE' ;3.30 + ENDM ;3.30 + ;3.30 +; : : : : : : : : : : : : : : ;3.30 + ENDIF ;3.30 +; : : : : : : : : : : : : : : ;3.30 + ;3.30 + CODE_SEGMENT ;3.30 + ASSUME CS:CODE ;3.30 + ;3.30 + \ No newline at end of file diff --git a/SRC/BIOS/MSHARD.ASM b/SRC/BIOS/MSHARD.ASM new file mode 100644 index 0000000..5ac9572 --- /dev/null +++ b/SRC/BIOS/MSHARD.ASM @@ -0,0 +1,418 @@ +;*** +; Title: Disk +; By: Michael Hanson +; C: Copyright (C) 1985-1987 by Microsoft corp. +; Date: 1/11/85 +; +; There is a bug in some versions of IBM's AT ROM BIOS +; interupts are not disabled during read operations. +; +; Use: This program should be chained in line with the disk +; interupt 13h, it intercepts read calls to the hard disk +; and handles them appropriately. For other functions it +; passes controll to OLD13, which should contain the +; address of the AT ROM disk routine. The entry point for +; this program is IBM_DISK_IO. +; + + + .286c ;Use 80286 non-protected mode + +BIOSEG = 040h ;Segment for ROM BIOS Data +ROMSEG = 0F000h ;Segment of ROM + + +BAD_DISK = 01 + +HF_PORT = 01F0h +HF_REG_PORT = 03F6h + +;* Offsets into Fixed disk parameter table +FDP_PRECOMP = 5 +FDP_CONTROL = 8 + +DATA SEGMENT AT BIOSEG ;ROM BIOS data segment + + ORG 42h +CMD_BLOCK DB 6 DUP (?) + +;* Offsets into CMD_BLOCK for registers +PRE_COMP = 0 ;Write Pre-compensation +SEC_CNT = 1 ;Sector count +SEC_NUM = 2 ;Sector number +CYL_LOW = 3 ;Cylinder number, low part +CYL_HIGH = 4 ;Cylinder number, high part +DRV_HEAD = 5 ;Drive/Head (Bit 7 = ECC mode, Bit 5 = 512 byte sectors, + ; Bit 4 = drive number, Bits 3-0 have head number) +CMD_REG = 6 ;Command register + + + ORG 074h + +DISK_STATUS1 DB ? +HF_NUM DB ? +CONTROL_BYTE DB ? + +DATA ENDS + + + +;*** Define where the ROM routines are actually located +ROM SEGMENT AT ROMSEG + + ORG 02E1Eh +ROMCOMMAND PROC FAR +ROMCOMMAND ENDP + + ORG 02E7Fh +ROMWAIT PROC FAR +ROMWAIT ENDP + + ORG 02EE2h +ROMWAIT_DRQ PROC FAR +ROMWAIT_DRQ ENDP + + ORG 02EF8h +ROMCHECK_STATUS PROC FAR +ROMCHECK_STATUS ENDP + + ORG 02F69h +ROMCHECK_DMA PROC FAR +ROMCHECK_DMA ENDP + + ORG 02F8Eh +ROMGET_VEC PROC FAR +ROMGET_VEC ENDP + + ORG 0FF65h +ROMFRET PROC FAR ;Far return at F000:FF65 in AT ROM. +ROMFRET ENDP + +ROM ENDS + + +CODE SEGMENT BYTE PUBLIC 'code' + +EXTRN OLD13:DWORD ;Link to AT bios int 13h + +PUBLIC IBM_DISK_IO + + + ASSUME CS:CODE + ASSUME DS:DATA + + +;*** IBM_DISK_IO - main routine, fixes AT ROM bug +; +; ENTRY: (AH) = function, 02 or 0A for read. +; (DL) = drive number (80h or 81h). +; (DH) = head number. +; (CH) = cylinder number. +; (CL) = Sector number (high 2 bits has cylinder number). +; (AL) = number of sectors. +; (ES:BX) = address of read buffer. +; For more on register contents see ROM BIOS listing. +; Stack set up for return by an IRET. +; +; EXIT: (AH) = status of current operation. +; (CY) = 1 IF failed, 0 if successful. +; For other register contents see ROM BIOS listing. +; +; USES: +; +; +; WARNING: Uses OLD13 vector for non-read calls. +; Does direct calls to the AT ROM. +; Does segment arithmatic. +; +; EFFECTS: Performs DISK I/O operation. +; +IBM_DISK_IO PROC FAR + CMP DL, 80h + JB ATD1 ;Pass through floppy disk calls. + CMP AH, 02 + JE ATD2 ;Intercept call 02 (read sectors). + CMP AH, 0Ah + JE ATD2 ;and call 0Ah (read long). +ATD1: + JMP OLD13 ;Use ROM INT 13h handler. +ATD2: + PUSH BX + PUSH CX + PUSH DX + PUSH DI + PUSH DS + PUSH ES + PUSH AX + MOV AX,BIOSEG ;Establish BIOS segment addressing. + MOV DS,AX + MOV DISK_STATUS1, 0 ;Initially no error code. + AND DL, 07fh ;Mask to hard disk number + CMP DL, HF_NUM + JB ATD3 ;Disk number in range + MOV DISK_STATUS1, BAD_DISK + JMP SHORT ATD4 ;Disk number out of range error, return + +ATD3: + PUSH BX + MOV AX, ES ;Make ES:BX to Seg:000x form. + SHR BX, 4 + ADD AX, BX + MOV ES, AX + POP BX + AND BX,000Fh + PUSH CS + CALL CHECK_DMA + JC ATD4 ;Abort if DMA across segment boundary + + POP AX ;Restore AX register for SETCMD + PUSH AX + CALL SETCMD ;Set up command block for disk op + MOV DX, HF_REG_PORT + OUT DX, AL ;Write out command modifier + CALL DOCMD ;Carry out command +ATD4: + POP AX + MOV AH,DISK_STATUS1 ;On return AH has error code + STC + OR AH,AH + JNZ ATD5 ;Carry set if error + CLC +ATD5: + POP ES + POP DS + POP DI + POP DX + POP CX + POP BX + RET 2 ;Far return, dropping flags +IBM_DISK_IO ENDP + + + +;*** SETCMD - Set up CMD_BLOCK for the disk operation +; +; ENTRY: (DS) = BIOS Data segment. +; (ES:BX) in seg:000x form. +; Other registers as in INT 13h call +; +; EXIT: CMD_BLOCK set up for disk read call. +; CONTROL_BYTE set up for disk operation. +; (AL) = Control byte modifier +; +; +; Sets the fields of CMD_BLOCK using the register contents +; and the contents of the disk parameter block for the given drive. +; +; WARNING: (AX) destroyed. +; Does direct calls to the AT ROM. +; +SETCMD PROC NEAR + MOV CMD_BLOCK[SEC_CNT], AL + MOV CMD_BLOCK[CMD_REG], 020h ;Assume function 02 + CMP AH, 2 + JE SETC1 ;CMD_REG = 20h if function 02 (read) + MOV CMD_BLOCK[CMD_REG], 022h ;CMD_REG = 22h if function 0A (" long) +SETC1: ;No longer need value in AX + MOV AL, CL + AND AL, 03fh ;Mask to sector number + MOV CMD_BLOCK[SEC_NUM], AL + MOV CMD_BLOCK[CYL_LOW], CH + MOV AL, CL + SHR AL, 6 ;Get two high bits of cylender number + MOV CMD_BLOCK[CYL_HIGH], AL + MOV AX, DX + SHL AL, 4 ;Drive number + AND AH, 0Fh + OR AL, AH ;Head number + OR AL, 0A0h ;Set ECC and 512 bytes per sector + MOV CMD_BLOCK[DRV_HEAD], AL + PUSH ES ;GET_VEC destroys ES:BX + PUSH BX + PUSH CS + CALL GET_VEC + MOV AX, ES:FDP_PRECOMP[BX] ;Write pre-comp from disk parameters + SHR AX, 2 + MOV CMD_BLOCK[PRE_COMP],AL ;Only use low part + MOV AL, ES:FDP_CONTROL[BX] ;Control byte modifier + POP BX + POP ES + MOV AH, CONTROL_BYTE + AND AH, 0C0h ;Keep disable retry bits + OR AH, AL + MOV CONTROL_BYTE, AH + RET +SETCMD ENDP + + + +;*** DOCMD - Carry out READ operation to AT hard disk +; +; ENTRY: (ES:BX) = address for read in data. +; CMD_BLOCK set up for disk read. +; +; EXIT: Buffer at (ES:BX) contains data read. +; DISK_STATUS1 set to error code (0 if success). +; +; +; +; WARNING: (AX), (BL), (CX), (DX), (DI) destroyed. +; No check is made for DMA boundary overrun. +; +; EFFECTS: Programs disk controller. +; Performs disk input. +; +DOCMD PROC NEAR + MOV DI, BX ;(ES:DI) = data buffer addr. + PUSH CS + CALL COMMAND + JNZ DOC3 +DOC1: + PUSH CS + CALL WAIT ;Wait for controller to complete read + JNZ DOC3 + MOV CX, 100h ;256 words per sector + MOV DX, HF_PORT + CLD ;String op goes up + CLI ;Disable interrupts (BUG WAS FORGETTING THIS) + REPZ INSW ;Read in sector + STI + TEST CMD_BLOCK[CMD_REG], 02 + JZ DOC2 ;No ECC bytes to read. + PUSH CS + CALL WAIT_DRQ + JC DOC3 + MOV CX, 4 ;4 bytes of ECC + MOV DX, HF_PORT + CLI + REPZ INSB ;Read in ECC + STI +DOC2: + PUSH CS + CALL CHECK_STATUS + JNZ DOC3 ;Operation failed + DEC CMD_BLOCK[SEC_CNT] + JNZ DOC1 ;Loop while more sectors to read +DOC3: + RET +DOCMD ENDP + + + +;*** GET_VEC - Get pointer to hard disk parameters. +; +; ENTRY: (DL) = Low bit has hard disk number (0 or 1). +; +; EXIT: (ES:BX) = address of disk parameters table. +; +; USES: AX for segment computation. +; +; Loads ES:BX from interrupt table in low memory, vector 46h (disk 0) +; or 70h (disk 1). +; +; WARNING: (AX) destroyed. +; This does a direct call to the AT ROM. +; +GET_VEC PROC NEAR + PUSH OFFSET ROMFRET + JMP ROMGET_VEC +GET_VEC ENDP + + + +;*** COMMAND - Send contents of CMD_BLOCK to disk controller. +; +; ENTRY: Control_byte +; CMD_BLOCK - set up with values for hard disk controller. +; +; EXIT: DISK_STATUS1 = Error code. +; NZ if error, ZR for no error. +; +; +; WARNING: (AX), (CX), (DX) destroyed. +; Does a direct call to the AT ROM. +; +; EFFECTS: Programs disk controller. +; +COMMAND PROC NEAR + PUSH OFFSET ROMFRET + JMP ROMCOMMAND +COMMAND ENDP + + + +;*** WAIT - Wait for disk interrupt +; +; ENTRY: Nothing. +; +; EXIT: DISK_STATUS1 = Error code. +; NZ if error, ZR if no error. +; +; +; WARNING: (AX), (BL), (CX) destroyed. +; Does a direct call to the AT ROM. +; +; EFFECTS: Calls int 15h, function 9000h. +; +WAIT PROC NEAR + PUSH OFFSET ROMFRET + JMP ROMWAIT +WAIT ENDP + + + +;*** WAIT_DRQ - Wait for data request. +; +; ENTRY: Nothing. +; +; EXIT: DISK_STATUS1 = Error code. +; CY if error, NC if no error. +; +; +; WARNING: (AL), (CX), (DX) destroyed. +; Does a direct call to the AT ROM. +; +WAIT_DRQ PROC NEAR + PUSH OFFSET ROMFRET + JMP ROMWAIT_DRQ +WAIT_DRQ ENDP + + + +;*** CHECK_STATUS - Check hard disk status. +; +; ENTRY: Nothing. +; +; EXIT: DISK_STATUS1 = Error code. +; NZ if error, ZR if no error. +; +; +; WARNING: (AX), (CX), (DX) destroyed. +; Does a direct call to the AT ROM. +; +CHECK_STATUS PROC NEAR + PUSH OFFSET ROMFRET + JMP ROMCHECK_STATUS +CHECK_STATUS ENDP + + + +;*** CHECK_DMA - check for DMA overrun 64k segment. +; +; ENTRY: (ES:BX) = addr. of memory buffer in seg:000x form. +; CMD_BLOCK set up for operation. +; +; EXIT: DISK_STATUS1 - Error code. +; CY if error, NC if no error. +; +; +; WARNING: Does a direct call to the AT ROM. +; +CHECK_DMA PROC NEAR + PUSH OFFSET ROMFRET + JMP ROMCHECK_DMA +CHECK_DMA ENDP + + +CODE ENDS + END diff --git a/SRC/BIOS/MSHARD.OBJ b/SRC/BIOS/MSHARD.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..4929245a8052818b5a97f76caddfa55b596bc0aa GIT binary patch literal 679 zcma)&O-mb56o%hBcQO-3F~Nc@2x_gQQf1O&SM8$4jKkQ%-H)i6~kdBNlae#!m=9m=lI%3`hB zR46WOSNCMI5zs_ug;YtovqPnruhx{vL&cast-8a_MpfHep`czmb!!SY+poR}wspwP zT1U@Mk7e;P70)D#J_+R#}OH6btoQXj&I;6NpC_r3q zn>7W_uQDq^cmivVunn=`RX!y|Azl!sAzpb{CKwQ}36l_S2vZR2gcz(1YIh($kWD~* zB)o+9+=jJ7e=4(f2>~X)Q*s(sgX|)+eiQncXi+i>n{FUwov)lw4%>duItYEb9rWx1 xVM(_ydDctV*X;q%t`JUid)TuP!sD>>wj1Cb@rgvnh^Ovm;z_#TpP~fh&jI!%x&Z(H literal 0 HcmV?d00001 diff --git a/SRC/BIOS/MSINIT.ASM b/SRC/BIOS/MSINIT.ASM new file mode 100644 index 0000000..5e4a840 --- /dev/null +++ b/SRC/BIOS/MSINIT.ASM @@ -0,0 +1,2213 @@ + +; modification history +; +; 3.21 sp added pushf-popf fix around NoParms to fix bug + +;;Rev 3.30 Modification ----------------------------------------------- + test = 0 + include msgroup.inc ;define code segment + include dskprm.inc + include msequ.inc + include msmacro.inc + include msextrn.inc + include biostruc.inc + include cmosequ.inc + + EXTRN OLD13:DWORD + +; THE FOLLOWING LABEL DEFINES THE END OF THE AT ROM PATCH. THIS IS USED +; AT CONFIGURATION TIME. +; Warning!!! This code will be dynamically relocated by MSINIT. + + PUBLIC ENDATROM ;NOT REFERENCES EXTERNALLY, BUT + ; JUST TO CAUSE ENTRY IN LINK MAP +ENDATROM LABEL BYTE + +;CMOS Clock setting support routines used by MSCLOCK. +;Warning!!! This code will be dynamically relocated by MSINIT. + + EXTRN base_century:byte + EXTRN base_year:byte + EXTRN month_tab:byte + + public Daycnt_to_day ;for real time clock support +Daycnt_to_day proc near ;for real time clock support +;Entry: [DAYCNT] = number of days since 1-1-80 +;Return: CH=centry in BCD, CL=year in BCD, DH=month in BCD, DL=day in BCD + + push [daycnt] ;save daycnt + cmp daycnt, (365*20+(20/4)) ;# days from 1-1-1980 to 1-1-2000 + jae century20 + mov base_century, 19 + mov base_year, 80 + jmp years +century20: ;20th century + mov base_century, 20 + mov base_year, 0 + sub daycnt, (365*20+(20/4)) ;adjust daycnt +years: + xor dx, dx + mov ax, daycnt + mov bx, (366+365*3) ;# of days in a Leap year block + div bx ;AX = # of leap block, DX=daycnt + mov daycnt, dx ;save daycnt left +; or ah, ah ;ax should be less than 256 +; jz OK1 +; jmp Erroroccur +;OK1: + mov bl,4 + mul bl ;AX=# of years. Less than 100 + add base_year, al ;So, ah = 0. Adjust year + inc daycnt ;set daycnt to 1 base + cmp daycnt, 366 ;daycnt=remainder of leap year bk + jbe Leapyear ;within 366+355+355+355 days. + inc base_year ;if daycnt <= 366, then leap year + sub daycnt, 366 ;else daycnt--, base_year++; + ;And next three years are normal + mov cx, 3 +Regularyear: + cmp daycnt, 365 ;for(i=1; i>3 or daycnt <=365;i++) + jbe YearDone ;{if (daycnt > 365) + inc base_year ; { daycnt -= 365 + sub daycnt, 365 ; } + loop regularyear ;} +; jmp Erroroccur ;cannot come to here +Leapyear: + mov byte ptr month_tab+1,29 ;leap year. change month table. +Yeardone: + xor bx,bx + xor dx,dx + mov ax, daycnt + mov si, offset month_tab + mov cx, 12 +Months: + inc bl ; + mov dl, byte ptr ds:[si] ;cmp daycnt for each month til fit + cmp ax, dx ;dh=0. + jbe Month_done + inc si ;next month + sub ax, dx ;adjust daycnt + loop Months +; jmp Erroroccur +Month_done: + mov byte ptr month_tab+1, 28 ;restore month table value + mov dl, bl + mov dh, base_year + mov cl, base_century ;al=day,dl=month,dh=year,cl=cntry + call word ptr BinToBCD ;To save 15 bytes, Bin_To_BCD proc + ;was rel from Daycnt_to_Day proc. +; call Bin_to_bcd ;convert "day" to bcd + xchg dl, al ;dl = bcd day, al = month + call word ptr BinToBCD +; call Bin_to_bcd + xchg dh, al ;dh = bcd month, al = year + call word ptr BinToBCD +; call Bin_to_bcd + xchg cl, al ;cl = bcd year, al = century + call word ptr BinToBCD +; call Bin_to_bcd + mov ch, al ;ch = bcd century + pop [daycnt] ;restore original value + ret +Daycnt_to_day endp + + public EndDaycntToDay +EndDaycntToDay label byte + + public Bin_to_bcd +Bin_to_bcd proc near ; real time clock sup +;Convert a binary input in AL (less than 63h or 99 decimal) +;into a bcd value in AL. AH destroyed. + push cx + xor ah, ah + mov cl, 10 + div cl ;al=high digit bcd, ah=low digit bcd + mov cl, 4 + shl al, cl ;mov the high digit to high nibble + or al, ah + pop cx + ret +Bin_to_bcd endp + + Public EndCMOSClockset ;End of routines for CMOS clock +EndCMOSClockset label byte +; + + EXTRN INT6C_RET_ADDR:DWORD ; RETURN ADDRESS FROM INT 6C + EXTRN BIN_DATE_TIME:BYTE + EXTRN MONTH_TABLE:WORD + EXTRN DAYCNT2:WORD + EXTRN FEB29:BYTE + EXTRN TimeToTicks:Word ;indirect intra-segment call add + + EVENB +; +; THE K09 REQUIRES ROUTINES FOR READING THE CLOCK BECAUSE OF THE SUSPEND/ +; RESUME FACILITY. THE SYSTEM CLOCK NEEDS TO BE RESET AFTER RESUME. +; + ASSUME ES:NOTHING + +; THE FOLLOWING ROUTINE IS EXECUTED AT RESUME TIME WHEN THE SYSTEM +; POWERED ON AFTER SUSPENSION. IT READS THE REAL TIME CLOCK AND +; RESETS THE SYSTEM TIME AND DATE, AND THEN IRETS. +; Warning!!! This code will be dynamically relocated by MSINIT. +INT6C PROC FAR + PUSH CS + POP DS + + ASSUME DS:CODE + + POP WORD PTR INT6C_RET_ADDR ; POP OFF RETURN ADDRESS + POP WORD PTR INT6C_RET_ADDR+2 + POPF + CALL READ_REAL_DATE ; GET THE DATE FROM THE CLOCK + CLI + MOV DS:DAYCNT,SI ; UPDATE DOS COPY OF DATE + STI + CALL READ_REAL_TIME ; GET THE TIME FROM THE RTC + CLI + MOV AH, 01h ; COMMAND TO SET THE TIME + INT 1Ah ; CALL ROM-BIOS TIME ROUTINE + STI + JMP INT6C_RET_ADDR ; LONG JUMP + +INT6C ENDP + + + INCLUDE READCLOCK.INC + INCLUDE CLOCKSUB.INC + + PUBLIC ENDK09 ;NOT REFERENCES EXTERNALLY, BUT + ; JUST TO CAUSE ENTRY IN LINK MAP +ENDK09 LABEL BYTE + ASSUME DS:NOTHING,ES:NOTHING +;;End of Modification ----------------------------------------------- + +;------------------------------------------------------------------------ +; : +; System initiailzation : +; : +; The entry conditions are established by the bootstrap : +; loader and are considered unknown. The following jobs : +; will be performed by this module: : +; : +; 1. All device initialization is performed : +; 2. A local stack is set up and DS:SI are set : +; to point to an initialization table. Then : +; an inter-segment call is made to the first : +; byte of the dos : +; 3. Once the dos returns from this call the ds : +; register has been set up to point to the start : +; of free memory. The initialization will then : +; load the command program into this area : +; beginning at 100 hex and transfer control to : +; this program. : +; : +;------------------------------------------------------------------------ + +; DRVFAT must be the first location of freeable space! + EVENB +DRVFAT DW 0000 ; Drive and FAT ID of DOS +BIOS$ DW 0000 ; First sector of data +DOSCNT DW 0000 ; How many sectors to read +fBigFAT DB 0 ; Flags for drive +FatLen DW ? ; number of sectors in FAT. +FatLoc DW ? ; seg addr of fat sector + +;;Rev 3.30 Modification ----------------------------------------------- +; THE FOLLOWING TWO BYTES ARE USED TO SAVE INFO RETURNED BY INT 13, AH=8 +; CALL TO DETERMINE DRIVE PARAMETERS. +NUM_HEADS DB 2 ; NUMBER OF HEADS RETURNED BY ROM +SEC_TRK DB 9 ; SEC/TRK RETURNED BY ROM +NUM_CYLN DB 40 ; NUMBER OF CYLINDERS RET BY ROM + + public Model_Byte +MODEL_BYTE DB 0FFH ; MODEL BYTE. SET UP AT INIT TIME. + ; FF - PC-1, EXPANSION, OLD PC-2 + ; FE - NEWER PC-2 (64/256K PLANAR) + ; FD - + ; FC - + public Secondary_Model_Byte +Secondary_Model_Byte db 0 +;;End of Modification ----------------------------------------------- + +BOOTBIAS = 200H + EVENB +DiskTable DW 512, 0100h, 64, 0 + DW 2048, 0201h, 112, 0 + DW 8192, 0402h, 256, 0 + DW 32680, 0803h, 512, 0 + DW 65535, 1004h, 1024, 0 + +DiskTable2 DW 32680, 0803h, 512, 0 + DW 65535, 0402h, 512, fBIG + +;;Rev 3.30 Modification ----------------------------------------------- +;************************************************************************* +;Variables for Mini disk initialization +;************************************************************************* +End_Of_BDSM dw ? ;offset value of the ending add + ;of BDSM table. Needed to figure + ;the Final_DOS_Location. +numh db 0 ;number of hard files +mininum db 0 ;logical drive num for mini disk +num_mini_dsk db 0 ;# of mini disk installed +Rom_Minidsk_num db 80h ;physical mini disk number +Mini_HDLIM dw 0 +Mini_SECLIM dw 0 +Mini_BPB_ptr dw 0 ;temporary variable used to save + ;Mini Disk BPB pt add in DskDrvs. +;;End of Modification ----------------------------------------------- + +Bios_Date DB '01/10/84',0 + +; +; The following are the recommended BPBs for the media that we know of so +; far. + +; 48 tpi diskettes + EVENB +BPB48T DW 512 + DB 2 + DW 1 + DB 2 + DW 112 + DW 2*9*40 + DB 0FDH + DW 2 + DW 9 + DW 2 + DD 0 ;hidden sectors - sp + DD 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved + +; 96tpi diskettes + EVENB +BPB96T DW 512 + DB 1 + DW 1 + DB 2 + DW 224 + DW 2*15*80 + DB 0f9H + DW 7 + DW 15 + DW 2 + DD 0 ;hidden sectors - sp + DD 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved + +BPBSIZ = $-BPB96T + +; 3 1/2 inch diskette BPB + EVENB +BPB35 DW 512 + DB 2 + DW 1 ; Double sided with 9 sec/trk + DB 2 + DW 70h + DW 2*9*80 + DB 0f9H + DW 3 + DW 9 + DW 2 + DD 0 ;hidden sectors - sp + DD 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved + + + EVENB +BPBTable dw BPB48T ; 48tpi drives + dw BPB96T ; 96tpi drives + dw BPB35 ; 3.5" drives + ;dw BPB48T ; Not used - 8" drives + ;dw BPB48T ; Not Used - 8" drives + ;dw BPB48T ; Not Used - hard files + ;dw BPB48T ; Not Used - tape drives + ;dw BPB48T ; Not Used - Other + +PatchTable LABEL BYTE + DW 10,media_patch + DW 3,getbp1_patch + DW 3,SET_PATCH + DW 3,DiskIO_Patch + DW 3,DSKErr + DW 10,Changed_Patch + DW 3,INIT_PATCH + DW 0 + + ASSUME DS:NOTHING,ES:NOTHING + +; +; Entry from boot sector. The register contents are: +; DL = INT 13 drive number we booted from +; CH = media byte +; BX = First data sector on disk (0-based) +; +Public INIT +INIT PROC NEAR + MESSAGE FTESTINIT,<"MSBIO",CR,LF> ;3.30 + CLI + XOR AX,AX + MOV DS,AX +; +; Preserve original int 13 vector +; We need to save INT13 in two places in case we are running on an AT. +; On ATs we install the IBM supplied ROM_BIOS patch DISK.OBJ which hooks +; INT13 ahead of ORIG13. Since INT19 must unhook INT13 to point to the +; ROM INT13 routine, we must have that ROM address also stored away. +; + MOV AX,DS:[13h*4] + MOV WORD PTR Old13,AX + MOV WORD PTR Orig13,AX + MOV AX,DS:[13h*4+2] + MOV WORD PTR Old13+2,AX + MOV WORD PTR Orig13+2,AX +; +; Set up INT 13 for new action +; + MOV WORD PTR DS:[13h*4],OFFSET Block13 + MOV DS:[13h*4+2],CS +; +; Preserve original int 19 vector +; + MOV AX,DS:[19h*4] + MOV WORD PTR Orig19,AX + MOV AX,DS:[19h*4+2] + MOV WORD PTR Orig19+2,AX +; +; Set up INT 19 for new action +; + MOV WORD PTR DS:[19h*4],OFFSET int19 + MOV DS:[19h*4+2],CS + STI + + + int 11h ; rom-bios equipment determination + ROL AL,1 ;PUT BITS 6 & 7 INTO BITS 0 & 1 + ROL AL,1 + AND AX,3 ;ONLY LOOK AT BITS 0 & 1 + JNZ NOTSINGLE ;ZERO MEANS SINGLE DRIVE SYSTEM + INC AX ;PRETEND IT'S A TWO DRIVE SYSTEM + INC CS:SINGLE ;REMEMBER THIS +NOTSINGLE: + INC AX ;AX HAS NUMBER OF DRIVES, 2-4 + ;IS ALSO 0 INDEXED BOOT DRIVE IF WE + ; BOOTED OFF HARD FILE + mov CL, AL ; save number of diskette drives in CL + test DL, 80h ; booted from hard disk ? + jnz GotHrd ; yes, jump down + xor AX, AX ; no - indicate boot from drive A +GotHrd: + + ; At this point the registers contain these values: + ; AX = 0-based drive we booted from + ; BX = the logical number of the first data sector on the disk + ; CL = number of floppies including logical one + ; CH = media byte + ; + + Message fTestINIT,<"Init",CR,LF> + +; +; set up local stack +; + xor DX,DX + cli ; turn interrupts off while manupulating stack + mov SS,DX ; set stack segment register + mov SP,700h ; set stack pointer + sti ; turn interrupts on +ASSUME SS:NOTHING + + ; preserve some of the values in registers + + push CX ; save number of floppies and media byte + mov BIOS$,BX ; save first data sector + mov AH,CH ; FAT ID to AH too + push AX ; save boot drive number, and media byte +;;Rev 3.30 Modification ----------------------------------------------- +; Let Model_byte, Secondary_Model_Byte be set here!!! + mov ah,0c0h ; return system environment + int 15h ; call ROM-Bios routine + jc No_Rom_System_Conf ; just use Model_Byte + cmp ah, 0 ; double check + jne No_Rom_System_Conf + mov al, ES:[BX.bios_SD_modelbyte] ;get the model byte + mov [Model_Byte], al + mov al, ES:[BX.bios_SD_scnd_modelbyte] ;secondary model byte + mov [Secondary_Model_Byte], al + jmp short Turn_Timer_On +No_Rom_System_Conf: + MOV SI,0FFFFH ;MJB001 + MOV ES,SI ;MJB001 + MOV AL,ES:[0EH] ; GET MODEL BYTE ARR 2.41 + MOV MODEL_BYTE,AL ; SAVE MODEL BYTE ARR 2.41 +;;End of Modification ----------------------------------------------- +Turn_Timer_On: + mov AL,EOI + out AKPORT,AL ; turn on the timer + + Message fTestINIT,<"COM devices",CR,LF> + +;;Rev 3.30 Modification ----------------------------------------------- + mov si,offset COM4DEV + call AUX_INIT + mov si,offset COM3DEV + call AUX_INIT +;;End of Modification ----------------------------------------------- + mov SI,OFFSET COM2DEV + call AUX_INIT ;INIT COM2 + mov SI,OFFSET COM1DEV + call AUX_INIT ;INIT COM1 + + Message fTestINIT,<"LPT devices",CR,LF> + mov SI,OFFSET LPT3DEV + call PRINT_INIT ;INIT LPT3 + mov SI,OFFSET LPT2DEV + call PRINT_INIT ;INIT LPT2 + mov SI,OFFSET LPT1DEV + call PRINT_INIT ;INIT LPT1 + + xor DX,DX + mov DS,DX ;TO INITIALIZE PRINT SCREEN VECTOR + mov ES,DX + + xor AX,AX + mov DI,INITSPOT + stosw ;INIT four bytes to 0 + stosw + + mov AX,CS ;FETCH SEGMENT + + mov DS:WORD PTR BRKADR,OFFSET CBREAK ;BREAK ENTRY POINT + mov DS:BRKADR+2,AX ;VECTOR FOR BREAK + + mov DS:WORD PTR CHROUT*4,OFFSET WORD PTR OUTCHR + mov DS:WORD PTR CHROUT*4+2,AX + + Message fTestINIT,<"Interrupt vectors",CR,LF> + mov DI,4 + mov BX,OFFSET INTRET ;WILL INITIALIZE REST OF INTERRUPTS + xchg AX,BX + stosw ;Location 4 + xchg AX,BX + stosw ;INT 1 ;Location 6 + add DI,4 + xchg AX,BX + stosw ;Location 12 + xchg AX,BX + stosw ;INT 3 ;Location 14 + xchg AX,BX + stosw ;Location 16 + xchg AX,BX + stosw ;INT 4 ;Location 18 + + mov DS:WORD PTR 500H,DX ;SET PRINT SCREEN & BREAK =0 + mov DS:WORD PTR LSTDRV,DX ;clean out last drive spec + + Message fTestINIT,<"Disk parameter table",CR,LF> + + mov SI,WORD PTR DS:DSKADR ; ARR 2.41 + mov DS,WORD PTR DS:DSKADR+2 ; DS:SI -> current table ARR 2.41 + + mov DI,SEC9 ; ES:DI -> New Table ARR 2.41 + mov CX,SIZE DISK_PARMS ; ARR 2.41 + rep MOVSB ; Copy Table ARR 2.41 + push ES ; ARR 2.41 + pop DS ; DS = 0 ARR 2.41 + + mov WORD PTR DS:DSKADR,SEC9 ; ARR 2.41 + mov WORD PTR DS:DSKADR+2,DS ; Point disk parm vector to new table + ; ARR 2.41 + + +;----------------------------------------------- +; +; THE FOLLOWING DEPEND ON THE TYPE OF MACHINE. +; + CMP MODEL_BYTE,0FDH ; IS THIS AN OLD ROM? ARR 2.41 + JB NO_DIDDLE ; NO ARR 2.41 + MOV WORD PTR DS:(SEC9 + DISK_HEAD_STTL),0200H+NORMSETTLE + ; SET HEAD SETTLE AND MOTOR START + ; ON PC-1 PC-2 PC-XT HAL0 ARR 2.41 + MOV DS:(SEC9 + DISK_SPECIFY_1),0DFH + ; SET 1ST SPECIFY BYTE + ; ON PC-1 PC-2 PC-XT HAL0 ARR 2.41 +NO_DIDDLE: ; ARR 2.41 + int 12h ; call rom-bios for memory size + mov CL, 6 ; get ready for shift + shl AX, CL ; change from K to 16 byte blocks + pop CX ; restore CX + mov DRVFAT, CX + push AX + mov dx,ds:(7C00h + 16h) ; number of sectors/fat from boot sec + xor dh,dh + mov FatLen,DX +; +; Convert sector count to paragraph count:512 bytes / sec / 16 bytes / para +; = 32 para /sector +; +;;Rev 3.30 Modification ----------------------------------------------- + SHL DX,1 + SHL DX,1 + SHL DX,1 + SHL DX,1 + SHL DX,1 +;;End of Modification ----------------------------------------------- + SUB AX,dx ; room for FAT + MOV FatLoc,AX ; location to read fat + POP AX + + MOV DX,SYSINITSEG + MOV DS,DX + + ASSUME DS:SYSINITSEG + + MOV WORD PTR DEVICE_LIST,OFFSET CONHeader + MOV WORD PTR DEVICE_LIST+2,CS + +; Allocation of buffers has moved to SYSINIT - Aug 19/85 BAS + +;DEF_BUFF: + + MOV MEMORY_SIZE,AX + INC CL + MOV DEFAULT_DRIVE,CL ;SAVE DEFAULT DRIVE SPEC + +;DOSSEG = ((((OFFSET END$)-(OFFSET START$))+15)/16)+BIOSEG+SYSIZE + +; BAS DEBUG +;MOV CURRENT_DOS_LOCATION,((((OFFSET END$)-(OFFSET START$))+15)/16)+SYSIZE + MOV AX, OFFSET END$ + SUB AX, OFFSET START$ + ADD AX, 15 + RCR AX, 1 ; DIVIDE BY 16 + SHR AX, 1 + SHR AX, 1 + SHR AX, 1 + ADD AX, SYSIZE + ADD AX, CODE + MOV Current_DOS_Location, AX +; BAS DEBUG +; ADD Current_DOS_Location,CODE + +; +; IMPORTANT: Some old IBM hardware generates spurious INT F's due to bogus +; printer cards. We initialize this value to point to an IRET ONLY IF +; +; 1) The original segment points to storage inside valid RAM. +; +; 2) The original segment is 0F000:xxxx +; +; Theses are capricious requests from our OEM for reasons behind them, read +; the DCR's for the IBM DOS 3.2 project. +; + push ax + +ASSUME ES:SYSINITSEG, DS:NOTHING + mov ax,SYSINITSEG + mov es,ax + xor ax,ax + mov ds,ax + + mov ax,word ptr ds:(0fH*4+2) ; segment for Int 15 + + cmp ax,es:MEMORY_SIZE ; Condition 1 + jna ResetIntF + + cmp ax, 0F000h ; Condition 2 + jne KeepIntF + +ResetIntF: + mov word ptr ds:[0FH*4],offset INTRET + mov word ptr ds:[0FH*4+2],cs + +KeepIntF: + pop ax +; +; END IMPORTANT +; + +;************************************************************** +; WILL INITIALIZE THE NUMBER OF DRIVES +; AFTER THE EQUIPMENT CALL (INT 11H) BITS 6&7 WILL TELL +; THE INDICATIONS ARE AS FOLLOWS: +; +; BITS 7 6 DRIVES +; 0 0 1 +; 0 1 2 +; 1 0 3 +; 1 1 4 +;************************************************************** + PUSH CS + POP DS + PUSH CS + POP ES + + ASSUME DS:CODE,ES:CODE + + call CMOS_Clock_Read ;Before doing anything if CMOS clock, + ;then set the system time accordingly. + ;Also, reset the cmos clock rate. + + Message fTestINIT,<"Disk devices",CR,LF> + + XOR SI,SI + MOV WORD PTR [SI],OFFSET HARDDRV ;set up pointer to hdrive + + POP AX ;number of floppies and FAT ID + XOR AH,AH ; Chuck FAT ID byte + MOV HARDNUM,AL ;Remember which drive is hard disk + MOV DRVMAX,AL ;And set initial number of drives + SHL AX,1 ;Two bytes per address + MOV DI,OFFSET DSKDRVS + ADD DI,AX ;Point to hardfile location + MOV SI,OFFSET HDSKTAB + MOVSW ;Two addresses to move + MOVSW + MESSAGE FTESTINIT,<"BEFORE INT 13",CR,LF> + mov DL, 80h ; tell rom bios to look at hard drives + mov AH, 8h ; set command to get drive parameter + int 13h ; call ROM-BIOS to get number of drives + jc ENDDRV ; old, rom therefore no hard disks + mov HNUM, DL ; save number of hard drives in HNUM + +ENDDRV: + Message fTestINIT,<"Setting up BDSs",CR,LF> + +; +; Scan the list of drives to determine their type. We have three flavors of +; diskette drives: +; +; 48tpi drives We do nothing special for them +; 96tpi drives Mark the fact that they have changeline support. +; 3 1/4 drives Mark changeline support and small. +; +; The following code uses registers for certain values: +; DL - Physical Drive +; DS:DI - points to current BDS +; CX - Flag bits for BDS +; DH - Form Factor for the drive (1 - 48tpi, 2 - 96tpi, 3 - 3.5" medium) +; + XOR DL,DL ; start out with drive 0. + push cs + pop ds + ASSUME DS:CODE + MOV EOT,9 + mov di,offset Start_BDS +loop_drive: + cmp dl,drvmax + jb got_more + jmp Done_Drives +got_more: + xor cx,cx ; zero all flags + mov di,word ptr [di].link ; get next BDS + mov dh,ff48tpi ; Set Form Factor to 48 tpi + MOV NUM_CYLN,40 ; 40 TRACKS PER SIDE + + PUSH DS + PUSH DI + PUSH DX + PUSH CX + PUSH ES + + MOV AH, 8h ;GET DRIVE PARAMETERS + INT 13h ;CALL ROM-BIOS + JNC PARMSFROMROM + JMP NOPARMSFROMROM ; GOT AN OLD ROM +PARMSFROMROM: +;If CMOS is bad, it gives ES,AX,BX,CX,DH,DI=0. CY=0. +;In this case, we are going to put bogus informations to BDS table. +;We are going to set CH=39,CL=9,DH=1 to avoid divide overflow when +;they are calculated at the later time. This is just for the Diagnostic +;Diskette which need IO.SYS,MSDOS to boot up before it sets CMOS. +;This should only happen with drive B. + +;;Rev 3.30 Modification ----------------------------------------------- + CMP CH,0 ; if ch=0, then cl,dh=0 too. + JNE PFR_OK + MOV CH,39 ; ROM gave wrong info. + MOV CL,9 ; Let's default to 360K. + MOV DH,1 +PFR_OK: + INC DH ; MAKE NUMBER OF HEADS 1-BASED + INC CH ; MAKE NUMBER OF CYLINDERS 1-BASED + MOV NUM_HEADS,DH ; SAVE PARMS RETURNED BY ROM + AND CL,00111111B ; EXTRACT SECTORS/TRACK + MOV SEC_TRK,CL + MOV NUM_CYLN,CH ; ASSUME LESS THAN 256 CYLINDERS!! +; MAKE SURE THAT EOT CONTAINS THE MAX NUM OF SEC/TRK IN SYSTEM OF FLOPPIES + CMP CL,EOT ; MAY SET CARRY + JBE EOT_OK + MOV EOT,CL +EOT_OK: + POP ES + POP CX + POP DX + POP DI + POP DS + +; +; Check for presence of changeline +; + mov AH, 15h ; set command to get DASD type + int 13h ; call ROM-BIOS + JC CHANGELINE_DONE + CMP AH,02 ; CHECK FOR PRESENCE OF CHANGELINE + JNE CHANGELINE_DONE +;;End of Modification ----------------------------------------------- +; +; We have a drive with change line support. +; + Message fTestINIT,<"96tpi devices",CR,LF> + + or CL,fChangeLine ; signal type + mov fHave96,1 ; Remember that we have 96tpi disks +; ;3.30 +; WE NOW TRY TO SET UP THE FORM FACTOR FOR THE TYPES OF MEDIA THAT WE KNOW;3.30 +; AND CAN RECOGNISE. FOR THE REST, WE SET THE FORM FACTOR AS "OTHER". ;3.30 +; ;3.30 +CHANGELINE_DONE: ;3.30 +; 40 CYLINDERS AND 9 OR LESS SEC/TRK, TREAT AS 48 TPI MEDIUM. ;3.30 + CMP NUM_CYLN,40 ;3.30 + JNZ TRY_80 ;3.30 + CMP SEC_TRK,9 ;3.30 + JBE GOT_FF ;3.30 +GOTOTHER: ;3.30 + MOV DH,FFOTHER ; WE HAVE A "STRANGE" MEDIUM ;3.30 + JMP SHORT GOT_FF ;3.30 + ;3.30 +; ;3.30 +; 80 CYLINDERS AND 9 SECTORS/TRACK => 720 KB DEVICE ;3.30 +; 80 CYLINDERS AND 15 SEC/TRK => 96 TPI MEDIUM ;3.30 +; ;3.30 +TRY_80: ;3.30 + CMP NUM_CYLN,80 ;3.30 + JNZ GOTOTHER ;3.30 + CMP SEC_TRK,15 ;3.30 + JZ GOT96 ;3.30 + CMP SEC_TRK,9 ;3.30 + JNZ GOTOTHER ;3.30 + MOV DH,FFSMALL ;3.30 + JMP SHORT GOT_FF ;3.30 + ;3.30 +GOT96: ;3.30 + MOV DH,FF96TPI ;3.30 + ;3.30 +GOT_FF: ;3.30 + JMP SHORT NEXTDRIVE ;3.30 + ;3.30 +; AN OLD ROM, SO WE EITHER HAVE A 48TPI OR 96TPI DRIVE. IF THE DRIVE ;3.30 +; HAS CHANGELINE, WE ASSUME IT IS A 96TPI, OTHERWISE IT IS A 48TPI. ;3.30 + ;3.30 +NOPARMSFROMROM: ;3.30 + POP ES ;3.30 + POP CX ;3.30 + POP DX ;3.30 + POP DI ;3.30 + POP DS ;3.30 + ;3.30 + MOV AH, 15h ; SET COMMAND TO GET DASD TYPE ;3.30 + INT 13h ; CALL ROM-BIOS ;3.30 + JC NEXTDRIVE ;3.30 + CMP AH,2 ; IS THERE CHANGELINE? ;3.30 + JNZ NEXTDRIVE ;3.30 + OR CL,FCHANGELINE ;3.30 + MOV FHAVE96,1 ; REMEMBER WE HAVE 96TPI DRIVES ;3.30 + MOV NUM_CYLN,80 ;3.30 + MOV DH,FF96TPI ;3.30 + MOV AL,15 ; SET EOT IF NECESSARY ;3.30 + CMP AL, EOT ;3.30 + JBE EOT_OK2 ;3.30 + MOV EOT,AL ;3.30 +EOT_OK2: ;3.30 + +NextDrive: + or cl,fI_Own_Physical ; set this true for all drives + mov bh,dl ;save Int13 drive number +; +; We need to do special things if we have a single drive system and are setting +; up a logical drive. It needs to have the same Int13 drive number as its +; counterpart, but the next drive letter. Also reset ownership flag. +; We detect the presence of this situation by examining the flag SINGLE for the +; value 2. +; + cmp single,2 + jnz Not_Special + dec bh ; Int13 drive number same for logical drive + xor cl,fI_Own_Physical ; reset ownership flag for logical drive +Not_Special: +; The values that we put in for RHdlim and RSeclim will only remain if the +; form factor is of type "ffOther". + xor ax,ax ; fill BDS for drive + mov al,num_heads + mov word ptr [di].RHdlim,ax + mov al,sec_trk + mov word ptr [di].RSeclim,ax + mov word ptr [di].flags,cx + mov byte ptr [di].FormFactor,dh + mov byte ptr [di].DriveLet,dl + mov byte ptr [di].DriveNum,bh + MOV BL,BYTE PTR NUM_CYLN ;3.30 + mov byte ptr [di].cCyln,bl ; only the l.s. byte is set here + cmp single,1 ; Special case for single drive system + jnz No_Single + message fTestINIT,<"Single Drive System",CR,LF> + ; Don't forget we have + mov single,2 ; single drive system + or cx,fI_Am_Mult ; set that this is one of + ; several drives + or word ptr [di].flags,cx ; save flags + mov di,word ptr [di].link ; move to next BDS in list + inc dl ; add a number + jmp short NextDrive ; Use same info for BDS as previous + + + +No_Single: + inc dl + jmp loop_drive + +Done_Drives: + mov ax,-1 ; Signify end of list by + mov word ptr [di].link,ax ; setting pointer to -1 +; +; Set up all the hard drives in the system +; +DoHard: + MNUM fTestINIT+fTestHARD,AX + Message fTestINIT+fTestHARD,<" Hard disk(s) to initialize",CR,LF> + Message fTestINIT+fTestHARD,<"Hard disk 1",CR,LF> + + CMP HNUM,0 ; IF (No_Hard_files) + JLE STATIC_CONFIGURE ; THEN EXIT TO CONFIGURE ;3.30 + mov DL, 80h ; set first hard file number + mov di,offset BDSH ; Set up first hard file. + mov bl,HARDNUM + call SETHARD + jnc HardFile1_OK + + dec HNUM ; First hard file is bad. + cmp HNUM,0 ; IF (Second_Hard_File) + jg Second_Hard ; THEN Set up second hard file + JMP SHORT STATIC_CONFIGURE ;3.30 + +HardFile1_OK: + call Install_BDS ; install BDS into linked list + cmp HNUM,2 ; IF (Only_one_hardfile) + jb SetIt ; THEN SetIt "in place" + + mov bl,HARDNUM + inc BL ; next drive letter + mov di,offset BDSX + +Second_Hard: ; SETUP Second Hard FILE + + Message fTestINIT+fTestHARD,<"Hard disk 2",CR,LF> + mov DL, 81h ; set second hard file number + call SETHARD + jnc HardFile2_OK + dec HNUM + jmp short SetIt + +HardFile2_OK: + Call Install_BDS + +SETIT: + mov al,HNUM + or al,al + JZ STATIC_CONFIGURE ;3.30 + add al,HARDNUM + mov DRVMAX,al + +; End of physical drive initialization. ;3.30 +; *** Do not change the position of the following statement. +; *** DoMini routine will use [DRVMAX] value for the start of the logical ;3.30 +; *** drive number of Mini disk(s). ;3.30 + ;3.30 + call DoMini ;For setting up mini disks, if found -;3.30 + +; End of drive initialization. + +;9/24/86 We now decide, based on the configurations available so far,;3.30 +;what code or data we need to keep as a stay resident code. The following;3.30 +;table shows the configurations under consideration. They are listed in ;3.30 +;the order of their current position memory. ;3.30 +;Configuration will be done in two ways: ;3.30 +;First, we are going to set "Static configuration". Static configuration ;3.30 +;will consider from basic configuration to ENDOF96TPI configuration. ;3.30 +;The result of static configuration will be the address the Dynamic ;3.30 +;configuration will use to start with. ;3.30 +;Secondly, "Dynamic cofiguration" will be performed. Dynamic configuration;3.30 +;involves possible relocation of CODE/DATA. Dynamic configuration routine ;3.30 +;will take care of BDSM tables and AT ROM Fix module thru K09 suspend/res ;3.30 +;code individually. After these operation, FINAL_DOS_LOCATION will be set.;3.30 +;This will be the place SYSINIT routine will relocate MSDOS module. ;3.30 +; ;3.30 +; 1. BASIC CONFIGURATION FOR MSBIO (EndFloppy, EndSwap) ;3.30 +; 2. ENDONEHARD ;3.30 +; 3. ENDTWOHARD ;3.30 +; 4. END96TPI ;a system that supports "Change Line Error" ;3.30 +; 5. End of BDSM ;BDSM tables for mini disks. ;3.30 +; 6. ENDATROM ;Some of AT ROM fix module. ;3.30 +; 7. ENDCMOSCLOCKSET;Supporting program for CMOS clock write. ;3.30 +; 8. ENDK09 ;K09 CMOS Clock module to handle SUSPEND/RESUME ;3.30 +; ;3.30 +;9/24/86. ;3.30 + ;3.30 +; *** For mini disk configuration. 4/7/86 ;3.30 +; *** END_OF_BDSM will contain the ending address(off) of BDSM table for ;3.30 +; *** mini disks which is located right after the label END96TPI. ;3.30 +; *** The variable NUM_MINI_DSK will indicate the existance. 4/7/86 ;3.30 + ;3.30 + ;3.30 +STATIC_CONFIGURE: ;3.30 + ;3.30 + ;3.30 + PUSH AX ;3.30 + mov ax, offset END96TPI ;let's start with the biggest one.;3.30 + cmp fHave96, 0 ;Is change line support there? ;3.30 + jnz Config96 ;Yes. ;3.30 + ;3.30 + mov ax, offset ENDTWOHARD ;3.30 + cmp HNUM, 1 ;1 hard file? ;3.30 + jbe No_Two_HRD ;3.30 + jmp ConfigTwoHard ;3.30 +No_Two_HRD: ;3.30 + mov ax, offset ENDONEHARD ;3.30 + jnz Basic_Floppy ;3.30 + jmp ConfigOneHard ;3.30 +Basic_Floppy: ;3.30 + mov ax, offset ENDFLOPPY ;3.30 + jmp Dynamic_Configure ;static configuration is done! ;3.30 + +; +; Keep the 96tpi code +; +Config96: +; +; Save old INT 13 vector +; + PUSH AX + PUSH DS + XOR AX,AX + MOV DS,AX + ASSUME DS:NOTHING ;3.30 + MOV AX,DS:[4 * 13h] + MOV WORD PTR CS:Real13,AX + MOV AX,DS:[4 * 13h+2] + MOV WORD PTR CS:Real13+2,AX +; +; Insert new vector +; + MOV WORD PTR DS:[4 * 13h],OFFSET INT13 + MOV DS:[4 * 13h + 2],CS + POP DS + ASSUME DS:CODE ;3.30 + POP AX +; +; Keep two hard disk BPBs +; +ConfigTwoHard: +; +; Keep one hard disk BPB +; +ConfigOneHard: +; +; Adjust the number of drives to include the hard disks. +; + PUSH AX + MOV AL,HardNum + ADD AL,HNum + add al, num_mini_dsk ;4/7/86 for mini disks installed ;3.30 + ;if not installed, then num_mini_dsk = 0. ;3.30 + MOV DrvMax,AL + POP AX + +DYNAMIC_CONFIGURE: ;3.30 + call Get_Para_Offset ;For dynamic allocation, we are ;3.30 + ;going to use offset address that ;3.30 + ;is in paragraph boundary. ;3.30 + push cs ;3.30 + pop es ;es -> code ;3.30 + assume es:code ;3.30 + cld ;clear direction ;3.30 + ;3.30 + cmp [num_mini_dsk], 0 ;Mini disk(s) installed ? ;3.30 + jz CheckATROM ;No. ;3.30 + mov ax, End_Of_BDSM ;set the new ending address ;3.30 + call Get_Para_Offset ;3.30 +CheckATROM: ;3.30 + cmp Model_Byte, 0FCh ;AT ? ;3.30 + jnz CheckCMOSClock ;3.30 + cmp HNUM, 0 ;No hard file? ;3.30 + jz CheckCMOSClock ;3.30 + mov si, 0F000h ;3.30 + mov es, si ;ES -> BIOS segment ;3.30 + assume es:nothing ;3.30 + mov si, offset BIOS_DATE ;3.30 + mov di, 0FFF5H ;ROM BIOS string is at F000:FFF5 ;3.30 +Cmpbyte: ;Only patch ROM for bios 01/10/84 ;3.30 + cmpsb ;3.30 + jnz CheckCMOSClock ;3.30 + cmp byte ptr [si-1],0 ;3.30 + jnz Cmpbyte ;3.30 + ;3.30 +SetRomCode: ;Now we have to install ROM fix ;3.30 + ;AX is the address to move. ;3.30 + push cs ;3.30 + pop es ;set ES to CODE seg ;3.30 + assume es:code ;3.30 + mov word ptr ORIG13, ax ;3.30 + mov word ptr ORIG13+2, cs ;set new ROM bios int 13 vector ;3.30 + mov cx, offset ENDATROM ;3.30 + mov si, offset IBM_DISK_IO ;3.30 + sub cx, si ;size of AT ROM FIX module ;3.30 + mov di, ax ;destination ;3.30 + rep movsb ;relocate it ;3.30 + mov ax, di ;new ending address ;3.30 + call Get_Para_Offset ;in AX ;3.30 + ;3.30 +CheckCMOSClock: ;3.30 + push cs ;3.30 + pop es ;set ES to CODE seg ;3.30 + assume es:code ;3.30 + cmp HaveCMOSClock, 1 ;CMOS Clock exists? ;3.30 + jne CheckK09 ;3.30 + mov DaycntToDay, ax ;set the address for MSCLOCK ;3.30 + mov cx, offset EndDaycntToDay ;3.30 + mov si, offset Daycnt_To_Day ;3.30 + sub cx, si ;size of CMOS clock sup routine ;3.30 + mov di, ax ;3.30 + rep movsb ;3.30 + mov ax, di ;3.30 + call Get_Para_Offset ;3.30 + mov BinToBCD, ax ;set the address for MSCLOCK ;3.30 + mov cx, offset EndCMOSClockSet ;3.30 + mov si, offset Bin_To_BCD ;3.30 + sub cx, si ;3.30 + mov di, ax ;3.30 + rep movsb ;3.30 + mov ax, di ;3.30 + call Get_Para_Offset ;3.30 + ;3.30 +CheckK09: ;3.30 + push ax ;save ax ;3.30* + mov ax,4100h ;Q: is it a K09 ;3.30* + mov bl,0 ; ;3.30* + int 15h ; ;3.30* + pop ax ;3.30 + jc CONFIGDONE ;3.30 + ;3.30 + mov si, offset INT6C ;3.30 + mov cx, offset ENDK09 ;3.30 + sub cx, si ;size of K09 routine ;3.30 + mov di, ax ;3.30 + push di ;save destination ;3.30 + rep movsb ;3.30 + mov ax, di ; ;3.30 + call Get_Para_Offset ;AX = new ending address ;3.30 + pop di ;3.30 + ;3.30 + push ax ;3.30 + push ds ;3.30 + mov fHaveK09, 1 ;remember we have a K09 type ;3.30 + xor ax,ax ;3.30 + mov ds, ax ;3.30 + assume ds:nothing ;3.30 + ;3.30 + mov word ptr ds:[4 * 6Ch], di ;new INT 6Ch handler ;3.30 + mov ds:[4 * 6Ch +2], cs ;3.30 + ;3.30 + pop ds ;3.30 + assume ds:code ;3.30 + pop ax ;restore the ending address ;3.30 + +; +; Set up config stuff for SYSINIT +; +ConfigDone: + MOV DX,SYSINITSEG + MOV DS,DX + ASSUME DS:SYSINITSEG + SUB AX,OFFSET START$ ;3.30 + ADD AX,15 + RCR AX,1 + SHR AX, 1 + SHR AX, 1 + SHR AX, 1 + MOV FINAL_DOS_LOCATION, AX + POP AX + +GOINIT: + ADD Final_DOS_Location,CODE + Message fTestINIT,<"Final DOS location is "> + MNUM fTestINIT,Final_DOS_Location + Message fTestINIT, + PUSH CS + POP DS + + ASSUME DS:CODE,ES:NOTHING + + CMP BYTE PTR fHave96,0 + JNZ ReadDos + call purge_96tpi ;mjb001 eliminate calls to 96tpi hoohah + +ReadDos: + Message fTestINIT,<"Load FAT",CR,LF> + mov ax,DRVFAT ; Get drive and FAT ID + call SetDrive ; Get BDS for drive + call GetBP ; Ensure valid BPB is present + call GETFAT ; Read in the FAT sector + xor DI,DI + mov AL,ES:[DI] ; Get fat id byte + mov BYTE PTR DRVFAT+1,AL ; Save FAT byte + mov AX,DRVFAT + Message fTestINIT,<"FATID read "> + mnum ftestinit,ax + message ftestinit, + call SETDRIVE ; Get Correct BDS for this drive + mov BL,[DI].FatSiz ; get size of fat on media + mov fBigFat,BL + mov CL,[DI].SecPerClus ; get sectors/cluster + mov AX,[DI].HIDSEC ; get number of hidden sectors + sub BIOS$,AX ; subtract hidden sector offset + xor CH,CH ; CX = sectors/cluster +; +; THE BOOT PROGRAM HAS LEFT THE DIRECTORY AT 0:500 +; + PUSH DS + XOR DI,DI + MOV DS,DI ; ES:DI POINTS TO LOAD LOCATION + MOV BX,DS:WORD PTR [53AH] ; clus=*53A; + POP DS ; + Message fTestINIT,<"Load DOS",CR,LF> +; BAS DEBUG +;LOADIT: MOV AX,((((OFFSET END$)-(OFFSET START$))+15)/16)+SYSIZE +LOADIT: + MOV AX, OFFSET END$ ;3.30 + SUB AX, OFFSET START$ ;3.30 + ADD AX, 15 + RCR AX, 1 ; DIVIDE BY 16 + SHR AX, 1 + SHR AX, 1 + SHR AX, 1 + ADD AX, SYSIZE + + ADD AX,CODE + + MOV ES,AX ; + CALL GETCLUS ; clus = GetClus (clus); + +IsEof: + TEST fBigFat,fBIG ; if (fBigFAT) + JNZ EOFBig + Message fTestINIT, + CMP BX,0FF7h ; return (clus > 0ff7h); + JMP SHORT ISEOFX ;3.30 +EOFBig: + Message fTestINIT, + CMP BX,0FFF7h ; else +ISEOFX: ;3.30 + JB LOADIT ; } WHILE (!ISEOF (CLUS)); ;3.30 + ;3.30 + CALL SETDRVPARMS ;3.30 + ;3.30 + MESSAGE FTESTINIT,<"SYSINIT",CR,LF> ;3.30 + ZWAIT ;3.30 + MESSAGE FTESTINIT,<"ON TO SYSINIT...",CR,LF> ;3.30 + JMP SYSINIT ;3.30 + ;3.30 +INIT ENDP ;3.30 + ;3.30 +;**************************** ;3.30 + ;3.30 +Get_Para_Offset proc near ;3.30 +;in: AX - offset value ;3.30 +;out: AX - offset value adjusted for the next paragraph boundary. ;3.30 + add ax, 15 ;make a paragraph ;3.30 + rcr ax, 1 ;3.30 + shr ax, 1 ;3.30 + shr ax, 1 ;3.30 + shr ax, 1 ;3.30 + shl ax, 1 ;now, make it back to offset value ;3.30 + shl ax, 1 ;3.30 + shl ax, 1 ;3.30 + shl ax, 1 ;3.30 + ret ;3.30 +Get_Para_Offset endp ;3.30 + +; +; READ A FAT SECTOR INTO fat location +; +GETFAT PROC NEAR ;3.30 + XOR DI,DI ; offset + MOV DX,1 ; relative sector (1st sector of fat) + MOV CX,FatLen ; read entire fat. + MOV AX,FatLoc ; + MOV ES,AX ; location to read + MOV AX,DRVFAT ; AH FAT ID byte, AL drive + JMP DISKRD +GETFAT ENDP ;3.30 + + +; +; READ A BOOT RECORD INTO 7C0:BootBias +; GetBoot reads the boot record into 7C0:BootBias +; On Entry: +; DL contains ROM drive number (80 or 81) +; On Exit: +; if carry set error +; if carry clear: +; ES:BX piont to boot sector +; AX and CX are not preserved +; BX and ES are used to return values +; +GETBOOT PROC NEAR + mov AX, 07C0h ; prepare to load ES + mov ES, AX ; load ES segment register + mov BX, BootBias ; load BX, ES:BX is where sector goes + mov AX, 0201h ; command to read & num sec. to 1 + xor DH, DH ; head number zero + mov CX, 0001h ; cylinder zero and sector one + int 13h ; call rom bios + jc ERRET + cmp WORD PTR ES:[BootBias+1FEH],0AA55H ; DAVE LITTON MAGIC BYTE? + jz Norm_Ret + message ftesthard,<"Signature AA55 not found",cr,lf> +ERRET: + message ftesthard,<"Error in Getboot",cr,lf> + STC +Norm_Ret: + RET +GETBOOT ENDP ;3.30 +; +; SetHard - generate BPB for a variable sized hard file. IBM has a +; partitioned hard file; we must read physical sector 0 to determine where +; our own logical sectors start. We also read in our boot sector to +; determine version number +; +; Inputs: DL is ROM drive number (80 OR 81) +; DS:DI points to BDS +; Outputs: Carry clear -> BPB is filled in +; Carry set -> BPB is left uninitialized due to error +; + +SETHARD PROC NEAR ;3.30 + push di + push bx + push ds + mov byte ptr [di].DriveLet,bl + mov byte ptr [di].DriveNum,dl + xor ax,ax + or al,fNon_Removable + or word ptr [di].flags,ax + mov byte ptr [di].FormFactor,ffHardFile + MOV fBigFat,0 ; Assume 12 bit FAT + PUSH DX + + mov AH, 8 ; set command to get drive parameters + int 13h ; call rom-bios disk routine + + ; DH is number of heads-1 + ; DL is number of hard disks attached + ; Low 6 bits of CL is sectors/track + ; High 2 bits of CL with CH are max # of cylinders + INC DH ; get number of heads + MOV BYTE PTR [DI].HDLIM,DH + POP DX + JC SETRET ; carry here means no hard disk + AND CL,3FH ; extract number of sectors/track + MOV BYTE PTR [DI].SECLIM,CL + CALL GETBOOT ; if (getBoot ()) + JC SETRET ; return -1; + MOV BX,1C2H+BootBias ; p = &boot[0x1C2]; +SET1: + CMP BYTE PTR ES:[BX],1 ; while (p->PartitionType != 1 && + JZ SET2 + CMP Byte Ptr ES:[BX],4 ; p->PartitionType != 4) { + JZ Set2 + ADD BX,16 ; p += sizeof Partition; + CMP BX,202H+BootBias ; if (p == &boot[0x202h]) + JNZ SET1 ; return -1; +SETRET: + STC ; } + jmp Ret_Hard + +SET2: + PUSH DX + MOV AX,WORD PTR ES:[BX+4] + MOV DX,WORD PTR ES:[BX+6] + +;Decrement the sector count by 1 to make it zero based. Exactly 64k ;3.30 +;sectors should be allowed ;3.30 +; ;3.30 + SUB AX,1 ; PTM 901 12/12/86 MT ;3.30 + SBB DX,0 ; PTM 901 12/12/86 MT ;3.30 + + ADD AX,WORD PTR ES:[BX+8] + ADC DX,WORD PTR ES:[BX+10] + JZ OKDrive + Message fTestHard,<"Partition invalid",CR,LF> + OR fBigFat,fTOOBIG +OKDrive: + POP DX + MOV AX,WORD PTR ES:[BX+4] + MOV [DI].HIDSEC,AX ; BPB->HidSecCt = p->PartitionBegin; + MOV AX,WORD PTR ES:[BX+8] + CMP AX,64 ; if (p->PartitionLength < 64) + JB SETRET ; return -1; + + MOV WORD PTR [DI].DRVLIM,AX ; BPB->MaxSec = p->PartitionLength; + PUSH AX + + PUSH DX + MOV AX,[DI].HidSec ; boot sector number + XOR DX,DX + MOV BH,DH + MOV BL,byte ptr [DI].SecLim + DIV BX + MOV CL,DL ; CL is sector number + INC CL ; sectors are 1 based + CWD + MOV BL,byte ptr [DI].HdLim + DIV BX ; DL is head, AX is cylinder +; +; DL is head. +; AX is cylinder +; CL is sector number +; TOS is drive +; + +;*** For Mini Disks *** 4/7/86 ;3.30 + cmp word ptr [di].IsMini, 1 ;check for mini disk - 4/7/86 ;3.30 + jnz OKnotMini ;not mini disk. - 4/7/86 ;3.30 + add ax, [di].hidden_trks ;set phy track num - 4/7/86 ;3.30 +OKnotMini: ; 4/7/86 ;3.30 +;*** End of added logic for mini disk ;3.30 + + ROR AH,1 ; move high two bits of cyl to high + ROR AH,1 ; two bits of upper byte + AND AH,0C0h ; turn off remainder of bits + OR CL,AH ; move two bits to correct spot + MOV CH,AL ; CH is Cylinder +; +; CL is sector + 2 high bits of cylinder +; CH is low 8 bits of cylinder +; DL is head +; TOS is drive +; + POP AX ; AL is drive + MOV DH,DL ; DH is head + MOV DL,AL ; DL is drive +; +; CL is sector + 2 high bits of cylinder +; CH is low 8 bits of cylinder +; DH is head +; DL is drive +; + xor BX, BX ; clear BX -- ES:BX points to buffer + mov ax, 0201h ; set command to read one sector + int 13h ; call rom-bios to read sector + pop AX + +; +; ES:[0] points to the boot sector. In theory, (ha ha) the BPB in this thing +; is correct. We can, therefore, pull out all the relevant statistics on the +; media if we recognize the version number. +; + CMP WORD PTR ES:[3], "B" SHL 8 + "I" + JNZ Unknownj + CMP WORD PTR ES:[5], " " SHL 8 + "M" + JNZ Unknownj + CMP WORD PTR ES:[8], "." SHL 8 + "2" + JNZ Try5 + CMP BYTE PTR ES:[10], "0" + JNZ Try5 + Message fTestHard,<"Version 2.0 media",CR,LF> + JMP SHORT CopyBPB +unknownj: + jmp unknown +Try5: + CMP WORD PTR ES:[8],"." SHL 8 + "3" + JNZ Unknownj + cmp byte ptr es:[10],"1" ;do not trust 3.0 boot record. 4/15/86;3.30 + jb unknownj ;if version >= 3.1, then O.K. 4/15/86 ;3.30 + Message ftestHard,<"VERSION 3.1 OR ABOVE MEDIA",CR,LF> + +CopyBPB: +; We have a valid Boot sector. Use the BPB in it to build the +; BPB in BIOS. It is assumed that ONLY SecPerClus, cDIR, and +; cSecFat need to be set (all other values in already). fBigFat +; is also set. + MOV AX,WORD PTR ES:[11+DRVLIM-BytePerSec] ; Total sectors + MNUM fTestHard,AX + Message fTestHard,<" Sec "> + DEC AX ; Subtract # reserved (always 1) + MOV DX,WORD PTR ES:[11+cSecFAT-BytePerSec] ; Sectors for 1 fat + MNUM fTestHard,DX + Message fTestHard,<" Sec/Fat "> + MOV [DI+cSecFAT],DX ; Set in BIOS BPB + SHL DX,1 ; Always 2 FATs + SUB AX,DX ; Sub # FAT sectors + MOV DX,WORD PTR ES:[11+cDIR-BytePerSec] ; # root entries + MOV [DI+cDIR],DX ; Set in BIOS BPB + MNUM fTestHard,DX + Message fTestHard,<" directory entries "> + MOV CL,4 + SHR DX,CL ; Div by 16 ents/sector + SUB AX,DX ; Sub # dir sectors + ; AX now contains the # of data sectors. + MOV CL,BYTE PTR ES:[11+SecPerClus-BytePerSec] ; Sectors per cluster + MOV [DI.SecPerClus],CL ; Set in BIOS BPB + XOR DX,DX + MOV CH,DH + MNUM fTestHard,CX + Message fTestHard,<" SecPerClus",CR,LF> + DIV CX + ; AX now contains the # clusters. + CMP AX,4096-10 ; is this 16-bit fat? + JB GoodRetj ; No + OR fBigFat,fBIG ; 16 bit FAT +GoodRetj: + JMP GoodRet + +Unknown: + Message fTestHard,<"Unknown hard media. Assuming 3.0.",CR,LF> + MOV SI,OFFSET DiskTable2 +Scan: + CMP AX,[SI] + JBE GotParm + ADD SI,4 * 2 + JMP Scan +GotParm: + MOV CL,BYTE PTR [SI+6] + OR fBigFat,CL + MOV CX,[SI+2] + MOV DX,[SI+4] +; +; AX = number of sectors on disk drive +; DX = number of dir entries, +; CH = number of sectors per cluster +; CL = log base 2 of ch +; +; NOW CALCULATE SIZE OF FAT TABLE +; + MNUM fTestHard,AX + Message fTestHard,<" sectors "> + MNUM fTestHard,DX + Message fTestHard,<" directory entries "> + MNUM fTestHard,CX + Message fTestHard,<" SecPerClus|ClusShift"> + MOV WORD PTR cDir[DI],DX ;SAVE NUMBER OF DIR ENTRIES + MOV BYTE PTR SecPerClus[DI],CH ;SAVE SECTORS PER CLUSTER + TEST fBigFAT,fBIG ; if (fBigFat) + JNZ DoBig ; goto DoBig; + Message fTestHard,<" Small fat",CR,LF> + XOR BX,BX + MOV BL,CH + DEC BX + ADD BX,AX + SHR BX,CL ; BX = 1+(BPB->MaxSec+SecPerClus-1)/ + INC BX ; SecPerClus + AND BL,11111110B ; BX &= ~1; (=number of clusters) + MOV SI,BX + SHR BX,1 + ADD BX,SI + ADD BX,511 ; BX += 511 + BX/2 + SHR BH,1 ; BH >>= 1; (=BX/512) + MOV BYTE PTR [DI].cSecFat,BH ;SAVE NUMBER OF FAT SECTORS + JMP SHORT GOODRET ;3.30 +DoBig: + Message fTestHard,<" Big fat",CR,LF> + MOV CL,4 ; 16 (2^4) directory entries per sector + SHR DX,CL ; cSecDir = cDir / 16; + SUB AX,DX ; AX -= cSecDir; AX -= cSecReserved; + DEC AX ; ax = t - r - d + MOV BL,2 + MOV BH,SecPerClus[DI] ; bx = 256 * secperclus + 2 + XOR DX,DX + ADD AX,BX ; ax = t-r-d+256*spc+2 + ADC DX,0 + SUB AX,1 ; ax = t-r-d+256*spc+1 + SBB DX,0 + DIV BX ; cSecFat = ceil((total-dir-res)/ + ; (256*secperclus+2)); + MOV WORD PTR [DI].cSecFat,AX ; number of fat sectors +GoodRet: + MOV BL,fBigFat + MOV [DI].FatSiz,BL ; set size of fat on media + CLC +Ret_Hard: + pop ds + pop bx + pop di + RET +SETHARD ENDP ;3.30 + + +; +; SetDrvParms sets up the recommended BPB in each BDS in the system based on +; the form factor. It is assumed that the BPBs for the various form factors +; are present in the BPBTable. For hard files, the Recommended BPB is the same +; as the BPB on the drive. +; No attempt is made to preserve registers since we are going to jump to +; SYSINIT straight after this routine. +; +SETDRVPARMS PROC NEAR ;3.30 + message ftestinit,<"Setting Drive Parameters",cr,lf> + xor bx,bx + les di,dword ptr cs:[Start_BDS] ; get first BDS in list +Next_BDS: + cmp di,-1 + jnz Do_SetP +Done_SetParms: + RET +Do_SetP: + push es + push di ; preserve pointer to BDS + mov bl,es:[di].FormFactor + cmp bl,ffHardFile + jnz NotHardFF + mov ax,es:[di].DrvLim + push ax + mov ax,word ptr es:[di].hdlim + mul word ptr es:[di].seclim + mov cx,ax ; cx has # sectors per cylinder + pop ax + xor dx,dx ; set up for div + div cx ; div #sec by sec/cyl to get # cyl + or dx,dx + jz No_Cyl_Rnd ; came out even + inc ax ; round up +No_Cyl_Rnd: + mov es:[di].cCyln,ax + message ftestinit,<"Ccyln "> + MNUM ftestinit,AX + message ftestinit, + push es + pop ds + lea si,[di].BytePerSec ; ds:si -> BPB for hard file + jmp short Set_RecBPB +NotHardFF: + push cs + pop ds + cmp bl,ffOther ; Special case "other" type of medium + JNZ NOT_PROCESS_OTHER ;3.30 +Process_Other: + xor dx,dx + mov ax,[di].cCyln + mov bx,[di].RHdlim + mul bx + mov bx,[di].RSeclim + mul bx + mov [di].RDrvlim,ax ; Have the total number of sectors + dec ax + +; New logic to get the sectors/fat area. ;3.30 + ;Fat entry assumed to be 1.5 bytes;3.30 + mov bx, 3 ;3.30 + mul bx ;3.30 + mov bx,2 ;3.30 + div bx ;3.30 + xor dx, dx ;3.30 + mov bx, 512 ;3.30 + div bx ;3.30 + inc ax ;3.30 + +No_Round_Up: + mov [di].RcSecFat,ax + jmp short Go_To_Next_BDS + +NOT_PROCESS_OTHER: ;3.30 + shl bx,1 ; bx is word index into table of BPBs + mov si,offset BPBTable + mov si,word ptr [si+bx] ; get address of BPB +Set_RecBPB: + lea di,[di].RBytePerSec ; es:di -> RecBPB + mov cx,BPBSIZ + REP MOVSB ; MOVE BPBSIZ BYTES ;3.30 +Go_To_Next_BDS: + pop di + pop es ; restore pointer to BDS + mov bx,word ptr es:[di].link+2 + mov di,word ptr es:[di].link + mov es,bx + jmp Next_BDS +SETDRVPARMS ENDP ;3.30 + + +; +; READ CLUSTER SPECIFIED IN BX +; CX = SECTORS PER CLUSTER +; DI = LOAD LOCATION +; +GETCLUS PROC NEAR ;3.30 + PUSH CX + PUSH DI + MOV DOSCNT,CX ;SAVE NUMBER OF SECTORS TO READ + MOV AX,BX + DEC AX + DEC AX + MUL CX ;CONVERT TO LOGICAL SECTOR + ADD AX,BIOS$ ;ADD IN FIRST DATA SECTOR + MOV DX,AX ;DX = FIRST SECTOR TO READ + +GETCL1: + MNUM fTestINIT + Message fTestINIT,<" => "> + ;SI = BX, BX = NEXT ALLOCATION UNIT +; +; GET THE FAT ENTRY AT BX, WHEN FINISHED SI=ENTRY BX +; +UNPACK: + PUSH DS + PUSH BX + MOV SI,FatLoc + TEST fBigFat,fBIG ; if (!fBigFat) { + JNZ Unpack16 + MOV DS,SI + MOV SI,BX + SHR SI,1 + MOV BX,[SI+BX] ; p = fat[clus+clus/2]; + JNC HAVCLUS ; if (clus&1) + SHR BX,1 ; p >>= 4; + SHR BX,1 + SHR BX,1 + SHR BX,1 +HAVCLUS: + AND BX,0FFFH ; oldclus=clus; clus = p & 0xFFF; + JMP SHORT UNPACKX ;3.30 +Unpack16: ; else { + MOV DS,SI + SHL BX,1 ; oldclus = clus; + MOV BX,[BX] ; clus = fat[2*clus]; +UNPACKX: ;3.30 + POP SI ; return; + POP DS + ; } + MNUM fTestINIT + Message fTestINIT,<" "> + SUB SI,BX + CMP SI,-1 ;one apart? + JNZ GETCL2 + ADD DOSCNT,CX + JMP GETCL1 + +GETCL2: + PUSH BX + MOV AX,DRVFAT ;GET DRIVE AND FAT SPEC + MOV CX,DOSCNT + CALL DISKRD ;READ THE CLUSTERS + POP BX + POP DI + MOV AX,DOSCNT ;GET NUMBER OF SECTORS READ + XCHG AH,AL ;MULTIPLY BY 256 + SHL AX,1 ;TIMES 2 EQUAL 512 + ADD DI,AX ;UPDATE LOAD LOCATION + POP CX ;RESTORE SECTORS/CLUSTER + RET +GETCLUS ENDP ; RETURN; ;3.30 + +; +; SI POINTS TO DEVICE HEADER +; +; 4/22/86 - print_init, aux_init is modified to eliminate the ;3.30 +; self-modifying code. ;3.30 + ;3.30 +PRINT_INIT: ;3.30 + call Get_device_number ;3.30 + mov ah,1 ;initalize printer port ;3.30 + int 17h ;call ROM-Bios routine ;3.30 + ret ;3.30 + ;3.30 +AUX_INIT: ;3.30 + call Get_device_number ;3.30 + mov al,RSINIT ;2400,N,1,8 (MSEQU.INC) ;3.30* + mov ah,0 ;initalize AUX port ;3.30* + int 14h ;call ROM-Bios routine ;3.30* + ret ;3.30 + ;3.30 +GET_DEVICE_NUMBER: ;3.30 +;SI -> device header ;3.30 + MOV AL,CS:[SI+13] ;GET DEVICE NUMBER FROM THE NAME ;3.30 + SUB AL,"1" ;3.30 + CBW ;3.30 + MOV DX,AX ;3.30 + RET ;3.30 + +; +; purge_96tpi NOP's calls to 96tpi support. +; +PURGE_96TPI PROC NEAR ;MJB001 ;3.30 + PUSH DS + PUSH ES + + push cs ;mjb001 + pop es ;mjb001 + push cs ;mjb001 + pop ds ;mjb001 + ASSUME DS:CODE,ES:CODE ;3.30 + MOV SI,OFFSET PatchTable +PatchLoop: + LODSW + MOV CX,AX + JCXZ PatchDone + LODSW + MOV DI,AX + MOV AL,90h + REP STOSB + JMP PatchLoop + +PatchDone: + mov di,offset TABLE_PATCH ; ARR 2.42 + MOV AX,OFFSET EXIT + STOSW + STOSW + + POP ES + POP DS + ret ;mjb001 +PURGE_96TPI ENDP ;3.30 + +;Mini disk initialization routine. Called right after DoHard - 4/7/86;3.30 +; DoMini **************************************************************** ;3.30 +; **CS=DS=ES=code ;3.30 +; **DoMini will search for every extended partition in the system, and ;3.30 +; initialize it. ;3.30 +; **BDSM stands for BDS table for Mini disk and located right after the ;3.30 +; label End96Tpi. End_Of_BDSM will have the offset value of the ending ;3.30 +; address of BDSM table. ;3.30 +; **BDSM is the same as usual BDS except that TIM_LO, TIM_HI entries are ;3.30 +; overlapped and used to id mini disk and the number of Hidden_trks. ;3.30 +; Right now, they are called as IsMini, Hidden_Trks respectively. ;3.30 +; **DoMini will use the same routine in SETHARD routine after label SET1 ;3.30 +; to save coding. ;3.30 +; **DRVMAX determined in DoHard routine will be used for the next ;3.30 +; available logical mini disk drive number. ;3.30 +; ;3.30 +; Input: DRVMAX, DSKDRVS ;3.30 +; ;3.30 +; Output: MiniDisk installed. BDSM table established and installed to BDS.;3.30 +; num_mini_dsk - number of mini disks installed in the system. ;3.30 +; End_Of_BDSM - ending offset address of BDSM. ;3.30 +; ;3.30 +; ;3.30 +; Called modules: ;3.30 +; GetBoot, WRMSG, int 13h (AH=8, Rom) ;3.30 +; FIND_MINI_PARTITION (new), Install_BDSM (new), ;3.30 +; SetMini (new, it will use SET1 routine) ;3.30 +; Variables used: End_Of_BDSM, numh, mininum, num_mini_dsk, ;3.30 +; Rom_Minidsk_num, Mini_HDLIM, Mini_SECLIM ;3.30 +; BDSMs, BDSM_type (struc), Start_BDS ;3.30 +;************************************************************************ ;3.30 +; ;3.30 + ;3.30 +DoMini: ;3.30 + Message fTestHard,<"Start of DoMini...",cr,lf> ;3.30 + ;3.30 + push ax ;Do I need to do this? ;3.30 + ;3.30 + mov di, offset BDSMs ;from now on, DI points to BDSM ;3.30 + mov dl, 80h ;look at first hard drive ;3.30* + mov ah, 8h ;get drive parameters ;3.30* + int 13h ;call ROM-Bios ;3.30* + cmp dl, 0 ;3.30 + jz DoMiniRet ;no hard file? Then exit. ;3.30 + mov numh, dl ;save the number of hard files. ;3.30 + xor ax,ax ;3.30 + mov al, drvmax ;3.30 + mov mininum, al ;this will be logical drive letter;3.30 + ;for mini disk to start with. ;3.30 + ;3.30 + shl ax, 1 ;ax=number of devices. word bndry ;3.30 + push bx ;3.30 + mov bx, offset DSKDRVS ;3.30 + add bx, ax ;3.30 + mov Mini_BPB_ptr, BX ;Mini_BPB_ptr points to first avlb;3.30 + ;spot in DskDrvs for Mini disk ;3.30 + ;which points to BPB area of BDSM.;3.30 + pop bx ;3.30 + ;3.30 + mov Rom_Minidsk_num, 80h ;3.30 +DoMiniBegin: ;3.30 + inc dh ;Get # of heads (conv to 1 based) ;3.30 + xor ax, ax ;3.30 + mov al, dh ;3.30 + mov Mini_HDLIM, ax ;save it. ;3.30 + xor ax, ax ;3.30 + and cl, 3fh ;Get # of sectors/track ;3.30 + mov al, cl ;3.30 + mov Mini_SECLIM, ax ;and save it. ;3.30 + ;3.30 + mov dl, Rom_Minidsk_num ;drive number
;3.30 + call GETBOOT ;rd master boot rec 7c0:BootBias ;3.30 + jc DoMiniNext ;3.30 + call FIND_MINI_PARTITION ;3.30 +DoMiniNext: ;3.30 + dec numh ;3.30 + jz DoMiniRet ;3.30 + inc Rom_MiniDsk_Num ;Next hard file ;3.30 + mov dl, Rom_MiniDsk_Num ;look at next hard drive ;3.30* + mov ah, 8h ;get drive parameters ;3.30* + int 13h ;call ROM-Bios ;3.30* + jmp DoMiniBegin ;3.30 + ;3.30 +DoMiniRet: ;3.30 + pop ax ;3.30 + ret ;3.30 + ;3.30 + ;3.30 +;Find_Mini_Partition tries to find every Extended partition on a disk. ;3.30 +;At entry: DI -> BDSM entry ;3.30 +; ES:BX -> 07c0:BootBias - Master Boot Record ;3.30 +; Rom_MiniDsk_Num - ROM drive number ;3.30 +; MiniNum - Logical drive number ;3.30 +; Mini_HDLIM, Mini_SECLIM ;3.30 +; ;3.30 +;Called routine: SETMINI which uses SET1 (in SETHARD routine) ;3.30 +;Variables & equates used from orig BIOS - flags, fNon_Removable, fBigfat ;3.30 +; ;3.30 +; ;3.30 +FIND_MINI_PARTITION: ;3.30 + ;3.30 + add bx, 1C2h ;BX -> system id. ;3.30 + ;3.30 +FmpNext: ;3.30 + cmp byte ptr ES:[BX], 5 ; 5 = extended partition ID. ;3.30 + jz FmpGot ;3.30 + add bx, 16 ; for next entry ;3.30 + cmp bx, 202h+BootBias ;3.30 + jnz FmpNext ;3.30 + jmp FmpRet ;not found extended partition ;3.30 + ;3.30 +FmpGot: ;found my partition. ;3.30 + Message ftestHard,<"Found my partition...",cr,lf> ;3.30 + xor ax,ax ;3.30 + or al, fNon_Removable ;3.30 + or word ptr [DI].Flags, ax ;3.30 + mov byte ptr [DI].FormFactor, ffHardFile ;3.30 + mov fBigFat, 0 ;assume 12 bit Fat. ;3.30 + mov ax, Mini_HDLIM ;3.30 + mov [DI].HDLIM, ax ;3.30 + mov ax, Mini_SECLIM ;3.30 + mov [DI].SECLIM, ax ;3.30 + mov al, Rom_MiniDsk_Num ;3.30 + mov [DI].DriveNum, al ;set physical number ;3.30 + mov al, Mininum ;3.30 + mov [DI].DriveLet, al ;set logical number ;3.30 + ;3.30 + cmp word ptr ES:[BX+8], 64 ;**With current BPB, only lower word ;3.30 + ; is meaningful. ;3.30 + je FmpRet ;should be bigger than 64 sectors at least ;3.30 + sub bx, 4 ;let BX point to the start of the entry ;3.30 + mov dh, byte ptr ES:[BX+2] ;3.30 + and dh, 11000000b ;get higher bits of cyl ;3.30 + rol dh, 1 ;3.30 + rol dh, 1 ;3.30 + mov dl, byte ptr ES:[BX+3] ;cyl byte ;3.30 + mov [DI].Hidden_Trks, dx ;set hidden trks ;3.30 +;** Now, read the volume boot record into BootBias. ;3.30 + mov cx,ES:[BX+2] ;cylinder,cylinder/sector ;3.30* + mov dh,ES:[BX+1] ;head ;3.30* + mov dl,Rom_MiniDsk_Num ;drive ;3.30* + mov ax,7c0h ; ;3.30* + mov es,ax ;buffer segment ;3.30* + mov bx,BOOTBIAS ;buffer offset ;3.30* + mov ax,0201h ;read,1 sector ;3.30* + int 13h ;call ROM-Bios routine ;3.30* + jc FmpRet ;cannot continue. ;3.30 + mov bx, 1c2h+BootBias ;3.30 + ;3.30 + call SetMini ;install a mini disk. BX value saved. ;3.30 + jc FmpnextChain ;3.30 + ;3.30 + call Install_BDSM ;install the BDSM into the BDS table ;3.30 +; call Show_Installed_Mini ;show the installed message. 3/35/86 - Don't show messages. ;3.30 + inc mininum ;increase the logical drive number for next ;3.30 + inc num_mini_dsk ;increase the number of mini disk installed. ;3.30 + ;3.30 + push bx ;now, set the DskDrvs pointer to BPB info. ;3.30 + mov bx, Mini_BPB_ptr ;3.30 + lea si, [di].BytePerSec ;points to BPB of BDSM ;3.30 + mov [bx], si ;3.30 + inc Mini_BPB_ptr ;advance to the next address ;3.30 + inc Mini_BPB_ptr ;3.30 + pop bx ;3.30 + ;3.30 + add DI, type BDSM_type ;adjust to the next BDSM table entry. ;3.30 + mov End_OF_BDSM, DI ;set the ending address of BDSM table to this. ;3.30 +; Message fTestHard,<"Mini disk installed.",cr,lf> ;3.30 +FmpnextChain: jmp FmpNext ;let's find out if we have any chained partition ;3.30 +FmpRet: ;3.30 + ret ;3.30 + ;3.30 +SetMini: ;3.30 + push di ;3.30 + push bx ;3.30 + push ds ;3.30 + jmp SET1 ;will be returned to Find mini partition routine. ;3.30 + ;Some logic has been added to SET1 to ;3.30 + ;deal with Mini disks. ;3.30 + ;3.30 +; ;3.30 +;Install BDSM installs a BDSM (pointed by DS:DI) into the end of the current ;3.30 +;linked list of BDS. ;3.30 +;Also, set the current BDSM pointer segment to DS. ;3.30 +;At entry: DS:DI -> BDSM ;3.30 +; ;3.30 +Install_BDSM: ;3.30 + ;3.30 + push ax ;3.30 + push si ;3.30 + push es ;3.30 + ;3.30 + les si, dword ptr cs:Start_BDS ;start of the beginning of list ;3.30 +I_BDSM_Next: ;3.30 + cmp word ptr es:[si], -1 ;end of the list? ;3.30 + jz I_BDSM_New ;3.30 + mov si, word ptr es:[si].link ;3.30 + mov ax, word ptr es:[si].link+2 ;next pointer ;3.30 + mov es, ax ;3.30 + jmp short I_BDSM_Next ;3.30 +I_BDSM_New: ;3.30 + mov ax, ds ;3.30 + mov word ptr ds:[di].link+2, ax ;BDSM segment had not been initialized. ;3.30 + mov word ptr es:[si].link+2, ax ;3.30 + mov word ptr es:[si].link, di ;3.30 + mov word ptr ds:[di].link, -1 ;make sure it is a null ptr. ;3.30 + ;3.30 +I_BDSM_ret: ;3.30 + pop es ;3.30 + pop si ;3.30 + pop ax ;3.30 + ret ;3.30 + ;3.30 +;***The following code is not needed any more. Don't show any ;3.30 +;***messages to be compatible with the behavior of IO.SYS. ;3.30 +;;Show the message "Mini disk installed ..." ;3.30 +;;This routine uses WRMSG procedure which will call OUTCHR. ;3.30 +;Show_Installed_Mini: ;3.30 +; push ax ;3.30 +; push bx ;3.30 +; push ds ;3.30 +; ;3.30 +; mov al, Mininum ;logical drive number ;3.30 +; add al, Drv_Letter_Base ;='A' ;3.30 +; mov Mini_Drv_Let, al ;3.30 +; mov si, offset Installed_Mini ;3.30 +; call WRMSG ;3.30 +; ;3.30 +; pop ds ;3.30 +; pop bx ;3.30 +; pop ax ;3.30 +; ret ;3.30 +;**End of mini disk initialization** ; 4/7/86 ;3.30 + ;3.30 + ;3.30 +CMOS_Clock_Read proc near ;3.30 + ;3.30 +; IN ORDER TO DETERMINE IF THERE IS A CLOCK PRESENT IN THE SYSTEM, THE FOLLOWING ;3.30 +; NEEDS TO BE DONE. ;3.30 + PUSH AX ;3.30 + PUSH CX ;3.30 + PUSH DX ;3.30 + PUSH BP ;3.30 + ;3.30 + XOR BP,BP ;3.30 +LOOP_CLOCK: ;3.30 + XOR CX,CX ;3.30 + XOR DX,DX ;3.30 + MOV AH,2 ;READ REAL TIME CLOCK ;3.30 + INT 1Ah ;CALL ROM-BIOS ROUTINE ;3.30 + CMP CX,0 ;3.30 + JNZ CLOCK_PRESENT ;3.30 + ;3.30 + CMP DX,0 ;3.30 + JNZ CLOCK_PRESENT ;3.30 + ;3.30 + CMP BP,1 ; READ AGAIN AFTER A SLIGHT DELAY, IN CASE CLOCK ;3.30 + JZ NO_READDATE ; WAS AT ZERO SETTING. ;3.30 + ;3.30 + INC BP ; ONLY PERFORM DELAY ONCE. ;3.30 + MOV CX,4000H ;3.30 +DELAY: ;3.30 + LOOP DELAY ;3.30 + JMP LOOP_CLOCK ;3.30 + ;3.30 +CLOCK_PRESENT: ;3.30 + mov cs:HaveCMOSClock, 1 ; Set the flag for cmos clock ;3.30 + ;3.30 + call CMOSCK ; Reset CMOS clock rate that may be ;3.30 + ;possibly destroyed by CP DOS and POST routine did not ;3.30 + ;restore that. ;3.30 + ;3.30 + PUSH SI ;3.30 + MESSAGE FTESTINIT,<"CLOCK DEVICE",CR,LF> ;3.30 + CALL READ_REAL_DATE ;MJB002 READ REAL-TIME CLOCK FOR DATE ;3.30 + ;3.30 + CLI ;MJB002 ;3.30 + MOV DAYCNT,SI ;MJB002 SET SYSTEM DATE ;3.30 + STI ;MJB002 ;3.30 + POP SI ;MJB002 ;3.30 +NO_READDATE: ;3.30 + POP BP ;3.30 + POP DX ;3.30 + POP CX ;3.30 + POP AX ;3.30 + RET ;3.30 + ;3.30 +CMOS_Clock_Read endp ;3.30 +; ;3.30 +; 10/28/86 ;3.30 +; THE FOLLOWING CODE IS WRITTEN BY JACK GULLEY IN ENGINEERING GROUP. ;3.30 +; CP DOS IS CHANGING CMOS CLOCK RATE FOR ITS OWN PURPOSES AND IF THE ;3.30 +; USE COLD BOOT THE SYSTEM TO USE PC DOS WHILE RUNNING CP DOS, THE CMOS ;3.30 +; CLOCK RATE ARE STILL SLOW WHICH SLOW DOWN DISK OPERATIONS OF PC DOS ;3.30 +; WHICH USES CMOS CLOCK. PC DOS IS PUT THIS CODE IN MSINIT TO FIX THIS ;3.30 +; PROBLEM AT THE REQUEST OF CP DOS. ;3.30 +; THE PROGRAM IS MODIFIED TO BE RUN ON MSINIT. Equates are defined in CMOSEQU.INC. ;3.30 +; This program will be called by CMOS_Clock_Read procedure. ;3.30 +; ;3.30 +; The following code CMOSCK is used to insure that the CMOS has not ;3.30 +; had its rate controls left in an invalid state on older AT's. ;3.30 +; ;3.30 +; It checks for an AT model byte "FC" with a submodel type of ;3.30 +; 00, 01, 02, 03 or 06 and resets the periodic interrupt rate ;3.30 +; bits incase POST has not done it. This initilization routine ;3.30 +; is only needed once when DOS loads. It should be ran as soon ;3.30 +; as possible to prevent slow diskette access. ;3.30 +; ;3.30 +; This code exposes one to DOS clearing CMOS setup done by a ;3.30 +; resident program that hides and re-boots the system. ;3.30 +; ;3.30 +CMOSCK PROC NEAR ; CHECK AND RESET RTC RATE BITS ;3.30 + ;3.30 +;Model byte and Submodel byte were already determined in MSINIT. ;3.30 + push ax ;3.30 + cmp cs:Model_byte, 0FCh ;check for PC-AT model byte ;3.30 + ; EXIT IF NOT "FC" FOR A PC-AT ;3.30 + JNE CMOSCK9 ; Exit if not an AT model ;3.30 + ;3.30 + CMP cs:Secondary_Model_Byte,06H ; Is it 06 for the industral AT ;3.30 + JE CMOSCK4 ; Go reset CMOS periodic rate if 06 ;3.30 + CMP cs:Secondary_Model_Byte,04H ; Is it 00, 01, 02, or 03 ;3.30 + JNB CMOSCK9 ; EXIT if problem fixed by POST ;3.30 + ; Also,Secondary_model_byte = 0 when AH=0c0h, int 15h failed. ;3.30 +CMOSCK4: ; RESET THE CMOS PERIODIC RATE ;3.30 + ; Model=FC submodel=00,01,02,03 or 06 ;3.30 + + mov al,CMOS_REG_A or NMI ;NMI disabled on return + mov ah,00100110b ;Set divider & rate selection + call CMOS_WRITE + + + mov al,CMOS_REG_B or NMI ;NMI disabled on return + call CMOS_READ + and al,00000111b ;clear SET,PIE,AIE,UIE,SQWE + mov ah,al + mov al,CMOS_REG_B ;NMI enabled on return + call CMOS_WRITE + +CMOSCK9: ; EXIT ROUTINE ;3.30 + pop ax ;3.30 + RET ; RETurn to caller ;3.30 + ; Flags modifyied ;3.30 +CMOSCK ENDP ;3.30 +PAGE ;3.30 +;--- CMOS_READ ----------------------------------------------------------------- ;3.30 +; READ BYTE FROM CMOS SYSTEM CLOCK CONFIGURATION TABLE : ;3.30 +; : ;3.30 +; INPUT: (AL)= CMOS TABLE ADDRESS TO BE READ : ;3.30 +; BIT 7 = 0 FOR NMI ENABLED AND 1 FOR NMI DISABLED ON EXIT : ;3.30 +; BITS 6-0 = ADDRESS OF TABLE LOCATION TO READ : ;3.30 +; : ;3.30 +; OUTPUT: (AL) VALUE AT LOCATION (AL) MOVED INTO (AL). IF BIT 7 OF (AL) WAS : ;3.30 +; ON THEN NMI LEFT DISABLED. DURING THE CMOS READ BOTH NMI AND : ;3.30 +; NORMAL INTERRUPTS ARE DISABLED TO PROTECT CMOS DATA INTEGRITY. : ;3.30 +; THE CMOS ADDRESS REGISTER IS POINTED TO A DEFAULT VALUE AND : ;3.30 +; THE INTERRUPT FLAG RESTORED TO THE ENTRY STATE ON RETURN. : ;3.30 +; ONLY THE (AL) REGISTER AND THE NMI STATE IS CHANGED. : ;3.30 +;------------------------------------------------------------------------------- ;3.30 + ;3.30 +CMOS_READ PROC NEAR ; READ LOCATION (AL) INTO (AL) ;3.30 + PUSHF ; SAVE INTERRUPT ENABLE STATUS AND FLAGS ;3.30 + + cli + push bx + push ax ;save user NMI state + or al,NMI ;disable NMI for us + out CMOS_PORT,al + nop ;undocumented delay needed + in al,CMOS_DATA ;get data value + + ;set NMI state to user specified + mov bx,ax ;save data value + pop ax ;get user NMI + and al,NMI + or al,CMOS_SHUT_DOWN + out CMOS_PORT,al + nop + in al,CMOS_DATA + + mov ax,bx ;data value + pop bx + + PUSH CS ; *PLACE CODE SEGMENT IN STACK AND ;3.30 + CALL CMOS_POPF ; *HANDLE POPF FOR B- LEVEL 80286 ;3.30 + RET ; RETURN WITH FLAGS RESTORED ;3.30 + ;3.30 +CMOS_READ ENDP ;3.30 + ;3.30 +CMOS_POPF PROC NEAR ; POPF FOR LEVEL B- PARTS ;3.30 + IRET ; RETURN FAR AND RESTORE FLAGS ;3.30 + ;3.30 +CMOS_POPF ENDP ;3.30 + ;3.30 +;--- CMOS_WRITE ---------------------------------------------------------------- ;3.30 +; WRITE BYTE TO CMOS SYSTEM CLOCK CONFIGURATION TABLE : ;3.30 +; : ;3.30 +; INPUT: (AL)= CMOS TABLE ADDRESS TO BE WRITTEN TO : ;3.30 +; BIT 7 = 0 FOR NMI ENABLED AND 1 FOR NMI DISABLED ON EXIT : ;3.30 +; BITS 6-0 = ADDRESS OF TABLE LOCATION TO WRITE : ;3.30 +; (AH)= NEW VALUE TO BE PLACED IN THE ADDRESSED TABLE LOCATION : ;3.30 +; : ;3.30 +; OUTPUT: VALUE IN (AH) PLACED IN LOCATION (AL) WITH NMI LEFT DISABLED : ;3.30 +; IF BIT 7 OF (AL) IS ON. DURING THE CMOS UPDATE BOTH NMI AND : ;3.30 +; NORMAL INTERRUPTS ARE DISABLED TO PROTECT CMOS DATA INTEGRITY. : ;3.30 +; THE CMOS ADDRESS REGISTER IS POINTED TO A DEFAULT VALUE AND : ;3.30 +; THE INTERRUPT FLAG RESTORED TO THE ENTRY STATE ON RETURN. : ;3.30 +; ONLY THE CMOS LOCATION AND THE NMI STATE IS CHANGED. : ;3.30 +;------------------------------------------------------------------------------- ;3.30 + ;3.30 +CMOS_WRITE PROC NEAR ; WRITE (AH) TO LOCATION (AL) ;3.30 + PUSHF ; SAVE INTERRUPT ENABLE STATUS AND FLAGS ;3.30 + PUSH AX ; SAVE WORK REGISTER VALUES ;3.30 + + cli + push ax ;save user NMI state + or al,NMI ;disable NMI for us + out CMOS_PORT,al + nop + mov al,ah + out CMOS_DATA,al ;write data + + ;set NMI state to user specified + pop ax ;get user NMI + and al,NMI + or al,CMOS_SHUT_DOWN + out CMOS_PORT,al + nop + in al,CMOS_DATA + + POP AX ; RESTORE WORK REGISTERS ;3.30 + PUSH CS ; *PLACE CODE SEGMENT IN STACK AND ;3.30 + CALL CMOS_POPF ; *HANDLE POPF FOR B- LEVEL 80286 ;3.30 + RET ;3.30 + ;3.30 +CMOS_WRITE ENDP ;3.30 +; ;3.30 + +END$: +code ends +end diff --git a/SRC/BIOS/MSINIT.OBJ b/SRC/BIOS/MSINIT.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..62700d67bd59e30c0ea708bb7542d0e5f0b91624 GIT binary patch literal 6639 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 literal 0 HcmV?d00001 diff --git a/SRC/BIOS/MSIOCTL.INC b/SRC/BIOS/MSIOCTL.INC new file mode 100644 index 0000000..cc1e8ba --- /dev/null +++ b/SRC/BIOS/MSIOCTL.INC @@ -0,0 +1,1036 @@ + include ioctl.inc + +; +; Generic IOCTL dispatch tables +; +IOReadJumpTable db 2 + dw offset GetDeviceParameters + dw offset ReadTrack + dw offset VerifyTrack + +IOWriteJumpTable db 2 + dw offset SetDeviceParameters + dw offset WriteTrack + dw offset FormatTrack + +MAX_SECTORS_CURR_SUP EQU 63 ; CURRENT MAXIMUM SEC/TRK THAT ;3.30 + ; WE SUPPORT (Was 40 in DOS 3.2) ;3.30 +; +; TrackTable is an area for saving information passwd by the set device +; parameter function for laster use my Read/Write/Format/Verify. +; +; Entries are 4-Tuples (C,H,R,N) where: +; C = Cylinder, H = Head, R = Sector, N = Bytes/Sector +; +; fixed for bug0016 - initialised table with values - sp +TrackTable db 0,0,1,2 + db 0,0,1,2 + db 0,0,3,2 + db 0,0,4,2 + db 0,0,5,2 + db 0,0,6,2 + db 0,0,7,2 + db 0,0,8,2 + db 0,0,9,2 + db 0,0,10,2 + db 0,0,11,2 + db 0,0,12,2 + db 0,0,13,2 + db 0,0,14,2 + db 0,0,15,2 + db MAX_SECTORS_CURR_SUP * size a_SectorTable - ($-tracktable) dup (0) + +sectorsPerTrack dw 15 + + +; This is a real ugly place to put this +; it should really go in the BDS +mediaType db 0 + +Media_Set_For_Format db 0 ; 1 if we have done an Int 13 Set Media + ; Type for Format call +; Rev 3.30 ***************************************************************** +Had_Format_Error db 0 ; 1 if the previous format operation + ; failed. +Dsk_time_out_Err equ 80h ; Time out error (No media present). +Dsk_change_line_Err equ 6h ; Change line error +Dsk_illegal_combination equ 0Ch ; Return code of ah=18h function. +; Rev 3.30 ***************************************************************** + +; +; TempDPT is a temporary place to hold a pointer to the original +; Disk Parameter Table while DPT is made to point to a table returned +; by a BIOS call. A value of -1 indicateds no value has been saved. +; + +TempDPT DD -1 + +; +; Generic$IOCTL: +; Perform Generic IOCTL request +; Input: +; al - unit number +; Output: +; if carry set then al contains error code +; + Public Generic$IOCTL +Generic$IOCTL: + Message ftestdisk,<"Generic IOCTL",cr,lf> + les bx,cs:[PTRSAV] ; es:bx points to request header. + call SetDrive ; ds:di points to BDS for drive. +; +; At this point: +; es:bx - points to the Request Header +; ds:di points to the BDS for the drive +; + cmp es:[bx].MajorFunction, RAWIO + jne IOCTL_Func_Err + mov al, es:[bx].MinorFunction + mov si, offset IOReadJumpTable + test al, GEN_IOCTL_FN_TST ; Test of req. function + jnz NotGenericIoctlWrite ; function is a Read. + mov si, offset IOWriteJumpTable +NotGenericIoctlWrite: + and al, 0fH + cmp al, cs:[si] + ja IOCTL_Func_Err + cbw + shl ax, 1 + inc si + add si,ax + les bx, es:[bx].GenericIOCTL_Packet + call cs:[si] + jc FailGeneric$IOCTL + jmp exit + +FailGeneric$IOCTL: + jmp err$exit + +IOCTL_Func_Err: + jmp CMDERR + + + + + +; +; GetDeviceParameters: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to device parameter packet +; + + PUBLIC GETDEVICEPARAMETERS ;3.30 +GetDeviceParameters proc near +; Copy info from BDS to the device parameters packet + mov al, byte ptr ds:[di].FormFactor + mov byte ptr es:[bx].DP_DeviceType, al + mov ax, word ptr ds:[di].Flags + and ax,fNon_Removable+fChangeline ; mask off other bits + mov word ptr es:[bx].DP_DeviceAttributes, ax + mov ax, word ptr ds:[di].cCyln + mov word ptr es:[bx].DP_Cylinders, ax + +; Set media type to default + xor al, al + mov byte ptr es:[bx].DP_MediaType, al + +; Copy recommended BPB + lea si, byte ptr [di].RBytePerSec + test byte ptr es:[bx].DP_SpecialFunctions, BUILD_DEVICE_BPB + jz use_BPB_present +; Get the correct disk in the drive + call CheckSingle +; Build the BPB from scratch + call GETBP + jc Get_Parm_Ret + lea si,byte ptr [di].BytePerSec +use_BPB_present: + lea di, byte ptr [bx].DP_BPB + mov cx, size BPB_Type ; for now use 'small' BPB + rep movsb + clc +Get_Parm_Ret: + ret +GetDeviceParameters endp + + + + + +; +; SetDeviceParameters: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to device parameter packet +; + + PUBLIC SETDEVICEPARAMETERS ;3.30 +SetDeviceParameters proc near + +; Make sure the fChanged_By_Format flag gets set to kick DOS into looking at +; the BPB + or word ptr ds:[di].Flags, fChanged_By_Format or fChanged + test byte ptr es:[bx].DP_SpecialFunctions, ONLY_SET_TRACKLAYOUT + jz short SetDevParm_1 + jmp SetTrackTable ; Originally TrackLayout + +SetDevParm_1: +; Copy info from the device parameters packet to BDS + mov al, byte ptr es:[bx].DP_DeviceType + mov byte ptr ds:[di].FormFactor, al + + mov ax, word ptr es:[bx].DP_Cylinders + mov word ptr ds:[di].cCyln, ax + +; If change line is not loaded then ignore changeling flag + mov ax, word ptr es:[bx].DP_DeviceAttributes + cmp cs:[fHave96],0 + jnz Have_Change + and ax,not fChangeline +Have_Change: +; ignore all bits except Non_removable and Changeline + and ax,fNon_Removable or fChangeline + mov cx, word ptr ds:[di].Flags + and cx, not (fNon_Removable or fChangeline or GOOD_TRACKLAYOUT) + or ax, cx + mov word ptr ds:[di].Flags, ax + +; Set media type + mov al, byte ptr es:[bx].DP_MediaType + mov cs:mediaType, al +; the media changed (maybe) so we will have to do a SetDASD the next time +; we format a track + or word ptr ds:[di].Flags, SET_DASD_true + + SaveReg +; Figure out what we are supposed to do with the BPB + +; Were we asked to install a fake BPB? + test byte ptr es:[bx].DP_SpecialFunctions, INSTALL_FAKE_BPB + jnz short InstallFakeBPB + +; Were we returning a fake BPB when asked to build a BPB? + test word ptr ds:[di].Flags, RETURN_FAKE_BPB + jz short InstallRecommendedBPB + +; We were returning a fake BPB but we can stop now + and word ptr ds:[di].Flags, not RETURN_FAKE_BPB + jmp DoneWithBPBstuff + +InstallRecommendedBPB: + mov cx, size a_BPB + lea di, byte ptr [di].RBytePerSec + jmp short CopyTheBPB + +InstallFakeBPB: + mov cx, size BPB_Type ; move 'smaller' BPB + lea di, byte ptr [di].BytePerSec +CopyTheBPB: + lea si, byte ptr [bx].DP_BPB +; exchange es and ds + push es + push ds + pop es + pop ds + + rep movsb + +DoneWithBPBstuff: + Call RestoreOldDPT + RestoreReg + +; Set up track table (if neccessary) +SetTrackTable: + mov cx, word ptr es:[bx].DP_TrackTableEntries + mov cs:sectorsPerTrack, cx + and word ptr ds:[di].Flags, not GOOD_TRACKLAYOUT + test byte ptr es:[bx].DP_SpecialFunctions, TRACKLAYOUT_IS_GOOD + jz UglyTrackLayout + or word ptr ds:[di].Flags, GOOD_TRACKLAYOUT + +UglyTrackLayout: + cmp cx, MAX_SECTORS_IN_TRACK + ja TooManySectorsPerTrack + jcxz SectorInfoSaved ; if no value don't copy table + ; save information in the track table + + push BX ; get ES:BX to point to sector + add BX, DP_SectorTable ; table in Device param. struct + + push DI + mov DI, offset TrackTable + 2 ; CS:DI now points to sector id + ; of the first track table entry + push AX ; preserve AX value + + ; For MAX_SECTORS_IN_TRACK +TrackLoop: ; DO: + mov AX, word ptr ES:[BX] ; get sector number + mov byte ptr CS:[DI], AL ; save in track table + + mov AX, word ptr ES:[BX]+2 ; get sector size + call SectorSizeToSectorIndex ; convert size to index number + mov byte ptr CS:[DI]+1, AL ; save size in track table + + add BX, size a_sectorTable ; advance pointers to next + add DI, size a_sectorTable ; entries + loopnz TrackLoop ; End FOR + + pop AX ; restore the saved values + pop DI + pop BX + +SectorInfoSaved: + clc + ret + +TooManySectorsPerTrack: + mov al, 0cH + stc + ret + +SetDeviceParameters endp + + +; +; FormatTrack: +; If SpecialFunction byte is 1, then this is a status call to see if there is +; ROM support for the combination of sec/trk and # of cyln, and if the +; combination is legal. If SpecialFunction byte is 0, then format the track. +; +; Input: DS:DI points to BDS for drive +; ES:BX points to format packet +; +; Output: +; For status call: +; SpecialFunction byte set to: +; 0 - ROM support + legal combination +; 1 - No ROM support +; 2 - Illegal Combination +; 3 - no media present ;Rev 3.30 +; Carry cleared. +; +; For format track: +; Carry set if error +; +; +; Flags also may be altered. All other registers preserved. +; If the call to ROM returns no error, then the current DPT is "replaced" by +; the one returned by the ROM. This is done by changing the pointer in [DPT] +; to the one returned. The original pointer to the disk base table is stored +; in TempDPT, until it is restored. +; +; This proc was changed to force a status for format call if we are on the +; new ROM. +; +; +FormatTrack proc near + test byte ptr es:[bx].DP_SpecialFunctions,Status_For_Format + jz SkipStatusOnly + +Do_Status_Only: + call FormatStatus + mov byte ptr es:[bx].DP_SpecialFunctions,al + ret + +SkipStatusOnly: ; for a hard disk only do the verify + cmp byte ptr ds:[di].FormFactor, DEV_HARDDISK + jnz SkipVerify + jmp DoVerifyTrack +SkipVerify: + SaveReg ; Format a Track + call FormatStatus ; SetDASD checks media_set_for_format + cmp al,3 ; Check for time out + je Format_Failed ; Fail if time out + call SetDASD +; +; Store Cylinder,Head in track table +; ***** ASSUMPTION ******* +; Since format requests on Fixed Media are converted to Verifies, we +; assume that we are formatting a floppy and hence have 255 or less +; tracks and heads. We therefore must change the Cylinder, Head data +; from the Request Packet Size to that of the TrackTable (see Int 13 +; interface in IBM's Tech Ref.). + +; Check to ensure correct disk is in drive + call CheckSingle + + mov ax, word ptr es:[bx].FP_Cylinder + mov word ptr cs:[TRKNUM],ax + mov cx, word ptr es:[bx].FP_Head + mov byte ptr cs:[HDNUM],cl + mov ah,cl + ; this next piece of code copies the correct head + ; and cylinder numbers to the tracktable + push di ; preserve DI + mov di, offset TrackTable + mov CX, cs:SectorsPerTrack ; get number of sectors + jcxz EndSetUpTrackTable ; if nothing to do skip down +SetUpLoop: + mov cs:[di], AX ; set head and track value + add di, 4 ; move to next entry + loopnz SetUpLoop ; loop if not done yet +EndSetUpTrackTable: + pop di ; restore DI (BDS pointer) + mov cx, MAXERR ; Set up retry count +FormatRetry: + push cx + ; set up registers for format call to TO_ROM + mov AX, word ptr CS:SectorsPerTrack ; set number of sectors + mov AH, ROMFormat + push cs ; set ES:BX to point to + pop es ; the track table + mov BX, offset TrackTable + ; don't need to set CL on format + call to_rom + jnc FormatOk + pop cx + mov cs:[Had_Format_Error],1 ; Mark the error + push ax ;3.30 + push cx ;3.30 + push dx ;3.30 + call ResetDisk + call FormatStatus ;3.30 + cmp al, 1 ;3.30 + jnz While_Err ;3.30 + call SetDASD ;3.30 +While_Err: ;3.30 + pop dx ;3.30 + pop cx ;3.30 + pop ax ;3.30 + loop FormatRetry + +; Format failed +Format_Failed: + mov cs:[Had_Format_Error],1 ; Indicate a format error + cmp ah,Dsk_Change_Line_Err ; Convert change line to + jne Map_Err ; to time out. + mov ah,Dsk_Time_Out_Err +Map_Err: + call MapError + RestoreReg + ret + +FormatOk: + mov cs:[Had_Format_Error],0 ; Reset format error flag + pop cx ; clean up stack after bailing out + ; of FormatRetry loop early + RestoreReg + +DoVerifyTrack: + call VerifyTrack ; Will reset DPT entries. + ret + +FormatTrack endp + +; +; FormatStatus: +; If SpecialFunction byte is 1, then this routine is called to see if there is +; ROM support for the combination of sec/trk and # of cyln, and if the +; combination is legal. +; +; Input: DS:DI points to BDS for drive +; ES:BX points to format packet +; +; Output: +; SpecialFunction byte set to: +; 0 - ROM support + legal combination +; 1 - No ROM support +; 2 - Illegal Combination +; 3 - No media present, ROM support exists but can't determine +; media +; Carry cleared. +; +; For format track: +; Carry set if error +; +; +; Flags also may be altered. All other registers preserved. +; If the call to ROM returns no error, then the current DPT is "replaced" by +; the one returned by the ROM. This is done by changing the pointer in [DPT] +; to the one returned. The original pointer to the disk base table is stored +; in TempDPT, until it is restored. +; +; +FormatStatus proc near + SaveReg + cmp cs:[Had_Format_Error],1 ; Are we here because of a format err + je Fstat01 + cmp byte ptr cs:[Media_Set_For_Format],1 + jnz FStat03 + jmp Stat_Ret +Fstat03: + mov byte ptr cs:[Media_Set_For_Format],0 +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; modification - sp001 +; +; remove check for new rom from here. we shall just assume the +; prescence of the new rom and go ahead and issue the int13 call +; anyway. later on if there is an error we shall check this to +; see if it is there because of lack of rom support, in which +; case the appropriate error will be indicated by setting al to 1 +; +; I would ideally like to see the new rom testing code shifted to +; msinit and this code reintroduced. however for this version we +; are aiming to stick close to the IBM variety. +; +; More changes to support this commenting out will follow. All +; will be marked as modification sp001 +; +; mov al,1 ; No ROM support available error code +; test byte ptr cs:[New_ROM],1 +; jnz FStat01 +; jmp Stat_Ret +Fstat01: + SaveReg + + xor ax,ax + mov ds,ax + lds si, dword ptr ds:[DskAdr] ; DS:SI := pDPT + + mov word ptr cs:[DPT],si ; cs:[DPT] := pDPT + mov word ptr cs:[DPT + 2],ds + + RestoreReg + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; modification sp001 +; +; the following instruction introduced for the new rom modification +; + mov cs:[New_Rom],1 ; assume new rom +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + mov ax,word ptr [di].cCyln + mov cx,word ptr [di].Seclim + ; set up registers for format status call + and AH, 03h ; 'and' out unneeded track bits + ror AH, 1 ; get track and sector values correct + ror AH, 1 + or AH, CL ; set sector number + xchg AH, AL + mov CX, AX + dec CH + mov DL, byte ptr [DI].DriveNum ; get drive number + mov AH, 18h ; set command to "sec/trk supported?" + + SaveReg + int 13h ; call rom bios to see if supported + jc Format_Stat_Err ; if carry, combination is not supported + + ; ES:DI points to new Disk Base Table + ; combination for this drive replace + ; current (DskAdr) pointer with new one, + ; saving the old one in TempDPT. + + cmp cs:[Had_Format_Error],1 ; Are we here because of a format err + jnz Fstat02 ; Then skip the disk base setup + + xor al,al ; Supported and OK + mov cs:[Had_Format_Error],al ; Clear format error + jmp Pop_Stat_Ret ; Back to work + +Fstat02: + xor ax,ax + mov ds,ax + lds si, dword ptr ds:[DskAdr] ; DS:SI := pDPT + + mov word ptr cs:[TempDPT],si + mov word ptr cs:[TempDPT + 2],ds ; Save pDPT + + mov word ptr ds:[DskAdr],DI ; Setup New DPT returned by + mov word ptr ds:[DskAdr + 2],ES ; ROM + + mov byte ptr cs:[Media_Set_For_Format],1 ; set flag + xor al,al ; Legal combination + ROM support code + jmp short Pop_Stat_Ret + +Format_Stat_Err: + mov al,3 ; Assume a time out + cmp ah,Dsk_Time_Out_Err ; Was it a time out??? + jz Pop_Stat_Ret ; Yes - then done + dec al ; Assume an illegal comb. + cmp ah,Dsk_illegal_combination ; Was it an illegal comb??? + jz Pop_Stat_Ret ; Yes - then done + dec al ; Assume No ROM Support +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; modification sp001 +; +; the following instruction was introduced for the new_rom modification +; + mov cs:[New_Rom],0 ; the old rom +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Return result of status call +Pop_Stat_Ret: + RestoreReg +Stat_Ret: + clc + RestoreReg + ret +FormatStatus endp + + + +; +; VerifyTrack: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to verify packet +; + PUBLIC VERIFYTRACK ;3.30 +VerifyTrack proc near + mov cs:RFLAG, ROMverify + mov ax, word ptr es:[bx].VP_Cylinder + mov cs:curtrk, ax + mov ax, word ptr es:[bx].VP_Head + +; ****** ASSUMPTION ****** +; we assume that we have less than 256 heads, and that the Request +; Header Data Structure is unneccessarily big + mov cs:curhd, al + xor ax, ax + mov cx, cs:sectorsPerTrack +; Use 0:0 as the transfer address for verify + xor bx, bx + mov es, bx + call TrackIO + ret +VerifyTrack endp + +; +; ReadTrack: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to read packet +; + PUBLIC READTRACK ;3.30 +ReadTrack: + mov cs:RFLAG, ROMread + jmp ReadWriteTrack + +; +; WriteTrack: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to write packet +; + PUBLIC WRITETRACK ;3.30 +WriteTrack: + mov cs:RFLAG, ROMwrite + jmp ReadWriteTrack +; +; ReadWriteTrack: +; +; Input: +; DS:DI points to BDS for drive +; ES:BX points to write packet +; RFLAG - 2 for read, 3 for write +; + PUBLIC READWRITETRACK ;3.30 +ReadWriteTrack proc near + mov ax, word ptr es:[bx].TRWP_Cylinder + mov cs:curtrk, ax + mov ax, word ptr es:[bx].TRWP_Head + +; ****** ASSUMPTION ****** +; we assume that we have less than 256 heads, and that the Request +; Header Data Structure is unneccessarily big + mov cs:curhd, al + mov ax, word ptr es:[bx].TRWP_FirstSector + mov cx, word ptr es:[bx].TRWP_SectorsToReadWrite + les bx, es:[bx].TRWP_TransferAddress + call TrackIO + ret +ReadWriteTrack endp + + +; +; TrackIO: +; Performs Track Read/Write/Verify +; +; Input: +; RFLAG - 2 = Read +; 3 = Write +; 4 = Verify +; ax - Index into track table of first sector to IO +; cx - number of sectors to IO +; es:bx - Transfer address +; ds:di - pointer to BDS +; curtrk - current cylinder +; curhd - current head +; + public trackio +TrackIO proc near +; procedure `disk' will pop stack to SPsav and return if error + mov cs:SPsav, sp +; Ensure correct disk is in drive + call CheckSingle +; +; Set up tables and variables for I/O +; + cmp byte ptr cs:[Media_Set_For_Format],1 + jz DPTAlreadySet + +; ;3.30 +; SET UP TABLES AND VARIABLES FOR I/O ;3.30 +; ;3.30 + SaveReg + call IOSetUp + RestoreReg +; +; point si at the table entry of the first sector to be IO'd +; +DPTAlreadySet: + mov si, offset trackTable + shl ax, 1 + shl ax, 1 + add si, ax +; +; we want: +; cx to be the number of times we have to loop +; dx to be the number of sectors we read on each iteration + mov dx, 1 + test word ptr ds:[di].Flags, GOOD_TRACKLAYOUT + jz IOnextSector + +; Hey! we can read all the sectors in one blow + xchg dx, cx + +IOnextSector: + push cx + push dx +; skip over the cylinder and head in the track table + inc si + inc si + +; Get sector id from track table + mov AL, byte ptr cs:[si] ; get current sector value + mov cs:[cursec], AL ; save cursec value + +;*** For a Fixed disk multi-track disk I/O - 4/14/86 ;3.30 +;Assumptions: 1). In the input CX (# of sectors to go) to TRACKIO, only CL;3.30 is +;valid. 2). Sector size should be set to 512 bytes. 3). GOODTRACKLAYOUT. ;3.30 +; ;3.30 + test word ptr [di].Flags, fNon_Removable ;Fixed disk? - J.K;3.30 . + jz IOREMOVABLE ;no - ;3.30 + mov cs:[seccnt], dx ;# of sectors to I;3.30 /O - + mov ax, dx ; ;3.30 + call disk ; ;3.30 + pop dx ; ;3.30 + pop cx ; ;3.30 + clc ; ;3.30 + ret ; ;3.30 +IOREMOVABLE: ; ;3.30 + + mov AL, byte ptr cs:[si]+1 ; get sector size index + + ; The next eight lines put sector size index in DPT + push ES ; save value while getting pointer + push SI ; to DPT + push AX + + les SI, cs:DPT ; ES:SI points to DPT + ; put size in DPT + mov byte ptr ES:[si].Disk_Sector_Siz, AL + mov AX, word ptr [di].seclim ; get number of sector/track + mov byte ptr ES:[si].Disk_EOT,AL ; patch in DPT + + pop AX ; restore register values + pop SI + pop ES + ; convert index to byte value + call SectorSizeIndexToSectorSize + push AX ; save number of bytes in sector + mov AX, DX ; get number of sector for I/0 + +DoTheIO: + mov cs:[SECCNT],ax ; set up the count of sectors to I/O + call disk + ; advance buffer pointer by adding + ; sector size + pop ax + add bx, ax + pop dx + pop cx + loop IOnextSector + call DONE ; Set time of last access, and reset + clc ; entries in DPT. + ret + +TrackIO endp +; +; The sector size in bytes needs to be converted to an index value for the IBM +; ROM. (0=>128, 1=>256,2=>512,3=>1024). It is assumed that only these values +; are permissible. +; On Input AX contains sector size in bytes +; On Output AL contains index +; + public SectorSizeToSectorIndex +SectorSizeToSectorIndex proc near + and AH, 07h ; very simple error correction + mov AL, AH ; shift left 8 bits + cmp AL, 4 ; size 1024? + jnz SecToIndexRet ; no, then we are done + sub AL, 1 ; if 1024, adjust index to 3 +SecToIndexRet: + ret +SectorSizeToSectorIndex endp + +SectorSizeIndexToSectorSize proc near +; value in AH on entry is not important + push CX ; save CX value + mov CL, AL ; use index number as shift size + mov AX, 0080h ; set AX to 128 + shl AX, CL ; shift by index to get proper value + pop CX ; restore CX value + ret +SectorSizeIndexToSectorSize endp + + + +; +; Set up the ROM for formatting. +; we have to tell the ROM BIOS what type of disk is in the drive. +; On Input - DS:DI - points to BDS +; +SetDASD proc near +; See if we have new ROM and have issues Set Media Type For Format call + test byte ptr cs:[Media_Set_For_Format],1 + jnz DasdHasBeenSet +; See if we have previously set DASD type + cmp cs:[Had_Format_Error],1 + je DoSetDasd + test word ptr ds:[di].Flags, SET_DASD_true + jz DASDhasBeenSet + and word ptr ds:[di].Flags, not SET_DASD_true + ; the next nine lines determine and put the DASD type in AL +DoSetDasd: + mov cs:[Had_Format_Error],0 + mov cs:[GAP_PATCH], 50h ; assume 48tpi or 3.5" drive + cmp [di].FormFactor, ffSmall; is 3.5" drive? + jnz not35Drive ; no, skip down + mov AL, 04h ; yes set proper DASD value + jmp short Do_Set ; jump down + +Not35Drive: + mov AL, 01h ; + cmp [di].FormFactor, ff96tpi; 96tpi disk drive? + jnz Do_Set ; no skip down to rom call + inc AL ; reflect 96tpi drive in DASD type + cmp [di].seclim, 15 ; 96tpi media in drive? + jnz Do_Set ; no, skip down to rom call + inc AL ; reflect 96tpi media in DASD type + mov cs:[GAP_PATCH], 54h ; and in the GAP_PATCH +Do_Set: + mov AH, 17h ; set command to Set DASD type + mov DL, [di].DriveNum ; set drive number + int 13h ; call rom-bios +DASDhasBeenSet: + mov ah,byte ptr [di].seclim + mov cs:[FORMT_EOT],ah + ret +SetDasd endp + + +; +; This routine is called if an error occurs while formatting or verifying. +; It resets the drive, and decrements the retry count. +; On Entry - DS:DI - points to BDS for the drive +; BP - contains retry count +; On Exit Flags indicate result of decrementing retry count +; +; +; There are some drives that "lose" the changeline indication if another +; floppy drive is accessed before the changeline is recorded by the device +; driver. In this situation, it is possible for the ROM to also not detect +; that the medium has changed. So, the end result is that we could have a +; diskette in the drive for which we can not even read the boot sector. +; We "fix" this by setting the byte at location DISK_STATE_MACHINE_DRV_0 (hex) +; for physical drive 0 (or DISK_STATE_MACHINE_DRV_1 for drive 1) to 0 (See +; IBM PC/AT "blessed" addresses Document for explanation) . This tells the ROM +; that the medium is 'unknown'. The ROM actually uses these locations for +; itself. Note that we do this only for internal drives; we do not do this for +; fixed disks or for physical drives > 1. We may end up corrupting some +; other bytes in memory that may be used for something else. +; NOTE: We do not stuff this byte if the last operation was a FORMAT because +; the ROM loses track of what it is trying to format!! +; +; This routine was changed to only stuff 61H when the drive indicated it +; supported changeline. The Phoenix ROM was taking a very long time +; to figure out what the media was which caused disk time outs to take +; forever +; +; We assume that DS:DI points to the current BDS for this drive. +; no registers should be touched +; + +AGAIN: + call ResetDisk + dec bp ; decrement retry count + RET + + PUBLIC RESETDISK +ResetDisk: + push ax + xor AH, AH ; set command to reset disk + int 13h ; call the rom-bios + pop ax + mov cs:[STEP_DRV],-1 ; zap up the speed + ret + +; +; This routine sets up the Drive Parameter Table with the values needed for +; Format, does an Int 13. Values in DPT are restored after a VERIFY is done. +; +; On Entry - DS:DI - points to BDS for the drive +; ES:BX - points to TRKBUF +; AL - number of sectors +; AH - Int 13 function code +; CL - Sector number for verify +; On Exit - DS,DI,ES,BX remain unchanged. +; ax and flags are the results of the int 13 +; + Public To_ROM +To_ROM: + SAVEREG ;3.30 + +; The below line was replaced because saving the DPT is predicated upon +; whether the functionality of the new ROM was used, not if it exists. +; test byte ptr cs:[New_ROM],1 + + test byte ptr cs:[Media_Set_For_Format],1 + jnz Got_Valid_DPT + +; Set up values in the DPT +; Set up motor start correctly for 3.5" drives. + push ax + push ds + + xor ax,ax + mov ds,ax + lds si,dword ptr ds:[DskAdr] ; DS:SI := pDPT + + mov word ptr cs:[DPT],si + mov word ptr cs:[DPT+2],ds ; Save pDPT + + pop ds + push ES ; save value in ES + LES SI, CS:DPT + + mov DX, [di].seclim ; set the sector per track in + mov es:[si].DISK_EOT, DL ; the Disk Parameter Table + cmp DX, 15 ; 96tip media? + jz To_ROM1 ; yes, skip down + ; no - set Format Gap to 320/360 media value + mov CL, cs:[Gap_Patch] + mov byte ptr ES:[si].DISK_FORMT_GAP, CL +To_ROM1: ; 3.5" floppy drive? + cmp byte ptr [di].FormFactor, ffSmall + jnz To_ROM2 ; no, skip down + ; yes - reset disk moter start value + mov byte ptr ES:[si].DISK_MOTOR_STRT, 4 +To_ROM2: + pop ES ; restore ES value + pop ax + +Got_Valid_DPT: + ; now set up the registers + mov DL, [di].DriveNum ; set drive number + mov DH, CS:[HDNUM] ; set head number + mov CX, CS:[TRKNUM] ; set track number + ror CH,1 + ror CH,1 + xchg CH, CL + int 13h ; call the rom-bios disk routines + RestoreReg + ret + + +; +; Get the owner of the physical drive represented by the logical drive in BL. +; The assumption is that we **ALWAYS** keep track of the owner of a drive!! +; If this is not the case, the system may hang, just following the linked list. +; + PUBLIC IOCTL$GETOWN +IOCTL$GETOWN: + call SetDrive + mov al,byte ptr [di].DriveNum ; Get physical drive number + push cs + pop ds + mov di,word ptr Start_BDS +Own_Loop: + cmp byte ptr [di].DriveNum,al + jne GetNextBDS + test word ptr [di].flags,fI_Own_Physical + jnz Done_GetOwn +GetNextBDS: + mov bx,word ptr [di].link+2 + mov di,word ptr [di].link + mov ds,bx + jmp short Own_Loop +Done_GetOwn: + JMP SHORT EXIT_OWN + +; +; Set the ownership of the physical drive represented by the logical drive in +; BL. +; + PUBLIC IOCTL$SETOWN +IOCTL$SETOWN: + call SetDrive + mov byte ptr cs:[fSetOwner],1 ; set flag for CheckSingle to + ; look at. + call CheckSingle ; Set ownership of drive + mov byte ptr cs:[fSetOwner],0 ; reset flag + xor bx,bx + mov es,bx + mov cl,-1 + mov byte ptr es:[LSTDRV],cl ; Set up SDSB as well + +EXIT_OWN: +; If there is only one logical drive assigned to this physical drive, return +; 0 to user to indicate this. + xor cl,cl + test word ptr [di].flags,fI_Am_Mult + jz EXIT_NO_MULT + mov cl,byte ptr [di].DriveLet ; Get logical drive number + inc cl ; get it 1-based +EXIT_NO_MULT: + LDS BX,CS:[PtrSav] + mov byte ptr [BX].UNIT,CL + jmp EXIT + + + + +; +; Moves the old DPT that had been saved in TempDPT back to DPT. This is done +; only if the first byte of TempDPT is not -1. +; All registers (including flags) are preserved. +; + Public RestoreOldDPT +RestoreOldDPT: +; If we have already restored the disk base table earlier, do not do it +; again. + push ax + xor al,al +; Reset flag and get current flag setting + mov cs:[Had_Format_Error],al + xchg byte ptr cs:[Media_Set_For_Format],al + or al,al + jz DontRestore + SaveReg + LDS SI,CS:[TempDPT] + xor ax,ax + mov es,ax ; have ES -> segment 0 + MOV WORD PTR ES:[DskAdr],SI + MOV WORD PTR ES:[DskAdr+2],DS +GotCurrentDPT: + RestoreReg +DontRestore: + pop ax + clc ; clear carry + ret ; (7/31/86) + +;end of file msioctl.asm diff --git a/SRC/BIOS/MSLOAD.ASM b/SRC/BIOS/MSLOAD.ASM new file mode 100644 index 0000000..2ccd737 --- /dev/null +++ b/SRC/BIOS/MSLOAD.ASM @@ -0,0 +1,767 @@ +title Non-Contiguous BIOS Loader (MSLOAD) + +IF1 + %OUT ASSEMBLING: Non-Contiguous BIOS Loader (MSLOAD) + %OUT +ENDIF + +bootseg segment at 0h + org 7C00h +Boot_Sector label byte + org 7D00h +Relocate_Start label byte +bootseg ends + + +dosseg segment at 70h + org 00h +BIOS_Address label byte + +dosseg ends + + +cseg segment public para 'code' + assume cs:cseg,ds:cseg,es:cseg,ss:cseg + + + +include msload.inc + +org 0h + +start: + +subttl Setup Stack +page +;*********************************************************************** +; Setup_Stack +;*********************************************************************** +; +; Input: none +; +; Output: +; +; SS:SP = 0:7C00h +; AX destroyed +;----------------------------------------------------------------------- +; First thing is to reset the stack to a better and more known place. +; +; Move the stack to just under the boot record and relocation area (0:7C00h) +; +; Preserve all other registers +;---------------------------------------------------------------------- + + CLI ;Stop interrupts till stack ok + XOR AX,AX + MOV SS,AX ;Work in stack just below this routine + MOV SP,7C00h - 30 ;Leave room for stack frame + MOV BP,7C00h - 30 ;Point BP as stack index pointer + STI + + +subttl Save Input Values +page +;*********************************************************************** +; Save_Input_Values +;*********************************************************************** +; +; Input: none +; +; DL = INT 13 drive number we booted from +; CH = media byte +; BX = First data sector on disk (0-based) +; +; Output: +; +; BX = first data sector on disk +; CL = number of floppies including fake one +; CH = media byte +; +; [bp].Media_Byte = input CH +; [bp].Drive_Number = input DL +; [bp].First_Sector = input BX +; [bp].Drive_Boot = output AX +; [bp].Number_Floppy = output CL +; [bp].Number_Sectors = Sectors/track +; [bp].Number_Heads = heads/cylinder +; +; DS = 0 +; AX,DX,SI destroyed +; +; Calls: none +;----------------------------------------------------------------------- +; Save input information +; +; Get Equipment Flag +; +; Find how many drives on system +; +; Figure out boot drive +; +;---------------------------------------------------------------------- +Save_Input_Values: + mov [bp].First_Sector,bx + mov [bp].media_Byte,ch + mov [bp].Drive_Number,dl +; INT 11h ;GET EQUIPMENT STATUS +; ROL AL,1 ;Put bits 6 & 7 into bits 0 & 1 +; ROL AL,1 +; AND AX,3 ;Only look at bits 0 & 1 +; JNZ NOTsingle ;Zero means single drive system +; INC AX ;Pretend it's a two drive system +NOTSingle: +; INC AX ;AX has number of drives, 2-4 + ;Is also 0 indexed boot drive if we + ; booted off hard file +; MOV CL,AL ;CH is FAT ID, CL # floppies +; TEST DL,80H ;BOOT FROM FLOPPY ? +; JNZ GOTHRD ;NO. +; XOR AX,AX ;INDICATE BOOT FROM DRIVE A +GotHrd: + xor ax,ax ;Segment 0 + mov ds,ax + + assume ds:Bootseg + + mov ax,Boot_Sector.SECLIM ;Get Sectors per track + mov [bp].Sectors_Per_Track,ax + mov ax,Boot_Sector.HDLIM ;Get BPB heads per cylinder + mov [bp].Number_Of_Heads,ax + mov ax,Boot_Sector.cSecFat ;Get sectors per FAT + mov [bp].Number_Of_FAT_Sectors,ax + mov ax,Boot_Sector.cSecHid ;Get hidden sectors + mov [bp].Hidden_Sectors,ax + mov ax,Boot_Sector.cSecRes ;Get Reserved Sectors + mov [bp].Reserved_Sectors,ax + + +subttl Find_Cluster_Size +page +;*********************************************************************** +; Find_Cluster_Size +;*********************************************************************** +; +; Input: BPB information in loaded boot record at 0:7C00h +; +; Output: +; +; DS = 0 +; AX = Bytes/Cluster +; BX = Sectors/Cluster +; SI destroyed +; Calls: none +;----------------------------------------------------------------------- +; +; Get Bytes/sector from BPB +; +; Get sectors/cluster from BPB +; +; Bytes/cluster = Bytes/sector * sector/cluster +;---------------------------------------------------------------------- +Find_Cluster_Size: + +;For the time being just assume the boot record is valid and the BPB +;is there. + + xor ax,ax ;Segment 0 + mov ds,ax + + assume ds:bootseg + + mov ax,Boot_Sector.ByteSec ;Get BPB bytes/sector + xor bx,bx + mov bl,Boot_Sector.cAlloc ;Get sectors/cluster + mul bx ;Bytes/cluster + mov [bp].Size_Cluster,ax ;Save it + + + +subttl Determine FAT size +page +;*********************************************************************** +; Determine_FAT_Size +;*********************************************************************** +; +; Notes: +; +; Determine if FAT is 12 or 16 bit FAT. 12 bit FAT if floppy, read MBR +; to find out what system id byte is. +; +; Input: [bp].Media_Byte = FAT ID Byte +; +; Output: +; +; [BP].Fat_Size = FAT12_bit or FAT16_bit +; ES = 0 +; All other registers destroyed +; +; Calls: READ_DISK +;----------------------------------------------------------------------- +;IF (not FAT ID of F8) +; {12 bit FAT} +;ELSE +; { +; Read in master boot record at 0:7C00h +; +; Scan system id bytes for 1 or 4 +; +; IF (Sys id = 4) +; {16 bit FAT} +; ELSE +; {IF (Sys id = 1) +; {12 bit FAT} +; ELSE +; {Error} +; ENDIF +; ENDIF +; ENDIF +; +;---------------------------------------------------------------------- +Determine_FAT_Size: + mov [bp].FAT_Size,FAT12_bit ;Assume 12 bit fat + cmp [bp].Media_Byte,0F8h ;Is it floppy + jne FAT_Size_Found ;Yep, all set + mov [bp].Logical_Sector,0 ;Got hardfile, go get MBR + xor ax,ax + mov es,ax + mov di,offset Relocate_Start + mov [bp].Sector_Count,1 + call Disk_Read + mov si,offset Relocate_Start+1C2h + mov cx,4 + xor ax,ax + mov ds,ax +Find_Sys_Id: + mov [bp].FAT_Size,FAT12_bit ;Assume 12 bit fat + cmp byte ptr [si],1 + je FAT_Size_Found + mov [bp].FAT_Size,FAT16_bit ;Assume 12 bit fat + cmp byte ptr [si],4 + je Fat_Size_Found + add si,16 + loop Find_Sys_Id + ;xxxxxxxxxxxxxxxxxxxxxxxxxx error +FAT_Size_Found: + + +subttl Determine First Cluster +page +;*********************************************************************** +; Determine_First_Cluster +;*********************************************************************** +; +; Notes: Find the last cluster that was loaded +; +; +; Input: +; +; [BP].Size_Cluster +; Total_Length is offset of end of MSLOAD +; +; Output: +; +; [BP].Last_Found_Cluster = the last cluster loaded containing MSLOAD +; code. This is also the number of clusters +; with MSLOAD code +2 +; +; Calls: none +;----------------------------------------------------------------------- +; +;Get length of loader portion of bios +; +;Divide by bytes/cluster +; +;If (Remainder = 0) +; {Last_Used_Cluster = quotient+2} +;Else +; {Last_Used_Cluster = quotient+3} +;---------------------------------------------------------------------- +Determine_First_Cluster: + mov [bp].Last_Found_Cluster,1 ;2 is the first cluster-1 + mov ax,offset Total_Length ;Get whole length + xor dx,dx + div [bp].Size_Cluster ;Div by bytes/sector + add [bp].Last_Found_Cluster,ax ;Save the result + cmp dx,0 ;Was there remainder? + je First_Cluster_Found ;No + inc [bp].Last_Found_Cluster ;Yes, round up + +First_Cluster_Found: + + +subttl Relocate +page +; +;*********************************************************************** +; RELOCATE +;*********************************************************************** +; +; Notes: +; +; Relocate the loader code to 0:7C00 - this will allow bios to be loaded +; underneath at 70:0 +; +; Input: none +; +; Output: es is set to 0 +; ds is set to cs (70h) +; ax,cx,si,di destroyed +; +; Calls: none +;----------------------------------------------------------------------- +; Copy code from Relocate_Code to Relocate_Start (7C00h) +; +; The length to copy is Relocate_Length +; +; Jump to relocated code +;----------------------------------------------------------------------- +; +Relocate: + push cs ;Set up ds segreg + pop ds + xor ax,ax ;Set up ES segreg + mov es,ax + + assume es:bootseg,ds:cseg + + mov si,offset Relocate_Code ;Source + mov di,offset Relocate_Start ;Target + mov cx,Relocate_Length ;Length + rep movsb ;Go do it + + jmp far ptr Relocate_Start + +; +;************************************************************************* +;* RELOCATED CODE ******************************************************** +;************************************************************************* +; + +Relocate_Code label byte + +subttl Read In FAT +page +;*********************************************************************** +; Read_In_FAT +;*********************************************************************** +; +; Notes: +; +; Reads in the entire FAT at 0:8000. This gives the relocated portion +; of this loader a maximum size of 1024 bytes (8000 - 7C00). The max +; size of the FAT is 64 sectors (32k) so everything will fit under the +; 64k DMA boundary, so no problems with loading. +; +; Input: none +; +; Output: +; +; ES = 0 +; All sectors destroyed +; +; Calls: READ DISK +;----------------------------------------------------------------------- +; Get number of sectors in FAT +; +; Set ES:DI to 0:8000h +; +; Read in the sectors +; +;---------------------------------------------------------------------- +Read_In_FAT: + xor ax,ax + mov ds,ax + + assume ds:bootseg + + mov ax,[bp].Number_Of_FAT_Sectors ;Get sectors/FAT + mov [bp].Sector_Count,ax ;Number of sectors to read + mov ax,[bp].Hidden_Sectors ;Hidden+Reserved = Fat + add ax,[bp].Reserved_Sectors + mov [bp].Logical_Sector,ax ;Save it, setup for read + xor ax,ax + mov es,ax + mov di,8000h ;Point to buffer + call Disk_Read + +subttl Keep Loaded BIO +page +;*********************************************************************** +; KEEP LOADED BIO +;*********************************************************************** +; +; Notes: +; +; Determine how much of bios was loaded in when the loader was loaded +; by the boot record (only the portion that is guaranteed to be +; contiguous +; +; Input: +; +; [BP].Last_Found_Cluster = number of clusters used for loader+2 +; +; Output: +; ES = DS = 70h +; DI = Next offset to load bios code +; AX,BX,CX,DX,SI destroyed +; +; [bp].Next_BIO_Location = DI on output +; [bp].Last_Cluster = last cluster loaded +; +; Calls: none +;----------------------------------------------------------------------- +;Number of clusters loaded+2 is in [BP].Last_Found_Cluster +; +;Multiply cluster * cluster size in bytes to get total loaded for MSLOAD +; +;Subtract TOTAL_LOADED - LOADBIO_SIZE to get loaded bios in last cluster +; +;Relocate this piece of bios down to 70:0 +; +;---------------------------------------------------------------------- +Keep_Loaded_BIO: + push ds + mov ax,[bp].Last_Found_Cluster ;Point to last cluster loaded + sub ax,1 ;Get number of clusters loaded + mul [bp].Size_Cluster ;Get total bytes loaded by + ;This is always < 64k, so + ;lower 16 bits ok + sub ax,LoadBio_Size ;Get portion of bios loaded + mov cx,ax ;Save length to move + mov ax,70h ;Segment at 70h + mov ds,ax + mov es,ax + mov si,offset cs:Total_Length ;Point at bios + mov di,0 ;Point at 70:0 + rep movsb ;Relocate this code + mov [bp].Next_Bio_Location,di ;Save where to load next + pop ds + +subttl Get Contiguous Clusters +page +;*********************************************************************** +; Get_Contiguous_Clusters +;*********************************************************************** +; +; Notes: Go find clusters as long as they are contiguous +; +; +; Input: +; +; [BP].Next_BIO_Location +; [BP]. +; +; +; Output: +; +; +; Calls: Get_Next_FAT_Entry +;----------------------------------------------------------------------- +; +;Set [BP].Sector_Count to Sectors per cluster +; +;Call Get_Next_FAT_Entry to get next cluster in file +; +;Call Check_for_EOF +; +;IF (NC returned) +; +; {Call Get_Next_FAT_Entry +; +; IF (New cluster is contig to old cluster) +; {Add sectors per cluster to [BP].Sector_Count +; +; Call Check_For_EOF +; +; IF (NC returned) +; +; +;---------------------------------------------------------------------- +Get_Contiguous_Cluster: + xor ah,ah + mov al,Boot_Sector.cAlloc ;Assume we will get one cluster + mov [bp].Sector_Count,ax + call Get_Next_Fat_Entry ;Go get it + mov [bp].Last_Found_Cluster,ax ;Update the last one found + cmp [bp].EOF,End_Of_File + je GOTO_bios + +Got_Contig_Clusters: + sub ax,2 ;Zero base the cluster + xor ch,ch + mov cl,Boot_Sector.cAlloc ;Get sectors per cluster + mul cx ;Get how many + add ax,[bp].First_Sector ;See where the data sector starts + mov [bp].Logical_Sector,ax ;Save it + mov di,[bp].Next_Bio_Location ;Get where to put code + push [bp].Sector_Count ;Save how many sectors + mov ax,dosseg ;Get area to load code + mov es,ax + call Disk_Read + pop ax ;Get back total sectors read in +; jc ########## + mul Boot_Sector.ByteSec ;Get number of bytes we loaded + add [bp].Next_Bio_Location,ax ;Point to where to load next + jmp short Get_Contiguous_Cluster + +subttl GOTO bios +page +;*********************************************************************** +; GOTO_bios +;*********************************************************************** +; +; Notes: +; +; Set up required registers for bios, then jump to it (70:0) +; +; Input: none +; +; [bp].Media_Byte = media byte +; [bp].Drive_Number = INT 13 drive number we booted from +; [bp].First_Sector = First data sector on disk (0-based) +; +; Output: +; +; Required by MSINIT +; DL = INT 13 drive number we booted from +; CH = media byte +; BX = First data sector on disk (0-based) +; +; Calls: none +;----------------------------------------------------------------------- +; +; Set up registers for MSINIT then do Far Jmp +; +;---------------------------------------------------------------------- +GOTO_bios: + mov ch,[bp].Media_Byte ;Restore regs required for MSINT + mov dl,[bp].Drive_Number + mov bx,[bp].First_Sector + jmp far ptr bios_Address + + + + +subttl Disk Read +page +;*********************************************************************** +; Disk_Read +;*********************************************************************** +; +; Notes: +; +; Read in the [BP].Sector_Count number of sectors at ES:DI +; +; +; Input: none +; +; DI = Offset of start of read +; ES = Segment of read +; [bp].Sector_Count = number of sectors to read +; [bp].Logical_sector = starting sector +; Following is BPB info that must be setup prior to call +; [bp].Number_Of_Heads +; [bp].Number_Of_Sectors +; [bp].Drive_Number +; [bp].Sectors_Per_Track +; +; Output: +; +; ES = 0 +; AX,BX,CX,DX,SI,DI destroyed +; +; +; Calls: none +;----------------------------------------------------------------------- +; Divide start sector by sectors per track +; The remainder is the actual sector number, 0 based +; +; Increment actual sector number to get 1 based +; +; The quotient is the number of tracks - divide by heads to get the cyl +; +; The remainder is actual head, the quotient is cylinder +; +; Figure the number of sectors in that track, set AL to this +; +; Do the read +; +; If Error, Do RESET, then redo the INT 13h +; +; If successful read, Subtract # sectors read from Sector_Count, Add to +; Logical Sector, add #sectors read * Sector_Size to BX; +; +; If Sector_Count <> 0 Do next read +;---------------------------------------------------------------------- +Disk_Read: + +; +; convert a logical sector into Track/sector/head. AX has the logical +; sector number +; +DODIV: + MOV cx,5 ;5 retries + +Try_Read: + PUSH cx ;Save it + + MOV AX,[bp].Logical_Sector ;Get starting sector + XOR DX,DX + DIV word ptr [bp].Sectors_Per_Track + MOV bx,[bp].Sectors_Per_Track ;Get number of sectors we can + sub bx,dx ;read in this track + mov si,bx + cmp [bp].Sector_Count,si ;Is possible sectors in track more + jae Got_Length ;than what we need to read? + mov si,[bp].Sector_Count ;Yes, only read what we need to + +Got_Length: + INC DL ; sector numbers are 1-based + MOV bl,dl ;Start sector in DL + XOR DX,DX + DIV word ptr [bp].Number_Of_Heads ;Start cyl in ax,head in DL + MOV DH,DL +; +; Issue one read request. ES:BX have the transfer address, AL is the number +; of sectors. +; +; +; Now convert to standard ROM call +; + mov cl,bl ;Get starting sector + ror ah,1 ;Set up high 2 bits + ror ah,1 ;Set up high 2 bits + or cl,ah ;Combine cyl/start sector + mov ch,al ;Set low order of cyl + mov bx,di ;Set offset + mov dl,[bp].Drive_Number ;Set drive + mov ax,si ;Set count + mov ah,02 ;Read Command + push ax ;Save regs + push di ; * + int 13h ;Call ROM-Bios + pop di ;Restore Regs + pop ax ; * + pop cx ;Get retry count back + jnc Read_OK + push cx + mov bx,di ; + push di ;Save Reg + mov dl,[bp].Drive_Number ;Set drive + mov ah,0 ;RESET Disk Command + int 13h ;Call ROM-Bios + pop di ;Restore Reg + pop cx + loop Try_Read + ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx error +Read_OK: + xor ah,ah ;Mask out command, just get # read + sub [bp].Sector_Count,ax ;Bump number down + jz Read_Finished + add [bp].Logical_Sector,ax ;Where to start next time + xor bx,bx ;Get number sectors read + mov bl,al + mov ax,Boot_Sector.ByteSec ;Bytes per sector + mul bx ;Get total bytes read + add di,ax ;Add it to offset + jmp short DODIV +Read_Finished: + RET + +subttl GET NEXT FAT ENTRY +page +;*********************************************************************** +; GET_NEXT_FAT_ENTRY +;*********************************************************************** +; +; Notes: +; +; Given the last cluster found, this will return the next cluster of +; bios. If the last cluster is (F)FF8 - (F)FFF, then the final cluster +; of bios has been loaded, and control is passed to GOTO_bios +; +; Input: +; +; [bp].Last_Found_Cluster +; [bp].Fat_Size +; +; Output: +; +; [bp].Last_Found_Cluster (updated) +; +; Calls: none +;----------------------------------------------------------------------- +; Get Last_Found_Cluster +; +; IF (16 bit FAT) +; {IF (Last_Found_Cluster = FFF8 - FFFF) +; {JMP GOTO_bios} +; ELSE +; {Get offset by multiply cluster by 2} +; +; ELSE +; {IF (Last_Found_Cluster = FF8 - FFF) +; {JMP GOTO_bios} +; ELSE +; {Get offset by - multiply cluster by 3 +; +; Rotate right to divide by 2 +; +; IF (CY set - means odd number) +; {SHR 4 times to keep high twelve bits} +; +; ELSE +; {AND with 0FFFh to keep low 12 bits} +; } +; } +; +; Add in 8000h to get offset of next cluster in FAT buffer +; +;---------------------------------------------------------------------- +Get_Next_FAT_Entry: + + mov [bp].EOF,End_Of_File ;Assume last cluster + mov ax,[bp].Last_Found_Cluster ;Get last cluster + cmp [bp].Fat_Size,FAT12_bit + jne Got_16_Bit + xor bx,bx + mov bl,3 ;Mult by 3 + mul bx + shr ax,1 ;Div by 2 to get 1.5 + mov si,ax ;Get the final buffer offset + mov ax,[si]+8000h ;Get new cluster + test [bp].Last_Found_Cluster,1 ;Was last cluster odd? + jnz Odd_Result ;If Carry set it was odd + and ax,0FFFh ;Keep low 12 bits + jmp short Test_EOF + +Odd_Result: + mov cl,4 ;Keep high 12 bits for odd + shr ax,cl +Test_EOF: + cmp ax,0FF8h ;Is it last cluster? + jae Got_Cluster_Done ;Yep, all done here + jmp short Not_Last_CLuster + +Got_16_Bit: + shl ax,1 ;Multiply cluster by 2 + mov si,ax ;Get the final buffer offset + mov ax,[si]+8000h ;Get new cluster + cmp ax,0FFF8h + jae Got_Cluster_Done + +Not_Last_Cluster: + mov [bp].EOF,not End_Of_File ;Assume last cluster + +Got_Cluster_Done: + ret + + + + +Relocate_Length equ $ - Read_In_FAT +Total_Length label byte +LoadBIO_Size equ $ - Start + +cseg ends +end start diff --git a/SRC/BIOS/MSLOAD.INC b/SRC/BIOS/MSLOAD.INC new file mode 100644 index 0000000..eb8deeb --- /dev/null +++ b/SRC/BIOS/MSLOAD.INC @@ -0,0 +1,52 @@ + ;3.30 +Stack_Frame STRUC ;3.30 +Number_Of_Heads dw 0 ;3.30 +Size_Cluster dw 0 ;3.30 +Logical_Sector dw 0 ;3.30 +Sector_Count dw 0 ;3.30 +Number_Of_FAT_Sectors dw 0 ;3.30 +Hidden_Sectors dw 0 ;3.30 +Sector_Size dw 0 ;3.30 +Reserved_Sectors dw 0 ;3.30 +Last_Found_Cluster dw 0 ;3.30 +Next_BIO_Location dw 0 ;3.30 +First_Sector dw 0 ;3.30 +Sectors_Per_Track dw 0 ;3.30 +Drive_Number db 0 ;3.30 +FAT_Size db 0 ;3.30 +Media_Byte db 0 ;3.30 +EOF db 0 ;3.30 + ;3.30 +Stack_Frame ENDS ;3.30 + ;3.30 + ;3.30 +BPB STRUC ;3.30 +JUMP DB 0 ;3.30 + DB 0 ;3.30 + DB 0 ;3.30 +OEM DB "IBM " ;3.30 + DB "3.3" ;3.30 +ByteSec DW 512 ; SIZE OF A PHYSICAL SECTOR ;3.30 +cAlloc DB 8 ; SECTORS PER ALLOCATION UNIT ;3.30 +cSecRes DW 1 ; NUMBER OF RESERVED SECTORS ;3.30 +cFat DB 2 ; NUMBER OF FATS ;3.30 +DirNum DW 512 ; NUMBER OF DIREC ENTRIES ;3.30 +NumSec DW 4*17*305-1 ; NUMBER OF SECTORS - NUMBER OF HI;3.30 DDEN SECTORS +MEDIA DB 0F8H ; MEDIA BYTE ;3.30 +cSecFat DW 8 ; NUMBER OF FAT SECTORS ;3.30 +SECLIM DW 17 ; SECTORS PER TRACK ;3.30 +HDLIM DW 4 ; NUMBER OF SURFACES ;3.30 +cSecHid DW 1 ; NUMBER OF HIDDEN SECTORS ;3.30 +hSecHid dw 0 ; high order word of Hidden Sector;3.30 s +BNumSec dd 0 ; 32 bit version of NUMBER OF SECT;3.30 ORS + ; (when 16 bit version is zero) ;3.30 +Other db 6 dup(?) ; reserved for later expansion ;3.30 +BPB ENDS ;3.30 + ;3.30 + ;3.30 + ;3.30 +End_Of_File equ 0FFh ;3.30 +FAT12_Bit equ 01h ;3.30 +FAT16_Bit equ 04h ;3.30 + ;3.30 + \ No newline at end of file diff --git a/SRC/BIOS/MSLOAD.OBJ b/SRC/BIOS/MSLOAD.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..9a2cc0f1f66a33cddf78b8e2cc2edff20f0fd559 GIT binary patch literal 754 zcmXw0O-NKx6h8O8H%}RHe2l}OV`vZ~NzG=4pkQp_&u!-AW}f7Uw(PcfWJaJ@;u25PKp$ zx9>CoRCPom*ZR7zNS%?cZmAP9xhv9#;GcDZ{f!HRe6+}@MID5EnXQ81V=s04t9mDd0pR3?xIcm=R5S>mqk3zN7D6G;n8amPeP$$j0R3V|i8+cA>@p~}Pw z#KkgITrE~7EXQWc7s*U<{+qRm)rrw+oyv?lMe5S2RGFyZux3V;00Hxs5I80??CsJh zq<8-}DbDLDcT4bS&e~5#w@wu;)l`nR1q2BGFkHCLXOViaBTKoBGr7WLRyS$04#!|`}=FN=E5?Xlveq#P4jQvS1Q>{&V(zl`@=*{!TIYvkF1 zRh(HAt`2P0-xwT<)%CK20n`=&`B3gz@TiT-afM*deZ%?>=Al?B%&ui OUTPUT CHAR IN DL ;3.30 + call PRNOP ; print character + jnz PrRetry ; if error, try to print again + loop PRN$LOOP ; if more character, keep printing +EXVEC3: + jmp EXIT + +PrRetry: + dec DI ; undo the inc above... + dec BX ; Decrement retry count + jnz PRN$out ; See if done with retrys +PMESSG: + JMP ERR$CNT ; if so return with the error +PRN$WRIT ENDP ;3.30 + +;---------------------------------------------------------------- +; : +; PRINTER STATUS ROUTINE : +; : +;---------------------------------------------------------------- +; + PUBLIC PRN$STAT ;3.30 +PRN$STAT PROC NEAR ;3.30 + ASSUME DS:CODE ; SET BY PRINTER DEVICE DRIVER ENT;3.30 RY + ;3.30 + call PRNSTAT ; get the status + jnz PMESSG ; if error jump to error routine + MOV AL,9 ; AGAIN, ASSUME OUT OF PAPER... ;3.30 + TEST AH,NOPAPERSTATUS ;3.30 + JNZ PMESSG ;3.30 + TEST AH,NOTBUSYSTATUS ;3.30 + jnz EXVEC3 ; if not busy return via EXVEC3 + JMP BUS$EXIT ; else busy, return to busy exit ;3.30 +PRN$STAT ENDP ;3.30 + + + +; +; PRNSTAT get printer status +; PRNOP print a character +; +; PRNSTAT and PRNOP are two routines which call on the ROM-BIOS +; printer routines. The routines share code which calls on the bios and +; then determines which, if any, error occured. PRNSTAT and PRNOP differ +; only by the value put into AH before the ROM-BIOS call. +; +; INPUT if PRNOP then character in AL +; +; OUTPUT - AL holds error code +; - AH status byte from printer +; - flag NZ if error +PRNSTAT PROC NEAR ;3.30 + mov AH, 2 ; set command for get status ;3.30* +PRNOP: ;3.30* + call GETDX ; determine which printer ;3.30* + int 17h ; call ROM-BIOS printer routine ;3.30* + + TEST AH,IOERRSTATUS ; I/O ERROR? ;3.30 + JZ CHECKNOTREADY ; NO, TRY NOT READY ;3.30 + ;3.30 +; AT THIS POINT, WE KNOW WE HAVE AN ERROR. THE CONVERSE IS NOT TRUE. ;3.30 + ;3.30 + MOV AL,9 ; FIRST, ASSUME OUT OF PAPER ;3.30 + TEST AH,NOPAPERSTATUS ; OUT OF PAPER SET? ;3.30 + JNZ RET1 ; YES, ERROR IS SET ;3.30 + INC AL ; INDICATE I/O ERROR ;3.30 +RET1: ;3.30 + ;3.30 +; WE HAVE TRIAGED NOW FOR OUT OF PAPER AND IO ERR (IGNORING TIME-OUT) ;3.30 + ;3.30 + RET ; RETURN WITH ERROR ;3.30 + ;3.30 +; THE BITS SAID NO ERROR. UNFORTUNATELY, THERE MAY BE OTHER THINGS AT WOR;3.30 K +; HERE. ;3.30 + ;3.30 +CHECKNOTREADY: ;3.30 + MOV AL,2 ; ASSUME NOT-READY ;3.30 + TEST AH,TIMEOUTSTATUS ; IS TIME-OUT SET? ;3.30 + ; IF NZ THEN ERROR, ELSE OK??? ;3.30 +PRNOP2: ;3.30 + RET ;3.30 +PRNSTAT ENDP ;3.30 + + +;---------------------------------------------------------------- +; : +; Output until Busy : +; : +; Output until busy. This entry point is used EXCLUSIVELY by : +; the print spoolers. Under no curcumstances should the device : +; driver block waiting for the device to become ready. : +; : +; Inputs: CX has count of bytes to output. : +; ES:DI points to source buffer : +; Outputs: Set the number of bytes transferred : +; appropriately. : +; : +;---------------------------------------------------------------- + + PUBLIC PRN$TILBUSY ;3.30 +PRN$TILBUSY PROC NEAR ;3.30 + ASSUME DS:CODE ; SET BY PRINTER DEVICE DRIVER ENT;3.30 RY + ;3.30 + push DS ; save DS + push ES ; copy ES to DS + pop DS + ASSUME DS:NOTHING ;3.30 + + mov SI,DI ; everything is set for LODSB +PRN$TilBLoop: + push CX + push BX + xor BX,BX + mov BL,CS:[PRINTDEV] + shl BX,1 + mov CX,CS:WAIT_COUNT[BX] ; wait COUNT times to come ready + pop BX +PRN$GetStat: + call PrnStat ; get status + jnz PRN$BPERR ; if error jump to error routine + TEST AH,10000000B ; READY YET? ;3.30 + loopz PRN$GetStat ; if busy keep trying + pop CX ; get original count + jz PRN$BErr ; still not ready => done + lodsb + XOR AH,AH ;3.30 + call PrnOp ; print the character + jnz PRN$BErr ; error + loop PRN$TilBLoop ; go for more +PRN$B: + pop DS ; recover DS + lds BX,CS:[PTRSAV] ; get pointer to header + ASSUME DS:NOTHING ;3.30 + + sub WORD PTR [BX].COUNT,CX ; Determine number of succ. I/O's + jmp Exit ; all done, successful return +PRN$TILBUSY ENDP ;3.30 + +PRN$BPERR PROC NEAR ;3.30 + ASSUME DS:CODE ;3.30 + + pop CX ; recover number of char left +PRN$BErr: + pop DS ; get pointer to header + lds BX,CS:[PTRSAV] + ASSUME DS:NOTHING ;3.30 + + sub WORD PTR [BX].COUNT,CX ; Determine number of succ. I/O's + jmp err$exit ; jump to error exit +PRN$BPERR ENDP ;3.30 + + +; +; Prn$GenIOCTL: +; +; Manipulates the value in WAIT_COUNT depending on the value passed in the +; Generic IOCTL packet. +; It either sets or returns the current value for the retry count for the +; device. +; + PUBLIC PRN$GENIOCTL ;3.30 +PRN$GENIOCTL PROC NEAR ;3.30 + ASSUME DS:CODE ; SET BY PRINTER DEVICE DRIVER ENT;3.30 RY + + les di,[PTRSAV] + cmp es:[di].MajorFunction,IOC_PC + je PrnFunc_OK +PrnFuncErr: + jmp CMDERR + +PrnFunc_OK: + mov al,es:[di].MinorFunction + les di,es:[di].GenericIOCTL_Packet + xor bx,bx + mov bl,[PRINTDEV] ; get index into retry counts + shl bx,1 + mov CX,WAIT_COUNT[BX] ; pull out retry count for device + cmp al,GET_RETRY_COUNT + jz PrnGetCount + cmp al,SET_RETRY_COUNT + jnz PrnFuncErr + mov cx,es:[di].RC_Count +PrnGetCount: + mov WAIT_COUNT[BX],CX ; place "new" retry count + mov es:[di].RC_Count,cx ; return current retry count + jmp EXIT + +PRN$GENIOCTL ENDP ;3.30 +CODE ENDS ;3.30 + END ;3.30 diff --git a/SRC/BIOS/MSLPT.OBJ b/SRC/BIOS/MSLPT.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..1299fb38ab19fac5bf3935f3d45e6ef182a38bc0 GIT binary patch literal 535 zcmYjOy=xO;82`Q3+A!-J3SSp`bW+@@@H?)2aBp$)L;o{GQ*}J3Ipe`dZX#i?e42P_P5X zb)Flz{Rx`JR(I~fTKtEA3(60oYPRmpZ)1v zUQd4Ia*%u_?zKkj;bJb$cxEDL7jF;twOq1;GG7}0z7y4ts#zKMd|Dko2JWhsGR2Sc zUc9(B`DXs)%To0{nQjCNRNDK0k+%SA&@bxo6iHU*Ub1ArR6m+@s>K+F@@1nEz~ +; message fTestINIT, <"Begin BDS initialization"> +; +; +; MNUM Print the value in a register or memory location on +; the screen. Value is displayed in hex. +; Usage: +; MNUM bitpattern, valueLocation +; +; valueLocation is typically a regester: +; +; mnum fTestCom, AX +; mnum fTestDisk, DX +; +; ValueLocation can also be a memory location: +; +; mnum fTestINIT, Final_Dos_Location +; +; If no valueLocation is given the macro defaults to +; the BX register. +; +; ZWAIT Stops the program until any key is pressed. +; +; +; The three macros preserve all register values. If "test" is zero +; defined during assembly then the marco produce no code. +; + + IF TEST ;3.30 + IFNDEF MSGOUT ;3.30 + EXTRN MSGOUT:NEAR,MSGNUM:NEAR ;3.30 + ENDIF ;3.30 + IFNDEF NUMBUF ;3.30 + EXTRN NUMBUF:BYTE,DIGITS:BYTE,FTESTBITS:WORD ;3.30 + ENDIF ;3.30 + IFNDEF DUMPBYTES ;3.30 + EXTRN DUMPBYTES:NEAR,OUTCHAR:NEAR,HEX_TO_ASCII:NEAR ;3.30 + ENDIF ;3.30 + + + +fTestALL equ 1111111111111111b ; watch everything +fTestHARD equ 0000000000000001b ; watch hard disk initialization +fTest96 equ 0000000000000010b ; watch 96 tpi activity +FTEST13 EQU 0000000000000100B ; WATCH INT 13 ACTIVITY ;3.30 +FTESTCOM EQU 0000000000001000B ; WATCH PACKET ACTIVITY ;3.30 +FTESTINIT EQU 0000000000010000B ; WATCH INITIALIZATION MESSAGES ;3.30 +FTESTDISK EQU 0000000000100000B ; WATCH DISK DEVICE DRIVER CALLS ;3.30 +FTESTCON EQU 0000000001000000B ; WATCH SYSTEM WAIT ACTIVITY IN CO;3.30 NSOLE +FtestClock equ 0000000010000000b ; wathc clock device 5/2/86 ;3.30 + + +; +; message macro -- see above for description +; + +MESSAGE MACRO Bits,msg + LOCAL A,B ;3.30 + jmp SHORT b +a: db msg,0 +b: push SI + push AX + mov AX,Bits + mov SI,OFFSET a + call MSGOUT + pop AX + pop SI +endm + + +; +; mnum macro -- see above for description +; + +MNum MACRO Bits,num + push AX +ifb + mov AX,Bits + call MSGNUM +else + push BX + mov BX,num + mov AX,Bits + call MSGNUM + pop BX +endif + pop AX +endm + + +; +; zwait macro -- see above for description +; + +ZWAIT MACRO + Message fTestALL,<"? "> + CALL ZWAITrtn +ENDM + +ZWAITrtn: + pushf ; save the flags + push AX ; preserve AX + xor AH, AH ; set command to get character ;3.30* + int 16h ; call rom keyboard routine ;3.30* + pop AX ; restore AX + popf ; restore the flags + ret + +;Dump_byte dumps the memory contents in hex. ;3.30 +;DUMPOFFLABEL should be a label or a variable defined in DUMPSEG. ;3.30 +DUMP_BYTE MACRO DUMPSEG, DUMPOFFLABEL, BYTELENGTH ;3.30 + push es ;3.30 + PUSH DS ;3.30 + PUSH SI ;3.30 + PUSH CX ;3.30 + ;3.30 + MOV CX, DUMPSEG ;3.30 + MOV DS, CX ;3.30 + MOV SI, OFFSET DUMPOFFLABEL ;3.30 + MOV CX, BYTELENGTH ;3.30 + call dumpbytes ;3.30 + ;3.30 + POP CX ;3.30 + POP SI ;3.30 + POP DS ;3.30 + pop es ;3.30 + ENDM ;3.30 + ;3.30 +;Dump_Byte_Reg dumps the memory contents in hex. - 4/9/86 ;3.30 +;DUMPOFFREG should be a register contains the offset value in DUMPSEG. ;3.30 +DUMP_BYTE_REG MACRO DUMPSEG, DUMPOFFREG, BYTELENGTH ;3.30 + push es ;3.30 + PUSH DS ;3.30 + PUSH SI ;3.30 + PUSH CX ;3.30 + ;3.30 + MOV CX, DUMPSEG ;3.30 + MOV DS, CX ;3.30 + MOV SI, DUMPOFFREG ;3.30 + MOV CX, BYTELENGTH ;3.30 + call dumpbytes ;3.30 + ;3.30 + POP CX ;3.30 + POP SI ;3.30 + POP DS ;3.30 + pop es ;3.30 + ENDM ;3.30 + +else + ; if test is not defined then make macro into null statements +Message macro +ENDM + +MNUM macro +ENDM + +ZWAIT macro +ENDM + +DUMP_BYTE MACRO ;3.30 + ENDM ;3.30 +DUMP_BYTE_REG MACRO ;3.30 + ENDM ;3.30 + ENDIF ;3.30 + ;3.30 +PATHSTART MACRO INDEX,ABBR ;3.30 + IFDEF PATHGEN ;3.30 + PUBLIC ABBR&INDEX&S,ABBR&INDEX&E ;3.30 + ABBR&INDEX&S LABEL BYTE ;3.30 + ENDIF ;3.30 + ENDM ;3.30 + ;3.30 +PATHEND MACRO INDEX,ABBR ;3.30 + IFDEF PATHGEN ;3.30 + ABBR&INDEX&E LABEL BYTE ;3.30 + ENDIF ;3.30 + ENDM ;3.30 + diff --git a/SRC/BIOS/MSSTACK.INC b/SRC/BIOS/MSSTACK.INC new file mode 100644 index 0000000..a6908ce --- /dev/null +++ b/SRC/BIOS/MSSTACK.INC @@ -0,0 +1,306 @@ +; MSStack.inc +; +; Interrupt level 2, 3, 4, 5, 6, 7,(10, 11, 12, 14, 15 - AT level) +; should follow the standard Interrupt Sharing Scheme which has +; a standard header structure. +; Fyi, the following shows the relations between +; the interrupt vector and interrupt level. +; VEC(Hex) 2 8 9 A B C D E 70 72 73 74 76 77 +; LVL(Deci) 9 0 1 2 3 4 5 6 8 10 11 12 14 15 +; MSSTACK module modifies the following interrupt vectors +; to meet the standard Interrupt Sharing standard; +; A, B, C, D, E, 72, 73, 74, 76, 77. +; Also, for interrupt level 7 and 15, the FirstFlag in a standard header +; should be initialized to indicat whether this interrupt handler is +; the first (= 80h) or not. The FirstFlag entry of INT77h's +; program header is initialized in STKINIT.INC module. +; FirstFlag is only meaningful for interrupt level 7 and 15. +; + +; User specifies the number of stack elements - default = 9 +; minimum = 8 +; maximum = 64 +; +; Intercepts Asynchronous Hardware Interrupts only +; +; Picks a stack from pool of stacks and switches to it +; +; Calls the previously saved interrupt vector after pushing flags +; +; On return, returns the stack to the stack pool +; + + +; This is a modification of STACKS: +; 1. To fix a bug which was causing the program to take up too much space. +; 2. To dispense stack space from hi-mem first rather than low-mem first. +; . Clobbers the stack that got too big instead of innocent stack +; . Allows system to work if the only stack that got too big was the most +; deeply nested one +; 3. Disables NMI interrupts while setting the NMI vector. +; 4. Does not intercept any interupts on a PCjr. +; 5. Double checks that a nested interrupt didn't get the same stack. +; 6. Intercepts Ints 70, 72-77 for PC-ATs and other future products + +;The following variables are for MSSTACK.inc + EVEN + dw 0 ; SPARE FIELD BUT LEAVE THESE IN ORDER +StackCount dw 0 +StackAt dw 0 +StackSize dw 0 +Stacks dw 0 + dw 0 + +FirstEntry dw Stacks +LastEntry dw Stacks+(DefaultCount*EntrySize)-EntrySize +NextEntry dw Stacks+(DefaultCount*EntrySize)-EntrySize + +;End of variables defined for MSSTACK. + +;******************************************************************* +;Macro Interrupt handler for the ordinary interrupt vectors and +;the shared interrupt vectors. +;***************************** +Stack_Main MACRO AA + ASSUME DS:NOTHING + ASSUME ES:NOTHING + ASSUME SS:NOTHING +PUBLIC Int&AA +PUBLIC Old&AA +;----------------------------- + ife IntSharingFlag ;if not IntSharingFlag +;----------------------------- + Old&AA DD 0 +Int&AA PROC FAR +;----------------------------- + else ;for shared interrupt. A Header exists. + +PUBLIC FirstFlag&AA +Int&AA PROC FAR + jmp short Entry_Int&AA&_Stk + Old&AA dd 0 ;Forward pointer + dw 424Bh ;compatible signature for Int. Sharing + FirstFlag&AA db 0 ;the firstly hooked. + jmp short Intret_&AA ;Reset routine. We don't care this. + db 7 dup (0) ;Reserved for future. +Entry_Int&AA&_Stk: +;----------------------------- + endif +;----------------------------- + +; +; Keyboard interrupt must have a three byte jump, a NOP and a zero byte +; as its first instruction for compatibility reasons + ifidn <&aa>,<09> + jmp Keyboard_lbl + nop + db 0 +Keyboard_lbl label near + endif + +; This patches INTERRUPT 75h to be "unhooked". We do this Wierdness, +; rather than never hooking INT 75h, to maintain maximum compat. with IBMs +; post production patch. + push ax + + ifidn <&aa>,<02> + +; ********************************************************************* +; +; This is special support for the P12 / NMI handler +; +; On the P12, there is a situation where an NMI can be caused by +; using the "OUT" instructions to certain ports. When this +; occurs, the P12 hardware *GUARANTEES* that **NOTHING** can stop +; the NMI or interfere with getting to the NMI handler. This +; includes other type of interrupts (hardware and software), and +; also includes other type of NMI's. When any NMI has occured, +; no other interrtupt (hardware, software or NMI) can occur until +; the software takes specific steps to allow further interrupting. +; +; For P12, the situation where the NMI is generated by the "OUT" +; to a control port requires "fixing-up" and re-attempting. In +; otherwords, it is actually a "restartable exception". In this +; case, the software handler must be able to get to the stack in +; order to figure out what instruction caused the problem, where +; it was "OUT"ing to and what value it was "OUT"ing. Therefore, +; we will not switch stacks in this situation. This situation is +; detected by interrogating port 62h, and checking for a bit value +; of 80h. If set, *****DO NOT SWITCH STACKS*****. +; +; ********************************************************************* + + push es + mov ax,0f000h + mov es,ax + cmp byte ptr es:[0fffeh],0f9h ;check if P12 + pop es + jne Normal&aa + + in al,62h + test al,80h + jz Normal&aa + +Special&aa: + pop ax + jmp dword ptr Old&aa + +Normal&aa: + +; ********************************************************************* + + endif + + push bp + push es + mov es, cs:[STACKS+2] ; Get segment of stacks + + mov bp,NextEntry ; get most likely candidate + mov al,Allocated + xchg AllocByte,al ; grab the entry + cmp al,Free ; still avail? + jne NotFree&aa + + sub NextEntry,EntrySize ; set for next interrupt + +Found&aa: + mov SavedSP,sp ; save sp value + mov SavedSS,ss ; save ss also +; mov IntLevel,aa&h ; save the int level + + mov ax,bp ; temp save of table offset + + mov bp,NewSP ; get new SP value + cmp es:[bp],ax ; check for offset into table + jne FoundBad&aa + + mov ax,es ; point ss,sp to the new stack + mov ss,ax + mov sp,bp + + pushf ; go execute the real interrupt handler + call dword ptr old&aa ; which will iret back to here + + mov bp,sp ; retrieve the table offset for us + mov bp,es:[bp] ; but leave it on the stack + mov ss,SavedSS ; get old stack back + mov sp,SavedSP + +; cmp AllocByte,Allocated ; If an error occured, +; jne NewError&aa ; do not free us + + mov AllocByte,Free ; free the entry + mov NextEntry,bp ; setup to use next time + +NewError&aa: + pop es + pop bp ; saved on entry + pop ax ; saved on entry + +INTRET_&AA: ;3.30 + iret ; done with this interrupt + +NotFree&aa: + cmp al,Allocated ; error flag + je findnext&aa ; no, continue + xchg AllocByte,al ; yes, restore error value + +FindNext&aa: + call LongPath + jmp Found&aa + +FoundBad&aa: + cmp bp,FirstEntry + jc findnext&aa + mov bp,ax ; flag this entry + mov AllocByte,Clobbered +; add bp,EntrySize ; and previous entry +; mov AllocByte,Overflowed +; sub bp,EntrySize + jmp findnext&aa ; keep looking + +int&aa endp + + + endm + +;***************************** ;3.30 +;End of Macro definition ;3.30 +;******************************************************************** ;3.30 +; THESE ARE THE INDIVIDUAL INTERRUPT HANDLERS ;3.30 + ;3.30 + IRP A,<02,08,09,70> ;3.30 + IntSharingFlag=0 ;3.30 + Stack_Main &A ;3.30 + ENDM ;3.30 + ;3.30 + IRP A,<0A,0B,0C,0D,0E,72,73,74,76,77> ;3.30 + IntSharingFlag=1 ;3.30 + Stack_Main &A ;3.30 + ENDM ;3.30 + ;3.30 +;******************************************************************** ;3.30 +;Common routines ;3.30 + +longpath: + mov bp,LastEntry ; start with last entry in table + +LPLOOPP: ;3.30 + cmp AllocByte,Free ; is entry free? + jne inuse ; no, try next one + + mov al,Allocated + xchg AllocByte,al ; allocate entry + cmp al,Free ; is it still free? + je found ; yes, go use it + + cmp al,Allocated ; is it other than Allocated or Free? + je inuse ; no, check the next one + + mov AllocByte,al ; yes, put back the error state + +inuse: + cmp bp,FirstEntry + je Fatal + sub bp,EntrySize + JMP LPLOOPP ;3.30 + +found: + ret + + page + +fatal proc near + push ds ;3.30 + mov ax, 0f000h ;loook at the model byte ;3.30 + mov ds, ax ;3.30 + cmp ds:byte ptr [0fffeh], 0f9h ;convertible ;3.30 + pop ds ;3.30 + jne Skip_NMIS ;3.30 + ;3.30 + mov al,07h ; disable p12 NMIs + out 72h,al + +Skip_NMIS: ;3.30 + cli ; disable and mask + mov al,0ffh ; all other ints + out 021h,al + out 0a1h,al + + mov si,cs + mov ds,si + mov si,offset fatal_msg + +fatal_loop: + lodsb + cmp al,'$' + je fatal_done + + mov bl,7 ;3.30* + mov ah,14 ;3.30* + int 010h ; whoops, this enables ints ;3.30* + jmp fatal_loop + +fatal_done: + jmp fatal_done +fatal endp diff --git a/SRC/BIOS/MSVOLID.INC b/SRC/BIOS/MSVOLID.INC new file mode 100644 index 0000000..d1a9588 --- /dev/null +++ b/SRC/BIOS/MSVOLID.INC @@ -0,0 +1,297 @@ +;------------------------------------------------------------------------- +; +; File: msvolid.asm +; This file contains the volume_id subroutines and data structures. +; +; Routines in this file are: +; Set_Volume_ID - main routine, calls other routines. +; read_volume_id - read the volume ID and tells if it has +; been changed. +; Transfer_volume_id - copy the volume ID from TMP to special +; drive. +; Check_Volume_ID - compare volume ID in TMP area with one +; expected for drive. +; Fat_Check - see of the fatID has changed in the +; specified drive. +; Init_Vid_loop - set up for VID scan or move +; +; +;------------------------------------------------------------------------- + +; +; length of the volume id +; + +vid_size equ 12 + + PATHSTART 001,VOLID ;3.30 + +; +; null volume id +; + +nul_vid db "NO NAME ",0 + +; +; data scratch area used to hold volume ids +; + +tmp_vid db "NO NAME ",0 + + PATHEND 001,VOLID ;3.30 + +; +; Set_Volume_ID +; If drive has changeline support, read in and set the volume_ID +; and the last FAT_ID byte. If no change line support then do nothing. +; +; On entry: +; DS:DI points to the BDS for this disk. +; AH contains media byte +; +; On Exit: +; Carry clear: +; Successful call +; Carry set +; Error and AX has error code +; + +Set_Volume_ID: + PUBLIC SET_VOLUME_ID ;3.30 + push dx ; save registers + push ax + CALL HasChange ; does drive have changeline support? + jz setvret ; no, get out + push di + call read_volume_ID ; read the volume ID + pop di + jc SetErr ; if error go to error routine + call transfer_volume_ID ; copy the volume id to special drive + call ResetChanged ; restore value of change line + +setvret: ; SET Volume RETurn + clc ; no error, clear carry flag + pop ax ; restore registers + pop dx + ret +SetErr: + pop dx ; pop stack but don't overwrite AX + pop dx ; restore DX + ret + + + +root_sec DW ? ;Root sector # + + + + +; +; read_volume_id read the volume ID and tells if it has been changed. +; +; On entry: +; DS:DI points to current BDS for drive. +; On Exit: +; Carry Clear +; SI = 1 No change +; SI = 0 ? +; SI = -1 Change +; +; Carry Set: +; Error and AX has error code. +; + +read_volume_id: + push ES ; preserve registers + push DX + push CX + push BX + push AX + push DS ; Preserve Current BDS + push DI + push cs ; get ES segment correct + pop es + push cs ; get DS segment correct + pop ds + mov di,offset tmp_vid + mov si,offset nul_vid + mov cx,vid_size + rep movsb ; initialize tmp_vid to null vi_id + + pop DI ; Restore Current BDS + pop DS + mov al,byte ptr ds:[di].cFAT ; # of fats + mov cx,word ptr ds:[di].csecfat ; sectors / fat + mul cl ; size taken by fats + add ax,word ptr ds:[di].ressec ; add on reserved sectors + ; AX is now sector # (0 based) + mov cs:[root_sec],ax ; set initial value + mov ax,[di].cDir ; # root dir entries + mov cl,4 ; 16 entries/sector + shr ax,cl ; divide by 16 + mov cx,ax ; cx is # of sectors to scan +next_sec: + push cx ; save outer loop counter + mov ax,cs:[root_sec] ; get sector # + mov cx,word ptr ds:[di].seclim ; sectors / track + xor DX,DX + div cx + ; set up registers for call to read_sector + inc DX ; dx= sectors into track, ax= track count from 0 + mov cl,dl ; sector to read + xor DX,DX + div word ptr ds:[di].hdlim ; # heads on this disc + mov dh,dl ; Head number + mov ch,al ; Track # + call read_sector ; get first sector of the root directory, + ; ES:BX -> BOOT + jc ReadVIDErr ; error on read + mov cx,16 ; # of dir entries in a block of root + mov al,08h ; volume label bit +fvid_loop: + cmp byte ptr es:[bx],0 ; End of dir? + jz no_vid ; yes, no vol id + cmp byte ptr es:[bx],0E5h ; empty entry? + jz ent_loop ; yes, skip + test es:[bx+11],al ; is volume label bit set in fcb? + jnz found_vid ; jmp yes +ent_loop: + ADD BX,32 ;MJB003 ADD LENGTH OF DIRECTORY ENTRY ;3.30 + loop fvid_loop + pop cx ; outer loop + inc cs:[root_sec] ; next sector + loop next_sec ; continue +NotFound: + XOR SI,SI + jmp short fvid_ret + +found_vid: + pop cx ; clean stack of outer loop counter + mov si,bx ; point to volume_id + push ds ; preserve currnet BDS + push di + push es ; es:si points to volume id. + pop ds ; source segment + push cs + pop es ; destination segment + mov di,offset tmp_vid ; dest of volume_id + mov cx,vid_size -1 ; length of string minus NUL + rep movsb ; mov volume label to tmp_vid + xor al,al + stosb ; Null terminate + XOR SI,SI + pop DI ; restore current BDS + pop DS +fvid_ret: + pop ax + clc +RVIDRet: + pop BX ; restore register + pop CX + pop DX + pop ES + ret +no_vid: + pop cx ; clean stack of outer loop counter + jmp NotFound ; not found +ReadVIDErr: + pop SI + pop SI + jmp RVIDRet + + + +; +; Transfer_volume_id - copy the volume ID from TMP to special drive +; +; Inputs: DS:DI nas current BDS +; Outputs: BDS for drive has volume ID from TMP +; + +transfer_volume_ID: + push DS ; preserve current BDS + push DI + push ES + push SI + push CX + call init_vid_loop + cld + rep MOVSB ; transfer + pop CX + pop SI + pop ES + pop DI ; restore current BDS + pop DS + ret + + +; +; Check_Volume_ID - compare volume ID in TMP area with one expected for +; drive +; +; Inputs: DS:DI has current BDS for drive +; Outputs: SI = 0 if compare succeeds +; SI = -1 if compare fails. + +check_volume_id: + push DS ; preserve current BDS for drive + push DI + push ES + push CX + call init_vid_loop + cld + repz cmpsb ; are the 2 volume_ids the same? + mov si,0 ; assume unknown + jz check_vid_ret ; carry clear if jump taken + mov si,-1 ; failure +check_vid_ret: + pop CX + pop ES + pop DI ; restore current BDS + pop DS + ret + +; +; Fat_Check - see of the fatID has changed in the specified drive. +; - uses the FAT ID obtained from the boot sector. +; +; Inputs: MedByt is expected FAT ID +; DS:DI points to current BDS +; Output: Carry Clear +; SI = -1 if fat ID different, +; SI = 0 otherwise +; No other registers changed. + +FAT_CHECK: + push AX + xor SI, SI ; say FAT ID's are same. + mov AL, cs:MedByt + cmp AL, byte ptr [DI].Mediad ; compare it with the BDS medbyte + jz OKRET1 ; carry clear + dec SI +OkRet1: clc + pop AX + ret + + +; +; Init_Vid_loop - set up for VID scan or move +; +; Inputs: DS:DI pionts to BDS for the drive +; Outputs: DS:SI points to tmp_vid +; ES:DI points to vid for drive +; CX has size for VID compare +; + +init_vid_loop: + push ax + push ds + pop es + push cs + pop ds + mov si,offset tmp_vid ; source + add di,volid + mov cx,vid_size + pop ax + ret + diff --git a/SRC/BIOS/PUSHPOP.INC b/SRC/BIOS/PUSHPOP.INC new file mode 100644 index 0000000..aaa76eb --- /dev/null +++ b/SRC/BIOS/PUSHPOP.INC @@ -0,0 +1,20 @@ + IF1 ;3.30 + +SaveReg MACRO reglist ;; push those registers +IRP reg, + ?stackdepth = ?stackdepth + 1 + PUSH reg +ENDM +ENDM +.xcref SaveReg + + +RestoreReg MACRO reglist ;; pop those registers +IRP reg, + ?stackdepth = ?stackdepth - 1 + POP reg +ENDM +ENDM +.xcref RestoreReg + + ENDIF ;3.30 diff --git a/SRC/BIOS/READCLOC.INC b/SRC/BIOS/READCLOC.INC new file mode 100644 index 0000000..545a22f --- /dev/null +++ b/SRC/BIOS/READCLOC.INC @@ -0,0 +1,162 @@ +; SCCSID = @(#)readclock.asm 1.2 85/07/25 +;************************************************************************ +; +; read_real_date reads real-time clock for date and returns the number +; of days elapsed since 1-1-80 in si +; +read_real_date: ;mjb002 + PUSH AX + PUSH CX + PUSH DX + XOR AH,AH ; throw away clock roll over ;3.30* + INT 1AH ;3.30* + POP DX + POP CX + POP AX + + PUSH AX + PUSH BX + PUSH CX + PUSH DX + MOV CS:DAYCNT2,1 ;MJB002 REAL TIME CLOCK ERROR FLAG (+1 DA;3.30Y) + mov ah,4 ;mjb002 read date function code ;3.30* + int 1ah ;mjb002 read real-time clock ;3.30* + jnc read_ok ;mjb002 jmp success + jmp r_d_ret ;mjb002 jmp error +read_ok: ;mjb002 ******* get bcd values in binary ***** + mov byte ptr bin_date_time+0,ch ;mjb002 store as hex value + mov byte ptr bin_date_time+1,cl ;mjb002 ... + mov byte ptr bin_date_time+2,dh ;mjb002 ... + mov byte ptr bin_date_time+3,dl ;mjb002 ... + MOV CS:DAYCNT2,2 ;MJB002 READ OF R-T CLOCK SUCCESSFUL ;3.30 + call bcd_verify ;mjb002 verify bcd values in range + jc r_d_ret ;mjb002 jmp some value out of range + MOV CS:DAYCNT2,3 ;MJB002 READ OF R-T CLOCK SUCCESSFUL ;3.30 + call date_verify ;mjb002 verify date values in range + jc r_d_ret ;mjb002 jmp some value out of range + MOV CS:DAYCNT2,0 ;MJB002 VERIFY SUCCESSFUL ;3.30;3.30 + call in_bin ;mjb002 convert date to binary + ;mjb002 ******* years since 1-1-80 ********* + mov al,byte ptr bin_date_time+1 ;mjb002 get years into century + cbw ;mjb002 + cmp byte ptr bin_date_time+0,20 ;mjb002 20th century? + jnz century_19 ;mjb002 jmp no + add ax,100 ;mjb002 add in a century +century_19: ;mjb002 + sub ax,80 ;mjb002 subtract off 1-1-80 + mov cl,4 ;mjb002 leap year every 4 + div cl ;mjb002 al= # leap year blocks, ah= remainder + mov bl,ah ;mjb002 save odd years + cbw ;mjb002 zero ah + mov cx,366+3*365 ;mjb002 # of days in leap year blocks + mul cx ;mjb002 dx:ax is result + MOV CS:DAYCNT2,AX ;MJB002 SAVE COUNT OF DAYS ;3.30 + mov al,bl ;mjb002 get odd years count + cbw ;mjb002 + or ax,ax ;mjb002 is ax= 0? + jz leap_year ;mjb002 jmp if none + mov cx,365 ;mjb002 days in year + mul cx ;mjb002 dx:ax is result + ADD CS:DAYCNT2,AX ;MJB002 ADD ON DAYS IN ODD YEARS ;3.30 + jmp short leap_adjustment ;mjb002 account for leap year +leap_year: ;mjb002 possibly account for a leap day + cmp byte ptr bin_date_time+2,2 ;mjb002 is month february + jbe no_leap_adjustment ;mjb002 jan or feb. no leap day yet. +leap_adjustment: ;mjb002 account for leap day + INC CS:DAYCNT2 ;MJB002 ... ;3.30 +no_leap_adjustment: ;mjb002 ******* get days of month ******* + mov cl,byte ptr bin_date_time+3 ;mjb002 ... + xor ch,ch ;mjb002 + dec cx ;mjb002 because of offset from day 1, not day 0 + ADD CS:DAYCNT2,CX ;MJB002 ******* GET DAYS IN MONTHS PRECEE;3.30DING ***** + mov cl,byte ptr bin_date_time+2 ;mjb002 get month + xor ch,ch ;mjb002 + dec cx ;mjb002 january starts at offset 0 + shl cx,1 ;mjb002 word offset + mov si,offset month_table ;mjb002 beginning of month_table + add si,cx ;mjb002 point into month table + mov ax,word ptr [si];mjb002 get # days in previous months + ADD CS:DAYCNT2,AX ;MJB002 ... ;3.30 +r_d_ret: ;mjb002 + MOV SI,CS:DAYCNT2 ;MJB002 RESULT IN SI ;3.30 + POP DX + POP CX + POP BX + POP AX + ret ;mjb002 + +r_t_retj: + xor cx,cx + xor dx,dx + jmp r_t_ret +; +; Read_Real_Time reads the time from the RTC. on exit, it has the number of +; ticks (at 18.2 ticks per sec.) in CX:DX. +; +Read_Real_Time: + mov ah,2 ;3.30* + int 1AH ;3.30* + jc r_t_retj +oktime: + mov byte ptr bin_date_time,ch ; hours + mov byte ptr bin_date_time+1,cl ; minutes + mov byte ptr bin_date_time+2,dh ; seconds + mov byte ptr bin_date_time+3,0 ; unused for time + call bcd_verify + jc r_t_retj + call time_verify + jc r_t_retj + call in_bin + MOV ch,byte ptr bin_date_time + MOV cl,byte ptr bin_date_time+1 + MOV dh,byte PTR bin_date_time+2 + MOV dl,byte PTR bin_date_time+3 + message ftestinit,<"Read Time "> + mnum ftestinit,cx + message ftestinit,<" "> + mnum ftestinit,dx + message ftestinit, +; get time in ticks in CX:DX + CALL word ptr cs:TimeToTicks ;3.30 + message ftestinit,<"Conv Time "> + mnum ftestinit,cx + message ftestinit,<" "> + mnum ftestinit,dx + message ftestinit, +r_t_ret: + ret + +; +; in_bin converts bin_date_time values from bcd to bin +; +in_bin: ;mjb002 + mov al,byte ptr bin_date_time+0 ; century or hours + call bcd_to_bin ; ... + mov byte ptr bin_date_time+0,al ; + mov al,byte ptr bin_date_time+1 ; years or minutes + call bcd_to_bin ; ... + mov byte ptr bin_date_time+1,al ; + mov al,byte ptr bin_date_time+2 ; months or seconds + call bcd_to_bin ; ... + mov byte ptr bin_date_time+2,al ; + mov al,byte ptr bin_date_time+3 ; days (not used for time) + call bcd_to_bin ; ... + mov byte ptr bin_date_time+3,al ; + ret ; +; +; bcd_to_bin converts two bcd nibbles in al (value <= 99.) to +; a binary representation in al +; ah is destroyed +; +bcd_to_bin: ;mjb002 + mov ah,al ;mjb002 copy bcd number to ah + and ax,0f00fh ;mjb002 clear unwanted nibbles + mov bl,al ;mjb002 save units place + xchg ah,al ;mjb002 10's place to al + xor ah,ah ;mjb002 ah not wanted + mov cl,4 ;mjb002 shift count + shr ax,cl ;mjb004 swap nibbles + mov cl,10 ;mjb002 convert al to ... + mul cl ;mjb002 ... its binary value + add al,bl ;mjb002 add in units + ret ;mjb002 diff --git a/SRC/BIOS/STKINIT.INC b/SRC/BIOS/STKINIT.INC new file mode 100644 index 0000000..4c8e20f --- /dev/null +++ b/SRC/BIOS/STKINIT.INC @@ -0,0 +1,270 @@ +; +; To follow the standard interrupt sharing scheme, MSSTACK.ASM ;3.30 +; has been modified. This initialization routine also has to ;3.30 +; be modified because for the interrupt level 7 and 15, FirstFlag ;3.30 +; should be set to signal that this interrupt handler is the ;3.30 +; first handler hooked to this interrupt vector. ;3.30 +; We determine this by looking at the instruction pointed by ;3.30 +; this vector. If it is IRET, then this handler should be the ;3.30 +; first one. In our case, only the interrupt vector 77h is the ;3.30 +; interrupt level 15. (We don't hook interrupt level 7.) ;3.30 +; 9/10/1986 ;3.30 +; The followings are mainly due to M.R.Turner; PTM fix of P886 12/3/86 ;3.30 +; Some design changes are needed to the above interrupt sharing ;3.30 +; method. The above sharing scheme assumes that 1). Interrupt ;3.30 +; sharing is NEVER done on levels that have BIOS support. 2). "Phantom" ;3.30 +; interrupts would only be generated on levels 7 and 15. ;3.30 +; These assumptions are not true any more. We have to use the FirstFlag ;3.30 +; for EVERY level of interrupt. We will set the firstFlag on the following;3.30 +; conditions: ;3.30 +; a. if the CS portion of the vector is 0000, then "first" ;3.30 +; b. else if CS:IP points to valid shared header, then NOT "first" ;3.30 +; c. else if CS:IP points to an IRET, then "first" ;3.30 +; d. else if CS:IP points to DUMMY, then "first" ;3.30 +; where DUMMY is - the CS portion must be F000, and the IP portion must ;3.30 +; be equal to the value at F000:FF01. This location is the initial value ;3.30 +; from VECTOR_TABLE for interrupt 7, one of the preserved addresses in all;3.30 +; the BIOSes for all of the machines. ;3.30 +; ;3.30 +; System design group requests BIOS to handle the phantom interrupts. ;3.30 +; ;3.30 +; The "Phantom" interrupt is an illegal interrupt such as an interrupt ;3.30 +; produced by the bogus adapter card even without interrupt request is ;3.30 +; set. More specifically, 1). The 8259 has a feature when running in ;3.30 +; edge triggered mode to latch a pulse and present the interrupt when ;3.30 +; the processor indicates interrupt acknowledge (INTA). The interrupt ;3.30 +; pulse was exist at the time of INTA to get a "phantom" interrupt. ;3.30 +; 2). or, this is caused by adapter cards placing a glitch on the ;3.30 +; interrupt line. ;3.30 +; ;3.30 +; To handle those "phantom" interrupts, the main stack code will check ;3.30 +; the own FirstFlag, and if it is not "first" (which means the forward ;3.30 +; pointer points to the legal shared interrupt handler), then pass the ;3.30 +; control. If it is the first, then the following action should be ;3.30 +; taken. We don't have to implement skack logic in this case. ;3.30 +; ;3.30 +; To implement this logic, we rather choose a simple method. ;3.30 +; If ont of the above "FirstFlag" conditions is met, we are not ;3.30 +; going to hook this interrupt vector. The reason is if the original ;3.30 +; vector points to "IRET" and do nothing, we don't need ;3.30 +; to implement the stack logic for it. This will simplify implementation;3.30 +; while maintaining compatibility with the old version of DOS. ;3.30 +; This implies that in the main stack code, there might be a stack code ;3.30 +; that will never be used, a dead code. ;3.30 +; ;3.30 +; 12/3/86 ;3.30 + ;3.30 +;In - CS, DS -> sysinitseg, ES -> relocated stack code & data. ;3.30 + ;3.30 + PAGE ;3.30 +StackInit proc near ;3.30 + ;3.30 + PUSH AX ;SAVE ALL ;3.30 + PUSH DS ;3.30 + PUSH ES ;3.30 + PUSH BX ;3.30 + PUSH CX ;3.30 + PUSH DX ;3.30 + PUSH DI ;3.30 + PUSH SI ;3.30 + PUSH BP ;3.30 + ;3.30 +;Currently ES -> stack code area ;3.30 + MOV AX, cs:[STACK_COUNT] ;defined in CS ;3.30 + MOV es:[STACKCOUNT], AX ;defined in STACK CODE AREA ;3.30 + MOV AX, [STACK_SIZE] ;in CS ;3.30 + MOV es:[STACKSIZE], AX ; ;3.30 + MOV AX, WORD PTR cs:[STACK_ADDR] ; OFFSET ;3.30 + MOV WORD PTR es:[STACKS], AX ;3.30 + MOV AX, WORD PTR cs:[STACK_ADDR+WORD] ; SEGMENT ;3.30 + MOV WORD PTR es:[STACKS+WORD], AX ;3.30 + ;3.30 +; INITIALIZE THE DATA FIELDS WITH THE PARAMETERS ;3.30 + ;3.30 +; "FIRSTENTRY" WILL ALWAYS BE AT STACKS ;3.30 + ;3.30 + MOV BP, word ptr es:STACKS ; GET OFFSET OF STACK ;3.30 + MOV es:FIRSTENTRY,BP ;3.30 + ;3.30 +; THE STACKS WILL ALWAYS IMMEDIATELY FOLLOW THE TABLE ENTRIES ;3.30 + ;3.30 + MOV AX,ENTRYSIZE ;3.30 + MOV CX,es:STACKCOUNT ;3.30 + MUL CX ;3.30 + ADD AX,BP ;3.30 + MOV es:STACKAT,AX ;3.30 + MOV BX,AX ;3.30 + SUB BX,2 ;3.30 + ;3.30 +; ZERO THE ENTIRE STACK AREA TO START WITH ;3.30 + ;3.30 + MOV DI,es:STACKAT ;3.30 + MOV AX,es:STACKSIZE ;3.30 + MUL CX ;3.30 + MOV CX,AX ;3.30 + xor ax,ax ;3.30 + push es ;3.30 + pop ds ;ds = Relocated stack code seg.;3.30 + assume ds:nothing ;3.30 +;Now, DS -> stack code area ;3.30 + MOV ES, word ptr ds:[STACKS+2] ; GET SEGMENT OF STACK AREA.;3.30 + CLD ;3.30 + REP STOSB ;3.30 + ;3.30 + MOV CX, ds:STACKCOUNT ;3.30 + ;3.30 +; LOOP FOR "COUNT" TIMES, BUILDING A TABLE ENTRY ;3.30 +; cs = sysinitseg, ds = Relocated stack code seg , es = segment of stack space;3.30 +; CX = NUMBER OF ENTRIES ;3.30 +; ES:BP => BASE OF STACKS - 2 ;3.30 +; ES:BX => FIRST TABLE ENTRY ;3.30 + ;3.30 +BUILDLOOP: ;3.30 + MOV ALLOCBYTE,FREE ;3.30 + MOV INTLEVEL,AL ;AX = 0 ;3.30 + MOV SAVEDSP,AX ;3.30 + MOV SAVEDSS,AX ;3.30 + ADD BX,ds:STACKSIZE ;3.30 + MOV NEWSP,BX ;3.30 + MOV ES:[BX],BP ;3.30 + ADD BP,ENTRYSIZE ;3.30 + ;3.30 + LOOP BUILDLOOP ;3.30 + ;3.30 + SUB BP,ENTRYSIZE ;3.30 + MOV ds:LASTENTRY,BP ;3.30 + MOV ds:NEXTENTRY,BP ;3.30 + ;3.30 + push ds ;3.30 + mov ax, 0f000h ;loook at the model byte ;3.30 + mov ds, ax ;3.30 + cmp ds:byte ptr [0fffeh], 0f9h ;convertible?(P12) ;3.30 + pop ds ;3.30 + jne Skip_disableNMIS ;3.30 + ;3.30 + MOV AL,07H ; DISABLE P12 NMIS ;3.30 + OUT 72H,AL ;3.30 + ;3.30 +Skip_disableNMIS: ;3.30 + XOR AX,AX ;3.30 + MOV es,AX ;es - SEGID OF VECTOR TABLE AT 0;3.30 + ASSUME es:NOTHING ;ds - Relocated Stack code segment;3.30 + ;3.30 + CLI ;3.30 + ;3.30 + IRP AA,<02,08,09,70> ;3.30 + ;3.30 + MOV SI,AA&H*4 ;PASS WHERE VECTOR IS TO BE ADJUSTED ;3.30 + mov di, offset Int19OLD&AA ;we have to set OLD&AA for Int19 handler too.;3.30 + MOV BX,OFFSET OLD&AA ;PASS WHERE TO SAVE ORIGINAL OWNER POINTER;3.30 + MOV DX,OFFSET INT&AA ;PASS WHERE NEW HANDLER IS ;3.30 + CALL NEW_INIT_LOOP ;ADJUST THE VECTOR TO NEW HANDLER, ;3.30 + ; SAVING POINTER TO ORIGINAL OWNER ;3.30 + ENDM ;3.30 + ;3.30 + IRP AA,<0A,0B,0C,0D,0E,72,73,74,76,77> ;shared interrupts ;3.30 + ;3.30 + MOV SI,AA&H*4 ;PASS WHERE VECTOR IS TO BE ADJUSTED ;3.30 + push ds ;save relocated stack code segment ;3.30 + lds bx, es:[si] ;ds:bx -> original interrupt handler ;3.30 + push ds ;3.30 + pop dx ;dx = segment value ;3.30 + + cmp dx,0 + jz int&AA&_first + + cmp byte ptr ds:[bx],0cfh ;Does vector point to an IRET? + jz int&AA&_first + + cmp word ptr ds:[bx.6],424Bh ;Magic offset (see INT&AA, msstack.inc) + jz int&AA&_Not_first + + cmp dx,0f000h ;ROM BIOS segment + jnz int&AA&_Not_first + + push es + push dx + mov dx,0f000h + mov es,dx + cmp bx,word ptr es:0ff01h + pop dx + pop es + jz int&AA&_first + +int&AA&_Not_first: ;Not the first. We are going to hook vector.;3.30 + pop ds ;3.30 + mov di, offset Int19OLD&AA ;we have to set OLD&AA for Int19 handler too.;3.30 + mov BX, OFFSET OLD&AA ;PASS WHERE TO SAVE ORIGINAL OWNER POINTER;3.30 + MOV DX, OFFSET INT&AA ;PASS WHERE NEW HANDLER IS ;3.30 + CALL NEW_INIT_LOOP ;ADJUST THE VECTOR TO NEW HANDLER, SAVING;3.30 + ;POINTER TO ORIGINAL OWNER. ;3.30 + jmp short int&AA&_end ;3.30 +int&AA&_first: ;the first. Don't have to hook stack code.;3.30 + pop ds ;3.30 +int&AA&_end: ;3.30 + ;3.30 + ENDM ;3.30 + ;3.30 + push ds ;3.30 + mov ax, 0f000h ;loook at the model byte ;3.30 + mov ds, ax ;3.30 + cmp ds:byte ptr [0fffeh], 0f9h ;convertible?(P12) ;3.30 + pop ds ;3.30 + jne Skip_EnableNMIS ;3.30 + ;3.30 + MOV AL,27H ; ENABLE P12 NMIS ;3.30 + OUT 72H,AL ;3.30 + ;3.30 +Skip_EnableNMIS: ;3.30 + STI ;3.30 + MOV AX,code ;3.30 + MOV DS,AX ;3.30 + ASSUME DS:CODE ;3.30 + ;3.30 +; MOV SI,OFFSET STKMSG1 ;3.30 +; CALL WRMSG ;3.30 + ;3.30 + mov [INT19SEM],1 ; INDICATE THAT INT 19 ;3.30 + ; INITIALIZATION IS COMPLETE ;3.30 + ;3.30 + POP BP ; RESTORE ALL ;3.30 + POP SI ;3.30 + POP DI ;3.30 + POP DX ;3.30 + POP CX ;3.30 + POP BX ;3.30 + ;3.30 + POP ES ;3.30 + POP DS ;3.30 + assume ds:sysinitseg ;3.30 + POP AX ;3.30 + RET ;3.30 +STACKINIT ENDP ;3.30 +; ;3.30 + ;3.30 +NEW_INIT_LOOP PROC NEAR ;3.30 +;INPUT: SI=OFSET INTO VECTOR TABLE OF THE PARTICULAR INT VECTOR BEING ADJUSTED ;3.30 +; BX=ds:OFFSET OF OLDxx, WHERE WILL BE SAVED THE POINTER TO ORIGINAL OWNER;3.30 +; DX=ds:OFFSET OF INTxx, THE NEW INTERRUPT HANDLER ;3.30 +; di=offset value of Int19OLD&AA variable in BIOS. ;3.30 +; es=ZERO, SEGID OF VECTOR TABLE ;3.30 +; ds=Relocated Stack code segment ;3.30 + ;3.30 + MOV AX,es:[SI+0] ;REMEMBER OFFSET IN VECTOR ;3.30 + MOV WORD PTR ds:[BX],AX ; TO ORIGINAL OWNER in DS ;3.30 + MOV AX,es:[SI+2] ;REMEMBER SEGID IN VECTOR ;3.30 + MOV WORD PTR ds:[BX]+2,AX ; TO ORIGINAL OWNER in DS ;3.30 + push ds ;3.30 + mov ax, code ;3.30 + mov ds, ax ;Set Int19OLDxx value in BIOS for ;3.30 + mov ax,es:[si+0] ;Int 19 handler ;3.30 + mov word ptr ds:[di],ax ;3.30 + mov ax,es:[si+2] ;3.30 + mov word ptr ds:[di]+2,ax ;3.30 + pop ds ;3.30 + ;3.30 + MOV WORD PTR es:[SI+0],DX ;SET VECTOR TO POINT TO NEW INT HANDLER ;3.30 + MOV es:[SI+2],ds ;3.30 + RET ;3.30 +NEW_INIT_LOOP ENDP ;3.30 + ;3.30 diff --git a/SRC/BIOS/STKMES.INC b/SRC/BIOS/STKMES.INC new file mode 100644 index 0000000..79225d3 --- /dev/null +++ b/SRC/BIOS/STKMES.INC @@ -0,0 +1,6 @@ + PUBLIC FATAL_MSG ;3.30 +FATAL_MSG DB 0DH,0AH ;3.30 + DB 7,0DH,0AH ;3.30 + DB "Internal stack overflow",0DH,0AH ;3.30 + DB "System halted",0DH,0AH,"$" ;3.30 +; diff --git a/SRC/BIOS/SYSCONF.ASM b/SRC/BIOS/SYSCONF.ASM new file mode 100644 index 0000000..5f404ed --- /dev/null +++ b/SRC/BIOS/SYSCONF.ASM @@ -0,0 +1,868 @@ +TITLE BIOS SYSTEM INITIALIZATION +TRUE EQU 0FFFFh +FALSE EQU 0 + +;IBMVER EQU TRUE +;IBM EQU IBMVER +STACKSW EQU TRUE ;Include Switchable Hardware Stacks +;IBMJAPVER EQU FALSE ;If TRUE set KANJI true also +;MSVER EQU FALSE +;ALTVECT EQU FALSE ;Switch to build ALTVECT version +;KANJI EQU FALSE + +INCLUDE version.inc + + IF IBMJAPVER +NOEXEC EQU TRUE + ELSE +NOEXEC EQU FALSE + ENDIF + +DOSSIZE EQU 0A000H + +.xlist + include smdossym.inc ; Reduced version of DOSSYM.INC ;3.30 + INCLUDE devsym.inc + include ioctl.inc + include BIOSTRUC.INC ;3.30 +.list + + IF NOT IBMJAPVER + EXTRN RE_INIT:FAR + ENDIF + +SYSINITSEG SEGMENT PUBLIC 'SYSTEM_INIT' + +ASSUME CS:SYSINITSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING + + EXTRN BADOPM:BYTE,CRLFM:BYTE,BADCOM:BYTE,BADMEM:BYTE,BADBLOCK:BYTE + EXTRN BADSIZ_PRE:BYTE,BADLD_PRE:BYTE + EXTRN BADSIZ_POST:BYTE,BADLD_POST:BYTE + EXTRN BADSTACK:BYTE,BADCOUNTRYCOM:BYTE ;3.30 + EXTRN SYSSIZE:BYTE,BADCOUNTRY:BYTE,INSUFMEMORY:BYTE ;3.30 + EXTRN CONDEV:BYTE,AUXDEV:BYTE,PRNDEV:BYTE,COMMND:BYTE,CONFIG:BYTE + EXTRN Cntry_Drv:BYTE,Cntry_Root:BYTE,Cntry_Path:BYTE ;3.30 + EXTRN DeviceParameters:byte ;3.30 + EXTRN MEMORY_SIZE:word ;3.30 + EXTRN BUFFERS:word ;3.30 + EXTRN FILES:byte,NUM_CDS:byte ;3.30 + EXTRN DOSINFO:dword,ENTRY_POINT:dword ;3.30 + EXTRN FCBS:byte,KEEP:byte ;3.30 + EXTRN CONFBOT:word,ALLOCLIM:word,COMMAND_LINE:byte ;3.30 + EXTRN ZERO:byte,SEPCHR:byte ;3.30 + EXTRN COUNT:word,CHRPTR:word,CNTRYFILEHANDLE:word ;3.30 + EXTRN MEMLO:word,MEMHI:word,PRMBLK:word,LDOFF:word ;3.30 + EXTRN PACKET:byte,UNITCOUNT:byte,BREAK_ADDR:dword ;3.30 + EXTRN BPB_ADDR:dword,DRIVENUMBER:byte,SYSI_COUNTRY:dword ;3.30 + ;3.30 + EXTRN MEM_ERR:NEAR,SetDOSCountryInfo:NEAR ;3.30 + EXTRN PARAROUND:NEAR,TEMPCDS:NEAR ;3.30 + EXTRN Set_Country_Path:NEAR,Move_ASCIIZ:NEAR,DELIM:NEAR ;3.30 + EXTRN BADFIL:NEAR,ROUND:NEAR ;3.30 + + IF STACKSW +; +; Internal Stack Parameters +EntrySize equ 8 + +MinCount equ 8 +DefaultCount equ 9 +MaxCount equ 64 + +MinSize equ 32 +DefaultSize equ 128 +MaxSize equ 512 + + extrn stack_count:word ;3.30 + extrn stack_size:word ;3.30 + extrn stack_addr:dword ;3.30 + + ENDIF + + PUBLIC DOCONF ;3.30 + PUBLIC GETCHR ;3.30 + +;*************************************************************************;3.30 +;Take care of Config.sys file. ;3.30 + +DOCONF: + PUSH CS + POP DS + + ASSUME DS:SYSINITSEG + + MOV AX,(CHAR_OPER SHL 8) ;GET SWITCH CHARACTER + INT 21H + MOV [COMMAND_LINE+1],DL ; Set in default command line + + MOV DX,OFFSET CONFIG ;NOW POINTING TO FILE DESCRIPTION + MOV AX,OPEN SHL 8 ;OPEN FILE "CONFIG.SYS" + STC ;IN CASE OF INT 24 + INT 21H ;FUNCTION REQUEST + JC ENDCONF ;Wasn't there, or couldn't open ;3.30 + JMP NOPROB ;PROBLEM WITH OPEN + +ENDCONF: ;3.30 + return ;3.30 + + +BADOP: MOV DX,OFFSET BADOPM ;WANT TO PRINT COMMAND ERROR + invoke PRINT + JMP COFF + +NOPROB: ;GET FILE SIZE (NOTE < 64K!!) + MOV BX,AX + XOR CX,CX + XOR DX,DX + MOV AX,(LSEEK SHL 8) OR 2 + INT 21H + MOV [COUNT],AX + XOR DX,DX + MOV AX,LSEEK SHL 8 ;Reset pointer to beginning of file + INT 21H + MOV DX,CS + MOV AX,[COUNT] + call ParaRound + SUB DX,AX + SUB DX,11H ;ROOM FOR HEADER + MOV [CONFBOT],DX ; Config starts here + CALL TEMPCDS ; Finally get CDS to "safe" location +ASSUME DS:NOTHING,ES:NOTHING + + MOV DX,[CONFBOT] + MOV DS,DX + MOV ES,DX + XOR DX,DX + MOV CX,[COUNT] + MOV AH,READ + STC ;IN CASE OF INT 24 + INT 21H ;Function request + PUSHF +; +; Find the EOF mark in the file. If present, then trim length. +; + SaveReg + MOV AL,1Ah ; eof mark + MOV DI,DX ; point ro buffer + JCXZ PutEOL ; no chars + REPNZ SCASB ; find end + JNZ PutEOL ; none found and count exahusted +; +; We found a 1A. Back up +; + DEC DI ; backup past 1A +; +; Just for the halibut, stick in an extra EOL +; +PutEOL: + MOV AL,13 + STOSB ; CR + MOV AL,10 + STOSB ; LF + SUB DI,DX ; difference moved + MOV Count,DI ; new count +; +; Restore registers +; + RestoreReg + + PUSH CS + POP DS +ASSUME DS:SYSINITSEG + PUSH AX + MOV AH,CLOSE + INT 21H + POP AX + POPF + JC CONFERR ;IF NOT WE'VE GOT A PROBLEM + CMP CX,AX + JZ GETCOM ;COULDN'T READ THE FILE +CONFERR: + MOV DX,OFFSET CONFIG ;WANT TO PRINT CONFIG ERROR + CALL BADFIL +ENDCONV:JMP ENDCONF ;3.30 + +GETCOM: + invoke ORGANIZE ;ORGANIZE THE FILE + CALL GETCHR + +CONFLP: JC ENDCONV ;3.30 + MOV AH,AL + CALL GETCHR + JNC TryB + JMP BADOP + +COFF: PUSH CS + POP DS + invoke NEWLINE + JMP CONFLP + +;------------------------------------------------------------------------------ +; Buffer command +;------------------------------------------------------------------------------ +TryB: CMP AH,'B' ;BUFFER COMMAND? + JNZ TRYC + invoke GETNUM + JZ TryBBad ; Gotta have at least one + CMP AX,100 ; check for max number + JB SaveBuf +TryBBad:JMP BadOp +SaveBuf: + MOV [BUFFERS],AX +CoffJ1: JMP COFF + +;------------------------------------------------------------------------------ +; Break command +;------------------------------------------------------------------------------ +TryC: CMP AH,'C' + JZ GOTC + JMP TRYD +GOTC: + CMP AL,'O' ;FIRST LETTER OF "ON" or "OFF" + JNZ TryCBad + CALL GETCHR + JC TryCBad + CMP AL,'N' ;SECOND LETTER OF "ON" + JNZ TryCoff + MOV AH,SET_CTRL_C_TRAPPING ;TURN ON CONTROL-C CHECK + MOV AL,1 + MOV DL,AL + INT 21H +CoffJ2: JMP Coff +TryCOff:CMP AL,'F' + JNZ TryCBad ; Check for "OFF" + CALL GetChr + JC TryCBad + CMP AL,'F' + JZ COffJ2 +TryCBad:JMP BadOp + +;------------------------------------------------------------------------------ +; Device command +;------------------------------------------------------------------------------ +TRYD: CMP AH,'D' + JZ GOTD + JMP TRYQ +GOTD: MOV BX,CS + MOV DS,BX + + MOV WORD PTR [BPB_ADDR],SI + MOV WORD PTR [BPB_ADDR+2],ES + + CALL ROUND + XOR AX,AX + MOV WORD PTR [ENTRY_POINT],AX + MOV AX,[MEMHI] + MOV WORD PTR [ENTRY_POINT+2],AX ;SET ENTRY POINT + + IF NOT NOEXEC + MOV [LDOFF],AX ;SET LOAD OFFSET + ENDIF + + PUSH ES + POP DS +ASSUME DS:NOTHING + MOV DX,SI ;DS:DX POINTS TO FILE NAME + + IF NOEXEC + LES BX,DWORD PTR CS:[MEMLO] + CALL LDFIL ;LOAD IN THE DEVICE DRIVER + ELSE +; We are going to open the cdevice driver and size it as is done +; in LDFIL. The reason we must do this is that EXEC does NO checking +; for us. We must make sure there is room to load the device without +; trashing SYSINIT. This code is not +; perfect (for instance .EXE device drivers are possible) because +; it does its sizing based on the assumption that the file being loaded +; is a .COM file. It is close enough to correctness to be usable. + MOV ES,AX ;ES:0 is LOAD addr + MOV AX,OPEN SHL 8 ;OPEN THE FILE + STC ;IN CASE OF INT 24 + INT 21H + JC BADLDRESET + MOV BX,AX ;Handle in BX + PUSH DX ; Save pointer to name + XOR CX,CX + XOR DX,DX + MOV AX,(LSEEK SHL 8) OR 2 + STC ;IN CASE OF INT 24 + INT 21H ; Get file size in DX:AX + JNC GO_AHEAD_LOAD + MOV AH,CLOSE ; Close file + INT 21H + POP DX ; Clean stack + STC ; Close may clear carry + JMP SHORT BADLDRESET + +GO_AHEAD_LOAD: + ; Convert size in DX:AX to para in AX + ADD AX,15 ; Round up size for conversion to para + ADC DX,0 + MOV CL,4 + SHR AX,CL + MOV CL,12 + SHL DX,CL ; Low nibble of DX to high nibble + OR AX,DX ; AX is now # of para for file + + MOV CX,ES ; CX:0 is xaddr + ADD CX,AX ; New device will take up to here + JC MEM_ERRJY ; WOW!!!! + CMP CX,CS:[ALLOCLIM] + JB OKLDX +MEM_ERRJY: + JMP MEM_ERR + +OKLDX: + POP DX ; Recover name pointer + MOV AH,CLOSE ; Close file + INT 21H + MOV BX,CS + MOV ES,BX + MOV BX,OFFSET PRMBLK ;ES:BX POINTS TO PARAMETERS + MOV AL,3 + MOV AH,EXEC + STC ;IN CASE OF INT 24 + INT 21H ;LOAD IN THE DEVICE DRIVER + ENDIF + +BADLDRESET: + PUSH DS + POP ES ;ES:SI BACK TO CONFIG.SYS + PUSH CS + POP DS ;DS BACK TO SYSINIT +ASSUME DS:SYSINITSEG + JNC GOODLD +BADBRK: + cmp byte ptr es:[si], 13 ;file name is CR? ;3.30 + jne BADBRK_1 ;(entered "device=" without filename);3.30 ;3.30 + jmp BADOP ;"Unrecognized command in CONFIG.SYS";3.30 +BADBRK_1: ;3.30 + invoke BADLOAD + JMP COFF + +GOODLD: SaveReg ;INITIALIZE THE DEVICE +Restore:MOV BL,ES:[SI] ; while ((c=*p) != 0) + OR BL,BL + JZ Got + INC SI ; p++; + JMP Restore +Got: MOV BYTE PTR ES:[SI],' ' ; *p = ' '; + SaveReg + PUSH CS + POP ES + MOV BX,SDEVSTRAT + invoke CALLDEV ; CallDev (SDevStrat); + MOV BX,SDEVINT + invoke CALLDEV ; CallDev (SDevInt); + RestoreReg + MOV BYTE PTR [SI],0 ; *p = 0; + + PUSH CS + POP DS + MOV AX,WORD PTR [BREAK_ADDR+2] + CMP AX,[MEMORY_SIZE] + JB BREAKOK + POP SI + POP ES + JMP BADBRK + +BREAKOK: + LDS DX,[ENTRY_POINT] ;SET DS:DX TO HEADER + MOV SI,DX + ADD SI,SDEVATT ;DS:SI POINTS TO ATTRIBUTES + LES DI,CS:[DOSINFO] ;ES:DI POINT TO DOS INFO + MOV AX,DS:[SI] ;GET ATTRIBUTES + TEST AX,DEVTYP ;TEST IF BLOCK DEV + JZ ISBLOCK + invoke SET_BREAK ; Go ahead and alloc mem for device + jc Erase_Dev ;dev driver's Init routine failed ;3.30 + TEST AX,ISCIN ;IS IT A CONSOLE IN? + JZ TRYCLK + MOV WORD PTR ES:[DI.SYSI_CON],DX + MOV WORD PTR ES:[DI.SYSI_CON+2],DS + +TRYCLK: TEST AX,ISCLOCK ;IS IT A CLOCK DEVICE? + JZ GOLINK + MOV WORD PTR ES:[DI+SYSI_CLOCK],DX + MOV WORD PTR ES:[DI+SYSI_CLOCK+2],DS +GOLINK: JMP LINKIT + +ISBLOCK: + MOV AL,CS:[UNITCOUNT] ;IF NO UNITS FOUND, erase the device + OR AL,AL + JNZ PERDRV +ERASE_DEV: + MOV AX,-1 ; No call to SET_BREAK yet, so no alloc + JMP ENDDEV + +PERDRV: + CBW ; WARNING NO DEVICE > 127 UNITS + MOV CX,AX + MOV DH,AH + MOV DL,ES:[DI.SYSI_NUMIO] ;GET NUMBER OF DEVICES + MOV AH,DL + ADD AH,AL ; Check for too many devices + CMP AH,26 ; 'A' - 'Z' is 26 devices + JBE OK_BLOCK + PUSH CS + POP DS + MOV DX,OFFSET BADBLOCK + invoke PRINT + JMP ERASE_DEV + +OK_BLOCK: + invoke SET_BREAK ; Alloc the device + ADD ES:[DI.SYSI_NUMIO],AL ;UPDATE THE AMOUNT + ADD CS:DriveNumber,AL ; remember amount for next device + LDS BX,CS:[BPB_ADDR] ;POINT TO BPB ARRAY +PERUNIT: + LES BP,CS:[DOSINFO] + LES BP,DWORD PTR ES:[BP.SYSI_DPB] ;GET FIRST DPB + +SCANDPB:CMP WORD PTR ES:[BP.DPB_NEXT_DPB],-1 + JZ FOUNDPB + LES BP,ES:[BP.DPB_NEXT_DPB] + JMP SCANDPB +FOUNDPB: + MOV AX,CS:[MEMLO] + MOV WORD PTR ES:[BP.DPB_NEXT_DPB],AX + MOV AX,CS:[MEMHI] + MOV WORD PTR ES:[BP.DPB_NEXT_DPB+2],AX + LES BP,DWORD PTR CS:[MEMLO] + ADD WORD PTR CS:[MEMLO],DPBSIZ + CALL ROUND ;Check for alloc error + MOV WORD PTR ES:[BP.DPB_NEXT_DPB],-1 + MOV ES:[BP.DPB_FIRST_ACCESS],-1 + + MOV SI,[BX] ;DS:SI POINTS TO BPB + INC BX + INC BX ;POINT TO NEXT GUY + MOV WORD PTR ES:[BP.DPB_DRIVE],DX + MOV AH,SETDPB ;HIDDEN SYSTEM CALL + INT 21H + MOV AX,ES:[BP.DPB_SECTOR_SIZE] ;3.30 + PUSH ES ;3.30 + LES DI,CS:[DOSINFO] ;ES:DI POINT TO DOS INFO ;3.30 + CMP AX,ES:[DI.SYSI_MAXSEC] ;3.30 + POP ES ;3.30 + JBE NOTMAX ;3.30 + POP SI ;3.30 + POP ES ;3.30 + MOV DX,OFFSET BADSIZ_PRE ;3.30 + MOV BX,OFFSET BADSIZ_POST ;3.30 + invoke PRNERR ;3.30 + JMP COFF ;3.30 + +NOTMAX: PUSH DS + PUSH DX + LDS DX,CS:[ENTRY_POINT] + MOV WORD PTR ES:[BP.DPB_DRIVER_ADDR],DX + MOV WORD PTR ES:[BP.DPB_DRIVER_ADDR+2],DS + POP DX + POP DS + INC DX + INC DH + LOOP PERUNIT + PUSH CS + POP DS + CALL TEMPCDS ; Set CDS for new drives + +LINKIT: + LES DI,CS:[DOSINFO] ;ES:DI = DOS TABLE + MOV CX,WORD PTR ES:[DI.SYSI_DEV] ;DX:CX = HEAD OF LIST + MOV DX,WORD PTR ES:[DI.SYSI_DEV+2] + + LDS SI,CS:[ENTRY_POINT] ;DS:SI = DEVICE LOCATION + MOV WORD PTR ES:[DI.SYSI_DEV],SI ;SET HEAD OF LIST IN DOS + MOV WORD PTR ES:[DI.SYSI_DEV+2],DS + MOV AX,DS:[SI] ;GET POINTER TO NEXT DEVICE + MOV WORD PTR CS:[ENTRY_POINT],AX ;AND SAVE IT + + MOV WORD PTR DS:[SI],CX ;LINK IN THE DRIVER + MOV WORD PTR DS:[SI+2],DX +ENDDEV: + POP SI + POP ES + INC AX ;AX = FFFF (no more devs if YES)? + JZ COFFJ3 + JMP GOODLD ;OTHERWISE PRETEND WE LOADED IT IN +COFFJ3: JMP COFF + +;------------------------------------------------------------------------------ +; Country command +; The syntax is: ;3.30 +; COUNTRY=country id {,codepage {,path}} ;3.30 +; COUNTRY=country id {,,path} :Default CODEPAGE ID in DOS ;3.30 +;------------------------------------------------------------------------------ +TRYQ: + CMP AH,'Q' ;3.30 + JZ TRYQ_CONT ;3.30 + JMP TRYF ;3.30 +TRYQ_CONT: ;3.30 + invoke GETNUM ;3.30 + JZ TryQBad ; 0 is never a valid code, or number is;3.30 + ; bad ;3.30 + MOV BX,AX ; Country code in BX ;3.30 + ;3.30 + ; 5/26/86 ;3.30 + MOV DX,0 ; assume no code page id ;3.30 + ;3.30 + invoke skip_delim ;skip the delimeters after the first nu;3.30m + jc TryQ_Def_File ;no more characters left? then use defa;3.30ult file + cmp al, 13 ; ;3.30 + je TryQ_Def_File ;3.30 + cmp al, 10 ;3.30 + jne TRYQ_YES_EXTENDED ;3.30 + inc [COUNT] ;This is for NEWLINE routine in COFF. ;3.30 + dec [CHRPTR] ;3.30 +COFFJ41: ;3.30 + JMP TryQ_Def_File ;O.K. no code page, no path specified. ;3.30Use default path. + ;3.30 +TRYQ_YES_EXTENDED: ;3.30 + cmp al, ',' ;was the second comma? ;3.30 + jne TryQ_GETNUM ;3.30 + invoke skip_delim ;Yes, skip ',' and other possible delim;3.30 + jmp short TRYQ_PATH ;and No code page id entered. ;3.30 +TRYQ_GETNUM: ;3.30 + invoke GETNUM ;3.30 + jc TryQBadCOM ;"Country=xxx,path" will not be accepte;3.30d. +; jc TRYQ_PATH ;Codepage is not specified. No code pag;3.30e. +; ;At this point, AL already contain the ;3.30 +; ;first char of the PATH. ;3.30 + jz TryQBad ;codepage=0 entered. Error ;3.30 + mov DX, AX ;save code page in DX ;3.30 + invoke skip_delim ;move CHRPTR to the path string ;3.30 + jc TryQ_Def_File ;no more char? then use default filenam;3.30e + cmp al, 13 ;3.30 + je TryQ_Def_File ;3.30 + cmp al, 10 ;3.30 + jne TryQ_PATH ;path entered. ;3.30 + inc [COUNT] ;3.30 + dec [CHRPTR] ;3.30 +TryQ_Def_File: ;3.30 + push dx ;save code page ;3.30 + mov cs:CNTRY_DRV, 0 ;flag that the default path has been us;3.30ed!!! + mov dx, offset CNTRY_ROOT ;the default path ;3.30 + jmp TRYQ_OPEN ;3.30 + ;3.30 +TryQBad: ;"Invalid country code or code page" ;3.30 + STC ;3.30 + MOV DX,OFFSET BADCOUNTRY ;3.30 + jmp TryQChkErr ;3.30 + ;3.30 +TryQBadCOM: ;Error in COUNTRY command ;3.30 + STC ;3.30 + MOV DX,OFFSET BADCOUNTRYCOM ;3.30 + jmp TryQChkErr ;3.30 + ;3.30 +TRYQ_PATH: ;DS - sysinitseg, ES - CONFBOT, ;3.30 + mov CX, [COUNT] ;AL - the first char of path ;3.30 + inc CX ;BX - country id, DX - codepage id, 0 =;3.30 No code page + mov DI, SI ;3.30 +TRYQ_PATH_LOOP: ;find the end of path to put 0 after th;3.30at. + mov AL, byte ptr ES:[DI] ;3.30 + call delim ;3.30 + jz TRYQ_PATH_END ;3.30 + cmp al, 13 ;3.30 + jz TRYQ_PATH_END ;3.30 + inc DI ;3.30 + jmp short TRYQ_PATH_LOOP ;3.30 +TryQBad_Brg:jmp short TryQBad ;3.30 +TRYQ_PATH_END: ;3.30 + mov es:byte ptr [di], 0 ;make it a ASCIIZ string. (Organize did;3.30 not handle this string) + push ds ;switch ds,es ;3.30 + push es ;3.30 + pop ds ;3.30 + pop es ;3.30 + ;3.30 + mov di, offset CNTRY_DRV ;move the user specified path to CNTRY_;3.30DRV + call Move_ASCIIZ ;3.30 + ;3.30 + push ds ;restore ds,es ;3.30 + push es ;3.30 + pop ds ;3.30 + pop es ;3.30 + ;3.30 +; call Set_Country_Path ;set CNTRY_DRV ;3.30 + ;3.30 + push dx ;save DX ;3.30 + mov dx, offset CNTRY_DRV ;Now DS:DX -> CNTRY_DRV ;3.30 +TRYQ_OPEN: ;3.30 + mov ax, 3d00h ;open a file ;3.30 + stc ;3.30 + int 21h ;3.30 + pop dx ;restore codepage id ;3.30 + jc TryQFileBad ;open failure ;3.30 + ;3.30 + mov cs:CntryFileHandle, ax ;save file handle ;3.30 + xchg ax, bx ;now, AX = country id, BX = file handle;3.30 + mov cx, cs:[MEMHI] ;3.30 + add cx, 128 ;I need 2K buffer to handle COUNTRY.SYS;3.30 + cmp cx, cs:[ALLOCLIM] ;3.30 + ja TryQMemory ;cannot allocate the buffer for country;3.30.sys + ;3.30 + mov si, offset CNTRY_DRV ;DS:SI -> CNTRY_DRV ;3.30 + cmp byte ptr [si],0 ;default path? ;3.30 + jne TRYQ_Set_for_DOS ;3.30 + inc si ;3.30 + inc si ;DS:SI -> CNTRY_ROOT ;3.30 +TRYQ_Set_for_DOS: ;3.30 + les di, cs:SYSI_Country ;ES:DI -> country info tab in DOS ;3.30 + push di ;save di ;3.30 + add di, ccPath_CountrySys ;3.30 + call MOVE_ASCIIZ ;Set the path to COUNTRY.SYS in DOS. ;3.30 + pop di ;ES:DI -> country info tab again. ;3.30 + mov cx, cs:[MEMHI] ;3.30 + mov ds, cx ;3.30 + xor si, si ;DS:SI -> 2K buffer to be used. ;3.30 + call SetDOSCountryInfo ;now do the job!!! ;3.30 + jnc TryQchkERR ;read error or could not find country,c;3.30ode page combination + cmp cx, -1 ;Could not find matching country_id,cod;3.30e page? + je TryQBad_Brg ;then "Invalid country code or code pag;3.30e" +TryQFileBad: ;3.30 + cmp cs:CNTRY_DRV,0 ;Is the default file used? ;3.30 + je TryQDefBad ;3.30 + mov si, cs:[CONFBOT] ;3.30 + mov es, si ;3.30 + mov si, cs:[CHRPTR] ;3.30 + dec si ;ES:SI -> path in CONFBOT ;3.30 + jmp short TryQBADLOAD ;3.30 +TryQDefBad: ;Default file has been used. ;3.30 + push cs ;3.30 + pop es ;3.30 + mov si, offset CNTRY_ROOT ;ES:SI -> \COUNTRY.SYS in SYSINIT_SEG ;3.30 +TryQBADLOAD: ;3.30 + call BADLOAD ;DS will be restored to SYSINIT_SEG ;3.30 + mov cx, cs:[CONFBOT] ;3.30 + mov es, cx ;Restore ES -> CONFBOT. ;3.30 + jmp short CoffJ4 ;3.30 +TryQMemory: ;3.30 + MOV DX,OFFSET INSUFMEMORY ;3.30 +TryQChkErr: ;3.30 + mov cx, cs:[CONFBOT] ;3.30 + mov es, cx ;restore ES -> CONFBOT seg ;3.30 + push cs ;3.30 + pop ds ;retore DS to SYSINIT_SEG ;3.30 + jnc CoffJ4 ;if no error, then exit ;3.30 + invoke PRINT ;else show error message ;3.30 +CoffJ4: ;3.30 + mov bx, CntryFileHandle ;3.30 + mov ah, 3eh ;3.30 + int 21h ;close a file. Don't care even if it fa;3.30ils. + JMP COFF ;3.30 + +;------------------------------------------------------------------------------ +; Files command +;------------------------------------------------------------------------------ +TRYF: + CMP AH,'F' + JNZ TRYL + invoke GETNUM + CMP AX,5 + JB TryFBad ; Gotta have at least 5 + CMP AX,256 + JAE TryFBad ; Has to be a byte + MOV [FILES],AL +CoffJ5: JMP COFF +TryFBad:JMP BadOp +;------------------------------------------------------------------------------ +; LastDrive command +;------------------------------------------------------------------------------ +TRYL: + CMP AH,'L' + JNZ TRYP + OR AL,020h + SUB AL,'a' + JB TryLBad + INC AL + CMP AL,26 ; a-z are allowed + JA TryLBad + MOV [NUM_CDS],AL +CoffJ6: JMP COFF +TryLBad:JMP BadOp +;------------------------------------------------------------------------------- +; Setting Drive Parameters +;------------------------------------------------------------------------------- +TRYP: + CMP AH,'P' + JNZ TRYK + invoke PARSELINE + JC TryLBad + invoke SETPARMS + INVOKE DIDDLEBACK + jc TryLBad + JMP COFF +;------------------------------------------------------------------------------- +; Setting Internal Stack Parameters +; STACK=M,N where +; M is the number of stacks (range 8 to 64, default 9) +; N is the stack size (range 32 to 512 bytes, default 128) +; 5/5/86: STACKS=0,0 implies no stack installation. ;3.30 +; Any combinations that are not within the specified limits will ;3.30 +; result in "Unrecognized command" error. ;3.30 +;------------------------------------------------------------------------------- +TRYK: + CMP AH,'K' + JNZ TRYW + + IF STACKSW ;3.30 + + MOV SepChr,',' + INVOKE GetNum ; Get number of stacks + MOV SepChr,0 + cmp ax, 0 ; 5/5/86 ;3.30 + je TRYK_0 ; Let's accept 0. ;3.30 + CMP AX, MinCount ; 8 <= Number of Stacks <= 64 + JB TryKBad + CMP AX, MaxCount + JA TryKBad +TRYK_0: ;3.30 + MOV [STACK_COUNT], AX +; +; Skip delimiters after the , +; + invoke Skip_delim ; ;3.30 + JC TryKBad + + INVOKE GetNum ; Get size of individual stack + JC TryKBad ; Number bad + + cmp ax, 0 ; 5/5/86 ;3.30 + je TRYK_SIZE0 ; 5/5/86. Accept 0 ;3.30 + + CMP AX, MinSize ; 32 <= Stack Size <= 512 + JB TryKBad + CMP AX, MaxSize + JA TryKBad +TRYK_SIZE0: ;3.30 + MOV [STACK_SIZE], AX + cmp ax,0 ;3.30 + je TRYK_BOTH0 ;3.30 +TRYK_OK: ;3.30 + mov word ptr [stack_addr], -1 ;set flag. user entered stacks= ;3.30 + JMP COFF +TRYK_BOTH0: ;3.30 + cmp [STACK_COUNT],0 ;stack_size=0. Stack_Count=0 too? ;3.30 + je TRYK_OK ;yes. accepted. ;3.30 +TryKBad: + MOV DX, OFFSET BADSTACK ; 5/26/86 "Invalid stack parameter";3.30 + invoke PRINT ;3.30 + JMP COFF ;3.30 + + ENDIF ;3.30 +;------------------------------------------------------------------------------ +; Switch command +;------------------------------------------------------------------------------ +TRYW: + CMP AH,'W' + JNZ TRYA + JMP BadOp ; no longer implemented +; MOV DL,AL +; MOV AX,(CHAR_OPER SHL 8) OR 1 ;SET SWITCH CHARACTER +; MOV [COMMAND_LINE+1],DL +; INT 21H +; JMP COFF + +;------------------------------------------------------------------------------ +; Availdev command +;------------------------------------------------------------------------------ +TRYA: + CMP AH,'A' + JNZ TRYS + JMP BadOp ; NO LONGER IMPLEMENTED +; CMP AL,'F' ;FIRST LETTER OF "FALSE" +; JNZ COFFJ7 +; MOV AX,(CHAR_OPER SHL 8) OR 3 ;TURN ON "/DEV" PREFIX +; XOR DL,DL +; INT 21H +;COFFJ7: JMP COFF + +;------------------------------------------------------------------------------ +; shell command +;------------------------------------------------------------------------------ +TRYS: + CMP AH,'S' + JNZ TRYX + MOV [COMMAND_LINE+1],0 + MOV DI,OFFSET COMMND + 1 + MOV [DI-1],AL +STORESHELL: + CALL GETCHR + OR AL,AL + JZ GETSHPARMS + CMP AL," " + JB ENDSH + MOV [DI],AL + INC DI + JMP STORESHELL + +ENDSH: + MOV BYTE PTR [DI],0 + CALL GETCHR + CMP AL,10 + JNZ CONV + CALL GETCHR +CONV: JMP CONFLP + +;------------------------------------------------------------------------------ +; FCBS Command +;------------------------------------------------------------------------------ +TRYX: + CMP AH,'X' + JNZ TRYZ + invoke GETNUM + JZ TryXBad ; gotta have at least one + CMP AX,256 + JAE TryXBad ; Can't be more than 8 bits worth + MOV [FCBS],AL +; +; Skip delimiters after the , +; + invoke Skip_delim ; ;3.30 + jc tryxbad + invoke GetNum + JC TryXBad ; Number bad (Zero is OK here) + CMP AX,256 + JAE TryXBad + CMP AL,FCBS + JA TryXBad + MOV Keep,AL + JMP COFF +TryXBad:JMP BadOp + +;------------------------------------------------------------------------------ +; Bogus command +;------------------------------------------------------------------------------ +TRYZ: + JMP BADOP + +GETSHPARMS: + MOV BYTE PTR [DI],0 + MOV DI,OFFSET COMMAND_LINE+1 +PARMLOOP: + CALL GETCHR + CMP AL," " + JB ENDSH + MOV [DI],AL + INC DI + JMP PARMLOOP + +GETCHR: + PUSH CX + MOV CX,COUNT + JCXZ NOCHAR + MOV SI,CHRPTR + MOV AL,ES:[SI] + DEC COUNT + INC CHRPTR + CLC +GET_RET: + POP CX + return +NOCHAR: STC + JMP SHORT GET_RET + + +SYSINITSEG ENDS + END + \ No newline at end of file diff --git a/SRC/BIOS/SYSCONF.OBJ b/SRC/BIOS/SYSCONF.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..9d863b1bc5712d387f6fcfd6f85fa718cba38d35 GIT binary patch literal 3281 zcmYjTdu)@}6+hRpuN^yaLP{YEZC-$Bd3fE@!6;6HAD@GZUwlq@WE);YvX%A0BLIcQuq?+Dz-kRjZtl_=s#VpPL#50P)7DU_e-@( zme0B8o_n6Zd%im=$sUTOGO-_jhRB`SmWd@}eHpFS1GY~~WO@0UN1SxG?y%K}a_Iq^ zD;STb!tq#wWUzm0MB7ZRP%sjLY$Hi<;Z%a$iuNb_^leoCf1bBkB^rw>m3SnZPG$P2 z7Bc2_O>HMMOD&a7kOy0t*np+SX4L|U>@?FCgi}{29m)nH5gj&lEx6I*ouU3{RMRsg z!yEK;pH2;74hOEa4Z&n2u2F6H{(SCR*+_0Txh*z5n7{iIUf;DVPj!em0qtx&mPBm4 zN=BF_Id3OuG?eO7f@rLl9N`pl2GQfu1UVuaSE(^FynE-4;q+i`@V?>vaBhU05!5>w zO_3*}$2M!p{zORA$)j<6NHhi$_GmbiAqPjBAx|us>5rl+DU{Q`QPa}oh(}VcH?eE?a5k6;$6^EIgtKfof~urZIt`^y2lb$iu#r|;PlV!V zVp_M-(>2w8a?I^#v@~i-^D@JEWDwp};QGbx|Jp8UgeW^F$XZn#$q(+hCp$Palp~MD z@8AREwiY8hzdcNKjJK>R8ZvWYWrYslr8&sjexT2)seM4xQ?#_wL4wHJc8u1X?KrT2 z=sBWe)P3b_N3N#oId}@o1LY<%Yi(koAhS-2Mdl(YJP(yz6br9T`d-e2+R*n9KF;RL+D2s(Lw@?_WR{-T%YXb*gr(_1!8 zwG^+u7#d^?b!NQ&c5zU-i6p;sJd^m+(U+t zqQ|h45J$*tlHw+_6@NyD6rVMhOVMJik|JP!9-P_DyW9D11lbt7rEq?u7|-8Ij4UedZeNo zU`4n&b)0Cb=IBNoZgqOwMjCvhf%*c+@NoGam1sy+r-e+f6!VNWt5T~i(xVDy^n$!& zGgDGDm>HXBu#vG@iZ1g@Qgm{UZZQXKqSHp^kQB?zC#4X^5h+%f&q{Hd@rtr>n2XNy zE)|T>cNx$71S*3#}5XKPZ5p;J2 z0sfQ?9CvY7wztjL(RY+^9V(i$Z+BLIKMmv-FOALE{U&f(v>&0-eCO42hq4+moKi&0 zc{b6Auy2%Nx!K0a+$u%;c&UzRGg@C(jaB+}Wtzlm>?^nQh@ia7H{M_8D}BX##APj9 zSTOGV6?{rg6y&klS*#u@o|(Apo9J(!xL|vG^jgbqx3_KXD*OYse5AGe3BmfOTk&W5 zAu{hL-`L*f*}MeXT>a3Ge0<~4<~iD;wESZ@#8~s4jyBKE`evdFXNzmXVc+;>I+{7# z;VVXMQl;!$r!_ivd$&8`7AQDW&Z^Wkqa7W2#%3;&qTBF;KW8&FDQb)jd^rkS3GE>fo=vk!*=s?+}9qK#gXd)VWdEgkg)}% z)@}?)5xQQg$AG?P=Qp!M!}spIj{+54h<|hNxjO>&`PBh;!841p&*FCRWnWovV6VEC z6;|b!6klbg5t?<-T>Ocq?w`RK9@W+EgI7Qh{v6>^8Z2J-O|YGOElxUms~=R)`(_-} zD%+edsyKm}Vgs%p7q?6eC;vr299Z(Sc@ zF>>43mDzm7KZ=V$`38RxWuBZ-Bw2NMoiG6{>%>ddd2l($V_?)^r`U?gk9nf%A1y3^ zsM|p~PdAAX`M63W*0rx3%+*~#5op=->78_;@zL@{)u&#wfv5TnQZyMiOVMj| zq65YXaOPUxz~FB(!&1yQd!<-lCZ%u~o6xI^HD=`NUFrH(T6WB0LOYsHs4c>T@KQ$NF<9l#sye~!Ayu`9A zQY;;+s!>vV)R;Yj%ErglovqsfHn&)_lbNw(4KP~0E90BzYyUTFl^NM zt%Vg}^NSfPt-uNvIR;Q}9!u)(fagyk1xH}QfEhP<59fRpl96w;KRg$Xp1HUlm{ES4FRZS4GH-O0kx|V{42)OMNT$`4i?f z26_4oDXDRdevice name +; + +BADSIZ_PRE DB 13,10,"Sector size too large in file $" + +; +;PRINTED when installed device cannot be found. '$' terminated. +; FORM: device name +; + +BADLD_PRE DB 13,10,"Bad or missing $" + +; +;PRINTED when command interpreter is not found. NUL terminated. +; FORM: +; + +BADCOM DB "Command Interpreter",0 + +;PRINTED when country code, code page combination was not found ;3.30 +; in country.sys file. '$' terminated. ;3.30 +; FORM: ;3.30 +BADCOUNTRY DB 13,10,"Invalid country code or code page",13,10,"$" ;3.30 + ;3.30 +;PRINTED when code page id is missing or wrong syntax. - J.K. ;3.30 +; FORM: ;3.30 +BADCOUNTRYCOM DB 13,10,"Error in COUNTRY command",13,10,"$" ;3.30 + ;3.30 +;PRINTED when the memory left is not sufficient to handle COUTRY.SYS file ;3.30 +; FORM: ;3.30 +INSUFMEMORY DB 13,10, "Insufficient memory for COUNTRY.SYS file",13,10,"$" ;3.30 + ;3.30 +; +; PRINTED when there is insufficient memory. '$' TERMINATED, note +; that this message includes crlfm! +; + +BADMEM DB 13,10,"Configuration too large for memory",13,10,"$" + +; +; PRINTED when the attempt is made to install a block device which would +; have a drive letter > 'Z' +; + +BADBLOCK DB 13,10,"Too many Block Devices",13,10,"$" + + +; PRINTED when the attempt is made to install a stack with invalid ;3.30 +; combinations of # of stacks, stack size. - J.K. 5/23/86 ;3.30 +BADSTACK DB 13,10,"Invalid STACK parameters",13,10,"$" ;3.30 + ;3.30 + \ No newline at end of file diff --git a/SRC/BIOS/SYSIMES.OBJ b/SRC/BIOS/SYSIMES.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..26195363890b4f87d65cd0589f2cd946f3d1b5e2 GIT binary patch literal 673 zcmYjNJ#W)M7=Eu+DRnVl>cVzIBoG5C5*zA}I8JLdjw_!tq(Z7J=WLyb@50%sR3=ss zgNF(+vNFPtVB!ZbA;ike!o+*$#<2MOKKFdR_i7VJ|LMDX01lh6U=k$EKitLN#1GHR z`1$=dJUAd5o8PO#jewH9mca-X<8wT z)=JSustay-xma+Dgh4u|NGL^B30csdcV!jGn(L+J_{Fq9o~H|8f>yHD7kJLOk=b*Z z7TkvUS|eslOeaY^Tlcb;fvi?}E;7MoO-o)Xw8@d~MV4zC+ftV7DVd96rPEp{`CoA( zXtkD>;6}Lk1syC@_M8s+xyX2R71uUqN#8rB%T%YO*~MJGZf*gP>x2GqFpj+AEdsQ0 z5xItl7lo$)&zd_pJ9f71B*3p`4>9*2hSW=dA02f(JUfY4(gS$X+(zmSQVkaSM*uIn zgwPMa1AOb|=p+PykIh|_?4pDPr)!_Dowo&J|31LOu6(;0fj`X+lx}(Pcobszm)0qm uu;~c1qImWRz-yiGjYFU9??3hr$a={RV_4&Da}&L`5yM17`uS!9p#BT0gtY+x literal 0 HcmV?d00001 diff --git a/SRC/BIOS/SYSINIT1.ASM b/SRC/BIOS/SYSINIT1.ASM new file mode 100644 index 0000000..669840b --- /dev/null +++ b/SRC/BIOS/SYSINIT1.ASM @@ -0,0 +1,1084 @@ +TITLE BIOS SYSTEM INITIALIZATION + +TRUE EQU 0FFFFh +FALSE EQU 0 + +;IBMVER EQU TRUE +;IBM EQU IBMVER +STACKSW EQU TRUE ;Include Switchable Hardware Stacks +;IBMJAPVER EQU FALSE ;If TRUE set KANJI true also +;MSVER EQU FALSE +;ALTVECT EQU FALSE ;Switch to build ALTVECT version +;KANJI EQU FALSE + +include version.inc + + IF IBMJAPVER +NOEXEC EQU TRUE + ELSE +NOEXEC EQU FALSE + ENDIF + +DOSSIZE EQU 0A000H + +.xlist + include smdossym.inc ; Reduced version of DOSSYM.INC ;3.30 + INCLUDE devsym.inc + include ioctl.inc + include BIOSTRUC.INC ;3.30 +.list + + IF NOT IBMJAPVER + EXTRN RE_INIT:FAR + ENDIF + +;--------------------------------------- ;3.30 +;Equates for Main stack and stack Initialization program ;3.30 + IF STACKSW ;3.30 +cr equ 0dh ;3.30 +lf equ 0ah ;3.30 + ;3.30 +EntrySize equ 8 ;3.30 + ;3.30 +MinCount equ 8 ;3.30 +DefaultCount equ 9 ;3.30 +MaxCount equ 64 ;3.30 + ;3.30 +MinSize equ 32 ;3.30 +DefaultSize equ 128 ;3.30 +MaxSize equ 512 ;3.30 + ;3.30 +AllocByte equ es:byte ptr [bp+0] ;3.30 +IntLevel equ es:byte ptr [bp+1] ;3.30 +SavedSP equ es:word ptr [bp+2] ;3.30 +SavedSS equ es:word ptr [bp+4] ;3.30 +NewSP equ es:word ptr [bp+6] ;3.30 +Free equ 0 ;3.30 +allocated equ 1 ;3.30 +overflowed equ 2 ;3.30 +clobbered equ 3 ;3.30 + ;3.30 + ;3.30 +;External variables in BIOS for INT19h handling rouitne. 10/23/86 ;3.30 + ;3.30 +CODE segment public 'code' ;3.30 + EXTRN Int19sem:byte ;3.30 + ;3.30 + IRP AA,<02,08,09,0A,0B,0C,0D,0E,70,72,73,74,76,77> ;3.30 + EXTRN Int19OLD&AA:dword ;3.30 + ENDM ;3.30 +CODE ends ;3.30 + ENDIF ;3.30 +;--------------------------------------- ;3.30 + ;3.30 + ;3.30 +SYSINITSEG SEGMENT PUBLIC 'SYSTEM_INIT' + +ASSUME CS:SYSINITSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING + + ;3.30 + EXTRN BADCOM:BYTE ;3.30 + EXTRN SYSSIZE:BYTE ;3.30 + EXTRN CONDEV:BYTE,AUXDEV:BYTE,PRNDEV:BYTE,COMMND:BYTE ;3.30 + extrn DeviceParameters:byte ;3.30 + ;3.30 + EXTRN INT24:NEAR,MEM_ERR:NEAR ;3.30 + EXTRN DOCONF:NEAR ;3.30 + + PUBLIC CURRENT_DOS_LOCATION + PUBLIC FINAL_DOS_LOCATION + PUBLIC DEVICE_LIST + PUBLIC SYSI_COUNTRY ;3.30 + PUBLIC MEMORY_SIZE + PUBLIC DEFAULT_DRIVE + PUBLIC BUFFERS + PUBLIC FILES + PUBLIC NUM_CDS ;3.30 + PUBLIC SYSINIT + PUBLIC CNTRYFILEHANDLE ;3.30 + PUBLIC COMMAND_LINE ;3.30 + + IF STACKSW +; Internal Stack Information + PUBLIC STACK_COUNT + PUBLIC STACK_SIZE + PUBLIC STACK_ADDR + ENDIF + + PUBLIC dosinfo,entry_point + PUBLIC fcbs,keep + PUBLIC confbot,alloclim + PUBLIC zero,sepchr,STALL + PUBLIC count,chrptr + PUBLIC bufptr,memlo,prmblk,memhi + PUBLIC ldoff,area,PACKET,UNITCOUNT + PUBLIC BREAK_ADDR,BPB_ADDR,drivenumber + +SYSINIT$: ;3.30 + IF STACKSW ;3.30 + include MSSTACK.INC ;Main stack program and data defin;3.30 itions + include STKMES.INC ;Fatal stack error message ;3.30 + public Endstackcode ;3.30 +Endstackcode label byte ;3.30 + ENDIF ;3.30 + +; +SYSINIT: + JMP GOINIT + +DOSINFO LABEL DWORD + DW 0000 +CURRENT_DOS_LOCATION DW 0000 + +MSDOS LABEL DWORD +ENTRY_POINT LABEL DWORD + DW 0000 +FINAL_DOS_LOCATION DW 0000 +DEVICE_LIST DD 00000000 + +SYSI_Country LABEL DWORD ; 5/29/86 Pointer to ;3.30 + DW 0000 ;country table in DOS ;3.30 + DW 0000 ;3.30 + + IF STACKSW +; +; Internal Stack Parameters + +STACK_COUNT DW DefaultCount +STACK_SIZE DW DefaultSize +STACK_ADDR DD 00000000 + ENDIF + +; various default values + +MEMORY_SIZE DW 0001 +DEFAULT_DRIVE DB 00 +BUFFERS DW -1 ; initialized during buffer allocation +;BUFFERS DW 2 ; two buffers +FILES DB 8 ; enough files for pipe +FCBS DB 4 ; performance for recycling +Keep DB 0 ; keep original set +NUM_CDS DB 5 ; 5 net drives +CONFBOT DW ? +ALLOCLIM DW ? +FOOSTRNG DB "A:\",0 +COMMAND_LINE DB 2,0,"P" ;Default Command.com Args + DB 29 DUP (0) +ZERO DB 0 +SepChr DB 0 + + ;3.30 +Sys_Model_Byte db 0FFh ;model byte used in SYSINIT ;3.30 +Sys_Scnd_Model_Byte db 0 ;secondary model byte used in SYSI;3.30 NIT + ;3.30 + IF NOT NOEXEC +COMEXE EXEC0 <0,COMMAND_LINE,DEFAULT_DRIVE,ZERO> + ENDIF + +COUNT DW 0000 +CHRPTR DW 0000 +CntryFilehandle DW 0000 ;3.30 + +BUFPTR LABEL DWORD ;LEAVE THIS STUFF IN ORDER! +MEMLO DW 0 +PRMBLK LABEL WORD +MEMHI DW 0 +LDOFF DW 0 +AREA DW 0 + +PACKET DB 22 + DB 0 + DB 0 ;INITIALIZE CODE + DW 0 + DB 8 DUP (?) +UNITCOUNT DB 0 +BREAK_ADDR DD 0 +BPB_ADDR DD 0 +DriveNumber DB 0 + +TempStack DB 80h DUP (?) + +GOINIT: +; before doing anything else, let's set the model byte ;3.30 + mov ah,0c0h ;get system configuration ;3.30* + int 15h ; * ;3.30* + jc No_ROM_Config ;3.30 + cmp ah, 0 ; double check ;3.30 + jne No_ROM_Config ;3.30 + mov al, ES:[BX.bios_SD_modelbyte] ;3.30 + mov cs:[Sys_Model_Byte], al ;3.30 + mov al, ES:[BX.bios_SD_scnd_modelbyte] ;3.30 + mov cs:[Sys_Scnd_Model_Byte], al ;3.30 + jmp short Move_Myself ;3.30 +No_ROM_Config: ; Old ROM ;3.30 + mov ax, 0f000h ;3.30 + mov ds, ax ;3.30 + mov al, byte ptr ds:[0fffeh] ;3.30 + mov cs:[Sys_Model_Byte], al ;set the model byte. ;3.30 + ;3.30 +Move_Myself: ;3.30 + CLD ; Set up move + XOR SI,SI + MOV DI,SI + + IF MSVER + MOV CX,cs:[MEMORY_SIZE] ;3.30 + CMP CX,1 ; 1 means do scan + JNZ NOSCAN + MOV CX,2048 ;START SCANNING AT 32K BOUNDARY + XOR BX,BX + +MEMSCAN:INC CX + JZ SETEND + MOV DS,CX + MOV AL,[BX] + NOT AL + MOV [BX],AL + CMP AL,[BX] + NOT AL + MOV [BX],AL + JZ MEMSCAN +SETEND: + MOV cs:[MEMORY_SIZE],CX + ENDIF + + IF IBMVER OR IBMJAPVER + MOV CX,cs:[MEMORY_SIZE] + ENDIF + +NOSCAN: ; CX is mem size in para + MOV AX,CS + MOV DS,AX +ASSUME DS:SYSINITSEG + + MOV AX,OFFSET SYSSIZE + Call ParaRound + SUB CX,AX ;Compute new sysinit location + MOV ES,CX + MOV CX,OFFSET SYSSIZE + 1 + SHR CX,1 ;Divide by 2 to get words + REP MOVSW ;RELOCATE SYSINIT + + ASSUME ES:SYSINITSEG + + PUSH ES + MOV AX,OFFSET SYSIN + PUSH AX + +AAA_DUMMY PROC FAR ;3.30 + RET +AAA_DUMMY ENDP ;3.30 +; +; MOVE THE DOS TO ITS PROPER LOCATION +; +SYSIN: + + ASSUME DS:NOTHING,ES:SYSINITSEG,SS:NOTHING + + MOV AX,[CURRENT_DOS_LOCATION] ; Where it is (set by BIOS) ;3.30 + MOV DS,AX + MOV AX,[FINAL_DOS_LOCATION] ; Where it is going (set by BI;3.30 OS) + MOV ES,AX + + ASSUME ES:NOTHING + + XOR SI,SI + MOV DI,SI + + MOV CX,DOSSIZE/2 + REP MOVSW + + LDS SI,[DEVICE_LIST] ; Set for call to DOSINIT + MOV DX,[MEMORY_SIZE] ; Set for call to DOSINIT + + CLI + MOV AX,CS + MOV SS,AX + MOV SP,OFFSET LOCSTACK ; Set stack + + ASSUME SS:SYSINITSEG + + IF NOT ALTVECT + STI ; Leave INTs disabled for ALTVECT + ENDIF +LOCSTACK LABEL BYTE + + CALL MSDOS ; Call DOSINIT + mov ax, word ptr es:[di.SYSI_InitVars] ; 5/29/86 ;3.30 + mov word ptr [dosinfo], ax ;3.30 + mov ax, word ptr es:[di.SYSI_InitVars+2] ;3.30 + mov word ptr [dosinfo+2],ax ;set the sysvar pointer ;3.30 + ;3.30 + mov ax, word ptr es:[di.SYSI_Country_Tab] ;3.30 + mov word ptr [SYSI_Country],ax ;3.30 + mov ax, word ptr es:[di.SYSI_Country_Tab+2] ;3.30 + mov word ptr [SYSI_Country+2],ax ;set the SYSI_Country poin;3.30 ter + ;3.30 + les di, dosinfo ;es:di -> dosinfo ;3.30 + + MOV AL,ES:[DI.SYSI_NUMIO] + MOV DriveNumber,AL ; Save start of installable block drvs + + MOV AX,CS + SUB AX,11H ; room for header we will copy shortly + MOV [CONFBOT],AX ; Temp "unsafe" location + + PUSH DS ; Save as input to RE_INIT + PUSH CS + POP DS +ASSUME DS:SYSINITSEG + CALL TEMPCDS ; Set up CDSs so RE_INIT and SYSINIT + ; can make DISK system calls + + POP DS ; Recover DS input to RE_INIT +ASSUME DS:NOTHING + + IF NOT IBMJAPVER + CALL RE_INIT ; Re-call the BIOS + ENDIF + + STI ; INTs OK + CLD ; MAKE SURE +; DOSINIT has set up a default "process" (PHP) at DS:0. We will move it out +; of the way by putting it just below SYSINIT at end of memory. + MOV BX,CS + SUB BX,10H + MOV ES,BX + XOR SI,SI + MOV DI,SI + MOV CX,80H + REP MOVSW + MOV WORD PTR ES:[PDB_JFN_Pointer + 2],ES ; Relocate + MOV AH,SET_CURRENT_PDB + INT 21H ; Tell DOS we moved it + PUSH DS + PUSH CS + POP DS +ASSUME DS:SYSINITSEG + MOV DX,OFFSET INT24 ;SET UP INT 24 HANDLER + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H + INT 21H + + MOV BX,0FFFFH + MOV AH,ALLOC + INT 21H ;FIRST TIME FAILS + MOV AH,ALLOC + INT 21H ;SECOND TIME GETS IT + MOV [AREA],AX + MOV [MEMHI],AX ; MEMHI:MEMLO now points to + ; start of free memory + IF ALTVECT + MOV DX,OFFSET BOOTMES + invoke PRINT ;Print message DOSINIT couldn't + ENDIF + + POP DS +ASSUME DS:NOTHING + + MOV DL,[DEFAULT_DRIVE] + OR DL,DL + JZ NODRVSET ; BIOS didn't say + DEC DL ;A = 0 + MOV AH,SET_DEFAULT_DRIVE + INT 21H ;SELECT THE DISK +NODRVSET: + + CALL DOCONF ;DO THE CONFIG STUFF + CALL ENDFILE ;Set the system according to Confi;3.30 g.sys file info. + + IF NOEXEC + MOV BP,DS ;SAVE COMMAND.COM SEGMENT + PUSH DS + POP ES + MOV BX,CS + SUB BX,10H ; Point to current PHP + MOV DS,BX + XOR SI,SI + MOV DI,SI + MOV CX,80H + REP MOVSW ; Copy it to new location for shell + MOV WORD PTR ES:[PDB_JFN_Pointer + 2],ES ; Relocate + MOV BX,ES + MOV AH,SET_CURRENT_PDB + INT 21H ; Tell DOS we moved it + MOV ES:[PDB_PARENT_PID],ES ;WE ARE THE ROOT + ENDIF + +; We must now close all handles and reopen STDIN,STDOUT,STDERR in order +; to get a possibly NEW device driver for CON. STDAUX and STDPRN must +; also be openned. + PUSH CS + POP DS +ASSUME DS:SYSINITSEG + MOV AL,[FILES] + XOR AH,AH ; DO NOT USE CBW INSTRUCTION!!!!! + ; IT DOES SIGN EXTEND. + MOV CX,AX + XOR BX,BX ;Close standard input + MOV AH,CLOSE + INT 21H + MOV BX,2 +RCCLLOOP: ;Close everybody but standard output + MOV AH,CLOSE ; Need output so we can print message + INT 21H ; in case we can't get new one open. + INC BX + LOOP RCCLLOOP + + MOV DX,OFFSET CONDEV + MOV AL,2 + MOV AH,OPEN ;OPEN CON FOR READ/WRITE + STC ; Set for possible INT 24 + INT 21H + JNC GOAUX + INVOKE BADFIL + JMP SHORT GOAUX2 + +GOAUX: PUSH AX + MOV BX,1 ;close standard output + MOV AH,CLOSE + INT 21H + POP AX + + MOV BX,AX ;New device handle + MOV AH,XDUP + INT 21H ;Dup to 1, STDOUT + MOV AH,XDUP + INT 21H ;Dup to 2, STDERR + +GOAUX2: MOV DX,OFFSET AUXDEV + MOV AL,2 ;READ/WRITE ACCESS + INVOKE OPEN_DEV + + MOV DX,OFFSET PRNDEV + MOV AL,1 ;WRITE ONLY + INVOKE OPEN_DEV + +;Global Rearm command for Shared Interrupt devices attached in the system; +;Shared interrupt attachment has some problem when it issues interrupt +;during a warm reboot. Once the interrupt is presented by the attachment, +;no further interrupts on that level will be presented until a global rearm +;is issued. BIOS will issue a global rearm after each device driver is loaded. +;To issue a global rearm: ;For PC1, XT, Palace +; OUT 02F2h, XX ; Interrupt level 2 +; OUT 02F3h, XX ; Interrupt level 3 +; OUT 02F4h, XX ; Interrupt level 4 +; OUT 02F5h, XX ; Interrupt level 5 +; OUT 02F6h, XX ; Interrupt level 6 +; OUT 02F7h, XX ; Interrupt level 7 +; +; ;For PC AT, in addition to the above commands, +; ;need to handle the secondary interrupt handler +; OUT 06F2h, XX ; Interrupt level 10 +; OUT 06F3h, XX ; Interrupt level 11 +; OUT 06F4h, XX ; Interrupt level 12 +; OUT 06F6h, XX ; Interrupt level 14 +; OUT 06F7h, XX ; Interrupt level 15 +; +; ;For All others machine +; None. +; where XX stands for any value. + + PUSH AX ;Save register + PUSH BX ;Save register + PUSH DX ;Save register + PUSH ES ;Save register + + MOV AL,0FFH ;Set up registers for global rearm + MOV DX,02F2H ; + OUT DX,AL ;OUT 02F2H,0FFH + INC DX ; + OUT DX,AL ;OUT 02F3H,0FFH + INC DX ; + OUT DX,AL ;OUT 02F4H,0FFH + INC DX ; + OUT DX,AL ;OUT 02F5H,0FFH + INC DX ; + OUT DX,AL ;OUT 02F6H,0FFH + INC DX ; + OUT DX,AL ;OUT 02F7H,0FFH + + MOV AX,0F000H ;Get machine type + MOV ES,AX ; + CMP BYTE PTR ES:[0FFFEH],0FCH ;Q: Is it an AT type machine? + JNE REARMDONE ; N: Skip next rearm + MOV AH,0C0H ;Get system configuration + INT 15H ;Q: Is it an old ROM? + JC REARMDONE ; Y: Skip next rearm + TEST ES:[BX.BIOS_SD_FEATUREBYTE1],SCNDINTCONTROLLER ; Q: Present? + JE REARMDONE ; N: Skip next rearm + + MOV AL,0FFH ;Set up registers for global rearm + MOV DX,06F2H ; + OUT DX,AL ;OUT 06F2H,0FFH + INC DX ; + OUT DX,AL ;OUT 06F3H,0FFH + INC DX ; + OUT DX,AL ;OUT 06F4H,0FFH + INC DX ; + INC DX ; + OUT DX,AL ;OUT 02F6H,0FFH + INC DX ; + OUT DX,AL ;OUT 02F7H,0FFH + +REARMDONE: + POP ES ;Restore register + POP DX ;Restore register + POP BX ;Restore register + POP AX ;Restore register + +;Global Rearm end ******************* + +; +; SET UP THE PARAMETERS FOR COMMAND +; +GOSET: + MOV SI,OFFSET COMMAND_LINE+1 + + IF NOEXEC + MOV DI,81H + ELSE + PUSH DS + POP ES + MOV DI,SI + ENDIF + + MOV CL,-1 +COMTRANLP: ;FIND LENGTH OF COMMAND LINE + INC CL + LODSB + STOSB ;COPY COMMAND LINE IN + OR AL,AL + JNZ COMTRANLP + DEC DI + MOV AL,0DH ; CR terminate + STOSB + + IF NOEXEC + MOV ES:[80H],CL ; Set up header + MOV AL,[DEFAULT_DRIVE] + MOV ES:[5CH],AL + ELSE + MOV [COMMAND_LINE],CL ;Count + ENDIF + + MOV DX,OFFSET COMMND ;NOW POINTING TO FILE DESCRIPTION + + IF NOEXEC + MOV ES,BP ;SET LOAD ADDRESS + MOV BX,100H + CALL LDFIL ;READ IN COMMAND + JC COMERR + MOV DS,BP + MOV DX,80H + MOV AH,SET_DMA ;SET DISK TRANFER ADDRESS + INT 21H + CLI + MOV SS,BP + MOV SP,DX + STI + XOR AX,AX ;PUSH A WORD OF ZEROS + PUSH AX + PUSH BP ;SET HIGH PART OF JUMP ADDRESS + MOV AX,100H + PUSH AX ;SET LOW PART OF JUMP ADDRESS +CCC PROC FAR + RET ;CRANK UP COMMAND! +CCC ENDP + + ELSE +; We are going to open the command interpreter and size it as is done in +; LDFIL. The reason we must do this is that SYSINIT is in free memory. If +; there is not enough room for the command interpreter, EXEC will probably +; overlay our stack and code so when it returns with an error SYSINIT won't be +; here to catch it. This code is not perfect (for instance .EXE command +; interpreters are possible) because it does its sizing based on the +; assumption that the file being loaded is a .COM file. It is close enough to +; correctness to be usable. + + PUSH DX ; Save pointer to name + +; First, find out where the command interpreter is going to go. + MOV BX,0FFFFH + MOV AH,ALLOC + INT 21H ;Get biggest piece + MOV AH,ALLOC + INT 21H ;SECOND TIME GETS IT + JC MEMERRJX ; Oooops + MOV ES,AX + MOV AH,DEALLOC + INT 21H ; Give it right back + MOV BP,BX +; ES:0 points to Block, and BP is the size of the block +; in para. + +; We will now adjust the size in BP DOWN by the size of SYSINIT. We +; need to do this because EXEC might get upset if some of the EXEC +; data in SYSINIT is overlayed during the EXEC. + MOV BX,[MEMORY_SIZE] + MOV AX,CS + SUB BX,AX ; BX is size of SYSINIT in Para + ADD BX,11H ; Add the SYSINIT PHP + SUB BP,BX ; BAIS down + JC MEMERRJX ; No Way. + + MOV AX,(OPEN SHL 8) ;OPEN THE FILE being EXECED + STC ;IN CASE OF INT 24 + INT 21H + JC COMERR ; Ooops + MOV BX,AX ;Handle in BX + XOR CX,CX + XOR DX,DX + MOV AX,(LSEEK SHL 8) OR 2 + STC ;IN CASE OF INT 24 + INT 21H ; Get file size in DX:AX + JC COMERR + ; Convert size in DX:AX to para in AX + ADD AX,15 ; Round up size for conversion to para + ADC DX,0 + MOV CL,4 + SHR AX,CL + MOV CL,12 + SHL DX,CL ; Low nibble of DX to high nibble + OR AX,DX ; AX is now # of para for file + ADD AX,10H ; 100H byte PHP + CMP AX,BP ; Will it fit? + JB OKLD ; Jump if yes. +MEMERRJX: + JMP MEM_ERR + +OKLD: + MOV AH,CLOSE + INT 21H ; Close file + POP DX ; Recover pointer to name + PUSH CS + POP ES + ASSUME ES:SYSINITSEG + MOV BX,OFFSET COMEXE ; Point to EXEC block + MOV WORD PTR [BX.EXEC0_COM_LINE+2],CS ; Set segments + MOV WORD PTR [BX.EXEC0_5C_FCB+2],CS + MOV WORD PTR [BX.EXEC0_6C_FCB+2],CS + XOR AX,AX ;Load and go + MOV AH,EXEC + STC ;IN CASE OF INT 24 + INT 21H ;GO START UP COMMAND + ENDIF +; NOTE FALL THROUGH IF EXEC RETURNS (an error) + +COMERR: + MOV DX,OFFSET BADCOM ;WANT TO PRINT COMMAND ERROR + INVOKE BADFIL +STALL: JMP STALL + + PUBLIC TEMPCDS ;3.30 +TEMPCDS: +ASSUME DS:SYSINITSEG + LES DI,[DOSINFO] + + MOV CL,BYTE PTR ES:[DI.SYSI_NUMIO] + XOR CH,CH + MOV ES:[DI.SYSI_NCDS],CL + MOV AL,CL + MOV AH,SIZE curdir_list + MUL AH + call ParaRound + MOV SI,[CONFBOT] + SUB SI,AX + MOV [ALLOCLIM],SI ; Can't alloc past here! + MOV WORD PTR ES:[DI.SYSI_CDS + 2],SI + MOV AX,SI + MOV WORD PTR ES:[DI.SYSI_CDS],0 + LDS SI,ES:[DI.SYSI_DPB] +ASSUME DS:NOTHING + MOV ES,AX + XOR DI,DI + +FOOSET: ; Init CDSs + MOV AX,WORD PTR [FOOSTRNG] + STOSW + MOV AX,WORD PTR [FOOSTRNG + 2] + STOSW + INC BYTE PTR [FOOSTRNG] + XOR AX,AX + PUSH CX + MOV CX,curdir_flags - 4 + REP STOSB + CMP SI,-1 + JNZ NORMCDS + XOR AX,AX + MOV CL,3 + REP STOSW + POP CX + JMP SHORT FINCDS + +NORMCDS: + POP CX + MOV AX,curdir_inuse + STOSW ; curdir_flags + MOV AX,SI + STOSW ; curdir_devptr + MOV AX,DS + STOSW + LDS SI,[SI.dpb_next_dpb] +FINCDS: + MOV AX,-1 + STOSW ; curdir_ID + STOSW ; curdir_ID + STOSW ; curdir_user_word + mov ax,2 + stosw ; curdir_end + LOOP FOOSET + MOV BYTE PTR [FOOSTRNG],"A" + return + + +;------------------------------------------------------------------------------ +; Allocate FILEs +;------------------------------------------------------------------------------ +ENDFILE: +; WE ARE NOW SETTING UP FINAL CDSs, BUFFERS, FILES, FCSs STRINGs etc. We no +; longer need the space taken by The TEMP stuff below CONFBOT, so set ALLOCLIM +; to CONFBOT. + MOV AX,[CONFBOT] + MOV [ALLOCLIM],AX + + PUSH CS + POP DS + INVOKE ROUND + MOV AL,[FILES] + SUB AL,5 + JBE DOFCBS + XOR AH,AH ; DO NOT USE CBW INSTRUCTION!!!!! + ; IT DOES SIGN EXTEND. + MOV BX,[MEMLO] + MOV DX,[MEMHI] + LDS DI,[DOSINFO] ;GET POINTER TO DOS DATA + LDS DI,[DI+SYSI_SFT] ;DS:BP POINTS TO SFT + MOV WORD PTR [DI+SFLINK],BX + MOV WORD PTR [DI+SFLINK+2],DX ;SET POINTER TO NEW SFT + PUSH CS + POP DS + LES DI,DWORD PTR [MEMLO] ;POINT TO NEW SFT + MOV WORD PTR ES:[DI+SFLINK],-1 + MOV ES:[DI+SFCOUNT],AX + MOV BL,SIZE SF_ENTRY + MUL BL ;AX = NUMBER OF BYTES TO CLEAR + MOV CX,AX + ADD [MEMLO],AX ;ALLOCATE MEMORY + MOV AX,6 + ADD [MEMLO],AX ;REMEMBER THE HEADER TOO + INVOKE ROUND ; Check for mem error before the STOSB + ADD DI,AX + XOR AX,AX + REP STOSB ;CLEAN OUT THE STUFF + +;------------------------------------------------------------------------------ +; Allocate FCBs +;------------------------------------------------------------------------------ +DOFCBS: + PUSH CS + POP DS + INVOKE ROUND + MOV AL,[FCBS] + XOR AH,AH ; DO NOT USE CBW INSTRUCTION!!!!! + ; IT DOES SIGN EXTEND. + MOV BX,[MEMLO] + MOV DX,[MEMHI] + LDS DI,[DOSINFO] ;GET POINTER TO DOS DATA + ASSUME DS:NOTHING + MOV WORD PTR [DI+SYSI_FCB],BX + MOV WORD PTR [DI+SYSI_FCB+2],DX ;SET POINTER TO NEW Table + MOV BL,CS:Keep + XOR BH,BH + MOV [DI+SYSI_keep],BX + PUSH CS + POP DS + ASSUME DS:SYSINITSEG + LES DI,DWORD PTR [MEMLO] ;POINT TO NEW Table + MOV WORD PTR ES:[DI+SFLINK],-1 + MOV ES:[DI+SFCOUNT],AX + MOV BL,SIZE SF_ENTRY + MOV CX,AX + MUL BL ;AX = NUMBER OF BYTES TO CLEAR + ADD [MEMLO],AX ;ALLOCATE MEMORY + MOV AX,size sf-2 + ADD [MEMLO],AX ;REMEMBER THE HEADER TOO + INVOKE ROUND ; Check for mem error before the STOSB + ADD DI,AX ;Skip over header + MOV AL,"A" +FillLoop: + PUSH CX ; save count + MOV CX,SIZE sf_entry ; number of bytes to fill + cld + REP STOSB ; filled + MOV WORD PTR ES:[DI-(SIZE sf_entry)+sf_ref_count],0 + MOV WORD PTR ES:[DI-(SIZE sf_entry)+sf_position],0 + MOV WORD PTR ES:[DI-(SIZE sf_entry)+sf_position+2],0 + POP CX + LOOP FillLoop + +;------------------------------------------------------------------------------ +; Allocate Buffers +;------------------------------------------------------------------------------ + +; Search through the list of media supported and allocate 3 buffers if the +; capacity of the drive is > 360KB + + CMP [BUFFERS], -1 ; Has buffers been already set? + je DoDefaultBuff ;3.30 + jmp DOBUFF ; the user entered the buf;3.30 fers=. + ;3.30 +DoDefaultBuff: ;3.30 + + MOV [BUFFERS], 2 ; Default to 2 buffers + PUSH AX + PUSH DS + LES BP,CS:[DOSINFO] ; Search through the DPB's + LES BP,DWORD PTR ES:[BP.SYSI_DPB] ; Get first DPB + +ASSUME DS:SYSINITSEG + PUSH CS + POP DS + +NEXTDPB: + ; Test if the drive supports removeable media + MOV BL, BYTE PTR ES:[BP.DPB_DRIVE] + INC BL + MOV AX, (IOCTL SHL 8) OR 8 + INT 21H + +; Ignore fixed disks + OR AX, AX ; AX is nonzero if disk is nonremoveable + JNZ NOSETBUF + +; Get parameters of drive + XOR BX, BX + MOV BL, BYTE PTR ES:[BP.DPB_DRIVE] + INC BL + MOV DX, OFFSET DeviceParameters + MOV AX, (IOCTL SHL 8) OR GENERIC_IOCTL + MOV CX, (RAWIO SHL 8) OR GET_DEVICE_PARAMETERS + INT 21H + JC NOSETBUF ; Get next DPB if driver doesn't support + ; Generic IOCTL + +; Determine capacity of drive +; Media Capacity = #Sectors * Bytes/Sector + MOV BX, WORD PTR DeviceParameters.DP_BPB.BPB_TotalSectors + +; To keep the magnitude of the media capacity within a word, +; scale the sector size +; (ie. 1 -> 512 bytes, 2 -> 1024 bytes, ...) + MOV AX, WORD PTR DeviceParameters.DP_BPB.BPB_BytesPerSector + XOR DX, DX + MOV CX, 512 + DIV CX ; Scale sector size in factor of + ; 512 bytes + + MUL BX ; AX = #sectors * size factor + OR DX, DX ; Just in case of LARGE floppies + JNZ SETBUF + CMP AX, 720 ; 720 Sectors * size factor of 1 + JBE NOSETBUF +SETBUF: + MOV [BUFFERS], 3 + jmp Chk_Memsize_for_Buffers ; Now check the memory siz;3.30 e for default buffer count +NOSETBUF: + CMP WORD PTR ES:[BP.DPB_NEXT_DPB],-1 + jz Chk_Memsize_for_Buffers ;3.30 + LES BP,ES:[BP.DPB_NEXT_DPB] + JMP NEXTDPB + +;From DOS 3.3, the default number of buffers will be changed according to ;3.30 the +;memory size too. ;3.30 +; Default buffers = 2 ;3.30 +; If diskette Media > 360 kb, then default buffers = 3 ;3.30 +; If memory size > 128 kb (2000H para), then default buffers = 5 ;3.30 +; If memory size > 256 kb (4000H para), then default buffers = 10 ;3.30 +; If memory size > 512 kb (8000H para), then default buffers = 15. ;3.30 + ;3.30 +Chk_Memsize_for_Buffers: ;3.30 + cmp [memory_size], 2000h ;3.30 + jbe BufSet ;3.30 + mov [buffers], 5 ;3.30 + cmp [memory_size], 4000h ;3.30 + jbe BufSet ;3.30 + mov [buffers], 10 ;3.30 + cmp [memory_size], 8000h ;3.30 + jbe BufSet ;3.30 + mov [buffers], 15 ;3.30 + ;3.30 +BUFSET: +ASSUME DS:NOTHING + POP DS + POP AX +DOBUFF: + + INVOKE ROUND + DEC [BUFFERS] ; FIRST DEC acounts for buffer already + ; in system. + JZ BUF1 ; All done + PUSH DS + LES DI,BUFPTR + LDS BX,DOSINFO + MOV AX,WORD PTR [BX.SYSI_BUF] ; Link in new buffer + MOV WORD PTR ES:[DI.buf_link],AX + MOV AX,WORD PTR [BX.SYSI_BUF+2] + MOV WORD PTR ES:[DI.buf_link+2],AX + MOV WORD PTR [BX.SYSI_BUF],DI + MOV WORD PTR [BX.SYSI_BUF+2],ES + MOV WORD PTR ES:[DI.buf_ID],00FFH ;NEW BUFFER FREE + MOV BX,[BX.SYSI_MAXSEC] + POP DS + ADD BX,BUFINSIZ + ADD [MEMLO],BX + JMP DOBUFF + +;------------------------------------------------------------------------------ +; Allocate CDSs +;------------------------------------------------------------------------------ +BUF1: + INVOKE ROUND + LES DI,[DOSINFO] + MOV CL,BYTE PTR ES:[DI.SYSI_NUMIO] + CMP CL,[NUM_CDS] + JAE GOTNCDS ; User setting must be at least NUMIO + MOV CL,[NUM_CDS] +GOTNCDS: + XOR CH,CH + MOV ES:[DI.SYSI_NCDS],CL + MOV AX,[MEMHI] + MOV WORD PTR ES:[DI.SYSI_CDS + 2],AX + MOV AX,[MEMLO] + MOV WORD PTR ES:[DI.SYSI_CDS],AX + MOV AL,CL + MOV AH,SIZE curdir_list + MUL AH + call ParaRound + ADD [MEMHI],AX + INVOKE ROUND ; Check for mem error before initializing + LDS SI,ES:[DI.SYSI_DPB] +ASSUME DS:NOTHING + LES DI,ES:[DI.SYSI_CDS] + CALL FOOSET + +;------------------------------------------------------------------------------ +; Allocate Space for Internal Stack +;------------------------------------------------------------------------------ + + IF STACKSW + + PUSH CS ;3.30 + POP DS ;3.30 + ASSUME DS:SYSINITSEG ;3.30 + + IF IBM + +;Don't install the system stack on the PCjr. Ignore STACKS=command too. ;3.30 + CMP [Sys_Model_Byte], 0FDh ; PCjr = 0FDh ;3.30 + JE SkipStack ;3.30 + ENDIF ;3.30 + ;3.30 +;If the use does not entered STACKS= command, as a default, do not install;3.30 +;sytem stacks for PC1, PC XT, PC Portable cases. ;3.30 +;Otherwise, install it to the user specified value or to the default ;3.30 +;value of 9, 128 for the rest of the system. ;3.30 + ;3.30 + cmp word ptr [stack_addr], -1 ;Has the user entered "sta;3.30 cks=" command? + je DoInstallStack ;Then install as specified;3.30 by the user + cmp [Sys_Scnd_Model_Byte], 0 ;PC1, XT has the secondary;3.30 model byte = 0 + jne DoInstallStack ;Other model should have d;3.30 efault stack of 9, 128 + cmp [Sys_Model_Byte], 0FFh ;PC1 ? ;3.30 + je SkipStack ;3.30 + cmp [Sys_Model_Byte], 0FEh ;PC/XT or PC Portable ? ;3.30 + je SkipStack ;3.30 + ;3.30 +DoInstallStack: ;3.30 + mov ax, [stack_count] ; Stack_count = 0? ;3.30 + cmp ax, 0 ;then, stack size must be ;3.30 0 too. + jz SkipStack ;Don't install stack. ;3.30 +; 10/21/86 Dynamic Relocation of Stack code. ;3.30 + call Round ;[memhi] = Seg. for stack ;3.30 code + ;[memlo] = 0 ;3.30 + mov ax, [memhi] ;3.30 + mov es, ax ;ES -> Seg. the stack code;3.30 is going to move. + assume es:nothing ;3.30 + push cs ;3.30 + pop ds ;3.30 + xor si,si ;!!We know that Stack code;3.30 is at the beginning of SYSINIT. + xor di,di ;3.30 + mov cx, offset Endstackcode ;3.30 + mov [memlo],cx ;3.30 + call Round ;Have enough space for rel;3.30 ocation? + rep movsb ;3.30 + ;3.30 + MOV AX, [MEMLO] ; Set address of stacks + MOV word ptr [STACK_ADDR],AX + MOV AX, [MEMHI] + MOV word ptr [STACK_ADDR+2],AX + +; Space for Internal Stack = STACK_COUNT(ENTRYSIZE + STACK_SIZE) + MOV AX, EntrySize + ADD AX, [STACK_SIZE] + MOV CX, [STACK_COUNT] + MUL CX + call ParaRound ; Convert size to pargraphs + ADD [MEMHI], AX + INVOKE ROUND ; Check for memory error before + ; continuing + CALL StackInit ; Initialize hardware stack + +SkipStack: + ENDIF + + PUSH CS + POP DS + ASSUME DS:SYSINITSEG +;------------------------------------------------------------------------------ +; Allocate rest of memory to system +;------------------------------------------------------------------------------ + INVOKE ROUND + MOV BX,[MEMHI] + MOV AX,[AREA] + MOV ES,AX ;CALC WHAT WE NEEDED + SUB BX,AX + MOV AH,SETBLOCK + INT 21H ;GIVE THE REST BACK + PUSH ES + MOV AX,ES + DEC AX + MOV ES,AX ;Point to arena + MOV ES:[arena_owner],8 ;Set impossible owner + POP ES + + IF NOEXEC + MOV BX,0FFFFH ;ALLOCATE THE REST OF MEM FOR COMMAND + MOV AH,ALLOC + INT 21H + MOV AH,ALLOC + INT 21H + MOV DS,AX + ENDIF + + return + +Public ParaRound +ParaRound: + ADD AX,15 + RCR AX,1 + SHR AX,1 + SHR AX,1 + SHR AX,1 + return + +;-------------------------------------------------------------------------;3.30 ----- +; 5/6/86. MSSTACK initialization routine. ;3.30 + IF STACKSW ;3.30 + ;3.30 +INCLUDE STKINIT.INC ;3.30 + ;3.30 + ENDIF ;3.30 +;-------------------------------------------------------------------------;3.30 ----- + +SYSINITSEG ENDS + END + \ No newline at end of file diff --git a/SRC/BIOS/SYSINIT1.OBJ b/SRC/BIOS/SYSINIT1.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..154a264ad0fd994291ca1dc1e4242b9157e1bf71 GIT binary patch literal 8616 zcmc&)eOOahnt$(2a_`|Qe25e+66x66ZMD=A4Qkbzkf106hL1t2vZA4WAh;p8Pxslj z^dYD*S(cgI>2znf-IJDfGSSwRy+-I5E*-okB(>B`~Tl}aWCHubj zs!6HK{NW!ElHYmXbKdiw_v4&<&PiGY(A$bi%Zpyj2GAFj+8y!bYs-sDiYm$-%M-9z z;aFWuWXDS)YyseT?h=&-Q+0Z7O5i?DuvS*v9aSLMtoDM^)ga)<>JmF)3Gq|xu3cL< zxym-WH|}tGT<&HN?4?*&2=PUYp2ruK7Tf3M#grGslo!U7tubX=Ot~PYY>z2BqUHR# zG36Lt`Q{k@yqK~jrkoE<9cQy^2N;SEKhWQC+W&{H+z5ux|G&rwsiR6S`LSiN5c~0=pt!#J zy~UhIPrZEt5dM$cCy?vDa`r?0X>xOQdNM<6HS z%wixL5mtblqQP8*G?4QV;z3@FkOJ~54H~pMuS$9U0b!dc{|F%wi1cmg4d zm&;YkTZe!S-inY2FOxMti?QYhWKHknTl04lT65s;)=VR7=If%dNhE6)>n1%m`U$O> zqq}QtI?0+}##rMeYvjqd=5HsoruXjFFtWy>kH+Q(SyQZ^^w^9}Xw72%U1Re+Su+@8 zO*2_@cJi&+KA|=8-L1Jw)>ImzvH6UwS!bB^*o;hQO|jvwv1uf0eivg+9a(dJ@~x?v z(3-P%x8?#_;}W8=`7K$~AWV8}&P-^{I^nLdSx?q{9%Id#?#DU)(j-}FNe^Zy~6AOOMd@ISZc~$fk|%u)5DRwdfCv7u?qmM=s=CcscOvj{i9h@YBV! zJnRjz*EpCG9u1Er#fwRFDsZ_QH#W>{_H5j=eP+`xm%F~9>93RG%b#iXxOU9kva!MA z+MEr>i6ee*94T2%(_F(MJB2Ln;oMeBfvvevGW37+)l@9uf|8GPUyLH?oo+?Ria zAdB7z!e#a_MJ0#LxU;7*bTiV=6BtB9FC{Ae{ib%zSf%<7HQvdK6gI=qK+_} zs0N~YEJD;x^A-PCuHOg{IMFfO2XrWyeWK&7qX1_<9X*Jr6DWIEdKsW&SpDp$_D7*? z^kA-Hp|c4N<2s6-{!f4#7CL!IeuL!|0tbH!^|w$Uw8%?oERLBL)E+qTXetml+h{_? zrXP__H*N;rZ40M#45+GFVf3IB5G>GJHkgCWjsf(|dT=o3%}Ato#b6G-Q6B$ImVG#u z_#uxlb`p~)2m8Z+qp2Gp@4Wwn`CRW(l;VM)VB{M1bC~a4a&0iD*^tq78st=T^)e<; zL$EUWA&q(*A&JQg1b(`gHi4-|*~atJIgnQ(RS+kaAzT&ZDuf%NT#xXzC~rqVsb+-j zacbIJ6XjNI zv5v`KAXGD%w${n4T`%xLyNKm~N>C_w(wOocf!F^j5T_o)3yX?jpgRZn@5G}w!c)rL ztJ$*d%jJ#zDqL6ifI-p5l zG;QnJtwteB#;|63;{-lSUX4LDF?kb0Hk0cGUZ3L_Z~b&%WmfJ!RFN0)t;ad9h9=sn|HPG#Z}mx_c6r#k z=IDI5IeG}=^Df3G7vLF3RhKcn6*^5y!4;=;m>K9i(P8e!2EIG~ZilhE?5H@y7ZO>&! zJOXx^8UEP|s1IiDdVp#Tpi;|rr4tpeQLVcKqLRT>O^%IV=6mw8Rqt68)a75ECix8h z<>}}~-uHZ3081f_gCUnDPqcGjCzWot(ZM z3CviCDA7HcM3-EsTGI6D6l&=oZVU60AFZHg*wv5l zY0xj2=xz-Yh8n8(W76J2PVyD<_}1&PsjCfwn7KS>e_qX>k=KhZU>&F@V z3INv^Z9O?Y^PA+XZ<77oHyZy1WJ^j`c1_!L@I2o7%=d`--X+Y1$D(3w$3DagP zg?SZ(n~Cx}DkTpgpzxOhZ=edy8AXR6fTu>FH(aaYpeqZQ<>7E!7mW1net17D%O4yA=Rk7r!w1z zP^$d{ESD!JBM8fw@+m?bQ!XM{nR-8l%rUhts7Elc-H9j_OvZ9G3zBcY6oa%6tYW)! zs0MeFSPqiA<5+MG0=6Sl6IjrKAhO^h1nlTZgj8d&0HK=gE=1woMOdC;++9K)IaPj; z*8g=Z*p6UeK_3DS!2kkwMB5Yrg8ztsx+o$Hf?Wuxs~aI6f(JDw-2x^;@O1OLls!==0cQy2e>^oT1|(*#fK=g zS$v3$o6hg~p;q&2flCOT!SVq@A+@FhIQxh{J$js*||7x;<@x^X(V`;=&^9+3QcpD6k5yl**= zB6K`LjzQ%(c$4Hymjdhff%LB5gPbOCiRxO3*OZx%6oLdo@-5zQ7sfA7B};&uH2$(tBz3!I~j~OOgKz%Xk$vjPSPJOEc=#R0Z{%8rn5I3hGHyNY7b=LVAV_?V271^-NJn&pJUNJvBnRrbj_N=?dvNFDRsEL}=Ia zymLvUbIyf7CM~eDGcUyCLu$pYpLJqaaS?erqP?WxRG`; zXzaw@C!btUQsG>ShaATWYl*$sQ9->=!HPus>JeGB#YH8KYzD7r{cmb&tgmbGWH2b} zOvGk}O-(J09z0rq(0M?Ter=z5z)?Qj(TU=UTttcujxhg_VXFAp<*&T(}%3`c_ z7F9Wt8B}+sAv*!jNJRw>)Kp&aHLhctrp-;wTN~?}E{m{TYqir7rmc;hYa+bZiQfEI{hnGTyC(#J9L^G@pFrSVL&(*VZt%z5t{pnW{kQYXOm@yz_s z1o$h>c)Tf^n}->3EJ`lu!ApTCx$r>_vp@|xHMUOY;b4@s?dKsYN)|k#gYQR4`|CQ0 zi;|8-dU*a0nLqac2U3*Gds`2>C~014fM=rQydeWzjFOfb0bEfse?+()-0d#c&UA*} zRfpWLxv9RshTRt3;o7lfYc+$~!y_YuJvSYu4yy*G^ngo@DU%+M-lmfqkfpQXB)P z=1z@QfT!UK14CWv>ZLKs#Ud?M>gbSHTs$KIexZ5%){iG}UO%eMc4E}3{W#Zh3>OA< q&BI?+lwn{@37D BPB + mov cx,size a_BPB + cld + repe movsb + pop es +ASSUME ES:NOTHING + test word ptr switches,flagseclim + jz see_heads + mov ax,word ptr slim + mov word ptr DeviceParameters.DP_BPB.BPB_SectorsPerTrack,ax +see_heads: + test word ptr switches,flagheads + jz Set_All_Done + mov ax,word ptr hlim + mov word ptr DeviceParameters.DP_BPB.BPB_Heads,ax +; +; We need to set the media byte and the total number of sectors to reflect the +; number of heads. We do this by multiplying the number of heads by the number +; of 'sectors per head'. This is not a fool-proof scheme!! +; + mov cx,ax ; cx has number of heads + dec cl ; get it 0-based + mov ax,DeviceParameters.DP_BPB.BPB_TotalSectors ; this is OK for two heads + sar ax,1 ; ax contains # of sectors/head + sal ax,cl + jc Set_All_Done ; We have too many sectors - overflow!! + mov DeviceParameters.DP_BPB.BPB_TotalSectors,ax +; Set up correct Media Descriptor Byte + cmp cl,1 + mov bl,0F0H + mov al,2 ; AL contains sectors/cluster + ja Got_Correct_Mediad + mov bl,byte ptr DeviceParameters.DP_BPB.BPB_MediaDescriptor + je Got_Correct_Mediad +; We have one head - OK for 48tpi medium + mov al,1 ; AL contains sectors/cluster + mov ch,DeviceParameters.DP_DeviceType + cmp ch,DEV_5INCH + jz Dec_Mediad + mov bl,0F0H + jmp short Got_Correct_Mediad +Dec_Mediad: + dec bl ; adjust for one head +Got_Correct_Mediad: + mov byte ptr DeviceParameters.DP_BPB.BPB_MediaDescriptor,bl + mov byte ptr DeviceParameters.DP_BPB.BPB_SectorsPerCluster,al + clc +Set_All_Done: + RET + +ASSUME DS:NOTHING, ES:NOTHING + +NOCHAR1: STC + return + +ORGANIZE: + MOV CX,[COUNT] + JCXZ NOCHAR1 + CALL MAPCASE + XOR SI,SI + MOV DI,SI + +ORG1: CALL GET ;SKIP LEADING CONTROL CHARACTERS + CMP AL,' ' + JB ORG1 + + PUSH CX + PUSH SI + PUSH DI + MOV BP,SI + DEC BP + MOV SI,OFFSET COMTAB ;Prepare to search command table + MOV CH,0 +FINDCOM: + MOV DI,BP + MOV CL,[SI] + INC SI + JCXZ NOCOM + REPE CMPSB + LAHF + ADD SI,CX ;Bump to next position without affecting flags + SAHF + LODSB ;Get indicator letter + JNZ FINDCOM + POP DI + POP SI + POP CX + JMP SHORT GOTCOM + +NOCOM: + POP DI + POP SI + POP CX + MOV AL,'Z' +GOTCOM: STOSB ;SAVE INDICATOR CHAR IN BUFFER + +ORG2: CALL GET2 ;SKIP NAME UNTIL DELIMITER + CALL DELIM ; + JNZ ORG2 + + CALL GET ;GET CHARS TO RIGHT OF EQUALS SIGN + STOSB + +ORG4: CALL GET2 + call delim ; 5/30/86. "device=filename/p..." ;3.30 + jz ORG_EXT ; 5/30/86 ;3.30 + STOSB + CMP AL,' ' + JA ORG4 + CMP AL,10 + JZ ORG1 + + MOV BYTE PTR ES:[DI-1],0 +ORG5: CALL GET2 + STOSB + CMP AL,10 + JNZ ORG5 + JMP ORG1 + +ORG_EXT: ;3.30 + mov byte ptr es:[di], 0 ;put 0 at DI to make it an ASCIIZ ;3.30 + inc DI ; ;3.30 + stosb ;and copy the delimeter char. ;3.30 + jmp short ORG5 ;and continue as usual. ;3.30 + +GET2: + JCXZ NOGET + MOV AL,ES:[SI] + INC SI + DEC CX + return + +GET: JCXZ NOGET + MOV AL,ES:[SI] + INC SI + DEC CX + CALL DELIM + JZ GET + return + + +DELIM: CMP AL,' ' + retz + CMP AL,9 + retz + CMP AL,'=' + retz + CMP AL,',' + retz + CMP AL,';' + retz ; 5/23/86 ;3.30 + CMP AL,'/' ; 5/30/86. IBM will assume "/" delim ;3.30 + retz ;3.30 + cmp al, 0 ; 5/23/86 Special case for sysinit!!! ;3.30 + return + + +NOGET: POP CX + MOV COUNT,DI + XOR SI,SI + MOV CHRPTR,SI + return +; +; NEWLINE RETURNS WITH FIRST CHARACTER OF NEXT LINE +; +NEWLINE:invoke GETCHR ;SKIP NON-CONTROL CHARACTERS + retc + CMP AL,10 ;LOOK FOR LINE FEED + JNZ NEWLINE + invoke GETCHR + return + +MAPCASE: + PUSH CX + PUSH SI + PUSH DS + PUSH ES + POP DS + XOR SI,SI +CONVLOOP: + LODSB + + IF KANJI + CALL TESTKANJ + JZ NORMCONV + INC SI ;Skip next char + DEC CX + JCXZ CONVDONE ;Just ignore 1/2 kanji error +;Fall through, know AL is not in 'a'-'z' range +NORMCONV: + ENDIF + + CMP AL,'a' + JB NOCONV + CMP AL,'z' + JA NOCONV + SUB AL,20H + MOV [SI-1],AL +NOCONV: + LOOP CONVLOOP +CONVDONE: + POP DS + POP SI + POP CX + return + + IF KANJI +TESTKANJ: + CMP AL,81H + JB NOTLEAD + CMP AL,9FH + JBE ISLEAD + CMP AL,0E0H + JB NOTLEAD + CMP AL,0FCH + JBE ISLEAD +NOTLEAD: + PUSH AX + XOR AX,AX ;Set zero + POP AX + return + +ISLEAD: + PUSH AX + XOR AX,AX ;Set zero + INC AX ;Reset zero + POP AX + return + ENDIF + +ASSUME DS:NOTHING + +Yes_Break_Failed: ;dev drv Init failed and aborted. ;3.30 + stc ;3.30 + pop ax ;3.30 + return ;3.30 + +SET_BREAK: +; 8/14/86 For DOS 3.3, this routine is modified to take care of the ;3.30 +;Device driver's initialization error and abort. ;3.30 +;If [break_addr+2] == [memhi] && [break_addr] = 0 then assume ;3.30 +;that the device driver's initialization has an error and wanted to ;3.30 +;abort the device driver. In this case, this routine will set carry ;3.30 +;and return to the caller. ;3.30 +; ;3.30 + PUSH AX + MOV AX,WORD PTR [BREAK_ADDR+2] ;REMOVE THE INIT CODE + cmp ax, [MEMHI] ;3.30 + jne Set_Break_Continue ;if not same, then O.K. ;3.30 + ;3.30 + cmp word ptr [BREAK_ADDR],0 ;3.30 + je Yes_Break_failed ;[Break_addr+2]=[MEMHI] & [Break_addr]=0 ;3.30 + ;3.30 +Set_Break_Continue: ;3.30 + MOV [MEMHI],AX + MOV AX,WORD PTR [BREAK_ADDR] + MOV [MEMLO],AX + POP AX ; NOTE FALL THROUGH + +; +; Round the values in MEMLO and MEMHI to paragraph boundary. +; Perform bounds check. +; +ROUND: + PUSH AX + MOV AX,[MEMLO] + + invoke ParaRound ; para round up + + ADD [MEMHI],AX + MOV [MEMLO],0 + mov ax,memhi ; ax = new memhi + CMP AX,[ALLOCLIM] ; if new memhi >= alloclim, error + JAE MEM_ERR + POP AX + clc ;clear carry ;3.30 + return + +MEM_ERR: + MOV DX,OFFSET BADMEM + PUSH CS + POP DS + CALL PRINT + JMP STALL + +CALLDEV:MOV DS,WORD PTR CS:[ENTRY_POINT+2] + ADD BX,WORD PTR CS:[ENTRY_POINT] ;Do a little relocation + MOV AX,DS:[BX] + PUSH WORD PTR CS:[ENTRY_POINT] + MOV WORD PTR CS:[ENTRY_POINT],AX + MOV BX,OFFSET PACKET + CALL [ENTRY_POINT] + POP WORD PTR CS:[ENTRY_POINT] + return + +BADNUM: + MOV sepchr,0 + XOR AX,AX ; Set Zero flag, and AX = 0 + pop bx ; ;3.30 + stc ; AND carry set + return + +ToDigit: + SUB AL,'0' + JB NotDig + CMP AL,9 + JA NotDig + CLC + return +NotDig: STC + return + +; GetNum parses a decimal number. +; Returns it in AX, sets zero flag if AX = 0 (MAY BE considered an +; error), if number is BAD carry is set, zero is set, AX=0. +GETNUM: push bx ; ;3.30 + XOR BX,BX ; running count is zero +B2: CALL ToDigit ; do we have a digit + JC BadNum ; no, bomb + XCHG AX,BX ; put total in AX + PUSH BX ; save digit + MOV BX,10 ; base of arithmetic + MUL BX ; shift by one decimal di... + POP BX ; get back digit + ADD AL,BL ; get total + ADC AH,0 ; make that 16 bits + JC BADNUM ; too big a number + XCHG AX,BX ; stash total + + invoke GETCHR ;GET NEXT DIGIT + JC B1 ; no more characters + cmp al, ' ' ; 5/23/86 space? ;3.30 + jz B15 ; 5/23/86 then end of digits ;3.30 + cmp al, ',' ; 5/23/86 ',' is a seperator! ;3.30 + jz B15 ; 5/23/86 then end of digits. ;3.30 + cmp al, 9 ; 5/23/86 TAB ;3.30 + jz B15 ; ;3.30 + CMP AL,SepChr ; allow , separators + JZ b15 + cmp al,SWTCHR ; See if another switch follows + JZ b15 + cmp al,10 ; Line-feed? + jz b15 + cmp al,13 ; Carriage return? + jz b15 + OR AL,AL ; end of line separator? + JNZ B2 ; no, try as a valid char... +b15: INC COUNT ; one more character to s... + DEC CHRPTR ; back up over separator +B1: MOV AX,BX ; get proper count + OR AX,AX ; Clears carry, sets Zero accordingly + pop bx ;3.30 + return + +SKIP_DELIM proc near ; ;3.30 +;Skip the delimeters pointed by CHRPTR. AL will contain the first non delimete;3.30r +;character encountered and CHRPTR will point to the next character. ;3.30 +;This rouitne will assume the second "," found as a non delimiter character. So;3.30 +;in case if the string is " , , ", this routine will stop at the second ",". At;3.30 +;this time, Zero flag is set. ;3.30 +;If COUNT is exhausted, then carry will be set. ;3.30 +Skip_delim_char: ;3.30 + call getchr ;3.30 + jc Skip_delim_exit ;3.30 + cmp al, ',' ;the first comma? ;3.30 + je Skip_delim_next ;3.30 + call delim ;check the charater in AL. ;3.30 + jz Skip_delim_char ;3.30 + jmp short Skip_delim_exit ;found a non delim char ;3.30 +Skip_delim_next: ;3.30 + call getchr ;3.30 + jc Skip_delim_exit ;3.30 + cmp al, ',' ;the second comma? ;3.30 + je Skip_delim_exit ;done ;3.30 + call delim ;3.30 + jz Skip_delim_next ;3.30 +Skip_delim_exit: ;3.30 + return ;3.30 +SKIP_DELIM endp ;3.30 + ;3.30 +; 5/26/86 *****************************************************************;3.30 +SetDOSCountryInfo proc near ;3.30 +;Input: ES:DI -> pointer to DOS_COUNTRY_CDPG_INFO ;3.30 +; DS:0 -> buffer. ;3.30 +; SI = 0 ;3.30 +; AX = country id ;3.30 +; DX = code page id. (If 0, then use ccSysCodePage as a default.) ;3.30 +; BX = file handle ;3.30 +; This routine can handle maxium 72 COUNTRY_DATA entries. ;3.30 +;Output: DOS_country_cdpg_info set. ;3.30 +; Carry set if any file read failure or wrong information in the file. ;3.30 +; Carry set and CX = -1 if cannot find the matching COUNTRY_id, CODEPAGE;3.30 +; _id in the file. ;3.30 + ;3.30 + push di ;3.30 + push ax ;3.30 + push dx ;3.30 + ;3.30 + xor cx,cx ;3.30 + xor dx,dx ;3.30 + mov ax, 512 ;read 512 bytes ;3.30 + call ReadInControlBuffer ;Read the file header ;3.30 + jc SetDOSData_fail ;3.30 + push es ;3.30 + push si ;3.30 + push cs ;3.30 + pop es ;3.30 + mov di, offset COUNTRY_FILE_SIGNATURE ;3.30 + mov cx, 8 ;length of the signature ;3.30 + repz cmpsb ;3.30 + pop si ;3.30 + pop es ;3.30 + jnz SetDOSData_fail ;signature mismatch ;3.30 + ;3.30 + add si, 18 ;SI -> county info type ;3.30 + cmp byte ptr ds:[si], 1 ;Only accept type 1 (Currently only 1 h;3.30eader type) + jne SetDOSData_fail ;cannot proceed. error return ;3.30 + inc si ;SI -> file offset ;3.30 + mov dx, word ptr ds:[si] ;Get the INFO file offset. ;3.30 + mov cx, word ptr ds:[si+2] ;3.30 + mov ax, 1024 ;read 1024 bytes. ;3.30 + call ReadInControlBuffer ;Read INFO ;3.30 + jc SetDOSData_fail ;3.30 + mov cx, word ptr ds:[si] ;get the # of country, codepage combina;3.30tion entries + cmp cx, 72 ;cannot handle more than 72 entries. ;3.30 + ja SetDOSData_fail ;3.30 + inc si ;3.30 + inc si ;SI -> entry information packet ;3.30 + pop dx ;restore code page id ;3.30 + pop ax ;restore country id ;3.30 + pop di ;3.30 + ;3.30 +SetDOSCntry_find: ;Search for desired country_id,codepage;3.30_id. + cmp ax, word ptr ds:[si+2] ;compare country_id ;3.30 + jne SetDOSCntry_next ;3.30 + cmp dx, 0 ;No user specified code page ? ;3.30 + je SetDOSCntry_any_codepage;then no need to match code page id. ;3.30 + cmp dx, word ptr ds:[si+4] ;compare code page id ;3.30 + je SetDOSCntry_got_it ;3.30 +SetDOSCntry_next: ;3.30 + add si, word ptr ds:[si] ;next entry ;3.30 + inc si ;3.30 + inc si ;take a word for size of entry itself ;3.30 + loop SetDOSCntry_find ;3.30 + mov cx, -1 ;signals that bad country id entered. ;3.30 +SetDOSCntry_fail: ;3.30 + stc ;3.30 + ret ;3.30 + ;3.30 +SetDOSData_fail: ;3.30 + pop si ;3.30 + pop cx ;3.30 + pop di ;3.30 + jmp short SetDOSCntry_fail ;3.30 + ;3.30 +SetDOSCntry_any_CodePage: ;use the code_page_id of the country_id;3.30 found. + mov dx, word ptr ds:[si+4] ;3.30 +SetDOSCntry_got_it: ;found the matching entry ;3.30 + mov cs:CntryCodePage_Id, dx ;save code page ID for this country. ;3.30 + mov dx, word ptr ds:[si+10] ;get the file offset of country data ;3.30 + mov cx, word ptr ds:[si+12] ;3.30 + mov ax, 512 ;read 512 bytes ;3.30 + call ReadInControlBuffer ;3.30 + jc SetDOSCntry_fail ;3.30 + mov cx, word ptr ds:[si] ;get the number of entries to handle. ;3.30 + inc si ;3.30 + inc si ;SI -> first entry ;3.30 + ;3.30 +SetDOSCntry_data: ;3.30 + push di ;ES:DI -> DOS_COUNTRY_CDPG_INFO ;3.30 + push cx ;save # of entry left ;3.30 + push si ;si -> current entry in Control buffer ;3.30 + ;3.30 + mov al, byte ptr ds:[si+2] ;get data entry id ;3.30 + call GetCountryDestination ;get the address of destination in ES:D;3.30I + jc SetDOSCntry_data_next ;No matching data entry id in DOS ;3.30 + ;3.30 + ;3.30 + mov dx, word ptr ds:[si+4] ;get offset of data ;3.30 + mov cx, word ptr ds:[si+6] ;3.30 + mov ax, 4200h ;3.30 + stc ;3.30 + int 21h ;move pointer ;3.30 + jc SetDOSData_fail ;3.30 + mov dx, 512 ;start of data buffer ;3.30 + mov cx, word ptr es:[di] ;length of the corresponding data in DO;3.30S. + add cx, 10 ;Signature + A word for the length itse;3.30lf + mov ah, 3fh ;3.30 + stc ;3.30 + int 21h ;read the country.sys data ;3.30 + jc SetDOSData_fail ;read failure ;3.30 + cmp ax, cx ;3.30 + jne SetDOSData_fail ;3.30 + ;3.30 + mov al, byte ptr ds:[si+2] ;save Data id for future use. ;3.30 + mov si, (512+8) ;SI-> data buffer + id tag field ;3.30 + mov cx, word ptr ds:[si] ;get the length of the file ;3.30 + inc cx ;Take care of a word for lenght of tab ;3.30 + inc cx ;itself. ;3.30 + cmp cx, (2048 - 512 - 8) ;Fit into the buffer? ;3.30 + ja SetDOSData_fail ;3.30 + cmp al, SetCountryInfo ;is the data for SetCountryInfo table? ;3.30 + jne SetDOSCntry_Mov ;no, don't worry ;3.30 + push word ptr es:[di+24] ;Cannot destroy ccMono_ptr address. Sav;3.30e them. + push word ptr es:[di+26] ;3.30 + push di ;save DI ;3.30 + ;3.30 + push ax ;3.30 + mov ax,cs:CntryCodePage_Id ;Do not use the Code Page info in Count;3.30ry_Info + mov ds:[si+4], ax ;Use the saved one for this !!!! ;3.30 + pop ax ;3.30 + ;3.30 +SetDOSCntry_Mov: ;3.30 + rep movsb ;copy the table into DOS ;3.30 + cmp al, SetCountryInfo ;was the ccMono_ptr saved? ;3.30 + jne SetDOSCntry_data_next ;3.30 + pop di ;restore DI ;3.30 + pop word ptr es:[di+26] ;restore ccMono_ptr in DOS. ;3.30 + pop word ptr es:[di+24] ;3.30 + ;3.30 +SetDOSCntry_data_next: ;3.30 + pop si ;restore control buffer pointer ;3.30 + pop cx ;restore # of entries left ;3.30 + pop di ;restore pointer to DSO_COUNTRY_CDPG ;3.30 + add si, word ptr ds:[si] ;try to get the next entry ;3.30 + inc si ;3.30 + inc si ;take a word of entry length itself ;3.30 + loop SetDOSCntry_data ;3.30 + ret ;3.30 +SetDOSCountryInfo endp ;3.30 +; ;3.30 + ;3.30 +GetCountryDestination proc near ;3.30 +;Get the destination address in the DOS country info table. ;3.30 +;Input: AL - Data ID ;3.30 +; ES:DI -> DOS_COUNTRY_CDPG_INFO ;3.30 +;On return: ;3.30 +; ES:DI -> Destination address of the matching data id ;3.30 +; carry set if no matching data id found in DOS. ;3.30 + ;3.30 + push cx ;3.30 + add di, ccNumber_of_entries ;skip the reserved area, syscodepage et;3.30c. + mov cx, word ptr es:[di] ;get the number of entries ;3.30 + inc di ;3.30 + inc di ;SI -> the first start entry id ;3.30 +GetCntryDest: ;3.30 + cmp byte ptr es:[di], al ;3.30 + je GetCntryDest_OK ;3.30 + cmp byte ptr es:[di], SetCountryInfo ;was it SetCountryInfo entry? ;3.30 + je GetCntryDest_1 ;3.30 + add di, 5 ;next data id ;3.30 + jmp short GetCntryDest_loop ;3.30 +GetCntryDest_1: ;3.30 + add di, NEW_COUNTRY_SIZE + 3 ;next data id ;3.30 +GetCntryDest_loop: ;3.30 + loop GetCntryDest ;3.30 + stc ;3.30 + jmp short GetCntryDest_exit ;3.30 +GetCntryDest_OK: ;3.30 + cmp al, SetCountryInfo ;select country info? ;3.30 + jne GetCntryDest_OK1 ;3.30 + inc di ;now DI -> ccCountryInfoLen ;3.30 + jmp short GetCntryDest_exit ;3.30 +GetCntryDest_OK1: ;3.30 + les di, dword ptr es:[di+1] ;get the destination in ES:DI ;3.30 +GetCntryDest_Exit: ;3.30 + pop cx ;3.30 + ret ;3.30 +GetCountryDestination endp ;3.30 + ;3.30 +; ;3.30 +ReadInControlBuffer proc near ;3.30 +;Move file pointer to CX:DX ;3.30 +;Read AX bytes into the control buffer. (Should be less than 2 Kb) ;3.30 +;SI will be set to 0 hence DS:SI points to the control buffer. ;3.30 +;Entry: CX,DX offset from the start of the file where the read/write pointer ;3.30 +; be moved. ;3.30 +; AX - # of bytes to read ;3.30 +; BX - file handle ;3.30 +; DS - buffer seg. ;3.30 +;Return: The control data information is read into DS:0 - DS:0200. ;3.30 +; CX,DX value destroyed. ;3.30 +; Carry set if error in Reading file. ;3.30 +; ;3.30 + push ax ;# of bytes to read ;3.30 + mov ax, 4200h ;3.30 + stc ;3.30 + int 21h ;move pointer ;3.30 + pop cx ;# of bytes to read ;3.30 + jc RICB_exit ;3.30 + xor dx,dx ;ds:dx -> control buffer ;3.30 + xor si,si ;3.30 + mov ah,3fh ;read into the buffer ;3.30 + stc ;3.30 + int 21h ;should be less than 1024 bytes. ;3.30 +RICB_exit: ;3.30 + ret ;3.30 +ReadInControlBuffer endp ;3.30 + ;3.30 +; ;3.30 +SET_COUNTRY_PATH proc near ;3.30 +;In: DS - SYSINITSEG, ES - CONFBOT, SI -> start of the asciiz path string ;3.30 +; DOSINFO_EXT, CNTRY_DRV, CNTRY_ROOT, CNTRY_PATH ;3.30 +; Assumes current directory is the ROOT directory. ;3.30 +;Out: DS:DI -> full path (CNTRY_DRV). ;3.30 +; Set the CNTRY_DRV string from the COUNTRY=,,path command. ;3.30 +; DS, ES, SI value saved. ;3.30 + ;3.30 + push si ;3.30 + push ds ;switch ds, es ;3.30 + push es ;3.30 + pop ds ;3.30 + pop es ;now DS -> CONFBOT, ES -> SYSINITSEG ;3.30 + ;3.30 + call chk_drive_letter ;current DS:[SI] is a drive letter? ;3.30 + jc SCP_Default_drv ;no, use current default drive. ;3.30 + mov al, byte ptr DS:[SI] ;3.30 + inc si ;3.30 + inc si ;SI -> next char after ":" ;3.30 + jmp short SCP_SetDrv ;3.30 +SCP_Default_drv: ;3.30 + mov ah, 19h ;3.30 + int 21h ;3.30 + add al, "A" ;convert it to a character. ;3.30 +SCP_SetDrv: ;3.30 + mov cs:CNTRY_DRV, al ;set the drive letter. ;3.30 + mov di, offset CNTRY_PATH ;3.30 + mov al, byte ptr DS:[SI] ;3.30 + cmp al, "\" ;3.30 + je SCP_Root_Dir ;3.30 + cmp al, cs:SWTCHR ;let's accept "/" as an directory delim;3.30 + je SCP_Root_Dir ;3.30 + jmp short SCP_Path ;3.30 +SCP_Root_Dir: ;3.30 + dec di ;DI -> CNTRY_ROOT ;3.30 +SCP_Path: ;3.30 + call MOVE_ASCIIZ ;copy it ;3.30 + mov di, offset CNTRY_DRV ;3.30 +SCPath_Exit: ;3.30 + push ds ;switch ds, es ;3.30 + push es ;3.30 + pop ds ;3.30 + pop es ;DS, ES value restored ;3.30 + pop si ;3.30 + RET ;3.30 +SET_COUNTRY_PATH endp ;3.30 + ;3.30 +; ;3.30 +CHK_DRIVE_LETTER proc near ;3.30 +;Check if DS:[SI] is a drive letter followed by ":". ;3.30 +;Assume that every alpha charater is already converted to UPPER CASE. ;3.30 +;Carry set if not. ;3.30 +; ;3.30 + push ax ;3.30 + cmp byte ptr ds:[si], "A" ;3.30 + jb CDLetter_NO ;3.30 + cmp byte ptr ds:[si], "Z" ;3.30 + ja CDLetter_NO ;3.30 + cmp byte ptr ds:[si+1], ":" ;3.30 + jne CDLetter_NO ;3.30 + jmp short CDLetter_exit ;3.30 +CDLetter_NO: ;3.30 + stc ;3.30 +CDLetter_exit: ;3.30 + pop ax ;3.30 + ret ;3.30 +CHK_DRIVE_LETTER endp ;3.30 + ;3.30 +; ;3.30 +MOVE_ASCIIZ proc near ;3.30 +;In: DS:SI -> source ES:DI -> target ;3.30 +;Out: copy the string until 0. ;3.30 +;Assumes there exists a 0. ;3.30 +MASCIIZ_loop: ;3.30 + movsb ;3.30 + cmp byte ptr DS:[SI-1], 0 ;Was it 0? ;3.30 + jne MASCIIZ_loop ;3.30 + ret ;3.30 +MOVE_ASCIIZ endp ;3.30 + +; +; DS:DX POINTS TO STRING TO OUTPUT (ASCIZ) +; +; PRINTS +; +; +; +BADFIL: + PUSH CS + POP ES + MOV SI,DX +BADLOAD: + MOV DX,OFFSET BADLD_PRE ;WANT TO PRINT CONFIG ERROR + MOV BX,OFFSET BADLD_POST +PRNERR: + PUSH CS + POP DS + MOV AH,STD_CON_STRING_OUTPUT + INT 21H +PRN1: MOV DL,ES:[SI] + OR DL,DL + JZ PRN2 + MOV AH,STD_CON_OUTPUT + INT 21H + INC SI + JMP PRN1 +PRN2: MOV DX,BX +PRINT: MOV AH,STD_CON_STRING_OUTPUT + INT 21H + return + + + IF NOEXEC +; +; LOAD NON EXE FILE CALLED [DS:DX] AT MEMORY LOCATION ES:BX +; +LDFIL: + PUSH AX + PUSH BX + PUSH CX + PUSH DX + PUSH SI + PUSH DS + PUSH BX + XOR AX,AX ;OPEN THE FILE + MOV AH,OPEN + STC ;IN CASE OF INT 24 + INT 21H + POP DX ;Clean stack in case jump + JC LDRET + PUSH DX + MOV BX,AX ;Handle in BX + XOR CX,CX + XOR DX,DX + MOV AX,(LSEEK SHL 8) OR 2 + STC ;IN CASE OF INT 24 + INT 21H ; Get file size in DX:AX + JC LDCLSP + OR DX,DX + JNZ LDERRP ; File >64K + POP DX + PUSH DX + MOV CX,ES ; CX:DX is xaddr + ADD DX,AX ; Add file size to Xaddr + JNC DOSIZE + ADD CX,1000H ; ripple carry +DOSIZE: + mov ax,dx + call ParaRound + mov dx,ax + + ADD CX,DX + CMP CX,[ALLOCLIM] + JB OKLD + JMP MEM_ERR + +OKLD: + XOR CX,CX + XOR DX,DX + MOV AX,LSEEK SHL 8 ;Reset pointer to beginning of file + STC ;IN CASE OF INT 24 + INT 21H + JC LDCLSP + POP DX + PUSH ES ;READ THE FILE IN + POP DS ;Trans addr is DS:DX + MOV CX,0FF00H ; .COM files arn't any bigger than + ; 64k-100H + MOV AH,READ + STC ;IN CASE OF INT 24 + INT 21H + JC LDCLS + MOV SI,DX ;CHECK FOR EXE FILE + CMP WORD PTR [SI],"ZM" + CLC ; Assume OK + JNZ LDCLS ; Only know how to do .COM files + STC + JMP SHORT LDCLS + +LDERRP: + STC +LDCLSP: + POP DX ;Clean stack +LDCLS: + PUSHF + MOV AH,CLOSE ;CLOSE THE FILE + STC + INT 21H + POPF + +LDRET: POP DS + POP SI + POP DX + POP CX + POP BX + POP AX + return + ENDIF + +; +; OPEN DEVICE POINTED TO BY DX, AL HAS ACCESS CODE +; IF UNABLE TO OPEN DO A DEVICE OPEN NULL DEVICE INSTEAD +; +OPEN_DEV: + CALL OPEN_FILE + JNC OPEN_DEV3 +OPEN_DEV1: + MOV DX,OFFSET NULDEV + CALL OPEN_FILE + return + +OPEN_DEV3: + MOV BX,AX ; Handle from open to BX + XOR AX,AX ; GET DEVICE INFO + MOV AH,IOCTL + INT 21H + TEST DL,10000000B + retnz + MOV AH,CLOSE + INT 21H + JMP OPEN_DEV1 + +OPEN_FILE: + MOV AH,OPEN + STC + INT 21H + return + +INT24: ADD SP,6 ;RESTORE MACHINE STATE + POP AX + POP BX + POP CX + POP DX + POP SI + POP DI + POP BP + POP DS + POP ES + PUSH AX + MOV AH,GET_DEFAULT_DRIVE ;INITIALIZE DOS + INT 21H + POP AX + IRET ;BACK TO USER + + IF ALTVECT +BOOTMES DB 13,10,"MS-DOS version " + DB MAJOR_VERSION + "0" + DB "." + DB (MINOR_VERSION / 10) + "0" + DB (MINOR_VERSION MOD 10) + "0" + DB 13,10 + DB "Copyright 1981,82 Microsoft Corp.",13,10,"$" + ENDIF + +NULDEV DB "NUL",0 +CONDEV DB "CON",0 +AUXDEV DB "AUX",0 +PRNDEV DB "PRN",0 + +CONFIG DB "\CONFIG.SYS",0 + +CNTRY_DRV DB "A:" ;3.30 +CNTRY_ROOT DB "\" ;3.30 +CNTRY_PATH DB "COUNTRY.SYS",0 ;3.30 + DB 52 DUP (0) ;3.30 + ;3.30 +COUNTRY_FILE_SIGNATURE db 0FFh,'COUNTRY' ;3.30 + ;3.30 +CntryCodePage_Id DW ? ;3.30 + +COMMND DB "\COMMAND.COM",0 + DB 20 dup (0) ;3.30 + +COMTAB LABEL BYTE +;;;; DB 8,"AVAILDEV",'A' ; NO LONGER SUPPORTED + DB 7,"BUFFERS", 'B' + DB 5,"BREAK", 'C' + DB 6,"DEVICE", 'D' + DB 5,"FILES", 'F' + DB 4,"FCBS", 'X' + DB 9,"LASTDRIVE",'L' + DB 8,"DRIVPARM", 'P' ; RS for DOS 3.2 + IF STACKSW ;3.30 + DB 6,"STACKS", 'K' ; BAS for DOS 3.2 ;3.30 + ENDIF ;3.30 + DB 7,"COUNTRY", 'Q' + DB 5,"SHELL", 'S' +;;;; DB 8,"SWITCHAR",'W' ; NO LONGER SUPPORTED + DB 0 + +public DeviceParameters +DeviceParameters a_DeviceParameters <0,DEV_3INCH720KB,0,80> + +hlim dw 2 +slim dw 9 + +public drive +drive db ? + +public switches +Switches dw ? + +; +; The following are the recommended BPBs for the media that we know of so +; far. + +; 48 tpi diskettes + +BPB48T DW 512 + DB 2 + DW 1 + DB 2 + DW 112 + DW 2*9*40 + DB 0FDH + DW 2 + DW 9 + DW 2 + Dd 0 ;hidden sectors - sp + Dd 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved - sp + +; 96tpi diskettes + +BPB96T DW 512 + DB 1 + DW 1 + DB 2 + DW 224 + DW 2*15*80 + DB 0f9H + DW 7 + DW 15 + DW 2 + Dd 0 ;hidden sectors - sp + Dd 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved - sp + +; 3 1/2 inch diskette BPB + +BPB35 DW 512 + DB 2 + DW 1 ; Double sided with 9 sec/trk + DB 2 + DW 70h + DW 2*9*80 + DB 0f9H + DW 3 + DW 9 + DW 2 + Dd 0 ;hidden sectors - sp + Dd 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved - sp + + +BPBTable dw BPB48T ; 48tpi drives + dw BPB96T ; 96tpi drives + dw BPB35 ; 3.5" drives +; The following are not supported, so default to 3.5" media layout + dw BPB35 ; Not used - 8" drives + dw BPB35 ; Not Used - 8" drives + dw BPB35 ; Not Used - hard files + dw BPB35 ; Not Used - tape drives + dw BPB35 ; Not Used - Other + +switchlist db 7,"FHSTDCN" ; Preserve the positions of N and C. + +; The following depend on the positions of the various letters in SwitchList + +flagdrive equ 0004H +flagcyln equ 0008H +flagseclim equ 0010H +flagheads equ 0020H +flagff equ 0040H + +SWTCHR EQU "/" ; switch follows this character + +SYSINITSEG ENDS + END + \ No newline at end of file diff --git a/SRC/BIOS/SYSINIT2.OBJ b/SRC/BIOS/SYSINIT2.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..057e8c11d441a536a4a21a9df1c9b3110dd74f26 GIT binary patch literal 3549 zcmY*c3vg7`8UF9heeC9CcvQd&n>Tas+Nxtl1` zHZ=(YS=4l#+S*#1QbtF{sVJe1I)h2?P0;C3D>xlnr)o{D+MOaohh#-azjJS3EJM!s zzt4aEbIyOy_DLj^mIou{Pc0+LjxJ^L_@(yHCZ8Nbl7W{2D||S zgP{QBKou!(H0_wb!NAZ`8Y+#tJf1Kjg}tr{la@-ue570$-qGAUmkg8T%%L3H7_a&prcM`u4uA={kyQg6PnkJLiuvD~>ixeP?a!Pd+~ z20=}rX0_tKX0$;>Nfysc2&9UKG101-iEZ=b@|(JmQda@aLM2mG zTbDW)KmsQyb!8~mH=Td+xnE^{`Rt3y^U)m*X%WM*#-lLC|0JvMJgqK0>MZQNi0%KK zeabt>)JL7!$=USt_9>Cdj;7B|JM2S(uUwn98wdmSznZg9z3jBAGtMpQMdw=e3ulR% z#?krINm_&B;8vEJw(x*w?&I^e9SvHh zUJE%;5Jw5hl(abd5rfpv9Vm?<2G$z}w?6Y2H^51pUC%WRnSP@QHv@1E3jqOXzz!(n z^tBSVP+u=`1p{|5kL{4YA?pFaxU4q;aAbEuGtkAMh!4Uw?{c!+p!AU?s)-^zdtpCZ>{ms;U2zW`>{|RtN`WJwZtX~4aApu)Kl{8sma$5oGrO7g^Z_p3AjvtHw7W0!20Nxb` z`vAH8U_YRUA3R{_1`nCSCrsgClVhnD@spn-)Z{soYVZPTF?bonl#S=|c$!)%aW_w` zk+{66+ZnZqQJW=h`P4QHg@kpCqq+=UGD4^q()lcs6})KhT3sky{8sUqF=C5T{8DYc%&xkHE=R!Oy>F3Q^I^L?Ctb#5-B z?P!RmGpTC9aqvbYQ=Ogi=gvZ)poJjSebFiQEQF)GcRE>hlnjd*)1uYV$Y z^d82Kl}sc@VR_QRr*d7cA7y66-Xq9qp?xm76n{6>88_&lN2tHZ8$=!t3OU>(mC+UDoYD?{rg;l7BVwwP^`sg ziZ2;iXzY%&5-JkfhA%CRE<0T$xEyF+DA$nSyic`aOV*Lfr@0{PAY~pqv``;fd|n@V zyrpj+w>b$ty26pZeRGt|X!&yL0uBz&M!s#-db-Fyv^e{WDv$D~i+t$|sk2PRwy;}< z6;MmPS3ExIIbC$=4}HlCqgziGrT;a$1!dCub*a9op>ap_ew!R(+10;YS>q>nu##Lg z^%M$M(tTij6*nqR z9I#8=E&3XsTf!6TK}+;I*-*lUtrBO`-Hh7KhDz3K+TisiKkx|aM2|zDKhK)ii>!H_ zfNX$unj(H+lF_Wsfc^mRsGxrectIRwP2^Ew@@~M(;-J^y2CD(p!sO2l;eHPAwlK8_ z&?Zi?&KVc?uLgV~OtA(7VV%UuQ;iZQ?SBY@4dT@I0r!ggSwq<%Zaa+TloU7O&B38T zbM)-Uw+WNa&6kK+=>h>)rN_bEbC;RxDg_VlN)66Y-ytU`a`jVvebL78|C`j6-VYeuFU zzM=mf(+@*$`j3d2tpD>rFoI9jOY*gF*HHFt$7Ekt_kduF)Z&M&V#4qNz4wZGzD(F zG2x-{^wn?yEUa$hJ?l|=+C&NsFMuf96os1A-Eoor{Y_aokx+Mw^sYIXJJHe6*?L?g z-!;CoHP%xp($VXDTYOieNY4-FBChC(;Ritxk7<^GEkGLamKgh(d;hIxsytGP42 zH}*>oi5LY#!rd`H+%^+EZB8Ci@M|DXqHuWt;Yt l0C!^}BYWaq(N32M support +; Move PHYDRV to 3rd byte from end of sector +; so that it won't have to be moved again +; FORMAT and SYS count on PHYDRV being in a known location +; +; Rev. 3.3 DCLove Changed Sec 9 EOT field from 15 to 18. May 29, 1986. +; +; Rev 3.31 MarkT The COUNT value has a bogus check (JBE????) to determine +; if we've loaded in all the sectors of IO.SYS. This will +; cause too big of a load if the sectors per track is high +; enough, causing either a stack overflow or the boot code +; to be overwritten. +; +; +; The ROM in the IBM PC starts the boot process by performing a hardware +; initialization and a verification of all external devices. If all goes +; well, it will then load from the boot drive the sector from track 0, head 0, +; sector 1. This sector is placed at physical address 07C00h. The initial +; registers are set up as follows: CS=DS=ES=SS=0. IP=7C00h, SP=0400H. +; +; The code in this sector is responsible for locating the MSDOS device drivers +; (IO.SYS) and for placing the directory sector with this information at +; physical address 00500h. After loading in this sector, it reads in the +; entirety of the BIOS at BIOSEG:0 and does a long jump to that point. +; +; If no BIOS/DOS pair is found an error message is displayed and the user is +; prompted to reinsert another disk. If there is a disk error during the +; process, a message is displayed and things are halted. +; +; At the beginning of the boot sector, there is a table which describes the +; MSDOS structure of the media. This is equivalent to the BPB with some +; additional information describing the physical layout of the driver (heads, +; tracks, sectors) +; + +ORIGIN EQU 7C00H ; Origin of bootstrap LOADER +BIOSEG EQU 70H ; destingation segment of BIOS +BioOff EQU 700H ; offset of bios +cbSec EQU 512 +cbDirEnt EQU 32 +DirOff EQU 500h + +; +; Define the destination segment of the BIOS, including the initialization +; label +; +SEGBIOS SEGMENT AT BIOSEG +BIOS LABEL BYTE +SEGBIOS ENDS + +CODE SEGMENT + ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING + ORG DirOff + 1Ch +BiosFS LABEL WORD + + ORG ORIGIN + +DSKADR = 1EH*4 ;POINTER TO DRIVE PARAMETERS + +Public $START +$START: + JMP START +;---------------------------------------------------------- +; +; THE FOLLOWING DATA CONFIGURES THE BOOT PROGRAM +; FOR ANY TYPE OF DRIVE OR HARDFILE +; + DB "MSDOS" + DB "3.3" +ByteSec DW cbSec ; SIZE OF A PHYSICAL SECTOR + DB 8 ; SECTORS PER ALLOCATION UNIT +cSecRes DW 1 ; NUMBER OF RESERVED SECTORS +cFat DB 2 ; NUMBER OF FATS +DirNum DW 512 ; NUMBER OF DIREC ENTRIES + DW 4*17*305-1 ; NUMBER OF SECTORS - NUMBER OF HIDDEN SECTORS +MEDIA DB 0F8H ; MEDIA BYTE +cSecFat DW 8 ; NUMBER OF FAT SECTORS +SECLIM DW 17 ; SECTORS PER TRACK +HDLIM DW 4 ; NUMBER OF SURFACES +cSecHid DW 1 ; NUMBER OF HIDDEN SECTORS + dw 0 ; high order word of Hiden Sectors + dd 0 ; 32 bit version of NUMBER OF SECTORS + ; (when 16 bit version is zero) + db 6 dup(?) ; reserved for later expansion + + +CURHD DB ? ; Unitialized + +; this is an image of the disk parameter table. Zero entries are copied +; from the rom table at boot. +; +SEC9 DB 0 ; DISK_SPECIFY_1 + DB 0 ; DISK_SPECIFY_2 + DB 0 ; DISK_MOTOR_WAIT + DB 0 ; DISK_SECTOR_SIZ + DB 12h ; DISK_EOT + DB 0 ; DISK_RW_GAP + DB 0 ; DISK_DTL + DB 0 ; DISK_FORMT_GAP + DB 0 ; DISK_FILL + DB 1 ; DISK_HEAD_STTL + DB 0 ; DISK_MOTOR_STRT + +Public UDATA +UDATA LABEL WORD +BIOS$ EQU WORD PTR UDATA+1 +CURTRK EQU WORD PTR UDATA+3 +CURSEC EQU BYTE PTR UDATA+5 +COUNT EQU BYTE PTR UDATA+6 ; NUMBER OF BIOS SECTORS +BIOSAV EQU WORD PTR UDATA+7 +DIR$ EQU WORD PTR UDATA+9 + +START: + +; +; First thing is to reset the stack to a better and more known place. The ROM +; may change, but we'd like to get the stack in the correct place. +; + CLI ;Stop interrupts till stack ok + XOR AX,AX + MOV SS,AX ;Work in stack just below this routine + ASSUME SS:CODE + MOV SP,ORIGIN + PUSH SS + POP ES + ASSUME ES:CODE +; +; We copy the disk parameter table into a local area. We scan the table above +; for non-zero parameters. Any we see get changed to their non-zero values. +; + MOV BX,DSKADR + LDS SI,DWORD PTR SS:[BX] ; get address of disk table + PUSH DS ; save original vector for possible + PUSH SI ; restore + PUSH SS + PUSH BX + MOV DI,OFFSET Sec9 + MOV CX,11 + CLD +changeloop: + LODSB + CMP BYTE PTR ES:[DI],0 ; is the template zero? + JZ Store ; yes, store what we've got + MOV AL,ES:[DI] +Store: + STOSB + MOV AL,AH + LOOP ChangeLoop +; +; Place in new disk parameter table. +; + PUSH ES + POP DS + ASSUME DS:CODE + MOV [BX+2],AX + MOV [BX],OFFSET SEC9 +; +; We may now turn interrupts back on. Before this, there is a small window +; when a reboot command may come in when the disk parameter table is garbage +; + STI ;Interrupts OK now +; +; Reset the disk system just in case any thing funny has happened. +; + INT 13H ;Reset the system + JC RERROR +; +; The system is now prepared for us to begin reading. First, determine +; logical sector numbers of the start of the directory and the start of the +; data area. +; + MOV AL,cFat ;Determine sector dir starts on + CBW + MUL cSecFat + ADD AX,cSecHid + ADD AX,cSecRes + MOV [DIR$],AX ; AX = cFat*cSecFat + cSecRes + cSecHid + MOV [BIOS$],AX +; +; Take into account size of directory (only know number of directory entries) +; + MOV AX,cbDirEnt ; bytes per directory entry + MUL DirNum ; convert to bytes in directory + MOV BX,ByteSec ; add in sector size + ADD AX,BX + DEC AX ; decrement so that we round up + DIV BX ; convert to sector number + ADD [BIOS$],AX +; +; We load in the first directory sector and examine it to make sure the the +; BIOS and DOS are the first two directory entries. If they are not found, +; the user is prompted to insert a new disk. The directory sector is loaded +; into 00500h +; + MOV BX,DirOff ; sector to go in at 00500h + MOV AX,DIR$ ; logical sector of directory + CALL DODIV ; convert to sector, track, head + MOV AX,0201H ; disk read 1 sector + CALL DOCALL ; do the disk read + JB CKERR ; if errors try to recover +; +; Now we scan for the presence of IO.SYS and MSDOS.SYS. Check the +; first directory entry. +; + MOV DI,BX + MOV CX,11 + MOV SI,OFFSET BIO ; point to "bios com" + REPZ CMPSB ; see if the same + JNZ CKERR ; if not there advise the user +; +; Found the BIOS. Check the second directory entry. +; + LEA DI,[BX+20h] + MOV SI,OFFSET DOS ; point to "86dos com" + MOV CX,11 + REPZ CMPSB + JZ DoLoad +; +; There has been some recoverable error. Display a message and wait for a +; keystroke. +; +CKERR: MOV SI,OFFSET SYSMSG ; point to no system message +ErrOut: CALL WRITE ; and write on the screen + XOR AH,AH ; wait for response + INT 16H ; get character from keyboard + POP SI ; reset disk parameter table back to + POP DS ; rom + POP [SI] + POP [SI+2] + INT 19h ; Continue in loop till good disk + +RERROR: MOV SI,OFFSET DMSSG ; DISK ERROR MESSAGE + JMP ErrOut +; +; We now begin to load the BIOS in. Compute the number of sectors needed +; +DoLoad: + MOV AX,BiosFS ; get file size + XOR DX,DX ; presume < 64K + DIV ByteSec ; convert to sectors + INC AL ; reading in one more can't hurt + MOV COUNT,AL ; Store running count + MOV AX,BIOS$ ; get logical sector of beginning of BIOS + MOV BIOSAV,AX ; store away for real bios later + MOV BX,BioOff ; Load address from BIOSSEG +; +; Main read-in loop. +; ES:BX points to area to read. +; Count is the number of sectors remaining. +; BIOS$ is the next logical sector number to read +; +LOOPRD: + MOV AX,BIOS$ ; Starting sector + CALL DODIV +; +; CurHD is the head for this next disk request +; CurTrk is the track for this next request +; CurSec is the beginning sector number for this request +; +; Compute the number of sectors that we may be able to read in a single ROM +; request. +; + MOV AX,SECLIM + SUB AL,CURSEC + INC AX +; +; AX is the number of sectors that we may read. +; + +; +;New code for Rev 3.31 +;***************************************************************************** + + CMP COUNT,AL ;Is sectors we can read more than we need? + JAE GOT_SECTORS ;No, it is okay + MOV AL,COUNT ;Yes, only read in what is left + +GOT_SECTORS: + +;***************************************************************************** +;End of change +; + + + PUSH AX + CALL DOCALL + POP AX + JB RERROR ; If errors report and go to ROM BASIC + SUB COUNT,AL ; Are we finished? +; +;Old code replaced by Rev 3.3 +;******************************************************************** +; JBE DISKOK ; Yes -- transfer control to the DOS +;******************************************************************** +;New code for Rev 3.3 +; + + JZ DISKOK ; Yes -- transfer control to the DOS + +;******************************************************************** +;End of change +; + ADD BIOS$,AX ; increment logical sector position + MUL ByteSec ; determine next offset for read + ADD BX,AX ; (BX)=(BX)+(SI)*(Bytes per sector) + JMP LOOPRD ; Get next track +; +; IBMINIT requires the following input conditions: +; +; DL = INT 13 drive number we booted from +; CH = media byte +; BX = First data sector on disk (0-based) +; +DISKOK: + MOV CH,Media + MOV DL,PhyDrv + MOV BX,[BIOSAV] ;Get bios sector in bx + JMP FAR PTR BIOS ;CRANK UP THE DOS + +WRITE: LODSB ;GET NEXT CHARACTER + OR AL,AL ;clear the high bit + JZ ENDWR ;ERROR MESSAGE UP, JUMP TO BASIC + MOV AH,14 ;WILL WRITE CHARACTER & ATTRIBUTE + MOV BX,7 ;ATTRIBUTE + INT 10H ;PRINT THE CHARACTER + JMP WRITE +; +; convert a logical sector into Track/sector/head. AX has the logical +; sector number +; +DODIV: + XOR DX,DX + DIV SECLIM + INC DL ; sector numbers are 1-based + MOV CURSEC,DL + XOR DX,DX + DIV HDLIM + MOV CURHD,DL + MOV CURTRK,AX +ENDWR: RET +; +; Issue one read request. ES:BX have the transfer address, AL is the number +; of sectors. +; +DOCALL: MOV AH,2 + MOV DX,CURTRK + MOV CL,6 + SHL DH,CL + OR DH,CURSEC + MOV CX,DX + XCHG CH,CL + MOV DL, PHYDRV + mov dh, curhd + INT 13H + RET + + include messages.inc + +BIO DB "IO SYS" +DOS DB "MSDOS SYS" + +Free EQU (cbSec - 3) - ($-$start) +if Free LT 0 + %out FATAL PROBLEM:boot sector is too large +endif + + org origin + (cbSec - 3) + +; FORMAT and SYS count on PHYDRV being right here +PHYDRV db 0 +; Boot sector signature + db 55h,0aah + +CODE ENDS + END diff --git a/SRC/BUGFIX/BIOS/MSBIO2.ASM b/SRC/BUGFIX/BIOS/MSBIO2.ASM new file mode 100644 index 0000000..e873b4c --- /dev/null +++ b/SRC/BUGFIX/BIOS/MSBIO2.ASM @@ -0,0 +1,650 @@ + TITLE MSBIO2 - DOS 3.3 + +;------------------------------------------------------------------------------- +; : +; Microsoft Bio : +; : +; The file msbio.asm is the main file in the Mircosoft bio. This file : +; includes the other main files in the bio. Most of the routines are : +; in these include files. The main files included are: : +; : +; File Contains : +; : +; msdisk.inc Disk device driver routines : +; ms96tpi.inc Routines for 96tpi drives : +; msaux.inc Device driver for the rs-232 serial ports : +; msclock.inc Device driver for "clock$" device : +; mscon.inc Device driver for "con" : +; mslpt.inc Device driver for the printers : +; : +; Each of these files contain a header section documenting the code : +; in that file. : +; Msbio also includes several files for equ's, structure definition, : +; macro definitions, etc. These are: : +; : +; msbiomes.inc msmacro.inc devsym.inc : +; dskprm.inc error.inc : +; : +; Each of these file contains explanitory notes. : +; : +; The actual code in msbio can be broken down into several piece: : +; : +; macro definitions Several marco are defined in msbio. They : +; are a few odds and end that did not fit : +; anywhere else. : +; : +; Command Jump Table List of entry points in the device drivers. : +; See notation below for full explination. : +; : +; Interrupt and Strategy : +; Entry points Calls on the device driver first come to here. : +; There is common code with pushes registers and : +; the like before jumping to routines in the : +; driver files. The common exit points are also : +; in this file. : +; : +; Miscellaneous Code There are several routines and data structure : +; declarations. See below for details. : +; : +;------------------------------------------------------------------------------- + + + +; +; If the variable TEST is non-zero then code for debugging is included. +; The extra code will make the binary file nuch larger. +; The symbol is also defined in msequ.inc. Both must be changed to +; turn debugging on or off. +; +; The level of the debugging is controled by the variable fTestBits in +; this file. See the comment preceeding the variable for more information. +; The actual routines which print the messages are in msmacro.inc +; See the header comment in this file for more information. +; + + +; +; Revision History +; +; REV 2.1 5/1/83 ARR added timer int handler and changed order of AUX +; PRN init for HAL0 +; +; REV 2.15 7/13/83 ARR Because of IBM design issues, and that BASCOM +; is ill behaved with respect to the 1CH timer interrupt, +; the timer handler has to be backed out! The intended +; code is commented out and has an ARR 2.15 annotation. +; This means the BIOS will go back to the multiple roll +; over bug. +; +; REV 2.20 8/5/83 ARR IBM makes hardware change. Now wants to use half +; height drives for HAL0, and back fit for PC/PC XT. Problem +; with head settle time. Previous drives got by on a 0 +; settle time, 1/2 hight drives need 15 head settle when +; doing WRITEs (0 ok on READ) if the head is being stepped. +; This requires a last track value to be kept so that BIOS +; knows when head is being moved. To help out +; programs that issue INT 13H directly, the head settle will +; normally be set to 15. It will be changed to 0 on READs, +; or on WRITEs which do not require head step. +; +; REV 2.21 8/11/83 MZ IBM wants write with verify to use head settle 0. +; Use same trick as above. +; +; REV 2.25 6/20/83 mjb001 added support for 96tpi and salmon +; +; REV 2.30 6/27/83 mjb002 added real-time clock +; +; REV 2.40 7/8/83 mjb003 added volume-id checking and int 2f macro +; definitions push* and pop* +; +; REV 2.41 7/12/83 ARR more 2.X enhancements. Open/Close media change +; +; REV 2.42 11/3/83 ARR more 2.X enhancements. Disk OPEN/CLOSE, FORMAT +; code and other misc hooked out to shrink BIOS. Code for +; Disk OPEN/CLOSE, FORMAT included only with 96tpi disks. +; +; Rev 2.43 12/6/83 MZ Examine boot sectors on hard disks for 16-bit fat +; check. Examine large fat bit in BPB for walk of media for +; DOS +; +; Rev 2.44 12/9/83 ARR Change to error reporting on INT 17H +; +; Rev 2.45 12/22/83 MZ Make head settle change only when disk parm is 0. + +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +; IBM ADDRESSES FOR I/O +; +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +;Below was moved from sysinit1 +ROMSEGMENT EQU 0F000H +MODELBYTE EQU DS:BYTE PTR [0FFFEH] +MODELPCJR EQU 0FDH + + test=0 +;;Rev 3.30 modification ---------------------------- + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + INCLUDE MSEQU.INC + INCLUDE DEVSYM.INC + INCLUDE PUSHPOP.INC + INCLUDE MSMACRO.INC + + ASSUME DS:NOTHING,ES:NOTHING + + EXTRN DSK$IN:NEAR + EXTRN SETPTRSAV:NEAR + EXTRN OUTCHR:NEAR + EXTRN SETDRIVE:NEAR + EXTRN FLUSH:NEAR + EXTRN HARDERR:NEAR + EXTRN HARDERR2:NEAR + EXTRN MAPERROR:NEAR + EXTRN GETBP:NEAR + EXTRN CHECKSINGLE:NEAR + EXTRN CHECK_TIME_OF_ACCESS:NEAR + EXTRN EXIT:NEAR + EXTRN HAS1:NEAR + EXTRN HAS1_res:NEAR + EXTRN READ_SECTOR:NEAR + EXTRN INT_2F_13:FAR + + EXTRN OLD13:DWORD + +;DATA + EXTRN PTRSAV:DWORD + EXTRN START_BDS:WORD + EXTRN FDRIVE1:WORD + EXTRN FDRIVE2:WORD + EXTRN FDRIVE3:WORD + EXTRN FDRIVE4:WORD + EXTRN FLAGBITS:WORD + EXTRN TIM_DRV:BYTE + EXTRN MEDBYT:BYTE + EXTRN DRVMAX:BYTE + + PATHSTART 005,DISK + EVENB + PUBLIC ORIG19 +ORIG19 DD ? + + PUBLIC INT19SEM +INT19SEM DB 0 ; INDICATE THAT ALL INT 19 + ; INITIALIZATION IS COMPLETE + + IRP AA,<02,08,09,0A,0B,0C,0D,0E,70,72,73,74,76,77> + public Int19OLD&AA +Int19OLD&AA dd -1 ;Orignal hw int. vec for INT 19h. + ENDM + + EVENB + PUBLIC DSKDRVS +DSKDRVS DW FDRIVE1 + DW FDRIVE2 + DW FDRIVE3 + DW FDRIVE4 + PUBLIC HDSKTAB +HDSKTAB DW HDRIVE + DW DRIVEX +;* Next area is reseved for mini disk BPB pointers *** 4/7/86 +;* Don't change this pos. Should be add. from DskDrvs *** 4/7/86 +MINI_DISK_BPB_PTRS DB 40 dup (?) ;4/7/86 - mem res for Mini disk. + + EVENB + PUBLIC INT_2F_NEXT +INT_2F_NEXT DD ? + +RET_ADDR DD ? + + PATHEND 005,DISK +;;End of modification ---------------------------- + +; INT19 +; +; We "hook" the INT_REBOOT vector, because contrary to IBM documentation, +; it does NOT "bootstrap" the machine. It leaves memory almost untouched. +; Since the BIOS_INIT code assumes that certain Interrupt Vectors point to +; the ROM_BIOS we must "unhook" them before issuing the actual INT_REBOOT. +; Currently the following vectors need to be unhooked: +; 02,08,09,0A,0B,0C,0D,0E,70,72,73,74,75,76,77 +; + +Public Int19 +Int19 proc FAR + xor AX,AX ; get data segment to + mov DS,AX ; point to the vector table + assume ds:nothing + assume es:nothing + les DI,Old13 ; get ES to point to this segment + mov DS:[13h*4],DI ; restore old int13 value + mov DS:[13h*4+2],ES + + cmp Byte ptr Int19Sem, 0 + jnz int19vecs + jmp doint19 + +;;Dos 3.30 Will not support the PC-Jr +;;Rev 3.30 modification ---------------------------- +; ON THE PCJR, DON'T REPLACE ANY VECTORS +; MODEL BYTE DEFINITIONS FROM MSSTACK.ASM +; MOV AX,ROMSEGMENT +; MOV DS,AX +; MOV AL,MODELPCJR +; +; CMP AL,MODELBYTE +; JNE INT19VECS +; JMP DOINT19 + + +;Stacks code has changed these hardware interrupt vectors +;STKINIT in SYSINIT1 will initialzie Int19hOLDxx values. +int19vecs: + +; +; we now need to unhook all the vector replace to prevent stack overflow +; + +;;Rev 3.30 modification ---------------------------- + XOR AX,AX + MOV DS,AX + + IRP AA,<02,08,09,0A,0B,0C,0D,0E,70,72,73,74,76,77> + + LES DI,Int19OLD&AA + + mov ax,es ; Put segment where we can compare it + cmp ax,-1 ; OPT 0ffffh is not likely + je skip_int&AA ; OPT could get away without checking + cmp di,-1 ; OPT offset here. + je skip_int&AA + + MOV DS:[AA&H*4],DI + MOV DS:[AA&H*4+2],ES +skip_int&AA: + ENDM +;;End of modification ---------------------------- + +doint19: + LES DI,Orig19 + MOV DS:[19h*4],DI + MOV DS:[19h*4+2],ES + + INT 19h +INT19 ENDP +ASSUME DS:CODE + +;***************************************************************************** +PUBLIC DSK$INIT +DSK$INIT PROC NEAR + PUSH CS + POP DS + MOV AH,BYTE PTR DRVMAX + MOV DI,OFFSET DskDrvs + JMP SetPTRSAV +DSK$INIT ENDP + + +; +; Int 2f handler for external block drivers to communicate with the internal +; block driver in msdisk. The multiplex number chosen is 8. The handler +; sets up the pointer to the request packet in [PTRSAV] and then jumps to +; DSK$IN, the entry point for all disk requests. +; On exit from this driver (at EXIT), we will return to the external driver +; that issued this Int 2F, and can then remove the flags from the stack. +; This scheme allows us to have a small external device driver, and makes +; the maintainance of the various drivers (DRIVER and msBIO) much easier, +; since we only need to make changes in one place (most of the time). +; +; AL contains the Int2F function: +; 0 - Check for installed handler - RESERVED +; 1 - Install the BDS into the linked list +; 2 - DOS request +; + +MYNUM EQU 8 + +Public Int2F_Disk +Int2F_Disk PROC FAR + cmp ah,MYNUM + je Mine + jmp cs:[Int_2F_Next] ; chain to next Int 2F handler +Mine: + cmp al,0F8H ; IRET on reserved functions + jb Do_Func + IRET +Do_Func: + or al,al ; A GET INSTALLED STATE request? + jne Disp_Func + mov al,0FFH + IRET +Disp_Func: + Message fTestInit,<"Int2F_disk",cr,lf> + cmp al,1 ; Request for installing BDS? + jne Do_DOS_Req + call Install_BDS + IRET + +Do_DOS_Req: +; Set up pointer to request packet + MOV WORD PTR CS:[PTRSAV],BX + MOV WORD PTR CS:[PTRSAV+2],ES + jmp DSK$IN + +Int2F_Disk ENDP + +; +; Install_BDS installs a BDS a location DS:DI into the current linked list of +; BDS maintained by this device driver. It places the BDS at the END of the +; list. +Public Install_BDS +INSTALL_BDS PROC NEAR + message ftestinit,<"Install BDS",cr,lf> +; ds:di point to BDS to be installed + les si,dword ptr cs:[Start_BDS] ; Start at beginning of list + push es ; Save pointer to current BDS + push si +; es:si now point to BDS in linked list +Loop_Next_BDS: + cmp si,-1 ; got to end of linked list? + jz Install_Ret +; If we have several logical drives using the same physical drive, we must +; set the I_Am_Mult flag in each of the appropriate BDSs. + mov al,byte ptr ds:[di].DriveNum + cmp byte ptr es:[si].DriveNum,al + jnz Next_BDS + message ftestinit,<"Logical Drives",cr,lf> + xor bx,bx + mov bl,fI_Am_Mult + or word ptr ds:[di].flags,bx ; set flags in both BDSs concerned + or word ptr es:[si].flags,bx + mov bl,fI_Own_Physical + xor bx,-1 + and word ptr ds:[di].flags,bx ; reset that flag for 'new' BDS +; We must also set the fChangeline bit correctly. + mov bx,word ptr es:[si].flags ; determine if changeline available + and bl,fChangeline + xor bh,bh + or word ptr ds:[di].flags,bx + +Next_BDS: +; Before moving to next BDS, preserve pointer to current one. This is needed at +; the end when the new BDS is linked into the list. + pop bx ; discard previous pointer to BDS + pop bx + push es + push si + mov bx,word ptr es:[si].link + 2 + mov si,word ptr es:[si].link + mov es,bx + jmp short Loop_Next_BDS + +Install_Ret: + pop si ; Retrieve pointer to last BDS + pop es ; in linked list. + mov ax,ds + mov word ptr es:[si].link+2,ax ; install BDS + mov word ptr es:[si].link,di + mov word ptr ds:[di].link,-1 ; set NEXT pointer to NULL + RET +INSTALL_BDS ENDP + +; +; RE_INIT installs the Int 2F vector that will handle communication between +; external block drivers and the internal driver. It also installs the +; Reset_Int_13 interface. It is called by SYSYINIT +; +PUBLIC RE_INIT +RE_INIT PROC FAR + Message ftestinit,<"REINIT",CR,LF> + PUSH AX + PUSH DS + PUSH DI + XOR DI,DI + MOV DS,DI + MOV DI,2FH*4 ; point it to Int 2F Vector + MOV AX,WORD PTR DS:[DI] + MOV WORD PTR CS:[INT_2F_NEXT],AX + MOV AX,WORD PTR DS:[DI+2] ; preserve old Int 2F vector + MOV WORD PTR CS:[INT_2F_NEXT+2],AX + +; INSTALL the Reset_Int_13 +; interface + + + CLI + MOV Word Ptr DS:[DI],Offset Int_2f_13 ; install new vectors + MOV Word Ptr DS:[DI+2],CS + STI + POP DI + POP DS + POP AX + RET + +RE_INIT ENDP + +;------------------------------------------------- +; +; Ask to swap the disk in drive A: +; Using a different drive in a one drive system so +; request the user to change disks +; +Public SWPDSK +SWPDSK PROC NEAR + mov al,byte ptr ds:[di].drivelet ; get the drive letter + add al,"A" + mov cs:DRVLET,AL + push ds ; preserve segment register + push cs + pop ds + mov SI,OFFSET SNGMSG ; ds:si -> message + push BX + call WRMSG ;Print disk change message + call FLUSH + ; wait for a keyboard character + xor AH, AH ; set command to read character + int 16h ; call rom-bios + POP BX + pop ds ; restore segment register +WRMRET: + ret +SWPDSK ENDP + +;---------------------------------------------- +; +; WrMsg writes out message pointed to by [SI] +; +Public WrMsg +WRMSG PROC NEAR + lodsb ; get the next character of the message + or AL,AL ; see fi end of message + jz WRMRET + pushf + push CS + call OUTCHR + jmp SHORT WRMSG +WRMSG ENDP + + INCLUDE BIOMES.INC + +; +; End of support for multiple floppies with no logical drives +; This is not 'special' any more because we now have the capability of +; defining logical drives in CONFIG.SYS. We therefore keep the code for +; swapping resident ALL the time. +; + +;;Rev 3.30 modification ---------------------------- +;Variables for Dynamic Relocatable modules +;These should be stay resident. + + public INT6C_RET_ADDR +INT6C_RET_ADDR DD ? ;ret add from INT 6C for P12 mach + + PATHSTART 001,CLK +; +; DATA STRUCTURES FOR REAL-TIME DATE AND TIME +; + public BIN_DATE_TIME + public MONTH_TABLE + public DAYCNT2 + public FEB29 +BIN_DATE_TIME: + DB 0 ; CENTURY (19 OR 20) OR HOURS (0-23) + DB 0 ; YEAR IN CENTURY (0-99) OR MINUTES (0-59) + DB 0 ; MONTH IN YEAR (1-12) OR SECONDS (0-59) + DB 0 ; DAY IN MONTH (1-31) +MONTH_TABLE: + DW 0 ;MJB002 JANUARY + DW 31 ;MJB002 FEBRUARY + DW 59 ;MJB002 + DW 90 ;MJB002 + DW 120 ;MJB002 + DW 151 ;MJB002 + DW 181 ;MJB002 + DW 212 ;MJB002 + DW 243 ;MJB002 + DW 273 ;MJB002 + DW 304 ;MJB002 + DW 334 ;MJB002 +DAYCNT2 DW 0000 ;MJB002 TEMP FOR CNT OF DAYS SINCE 1-1-80 +FEB29 DB 0 ;MJB002 FEBRUARY 29 IN A LEAP YEAR FLAG + PATHEND 001,CLK + +;;End of modification modification ---------------------------- + +Public EndFloppy +EndFloppy Label Byte +; +; End of code for virtual floppy drives +; +Public EndSwap +EndSwap Label Byte + + PATHSTART 004,BIO + +Public HNUM +HNUM DB 0 ; number of hardfile (hard drives) + +Public HardDrv +HARDDRV DB 80H ;Physical drive number of first hardfile + + +; +; "HDRIVE" is a hard disk with 512 byte sectors +; + + EVENB +Public BDSH +BDSH DW -1 ; Link to next structure + DW Code + DB 80h ; physical drive number + DB "C" ; Logical Drive Letter +Public HDRIVE +HDRIVE: + DW 512 + DB 1 ; Sectors/allocation unit + DW 1 ; Reserved sectors for DOS + DB 2 ; No. of allocation tables + DW 16 ; Number of directory entries + DW 0000 ; Number of sectors (at 512 bytes each) + DB 11111000B ; Media descriptor + DW 1 ; Number of FAT sectors + DW 00 ; Sector limit + DW 00 ; Head limit + DW 00 ; Hidden sector count + DB 0 ; TRUE => bigfat +OPCNTH DW 0 ; Open Ref. Count +VOLIDH DB "NO NAME ",0 ; Volume ID for this disk + DB 3 ; Form Factor +FLAGSH DW 0020H ; Various Flags + dw 40 ; number of cylinders +RecBPBH db 31 dup (?) ; Recommended BPB for drive +TRACKH DB -1 ; Last track accessed on this drive +TIM_LOH DW -1 ; Keep these two contiguous (?) +TIM_HIH DW -1 +; +; End of single hard disk section +; + + +Public EndOneHard +EndOneHard Label Byte + + + + +; +;"DRIVEX" is an extra type of drive usually reserved for an +; additional hard file +; + + EVENB +Public BDSX +BDSX DW -1 ; Link to next structure + DW Code + DB 81h ; physical drive number + DB "D" ; Logical Drive Letter +Public DRIVEX +DRIVEX: + DW 512 + DB 00 ; Sectors/allocation unit + DW 1 ; Reserved sectors for DOS + DB 2 ; No. of allocation tables + DW 0000 ; Number of directory entries + DW 0000 ; Number of sectors (at 512 bytes each) + DB 11111000B ; Media descriptor + DW 0000 ; Number of FAT sectors + DW 00 ; Sector limit + DW 00 ; Head limit + DW 00 ; Hidden sector count + DB 0 ; TRUE => bigfat +OPCNTD DW 0 ; Open Ref. Count +VOLIDD DB "NO NAME ",0 ; Volume ID for this disk + DB 3 ; Form Factor +FLAGSD DW 0020H ; Various Flags + dw 40 ; number of cylinders +RecBPBD db 31 dup (?) ; Recommended BPB for drive +TRACKD DB -1 ; Last track accessed on this drive +TIM_LOD DW -1 ; Keep these two contiguous +TIM_HID DW -1 + +; +; End of section for two hard disks +Public EndTwoHard +EndTwoHard Label Byte + + PATHEND 004,BIO + + +Public TwoHard +TWOHARD LABEL BYTE + +PAGE +include ms96tpi.inc + +;;Rev 3.30 modification ---------------------------- +;Memory allocation for BDSM table. + PUBLIC BDSMs +BDSMs BDSM_type Max_mini_dsk_num dup (<>) ;currently max. 23 + +;** End_of_BDSM defined in MSINIT.ASM will be used to set the appropriate +;** ending address of BDSM table. +;;End of modification ---------------------------- + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug005sp +; +;;3.3 BUG FIX -SUNILP ------------------------------ +;Paragraph buffer between the BDSMs and MSHARD +; +;The relocation code for MSHARD needs this. this cannot be used for +;anything. nothing can come before this or after this.....IMPORTANT!!!! +;don't get too smart and using this buffer for anything!!!!!! +; + db 16 dup(0) +; +;end of bug fix buffer +;; +;;3.3 BUG FIX -SUNILP------------------------------ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug005sp +CODE ENDS + END diff --git a/SRC/BUGFIX/CMD/COMMAND/COMMAND.COM b/SRC/BUGFIX/CMD/COMMAND/COMMAND.COM new file mode 100644 index 0000000000000000000000000000000000000000..62d13ccad3a950676ca6472990b2ea3d8355f42e GIT binary patch literal 25276 zcmeIa3wTpi+BUp$+G&y|6bb=ElT=DZ1Orknkfsey6QEOCN{gkX2v%B@5h!oEw+u5L z!gNHMjfmsSIP(t7K#PYd3{#vsl;E_LNXx-0prZ&g16q|8wkS|7ltc30Yo|r@o$vks z|GK{KyT0rCgsa(muk+zq&w8HwdDe>DWelCrXKDyPD%7UWR1!Wp^prj`f$)aVf9Nv} zgja$+G8-Z3tVBdu`8wY68C~37US~}GJ`Hs(pOY9Q;Rns z&@Nikr1mP|6SxiG=G?9ntvzT`5Ckg;`>eAdqv@JKI99&Sbk5Mh%}*pWtfAACY3(Ad zzig=QGtgVfRIbOsbDj8&#RB%S#H&-dh(SI#de#ugil9Wau>IYYdTTv6e^jcd6f{VHV;4 zQch1C4Wo@?$axJ(@+Uh)^Jt^$-HaoTCX73><_bxwQ9HJdHaZ%H8QD{H9F=}*pu1z^ z*xM(jb~g5a%I2 zp*ah6m`0Es=NJ7Sj*+A`tll$-u&A7m`@)vuLN>A+PVTqdLqx5k;g<%-mRm^hbe*=e z+#04<5=o5pC))Z;Lp)tPE_6;8>At?@69fHGOt`q_$~m2&q9v+8R*D`J(mb*&MV(!r zq7P~Gbec*ue`pZXPZ~PBid1^H3J($*uBSgxq2b{cE!I&B!B5y1`mLdbWTJaXnQ9_% zp;z>gC$7`q#H3Hfq`Va*|e}*yGK*b~KW9>`$sAwa3WEm#yK@tIC$!$JCkiWW6Pkbftt`ifB6?B^ve! zTR4+dG?kb)a4KUUYk^rI=tWDRnQQ(b*4=t;JlSBGYfkG;i(Tv4me$^=wMJH74|(;p zMA@Q1Kk#&Nj~N6-*vb9WAbi>vzG~s-%$rlV;h&;c?O11jM+eew(CtYewH^ANZKY+4 zXid~)Euuq|^ViuwH(=;q(Dl9<;Pt)SJGuZ!DxzrpF+vo)sx_di%Nk>}+*eXGr?|PS zE2X?_{=)mMby;f+>$zIPq))`lwO=OJsM-=q2lteL)W(u{O>Jzjpkbeix~yLq@bze> zc)5jWx+b_{!Wgl$8E^jE>Yp-LIIH-**B`^B9dzE~;<84qHWM#zPUsF{^;^o;no zX$enXp_Ph27AoO2be=+Tgx2Y3kwSc*<}2ie^SaRQbj`Z16e&5hQAZ~uF^HV!Xyf(B z*6Xz>XpnI09E)~;`WnN$wjb&C7zjpm5oaw6&6D$mcIv1CWqoc);<-?>j($bhhYcUE z>*yKzBLN@#b@T)Yy``h?A?T7J#%r2Ykwy}qjlU7PpEM6-baGD`__5J9`wMk)j~n<~ zqHj96Ck*`1crZ$IasdMvczH~!iZk_F;w&&BG|ND%i4+C51G8(1fxY!|AF~=exNd_Y zXr7-)U%R3|#v5g3IlyaKUkR^e52Y}qgX_b@FlIUsAAD2%fd2AYnb!JF=!lLQ2^%jh zX;Mm&&~J2w&AQ7V@31T2PZ}Sv6z{jF6KliD56Z2Q-c{k}Tt8W*9B&Jg{{#M2CioM6 zn($P@FA`ozcsXH5!k&af3GXJHN;sQvB_UBaN;g60*3I)T<*RHf{ndQcVm{SVQE3xa zEag)Rs(G8gs-kkW9JIK4`SOYtm9|uG1z!;lsaUqmwxrs>yn;_HuBv(j8CKloon36J zTw3!8LKgGYe%lHZvZPvAQHfaF%8Hd${?vGNODcqAd}c4KV0Eoy5b>Q$K0}pHCfcE2`rCtMSZzXhk); zGG6Xfs@s-IjQZ(ImsQy?bk&RHUfFooP}_qQmE%*5`hh;>%+AlxF7P_=M6owFbJbG* zVKiguivE_^jCwXLHN1c6BPe&pYTF}Kt8J?uu38bFJY+ZO=T`ZbFI`cAS$?pBU;MD` zN7WD7?kJm3FcwYnmHKip1@fRHu}|(NibuF@3EGOVLVxu`{)*)`zPj4>;L?ZiL=4Z` zu)Jz{wSTo-2j+K)zp6^kW5aAzE~~1M=_IG0axi?XJll$j<*d-`#fz(IYA}c^mR42D zCFIM6-8?q^gKpI4RIFf>w5%HB(myuiZ8fWF_^RcoYZ;Fzy^*MfufUw%NLBS?c?RVg z=2ow?EvtI8Y8j(;x%vt=V^x*oZHwbIEUsRG`4*}iw$!qMqU_x1H<88v^w;r zZyvX=;gn(Pcw%VhxhR)mmJBT$jdHOkP_4?iq5Xyg?lk9`g~3~XXs%B(2eLBEL{Qu7 zO@s-s(f0aJ3|kfu=tK5qC*IZ5uE&!kLriM>18Ln%_G~0Q+pP8m6S>x4G1Hg6ZViwf z!2^@dsV;P=jjd})_srZKPA<>P_qufaMJG4h2(jWc>ApL6N21NOM9_9Hc||(zPpqAQk?GwR5VTBqm+sj(sW)&) z)uKSC_-=XmoINU%cCuep5l=Mxx>9cZA$?hQMPzHV1G7uMJGoo(%1B%Ry0&PjHah% zW)ndbdTtnfMTzXJWE9b}O*#>m3msf@;rf#s!d)qCdeZW$a{Kz@+gn@;`B9=_kM$Na z39V7KIL1JSh|@g_+B$+Xd}&y3(SoE6_#0$w`z>@OSDYBvALpza+WFf|*48XDH;?8k z#Y>!Zk+ueS0Me}K*l09a?R8ln8Ul|goC0UBS>~J9NC8r3DKdk2lKk4e zu|e#EB@`_xV;wZ8POij^dQYayOERrjjHZi7ad@(byF(lFIr8na9` zGa}+b4a4YSjP?r#hJ|$ENw9d&85FEiLRy})HB2yXJ!NRP+Z?k@Fvl?$E)*L^??Sq= zL=staA?@IfY&OSXqzhzW4*9{w>kqd)U_MIY|5f4ga3MV%Yq%GMq?t>@ML{sSDS#Y! zwR0c-xF4G5hpC469a8qjYxE8@NM%fm%_*6;gSyBJyVDmFlppsjT3E&>&Y`!HGJ7DC z2&aJ=XvOF}nn)z|JZd0iSiJm+*HKjkV<$GZ~(}*-EPXHITb)X^ymsM!oIke|O}J&8c3w z+Q0Onhk4tL{I;BG|4Q54Q>Wa07k(z+oPoW6r;P7L|NC#Fp8WfWe;Zo7vTE_tB@ieF zh;are?-`v?ugm-wd=Mq_NJbe!#!>mYex*?}zR{Uhb0^7>U#o7O@@bG_O zWU~qI}@?EFsC#!QpALhHA2#GXRSPvdR+)uMcDa3*vx z7luaUw~#3S6~=MTdy4lakxSj>V5TZGE0ZW6RgEFhhF3kT(q6`!cniJ%Hvh<8z{4?N zNH6e8-cjukZA)Q)} zez`m-M8}Y;1om^;K>7jku@>5@w03aH#QqQ=S+tNu28in!^xer3$n7SplplvxZfgZL z3(=_U;xzEe#%z~S=*u-(*O@L%lkVKuqPriEW5WHfDi}B&T0X5=-<1+HEuS{&T%C`oG2R=S^r#Z>(it&kJ)>}TtNx8^Z*CU?|4{GXn zd75l{bY#ZGolOaMzEN+;XQjtZ2@pEG@$+^kC=55k&TEvH4wS1Kk{Wneul^$cpmXx z`e1aHII}Kmr)P^HCurW~(H|2u(F2i!;gRdZ84>hP13)fiqC%!oOqnhkDY?#-0N5;U zA?G)=+XGqA*mXYPaybyqh1zfnX=hugeNE>4+nij@n}B>%1HG9i}~;UlCq&C36a& zjJ5hZ4?mp#T}MB%z_t>4VlpjK!BR4GVkG4ngcYisNL4^h549vf=ZS;c9o!cNK$+cG zISCzr3>9>H4CJ}~_y%UWN!OBCx{koI@RY{oESt}#^$)qzHI1eJ!a$@68-ZxQV5l=| zNu5bYAg%%ohb?4Eek_)DP)gbec$7|1^)Jhp!gRDMdre<})OcNE_#c9BgmY`Y?3pHZ z+UqY&qnwH+a)B%q%xmQ(DyU6X{!kzbGt8^#$z=LDgv$^J(J_>EC5J(VD*8NWl=jlY zN)-5K1Z*Ea(LdFtTXpYm#N$W1xwxTfl|fq@Wpr3;hVtqLruBz2j{6hF9cMIBqqaj6wL=wcc-|u(Uw>d+_=4MQA~wI&9)oPjVMI_* z2ZwFf4xIF?G0B9LCZOV74fh&HfZsu zBQx6!L_8%6!s4NxZD3V+r!9jq%eQrN_BuD9=^eCbFt5d|@_MPK$=KL^Dp&f)r1r*V z?jJOuduTape6y3yk>_Kj_2&$c?#uH_OKCwgbjTI44K3s>#SS)x^2){_L814cgK=^N zGXnA2gJ{}1G*Y&Z)>*DV-9cy8v0e=rN40g>E1(KpGoVW^7|N~M(r{s1ODYW)&#}Z; z<--2yD2dZ?EvF?4d#zbVh?Z@cqGd{c?bVoYTgaI&nmlgN@|uqspTq;*wmQ@N{IrvG zND+M6nV*wknV;`hf#6t(>lPu6jWnGYqrX!&8Rg2Du>k8%-kzkPY#h!DuoyrA5c;jN z*0S<&Y3Mhu$jIalZkq=n$FNz108yX?Nf_2o#V^{e&X72 z?-^xyZCE-hCk@)q8myDro!vDrL=Q;Mv+vP2E}2(2hwaR7nQA-KXxpC000EShE?U^% zyr@CJRw~R~Ozu+AyrI_cO}l4X+A$>TXW*bKEB#|%+x-MquO{2Yoq{5}He$H+p`*?e z%%M-l{I|NC{Ajx9x=SzUXm!k=i0|ZnUPoymlk=W-MXn^#;+X$D%5jLuC~4-<@z=`| zZFZ+dP)geI^2@;)A5%K)x}!ELn3M3h+GSg{8}q28%IoNIAH8~w8DbrbqHC{e{Az}N zuq}#&<@ScGm^%jA+$v)05!u$`Xn4)X5S(u|ps;u%)H<0aCI_|Sr&;^Lv_&be+BM9~ z6%z)wqk&piT(lmaKt z)<`KE=P(m8$goV}Hnx!2*qdW9zX~Nb_%!gjcvhU;mZ$02Cg&6ktr3VFn8=F zgO`q`oy4>UEnZD9J&!YKSySvI#8tZKLG^U(RYRxTBP2~PY0c9x?gBY2d!h7cV=e~y zRPRv-qiA_d;+>x`u+^?ilm%Opbsk;KEs}RZ2=?BK(?W|T(>H#=0*sNBU-u`9Ed81; zP(<8{$my%{J{QOWzZN9y7jdfl`(R)udWHWK8gx>mI{*~CN3Rh7J7Z3r%HT%2g$@Mq zW+ykyE$pq;Dr;xxl(p3wrRa@G8hVuY0WBhGOW+#ehdAwKH@5PL(U>+iTQgl6vXTCo z_H?x&k}z``dqxyp(ZRDub4p}BmVd0+DEyC zF4mv}bSd$N3ybFz%`3T&7F?!5vNu6NUmv;2jy;FwU*3HG!bS7T%1iw&&K^s@V$kN! zw%3_vXn<iusv%F?Que$mPbb#$f{%9=ZcMoNqjY=_l8sZsIfTCEBLjz5(O zgRZK*5)=L*zMC!WtxJE!Q#7d^0eq5pLUacnXNX=Y$j2dkUhac{YSJe;!(UM}DR^a*roP2fzuVKv?Lh=MF%x`)W@J92E63i&4-xH2~Z-Gf0fk1A6X}l=q(63W z_mNl!S5A_e2Z!#1=SCr|NGOfAgG7&!7`om1iyWE=G5a4mkhdc1VD;aelf);4Mr6=c zsghYV??hEU@`~mrJePSxC6no*)UAySp1Sl^Ub=O3b2^)1*kF)S5x(@%rS68+-a7M7y&>P!$j?Tj zR}7lm)?{l0qAokE6y4OciqZ4Kq47>yHk!`qp`U8Qp=UCg5d$nDi*_?Wqb1W9rSH2j2cE>gA7vg!uch%ETP5}$Xf4(V6%|T*&;pil{ML>aQ74b z0yOK43xbw0=qTSEnPNsh`ZHF+`_!5cT9(PbU89RJ>#XXRQpzX~4uL~{fqxU98p3`-3!)Fl@ z`r7lJv}15P!ZET)mkyh%^!qcibGZM8mWlDpaMoGpk$!;lO%MiDu z+A`RUw$CeSTjOmE6=u*Aw)u;+;W(n6}KcoEx-0OK7FY! zYlXLY2F!?yCfBG!1}Ckzg{g_Lx`CzkoGr|jLvWvZ8Z>84$-U@_wimWOlf$yrFko#Z z*M@>WDD5vaObsgfsE)srex#&WUPUVUu+Ejio0+IPnEqUacMbhWji2=@=`2hEVX7u{ zuR0tbsL(ijz85|8*AZ~) zJg}E&o4Kx}v}3zTvl3}qLz%Mav6nVc7@ zanbv&(%74CFRj~_%NNK5Kqyeijt>KwN7>IQInpRna|w; zpF+I4P%cG7^Au9=!a&vmV1>`qwMy1hX6`!$ECBXp*@ibHsD{C7e0FW8GAf6vr$OfV z&|rr*rFeA*Emg`Y8i14@$fT@%0?7!bK3UV)0MlApFWX#y588{XxF9^(tLekHS*6cf z?{Z11)=91s3mrrJNg&ou(aLWd zhz`%8CEqm=Wy=O4cfWy%sg756&?$uG5)9?}aQ_Z-iLOz&jPWUp8=%;l;=iCAk-i4g zxXGw=yPFx6M!T6&3HaNc`QbUm)Jwz zZNkJu1MfYj-CR~$!-XE564|F}w0CL0{~2>B}XS_VC?p~pta+fofH%ObwNgZ>BMbttHpSuU_!f9+{|clX1>G@e15X!Qy2va(qT zl}&-_0t*HFLZ8=#F1jK=P!={%m}38xhgZ8M@JiQ$QkkXG+hcUTDn6cOHlF?@`p=t$ z;z{jcCN&f=iS=(WJ~iVaKOT$eRahYkq>F`UH6(~qJ`wTIqzBXA!ot}X24|G#W_TEB z*T(vUOOsBnU7(Q5|9ss71^tP7dR_VkFB4pq5M0C0htp2dLs1!#?^$!01g6v1qnMa8 z(`o7TwoErXT{c3S*R?3fyQdAurFW&HY_~2_L|$dCBz^QLC4YO+WXO39C@zGYVX9U` z4it$N#m+9MgoYfLYNXPQZK|xag8)4lytChl+ZpsA2Vm>Tj9iM?yG%6bowdWKcNXk&$#y!_M1&@=O3 zcNp+qacudO$3-sgTok4sFgbd548HRKp&ZOM;8@|my=6&3t3at0=EM?V?rX0UPEeQhsFr4QJ1JA zk>8VfZMsD96vtTq3i{bKekq%6elZGAM!OoNGfr-ZTd<1%qWf501M+slcBLay<-9hR z2RThzX5Zg z5#R65oKr#-*Bd_0DIfQ*GSy*(jLY3Y=Ul^>Bc;nNXaXh((oXKSfmiy+tNq5S_X;Mp zuLVeA6qM`KtcE(2`OQ9{0_OuK`pH#6?aB~(3&NHnpaU{m5;tE0HwF49a8yU=TmocZ zzBLRogT;`)1XdPuc_6oo$6@vK8^q&Hv9&Ws)Q=$GF;J}FcfltFVwu>pH%y5fxZW?? ze;vx4!cO{}3yqr+c@@50usrgafh^b_d22|Q*rLe9DV1`+G3{8|LC8%?pk2~1^~)0X zE=XLbo%G2%`=Z2k_Uc6OUG#1~SZs6LkA+poK3|M~(w|4g^v4o!!tcp>X<`7REr;&_ zQR^Lys|p(mE2{on-F@|NncHd*;fm`RIEFbMt%I-2+w&-wV@#!hdDYGA&Ibn+i7b7S@cBFy!(>0}w6- z75}9&_-1c+xp)AlNBl>FZ#EOvfpF+yCw*&3WH8|P3H${ocZZvooSenY;~Wi>w`Mb~ z;jz6=2jvtIku;C*N|^_K3z*|C3JmeLftT7L+C|~u{@(DD!jRn+u0%h#dnK>aknFG zFyf3(E+t>M6-u^$c<{ZO2R@+V;8hU;DqB9)3^1_D$o& ziLQx)^3KlPWP7+#)+5;2!0QP(p$K8oQYbSXuBB(5{Ga%b#RY*VWN6A z4}fU<9c5xK1CT4}ML_pc);VT?S(BhXe$*T0-zHyi8R;ff( zSGP(hUJ|p6d8)oOvGuu+4;$CV>`tVy4q>QA4`EJHwJ1q{eGIvtx2d;N0sJEio#sc0 zmS^)=O(Te|TB~!2GdK5130v!CHav^`i?CgV3xnam7(neRNRZz+KB3*%A2u;>5*3(b zm{6A@^n9Ld{ov?-TwKq!=GA4j<8NP{c5i?%BXFM5|GxNsCzm{H=~Nuh0t0$Pq!7Hs z^n*Up^pzRA(n|Zt? zyP!n8)Iy*ih|z_JWm=ey{itS0mm480!ArJV*|QDYoHbP~jM|+cno*Vcpl{7SwCO*I zNdI6sCuo0P)05UNtz^wH?aLF>+w-_sdTXB64iwlS+%v}>RIk(6gI>itp8^%F^C?U0 z!J&aeHZ)7TRNDb#3|c||dKvDfXbS?$wBz2kurjQe6YFebf^#DDk=BkpCevUkUlI3j z##Rb@LAbDK0&VZ%wM`4^-^?ow%Rl|J(H#SMiRt_D>d>fofehu;V#Pq4{>oa1sNnIm z_BF9VdHiiRsu3^ttI>n<*pNTq!jjUTojZF=^4m>E=)RPxv$R_6zh0xXtg$1i0hmS~53L)rHN%JI%@R77Aoo zO;gT?n{San8B$tE2cIv6e2Az_$ZC<_^|0M>2osqA=i+3wA}otJVQRw)3H^-FqzjQh zpJ(yRQ^I5obSpycOvw?c=wZ9n*7J~S=^S`nrTG&D4f8kyvWXu!=L#n$wZlGhBJ_hy zdcqJY$kd;NkNJ$uNS6V7Ym36+*9$5njUHg>n_|ND=DA3JJakW{^foKpi^BOk|75h; zGI5M3DYJTsaBKWn!LY<73_SURc$`|1NYIGk-(L=gbgsT|A&xZ2*r*nqL6-i0?kx=o z8CXZdv5ATwwEjm1J^ioQu%uw5WqU!L`DfnHBN>q~1_tf|SZcnrE9EzI5TO@(p`HL> zqPG~Z(TeAfex^FVro-zLKa_0^usN_pi$mF=MK(nLgM*9k%2?@bc+uBz!CT+tX=wH| z?C><~_BCwq!aJ`18E^f0Z~aDZeUG>PWncYzZ~d3v`kL(eKlKlFaJADm%JPq4@@Q17a+}m)@+fd+Zc+T7KmABzY zPD3!KVMb1UlW%4N_16E@Q!jZ@0me3HvAUz!g4l+mNITb70Lx**rYP6s>+KA%!=8Wk zDH#7Z>Kr>fI>%1WW`COW!Dhb$(M%nB*;BH0x39IpH?E`YIj^b{eOYIE#+%)z3fp4IBVPlpF$jTof7%0W(%7ClIO_jBd5`8fIeGZ_JCWd zU2x8fXfFH>`j$ety?+XuogLE^N>sExUUJ8DwXy?8$>{Uiz!M6kV20I&`-N991q#&4 zw&%Ta+$yd3gc3Yn7zS7h34BrEB}6EZhNJVfKn%9-^!%~=Nnzt3lb~%f+LJeL=!jn% ztRPQFBIo*tijB`aEe1sRnhnUM{Ruc15XgE7+8M@br%z2^P|*w$*+_7JB4p_|U#;}g zj}szaz9%OXoT0B^wtCnb%AZUR!(uljvP(@Lz>#v4BEWMeP8y(yy7U))z`6eRrI&u7 z5z{Yt!)zFFjeu02c1}bjn>^N{{ha@EHeF{}!@i)qVu7sBaundAz-Fsq2ABDM{{A+z5C{OV@r*50ZESJ^h2ikFja;!~^(5+6ctvb3h$R zDUm)!ghd_PE)S8m1hQD5k#(#t{hYUhrTKP0|EXcUoWy#0o*s_UY>9cHvR>^ynga}p zHIDvNEmzFuBwPqK8O(vp zu*@v=?cvt1ylrjn<_DOw2*4q9HLm3irrd>1@v{z@Qz+4H4vWX@EP1{bG7m_-d6%!w z^cQ^KoKN86z&dljj|b&90u$##qcS6}D@CMbRyEPw>=}1RFwy7WQS&EEa1{#$4L&a$ z+^qil;CnSEkd==pZ6IqWN*E;`6|O}7B>ecp3%rxtFkXj}HUqij!W_SE4o1BLh# zA!o%4O_H9Ki+}+u3%%giu|1BprXrRRyl2tVQS;f0n+E8=e!I^2!F$;zG8gp0{GPV zIG^hAE)@6EM-T9Gnsv-&^mcrwCne zhH)dwi+x)a2?C}AMm;0G>SgDO4xi$&tSkwJ<8kPJOX?1%^Q%sK!sE^Nq1*%Y75Y%n7~N!Gznzzt`@A zCm8cRGxt*iqjGj=(1#Ri-Yu4B0#R`6SEt2Q2ujY#nSxKK182BEj1z{7k1GG-oU$M) zaBO#zH275%NDl^LO4#SHNrveQpUZInXz>cOtL9$ZIUCkymY69TnnspE-V}W>#UKO9 z?(J0bJuC$ZXQO>b&;s+qt-MXH2|Sk70Yk#AG~;vU0{GRk3fA6Q)7BU1{#PBg-RX+N ztz+HHF@u>>*1ow*)zirO-TIuj%{-0q)YdjP-snr8h11&WvUdCGL%#aGzTo9e^U@Bk zGkun`gXVuG+=k(lPnNFb_JT_Iv;EQuwzlVZoCAtpv?;!X-wov(hNo$0=+4ll}+wD?R$Lwvui)<)~)@B zhRE8FKE8yP=%+$T;2kVq@{=GA11|(r ze+QtDR9NId+5il|4HpsV*mP-dq$CD^j>!Hqkp=%OShTq>Tp+mv?=tjO#n- zrcc7~%rA38(bCE<3UaOJKJoK8#f9@qI17p_cZ(~OS>mIlc0Z0D&_2ZuIMtgmhZ?#L zcLY%paO1*7rR8P!&kw`eQs{=tGluU*|A2+f#KY?5&){Km^Bz1>+Yf9eXc;^x8rQ_y z;K3N)Q|^BHopJB*y~Xg7Eps!2L%ExA>>52CNi#XZ-w6%*0G}$JP#q7rZ{bH-%Vj4* zX5EY*h2rRIpEK)b?x)uBaEaIhOLdkwNgTQm>)TOZ=yuf4akDvTvN`HY-2)KO#JeY@ z-E(jH~v=Z?LO9R{GgJ8UOBP4-%NnZfhC1n&sOU zY>@WJUSZ|3rMPCK|56Ti@rDhFrpvc*3|!2DX8d#Ve+kk~DXhRnBR8&ZL8@D(eD~zz zT~p9_+^n*6@ltl?k=^@ppzN4%J2)iu2B!7AKIBj?1uB;>DXV*HvI zHlPC|z}~;rw~wccnOZ3i%pEmj`)fsR-PDzs&~GBh?Ne9DGi-ZsHD6UDUwDFKX;W8w zf9f5mD1Jjs|0&M+B`-*mHx(C@R9E7jor;I5Y-8@Nlc0wy zTz1-A-rS-roGd1$jQBz58;79B++FDyGjUSozdd$LZpnDu`=obF4$04028=rDy)$)}*TMfH2@&zoBIBl-B%`RZ`QLePV*S*+u7!{n=>5GJ^aSFhkJetd%y)VYk)XBQ3J$^%ZY0_&XJ6GZ+KCEmnz z25ulC%?JlEEw8FvdV}M|?+>aJgBeI z{xyY!U%5O*zU(}iR&UEJ@fGDxFOxsUX8Lkw&X!-(f$=exlnuZSkKD|G-m>nq!Hsho z`Nktscq4X&u>3*LJ%;(lN@9z6MP~f=rT$B&*gZ?}6^^)PGx4)MGr^WXnle|fC@WBp zDxdU2Pr^`d+gRU~Tz!2bgVRIY&l literal 0 HcmV?d00001 diff --git a/SRC/BUGFIX/CMD/FDISK/FDISK.COM b/SRC/BUGFIX/CMD/FDISK/FDISK.COM new file mode 100644 index 0000000000000000000000000000000000000000..385fa9d75e3cfc94e7baf215b4e3a558d07eef9b GIT binary patch literal 48919 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 literal 0 HcmV?d00001 diff --git a/SRC/BUGFIX/CMD/FORMAT/FORMAT.ASM b/SRC/BUGFIX/CMD/FORMAT/FORMAT.ASM new file mode 100644 index 0000000..17d7e50 --- /dev/null +++ b/SRC/BUGFIX/CMD/FORMAT/FORMAT.ASM @@ -0,0 +1,3032 @@ +page 84,132 +; SCCSID = @(#)format.asm 1.26 85/10/20 +; SCCSID = @(#)format.asm 1.26 85/10/20 +;*************************************************************** +; +; 86-DOS FORMAT DISK UTILITY +; +; This routine formats a new disk,clears the FAT and DIRECTORY then +; optionally copies the SYSTEM and COMMAND.COM to this new disk +; +; SYNTAX: FORMAT [drive][/switch1][/switch2]...[/switch16] +; +; Regardless of the drive designator , the user will be prompted to +; insert the diskette to be formatted. +; +;*************************************************************** + +; 5/12/82 ARR Mod to ask for volume ID +; 5/19/82 ARR Fixed rounding bug in CLUSCAL: +; REV 1.5 +; Added rev number message +; Added dir attribute to DELALL FCB +; REV 2.00 +; Redone for 2.0 +; REV 2.10 +; 5/1/83 ARR Re-do to transfer system on small memory systems +; REV 2.20 +; 6/17/83 system size re-initialization bug -- mjb001 +; Rev 2.25 +; 8/31/83 16-bit fat insertion +; Rev 2.26 +; 11/2/83 MZ fix signed compare problems for bad sectors +; Rev 2.27 +; 11/8/83 EE current directories are always saved and restored +; Rev 2.28 +; 11/9/83 NP Printf and changed to an .EXE file +; Rev 2.29 +; 11/11/83 ARR Fixed ASSIGN detection to use NameTrans call to see +; if drive letter remapped. No longer IBM only +; Rev 2.30 +; 11/13/83 ARR SS does NOT = CS, so all use of BP needs CS override +; Rev 2.31 +; 12/27/83 ARR REP STOSB instruction at Clean: changed to be +; sure ES = CS. + +code segment public 'CODE' +code ends + +printf_code segment public + extrn printf:far +printf_code ends + +stack segment stack + db (362 - 80h) + 100H dup (?) ; (362-80h) is the additional IBM ROM + ; overhead recently discovered by them. +stack ends + +data segment public 'DATA' +data ends + +public end_of_memory +_end segment public para 'DATA' +end_of_memory label byte +_end ends + +code segment + + assume cs:code,ds:nothing,es:nothing,ss:stack + +;------------------------------------------------------------------------------- +; Define as public for debugging + +; procedures + public GetSize + public AddToSystemSize + public Phase1Initialisation + public SetStartSector + public SetfBigFat + public Phase2Initialisation + public DiskFormat + public BadSector + public FormatTrack + public DisplayCurrentTrack + public NextTrack + public WriteFileSystem + public Done + public CurrentLogicalSector + public PrintErrorAbort + public GetDeviceParameters + public SetDeviceParameters + + public START + public GOTBADDOS + public OKDOS + public BogusDrive + public DRVGD + public DRVSPEC + public NXTSWT + public GETPARM + public GETCHR + public INVALID + public SCANOFF + public MEMERR + public SAVSWT + public NotNet + public RE_ASSIGN + public NO_ASSIGN + public FatAllocated + public MEMERRJ + public MEM_OK + public RDFRST + public NEEDSYS + public INITCALL + public SWITCHCHK + public SYSLOOP + public FRMTPROB + public GETTRK + public TRKFND + public CLRTEST + public CMPTRKS + public PACKIT + public BadClus + public DoBig + public DoSet + public DRTFAT + public CLEARED + public LOUSE + public LOUSEP + public FATWRT + public SYSOK + public STATUS + public REPORTC + public ONCLUS + public MORE + public FEXIT + public SYSPRM + public fexitJ + public DoPrompt + public TARGPRM + public IsRemovable + public CheckRemove + public IsRemove + public NotRemove + public DSKPRM + public GOPRNIT + public crlf + public PrintString + public std_printf + public VOLID + public VRET + public DOVOL + public VOL_LOOP + public GOOD_CREATE + public VOLRET + public READDOS + public RDFILS + public FILESDONE + public CLSALL + public GOTBIOS + public GOTDOS + public CLSALLJ + public GOTCOM + public WRITEDOS + public GOTALLBIO + public BIOSDONE + public GOTNDOS + public PARTDOS + public GOTALLDOS + public DOSDONE + public PARTCOM + public GOTALLCOM + public COMDONE + public MAKEFIL + public CheckMany + public CLOSETARG + public IOLOOP + public GOTTARG + public GSYS + public TESTSYS + public GETOFFS +; public TESTSYSDISK ; dcl 8/23/86 + public SETBIOS + public BIOSCLS + public SETBIOSSIZ + public DOSOPNOK + public DOSCLS + public SETDOSSIZ + public GotComHand + public COMCLS + public SETCOMSIZ + public GETFSIZ + public READFILE + public WRITEFILE + public FILIO + public NORMIO + public IORETP + public IORET + public NORMALIZE + public GotDeviceParameters + public SmallFAT + public LoadSectorTable + public NotBigTotalSectors + public NotBig + public FormatLoop + public FormatDone + public FailDiskFormat + public FormatReallyFailed + public ContinueFormat + public ReportBadTrack + public NoMoreTracks + public ExitNextTrack + public ThatsAllFolks + public WriteFATloop + public WriteDIRloop + public CanNotWriteFAT + public CanNotWriteDirectory + public ControlC_Handler + +; bytes + public fBigFat + public formatError + public ROOTSTR + public DBLFLG + public DRIVE + public FILSTAT + public USERDIRS + public VOLFCB + public VOLNAM + public TRANSRC + public TRANDST + public INBUFF + public driveLetter + public systemDriveLetter +; words + public startSector + public fatSpace + public firstHead + public firstCylinder + public tracksLeft + public tracksPerDisk + public sectorsInRootDirectory + public directorySector + public printStringPointer + public MSTART + public MSIZE + public TempHandle + public BEGSEG + public SWITCHMAP + public SWITCHCOPY + public FAT + public CLUSSIZ + public SECSIZ + public SYSTRKS + public SECTORS + public ptr_msgHardDiskWarning + public ptr_msgInsertDisk + public ptr_msgReInsertDisk + public ptr_msgInsertDosDisk + public ptr_msgCurrentTrack + public currentHead + public currentCylinder + +; other + public deviceParameters + public formatPacket +;------------------------------------------------------------------------------- + +data segment + extrn msgAssignedDrive:byte + extrn msgBadDosVersion:byte + extrn msgDirectoryWriteError:byte + extrn msgFormatComplete:byte + extrn msgFormatNotSupported:byte + extrn msgFATwriteError:byte + extrn msgInvalidDeviceParameters:byte + extrn msgLabelPrompt:byte + extrn msgNeedDrive:byte + extrn msgNoSystemFiles:byte + extrn msgTooManyFilesOpen:byte + extrn msgNetDrive:byte + extrn msgInsertDisk:byte + extrn msgHardDiskWarning:byte + extrn msgSystemTransfered:byte + extrn msgFormatAnother?:byte + extrn msgBadCharacters:byte + extrn msgBadDrive:byte + extrn msgInvalidParameter:byte + extrn msgParametersNotSupported:byte + extrn msgReInsertDisk:byte + extrn msgInsertDosDisk:byte + extrn msgFormatFailure:byte + extrn msgNotSystemDisk:byte +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +; reintroduce following extrn + extrn msgNoRoomDestDisk:byte +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + extrn msgDiskUnusable:byte + extrn msgOutOfMemory:byte + extrn msgCurrentTrack:byte + extrn msgWriteProtected:byte + extrn msgNotReady:byte + extrn msgInterrupt:byte + extrn msgCRLF:byte + +data ends + + +debug equ 0 + .xlist + INCLUDE VERSIONA.INC + INCLUDE DOSMAC.INC + INCLUDE SYSCALL.INC + INCLUDE ERROR.INC + INCLUDE DPB.INC + INCLUDE CPMFCB.INC + INCLUDE DIRENT.INC + INCLUDE CURDIR.INC + INCLUDE PDB.INC + INCLUDE BPB.INC + .list + +;------------------------------------------------------------------------------- +; Constants + +;Limits +BIG_FAT_THRESHOLD equ 4086 + +;------------------------------------------------------------------------------- + +;FORMAT Pre-defined switches +SWITCH_S EQU 1 ; System transfer +SWITCH_V EQU 2 ; Volume ID prompt +SWITCH_H EQU 4 ; E5 dir terminator +SWITCH_C EQU 8 +SWITCH_T EQU 16 +SWITCH_N EQU 32 +SWITCH_1 EQU 64 +SWITCH_4 EQU 128 +SWITCH_8 EQU 256 +SWITCH_B EQU 512 + +NUM_SWITCHES EQU SWITCH_T or SWITCH_N + +DRNUM EQU 5CH + +RECLEN EQU fcb_RECSIZ+7 +RR EQU fcb_RR+7 + +;------------------------------------------------------------------------------- +; These are the data structures which we will need + + include ioctl.INC + +;Per system file data structure + +a_FileStructure struc +fileHandle DW ? +fileSizeInParagraphs DW ? +fileSizeInBytes DD ? +fileOffset DD ? +fileStartSegment DW ? +fileDate DW ? +fileTime DW ? +a_FileStructure ends + +;------------------------------------------------------------------------------- +; And this is the actual data + +data segment + public deviceParameters + +validSavedDeviceParameters db 0 +savedDeviceParameters a_DeviceParameters <> +deviceParameters a_DeviceParameters <> + +formatPacket a_FormatPacket <> + +startSector dw ? +fatSpace dd ? +fBigFat db FALSE + +firstHead dw ? +firstCylinder dw ? +tracksLeft dw ? +tracksPerDisk dw ? + +public NumSectors ,TrackCnt +NumSectors dw 0FFFFh +TrackCnt dw 0FFFFh + +public Old_Dir +Old_Dir db FALSE + +public fLastChance +fLastChance db FALSE ; Flags reinvocation from + ; LastChanceToSaveIt. Used by DSKPRM + +sectorsInRootDirectory dw ? + +directorySector dd 0 + +formatError db 0 + +printStringPointer dw 0 + +; Exit status defines +ExitStatus db 0 +ExitOK equ 0 +ExitCtrlC equ 3 +ExitFatal equ 4 +ExitNo equ 5 + +ROOTSTR DB ? + DB ":\",0 +DBLFLG DB 0 ;Initialize flags to zero +IOCNT DD ? +MSTART DW ? ; Start of sys file buffer (para#) +MSIZE DW ? ; Size of above in paragraphs +TempHandle DW ? +FILSTAT DB ? ; In memory status of files + ; XXXXXX00B BIOS not in + ; XXXXXX01B BIOS partly in + ; XXXXXX10B BIOS all in + ; XXXX00XXB DOS not in + ; XXXX01XXB DOS partly in + ; XXXX10XXB DOS all in + ; XX00XXXXB COMMAND not in + ; XX01XXXXB COMMAND partly in + ; XX10XXXXB COMMAND all in + +USERDIRS DB DIRSTRLEN+3 DUP(?) ; Storage for users current directory + +bios a_FileStructure <> +BiosAttributes EQU attr_hidden + attr_system + attr_read_only + +dos a_FileStructure <> +DosAttributes EQU attr_hidden + attr_system + attr_read_only + +command a_FileStructure <> +CommandAttributes EQU 0 +CommandFile DB "X:\COMMAND.COM",0 + +VOLFCB DB -1,0,0,0,0,0,8 + DB 0 +VOLNAM DB " " + DB 8 + DB 26 DUP(?) + +TRANSRC DB "A:CON",0,0 ; Device so we don't hit the drive +TRANDST DB "A:\",0,0,0,0,0,0,0,0,0,0 + +BEGSEG DW ? +SWITCHMAP DW ? +SWITCHCOPY DW ? +FAT DW ? + DW ? +CLUSSIZ DW ? +SECSIZ DW ? +SYSTRKS DW ? +SECTORS DW ? +INBUFF DB 80,0 + DB 80 DUP(?) + +ptr_msgHardDiskWarning dw msgHardDiskWarning + dw offset driveLetter + +ptr_msgInsertDisk dw msgInsertDisk + dw offset driveLetter + +ptr_msgReInsertDisk dw msgReInsertDisk + dw offset driveLetter + +ptr_msgInsertDosDisk dw offset msgInsertDosDisk + dw offset systemDriveLetter + +ptr_msgFormatNotSupported dw offset msgFormatNotSupported + dw offset driveLetter + +drive db 0 +driveLetter db "x" +systemDriveLetter db "x" + +data ends + +;For FORPROC and FORMES modules + + public secsiz,clussiz,inbuff + + PUBLIC crlf,std_printf + +;For OEM module + public switchmap,drive,driveLetter,fatSpace + public fBigFat, PrintString,currentHead,currentCylinder + extrn CheckSwitches:near,LastChanceToSaveIt:near + extrn WriteBootSector:near,OemDone:near + extrn AccessDisk:near +data segment + extrn switchlist:byte + extrn fdsksiz:word + extrn BiosFile:byte,DosFile:byte +data ends + +;For FORPROC module + + EXTRN FormatAnother?:near,Yes?:near,REPORT:NEAR,USER_STRING:NEAR +data segment + extrn badsiz:dword,syssiz:dword,biosiz:dword +data ends + +DOSVER_LOW EQU 0300H+20 +DOSVER_HIGH EQU 0300H+20 + + +START: + PUSH AX ;Save DRIVE validity info + MOV AH,GET_VERSION + INT 21H + CMP AX,EXPECTED_VERSION + JE OKDOS + +; XCHG AH,AL ;Turn it around to AH.AL +; CMP AX,DOSVER_LOW +; JB GotBadDos +; CMP AX,DOSVER_HIGH +; JBE OKDOS + + +GOTBADDOS: + MOV DX,OFFSET msgBadDosVersion + mov ax, seg data + mov ds, ax + mov ah,std_con_string_output + int 21h + push es + xor ax,ax + push ax + +foo proc far + ret ; Must use this method, version may be < 2.00 +foo endp + +OKDOS: + + mov ax, seg data + mov es, ax + assume es:data + POP AX + + CMP AL,0FFH ;See if invalid drive specified + JNZ DRVGD ;If not proceed +BogusDrive: + mov ax, seg data + mov ds, ax + lea dx, msgBadDrive + call PrintString + JMP FEXIT ;Exit + +DRVGD: + MOV AH,GET_DEFAULT_DRIVE ;Must get the default drive + INT 21H ;Default now in AL + ADD AL,"A" + MOV [BiosFile],AL + MOV [DosFile],AL + MOV [CommandFile],AL + MOV SI,DRNUM ;So we can get our parameters + LODSB ;Fetch drive designation + OR AL,AL ;See if specified + JNZ DRVSPEC ;If specfied proceed + mov ax, seg data + mov ds, ax + lea dx, msgNeedDrive + call PrintString + jmp fexit +DRVSPEC: + DEC AL ;Drive designator now correct + MOV BYTE PTR DS:[DRNUM],AL ;And updated + MOV DRIVE,AL ;Save copy + add al, 'A' + mov driveLetter, al +; Get all the switch information from the command line + MOV [BEGSEG],DS ;Save start segment + + XOR BX,BX ;Store switch information in BX + MOV SI,81H ;Point to the command line buffer +NXTSWT: + CALL SCANOFF + LODSB + CMP AL,"/" + JZ GETPARM + + CMP AL,13 + JNZ NxtS1 + JMP SavSwt +NxtS1: + MOV AH,AL + LODSB ; AX := getchar() + CMP AL,":" ; IF (AX != drive_spec) + JNZ INVALID ; THEN error + + CMP BYTE PTR DBLFLG,0 ; IF (previous drive_spec) + JNZ INVALID ; THEN error + + INC BYTE PTR DBLFLG ; Yes -- set the flag + OR AH,020h + SUB AH,'a' + CMP AH,Drive + JZ SHORT NXTSWT + JMP BogusDrive +GETPARM: + LODSB +; Convert any lower case input into upper case + CMP AL,41H + JB GETCHR ; Switch is a digit, so don't try to + ; convert it. + AND AL,0DFH +GETCHR: + MOV CL,SWITCHLIST ; CL := Number of Legal switches + OR CL,CL ; IF (Num_Legal_Switches == 0) + JZ INVALID ; THEN error + + MOV CH,0 ; FOR (i=0; i <= Max_switches; i++) + MOV DI,1+OFFSET SWITCHLIST ; IF (switch == SWITCHLIST[i]) + REPNE SCASB ; THEN set zero flag + ; END for + JNZ INVALID ; IF (zero_flag != TRUE ) THEN error + + MOV AX,1 + SHL AX,CL + OR BX,AX ;Set the appropriate bit in SWITCHMAP + + MOV CX,AX ; Current_Switch := Switch processed + Test AX,NUM_SWITCHES ; IF (Switch_processed does not require + ; numeric value) + JZ NXTSWT ; THEN parse next switch + + LODSB ; ELSE then parse :nn and save approp + cmp al,':' ; IF (getchar() != ':') + jne INVALID + + LODSB ; curr_num := MakeNum (getchar()) + SaveReg + call MakeNum + RestoreReg + jc INVALID ; IF error, THEN exit + + SaveReg + Call SaveNum ; SaveNum (curr_num) + Restorereg ; END else; + + + JMP SHORT NXTSWT ;See if there are anymore + +INVALID: + mov ax, seg data + mov ds, ax + lea dx, msgInvalidParameter + call PrintString + JMP FEXIT +MEMERR: + mov ax, seg data + mov ds, ax + lea dx, msgOutOfMemory + call PrintString + JMP FEXIT + +SAVSWT: + mov ax, seg data + mov ds, ax + assume ds:data + MOV SWITCHMAP,BX + +; Set memory requirements + mov es, begseg + mov bx, seg _end + sub bx, begseg + mov ah, setblock + int 21H + +; trap ^C + mov ax, (Set_Interrupt_Vector shl 8) or 23H + mov dx, offset ControlC_Handler + push ds + push cs + pop ds + int 21H + pop ds + +AroundControlC_Handler: + MOV BL,Drive ; x = IOCTL (getdrive, Drive+1); + INC BL + MOV AX,(IOCTL SHL 8) OR 9 + INT 21H + JC NotNet + TEST DX,1200H ; if (x & 0x1200)(redirected or shared) + JZ NotNet + lea dx, msgNetDrive ; Cann't format over net + call PrintString + JMP FEXIT + +NotNet: + TEST DX,8000h ; if local use + jnz re_assign + MOV BL,Drive + ADD BYTE PTR [TRANSRC],BL ; Make string "D:\" + MOV SI,OFFSET TRANSRC + push ds + pop es + MOV DI,OFFSET TRANDST + MOV AH,xNameTrans + INT 21H + MOV BL,BYTE PTR [TRANSRC] + CMP BL,BYTE PTR [TRANDST] ; Did drive letter change? + JZ NO_ASSIGN ; No +RE_ASSIGN: + lea dx, msgAssignedDrive + call PrintString + JMP FEXIT + +NO_ASSIGN: + + CALL Phase1Initialisation + jnc FatAllocated + + lea dx, msgFormatFailure ; IF (error_allocating_FAT) + call PrintString ; ISSUE error and abort + jmp Fexit +FatAllocated: + + TEST SWITCHMAP,SWITCH_S + JZ INITCALL + MOV BX,0FFFFH + MOV AH,ALLOC + INT 21H + OR BX,BX + JZ MEMERRJ ;No memory + MOV [MSIZE],BX + MOV AH,ALLOC + INT 21H + JNC MEM_OK +MEMERRJ: + JMP MEMERR ;No memory + +MEM_OK: + MOV [MSTART],AX + +RDFRST: + mov bios.fileSizeInParagraphs,0 ;mjb001 initialize file size + mov dos.fileSizeInParagraphs,0 ;mjb001 ... + mov command.fileSizeInParagraphs,0 ;mjb001 ... + CALL READDOS ;Read BIOS and DOS + JNC INITCALL ;OK -- read next file +NEEDSYS: + CALL SYSPRM ;Prompt for system disk + JMP RDFRST ;Try again + +INITCALL: + CALL Phase2Initialisation +; Barry S - No reason to jump on carry!!! +; JNC SWITCHCHK +; lea dx, msgFormatFailure +; call PrintString +; JMP FEXIT + +SWITCHCHK: + MOV DX,SWITCHMAP + MOV SWITCHCOPY,DX + +SYSLOOP: + MOV WORD PTR BADSIZ,0 ;Must intialize for each iteration + MOV WORD PTR BADSIZ+2,0 + MOV WORD PTR SYSSIZ,0 + MOV WORD PTR SYSSIZ+2,0 + MOV BYTE PTR DBLFLG,0 + mov ExitStatus, ExitOK + MOV DX,SWITCHCOPY + MOV SWITCHMAP,DX ;Restore original Switches +; DiskFormat will handle call for new disk +; CALL DSKPRM ;Prompt for new disk + CALL DISKFORMAT ;Format the disk + JNC GETTRK +FRMTPROB: + lea dx, msgFormatFailure + call PrintString + mov ExitStatus, ExitFatal + CALL MORE ;See if more disks to format + JMP SHORT SYSLOOP + +;Mark any bad sectors in the FATs +;And keep track of how many bytes there are in bad sectors + +GETTRK: + CALL BADSECTOR ;Do bad track fix-up + JC FRMTPROB ;Had an error in Formatting - can't recover + CMP AX,0 ;Are we finished? + JNZ TRKFND ;No - check error conditions + JMP DRTFAT ;Yes +TRKFND: + CMP BX,STARTSECTOR ;Are any sectors in the system area bad? + JAE CLRTEST ; MZ 2.26 unsigned compare + lea dx, msgDiskUnusable + call PrintString + JMP FRMTPROB ;Bad disk -- try again +CLRTEST: + MOV SECTORS,AX ;Save the number of sectors on the track + TEST SWITCHMAP,SWITCH_S ;If system requested calculate size + JZ BAD100 + CMP BYTE PTR DBLFLG,0 ;Have we already calculated System space? + JNZ CMPTRKS ;Yes -- all ready for the compare + INC BYTE PTR DBLFLG ;No -- set the flag + CALL GETBIOSIZE ; Get the size of the BIOS + MOV DX,WORD PTR SYSSIZ+2 + MOV AX,WORD PTR SYSSIZ + MOV WORD PTR BIOSIZ+2,DX + MOV WORD PTR BIOSIZ,AX + CALL GETDOSSIZE + CALL GETCMDSIZE + MOV DX,WORD PTR BIOSIZ+2 + MOV AX,WORD PTR BIOSIZ + DIV deviceParameters.DP_BPB.BPB_BytesPerSector + ADD AX,STARTSECTOR + MOV SYSTRKS,AX ;Space FAT,Dir,and system files require +CMPTRKS: + CMP BX,SYSTRKS + JA BAD100 ; MZ 2.26 unsigned compare + mov ExitStatus, ExitFatal + lea dx, msgNotSystemDisk + call PrintString + AND SWITCHMAP,NOT SWITCH_S ;Turn off system transfer switch + MOV WORD PTR SYSSIZ+2,0 ;No system to transfer + MOV WORD PTR SYSSIZ,0 ;No system to transfer +BAD100: +; BX is the first bad sector #, SECTORS is the number of bad sectors +; starting at BX. This needs to be converted to clusters. The start sector +; number may need to be rounded down to a cluster boundry, the end sector +; may need to be rounded up to a cluster boundry. Know BX >= STARTSECTOR + SUB BX,STARTSECTOR ; BX is now DATA area relative + MOV CX,BX + ADD CX,SECTORS + DEC CX ; CX is now the last bad sector # + MOV AX,BX + XOR DX,DX + xor bx,bx + mov bl, deviceParameters.DP_BPB.BPB_SectorsPerCluster + DIV bx + MOV BX,AX ; BX is rounded down and converted to + ; a cluster #. Where cluster 0 = + ; first cluster of data. First bad + ; Sector is in cluster BX. + MOV AX,CX + XOR DX,DX + push bx + xor bx,bx + mov bl, deviceParameters.DP_BPB.BPB_SectorsPerCluster + DIV bx + pop bx + MOV CX,AX ; CX is rounded up and converted to a + ; to a cluster #. Where cluster 0 = + ; first cluster of data. Last bad + ; Sector is in cluster CX. + SUB CX,BX + INC CX ; CX is number of clusters to mark bad + ADD BX,2 ; Bias start by correct amount since + ; first cluster of data is really + ; cluster 2. + xor ax,ax + MOV Al,deviceParameters.DP_BPB.BPB_SectorsPerCluster + MUL deviceParameters.DP_BPB.BPB_BytesPerSector + MOV BP,AX ; = Bytes/Cluster + +; Mark CX clusters bad starting at cluster BX +PACKIT: + CALL BadClus ;Put it in the allocation map + JZ BAD150 ;If already marked bad, don't count it + ADD WORD PTR BADSIZ,BP ;Add in number of bad bytes + JNB BAD150 + INC WORD PTR BADSIZ+2 +BAD150: + INC BX ;Next cluster + LOOP PACKIT ;Continue for # of clusters + JMP GETTRK + +; Inputs: BX = Cluster number +; Outputs: The given cluster is marked as invalid +; Zero flag is set if the cluster was already marked bad +; Registers modified: DX,SI +; No other registers affected +BadClus: + PUSH AX + PUSH BX + PUSH CX + PUSH DX + CMP fBigFat,-1 ; if (!fBigFat) { + JZ DoBig + MOV DX,0FF7h ; badval = 0xFF7; + MOV AX,0FFFh ; mask = 0xFFF; + MOV SI,BX ; p = FAT+clus+clus/2; + SHR SI,1 + ADD SI,BX + ADD SI, word ptr fatspace + TEST BX,1 ; if (clus&1) { + JZ DoSet + MOV CL,4 ; mask <<= 4; + SHL AX,CL + MOV CL,4 ; badval <<= 4; + SHL DX,CL ; } + JMP SHORT DoSet +DoBig: ; else { + MOV DX,0FFF7h ; badval = 0xFFF7; + MOV AX,0FFFFh ; mask = 0xFFFF; + MOV SI, word ptr fatSpace ; p = FAT + clus + clus; + ADD SI,BX + ADD SI,BX +DoSet: ; } + push es + mov es, word ptr fatSpace + 2 + MOV CX,es:[SI] ; op = *p & mask; + AND CX,AX + NOT AX ; *p &= ~mask; + AND es:[SI],AX + OR es:[SI],DX ; *p |= badval; + CMP DX,CX ; return op == badval; + pop es + POP DX + POP CX + POP BX + POP AX + return + +DRTFAT: + TEST SWITCHMAP,SWITCH_S ;If system requested, calculate size + JZ CLEARED + CMP BYTE PTR DBLFLG,0 ;Have we already calculated System space? + JNZ CLEARED ;Yes + INC BYTE PTR DBLFLG ;No -- set the flag + CALL GETSIZE ;Calculate the system size +CLEARED: + CALL WriteFileSystem + JNC FATWRT +LOUSE: + lea dx, msgDiskUnusable + call PrintString + JMP FRMTPROB + +LOUSEP: + POP DS + JMP LOUSE + +FATWRT: + + PUSH DS + MOV DL,DRIVE + INC DL + MOV AH,GET_DPB + INT 21H + CMP AL,-1 + JZ LOUSEP ;Something BAD has happened + MOV [BX.dpb_next_free],0 ; Reset allocation to start of disk + MOV [BX.dpb_free_cnt],-1 ; Force free space to be computed + POP DS + TEST SWITCHMAP,SWITCH_S ;System desired + JZ STATUS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +;reintroduce following section of code +; + CALL CHKSPACE ;Enough free space for system? + JNC SPACEOK ; Y: Go load system files + LEA DX, msgNoRoomDestDisk ; N: Print error message + CALL PrintString ; + MOV WORD PTR SYSSIZ+2,0 ;No system transfered + MOV WORD PTR SYSSIZ,0 ;No system transfered + JMP SHORT STATUS ; +SPACEOK: ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + mov al, drive + call AccessDisk ; note what is current logical drive + CALL WRITEDOS ;Write the BIOS & DOS + JNC SYSOK + lea dx, msgNotSystemDisk + call PrintString + MOV WORD PTR SYSSIZ+2,0 ;No system transfered + MOV WORD PTR SYSSIZ,0 ;No system transfered + JMP SHORT STATUS + +SYSOK: + lea dx, msgSystemTransfered + call PrintString +STATUS: + CALL CRLF + CALL VOLID + MOV AH,DISK_RESET + INT 21H + CALL DONE ;Final call to OEM module + JNC REPORTC + JMP FRMTPROB ;Report an error + +REPORTC: + CALL REPORT + + CALL MORE ;See if more disks to format + JMP SYSLOOP ;If we returned from MORE then continue + +;****************************************** +; Calculate the size in bytes of the system rounded up to sector and +; cluster boundries, Answer in SYSSIZ + +GetSize proc near + call GetBioSize + call GetDosSize + call GetCmdSize + return +GetSize endp + +GetBioSize proc near + MOV AX,WORD PTR bios.fileSizeInBytes + MOV DX,WORD PTR bios.fileSizeInBytes+2 + CALL AddToSystemSize + return +GetBioSize endp + +GetDosSize proc near + MOV AX,WORD PTR dos.fileSizeInBytes + MOV DX,WORD PTR dos.fileSizeInBytes+2 + CALL AddToSystemSize + return +GetDosSize endp + +GetCmdSize proc near + MOV AX,WORD PTR command.fileSizeInBytes + MOV DX,WORD PTR command.fileSizeInBytes+2 + call AddToSystemSize + return +GetCmdSize endp + +;Calculate the number of sectors used for the system +PUBLIC AddToSystemSize +AddToSystemSize proc near + push bx + DIV deviceParameters.DP_BPB.BPB_BytesPerSector + OR DX,DX + JZ FNDSIZ0 + INC AX ; Round up to next sector +FNDSIZ0: + PUSH AX + XOR DX,DX + xor bx,bx + mov bl, deviceParameters.DP_BPB.BPB_SectorsPerCluster + div bx + POP AX + OR DX,DX + JZ ONCLUS + SUB DX, bx + NEG DX + ADD AX,DX ; Round up sector count to cluster + ; boundry +ONCLUS: + MUL deviceParameters.DP_BPB.BPB_BytesPerSector + ADD WORD PTR SYSSIZ,AX + ADC WORD PTR SYSSIZ+2,DX + pop bx + return +AddToSystemSize endp + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +; reintroduce following section of code +;; Check free space to see if there is enough room to load the system +;; On Entry: DL = drive +;; On Exit: carry flag set if not enough room +;; no other registers are affected +CHKSPACE PROC NEAR + PUSH AX ;Save resisters + PUSH BX + PUSH CX + PUSH DX + + MOV AH,36H ;Get free space + INT 21h + +;;16 bit math okay here, no danger of overflow + MUL CX ;Get bytes/cluster + MOV CX,AX ; + MOV AX,WORD PTR SYSSIZ ;Get # of bytes for system + MOV DX,WORD PTR SYSSIZ+2 ; + DIV CX ;Get # of clusters for system + + CMP AX,BX ;Is there enough space? + JBE ENOUGHSPACE ; Y: Go clear carry + STC ; N: Set carry + JMP SHORT RESTOREREGS ; +; +ENOUGHSPACE: + CLC +; +RESTOREREGS: + POP DX ;Restore resisters + POP CX + POP BX + POP AX + RET +CHKSPACE ENDP +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + +MORE: CMP deviceParameters.DP_DeviceType, DEV_HARDDISK + je ExitProgram + CALL FormatAnother? ;Get yes or no response + JC ExitProgram + CALL CRLF + JMP CRLF + + +FEXIT: + mov ExitStatus,ExitFatal + +ExitProgram: + test validSavedDeviceParameters, 0ffH + jz DoNotRestoreDeviceParameters + mov savedDeviceParameters.DP_SpecialFunctions, TRACKLAYOUT_IS_GOOD + lea dx, savedDeviceParameters + call SetDeviceParameters +DoNotRestoreDeviceParameters: + mov al, ExitStatus + mov ah,exit + INT 21H + +; Prompt the user for a system diskette in the default drive +SYSPRM: + MOV AH,GET_DEFAULT_DRIVE ;Will find out the default drive + INT 21H ;Default now in AL + MOV BL,AL + INC BL ; A = 1 + ADD AL,41H ;Now in Ascii + MOV systemDriveLetter,AL ;Text now ok + CALL IsRemovable + JNC DoPrompt +; +; Media is non-removable. Switch sys disk to drive A. Check, though, to see +; if drive A is removable too. +; + MOV AL,"A" + MOV BYTE PTR [systemDriveLetter],AL + MOV [BiosFile],AL + MOV [DosFile],AL + MOV [CommandFile],AL + MOV BX,1 + CALL IsRemovable + JNC DoPrompt + lea dx, msgNoSystemFiles + call PrintString +fexitJ: + JMP FEXIT + +DoPrompt: + mov al, systemDriveLetter + sub al, 'A' + call AccessDisk + lea dx, ptr_msgInsertDosDisk + CALL std_printf ;Print first line + CALL USER_STRING ;Wait for a key + CALL CRLF + return + +TARGPRM: + mov al, drive + call AccessDisk + lea DX, ptr_msgInsertDisk + CALL std_printf ;Print first line + CALL USER_STRING ;Wait for a key + CALL CRLF + return + +; +; Determine if the drive indicated in BX is removable or not. +; +; Inputs: BX has drive (0=def, 1=A) +; Outputs: Carry clear +; Removable +; Carry set +; not removable +; Registers modified: none + +IsRemovable: + SaveReg + MOV AX,(IOCTL SHL 8) OR 8 ; Rem media check + INT 21H + JNC CheckRemove + MOV AX,(IOCTL SHL 8) + 9 ; Is it a NET drive? + INT 21h + JC NotRemove ; Yipe, say non-removable + TEST DX,1000h + JNZ NotRemove ; Is NET drive, say non-removeable + JMP IsRemove ; Is local, say removable +CheckRemove: + TEST AX,1 + JNZ NotRemove +IsRemove: + CLC + RestoreReg + return +NotRemove: + STC + RestoreReg + return + + +; DiSKPRoMpt: +; +; This routine prompts for the insertion of the correct diskette +; into the Target drive, UNLESS we are being re-entrantly invoked +; from LastChanceToSaveIt. If the target is a Hardisk we issue a +; warning message. +; +; INPUTS: +; deviceParameters.DP_DeviceType +; fLastChance +; +; OUTPUTS: +; Prompt string +; fLastChance := FALSE +; +; Registers affected: +; Flags +; +DSKPRM: + CMP fLastChance,TRUE + JE PrmptRet + + CMP deviceParameters.DP_DeviceType, DEV_HARDDISK + jne goprnit + lea dx, ptr_msgHardDiskWarning + call std_printf + CALL Yes? + jnc OkToFormatHardDisk + mov ExitStatus, ExitNo + jmp ExitProgram + +OkToFormatHardDisk: + CALL CRLF + CALL CRLF + return + +GOPRNIT: + mov al, drive + call AccessDisk + lea dx,ptr_msgInsertDisk + CALL std_printf + CALL USER_STRING ;Wait for any key + CALL CRLF + CALL CRLF + +PrmptRet: + mov fLastChance, FALSE + return + +;------------------------------------------------------------------------------- +; ScanOff +; Scan Off separator characters + +SCANOFF: + LODSB + CMP AL,' ' + JZ SCANOFF + CMP AL,9 + JZ SCANOFF + DEC SI + return + +;------------------------------------------------------------------------------- +; MakeNum +; Makenum converts digits from ASCII AlphaNumeric format to +; numeric values +; +; Entry: +; AL == Character to be converted +; DS:SI == Command line text +; +; Exit: +; AX == Value +; IF AX == 0 THEN Zero Flag == SET +; IF ERROR THEN Carry Flag == SET +; BX,CX,DX == Garbage +; DS:SI == Character after numeric value +; +; Procs used: +; ToDigit + +Public MakeNum,CalcLoop +MakeNum: + xor BX,BX ; Initialize running cnt + mov CX,10 ; and base of arithmetic +CalcLoop: ; UNTIL no more digits + call ToDigit ; AL := AL - '0' + jc BadNum ; IF error EXIT with carry set + + xchg ax,bx ; AX := running_cnt * 10 + + mul cx ; digit + add ax,bx + jc BadNum ; IF Overflow EXIT with carry + + xchg ax,bx ; BX := Running total + + LODSB ; Get Next Digit + cmp al,' ' ; IF ( ax = (' ',',',)) + je RetVal ; THEN return parsed value + cmp al,',' + je RetVal + + cmp al,'/' ; IF (ax = ('/','cr')) + je BURetVal ; THEN backup DS:SI and + cmp al,0dh ; return parsed value + je BURetVal + or al,al + jnz CalcLoop ; END until + +BURetVal: + dec SI +RetVal: + mov ax,bx + or ax,ax + return + +public Badnum +BadNum: + xor ax,ax + stc + return + +; ToDigit: +; Convert value in AX to decimal digit, range checking for valid values +; +public ToDigit +ToDigit: + sub al,'0' + jb NotDigit + cmp al,9 + ja NotDigit + clc + return + +NotDigit: + stc + return + +;------------------------------------------------------------------------------- + +ControlC_Handler: + mov ax, seg data + mov ds, ax + lea dx, msgInterrupt + call PrintString + mov ExitStatus, ExitCtrlC + jmp ExitProgram + +;------------------------------------------------------------------------------- +; SaveNum +; Save Number from switches into appropriate variable for later use +; Some switches have upper and lower bounds for legal values and +; these are checked for here +; +; ENTRY: +; cx == Switch just parsed +; ax == value parsed +; +; EXIT: +; Value stored in appropriate variable +; DS,DX == garbage +; + +public SaveNum +SaveNum: + mov dx, seg data + mov ds, dx + test word ptr data:Switchmap, CX ; IF already set THEN ignore + jnz done_ret + + test CX,SWITCH_T + jnz Store_T + + test CX,SWITCH_N + jz BadNum + +Store_N: + cmp AX,0 ; IF (value == 0) THEN ignore + je done_ret + + cmp AX, MAX_SECTORS_IN_TRACK ; IF (value > Max_sectors) + jbe short Store_N1 ; THEN issue error + jmp INVALID + +Store_N1: + mov word ptr data:NumSectors , AX + + jmp short done_ret + +Store_T: + mov word ptr data:TrackCnt, AX + +Done_ret: + ret +;------------------------------------------------------------------------------- + +crlf: + lea dx, msgCRLF + +PrintString: + mov printStringPointer, dx + lea dx, PrintStringPointer + +std_printf: + push dx + call printf + return + +;------------------------------------------------------------------------------- + +;***************************************** +; Process V switch if set + +VOLID: + TEST [SWITCHMAP],SWITCH_V + JNZ DOVOL +VRET: CLC + return + +DOVOL: + PUSH CX + PUSH SI + PUSH DI + PUSH ES + PUSH DS + POP ES +VOL_LOOP: + MOV AL,DRIVE + INC AL + MOV DS:BYTE PTR[VOLFCB+7],AL + lea dx, msgLabelPrompt + call PrintString + CALL USER_STRING + call crlf + call crlf + MOV CL,[INBUFF+1] + OR CL,CL + JZ VOLRET + XOR CH,CH + MOV SI,OFFSET INBUFF+2 + MOV DI,SI + ADD DI,CX + MOV CX,11 + MOV AL,' ' + REP STOSB + MOV CX,5 + MOV DI,OFFSET VOLNAM + REP MOVSW + MOVSB + MOV DX,OFFSET VOLFCB + MOV AH,FCB_CREATE + INT 21H + OR AL,AL + JZ GOOD_CREATE + lea dx, msgBadCharacters + call PrintString + JMP VOL_LOOP +GOOD_CREATE: + MOV DX,OFFSET VOLFCB + MOV AH,FCB_CLOSE + INT 21H + CALL CRLF +VOLRET: + POP ES + POP DI + POP SI + POP CX + return + +;**************************************** +;Copy IO.SYS, MSDOS.SYS and COMMAND.COM into data area. +; Carry set if problems + +READDOS: +; CALL TESTSYSDISK ; dcl 8/23/86 + call Get_BIOS ; dcl 8/23/86 + JNC RDFILS + return + +RDFILS: + MOV BYTE PTR [FILSTAT],0 + MOV BX,[bios.fileHandle] + MOV AX,[MSTART] + MOV DX,AX + ADD DX,[MSIZE] ; CX first bad para + MOV [bios.fileStartSegment],AX + MOV CX,[bios.fileSizeInParagraphs] + ADD AX,CX + CMP AX,DX + JBE GOTBIOS + MOV BYTE PTR [FILSTAT],00000001B ; Got part of BIOS + MOV SI,[MSIZE] + XOR DI,DI + CALL DISIX4 + push ds + MOV DS,[bios.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JC CLSALL + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR [bios.fileOffset],AX + MOV WORD PTR [bios.fileOffset+2],DX +FILESDONE: + CLC +CLSALL: + PUSHF +; CALL COMCLS ; dcl 8/23/86 + call FILE_CLS ; dcl 8/23/86 + POPF + return + +GOTBIOS: + MOV BYTE PTR [FILSTAT],00000010B ; Got all of BIOS + push es + LES SI,[bios.fileSizeInBytes] + MOV DI,ES + pop es + push ds + MOV DS,[bios.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JC CLSALL + + push ax ; dcl 8/23/86 + push dx ; dcl 8/23/86 + call File_Cls ; dcl 8/23/86 + call Get_DOS ; dcl 8/23/86 + pop dx ; dcl 8/23/86 + pop ax ; dcl 8/23/86 + + JNC Found_MSDOS ;mt 12/8/86 P894 + return ;mt 12/8/86 + +Found_MSDOS: ;mt 12/8/86 + + MOV BX,[dos.fileHandle] + MOV [dos.fileStartSegment],AX + CMP AX,DX ; No room left? + JZ CLSALL ; Yes + MOV CX,[dos.fileSizeInParagraphs] + ADD AX,CX + CMP AX,DX + JBE GOTDOS + OR BYTE PTR [FILSTAT],00000100B ; Got part of DOS + SUB DX,[dos.fileStartSegment] + MOV SI,DX + XOR DI,DI + CALL DISIX4 + push ds + MOV DS,[dos.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JC CLSALL + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR [dos.fileOffset],AX + MOV WORD PTR [dos.fileOffset+2],DX + JMP FILESDONE + +GOTDOS: + OR BYTE PTR [FILSTAT],00001000B ; Got all of DOS + LES SI,[dos.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[dos.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + +CLSALLJ: JNC NOTCLSALL ;PTM P894 mt 12/8/86 + jmp clsall ; + +NotCLSALL: + push ax ; dcl 8/23/86 + + push dx ; dcl 8/23/86 + call File_cls ; dcl 8/23/86 + call Get_COMMAND ; dcl 8/23/86 + pop dx ; dcl 8/23/86 + pop ax ; dcl 8/23/86 + + JNC Found_COMMAND ;mt 12/8/86 P894 + return ;mt 12/8/86 + +Found_COMMAND: ;mt 12/8/86 + MOV BX,[command.fileHandle] + MOV [command.fileStartSegment],AX + CMP AX,DX ; No room left? + JZ CLSALLJ ; Yes + MOV CX,[command.fileSizeInParagraphs] + ADD AX,CX + CMP AX,DX + JBE GOTCOM + OR BYTE PTR [FILSTAT],00010000B ; Got part of COMMAND + SUB DX,[command.fileStartSegment] + MOV SI,DX + XOR DI,DI + CALL DISIX4 + push ds + MOV DS,[command.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JC CLSALLJ + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR [command.fileOffset],AX + MOV WORD PTR [command.fileOffset+2],DX + JMP FILESDONE + +GOTCOM: + OR BYTE PTR [FILSTAT],00100000B ; Got all of COMMAND + LES SI,[command.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[command.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JMP CLSALL + +;************************************************** +;Write BIOS DOS COMMAND to the newly formatted disk. + +ASSUME DS:DATA +WRITEDOS: + MOV CX,BiosAttributes + MOV DX,OFFSET BiosFile + LES SI,[bios.fileSizeInBytes] + MOV DI,ES + CALL MAKEFIL + retc + + MOV [TempHandle],BX + TEST BYTE PTR FILSTAT,00000010B + JNZ GOTALLBIO + call Get_BIOS ; dcl 8/23/86 + jnc Got_WBIOS ;mt 12/8/86 P894 + ret + +Got_WBIOS: + + LES SI,[bios.fileOffset] + MOV DI,ES + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + MOV BP,OFFSET bios + CALL GOTTARG + retc + JMP SHORT BIOSDONE + +GOTALLBIO: + LES SI,[bios.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[bios.fileStartSegment] + assume ds:nothing + CALL WRITEFILE + pop ds + assume ds:data +BIOSDONE: + MOV BX,[TempHandle] + MOV CX,bios.fileTime + MOV DX,bios.fileDate + CALL CLOSETARG + MOV CX,DosAttributes + MOV DX,OFFSET DosFile + LES SI,[dos.fileSizeInBytes] + MOV DI,ES + CALL MAKEFIL + retc + +GOTNDOS: + MOV [TempHandle],BX + TEST BYTE PTR FILSTAT,00001000B + JNZ GOTALLDOS + call Get_DOS ; dcl 8/23/86 + jnc Got_WDOS ;mt 12/8/86 P894 + ret + +Got_WDOS: + MOV BP,OFFSET dos + TEST BYTE PTR FILSTAT,00000100B + JNZ PARTDOS + MOV WORD PTR [dos.fileOffset],0 + MOV WORD PTR [dos.fileOffset+2],0 + CALL GETSYS3 + retc + JMP SHORT DOSDONE + +PARTDOS: + LES SI,[dos.fileOffset] + MOV DI,ES + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + CALL GOTTARG + retc + JMP SHORT DOSDONE + +GOTALLDOS: + LES SI,[dos.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[dos.fileStartSegment] + assume ds:nothing + CALL WRITEFILE + pop ds + assume ds:data +DOSDONE: + MOV BX,[TempHandle] + MOV CX,dos.fileTime + MOV DX,dos.fileDate + CALL CLOSETARG + MOV CX,CommandAttributes + MOV DX,OFFSET CommandFile + LES SI,[command.fileSizeInBytes] + MOV DI,ES + CALL MAKEFIL + retc + + MOV [TempHandle],BX + TEST BYTE PTR FILSTAT,00100000B + JNZ GOTALLCOM + call Get_COMMAND ; dcl 8/23/86 + jnc Got_WCOM ;mt 12/8/86 P894 + ret + +Got_WCOM: + MOV BP,OFFSET command + TEST BYTE PTR FILSTAT,00010000B + JNZ PARTCOM + MOV WORD PTR [command.fileOffset],0 + MOV WORD PTR [command.fileOffset+2],0 + CALL GETSYS3 + retc + JMP SHORT COMDONE + +PARTCOM: + LES SI,[command.fileOffset] + MOV DI,ES + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + CALL GOTTARG + retc + JMP SHORT COMDONE + +GOTALLCOM: + LES SI,[command.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[command.fileStartSegment] + assume ds:nothing + CALL WRITEFILE + pop ds + assume ds:data +COMDONE: + MOV BX,[TempHandle] + MOV CX,command.fileTime + MOV DX,command.fileDate + CALL CLOSETARG +;**************************************************************** +; I don't see the need for the following code!! - RS 3.20 +; CMP BYTE PTR [FILSTAT],00101010B +; JZ NOREDOS +;RDFRST2: +; CALL READDOS ; Start back with BIOS +; JNC NOREDOS +; CALL SYSPRM ;Prompt for system disk +; JMP RDFRST2 ;Try again +;NOREDOS: +;**************************************************************** + CLC + return + +;********************************************* +; Create a file on target disk +; CX = attributes, DX points to name +; DI:SI is size file is to have +; +; There is a bug in DOS 2.00 and 2.01 having to do with writes +; from the end of memory. In order to circumvent it this routine +; must create files with the length in DI:SI +; +; On return BX is handle, carry set if problem + +MAKEFIL: + MOV BX,DX + PUSH WORD PTR [BX] + MOV AL,DriveLetter + MOV [BX],AL + MOV AH,CREAT + INT 21H + POP WORD PTR [BX] + MOV BX,AX + JC CheckMany + MOV CX,DI + MOV DX,SI + MOV AX,LSEEK SHL 8 + INT 21H ; Seek to eventual EOF + XOR CX,CX + MOV AH,WRITE + INT 21H ; Set size of file to position + XOR CX,CX + MOV DX,CX + MOV AX,LSEEK SHL 8 + INT 21H ; Seek back to start + return + +; +; Examine error code in AX to see if it is too-many-open-files. +; If it is, we abort right here. Otherwise we return. +; +CheckMany: + CMP AX,error_too_many_open_files + retnz + lea dx, msgTooManyFilesOpen + call PrintString + JMP FEXIT + +;********************************************* +; Close a file on the target disk +; CX/DX is time/date, BX is handle + +CLOSETARG: + MOV AX,(FILE_TIMES SHL 8) OR 1 + INT 21H + MOV AH,CLOSE + INT 21H + return + +;**************************************** +; Transfer system files +; BP points to data structure for file involved +; offset is set to current amount read in +; Start set to start of file in buffer +; TempHandle is handle to write to on target + +IOLOOP: + MOV AL,[systemDriveLetter] + CMP AL,[DriveLetter] + JNZ GOTTARG + MOV AH,DISK_RESET + INT 21H + CALL TARGPRM ;Get target disk + +GOTTARG: +ASSUME DS:DATA +;Enter here if some of file is already in buffer, IOCNT must be set +; to size already in buffer. + MOV BX,[TempHandle] + MOV SI,WORD PTR [IOCNT] + MOV DI,WORD PTR [IOCNT+2] + push ds + MOV DS,ds:[BP.fileStartSegment] + assume ds:nothing + CALL WRITEFILE ; Write next part + pop ds + assume ds:data + retc + + LES AX,ds:[BP.fileOffset] + CMP AX,WORD PTR ds:[BP.fileSizeInBytes] + JNZ GETSYS3 + MOV AX,ES + CMP AX,WORD PTR ds:[BP.fileSizeInBytes+2] + JNZ GETSYS3 + return ; Carry clear from CMP + +GETSYS3: +;Enter here if none of file is in buffer + MOV AH,DISK_RESET + INT 21H + MOV AX,[MSTART] ;Furthur IO done starting here + MOV ds:[BP.fileStartSegment],AX + MOV AL,[systemDriveLetter] + CMP AL,[DriveLetter] + JNZ TESTSYS +GSYS: + MOV AH,DISK_RESET + INT 21H + CALL SYSPRM ;Prompt for system disk +TESTSYS: +; CALL TESTSYSDISK ; dcl 8/23/86 + JC GSYS + MOV BX,word ptr DS:[BP.fileHandle] ; CS over ARR 2.30 + LES DX,dword ptr DS:[BP.fileOffset] ; CS over ARR 2.30 + PUSH DX + MOV CX,ES + MOV AX,LSEEK SHL 8 + INT 21H + POP DX + LES SI,dword ptr DS:[BP.fileSizeInBytes] ; CS over ARR 2.30 + MOV DI,ES + SUB SI,DX + SBB DI,CX ; DI:SI is #bytes to go + PUSH DI + PUSH SI + ADD SI,15 + ADC DI,0 + CALL DISID4 + MOV AX,SI + POP SI + POP DI + CMP AX,[MSIZE] + JBE GOTSIZ2 + MOV SI,[MSIZE] + XOR DI,DI + CALL DISIX4 +GOTSIZ2: + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + push ds + MOV DS,[MSTART] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JNC GETOFFS + CALL CLSALL + JMP GSYS +GETOFFS: + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR DS:[BP.fileOffset],AX ; CS over ARR 2.30 + MOV WORD PTR DS:[BP.fileOffset+2],DX ; CS over ARR 2.30 + CALL CLSALL + JMP IOLOOP + +;************************************************* +; Test to see if correct system disk. Open handles + +CRET12: + STC + return + +;TESTSYSDISK: ; dcl 8/23/86 +Get_BIOS: ; dcl 8/23/86 + MOV AX,OPEN SHL 8 + MOV DX,OFFSET BiosFile + INT 21H + JNC SETBIOS +; call CheckMany ; dcl 8/23/86 + jmp CheckMany ; dcl 8/23/86 + +SETBIOS: + MOV [Bios.fileHandle],AX + MOV BX,AX + CALL GETFSIZ + CMP [bios.fileSizeInParagraphs],0 + JZ SETBIOSSIZ + CMP [bios.fileSizeInParagraphs],AX + JZ SETBIOSSIZ +BIOSCLS: + MOV AH,CLOSE + MOV BX,[Bios.fileHandle] + INT 21H +; JMP CRET12 ; dcl 8/23/86 + ret + +SETBIOSSIZ: + MOV [bios.fileSizeInParagraphs],AX + MOV WORD PTR [bios.fileSizeInBytes],SI + MOV WORD PTR [bios.fileSizeInBytes+2],DI + MOV [bios.fileDate],DX + MOV [bios.fileTime],CX + clc + ret ; dcl 8/23/86 + +Get_DOS: ; dcl 8/23/86 + MOV AX,OPEN SHL 8 + MOV DX,OFFSET DosFile + INT 21H + JNC DOSOPNOK +; call CheckMany ; dcl 8/23/86 +; JMP BIOSCLS ; dcl 8/23/86 Checkmany no ret. + jmp CheckMany ; dcl 8/23/86 + +DOSOPNOK: + MOV [dos.fileHandle],AX + MOV BX,AX + CALL GETFSIZ + CMP [dos.fileSizeInParagraphs],0 + JZ SETDOSSIZ + CMP [dos.fileSizeInParagraphs],AX + JZ SETDOSSIZ + +DOSCLS: + MOV AH,CLOSE + MOV BX,[dos.fileHandle] + INT 21H +; JMP BIOSCLS ; dcl 8/23/86 + ret ; dcl 8/23/86 + +SETDOSSIZ: + MOV [dos.fileSizeInParagraphs],AX + MOV WORD PTR [dos.fileSizeInBytes],SI + MOV WORD PTR [dos.fileSizeInBytes+2],DI + MOV [dos.fileDate],DX + MOV [dos.fileTime],CX + clc + ret ; dcl 8/23/86 + +Get_COMMAND: + MOV AX,OPEN SHL 8 + MOV DX,OFFSET CommandFile + INT 21H + JNC GotComHand +; call CheckMany ; dcl 8/23/86 +; JMP DosCls ; dcl 8/23/86 + jmp Checkmany ; dcl 8/23/86 + +GotComHand: + MOV [command.fileHandle],AX + MOV BX,AX + CALL GETFSIZ + CMP [command.fileSizeInParagraphs],0 + JZ SETCOMSIZ + CMP [command.fileSizeInParagraphs],AX + JZ SETCOMSIZ +COMCLS: + MOV AH,CLOSE + MOV BX,[command.fileHandle] + INT 21H +; JMP DOSCLS ; dcl 8/23/86 + ret ; dcl 8/23/86 + +SETCOMSIZ: + MOV [command.fileSizeInParagraphs],AX + MOV WORD PTR [command.fileSizeInBytes],SI + MOV WORD PTR [command.fileSizeInBytes+2],DI + MOV [command.fileDate],DX + MOV [command.fileTime],CX + CLC + return + +FILE_CLS: ; dcl 8/23/86 + MOV AH,CLOSE ; dcl 8/23/86 + INT 21H ; dcl 8/23/86 + ret ; dcl 8/23/86 + +;******************************************* +; Handle in BX, return file size in para in AX +; File size in bytes DI:SI, file date in DX, file +; time in CX. + +GETFSIZ: + MOV AX,(LSEEK SHL 8) OR 2 + XOR CX,CX + MOV DX,CX + INT 21H + MOV SI,AX + MOV DI,DX + ADD AX,15 ; Para round up + ADC DX,0 + AND DX,0FH ; If the file is larger than this it + ; is bigger than the 8086 address + ; space! + MOV CL,12 + SHL DX,CL + MOV CL,4 + SHR AX,CL + OR AX,DX + PUSH AX + MOV AX,LSEEK SHL 8 + XOR CX,CX + MOV DX,CX + INT 21H + MOV AX,FILE_TIMES SHL 8 + INT 21H + POP AX + return + +;******************************************** +; Read/Write file +; DS:0 is Xaddr +; DI:SI is byte count to I/O +; BX is handle +; Carry set if screw up +; +; I/O SI bytes +; I/O 64K - 1 bytes DI times +; I/O DI bytes + + +READFILE: +; Must preserve AX,DX + PUSH AX + PUSH DX + PUSH BP + MOV BP,READ SHL 8 + CALL FILIO + POP BP + POP DX + POP AX + return + +WRITEFILE: + PUSH BP + MOV BP,WRITE SHL 8 + CALL FILIO + POP BP + return + +FILIO: + XOR DX,DX + MOV CX,SI + JCXZ K64IO + MOV AX,BP + INT 21H + retc + ADD DX,AX + CMP AX,CX ; If not =, AX= 4086) +; +Phase1Initialisation proc near + +; Get device parameters + lea dx, deviceParameters + mov deviceParameters.DP_SpecialFunctions, 0 + call GetDeviceParameters + jnc GotDeviceParameters + lea dx, ptr_msgFormatNotSupported + call std_printf + jmp fexit +GotDeviceParameters: + +; Save the device parameters for when we exit + lea si, deviceParameters + lea di, savedDeviceParameters + mov cx, size a_DeviceParameters + push ds + pop es + rep movsb + +; Ensure that there is a valid number of sectors in the track table + mov savedDeviceParameters.DP_TrackTableEntries, 0 + mov validSavedDeviceParameters, 1 + +; Initialise this to zero to know if CheckSwitches defined the track layout + mov deviceParameters.DP_TrackTableEntries, 0 + +; Detect whether "set media type" is supported +; test DeviceParameters.DeviceAttributes, SetMediaType +; jnz SetMTsupp + +SetMTsupp: + +; Check switches against parameters and use switches to modify device parameters + call CheckSwitches + retc + + cmp deviceParameters.DP_TrackTableEntries, 0 + jne TrackLayoutSet ; There is a good track layout + +; Store sector table info + mov cx, deviceParameters.DP_BPB.BPB_SectorsPerTrack + mov deviceParameters.DP_TrackTableEntries, cx + mov ax, 1 + mov bx, deviceParameters.DP_BPB.BPB_bytesPerSector + lea di, deviceParameters.DP_SectorTable +LoadSectorTable: + stosw + xchg ax, bx + stosw + xchg ax, bx + inc ax + loop LoadSectorTable +TrackLayoutSet: + +; +; directorySector = malloc( Bytes Per Sector ) +; + mov bx, deviceParameters.DP_BPB.BPB_BytesPerSector + add bx, 0fH + shr bx, 1 + shr bx, 1 + shr bx, 1 + shr bx, 1 + mov ah, Alloc + int 21H + retc + mov word ptr directorySector+2, ax + xor ax,ax + mov word ptr directorySector, ax + +; +; fatSpace = malloc( Bytes Per Sector * Sectors Per FAT ) +; + mov ax, deviceParameters.DP_BPB.BPB_BytesPerSector + mul deviceParameters.DP_BPB.BPB_SectorsPerFAT + add ax, 0fH + shr ax, 1 + shr ax, 1 + shr ax, 1 + shr ax, 1 + mov bx, ax + mov ah, Alloc + int 21H + retc + mov word ptr fatSpace+2, ax + xor ax, ax + mov word ptr fatSpace, ax + + call SetStartSector + call SetfBigFat + + clc + return + +Phase1Initialisation endp + +;------------------------------------------------------------------------------- + +SetStartSector proc near + +; startSector = number of reserved sectors +; + number of FAT Sectors ( Number of FATS * Sectors Per FAT ) +; + number of directory sectors ( 32* Root Entries / bytes Per Sector ) +; ( above is rounded up ) + +; Calculate the number of directory sectors + mov ax, deviceParameters.DP_BPB.BPB_RootEntries + mov bx, size dir_entry + mul bx + add ax, deviceParameters.DP_BPB.BPB_bytesPerSector + dec ax + xor dx,dx + div deviceParameters.DP_BPB.BPB_bytesPerSector + mov sectorsInRootDirectory,ax + mov startSector, ax + +; Calculate the number of FAT sectors + mov ax, deviceParameters.DP_BPB.BPB_SectorsPerFAT + mul deviceParameters.DP_BPB.BPB_numberOfFATs +; Add in the number of boot sectors + add ax, deviceParameters.DP_BPB.BPB_ReservedSectors + add startSector, ax + + return + +SetStartSector endp + +;------------------------------------------------------------------------------- + +SetfBigFat proc near +; +; fBigFat = ( ( (Total Sectors - Start Sector) / Sectors Per Cluster) >= 4086 ) +; + mov ax, deviceParameters.DP_BPB.BPB_TotalSectors + + +;************************* Fix for PTM PCDOS P51 + + ; + ; Old code + ; + ;cmp ax,20740 + ;jbe SmallFAT + ;mov fBigFat, TRUE + + ; + ; New Code + ; + + sub ax,startSector ;Get sectors in data area + xor dx,dx + xor bx,bx + mov bl,deviceParameters.DP_BPB.BPB_sectorsPerCluster + div bx ;Get total clusters + cmp ax,BIG_FAT_THRESHOLD ;Is clusters < 4086? + jb SmallFAT ;12 bit FAT if so + mov fBigFAT,TRUE ;16 bit FAT if >=4096 + +;************************* END of fix for PTM PCDOS P51 + +SmallFAT: + + return + +SetfBigFat endp + +;------------------------------------------------------------------------------- +; +; Phase2Initialisation: +; Use device parameters to build information that will be +; required for each format +; +; Algorithm: +; Calculate first head/cylinder to format +; Calculate number of tracks to format +; Calculate the total bytes on the disk and save for later printout +; First initialise the directory buffer +; +Phase2Initialisation proc near + +; Calculate first track/head to format (round up - kludge) + mov ax, deviceParameters.DP_BPB.BPB_HiddenSectors + mov dx, deviceParameters.DP_BPB.BPB_HiddenSectors + 2 + add ax, deviceParameters.DP_BPB.BPB_SectorsPerTrack + adc dx, 0 + dec ax + sbb dx, 0 + div deviceParameters.DP_BPB.BPB_SectorsPerTrack + xor dx,dx + div deviceParameters.DP_BPB.BPB_Heads + mov firstCylinder, ax + mov firstHead, dx + +; Calculate the total number of tracks to be formatted (round down - kludge) + mov ax, deviceParameters.DP_BPB.BPB_TotalSectors + xor dx,dx +; if (TotalSectors == 0) then use BigTotalSectors + or ax,ax + jnz NotBigTotalSectors + mov ax, deviceParameters.DP_BPB.BPB_BigTotalSectors + mov dx, deviceParameters.DP_BPB.BPB_BigTotalSectors + 2 + +NotBigTotalSectors: + div deviceParameters.DP_BPB.BPB_SectorsPerTrack + mov tracksPerDisk, ax + +; Initialise the directory buffer +; Clear out the Directory Sector before any information is inserted. + mov cx, deviceParameters.DP_BPB.BPB_BytesPerSector + les di, directorySector + xor ax,ax + rep stosb + + mov ax, deviceParameters.DP_BPB.BPB_BytesPerSector + xor dx, dx + mov bx, size dir_entry + div bx + mov cx, ax + + les bx, directorySector +; If Old_Dir = TRUE then put the first letter of each directory entry must be 0E5H + xor al, al + cmp old_Dir, TRUE + jne StickE5 + mov al, 0e5H +StickE5: + mov es:[bx], al + add bx, size dir_entry + loop stickE5 + +; +; fDskSiz = (Total Sectors - Start Sector) * Bytes Per Sector +; + mov ax, deviceParameters.DP_BPB.BPB_TotalSectors + sub ax, startSector + mul deviceParameters.DP_BPB.BPB_BytesPerSector + mov word ptr fDskSiz, ax + mov word ptr fDskSiz+2, dx + + return + +Phase2Initialisation endp + +;------------------------------------------------------------------------------- +; +; SetDeviceParameters: +; Set the device parameters +; +; Input: +; drive +; dx - pointer to device parameters +; +SetDeviceParameters proc near + + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + mov bl, drive + inc bl + mov cx, (RAWIO shl 8) or SET_DEVICE_PARAMETERS + int 21H + return + +SetDeviceParameters endp + +;------------------------------------------------------------------------------- +; +; GetDeviceParameters: +; Get the device parameters +; +; Input: +; drive +; dx - pointer to device parameters +; +GetDeviceParameters proc near + + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + mov bl, drive + inc bl + mov cx, (RAWIO shl 8) or GET_DEVICE_PARAMETERS + int 21H + return + +GetDeviceParameters endp + +;------------------------------------------------------------------------------- +; +; DiskFormat: +; Format the tracks on the disk +; Since we do our SetDeviceParameters here, we also need to +; detect the legality of /N /T if present and abort with errors +; if not. +; This routine stops as soon as it encounters a bad track +; Then BadSector is called to report the bad track, and it continues +; the format +; +; Algorithm: +; Initialise in memory FAT +; current track = first +; while not done +; if format track fails +; DiskFormatErrors = true +; return +; next track + +DiskFormat proc near + + +; +; Initialise fatSpace +; + push es + les di, fatSpace + mov ax, deviceParameters.DP_BPB.BPB_SectorsPerFAT + mul deviceParameters.DP_BPB.BPB_bytesPerSector + mov cx, ax + xor ax,ax + rep stosb + + mov di, word ptr fatSpace + mov al, deviceParameters.DP_BPB.BPB_MediaDescriptor + mov ah, 0ffH + stosw + mov ax, 00ffH + test fBigFat, TRUE + jz NotBig + mov ax, 0ffffH +NotBig: stosw + pop es + +; don't bother to do the formatting if /c was given + test switchmap, SWITCH_C + jz Keep_Going + jmp FormatDone ;FormatDone is to far away + +Keep_Going: +foofoo = INSTALL_FAKE_BPB or TRACKLAYOUT_IS_GOOD + mov deviceParameters.DP_SpecialFunctions, foofoo + lea dx, deviceParameters + + call SetDeviceParameters + + test switchmap, SWITCH_H ;Suppress prompt? + jnz No_Prompt + + call DSKPRM ; prompt user for disk + +No_Prompt: + test switchmap,switch_8 ; DCL 5/12/86 avoid Naples AH=18h + jnz stdBpB ; lackof support for 8 sectors/track + + ; DCL 5/12/86 + ; Always do the STATUS_FOR_FORMAT test, as we don't know if the machine + ; has this support. For 3.2 /N: & /T: were not documented & therefore + ; not fully supported thru the ROM of Aquarius & Naples & Royal Palm + + ;test SwitchMap, SWITCH_N or SWITCH_T ; IF ( /N or /T ) ;; DCL 5/12/86 + ;jz StdBPB + ; THEN check if + ; supported + mov formatPacket.FP_SpecialFunctions, STATUS_FOR_FORMAT + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + mov bl, drive + inc bl + mov cx, (RAWIO shl 8) or FORMAT_TRACK + lea dx, formatPacket + int 21H + ; switch ( FormatStatusCall) + + ;cmp FormatPacket.FP_SpecialFunctions, Format_No_ROM_Support + ;jb NTSupported ; 0 returned from IO.SYS + ;ja IllegalComb ; 2 returned - ROM Support + ; Illegal Combination! + cmp FormatPacket.FP_SpecialFunctions,0 + je NTSupported + lea dx, msgInvalidParameter + cmp FormatPacket.FP_SpecialFunctions,2 + je Abort_Prog + lea dx, msgNotReady + cmp FormatPacket.FP_SpecialFunctions,3 + je Abort_Prog + + ; DCL No ROM support is okay + ; except for /N: & /T: + test SwitchMap, SWITCH_N or SWITCH_T ; DCL 5/12/86 + jz StdBPB + lea dx, msgParametersNotSupported ; CASE: NOT SUPPORTED + +Abort_Prog: + Call PrintString + jmp Fexit +; +; We have the support to carry out the FORMAT +; +NTSupported: +StdBPB: + ;call DSKPRM ; prompt user for disk ;; DCL 5/12/86 + mov FormatPacket.FP_SpecialFunctions, 0 + mov ax, firstHead + mov formatPacket.FP_Head, ax + mov ax, firstCylinder + mov formatPacket.FP_Cylinder, ax + mov cx, tracksPerDisk + dec cx + mov tracksLeft, cx +FormatLoop: + call DisplayCurrentTrack + call FormatTrack + jc FailDiskFormat + call NextTrack + jnc FormatLoop + +; All done +FormatDone: + mov formatError, 0 + clc + return + +FailDiskFormat: + call CheckError + retc + call LastChanceToSaveIt + jc FormatReallyFailed + + call SetStartSector + call SetfBigFat + push ax + call Phase2Initialisation + clc + pop ax +; jc FormatReallyFailed + jmp DiskFormat + +FormatReallyFailed: + mov formatError, 1 + clc + return + +DiskFormat endp + + +;------------------------------------------------------------------------------- +; +; BadSector: +; Reports the bad sectors. +; Reports the track where DiskFormat stopped. +; From then on it formats until it reaches a bad track, or end, +; and reports that. +; +; Output: +; Carry: set --> fatal error +; if Carry not set +; ax - The number of consecutive bad sectors encountered +; ax == 0 --> no more bad sectors +; bx - The logical sector number of the first bad sector +; +; Algorithm: +; if DiskFormatErrors +; DiskFormatErrors = false +; return current track +; else +; next track +; while not done +; if format track fails +; return current track +; next track +; return 0 + +BadSector proc near + + +; don't bother to do the formatting if /c was given + test switchmap, SWITCH_C + jnz NoMoreTracks + + test formatError, 0ffH + jz ContinueFormat + mov formatError, 0 + jmp ReportBadTrack + +ContinueFormat: + call NextTrack + jc NoMoreTracks + + call DisplayCurrentTrack + call FormatTrack + jnc ContinueFormat + call CheckError + retc + +ReportBadTrack: + call CurrentLogicalSector + mov ax, deviceParameters.DP_BPB.BPB_SectorsPerTrack + clc + return + +NoMoreTracks: + lea dx, msgFormatComplete + call PrintString + mov ax, 0 + clc + return + +BadSector endp + + +;------------------------------------------------------------------------------- +; FormatTrack: +; format the current track +; +; Input: +; formatPacket +; +; Output: +; Carry: set if format failed +; +FormatTrack proc near + + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + mov bl, drive + inc bl + mov cx, (RAWIO shl 8) or FORMAT_TRACK + lea dx, formatPacket + int 21H + retnc + + mov ah, 59H + xor bx,bx + int 21H + stc + return + +FormatTrack endp + +;------------------------------------------------------------------------------- + +data segment + +ptr_msgCurrentTrack dw offset msgCurrentTrack +currentHead dw 0 +currentCylinder dw 0 + +data ends + +DisplayCurrentTrack proc near + + mov ax, formatPacket.FP_Cylinder + mov currentCylinder, ax + mov ax, formatPacket.FP_Head + mov currentHead, ax + lea dx, ptr_msgCurrentTrack + call std_printf + return + +DisplayCurrentTrack endp + +;------------------------------------------------------------------------------- +; NextTrack: +; Advance to the next track for formatting +; +; Input: +; formatPacket.FP_Head +; formatPacket.FP_Cylinder +; deviceParameters.DP_BPB.BPB_Heads +; tracksLeft +; +; Output: +; Carry: set --> all done +; formatPacket.FP_Head +; formatPacket.FP_cyliner +; tracksLeft +; +; Algorithm: +; if tracksLeft +; tracksLeft-- +; if ++head > highest head +; head = 0 +; cylinder++ +; +NextTrack proc near + + cmp tracksLeft, 0 + je ThatsAllFolks + dec tracksLeft + +; Bump the head + inc formatPacket.FP_Head + mov ax, formatPacket.FP_Head + cmp ax, deviceParameters.DP_BPB.BPB_Heads + jb ExitNextTrack + +; We've done all heads on this cylinder so move on to next +; (start on head 0 of the next cylinder) + mov formatPacket.FP_Head, 0 + inc formatPacket.FP_Cylinder + +ExitNextTrack: + clc + return + +ThatsAllFolks: +; Oh wow, we're all done + stc + return + +NextTrack endp + +;------------------------------------------------------------------------------- +; CheckError: +; Input: +; ax - extended error code +; Ouput: +; carry set if error is fatal +; Message printed if Not Ready or Write Protect +; +CheckError proc near + cmp ax, error_write_protect + je WriteProtectError + cmp ax, error_not_ready + je NotReadyError + cmp currentCylinder, 0 + jne CheckRealErrors + cmp currentHead, 0 + je BadTrackZero + +CheckRealErrors: + cmp ax, error_CRC + je JustABadTrack + cmp ax, error_sector_not_found + je JustABadTrack + cmp ax, error_write_fault + je JustABadTrack + cmp ax, error_read_fault + je JustABadTrack + cmp ax, error_gen_failure + je JustABadTrack + + stc + ret + +JustABadTrack: + clc + ret + +WriteProtectError: + lea dx, msgWriteProtected + call PrintString + stc + ret + +NotReadyError: + lea dx, msgNotReady + call PrintString + stc + ret + +BadTrackZero: + lea dx, msgDiskUnusable + call PrintString + stc + ret + +CheckError endp + +;------------------------------------------------------------------------------- +; WriteFileSystem: +; Write the boot sector and FATs out to disk +; Clear the directory sectors to zero +; +WriteFileSystem proc near + + + call WriteBootSector + retc + +; Write out each of the FATs + xor cx, cx + mov cl, deviceParameters.DP_BPB.BPB_numberOfFATs + mov dx, deviceParameters.DP_BPB.BPB_ReservedSectors +WriteFATloop: + push cx + push dx + mov al, drive + mov cx, deviceParameters.DP_BPB.BPB_SectorsPerFAT + push ds + lds bx, fatSpace + int 26H + pop ax + pop ds + jc CanNotWriteFAT + + pop dx + add dx, deviceParameters.DP_BPB.BPB_SectorsPerFAT + pop cx + loop WriteFATLoop + +; Clear the directory + +; Now write the initialised directory sectors out to disk + mov ax, deviceParameters.DP_BPB.BPB_SectorsPerFAT + xor dx,dx + mul deviceParameters.DP_BPB.BPB_NumberOfFATs + mov dx, deviceParameters.DP_BPB.BPB_ReservedSectors + add dx, ax + mov cx, sectorsInRootDirectory +WriteDIRloop: + push cx + push dx + mov al, drive + mov cx, 1 + push ds + lds bx, directorySector + int 26H + pop ax + pop ds + jc CanNotWriteDirectory + + pop dx + add dx, 1 + pop cx + loop WriteDIRLoop + + +; Ok, we can tell the device driver that we are finished formatting + mov savedDeviceParameters.DP_TrackTableEntries, 0 + mov savedDeviceParameters.DP_SpecialFunctions, TRACKLAYOUT_IS_GOOD + lea dx, savedDeviceParameters + call SetDeviceParameters + + MOV AH,DISK_RESET ; Flush any directories in + INT 21H ; buffers + + return + +CanNotWriteFAT: + lea dx, msgFATwriteError + jmp PrintErrorAbort + +CanNotWriteDirectory: + lea dx, msgDirectorywriteError + jmp PrintErrorAbort + +WriteFileSystem endp + +;------------------------------------------------------------------------------- +; Done: +; format is done... so clean up the disk! +; +Done proc near + + + call OemDone + return + +Done endp + +;------------------------------------------------------------------------------- +; CurrentLogicalSector: +; Get the current logical sector number +; +; Input: +; current track = tracksPerDisk - tracksLeft +; SectorsPerTrack +; +; Output: +; BX = logical sector number of the first sector in the track we +; just tried to format +; +CurrentLogicalSector proc near + mov ax, tracksPerDisk + sub ax, tracksLeft + dec ax + mul deviceParameters.DP_BPB.BPB_SectorsPerTrack + mov bx, ax + return + +CurrentLogicalSector endp + +;------------------------------------------------------------------------------- +; PrintErrorAbort: +; Print an error message and abort +; +; Input: +; dx - Pointer to error message string +; +PrintErrorAbort proc near + + push dx + call crlf + pop dx + call PrintString + + jmp fexit + +PrintErrorAbort endp + +code ends + + END START diff --git a/SRC/BUGFIX/CMD/FORMAT/MESSAGES.ASM b/SRC/BUGFIX/CMD/FORMAT/MESSAGES.ASM new file mode 100644 index 0000000..b8b9f0d --- /dev/null +++ b/SRC/BUGFIX/CMD/FORMAT/MESSAGES.ASM @@ -0,0 +1,68 @@ +; SCCSID = @(#)messages.asm 1.10 85/08/13 +TITLE FORMAT Messages + +data segment public 'DATA' + + public Yes_Byte + public No_Byte + public msgCRLF + public msgCurrentTrack + public msgSystemTransfered + public msgFormatComplete + public msgInterrupt + public msgInsertDisk + public msgHardDiskWarning + public msgFormatAnother? + public msgInsertDosDisk + public msgReInsertDisk + public msgLabelPrompt + public msgTotalDiskSpace + public msgSystemSpace + public msgBadSpace + public msgDataSpace + public msgFormatNotSupported + public msgInvalidDeviceParameters + public msgErrorInIOCTL + public msgNotBlockDevice + public msgFATwriteError + public msgDirectoryWriteError + public msgAssignedDrive + public msgNeedDrive + public msgBadDosVersion + public msgNoSystemFiles + public msgTooManyFilesOpen + public msgNetDrive + public msgBadCharacters + public msgBadDrive + public msgInvalidParameter + public msgParametersNotSupported + public msgFormatFailure + public msgNotSystemDisk +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +; reintroduce following public for fix + public msgNoRoomDestDisk +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + public msgDiskUnusable + public msgOutOfMemory + public msgWriteProtected + public msgNotReady + public msgBootWriteError + public msgDirectoryReadError + public msgBadVolumeId + public msgWhatIsVolumeId? + public msgIncompatibleParameters + public msgIncompatibleParametersForHardDisk + public msgBadPartitionTable + public msgParametersNotSupportedByDrive + public msgPartitionTableReadError + public msgPartitionTableWriteError + +CR equ 13 +LF equ 10 + +; Oem dependent messages + + include messages.inc + +data ends + END diff --git a/SRC/BUGFIX/CMD/FORMAT/MESSAGES.INC b/SRC/BUGFIX/CMD/FORMAT/MESSAGES.INC new file mode 100644 index 0000000..bf22638 --- /dev/null +++ b/SRC/BUGFIX/CMD/FORMAT/MESSAGES.INC @@ -0,0 +1,139 @@ +; SCCSID = @(#)messages.inc 1.6 85/08/02 + +DEBUG EQU 0 ; for Boot sector installation check + +IF DEBUG + public msgFormatBroken +ENDIF + +; THE FOLLOWING ONE BYTE CHARACTERS ARE THE PROMPT ANSWERS. +; THEY MUST BE LOWER CASE, AND THE UPPER TO LOWER, OR LOWER +; TO LOWER CONVERSION MUST BE DOABLE BY "OR AL,20h". +; Yes/No Answers + +Yes_Byte db "y" +No_Byte db "n" + +msgCRLF db CR, LF, 0 + +; Status messages + +msgCurrentTrack db "Head: %3d Cylinder: %4d", CR, 0 + +msgSystemTransfered db "System transferred",CR,LF,0 + +msgInterrupt db 13,10, 10, 0 + +; Note: This message must be long enough to wipe out message msgCurrentTrack +msgFormatComplete db "Format complete ",CR,LF,0 + +; Prompts + +msgInsertDisk db "Insert new diskette for drive %c:",CR,LF + db "and strike ENTER when ready",0 + +msgHardDiskWarning db CR,LF + db "WARNING, ALL DATA ON NON-REMOVABLE DISK",CR,LF + db "DRIVE %c: WILL BE LOST!",CR,LF + db "Proceed with Format (Y/N)?",0 + +msgFormatAnother? db "Format another (Y/N)?",0 + +msgInsertDosDisk db "Insert DOS disk in drive %c:", CR, LF + db "and strike ENTER when ready", CR, LF, 0 + +msgReInsertDisk db "Re-insert diskette for drive %c:",0 + +msgLabelPrompt db "Volume label (11 characters, ENTER for none)? ",0 + +; Disk usage messages + +msgTotalDiskSpace db "%l10d bytes total disk space", CR, LF, 0 + +msgSystemSpace db "%l10d bytes used by system", CR, LF, 0 + +msgBadSpace db "%l10d bytes in bad sectors", CR, LF, 0 + +msgDataSpace db "%l10d bytes available on disk",CR,LF,0 + +; Error messages + +msgFormatNotSupported db "Format not supported on drive %c:", CR,LF,0 + +msgInvalidDeviceParameters db "Invalid device parameters from device driver" + db CR, LF, 0 + +msgErrorInIOCTL db "Error in IOCTL call", CR, LF, 0 + +msgNotBlockDevice db "Not a block device", CR, LF, 0 + +msgFATwriteError db "Error writing FAT", CR, LF, 0 + +msgDirectoryWriteError db "Error writing directory", CR, LF, 0 + +msgAssignedDrive db "Cannot format an ASSIGNed or SUBSTed drive. ", CR, LF, 0 + +msgNeedDrive db "Drive letter must be specified",CR,LF,0 + +msgBadDosVersion db "Incorrect DOS version",CR,LF,"$" + +msgNoSystemFiles db "Cannot find System Files",CR,LF,0 + +msgTooManyFilesOpen db "Too many open files",CR,LF,0 + +msgNetDrive db "Cannot FORMAT a Network drive", CR, LF, 0 + +msgBadCharacters db "Invalid characters in volume label", CR, LF, 0 + +msgBadDrive db "Invalid drive specification", CR, LF, 0 + +msgInvalidParameter db "Invalid parameter", CR, LF, 0 + +msgParametersNotSupported db "Parameters not supported",CR,LF,0 + +; Note: This message must be long enough to wipe out message msgCurrentTrack +msgFormatFailure db "Format failure ",CR,LF,0 + +msgNotSystemDisk db "Disk unsuitable for system disk", CR, LF, 0 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +; reintroduce following message for fix +msgNoRoomDestDisk db "No room for system on destination disk", CR, LF, 0 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + +msgDiskUnusable db "Invalid media or Track 0 bad - disk unusable", CR, LF, 0 + +msgOutOfMemory db "Insufficient memory for system transfer", CR, LF, 0 + +; Note: This message must be long enough to wipe out message msgCurrentTrack +msgWriteProtected db "Attempted write-protect violation", CR, LF, 0 + +; Note: This message must be long enough to wipe out message msgCurrentTrack +msgNotReady db "Drive not ready ", CR, LF, 0 + + +msgBootWriteError db "Unable to write BOOT", CR, LF, 0 + +msgDirectoryReadError db "Error reading directory", CR, LF, 0 + +msgBadVolumeId db "Invalid Volume ID", CR, LF, 0 + +msgWhatIsVolumeId? db "Enter current Volume Label for drive %c: ", 0 + +msgIncompatibleParameters db "Parameters not compatible", CR,LF,0 + +msgIncompatibleParametersForHardDisk db "Parameters not compatible" + db " with fixed disk", CR,LF,0 + +msgBadPartitionTable db "Bad Partition Table", CR, LF, 0 + +msgParametersNotSupportedByDrive db "Parameters not Supported by Drive", CR, LF, 0 + +msgPartitionTableReadError db "Error reading partition table", CR, LF, 0 + +msgPartitionTableWriteError db "Error writing partition table", CR, LF, 0 + +IF DEBUG +msgFormatBroken db "Format Broken", CR, LF, 0 +ENDIF + diff --git a/SRC/BUGFIX/DOS/HANDLE.OBJ b/SRC/BUGFIX/DOS/HANDLE.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..4ce060685d5621bd673797f0ae64b370996c7f1b GIT binary patch literal 1642 zcmYjRZERCj7=F)f&+XURty|ZD$`+triG+X~RwLU&*WR+RcHMe!!xjR~vR$&uHpuNQ z^CL!<)`YH2Z6u=6Vv6!d5_B3OL;{Sg!^DptN<@&55HRuMsv+(N2tTgp+?HU{p8KA2 z-t)ZAbKdto2hG6t`UV0a{?ZXIfYBcb@Yo+25JZbU`UXV781RWcb08vYi$-FD#*j}C zu^{@QA{Ko;A^x9tO|TBYY)0#d)k{DO$XT^8Mvm&P#ez6$?O_-OeM_tf0Fw#*@ty-% z4QY&K(2N?^Sbu&eSp6wkmZp`#Ko78iu+KL>4m5l`DvgeVg<3o0gd#y5KP>XmXgn10 z#{@71M-!90ECah;m>88MFo_e1q!1Lr6iZ5Sye|N+me&FX_zgf_?{3R>1LRo%F5QI` zD>uh8o;#iU6;q+)f(&Xvc#x@B+{j$9HzG3w*}M}R`?m)Ng7Utp-qGptNeP}R+W@yw zK<*OOMoKI>=tkBv`MN4k|Kz@;1Rm0$Ay?rSwK+v&U=tisDlqDzTK`r-Yu3GfE^ z9iY4BQujsP0k(%ORGYQz2E2*-P!Ua!L_AYksmHcwj8*1!lzD^B{0AC{UYkD>4)=)= zDaQf#=m^GB6Y4GXcE?}o2d<>ytP8vadLubUJ8Ze8L}%8XL%$E6x+y(Ux38{No|X(wfsd7+wGKTU0~p4v*-jhITb5itx@ z64aiq+6StiSLjmOjf|N?)w74)2ydd5yp0rHiuOfP86DdTAC@Npzk>+FtjMZM++7~S z!IYH{a}r`r>UFZhkd?o=9M3#?2fDU`g1a_B>c*MX&hIuR&#NDIGV&u~cc|7w)`e8_ zeJ&TabGcak0}388Qv45^N-erNXN8EtnSPyIX15zTJ8Ay-G1B0)bzdv50jyD4T$Z3@ zWAz;iUX9!^H!I-_8aErpu=UrHT?cEV^=^6|(i9@}5aIyszEuo?P_O3}pRKi4)2DeW znDlOzBruel0DGv9+`{hI-FBE-_8T=^SH`CEo2U0i`zVmw9}gsCX-t6)<<)>Y=t=V9 z=2jhgLcOUT6^3%x$b9E88PuOVrDmO9bH+%s=yDOoD~a_+z8>m?;Q!u}o8`xVJUir6 z5-kpTj}gc%{KjErd7k}u@uON(x#_E9`LgH)gsuJwX>4y~W?GU58E_TtWR3MypB;d% zqJzv$9{;|nsf5x2@OIHg7L1-iY;X+&PZ#UR410*2_8ta~R1rP=OG@>53j>T68;Og} v6HH7>aWOF^B`+gTYGFbG&-d>|Ak=W8yf4s*fURxsi1vy69t6HQ20-}_%l6F> literal 0 HcmV?d00001 diff --git a/SRC/CMD/FORMAT/BOOTMES.INC b/SRC/CMD/FORMAT/BOOTMES.INC new file mode 100644 index 0000000..57d0a0f --- /dev/null +++ b/SRC/CMD/FORMAT/BOOTMES.INC @@ -0,0 +1,9 @@ +; SCCSID = @(#)bootmes.inc 1.1 85/04/18 + +; Message Include file for OEMFOR.ASM + +; THIS IS A SPECIAL MESSAGE WHICH IS INCLUDED IN THE "FAKE" IO.SYS +; FILE PLACED ON DISKS FORMATTED /B. NOTE THAT IT IS NUL TERMINATED. + +NO_SYS_MESS: + DB "Non-System disk or disk error",13,10,0 diff --git a/SRC/CMD/FORMAT/FILESIZE.INC b/SRC/CMD/FORMAT/FILESIZE.INC new file mode 100644 index 0000000..b62fb49 --- /dev/null +++ b/SRC/CMD/FORMAT/FILESIZE.INC @@ -0,0 +1,6 @@ + + %out ..filesize.inc + +BIOS_SIZE equ 22528 ; actually 22341 +DOS_SIZE equ 30208 ; actually 30128 + \ No newline at end of file diff --git a/SRC/CMD/FORMAT/FORMAT.ASM b/SRC/CMD/FORMAT/FORMAT.ASM new file mode 100644 index 0000000..3812a49 --- /dev/null +++ b/SRC/CMD/FORMAT/FORMAT.ASM @@ -0,0 +1,3032 @@ +page 84,132 +; SCCSID = @(#)format.asm 1.26 85/10/20 +; SCCSID = @(#)format.asm 1.26 85/10/20 +;*************************************************************** +; +; 86-DOS FORMAT DISK UTILITY +; +; This routine formats a new disk,clears the FAT and DIRECTORY then +; optionally copies the SYSTEM and COMMAND.COM to this new disk +; +; SYNTAX: FORMAT [drive][/switch1][/switch2]...[/switch16] +; +; Regardless of the drive designator , the user will be prompted to +; insert the diskette to be formatted. +; +;*************************************************************** + +; 5/12/82 ARR Mod to ask for volume ID +; 5/19/82 ARR Fixed rounding bug in CLUSCAL: +; REV 1.5 +; Added rev number message +; Added dir attribute to DELALL FCB +; REV 2.00 +; Redone for 2.0 +; REV 2.10 +; 5/1/83 ARR Re-do to transfer system on small memory systems +; REV 2.20 +; 6/17/83 system size re-initialization bug -- mjb001 +; Rev 2.25 +; 8/31/83 16-bit fat insertion +; Rev 2.26 +; 11/2/83 MZ fix signed compare problems for bad sectors +; Rev 2.27 +; 11/8/83 EE current directories are always saved and restored +; Rev 2.28 +; 11/9/83 NP Printf and changed to an .EXE file +; Rev 2.29 +; 11/11/83 ARR Fixed ASSIGN detection to use NameTrans call to see +; if drive letter remapped. No longer IBM only +; Rev 2.30 +; 11/13/83 ARR SS does NOT = CS, so all use of BP needs CS override +; Rev 2.31 +; 12/27/83 ARR REP STOSB instruction at Clean: changed to be +; sure ES = CS. + +code segment public 'CODE' +code ends + +printf_code segment public + extrn printf:far +printf_code ends + +stack segment stack + db (362 - 80h) + 100H dup (?) ; (362-80h) is the additional IBM ROM + ; overhead recently discovered by them. +stack ends + +data segment public 'DATA' +data ends + +public end_of_memory +_end segment public para 'DATA' +end_of_memory label byte +_end ends + +code segment + + assume cs:code,ds:nothing,es:nothing,ss:stack + +;------------------------------------------------------------------------------- +; Define as public for debugging + +; procedures + public GetSize + public AddToSystemSize + public Phase1Initialisation + public SetStartSector + public SetfBigFat + public Phase2Initialisation + public DiskFormat + public BadSector + public FormatTrack + public DisplayCurrentTrack + public NextTrack + public WriteFileSystem + public Done + public CurrentLogicalSector + public PrintErrorAbort + public GetDeviceParameters + public SetDeviceParameters + + public START + public GOTBADDOS + public OKDOS + public BogusDrive + public DRVGD + public DRVSPEC + public NXTSWT + public GETPARM + public GETCHR + public INVALID + public SCANOFF + public MEMERR + public SAVSWT + public NotNet + public RE_ASSIGN + public NO_ASSIGN + public FatAllocated + public MEMERRJ + public MEM_OK + public RDFRST + public NEEDSYS + public INITCALL + public SWITCHCHK + public SYSLOOP + public FRMTPROB + public GETTRK + public TRKFND + public CLRTEST + public CMPTRKS + public PACKIT + public BadClus + public DoBig + public DoSet + public DRTFAT + public CLEARED + public LOUSE + public LOUSEP + public FATWRT + public SYSOK + public STATUS + public REPORTC + public ONCLUS + public MORE + public FEXIT + public SYSPRM + public fexitJ + public DoPrompt + public TARGPRM + public IsRemovable + public CheckRemove + public IsRemove + public NotRemove + public DSKPRM + public GOPRNIT + public crlf + public PrintString + public std_printf + public VOLID + public VRET + public DOVOL + public VOL_LOOP + public GOOD_CREATE + public VOLRET + public READDOS + public RDFILS + public FILESDONE + public CLSALL + public GOTBIOS + public GOTDOS + public CLSALLJ + public GOTCOM + public WRITEDOS + public GOTALLBIO + public BIOSDONE + public GOTNDOS + public PARTDOS + public GOTALLDOS + public DOSDONE + public PARTCOM + public GOTALLCOM + public COMDONE + public MAKEFIL + public CheckMany + public CLOSETARG + public IOLOOP + public GOTTARG + public GSYS + public TESTSYS + public GETOFFS +; public TESTSYSDISK ; dcl 8/23/86 + public SETBIOS + public BIOSCLS + public SETBIOSSIZ + public DOSOPNOK + public DOSCLS + public SETDOSSIZ + public GotComHand + public COMCLS + public SETCOMSIZ + public GETFSIZ + public READFILE + public WRITEFILE + public FILIO + public NORMIO + public IORETP + public IORET + public NORMALIZE + public GotDeviceParameters + public SmallFAT + public LoadSectorTable + public NotBigTotalSectors + public NotBig + public FormatLoop + public FormatDone + public FailDiskFormat + public FormatReallyFailed + public ContinueFormat + public ReportBadTrack + public NoMoreTracks + public ExitNextTrack + public ThatsAllFolks + public WriteFATloop + public WriteDIRloop + public CanNotWriteFAT + public CanNotWriteDirectory + public ControlC_Handler + +; bytes + public fBigFat + public formatError + public ROOTSTR + public DBLFLG + public DRIVE + public FILSTAT + public USERDIRS + public VOLFCB + public VOLNAM + public TRANSRC + public TRANDST + public INBUFF + public driveLetter + public systemDriveLetter +; words + public startSector + public fatSpace + public firstHead + public firstCylinder + public tracksLeft + public tracksPerDisk + public sectorsInRootDirectory + public directorySector + public printStringPointer + public MSTART + public MSIZE + public TempHandle + public BEGSEG + public SWITCHMAP + public SWITCHCOPY + public FAT + public CLUSSIZ + public SECSIZ + public SYSTRKS + public SECTORS + public ptr_msgHardDiskWarning + public ptr_msgInsertDisk + public ptr_msgReInsertDisk + public ptr_msgInsertDosDisk + public ptr_msgCurrentTrack + public currentHead + public currentCylinder + +; other + public deviceParameters + public formatPacket +;------------------------------------------------------------------------------- + +data segment + extrn msgAssignedDrive:byte + extrn msgBadDosVersion:byte + extrn msgDirectoryWriteError:byte + extrn msgFormatComplete:byte + extrn msgFormatNotSupported:byte + extrn msgFATwriteError:byte + extrn msgInvalidDeviceParameters:byte + extrn msgLabelPrompt:byte + extrn msgNeedDrive:byte + extrn msgNoSystemFiles:byte + extrn msgTooManyFilesOpen:byte + extrn msgNetDrive:byte + extrn msgInsertDisk:byte + extrn msgHardDiskWarning:byte + extrn msgSystemTransfered:byte + extrn msgFormatAnother?:byte + extrn msgBadCharacters:byte + extrn msgBadDrive:byte + extrn msgInvalidParameter:byte + extrn msgParametersNotSupported:byte + extrn msgReInsertDisk:byte + extrn msgInsertDosDisk:byte + extrn msgFormatFailure:byte + extrn msgNotSystemDisk:byte +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +; reintroduce following extrn +; extrn msgNoRoomDestDisk:byte +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + extrn msgDiskUnusable:byte + extrn msgOutOfMemory:byte + extrn msgCurrentTrack:byte + extrn msgWriteProtected:byte + extrn msgNotReady:byte + extrn msgInterrupt:byte + extrn msgCRLF:byte + +data ends + + +debug equ 0 + .xlist + INCLUDE VERSIONA.INC + INCLUDE DOSMAC.INC + INCLUDE SYSCALL.INC + INCLUDE ERROR.INC + INCLUDE DPB.INC + INCLUDE CPMFCB.INC + INCLUDE DIRENT.INC + INCLUDE CURDIR.INC + INCLUDE PDB.INC + INCLUDE BPB.INC + .list + +;------------------------------------------------------------------------------- +; Constants + +;Limits +BIG_FAT_THRESHOLD equ 4086 + +;------------------------------------------------------------------------------- + +;FORMAT Pre-defined switches +SWITCH_S EQU 1 ; System transfer +SWITCH_V EQU 2 ; Volume ID prompt +SWITCH_H EQU 4 ; E5 dir terminator +SWITCH_C EQU 8 +SWITCH_T EQU 16 +SWITCH_N EQU 32 +SWITCH_1 EQU 64 +SWITCH_4 EQU 128 +SWITCH_8 EQU 256 +SWITCH_B EQU 512 + +NUM_SWITCHES EQU SWITCH_T or SWITCH_N + +DRNUM EQU 5CH + +RECLEN EQU fcb_RECSIZ+7 +RR EQU fcb_RR+7 + +;------------------------------------------------------------------------------- +; These are the data structures which we will need + + include ioctl.INC + +;Per system file data structure + +a_FileStructure struc +fileHandle DW ? +fileSizeInParagraphs DW ? +fileSizeInBytes DD ? +fileOffset DD ? +fileStartSegment DW ? +fileDate DW ? +fileTime DW ? +a_FileStructure ends + +;------------------------------------------------------------------------------- +; And this is the actual data + +data segment + public deviceParameters + +validSavedDeviceParameters db 0 +savedDeviceParameters a_DeviceParameters <> +deviceParameters a_DeviceParameters <> + +formatPacket a_FormatPacket <> + +startSector dw ? +fatSpace dd ? +fBigFat db FALSE + +firstHead dw ? +firstCylinder dw ? +tracksLeft dw ? +tracksPerDisk dw ? + +public NumSectors ,TrackCnt +NumSectors dw 0FFFFh +TrackCnt dw 0FFFFh + +public Old_Dir +Old_Dir db FALSE + +public fLastChance +fLastChance db FALSE ; Flags reinvocation from + ; LastChanceToSaveIt. Used by DSKPRM + +sectorsInRootDirectory dw ? + +directorySector dd 0 + +formatError db 0 + +printStringPointer dw 0 + +; Exit status defines +ExitStatus db 0 +ExitOK equ 0 +ExitCtrlC equ 3 +ExitFatal equ 4 +ExitNo equ 5 + +ROOTSTR DB ? + DB ":\",0 +DBLFLG DB 0 ;Initialize flags to zero +IOCNT DD ? +MSTART DW ? ; Start of sys file buffer (para#) +MSIZE DW ? ; Size of above in paragraphs +TempHandle DW ? +FILSTAT DB ? ; In memory status of files + ; XXXXXX00B BIOS not in + ; XXXXXX01B BIOS partly in + ; XXXXXX10B BIOS all in + ; XXXX00XXB DOS not in + ; XXXX01XXB DOS partly in + ; XXXX10XXB DOS all in + ; XX00XXXXB COMMAND not in + ; XX01XXXXB COMMAND partly in + ; XX10XXXXB COMMAND all in + +USERDIRS DB DIRSTRLEN+3 DUP(?) ; Storage for users current directory + +bios a_FileStructure <> +BiosAttributes EQU attr_hidden + attr_system + attr_read_only + +dos a_FileStructure <> +DosAttributes EQU attr_hidden + attr_system + attr_read_only + +command a_FileStructure <> +CommandAttributes EQU 0 +CommandFile DB "X:\COMMAND.COM",0 + +VOLFCB DB -1,0,0,0,0,0,8 + DB 0 +VOLNAM DB " " + DB 8 + DB 26 DUP(?) + +TRANSRC DB "A:CON",0,0 ; Device so we don't hit the drive +TRANDST DB "A:\",0,0,0,0,0,0,0,0,0,0 + +BEGSEG DW ? +SWITCHMAP DW ? +SWITCHCOPY DW ? +FAT DW ? + DW ? +CLUSSIZ DW ? +SECSIZ DW ? +SYSTRKS DW ? +SECTORS DW ? +INBUFF DB 80,0 + DB 80 DUP(?) + +ptr_msgHardDiskWarning dw msgHardDiskWarning + dw offset driveLetter + +ptr_msgInsertDisk dw msgInsertDisk + dw offset driveLetter + +ptr_msgReInsertDisk dw msgReInsertDisk + dw offset driveLetter + +ptr_msgInsertDosDisk dw offset msgInsertDosDisk + dw offset systemDriveLetter + +ptr_msgFormatNotSupported dw offset msgFormatNotSupported + dw offset driveLetter + +drive db 0 +driveLetter db "x" +systemDriveLetter db "x" + +data ends + +;For FORPROC and FORMES modules + + public secsiz,clussiz,inbuff + + PUBLIC crlf,std_printf + +;For OEM module + public switchmap,drive,driveLetter,fatSpace + public fBigFat, PrintString,currentHead,currentCylinder + extrn CheckSwitches:near,LastChanceToSaveIt:near + extrn WriteBootSector:near,OemDone:near + extrn AccessDisk:near +data segment + extrn switchlist:byte + extrn fdsksiz:word + extrn BiosFile:byte,DosFile:byte +data ends + +;For FORPROC module + + EXTRN FormatAnother?:near,Yes?:near,REPORT:NEAR,USER_STRING:NEAR +data segment + extrn badsiz:dword,syssiz:dword,biosiz:dword +data ends + +DOSVER_LOW EQU 0300H+20 +DOSVER_HIGH EQU 0300H+20 + + +START: + PUSH AX ;Save DRIVE validity info + MOV AH,GET_VERSION + INT 21H + CMP AX,EXPECTED_VERSION + JE OKDOS + +; XCHG AH,AL ;Turn it around to AH.AL +; CMP AX,DOSVER_LOW +; JB GotBadDos +; CMP AX,DOSVER_HIGH +; JBE OKDOS + + +GOTBADDOS: + MOV DX,OFFSET msgBadDosVersion + mov ax, seg data + mov ds, ax + mov ah,std_con_string_output + int 21h + push es + xor ax,ax + push ax + +foo proc far + ret ; Must use this method, version may be < 2.00 +foo endp + +OKDOS: + + mov ax, seg data + mov es, ax + assume es:data + POP AX + + CMP AL,0FFH ;See if invalid drive specified + JNZ DRVGD ;If not proceed +BogusDrive: + mov ax, seg data + mov ds, ax + lea dx, msgBadDrive + call PrintString + JMP FEXIT ;Exit + +DRVGD: + MOV AH,GET_DEFAULT_DRIVE ;Must get the default drive + INT 21H ;Default now in AL + ADD AL,"A" + MOV [BiosFile],AL + MOV [DosFile],AL + MOV [CommandFile],AL + MOV SI,DRNUM ;So we can get our parameters + LODSB ;Fetch drive designation + OR AL,AL ;See if specified + JNZ DRVSPEC ;If specfied proceed + mov ax, seg data + mov ds, ax + lea dx, msgNeedDrive + call PrintString + jmp fexit +DRVSPEC: + DEC AL ;Drive designator now correct + MOV BYTE PTR DS:[DRNUM],AL ;And updated + MOV DRIVE,AL ;Save copy + add al, 'A' + mov driveLetter, al +; Get all the switch information from the command line + MOV [BEGSEG],DS ;Save start segment + + XOR BX,BX ;Store switch information in BX + MOV SI,81H ;Point to the command line buffer +NXTSWT: + CALL SCANOFF + LODSB + CMP AL,"/" + JZ GETPARM + + CMP AL,13 + JNZ NxtS1 + JMP SavSwt +NxtS1: + MOV AH,AL + LODSB ; AX := getchar() + CMP AL,":" ; IF (AX != drive_spec) + JNZ INVALID ; THEN error + + CMP BYTE PTR DBLFLG,0 ; IF (previous drive_spec) + JNZ INVALID ; THEN error + + INC BYTE PTR DBLFLG ; Yes -- set the flag + OR AH,020h + SUB AH,'a' + CMP AH,Drive + JZ SHORT NXTSWT + JMP BogusDrive +GETPARM: + LODSB +; Convert any lower case input into upper case + CMP AL,41H + JB GETCHR ; Switch is a digit, so don't try to + ; convert it. + AND AL,0DFH +GETCHR: + MOV CL,SWITCHLIST ; CL := Number of Legal switches + OR CL,CL ; IF (Num_Legal_Switches == 0) + JZ INVALID ; THEN error + + MOV CH,0 ; FOR (i=0; i <= Max_switches; i++) + MOV DI,1+OFFSET SWITCHLIST ; IF (switch == SWITCHLIST[i]) + REPNE SCASB ; THEN set zero flag + ; END for + JNZ INVALID ; IF (zero_flag != TRUE ) THEN error + + MOV AX,1 + SHL AX,CL + OR BX,AX ;Set the appropriate bit in SWITCHMAP + + MOV CX,AX ; Current_Switch := Switch processed + Test AX,NUM_SWITCHES ; IF (Switch_processed does not require + ; numeric value) + JZ NXTSWT ; THEN parse next switch + + LODSB ; ELSE then parse :nn and save approp + cmp al,':' ; IF (getchar() != ':') + jne INVALID + + LODSB ; curr_num := MakeNum (getchar()) + SaveReg + call MakeNum + RestoreReg + jc INVALID ; IF error, THEN exit + + SaveReg + Call SaveNum ; SaveNum (curr_num) + Restorereg ; END else; + + + JMP SHORT NXTSWT ;See if there are anymore + +INVALID: + mov ax, seg data + mov ds, ax + lea dx, msgInvalidParameter + call PrintString + JMP FEXIT +MEMERR: + mov ax, seg data + mov ds, ax + lea dx, msgOutOfMemory + call PrintString + JMP FEXIT + +SAVSWT: + mov ax, seg data + mov ds, ax + assume ds:data + MOV SWITCHMAP,BX + +; Set memory requirements + mov es, begseg + mov bx, seg _end + sub bx, begseg + mov ah, setblock + int 21H + +; trap ^C + mov ax, (Set_Interrupt_Vector shl 8) or 23H + mov dx, offset ControlC_Handler + push ds + push cs + pop ds + int 21H + pop ds + +AroundControlC_Handler: + MOV BL,Drive ; x = IOCTL (getdrive, Drive+1); + INC BL + MOV AX,(IOCTL SHL 8) OR 9 + INT 21H + JC NotNet + TEST DX,1200H ; if (x & 0x1200)(redirected or shared) + JZ NotNet + lea dx, msgNetDrive ; Cann't format over net + call PrintString + JMP FEXIT + +NotNet: + TEST DX,8000h ; if local use + jnz re_assign + MOV BL,Drive + ADD BYTE PTR [TRANSRC],BL ; Make string "D:\" + MOV SI,OFFSET TRANSRC + push ds + pop es + MOV DI,OFFSET TRANDST + MOV AH,xNameTrans + INT 21H + MOV BL,BYTE PTR [TRANSRC] + CMP BL,BYTE PTR [TRANDST] ; Did drive letter change? + JZ NO_ASSIGN ; No +RE_ASSIGN: + lea dx, msgAssignedDrive + call PrintString + JMP FEXIT + +NO_ASSIGN: + + CALL Phase1Initialisation + jnc FatAllocated + + lea dx, msgFormatFailure ; IF (error_allocating_FAT) + call PrintString ; ISSUE error and abort + jmp Fexit +FatAllocated: + + TEST SWITCHMAP,SWITCH_S + JZ INITCALL + MOV BX,0FFFFH + MOV AH,ALLOC + INT 21H + OR BX,BX + JZ MEMERRJ ;No memory + MOV [MSIZE],BX + MOV AH,ALLOC + INT 21H + JNC MEM_OK +MEMERRJ: + JMP MEMERR ;No memory + +MEM_OK: + MOV [MSTART],AX + +RDFRST: + mov bios.fileSizeInParagraphs,0 ;mjb001 initialize file size + mov dos.fileSizeInParagraphs,0 ;mjb001 ... + mov command.fileSizeInParagraphs,0 ;mjb001 ... + CALL READDOS ;Read BIOS and DOS + JNC INITCALL ;OK -- read next file +NEEDSYS: + CALL SYSPRM ;Prompt for system disk + JMP RDFRST ;Try again + +INITCALL: + CALL Phase2Initialisation +; Barry S - No reason to jump on carry!!! +; JNC SWITCHCHK +; lea dx, msgFormatFailure +; call PrintString +; JMP FEXIT + +SWITCHCHK: + MOV DX,SWITCHMAP + MOV SWITCHCOPY,DX + +SYSLOOP: + MOV WORD PTR BADSIZ,0 ;Must intialize for each iteration + MOV WORD PTR BADSIZ+2,0 + MOV WORD PTR SYSSIZ,0 + MOV WORD PTR SYSSIZ+2,0 + MOV BYTE PTR DBLFLG,0 + mov ExitStatus, ExitOK + MOV DX,SWITCHCOPY + MOV SWITCHMAP,DX ;Restore original Switches +; DiskFormat will handle call for new disk +; CALL DSKPRM ;Prompt for new disk + CALL DISKFORMAT ;Format the disk + JNC GETTRK +FRMTPROB: + lea dx, msgFormatFailure + call PrintString + mov ExitStatus, ExitFatal + CALL MORE ;See if more disks to format + JMP SHORT SYSLOOP + +;Mark any bad sectors in the FATs +;And keep track of how many bytes there are in bad sectors + +GETTRK: + CALL BADSECTOR ;Do bad track fix-up + JC FRMTPROB ;Had an error in Formatting - can't recover + CMP AX,0 ;Are we finished? + JNZ TRKFND ;No - check error conditions + JMP DRTFAT ;Yes +TRKFND: + CMP BX,STARTSECTOR ;Are any sectors in the system area bad? + JAE CLRTEST ; MZ 2.26 unsigned compare + lea dx, msgDiskUnusable + call PrintString + JMP FRMTPROB ;Bad disk -- try again +CLRTEST: + MOV SECTORS,AX ;Save the number of sectors on the track + TEST SWITCHMAP,SWITCH_S ;If system requested calculate size + JZ BAD100 + CMP BYTE PTR DBLFLG,0 ;Have we already calculated System space? + JNZ CMPTRKS ;Yes -- all ready for the compare + INC BYTE PTR DBLFLG ;No -- set the flag + CALL GETBIOSIZE ; Get the size of the BIOS + MOV DX,WORD PTR SYSSIZ+2 + MOV AX,WORD PTR SYSSIZ + MOV WORD PTR BIOSIZ+2,DX + MOV WORD PTR BIOSIZ,AX + CALL GETDOSSIZE + CALL GETCMDSIZE + MOV DX,WORD PTR BIOSIZ+2 + MOV AX,WORD PTR BIOSIZ + DIV deviceParameters.DP_BPB.BPB_BytesPerSector + ADD AX,STARTSECTOR + MOV SYSTRKS,AX ;Space FAT,Dir,and system files require +CMPTRKS: + CMP BX,SYSTRKS + JA BAD100 ; MZ 2.26 unsigned compare + mov ExitStatus, ExitFatal + lea dx, msgNotSystemDisk + call PrintString + AND SWITCHMAP,NOT SWITCH_S ;Turn off system transfer switch + MOV WORD PTR SYSSIZ+2,0 ;No system to transfer + MOV WORD PTR SYSSIZ,0 ;No system to transfer +BAD100: +; BX is the first bad sector #, SECTORS is the number of bad sectors +; starting at BX. This needs to be converted to clusters. The start sector +; number may need to be rounded down to a cluster boundry, the end sector +; may need to be rounded up to a cluster boundry. Know BX >= STARTSECTOR + SUB BX,STARTSECTOR ; BX is now DATA area relative + MOV CX,BX + ADD CX,SECTORS + DEC CX ; CX is now the last bad sector # + MOV AX,BX + XOR DX,DX + xor bx,bx + mov bl, deviceParameters.DP_BPB.BPB_SectorsPerCluster + DIV bx + MOV BX,AX ; BX is rounded down and converted to + ; a cluster #. Where cluster 0 = + ; first cluster of data. First bad + ; Sector is in cluster BX. + MOV AX,CX + XOR DX,DX + push bx + xor bx,bx + mov bl, deviceParameters.DP_BPB.BPB_SectorsPerCluster + DIV bx + pop bx + MOV CX,AX ; CX is rounded up and converted to a + ; to a cluster #. Where cluster 0 = + ; first cluster of data. Last bad + ; Sector is in cluster CX. + SUB CX,BX + INC CX ; CX is number of clusters to mark bad + ADD BX,2 ; Bias start by correct amount since + ; first cluster of data is really + ; cluster 2. + xor ax,ax + MOV Al,deviceParameters.DP_BPB.BPB_SectorsPerCluster + MUL deviceParameters.DP_BPB.BPB_BytesPerSector + MOV BP,AX ; = Bytes/Cluster + +; Mark CX clusters bad starting at cluster BX +PACKIT: + CALL BadClus ;Put it in the allocation map + JZ BAD150 ;If already marked bad, don't count it + ADD WORD PTR BADSIZ,BP ;Add in number of bad bytes + JNB BAD150 + INC WORD PTR BADSIZ+2 +BAD150: + INC BX ;Next cluster + LOOP PACKIT ;Continue for # of clusters + JMP GETTRK + +; Inputs: BX = Cluster number +; Outputs: The given cluster is marked as invalid +; Zero flag is set if the cluster was already marked bad +; Registers modified: DX,SI +; No other registers affected +BadClus: + PUSH AX + PUSH BX + PUSH CX + PUSH DX + CMP fBigFat,-1 ; if (!fBigFat) { + JZ DoBig + MOV DX,0FF7h ; badval = 0xFF7; + MOV AX,0FFFh ; mask = 0xFFF; + MOV SI,BX ; p = FAT+clus+clus/2; + SHR SI,1 + ADD SI,BX + ADD SI, word ptr fatspace + TEST BX,1 ; if (clus&1) { + JZ DoSet + MOV CL,4 ; mask <<= 4; + SHL AX,CL + MOV CL,4 ; badval <<= 4; + SHL DX,CL ; } + JMP SHORT DoSet +DoBig: ; else { + MOV DX,0FFF7h ; badval = 0xFFF7; + MOV AX,0FFFFh ; mask = 0xFFFF; + MOV SI, word ptr fatSpace ; p = FAT + clus + clus; + ADD SI,BX + ADD SI,BX +DoSet: ; } + push es + mov es, word ptr fatSpace + 2 + MOV CX,es:[SI] ; op = *p & mask; + AND CX,AX + NOT AX ; *p &= ~mask; + AND es:[SI],AX + OR es:[SI],DX ; *p |= badval; + CMP DX,CX ; return op == badval; + pop es + POP DX + POP CX + POP BX + POP AX + return + +DRTFAT: + TEST SWITCHMAP,SWITCH_S ;If system requested, calculate size + JZ CLEARED + CMP BYTE PTR DBLFLG,0 ;Have we already calculated System space? + JNZ CLEARED ;Yes + INC BYTE PTR DBLFLG ;No -- set the flag + CALL GETSIZE ;Calculate the system size +CLEARED: + CALL WriteFileSystem + JNC FATWRT +LOUSE: + lea dx, msgDiskUnusable + call PrintString + JMP FRMTPROB + +LOUSEP: + POP DS + JMP LOUSE + +FATWRT: + + PUSH DS + MOV DL,DRIVE + INC DL + MOV AH,GET_DPB + INT 21H + CMP AL,-1 + JZ LOUSEP ;Something BAD has happened + MOV [BX.dpb_next_free],0 ; Reset allocation to start of disk + MOV [BX.dpb_free_cnt],-1 ; Force free space to be computed + POP DS + TEST SWITCHMAP,SWITCH_S ;System desired + JZ STATUS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +;reintroduce following section of code +; +; CALL CHKSPACE ;Enough free space for system? +; JNC SPACEOK ; Y: Go load system files +; LEA DX, msgNoRoomDestDisk ; N: Print error message +; CALL PrintString ; +; MOV WORD PTR SYSSIZ+2,0 ;No system transfered +; MOV WORD PTR SYSSIZ,0 ;No system transfered +; JMP SHORT STATUS ; +;SPACEOK: ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + mov al, drive + call AccessDisk ; note what is current logical drive + CALL WRITEDOS ;Write the BIOS & DOS + JNC SYSOK + lea dx, msgNotSystemDisk + call PrintString + MOV WORD PTR SYSSIZ+2,0 ;No system transfered + MOV WORD PTR SYSSIZ,0 ;No system transfered + JMP SHORT STATUS + +SYSOK: + lea dx, msgSystemTransfered + call PrintString +STATUS: + CALL CRLF + CALL VOLID + MOV AH,DISK_RESET + INT 21H + CALL DONE ;Final call to OEM module + JNC REPORTC + JMP FRMTPROB ;Report an error + +REPORTC: + CALL REPORT + + CALL MORE ;See if more disks to format + JMP SYSLOOP ;If we returned from MORE then continue + +;****************************************** +; Calculate the size in bytes of the system rounded up to sector and +; cluster boundries, Answer in SYSSIZ + +GetSize proc near + call GetBioSize + call GetDosSize + call GetCmdSize + return +GetSize endp + +GetBioSize proc near + MOV AX,WORD PTR bios.fileSizeInBytes + MOV DX,WORD PTR bios.fileSizeInBytes+2 + CALL AddToSystemSize + return +GetBioSize endp + +GetDosSize proc near + MOV AX,WORD PTR dos.fileSizeInBytes + MOV DX,WORD PTR dos.fileSizeInBytes+2 + CALL AddToSystemSize + return +GetDosSize endp + +GetCmdSize proc near + MOV AX,WORD PTR command.fileSizeInBytes + MOV DX,WORD PTR command.fileSizeInBytes+2 + call AddToSystemSize + return +GetCmdSize endp + +;Calculate the number of sectors used for the system +PUBLIC AddToSystemSize +AddToSystemSize proc near + push bx + DIV deviceParameters.DP_BPB.BPB_BytesPerSector + OR DX,DX + JZ FNDSIZ0 + INC AX ; Round up to next sector +FNDSIZ0: + PUSH AX + XOR DX,DX + xor bx,bx + mov bl, deviceParameters.DP_BPB.BPB_SectorsPerCluster + div bx + POP AX + OR DX,DX + JZ ONCLUS + SUB DX, bx + NEG DX + ADD AX,DX ; Round up sector count to cluster + ; boundry +ONCLUS: + MUL deviceParameters.DP_BPB.BPB_BytesPerSector + ADD WORD PTR SYSSIZ,AX + ADC WORD PTR SYSSIZ+2,DX + pop bx + return +AddToSystemSize endp + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +; reintroduce following section of code +;; Check free space to see if there is enough room to load the system +;; On Entry: DL = drive +;; On Exit: carry flag set if not enough room +;; no other registers are affected +;CHKSPACE PROC NEAR +; PUSH AX ;Save resisters +; PUSH BX +; PUSH CX +; PUSH DX +; +; MOV AH,36H ;Get free space +; INT 21h +; +;;16 bit math okay here, no danger of overflow +; MUL CX ;Get bytes/cluster +; MOV CX,AX ; +; MOV AX,WORD PTR SYSSIZ ;Get # of bytes for system +; MOV DX,WORD PTR SYSSIZ+2 ; +; DIV CX ;Get # of clusters for system +; +; CMP AX,BX ;Is there enough space? +; JBE ENOUGHSPACE ; Y: Go clear carry +; STC ; N: Set carry +; JMP SHORT RESTOREREGS ; +; +;ENOUGHSPACE: +; CLC +; +;RESTOREREGS: +; POP DX ;Restore resisters +; POP CX +; POP BX +; POP AX +; RET +;CHKSPACE ENDP +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + +MORE: CMP deviceParameters.DP_DeviceType, DEV_HARDDISK + je ExitProgram + CALL FormatAnother? ;Get yes or no response + JC ExitProgram + CALL CRLF + JMP CRLF + + +FEXIT: + mov ExitStatus,ExitFatal + +ExitProgram: + test validSavedDeviceParameters, 0ffH + jz DoNotRestoreDeviceParameters + mov savedDeviceParameters.DP_SpecialFunctions, TRACKLAYOUT_IS_GOOD + lea dx, savedDeviceParameters + call SetDeviceParameters +DoNotRestoreDeviceParameters: + mov al, ExitStatus + mov ah,exit + INT 21H + +; Prompt the user for a system diskette in the default drive +SYSPRM: + MOV AH,GET_DEFAULT_DRIVE ;Will find out the default drive + INT 21H ;Default now in AL + MOV BL,AL + INC BL ; A = 1 + ADD AL,41H ;Now in Ascii + MOV systemDriveLetter,AL ;Text now ok + CALL IsRemovable + JNC DoPrompt +; +; Media is non-removable. Switch sys disk to drive A. Check, though, to see +; if drive A is removable too. +; + MOV AL,"A" + MOV BYTE PTR [systemDriveLetter],AL + MOV [BiosFile],AL + MOV [DosFile],AL + MOV [CommandFile],AL + MOV BX,1 + CALL IsRemovable + JNC DoPrompt + lea dx, msgNoSystemFiles + call PrintString +fexitJ: + JMP FEXIT + +DoPrompt: + mov al, systemDriveLetter + sub al, 'A' + call AccessDisk + lea dx, ptr_msgInsertDosDisk + CALL std_printf ;Print first line + CALL USER_STRING ;Wait for a key + CALL CRLF + return + +TARGPRM: + mov al, drive + call AccessDisk + lea DX, ptr_msgInsertDisk + CALL std_printf ;Print first line + CALL USER_STRING ;Wait for a key + CALL CRLF + return + +; +; Determine if the drive indicated in BX is removable or not. +; +; Inputs: BX has drive (0=def, 1=A) +; Outputs: Carry clear +; Removable +; Carry set +; not removable +; Registers modified: none + +IsRemovable: + SaveReg + MOV AX,(IOCTL SHL 8) OR 8 ; Rem media check + INT 21H + JNC CheckRemove + MOV AX,(IOCTL SHL 8) + 9 ; Is it a NET drive? + INT 21h + JC NotRemove ; Yipe, say non-removable + TEST DX,1000h + JNZ NotRemove ; Is NET drive, say non-removeable + JMP IsRemove ; Is local, say removable +CheckRemove: + TEST AX,1 + JNZ NotRemove +IsRemove: + CLC + RestoreReg + return +NotRemove: + STC + RestoreReg + return + + +; DiSKPRoMpt: +; +; This routine prompts for the insertion of the correct diskette +; into the Target drive, UNLESS we are being re-entrantly invoked +; from LastChanceToSaveIt. If the target is a Hardisk we issue a +; warning message. +; +; INPUTS: +; deviceParameters.DP_DeviceType +; fLastChance +; +; OUTPUTS: +; Prompt string +; fLastChance := FALSE +; +; Registers affected: +; Flags +; +DSKPRM: + CMP fLastChance,TRUE + JE PrmptRet + + CMP deviceParameters.DP_DeviceType, DEV_HARDDISK + jne goprnit + lea dx, ptr_msgHardDiskWarning + call std_printf + CALL Yes? + jnc OkToFormatHardDisk + mov ExitStatus, ExitNo + jmp ExitProgram + +OkToFormatHardDisk: + CALL CRLF + CALL CRLF + return + +GOPRNIT: + mov al, drive + call AccessDisk + lea dx,ptr_msgInsertDisk + CALL std_printf + CALL USER_STRING ;Wait for any key + CALL CRLF + CALL CRLF + +PrmptRet: + mov fLastChance, FALSE + return + +;------------------------------------------------------------------------------- +; ScanOff +; Scan Off separator characters + +SCANOFF: + LODSB + CMP AL,' ' + JZ SCANOFF + CMP AL,9 + JZ SCANOFF + DEC SI + return + +;------------------------------------------------------------------------------- +; MakeNum +; Makenum converts digits from ASCII AlphaNumeric format to +; numeric values +; +; Entry: +; AL == Character to be converted +; DS:SI == Command line text +; +; Exit: +; AX == Value +; IF AX == 0 THEN Zero Flag == SET +; IF ERROR THEN Carry Flag == SET +; BX,CX,DX == Garbage +; DS:SI == Character after numeric value +; +; Procs used: +; ToDigit + +Public MakeNum,CalcLoop +MakeNum: + xor BX,BX ; Initialize running cnt + mov CX,10 ; and base of arithmetic +CalcLoop: ; UNTIL no more digits + call ToDigit ; AL := AL - '0' + jc BadNum ; IF error EXIT with carry set + + xchg ax,bx ; AX := running_cnt * 10 + + mul cx ; digit + add ax,bx + jc BadNum ; IF Overflow EXIT with carry + + xchg ax,bx ; BX := Running total + + LODSB ; Get Next Digit + cmp al,' ' ; IF ( ax = (' ',',',)) + je RetVal ; THEN return parsed value + cmp al,',' + je RetVal + + cmp al,'/' ; IF (ax = ('/','cr')) + je BURetVal ; THEN backup DS:SI and + cmp al,0dh ; return parsed value + je BURetVal + or al,al + jnz CalcLoop ; END until + +BURetVal: + dec SI +RetVal: + mov ax,bx + or ax,ax + return + +public Badnum +BadNum: + xor ax,ax + stc + return + +; ToDigit: +; Convert value in AX to decimal digit, range checking for valid values +; +public ToDigit +ToDigit: + sub al,'0' + jb NotDigit + cmp al,9 + ja NotDigit + clc + return + +NotDigit: + stc + return + +;------------------------------------------------------------------------------- + +ControlC_Handler: + mov ax, seg data + mov ds, ax + lea dx, msgInterrupt + call PrintString + mov ExitStatus, ExitCtrlC + jmp ExitProgram + +;------------------------------------------------------------------------------- +; SaveNum +; Save Number from switches into appropriate variable for later use +; Some switches have upper and lower bounds for legal values and +; these are checked for here +; +; ENTRY: +; cx == Switch just parsed +; ax == value parsed +; +; EXIT: +; Value stored in appropriate variable +; DS,DX == garbage +; + +public SaveNum +SaveNum: + mov dx, seg data + mov ds, dx + test word ptr data:Switchmap, CX ; IF already set THEN ignore + jnz done_ret + + test CX,SWITCH_T + jnz Store_T + + test CX,SWITCH_N + jz BadNum + +Store_N: + cmp AX,0 ; IF (value == 0) THEN ignore + je done_ret + + cmp AX, MAX_SECTORS_IN_TRACK ; IF (value > Max_sectors) + jbe short Store_N1 ; THEN issue error + jmp INVALID + +Store_N1: + mov word ptr data:NumSectors , AX + + jmp short done_ret + +Store_T: + mov word ptr data:TrackCnt, AX + +Done_ret: + ret +;------------------------------------------------------------------------------- + +crlf: + lea dx, msgCRLF + +PrintString: + mov printStringPointer, dx + lea dx, PrintStringPointer + +std_printf: + push dx + call printf + return + +;------------------------------------------------------------------------------- + +;***************************************** +; Process V switch if set + +VOLID: + TEST [SWITCHMAP],SWITCH_V + JNZ DOVOL +VRET: CLC + return + +DOVOL: + PUSH CX + PUSH SI + PUSH DI + PUSH ES + PUSH DS + POP ES +VOL_LOOP: + MOV AL,DRIVE + INC AL + MOV DS:BYTE PTR[VOLFCB+7],AL + lea dx, msgLabelPrompt + call PrintString + CALL USER_STRING + call crlf + call crlf + MOV CL,[INBUFF+1] + OR CL,CL + JZ VOLRET + XOR CH,CH + MOV SI,OFFSET INBUFF+2 + MOV DI,SI + ADD DI,CX + MOV CX,11 + MOV AL,' ' + REP STOSB + MOV CX,5 + MOV DI,OFFSET VOLNAM + REP MOVSW + MOVSB + MOV DX,OFFSET VOLFCB + MOV AH,FCB_CREATE + INT 21H + OR AL,AL + JZ GOOD_CREATE + lea dx, msgBadCharacters + call PrintString + JMP VOL_LOOP +GOOD_CREATE: + MOV DX,OFFSET VOLFCB + MOV AH,FCB_CLOSE + INT 21H + CALL CRLF +VOLRET: + POP ES + POP DI + POP SI + POP CX + return + +;**************************************** +;Copy IO.SYS, MSDOS.SYS and COMMAND.COM into data area. +; Carry set if problems + +READDOS: +; CALL TESTSYSDISK ; dcl 8/23/86 + call Get_BIOS ; dcl 8/23/86 + JNC RDFILS + return + +RDFILS: + MOV BYTE PTR [FILSTAT],0 + MOV BX,[bios.fileHandle] + MOV AX,[MSTART] + MOV DX,AX + ADD DX,[MSIZE] ; CX first bad para + MOV [bios.fileStartSegment],AX + MOV CX,[bios.fileSizeInParagraphs] + ADD AX,CX + CMP AX,DX + JBE GOTBIOS + MOV BYTE PTR [FILSTAT],00000001B ; Got part of BIOS + MOV SI,[MSIZE] + XOR DI,DI + CALL DISIX4 + push ds + MOV DS,[bios.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JC CLSALL + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR [bios.fileOffset],AX + MOV WORD PTR [bios.fileOffset+2],DX +FILESDONE: + CLC +CLSALL: + PUSHF +; CALL COMCLS ; dcl 8/23/86 + call FILE_CLS ; dcl 8/23/86 + POPF + return + +GOTBIOS: + MOV BYTE PTR [FILSTAT],00000010B ; Got all of BIOS + push es + LES SI,[bios.fileSizeInBytes] + MOV DI,ES + pop es + push ds + MOV DS,[bios.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JC CLSALL + + push ax ; dcl 8/23/86 + push dx ; dcl 8/23/86 + call File_Cls ; dcl 8/23/86 + call Get_DOS ; dcl 8/23/86 + pop dx ; dcl 8/23/86 + pop ax ; dcl 8/23/86 + + JNC Found_MSDOS ;mt 12/8/86 P894 + return ;mt 12/8/86 + +Found_MSDOS: ;mt 12/8/86 + + MOV BX,[dos.fileHandle] + MOV [dos.fileStartSegment],AX + CMP AX,DX ; No room left? + JZ CLSALL ; Yes + MOV CX,[dos.fileSizeInParagraphs] + ADD AX,CX + CMP AX,DX + JBE GOTDOS + OR BYTE PTR [FILSTAT],00000100B ; Got part of DOS + SUB DX,[dos.fileStartSegment] + MOV SI,DX + XOR DI,DI + CALL DISIX4 + push ds + MOV DS,[dos.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JC CLSALL + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR [dos.fileOffset],AX + MOV WORD PTR [dos.fileOffset+2],DX + JMP FILESDONE + +GOTDOS: + OR BYTE PTR [FILSTAT],00001000B ; Got all of DOS + LES SI,[dos.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[dos.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + +CLSALLJ: JNC NOTCLSALL ;PTM P894 mt 12/8/86 + jmp clsall ; + +NotCLSALL: + push ax ; dcl 8/23/86 + + push dx ; dcl 8/23/86 + call File_cls ; dcl 8/23/86 + call Get_COMMAND ; dcl 8/23/86 + pop dx ; dcl 8/23/86 + pop ax ; dcl 8/23/86 + + JNC Found_COMMAND ;mt 12/8/86 P894 + return ;mt 12/8/86 + +Found_COMMAND: ;mt 12/8/86 + MOV BX,[command.fileHandle] + MOV [command.fileStartSegment],AX + CMP AX,DX ; No room left? + JZ CLSALLJ ; Yes + MOV CX,[command.fileSizeInParagraphs] + ADD AX,CX + CMP AX,DX + JBE GOTCOM + OR BYTE PTR [FILSTAT],00010000B ; Got part of COMMAND + SUB DX,[command.fileStartSegment] + MOV SI,DX + XOR DI,DI + CALL DISIX4 + push ds + MOV DS,[command.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JC CLSALLJ + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR [command.fileOffset],AX + MOV WORD PTR [command.fileOffset+2],DX + JMP FILESDONE + +GOTCOM: + OR BYTE PTR [FILSTAT],00100000B ; Got all of COMMAND + LES SI,[command.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[command.fileStartSegment] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JMP CLSALL + +;************************************************** +;Write BIOS DOS COMMAND to the newly formatted disk. + +ASSUME DS:DATA +WRITEDOS: + MOV CX,BiosAttributes + MOV DX,OFFSET BiosFile + LES SI,[bios.fileSizeInBytes] + MOV DI,ES + CALL MAKEFIL + retc + + MOV [TempHandle],BX + TEST BYTE PTR FILSTAT,00000010B + JNZ GOTALLBIO + call Get_BIOS ; dcl 8/23/86 + jnc Got_WBIOS ;mt 12/8/86 P894 + ret + +Got_WBIOS: + + LES SI,[bios.fileOffset] + MOV DI,ES + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + MOV BP,OFFSET bios + CALL GOTTARG + retc + JMP SHORT BIOSDONE + +GOTALLBIO: + LES SI,[bios.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[bios.fileStartSegment] + assume ds:nothing + CALL WRITEFILE + pop ds + assume ds:data +BIOSDONE: + MOV BX,[TempHandle] + MOV CX,bios.fileTime + MOV DX,bios.fileDate + CALL CLOSETARG + MOV CX,DosAttributes + MOV DX,OFFSET DosFile + LES SI,[dos.fileSizeInBytes] + MOV DI,ES + CALL MAKEFIL + retc + +GOTNDOS: + MOV [TempHandle],BX + TEST BYTE PTR FILSTAT,00001000B + JNZ GOTALLDOS + call Get_DOS ; dcl 8/23/86 + jnc Got_WDOS ;mt 12/8/86 P894 + ret + +Got_WDOS: + MOV BP,OFFSET dos + TEST BYTE PTR FILSTAT,00000100B + JNZ PARTDOS + MOV WORD PTR [dos.fileOffset],0 + MOV WORD PTR [dos.fileOffset+2],0 + CALL GETSYS3 + retc + JMP SHORT DOSDONE + +PARTDOS: + LES SI,[dos.fileOffset] + MOV DI,ES + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + CALL GOTTARG + retc + JMP SHORT DOSDONE + +GOTALLDOS: + LES SI,[dos.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[dos.fileStartSegment] + assume ds:nothing + CALL WRITEFILE + pop ds + assume ds:data +DOSDONE: + MOV BX,[TempHandle] + MOV CX,dos.fileTime + MOV DX,dos.fileDate + CALL CLOSETARG + MOV CX,CommandAttributes + MOV DX,OFFSET CommandFile + LES SI,[command.fileSizeInBytes] + MOV DI,ES + CALL MAKEFIL + retc + + MOV [TempHandle],BX + TEST BYTE PTR FILSTAT,00100000B + JNZ GOTALLCOM + call Get_COMMAND ; dcl 8/23/86 + jnc Got_WCOM ;mt 12/8/86 P894 + ret + +Got_WCOM: + MOV BP,OFFSET command + TEST BYTE PTR FILSTAT,00010000B + JNZ PARTCOM + MOV WORD PTR [command.fileOffset],0 + MOV WORD PTR [command.fileOffset+2],0 + CALL GETSYS3 + retc + JMP SHORT COMDONE + +PARTCOM: + LES SI,[command.fileOffset] + MOV DI,ES + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + CALL GOTTARG + retc + JMP SHORT COMDONE + +GOTALLCOM: + LES SI,[command.fileSizeInBytes] + MOV DI,ES + push ds + MOV DS,[command.fileStartSegment] + assume ds:nothing + CALL WRITEFILE + pop ds + assume ds:data +COMDONE: + MOV BX,[TempHandle] + MOV CX,command.fileTime + MOV DX,command.fileDate + CALL CLOSETARG +;**************************************************************** +; I don't see the need for the following code!! - RS 3.20 +; CMP BYTE PTR [FILSTAT],00101010B +; JZ NOREDOS +;RDFRST2: +; CALL READDOS ; Start back with BIOS +; JNC NOREDOS +; CALL SYSPRM ;Prompt for system disk +; JMP RDFRST2 ;Try again +;NOREDOS: +;**************************************************************** + CLC + return + +;********************************************* +; Create a file on target disk +; CX = attributes, DX points to name +; DI:SI is size file is to have +; +; There is a bug in DOS 2.00 and 2.01 having to do with writes +; from the end of memory. In order to circumvent it this routine +; must create files with the length in DI:SI +; +; On return BX is handle, carry set if problem + +MAKEFIL: + MOV BX,DX + PUSH WORD PTR [BX] + MOV AL,DriveLetter + MOV [BX],AL + MOV AH,CREAT + INT 21H + POP WORD PTR [BX] + MOV BX,AX + JC CheckMany + MOV CX,DI + MOV DX,SI + MOV AX,LSEEK SHL 8 + INT 21H ; Seek to eventual EOF + XOR CX,CX + MOV AH,WRITE + INT 21H ; Set size of file to position + XOR CX,CX + MOV DX,CX + MOV AX,LSEEK SHL 8 + INT 21H ; Seek back to start + return + +; +; Examine error code in AX to see if it is too-many-open-files. +; If it is, we abort right here. Otherwise we return. +; +CheckMany: + CMP AX,error_too_many_open_files + retnz + lea dx, msgTooManyFilesOpen + call PrintString + JMP FEXIT + +;********************************************* +; Close a file on the target disk +; CX/DX is time/date, BX is handle + +CLOSETARG: + MOV AX,(FILE_TIMES SHL 8) OR 1 + INT 21H + MOV AH,CLOSE + INT 21H + return + +;**************************************** +; Transfer system files +; BP points to data structure for file involved +; offset is set to current amount read in +; Start set to start of file in buffer +; TempHandle is handle to write to on target + +IOLOOP: + MOV AL,[systemDriveLetter] + CMP AL,[DriveLetter] + JNZ GOTTARG + MOV AH,DISK_RESET + INT 21H + CALL TARGPRM ;Get target disk + +GOTTARG: +ASSUME DS:DATA +;Enter here if some of file is already in buffer, IOCNT must be set +; to size already in buffer. + MOV BX,[TempHandle] + MOV SI,WORD PTR [IOCNT] + MOV DI,WORD PTR [IOCNT+2] + push ds + MOV DS,ds:[BP.fileStartSegment] + assume ds:nothing + CALL WRITEFILE ; Write next part + pop ds + assume ds:data + retc + + LES AX,ds:[BP.fileOffset] + CMP AX,WORD PTR ds:[BP.fileSizeInBytes] + JNZ GETSYS3 + MOV AX,ES + CMP AX,WORD PTR ds:[BP.fileSizeInBytes+2] + JNZ GETSYS3 + return ; Carry clear from CMP + +GETSYS3: +;Enter here if none of file is in buffer + MOV AH,DISK_RESET + INT 21H + MOV AX,[MSTART] ;Furthur IO done starting here + MOV ds:[BP.fileStartSegment],AX + MOV AL,[systemDriveLetter] + CMP AL,[DriveLetter] + JNZ TESTSYS +GSYS: + MOV AH,DISK_RESET + INT 21H + CALL SYSPRM ;Prompt for system disk +TESTSYS: +; CALL TESTSYSDISK ; dcl 8/23/86 + JC GSYS + MOV BX,word ptr DS:[BP.fileHandle] ; CS over ARR 2.30 + LES DX,dword ptr DS:[BP.fileOffset] ; CS over ARR 2.30 + PUSH DX + MOV CX,ES + MOV AX,LSEEK SHL 8 + INT 21H + POP DX + LES SI,dword ptr DS:[BP.fileSizeInBytes] ; CS over ARR 2.30 + MOV DI,ES + SUB SI,DX + SBB DI,CX ; DI:SI is #bytes to go + PUSH DI + PUSH SI + ADD SI,15 + ADC DI,0 + CALL DISID4 + MOV AX,SI + POP SI + POP DI + CMP AX,[MSIZE] + JBE GOTSIZ2 + MOV SI,[MSIZE] + XOR DI,DI + CALL DISIX4 +GOTSIZ2: + MOV WORD PTR [IOCNT],SI + MOV WORD PTR [IOCNT+2],DI + push ds + MOV DS,[MSTART] + assume ds:nothing + CALL READFILE + pop ds + assume ds:data + JNC GETOFFS + CALL CLSALL + JMP GSYS +GETOFFS: + XOR DX,DX + MOV CX,DX + MOV AX,(LSEEK SHL 8) OR 1 + INT 21H + MOV WORD PTR DS:[BP.fileOffset],AX ; CS over ARR 2.30 + MOV WORD PTR DS:[BP.fileOffset+2],DX ; CS over ARR 2.30 + CALL CLSALL + JMP IOLOOP + +;************************************************* +; Test to see if correct system disk. Open handles + +CRET12: + STC + return + +;TESTSYSDISK: ; dcl 8/23/86 +Get_BIOS: ; dcl 8/23/86 + MOV AX,OPEN SHL 8 + MOV DX,OFFSET BiosFile + INT 21H + JNC SETBIOS +; call CheckMany ; dcl 8/23/86 + jmp CheckMany ; dcl 8/23/86 + +SETBIOS: + MOV [Bios.fileHandle],AX + MOV BX,AX + CALL GETFSIZ + CMP [bios.fileSizeInParagraphs],0 + JZ SETBIOSSIZ + CMP [bios.fileSizeInParagraphs],AX + JZ SETBIOSSIZ +BIOSCLS: + MOV AH,CLOSE + MOV BX,[Bios.fileHandle] + INT 21H +; JMP CRET12 ; dcl 8/23/86 + ret + +SETBIOSSIZ: + MOV [bios.fileSizeInParagraphs],AX + MOV WORD PTR [bios.fileSizeInBytes],SI + MOV WORD PTR [bios.fileSizeInBytes+2],DI + MOV [bios.fileDate],DX + MOV [bios.fileTime],CX + clc + ret ; dcl 8/23/86 + +Get_DOS: ; dcl 8/23/86 + MOV AX,OPEN SHL 8 + MOV DX,OFFSET DosFile + INT 21H + JNC DOSOPNOK +; call CheckMany ; dcl 8/23/86 +; JMP BIOSCLS ; dcl 8/23/86 Checkmany no ret. + jmp CheckMany ; dcl 8/23/86 + +DOSOPNOK: + MOV [dos.fileHandle],AX + MOV BX,AX + CALL GETFSIZ + CMP [dos.fileSizeInParagraphs],0 + JZ SETDOSSIZ + CMP [dos.fileSizeInParagraphs],AX + JZ SETDOSSIZ + +DOSCLS: + MOV AH,CLOSE + MOV BX,[dos.fileHandle] + INT 21H +; JMP BIOSCLS ; dcl 8/23/86 + ret ; dcl 8/23/86 + +SETDOSSIZ: + MOV [dos.fileSizeInParagraphs],AX + MOV WORD PTR [dos.fileSizeInBytes],SI + MOV WORD PTR [dos.fileSizeInBytes+2],DI + MOV [dos.fileDate],DX + MOV [dos.fileTime],CX + clc + ret ; dcl 8/23/86 + +Get_COMMAND: + MOV AX,OPEN SHL 8 + MOV DX,OFFSET CommandFile + INT 21H + JNC GotComHand +; call CheckMany ; dcl 8/23/86 +; JMP DosCls ; dcl 8/23/86 + jmp Checkmany ; dcl 8/23/86 + +GotComHand: + MOV [command.fileHandle],AX + MOV BX,AX + CALL GETFSIZ + CMP [command.fileSizeInParagraphs],0 + JZ SETCOMSIZ + CMP [command.fileSizeInParagraphs],AX + JZ SETCOMSIZ +COMCLS: + MOV AH,CLOSE + MOV BX,[command.fileHandle] + INT 21H +; JMP DOSCLS ; dcl 8/23/86 + ret ; dcl 8/23/86 + +SETCOMSIZ: + MOV [command.fileSizeInParagraphs],AX + MOV WORD PTR [command.fileSizeInBytes],SI + MOV WORD PTR [command.fileSizeInBytes+2],DI + MOV [command.fileDate],DX + MOV [command.fileTime],CX + CLC + return + +FILE_CLS: ; dcl 8/23/86 + MOV AH,CLOSE ; dcl 8/23/86 + INT 21H ; dcl 8/23/86 + ret ; dcl 8/23/86 + +;******************************************* +; Handle in BX, return file size in para in AX +; File size in bytes DI:SI, file date in DX, file +; time in CX. + +GETFSIZ: + MOV AX,(LSEEK SHL 8) OR 2 + XOR CX,CX + MOV DX,CX + INT 21H + MOV SI,AX + MOV DI,DX + ADD AX,15 ; Para round up + ADC DX,0 + AND DX,0FH ; If the file is larger than this it + ; is bigger than the 8086 address + ; space! + MOV CL,12 + SHL DX,CL + MOV CL,4 + SHR AX,CL + OR AX,DX + PUSH AX + MOV AX,LSEEK SHL 8 + XOR CX,CX + MOV DX,CX + INT 21H + MOV AX,FILE_TIMES SHL 8 + INT 21H + POP AX + return + +;******************************************** +; Read/Write file +; DS:0 is Xaddr +; DI:SI is byte count to I/O +; BX is handle +; Carry set if screw up +; +; I/O SI bytes +; I/O 64K - 1 bytes DI times +; I/O DI bytes + + +READFILE: +; Must preserve AX,DX + PUSH AX + PUSH DX + PUSH BP + MOV BP,READ SHL 8 + CALL FILIO + POP BP + POP DX + POP AX + return + +WRITEFILE: + PUSH BP + MOV BP,WRITE SHL 8 + CALL FILIO + POP BP + return + +FILIO: + XOR DX,DX + MOV CX,SI + JCXZ K64IO + MOV AX,BP + INT 21H + retc + ADD DX,AX + CMP AX,CX ; If not =, AX= 4086) +; +Phase1Initialisation proc near + +; Get device parameters + lea dx, deviceParameters + mov deviceParameters.DP_SpecialFunctions, 0 + call GetDeviceParameters + jnc GotDeviceParameters + lea dx, ptr_msgFormatNotSupported + call std_printf + jmp fexit +GotDeviceParameters: + +; Save the device parameters for when we exit + lea si, deviceParameters + lea di, savedDeviceParameters + mov cx, size a_DeviceParameters + push ds + pop es + rep movsb + +; Ensure that there is a valid number of sectors in the track table + mov savedDeviceParameters.DP_TrackTableEntries, 0 + mov validSavedDeviceParameters, 1 + +; Initialise this to zero to know if CheckSwitches defined the track layout + mov deviceParameters.DP_TrackTableEntries, 0 + +; Detect whether "set media type" is supported +; test DeviceParameters.DeviceAttributes, SetMediaType +; jnz SetMTsupp + +SetMTsupp: + +; Check switches against parameters and use switches to modify device parameters + call CheckSwitches + retc + + cmp deviceParameters.DP_TrackTableEntries, 0 + jne TrackLayoutSet ; There is a good track layout + +; Store sector table info + mov cx, deviceParameters.DP_BPB.BPB_SectorsPerTrack + mov deviceParameters.DP_TrackTableEntries, cx + mov ax, 1 + mov bx, deviceParameters.DP_BPB.BPB_bytesPerSector + lea di, deviceParameters.DP_SectorTable +LoadSectorTable: + stosw + xchg ax, bx + stosw + xchg ax, bx + inc ax + loop LoadSectorTable +TrackLayoutSet: + +; +; directorySector = malloc( Bytes Per Sector ) +; + mov bx, deviceParameters.DP_BPB.BPB_BytesPerSector + add bx, 0fH + shr bx, 1 + shr bx, 1 + shr bx, 1 + shr bx, 1 + mov ah, Alloc + int 21H + retc + mov word ptr directorySector+2, ax + xor ax,ax + mov word ptr directorySector, ax + +; +; fatSpace = malloc( Bytes Per Sector * Sectors Per FAT ) +; + mov ax, deviceParameters.DP_BPB.BPB_BytesPerSector + mul deviceParameters.DP_BPB.BPB_SectorsPerFAT + add ax, 0fH + shr ax, 1 + shr ax, 1 + shr ax, 1 + shr ax, 1 + mov bx, ax + mov ah, Alloc + int 21H + retc + mov word ptr fatSpace+2, ax + xor ax, ax + mov word ptr fatSpace, ax + + call SetStartSector + call SetfBigFat + + clc + return + +Phase1Initialisation endp + +;------------------------------------------------------------------------------- + +SetStartSector proc near + +; startSector = number of reserved sectors +; + number of FAT Sectors ( Number of FATS * Sectors Per FAT ) +; + number of directory sectors ( 32* Root Entries / bytes Per Sector ) +; ( above is rounded up ) + +; Calculate the number of directory sectors + mov ax, deviceParameters.DP_BPB.BPB_RootEntries + mov bx, size dir_entry + mul bx + add ax, deviceParameters.DP_BPB.BPB_bytesPerSector + dec ax + xor dx,dx + div deviceParameters.DP_BPB.BPB_bytesPerSector + mov sectorsInRootDirectory,ax + mov startSector, ax + +; Calculate the number of FAT sectors + mov ax, deviceParameters.DP_BPB.BPB_SectorsPerFAT + mul deviceParameters.DP_BPB.BPB_numberOfFATs +; Add in the number of boot sectors + add ax, deviceParameters.DP_BPB.BPB_ReservedSectors + add startSector, ax + + return + +SetStartSector endp + +;------------------------------------------------------------------------------- + +SetfBigFat proc near +; +; fBigFat = ( ( (Total Sectors - Start Sector) / Sectors Per Cluster) >= 4086 ) +; + mov ax, deviceParameters.DP_BPB.BPB_TotalSectors + + +;************************* Fix for PTM PCDOS P51 + + ; + ; Old code + ; + ;cmp ax,20740 + ;jbe SmallFAT + ;mov fBigFat, TRUE + + ; + ; New Code + ; + + sub ax,startSector ;Get sectors in data area + xor dx,dx + xor bx,bx + mov bl,deviceParameters.DP_BPB.BPB_sectorsPerCluster + div bx ;Get total clusters + cmp ax,BIG_FAT_THRESHOLD ;Is clusters < 4086? + jb SmallFAT ;12 bit FAT if so + mov fBigFAT,TRUE ;16 bit FAT if >=4096 + +;************************* END of fix for PTM PCDOS P51 + +SmallFAT: + + return + +SetfBigFat endp + +;------------------------------------------------------------------------------- +; +; Phase2Initialisation: +; Use device parameters to build information that will be +; required for each format +; +; Algorithm: +; Calculate first head/cylinder to format +; Calculate number of tracks to format +; Calculate the total bytes on the disk and save for later printout +; First initialise the directory buffer +; +Phase2Initialisation proc near + +; Calculate first track/head to format (round up - kludge) + mov ax, deviceParameters.DP_BPB.BPB_HiddenSectors + mov dx, deviceParameters.DP_BPB.BPB_HiddenSectors + 2 + add ax, deviceParameters.DP_BPB.BPB_SectorsPerTrack + adc dx, 0 + dec ax + sbb dx, 0 + div deviceParameters.DP_BPB.BPB_SectorsPerTrack + xor dx,dx + div deviceParameters.DP_BPB.BPB_Heads + mov firstCylinder, ax + mov firstHead, dx + +; Calculate the total number of tracks to be formatted (round down - kludge) + mov ax, deviceParameters.DP_BPB.BPB_TotalSectors + xor dx,dx +; if (TotalSectors == 0) then use BigTotalSectors + or ax,ax + jnz NotBigTotalSectors + mov ax, deviceParameters.DP_BPB.BPB_BigTotalSectors + mov dx, deviceParameters.DP_BPB.BPB_BigTotalSectors + 2 + +NotBigTotalSectors: + div deviceParameters.DP_BPB.BPB_SectorsPerTrack + mov tracksPerDisk, ax + +; Initialise the directory buffer +; Clear out the Directory Sector before any information is inserted. + mov cx, deviceParameters.DP_BPB.BPB_BytesPerSector + les di, directorySector + xor ax,ax + rep stosb + + mov ax, deviceParameters.DP_BPB.BPB_BytesPerSector + xor dx, dx + mov bx, size dir_entry + div bx + mov cx, ax + + les bx, directorySector +; If Old_Dir = TRUE then put the first letter of each directory entry must be 0E5H + xor al, al + cmp old_Dir, TRUE + jne StickE5 + mov al, 0e5H +StickE5: + mov es:[bx], al + add bx, size dir_entry + loop stickE5 + +; +; fDskSiz = (Total Sectors - Start Sector) * Bytes Per Sector +; + mov ax, deviceParameters.DP_BPB.BPB_TotalSectors + sub ax, startSector + mul deviceParameters.DP_BPB.BPB_BytesPerSector + mov word ptr fDskSiz, ax + mov word ptr fDskSiz+2, dx + + return + +Phase2Initialisation endp + +;------------------------------------------------------------------------------- +; +; SetDeviceParameters: +; Set the device parameters +; +; Input: +; drive +; dx - pointer to device parameters +; +SetDeviceParameters proc near + + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + mov bl, drive + inc bl + mov cx, (RAWIO shl 8) or SET_DEVICE_PARAMETERS + int 21H + return + +SetDeviceParameters endp + +;------------------------------------------------------------------------------- +; +; GetDeviceParameters: +; Get the device parameters +; +; Input: +; drive +; dx - pointer to device parameters +; +GetDeviceParameters proc near + + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + mov bl, drive + inc bl + mov cx, (RAWIO shl 8) or GET_DEVICE_PARAMETERS + int 21H + return + +GetDeviceParameters endp + +;------------------------------------------------------------------------------- +; +; DiskFormat: +; Format the tracks on the disk +; Since we do our SetDeviceParameters here, we also need to +; detect the legality of /N /T if present and abort with errors +; if not. +; This routine stops as soon as it encounters a bad track +; Then BadSector is called to report the bad track, and it continues +; the format +; +; Algorithm: +; Initialise in memory FAT +; current track = first +; while not done +; if format track fails +; DiskFormatErrors = true +; return +; next track + +DiskFormat proc near + + +; +; Initialise fatSpace +; + push es + les di, fatSpace + mov ax, deviceParameters.DP_BPB.BPB_SectorsPerFAT + mul deviceParameters.DP_BPB.BPB_bytesPerSector + mov cx, ax + xor ax,ax + rep stosb + + mov di, word ptr fatSpace + mov al, deviceParameters.DP_BPB.BPB_MediaDescriptor + mov ah, 0ffH + stosw + mov ax, 00ffH + test fBigFat, TRUE + jz NotBig + mov ax, 0ffffH +NotBig: stosw + pop es + +; don't bother to do the formatting if /c was given + test switchmap, SWITCH_C + jz Keep_Going + jmp FormatDone ;FormatDone is to far away + +Keep_Going: +foofoo = INSTALL_FAKE_BPB or TRACKLAYOUT_IS_GOOD + mov deviceParameters.DP_SpecialFunctions, foofoo + lea dx, deviceParameters + + call SetDeviceParameters + + test switchmap, SWITCH_H ;Suppress prompt? + jnz No_Prompt + + call DSKPRM ; prompt user for disk + +No_Prompt: + test switchmap,switch_8 ; DCL 5/12/86 avoid Naples AH=18h + jnz stdBpB ; lackof support for 8 sectors/track + + ; DCL 5/12/86 + ; Always do the STATUS_FOR_FORMAT test, as we don't know if the machine + ; has this support. For 3.2 /N: & /T: were not documented & therefore + ; not fully supported thru the ROM of Aquarius & Naples & Royal Palm + + ;test SwitchMap, SWITCH_N or SWITCH_T ; IF ( /N or /T ) ;; DCL 5/12/86 + ;jz StdBPB + ; THEN check if + ; supported + mov formatPacket.FP_SpecialFunctions, STATUS_FOR_FORMAT + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + mov bl, drive + inc bl + mov cx, (RAWIO shl 8) or FORMAT_TRACK + lea dx, formatPacket + int 21H + ; switch ( FormatStatusCall) + + ;cmp FormatPacket.FP_SpecialFunctions, Format_No_ROM_Support + ;jb NTSupported ; 0 returned from IO.SYS + ;ja IllegalComb ; 2 returned - ROM Support + ; Illegal Combination! + cmp FormatPacket.FP_SpecialFunctions,0 + je NTSupported + lea dx, msgInvalidParameter + cmp FormatPacket.FP_SpecialFunctions,2 + je Abort_Prog + lea dx, msgNotReady + cmp FormatPacket.FP_SpecialFunctions,3 + je Abort_Prog + + ; DCL No ROM support is okay + ; except for /N: & /T: + test SwitchMap, SWITCH_N or SWITCH_T ; DCL 5/12/86 + jz StdBPB + lea dx, msgParametersNotSupported ; CASE: NOT SUPPORTED + +Abort_Prog: + Call PrintString + jmp Fexit +; +; We have the support to carry out the FORMAT +; +NTSupported: +StdBPB: + ;call DSKPRM ; prompt user for disk ;; DCL 5/12/86 + mov FormatPacket.FP_SpecialFunctions, 0 + mov ax, firstHead + mov formatPacket.FP_Head, ax + mov ax, firstCylinder + mov formatPacket.FP_Cylinder, ax + mov cx, tracksPerDisk + dec cx + mov tracksLeft, cx +FormatLoop: + call DisplayCurrentTrack + call FormatTrack + jc FailDiskFormat + call NextTrack + jnc FormatLoop + +; All done +FormatDone: + mov formatError, 0 + clc + return + +FailDiskFormat: + call CheckError + retc + call LastChanceToSaveIt + jc FormatReallyFailed + + call SetStartSector + call SetfBigFat + push ax + call Phase2Initialisation + clc + pop ax +; jc FormatReallyFailed + jmp DiskFormat + +FormatReallyFailed: + mov formatError, 1 + clc + return + +DiskFormat endp + + +;------------------------------------------------------------------------------- +; +; BadSector: +; Reports the bad sectors. +; Reports the track where DiskFormat stopped. +; From then on it formats until it reaches a bad track, or end, +; and reports that. +; +; Output: +; Carry: set --> fatal error +; if Carry not set +; ax - The number of consecutive bad sectors encountered +; ax == 0 --> no more bad sectors +; bx - The logical sector number of the first bad sector +; +; Algorithm: +; if DiskFormatErrors +; DiskFormatErrors = false +; return current track +; else +; next track +; while not done +; if format track fails +; return current track +; next track +; return 0 + +BadSector proc near + + +; don't bother to do the formatting if /c was given + test switchmap, SWITCH_C + jnz NoMoreTracks + + test formatError, 0ffH + jz ContinueFormat + mov formatError, 0 + jmp ReportBadTrack + +ContinueFormat: + call NextTrack + jc NoMoreTracks + + call DisplayCurrentTrack + call FormatTrack + jnc ContinueFormat + call CheckError + retc + +ReportBadTrack: + call CurrentLogicalSector + mov ax, deviceParameters.DP_BPB.BPB_SectorsPerTrack + clc + return + +NoMoreTracks: + lea dx, msgFormatComplete + call PrintString + mov ax, 0 + clc + return + +BadSector endp + + +;------------------------------------------------------------------------------- +; FormatTrack: +; format the current track +; +; Input: +; formatPacket +; +; Output: +; Carry: set if format failed +; +FormatTrack proc near + + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + mov bl, drive + inc bl + mov cx, (RAWIO shl 8) or FORMAT_TRACK + lea dx, formatPacket + int 21H + retnc + + mov ah, 59H + xor bx,bx + int 21H + stc + return + +FormatTrack endp + +;------------------------------------------------------------------------------- + +data segment + +ptr_msgCurrentTrack dw offset msgCurrentTrack +currentHead dw 0 +currentCylinder dw 0 + +data ends + +DisplayCurrentTrack proc near + + mov ax, formatPacket.FP_Cylinder + mov currentCylinder, ax + mov ax, formatPacket.FP_Head + mov currentHead, ax + lea dx, ptr_msgCurrentTrack + call std_printf + return + +DisplayCurrentTrack endp + +;------------------------------------------------------------------------------- +; NextTrack: +; Advance to the next track for formatting +; +; Input: +; formatPacket.FP_Head +; formatPacket.FP_Cylinder +; deviceParameters.DP_BPB.BPB_Heads +; tracksLeft +; +; Output: +; Carry: set --> all done +; formatPacket.FP_Head +; formatPacket.FP_cyliner +; tracksLeft +; +; Algorithm: +; if tracksLeft +; tracksLeft-- +; if ++head > highest head +; head = 0 +; cylinder++ +; +NextTrack proc near + + cmp tracksLeft, 0 + je ThatsAllFolks + dec tracksLeft + +; Bump the head + inc formatPacket.FP_Head + mov ax, formatPacket.FP_Head + cmp ax, deviceParameters.DP_BPB.BPB_Heads + jb ExitNextTrack + +; We've done all heads on this cylinder so move on to next +; (start on head 0 of the next cylinder) + mov formatPacket.FP_Head, 0 + inc formatPacket.FP_Cylinder + +ExitNextTrack: + clc + return + +ThatsAllFolks: +; Oh wow, we're all done + stc + return + +NextTrack endp + +;------------------------------------------------------------------------------- +; CheckError: +; Input: +; ax - extended error code +; Ouput: +; carry set if error is fatal +; Message printed if Not Ready or Write Protect +; +CheckError proc near + cmp ax, error_write_protect + je WriteProtectError + cmp ax, error_not_ready + je NotReadyError + cmp currentCylinder, 0 + jne CheckRealErrors + cmp currentHead, 0 + je BadTrackZero + +CheckRealErrors: + cmp ax, error_CRC + je JustABadTrack + cmp ax, error_sector_not_found + je JustABadTrack + cmp ax, error_write_fault + je JustABadTrack + cmp ax, error_read_fault + je JustABadTrack + cmp ax, error_gen_failure + je JustABadTrack + + stc + ret + +JustABadTrack: + clc + ret + +WriteProtectError: + lea dx, msgWriteProtected + call PrintString + stc + ret + +NotReadyError: + lea dx, msgNotReady + call PrintString + stc + ret + +BadTrackZero: + lea dx, msgDiskUnusable + call PrintString + stc + ret + +CheckError endp + +;------------------------------------------------------------------------------- +; WriteFileSystem: +; Write the boot sector and FATs out to disk +; Clear the directory sectors to zero +; +WriteFileSystem proc near + + + call WriteBootSector + retc + +; Write out each of the FATs + xor cx, cx + mov cl, deviceParameters.DP_BPB.BPB_numberOfFATs + mov dx, deviceParameters.DP_BPB.BPB_ReservedSectors +WriteFATloop: + push cx + push dx + mov al, drive + mov cx, deviceParameters.DP_BPB.BPB_SectorsPerFAT + push ds + lds bx, fatSpace + int 26H + pop ax + pop ds + jc CanNotWriteFAT + + pop dx + add dx, deviceParameters.DP_BPB.BPB_SectorsPerFAT + pop cx + loop WriteFATLoop + +; Clear the directory + +; Now write the initialised directory sectors out to disk + mov ax, deviceParameters.DP_BPB.BPB_SectorsPerFAT + xor dx,dx + mul deviceParameters.DP_BPB.BPB_NumberOfFATs + mov dx, deviceParameters.DP_BPB.BPB_ReservedSectors + add dx, ax + mov cx, sectorsInRootDirectory +WriteDIRloop: + push cx + push dx + mov al, drive + mov cx, 1 + push ds + lds bx, directorySector + int 26H + pop ax + pop ds + jc CanNotWriteDirectory + + pop dx + add dx, 1 + pop cx + loop WriteDIRLoop + + +; Ok, we can tell the device driver that we are finished formatting + mov savedDeviceParameters.DP_TrackTableEntries, 0 + mov savedDeviceParameters.DP_SpecialFunctions, TRACKLAYOUT_IS_GOOD + lea dx, savedDeviceParameters + call SetDeviceParameters + + MOV AH,DISK_RESET ; Flush any directories in + INT 21H ; buffers + + return + +CanNotWriteFAT: + lea dx, msgFATwriteError + jmp PrintErrorAbort + +CanNotWriteDirectory: + lea dx, msgDirectorywriteError + jmp PrintErrorAbort + +WriteFileSystem endp + +;------------------------------------------------------------------------------- +; Done: +; format is done... so clean up the disk! +; +Done proc near + + + call OemDone + return + +Done endp + +;------------------------------------------------------------------------------- +; CurrentLogicalSector: +; Get the current logical sector number +; +; Input: +; current track = tracksPerDisk - tracksLeft +; SectorsPerTrack +; +; Output: +; BX = logical sector number of the first sector in the track we +; just tried to format +; +CurrentLogicalSector proc near + mov ax, tracksPerDisk + sub ax, tracksLeft + dec ax + mul deviceParameters.DP_BPB.BPB_SectorsPerTrack + mov bx, ax + return + +CurrentLogicalSector endp + +;------------------------------------------------------------------------------- +; PrintErrorAbort: +; Print an error message and abort +; +; Input: +; dx - Pointer to error message string +; +PrintErrorAbort proc near + + push dx + call crlf + pop dx + call PrintString + + jmp fexit + +PrintErrorAbort endp + +code ends + + END START diff --git a/SRC/CMD/FORMAT/FORMAT.LNK b/SRC/CMD/FORMAT/FORMAT.LNK new file mode 100644 index 0000000..6b68295 --- /dev/null +++ b/SRC/CMD/FORMAT/FORMAT.LNK @@ -0,0 +1,2 @@ +format.obj forproc.obj messages.obj oemfor.obj ..\..\libc\printf.obj +format.exe /m; diff --git a/SRC/CMD/FORMAT/FORPROC.ASM b/SRC/CMD/FORMAT/FORPROC.ASM new file mode 100644 index 0000000..88c12f4 --- /dev/null +++ b/SRC/CMD/FORMAT/FORPROC.ASM @@ -0,0 +1,141 @@ +; SCCSID = @(#)forproc.asm 1.2 85/07/25 +.xlist +.xcref +BREAK MACRO subtitle + SUBTTL subtitle + PAGE +ENDM + + INCLUDE SYSCALL.INC +.cref +.list +data segment public 'DATA' +data ends + +code segment public 'CODE' + assume cs:code,ds:data + + PUBLIC FormatAnother?,Yes?,REPORT,USER_STRING + public fdsksiz,badsiz,syssiz,datasiz,biosiz + + extrn std_printf:near,crlf:near,PrintString:near + +data segment + extrn driveLetter:byte + +; In formes.asm + extrn msgInsertDisk:byte + extrn msgFormatAnother?:byte + extrn msgTotalDiskSpace:byte + extrn msgSystemSpace:byte + extrn msgBadSpace:byte + extrn msgDataSpace:byte + extrn yes_byte:byte + extrn no_byte:byte + + extrn inbuff:byte + +ptr_msgTotalDiskSpace dw offset msgTotalDiskSpace +fdsksiz dd 0 + +ptr_msgSystemSpace dw offset msgSystemSpace +syssiz dd 0 +biosiz dd 0 + +ptr_msgBadSpace dw offset msgBadSpace +badsiz dd 0 + +ptr_msgDataSpace dw offset msgDataSpace +datasiz dd 0 + +ptr_msgInsertDisk dw offset msgInsertDisk + dw offset driveLetter +data ends + +FormatAnother? proc near +; Wait for key. If yes return carry clear, else no. Insures +; explicit Y or N answer. + lea dx, msgFormatAnother? + call PrintString + CALL Yes? + JNC WAIT20 + JZ WAIT20 + CALL CRLF + JMP SHORT FormatAnother? +FormatAnother? endp + +Yes? proc near + +; Wait for key. If YES return carry clear,else carry set. +; If carry is set, Z is set if explicit NO, else key was not Yes or No. + CALL USER_STRING + JNZ GETBYT + XOR AL,AL ; So that CMP with [NO_BYTE] is NZ + JMP SHORT CHECK_NO + +GETBYT: + MOV AL,BYTE PTR [INBUFF+2] + OR AL,20H ; Convert to lower case + CMP AL,[YES_BYTE] + JZ WAIT20 ; Carry clear if jump +CHECK_NO: + CMP AL,[NO_BYTE] + STC ; Set carry (wasn't Yes) +WAIT20: RET + +Yes? endp + +USER_STRING: +; Get a string from user. Z is set if user typed no chars (imm CR) +; We need to flush a second time to get rid of incoming Kanji characters also. + MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0 ; Clean out input + INT 21H + MOV DX,OFFSET INBUFF + MOV AH,STD_CON_STRING_INPUT + INT 21H + MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0 ; Clean out input + INT 21H + CMP BYTE PTR [INBUFF+1],0 + RET + +;********************************************* +; Make a status report including the following information: +; Total disk capacity +; Total system area used +; Total bad space allocated +; Total data space available + +REPORT: + lea dx, ptr_msgTotalDiskSpace + call std_printf + cmp WORD PTR SYSSIZ,0 + JNZ SHOWSYS + cmp WORD PTR SYSSIZ+2,0 + JZ CHKBAD +SHOWSYS: + MOV dx,OFFSET ptr_msgSystemSpace + CALL std_printf ;Report space used by system +CHKBAD: + cmp WORD PTR BADSIZ,0 + JNZ SHOWBAD + cmp WORD PTR BADSIZ+2,0 + JZ SHOWDATA +SHOWBAD: + lea dx, ptr_msgBadSpace + call std_printf +SHOWDATA: + MOV CX,WORD PTR FDSKSIZ + MOV BX,WORD PTR FDSKSIZ+2 + SUB CX,WORD PTR BADSIZ + SBB BX,WORD PTR BADSIZ+2 + SUB CX,WORD PTR SYSSIZ + SBB BX,WORD PTR SYSSIZ+2 + MOV word ptr datasiz,CX + MOV word ptr datasiz+2,BX + lea dx, ptr_msgDataSpace + call std_printf + call crlf + RET + +code ends + end diff --git a/SRC/CMD/FORMAT/MAKEFILE b/SRC/CMD/FORMAT/MAKEFILE new file mode 100644 index 0000000..7d5e68d --- /dev/null +++ b/SRC/CMD/FORMAT/MAKEFILE @@ -0,0 +1,58 @@ +#** makefile for format + +DEST =format +MSG =messages + +# Path definitions + +BIOS =..\..\BIOS +BOOT =..\..\BOOT +DOS =..\..\DOS + +# Definitions for assembler + +ASM =masm +AFLAGS =-Mx -t +AINC =-I..\..\inc -I$(DOS) + +# Definitions for C compiler + +CC =cl +CFLAGS =-c -Ox -Zlp +CINC =-I..\..\h + +# Definitions for linker + +LINK =link +LIBC =..\..\libc + + +# Rules and Dependencies follow + +filesize.inc: $(DOS)\msdos.sys $(BIOS)\io.sys + GWBASIC MAKE_INC + +FORMAT.OBJ: FORMAT.ASM $(DOS)\DOSMAC.INC $(DOS)\BPB.INC \ + $(DOS)\DIRENT.INC $(DOS)\DPB.INC $(DOS)\CURDIR.INC \ + $(DOS)\CPMFCB.INC $(DOS)\PDB.INC \ + $(DOS)\ERROR.INC $(DOS)\SYSCALL.INC $(DOS)\IOCTL.INC + masm $(AFLAGS) $(AINC) FORMAT; + +$(MSG).OBJ: $(MSG).ASM $(MSG).inc + masm $(AFLAGS) $(AINC) $(MSG); + +FORPROC.OBJ: FORPROC.ASM $(DOS)\SYSCALL.INC + masm $(AFLAGS) $(AINC) FORPROC; + +OEMFOR.OBJ: OEMFOR.ASM $(DOS)\DOSMAC.INC $(DOS)\SYSCALL.INC $(DOS)\BPB.INC \ + $(DOS)\DIRENT.INC bootmes.inc $(DOS)\IOCTL.INC \ + $(BOOT)\BOOT.INC $(BOOT)\BOOT11.INC filesize.inc + masm $(AFLAGS) $(AINC) OEMFOR; + +$(LIBC)\printf.obj: $(LIBC)\printf.asm + masm $(AFLAGS) $(AINC) $(LIBC)\printf,$(LIBC)\printf; + +FORMAT.EXE: FORMAT.OBJ FORPROC.OBJ $(MSG).OBJ OEMFOR.OBJ $(LIBC)\PRINTF.OBJ + LINK @FORMAT.LNK + convert format.exe + del format.exe diff --git a/SRC/CMD/FORMAT/MAKE_INC.BAS b/SRC/CMD/FORMAT/MAKE_INC.BAS new file mode 100644 index 0000000000000000000000000000000000000000..96fc13dfbff8b94bd6e66a7e63e6d92170e4b27c GIT binary patch literal 1072 zcmaJ=&ubGw6du%Ssuf{3n?vm3xhiHMEY#{r6dM~f&>CTrgHq5$ao zhL^R660*vAn%8wiwO@%1K3b7})TbesrXIyC=)P9jHz+}-t!eL)8|(&HS9!I1Bq?x< z4wgfsgc&j{F{glCC~CWIcdMW1d}eYYaU!!}JN}_d+w+f%M%Bz+$uEYxmH9T&111F= c-@|!uad<3%7A4^!)X7}f|Mwn3DBI8e1DaPsDF6Tf literal 0 HcmV?d00001 diff --git a/SRC/CMD/FORMAT/MESSAGES.ASM b/SRC/CMD/FORMAT/MESSAGES.ASM new file mode 100644 index 0000000..1dabff5 --- /dev/null +++ b/SRC/CMD/FORMAT/MESSAGES.ASM @@ -0,0 +1,68 @@ +; SCCSID = @(#)messages.asm 1.10 85/08/13 +TITLE FORMAT Messages + +data segment public 'DATA' + + public Yes_Byte + public No_Byte + public msgCRLF + public msgCurrentTrack + public msgSystemTransfered + public msgFormatComplete + public msgInterrupt + public msgInsertDisk + public msgHardDiskWarning + public msgFormatAnother? + public msgInsertDosDisk + public msgReInsertDisk + public msgLabelPrompt + public msgTotalDiskSpace + public msgSystemSpace + public msgBadSpace + public msgDataSpace + public msgFormatNotSupported + public msgInvalidDeviceParameters + public msgErrorInIOCTL + public msgNotBlockDevice + public msgFATwriteError + public msgDirectoryWriteError + public msgAssignedDrive + public msgNeedDrive + public msgBadDosVersion + public msgNoSystemFiles + public msgTooManyFilesOpen + public msgNetDrive + public msgBadCharacters + public msgBadDrive + public msgInvalidParameter + public msgParametersNotSupported + public msgFormatFailure + public msgNotSystemDisk +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +; reintroduce following public for fix +; public msgNoRoomDestDisk +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + public msgDiskUnusable + public msgOutOfMemory + public msgWriteProtected + public msgNotReady + public msgBootWriteError + public msgDirectoryReadError + public msgBadVolumeId + public msgWhatIsVolumeId? + public msgIncompatibleParameters + public msgIncompatibleParametersForHardDisk + public msgBadPartitionTable + public msgParametersNotSupportedByDrive + public msgPartitionTableReadError + public msgPartitionTableWriteError + +CR equ 13 +LF equ 10 + +; Oem dependent messages + + include messages.inc + +data ends + END diff --git a/SRC/CMD/FORMAT/MESSAGES.INC b/SRC/CMD/FORMAT/MESSAGES.INC new file mode 100644 index 0000000..41815d5 --- /dev/null +++ b/SRC/CMD/FORMAT/MESSAGES.INC @@ -0,0 +1,139 @@ +; SCCSID = @(#)messages.inc 1.6 85/08/02 + +DEBUG EQU 0 ; for Boot sector installation check + +IF DEBUG + public msgFormatBroken +ENDIF + +; THE FOLLOWING ONE BYTE CHARACTERS ARE THE PROMPT ANSWERS. +; THEY MUST BE LOWER CASE, AND THE UPPER TO LOWER, OR LOWER +; TO LOWER CONVERSION MUST BE DOABLE BY "OR AL,20h". +; Yes/No Answers + +Yes_Byte db "y" +No_Byte db "n" + +msgCRLF db CR, LF, 0 + +; Status messages + +msgCurrentTrack db "Head: %3d Cylinder: %4d", CR, 0 + +msgSystemTransfered db "System transferred",CR,LF,0 + +msgInterrupt db 13,10, 10, 0 + +; Note: This message must be long enough to wipe out message msgCurrentTrack +msgFormatComplete db "Format complete ",CR,LF,0 + +; Prompts + +msgInsertDisk db "Insert new diskette for drive %c:",CR,LF + db "and strike ENTER when ready",0 + +msgHardDiskWarning db CR,LF + db "WARNING, ALL DATA ON NON-REMOVABLE DISK",CR,LF + db "DRIVE %c: WILL BE LOST!",CR,LF + db "Proceed with Format (Y/N)?",0 + +msgFormatAnother? db "Format another (Y/N)?",0 + +msgInsertDosDisk db "Insert DOS disk in drive %c:", CR, LF + db "and strike ENTER when ready", CR, LF, 0 + +msgReInsertDisk db "Re-insert diskette for drive %c:",0 + +msgLabelPrompt db "Volume label (11 characters, ENTER for none)? ",0 + +; Disk usage messages + +msgTotalDiskSpace db "%l10d bytes total disk space", CR, LF, 0 + +msgSystemSpace db "%l10d bytes used by system", CR, LF, 0 + +msgBadSpace db "%l10d bytes in bad sectors", CR, LF, 0 + +msgDataSpace db "%l10d bytes available on disk",CR,LF,0 + +; Error messages + +msgFormatNotSupported db "Format not supported on drive %c:", CR,LF,0 + +msgInvalidDeviceParameters db "Invalid device parameters from device driver" + db CR, LF, 0 + +msgErrorInIOCTL db "Error in IOCTL call", CR, LF, 0 + +msgNotBlockDevice db "Not a block device", CR, LF, 0 + +msgFATwriteError db "Error writing FAT", CR, LF, 0 + +msgDirectoryWriteError db "Error writing directory", CR, LF, 0 + +msgAssignedDrive db "Cannot format an ASSIGNed or SUBSTed drive. ", CR, LF, 0 + +msgNeedDrive db "Drive letter must be specified",CR,LF,0 + +msgBadDosVersion db "Incorrect DOS version",CR,LF,"$" + +msgNoSystemFiles db "Cannot find System Files",CR,LF,0 + +msgTooManyFilesOpen db "Too many open files",CR,LF,0 + +msgNetDrive db "Cannot FORMAT a Network drive", CR, LF, 0 + +msgBadCharacters db "Invalid characters in volume label", CR, LF, 0 + +msgBadDrive db "Invalid drive specification", CR, LF, 0 + +msgInvalidParameter db "Invalid parameter", CR, LF, 0 + +msgParametersNotSupported db "Parameters not supported",CR,LF,0 + +; Note: This message must be long enough to wipe out message msgCurrentTrack +msgFormatFailure db "Format failure ",CR,LF,0 + +msgNotSystemDisk db "Disk unsuitable for system disk", CR, LF, 0 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp +; reintroduce following message for fix +;msgNoRoomDestDisk db "No room for system on destination disk", CR, LF, 0 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;bug007sp + +msgDiskUnusable db "Invalid media or Track 0 bad - disk unusable", CR, LF, 0 + +msgOutOfMemory db "Insufficient memory for system transfer", CR, LF, 0 + +; Note: This message must be long enough to wipe out message msgCurrentTrack +msgWriteProtected db "Attempted write-protect violation", CR, LF, 0 + +; Note: This message must be long enough to wipe out message msgCurrentTrack +msgNotReady db "Drive not ready ", CR, LF, 0 + + +msgBootWriteError db "Unable to write BOOT", CR, LF, 0 + +msgDirectoryReadError db "Error reading directory", CR, LF, 0 + +msgBadVolumeId db "Invalid Volume ID", CR, LF, 0 + +msgWhatIsVolumeId? db "Enter current Volume Label for drive %c: ", 0 + +msgIncompatibleParameters db "Parameters not compatible", CR,LF,0 + +msgIncompatibleParametersForHardDisk db "Parameters not compatible" + db " with fixed disk", CR,LF,0 + +msgBadPartitionTable db "Bad Partition Table", CR, LF, 0 + +msgParametersNotSupportedByDrive db "Parameters not Supported by Drive", CR, LF, 0 + +msgPartitionTableReadError db "Error reading partition table", CR, LF, 0 + +msgPartitionTableWriteError db "Error writing partition table", CR, LF, 0 + +IF DEBUG +msgFormatBroken db "Format Broken", CR, LF, 0 +ENDIF + diff --git a/SRC/CMD/FORMAT/OEMFOR.ASM b/SRC/CMD/FORMAT/OEMFOR.ASM new file mode 100644 index 0000000..b773206 --- /dev/null +++ b/SRC/CMD/FORMAT/OEMFOR.ASM @@ -0,0 +1,1204 @@ +; SCCSID = @(#)oemfor.asm 1.28 85/10/15 + name OemFormatRoutines + +debug equ 0 +;------------------------------------------------------------------------------- +; Public for debugging only + + public CheckSwitches + public LastChanceToSaveIt + public WriteBootSector + public OemDone + public WriteBogusDos + public ConvertToOldDirectoryFormat + public SetPartitionTable + public ReadSector + public WriteSector + public SectorIO + public GetVolumeId + public CheckVolumeId + + public customBPBs + public BootSectorIsFine + public NotSlashB + public NotSingleSided + public EndSwitchCheck + public WeCanNotIgnoreThisError + public CanNotWriteBoot + public HardDisk? + public BogusDos + public sys_mess_loop + public end_sys_loop + public DirectoryRead + public wrtdir + public DirectoryWritten + public PartitionTableRead + public partitionscan + public dochange + public partitionset + public BadPartitionTable + public FCBforVolumeIdSearch + public CopyVolumeId + public CompareVolumeIds + public VolumeToUpper + public NextLetter + public BadVolumeId + + public switchlist + public boot2 + public boot + public scratchBuffer + public bootDrive + public biosFilename + public dosFilename + public oldDrive + public oldVolumeId + + public bootSignature + public ptr_msgWhatIsVolumeId? + + public trackReadWritePacket + + public BPB81 + public BPB82 + public BPB91 + public BPB92 + +;------------------------------------------------------------------------------- + +data segment public 'DATA' +data ends + +code segment public 'CODE' + assume cs:code,ds:data + + Public AccessDisk + public CheckSwitches + public LastChanceToSaveIt + public WriteBootSector + public OemDone + public BiosFile + public DosFile + +data segment + extrn AddToSystemSize:near + extrn currentCylinder:word + extrn currentHead:word + extrn deviceParameters:byte + extrn drive:byte + extrn driveLetter:byte + extrn fBigFAT:byte + extrn inbuff:byte + extrn switchmap:word + extrn Old_Dir:byte + extrn fLastChance:byte + + extrn msgBadVolumeId:byte + extrn msgBadPartitionTable:byte + extrn msgBootWriteError:byte + extrn msgDirectoryReadError:byte + extrn msgDirectoryWriteError:byte + extrn msgInvalidParameter:byte + extrn msgIncompatibleParameters:byte + extrn msgIncompatibleParametersForHardDisk:byte + extrn msgParametersNotSupportedByDrive:byte + extrn msgPartitionTableReadError:byte + extrn msgPartitionTableWriteError:byte + extrn msgWhatIsVolumeId?:byte + extrn NumSectors:word, TrackCnt:word + +IF DEBUG + extrn msgFormatBroken:byte +ENDIF + +data ends + + extrn PrintString:near + extrn std_printf:near + extrn crlf:near + extrn user_string:near + +;------------------------------------------------------------------------------- +; Support Routines + +Switches macro s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16 +;; +switchCount = 0 +switchmask = 1 + irp x,<&s1,&s2,&s3,&s4,&s5,&s6,&s7,&s8,&s9,&s10,&s11,&s12,&s13,&s14,&s15,&s16> + ifnb + switchCount = switchCount + 1 + SWITCH_&&x = switchmask + switchmask = 2 * switchmask + endif + endm +public switchlist +switchlist db switchCount + db "&s16&&s15&&s14&&s13&&s12&&s11&&s10&&s9&&s8&&s7&&s6&&s5&&s4&&s3&&s2&&s1&" + endm + +;------------------------------------------------------------------------------- +; Constants + +; Standard dos macros + INCLUDE DOSMAC.INC + +; This defines all the int 21H system calls + INCLUDE SYSCALL.INC + +; Limits + +; following were removed into FILESIZE.INC by kwc on 10/04/86 + +;BIOS_SIZE equ 5400h ; Used to set size of +;DOS_SIZE equ 7600h ; Bogus DOS for /B switch + + include filesize.inc + +; end of FILESIZE.INC change by kwc on 10/04/86 + +LOGBOOTSECT equ 1 +;MAX_SECTORS_IN_TRACK equ 20 Already defined in ioctl.INC +Set_Drv_Owner equ 0Fh ; IOCTL subfunction + +;------------------------------------------------------------------------------- +; These are the data structures which we will need + + INCLUDE DIRENT.INC + include ioctl.INC + +;------------------------------------------------------------------------------- +; And this is the actual data +data segment + +BiosFile db "x:\IO.SYS", 0 +DosFile db "x:\MSDOS.SYS", 0 + +trackReadWritePacket a_TrackReadWritePacket <> + + Switches S,V,H,C,T,N,1,4,8,B + +; BIOS parameter blocks for various media +customBPBs label byte +BPB92 a_BPB <512, 2, 1, 2, 112, 2*9*40, 0fdH, 2, 9, 2, 0, 0, 0, 0> +BPB91 a_BPB <512, 1, 1, 2, 64, 1*9*40, 0fcH, 2, 9, 1, 0, 0, 0, 0> +BPB82 a_BPB <512, 2, 1, 2, 112, 2*8*40, 0ffH, 1, 8, 2, 0, 0, 0, 0> +BPB81 a_BPB <512, 1, 1, 2, 64, 1*8*40, 0feH, 1, 8, 1, 0, 0, 0, 0> +BPB720 a_BPB <512, 2, 1, 2, 112, 2*9*80, 0F9h, 3, 9, 2, 0, 0, 0, 0> + +Custom_Media equ 0F0H ; Media byte for custom format +Dual_8_Media equ 0FFh ; Dual sided 8 sectored +Single_8_Media equ 0FEh ; Single sided 8 sectored +Dual_9_Media equ 0FDh ; Dual sided 9 sectored +Single_9_Media equ 0FCh ; Single sided 9 sectored +Dual_15_Media equ 0F9h ; Dual sided 15 sectored +Fixed_Disk equ 0F8h ; Fixed Disk + + +boot2 db 0,0,0, "Boot 1.x" + db 512 - 11 dup(?) + +REORG2 LABEL BYTE + ORG BOOT2 + INCLUDE ..\BOOT\BOOT11.INC + ORG REORG2 + +boot db 0,0,0,"Boot 2.x" +bootBPB a_BPB <> + db 512 - (size a_BPB + 11 + 3) dup(0) + +bootDrive db 0 +bootSignature dw 0 + +REORG LABEL BYTE + ORG BOOT + INCLUDE ..\BOOT\BOOT.INC + ORG REORG + +scratchBuffer db 512 dup(?) + +ptr_msgWhatIsVolumeId? dw offset msgWhatIsVolumeId? + dw offset driveLetter + +data ends +;------------------------------------------------------------------------------- +; AccessDisk: +; Called whenever a different disk is about to be accessed +; +; Input: +; al - drive letter (0=A, 1=B, ...) +; +; Output: +; none +AccessDisk proc near + + push ax ; save drive letter + mov bl,al ; Set up GENERIC IOCTL REQUEST preamble + inc bl + mov ax,(IOCTL SHL 8) + Set_Drv_Owner ; IOCTL function + int 21h + pop ax + return + +AccessDisk endp + +;------------------------------------------------------------------------------- +; CheckSwitches: +; Check switches against device parameters +; Use switches to modify device parameters +; +; Input: +; deviceParameters +; +; Output: +; deviceParameters may be modified +; Carry set if error +; +; Algorithm: +; if hard disk +; Check Boot Sector for valid Signature +; IF (valid) +; Check the volume id +; Make sure no switches other than /V, /S are specifed +; else if 96 tpi without /4 or not 5.25" disk +; Make sure no switches other than /V, /S are specifed +; else +; if 48 tpi drive and switch /4 +; turn off switch /4 +; if single sided drive and switch /1 but not switch /8 +; turn off switch /1 +; if any of interesting switches are on (/C, /O, /V, /S are not) +; set number of cylinders to 40 +; choose new BPB depending on switches /1 and /8 +; +CheckSwitches proc near + +IF DEBUG +; See if the boot sector was initialised correctly + cmp bootSignature, 0aa55H + je BootSectorIsFine + lea dx, msgFormatBroken + jmp short SwitchError +ENDIF ; DEBUG + +BootSectorIsFine: + +; Disallow /C + lea dx, msgInvalidParameter + test switchmap, SWITCH_C + jz CheckExcl + +SwitchError: + call PrintString + stc + ret + +; Only certain permutations of the switches /N /T /V /B /S and /V are legal. +; For specific cases see the file Switchmap.legal. + +CheckExcl: + lea dx, msgIncompatibleParameters ; Error message + + + test SwitchMap, SWITCH_B ; IF ( SWITCH_B) + jz SVpermitted + + test SwitchMap, SWITCH_S or SWITCH_V ; THEN exclude SWITCH_S and + jnz SwitchError ; SWITCH_V + +SVpermitted: + test SwitchMap, SWITCH_8 ; IF ( SWITCH_8 ) + jz Check_N + ; THEN + test SwitchMap, SWITCH_N or SWITCH_T ; exclude SWITCH_N and + jnz SwitchError + + + test SwitchMap, SWITCH_V ; SWITCH_V if unaccompanied + jz Check_N ; by SWITCH_S + + test SwitchMap, SWITCH_S + jz SwitchError ; ENDIF ( SWITCH_8 ) + + +Check_N: ; IF ( SWITCH_N or SWITCH_T ) + test SwitchMap, SWITCH_N or SWITCH_T + jz ExclChkDone + + test SwitchMap, SWITCH_1 or SWITCH_4 ; THEN exclude SWITCH_1 and + jnz SwitchError ; SWITCH_4 + +ExclChkDone: +; Patch the boot sector so that the boot strap loader knows what disk to +; boot from + mov bootDrive, 00H + + cmp deviceParameters.DP_DeviceType, DEV_HARDDISK + jne CheckFor5InchDrives + +; Formatting a hard disk so we must repatch the boot sector + mov bootDrive, 80H + test switchmap, not (SWITCH_S or SWITCH_V) + jz SwitchesOkForHardDisk + lea dx, msgIncompatibleParametersForHardDisk + call PrintString + stc + ret + +; Before checking the Volume Id we need to verify that a valid one exists +; We assume that unless a valid boot sector exists on the target disk, no +; valid Volume Id can exist. + +SwitchesOkForHardDisk: + SaveReg + mov al,drive + mov cx,LogBootSect + xor dx,dx + lea bx,scratchBuffer ; ScratchBuffer := Absolute_Disk_Read( + INT 25h ; Logical_sec_1 ) + pop ax ; Stupid Int 25! leaves flags + ; on the stack. We throw them away + + jnc CheckSignature + stc + RestoreReg + ret + +CheckSignature: ; IF (BootSector.BootSignature != aa55) + + mov ax, Word Ptr (ScratchBuffer + (BootSignature - boot)) + cmp ax, 0aa55h + RestoreReg + clc ; not an error, just not vol. + retnz ; THEN RETURN + + call CheckVolumeId ; ELSE CheckVolumeID + return + +OnlyVSpermitted: + test switchmap, not (SWITCH_S or SWITCH_V) + retz + lea dx, msgIncompatibleParameters + +Print_And_Return: + call PrintString + stc + return + + +CheckFor5InchDrives: + + ;If drive type is anything other than 48 or 96, then only /V/S/H/N/T allowed + cmp byte ptr deviceParameters.DP_DeviceType,DEV_5INCH96TPI + je Got96 + + cmp byte ptr deviceParameters.DP_DeviceType,DEV_5INCH + je Got48 + + test switchmap, not (SWITCH_V or SWITCH_S or SWITCH_N or SWITCH_T or SWITCH_H) + jz Goto_Got_BPB + lea dx,msgParametersNotSupportedByDrive + jmp short Print_And_Return + + ; We have a 96tpi floppy drive + ; /4 allows just about all switches however, /1 requires /4 +Got96: + test switchmap, SWITCH_4 + jnz CheckForInterestingSwitches ;If /4 check /N/T/V/S + + test switchmap, SWITCH_1 ;If /1 and /4 check others + jz Got48 + + ;If only /1 with no /4, see if /N/T + test SwitchMap,(Switch_N or Switch_T) + jnz CheckForInterestingSwitches + + lea dx, msgIncompatibleParameters ;If no /4 but /1 die + jmp short Print_And_Return + +Got48: + ;Ignore /4 for non-96tpi 5 1/4" drives + and switchmap, not SWITCH_4 + + ;Ignore /1 if drive has only one head and not /8 + cmp word ptr deviceParameters.DP_BPB.BPB_Heads, 1 + ja CheckForInterestingSwitches + test switchmap, SWITCH_8 + jz CheckForInterestingSwitches + and switchmap, not SWITCH_1 + + ;Are any interesting switches set? +CheckForInterestingSwitches: + test switchmap, not (SWITCH_V or SWITCH_S or SWITCH_H) ;Anything but /V/S/H? + jz Goto_EndSwitchCheck ;No, everything ok + + ;At this point there are switches other than /v/s/h + test SwitchMap,(SWITCH_N or SWITCH_T) + jz Use_48tpi ;Not /n/t, so must be /b/1/8/4 + + ;We've got /N/T, see if there are others + test SwitchMap, not (SWITCH_N or SWITCH_T or SWITCH_V or SWITCH_S or SWITCH_H) + jz NT_Compatible ;Nope, all is well + + ;If 96tpi drive and /1 exists with /N/T, then okay, otherwise error + cmp byte ptr deviceParameters.DP_DeviceType,DEV_5INCH96TPI + jne Bad_NT_Combo + + test SwitchMap, not (SWITCH_1 or SWITCH_N or SWITCH_T or SWITCH_V or SWITCH_S or SWITCH_H) + jz Goto_Got_BPB + +Bad_NT_Combo: + lea dx, msgIncompatibleParameters + jmp Print_And_Return + +Goto_Got_BPB: + jmp Got_BPB_Ok ;Sleazy, but je won't reach it + +Goto_EndSwitchCheck: + jmp EndSwitchCheck + ;There is a problem with /N/T in that IO.SYS will default to a BPB with the + ;media byte set to F0 (other) if the /N/T combo is used for the format. This + ;will cause problems if we are creating a media that has an assigned media + ;byte, i.e. 160,180,320,360, or 720k media using /N/T. To avoid this problem, + ;if we detect a /N/T combo that would correspond to one of these medias, then + ; we will set things up using the /4/1/8 switches instead of the /N/T + ; MT - 7/17/86 PTR 33D0110 + + ; Combo's that we look for - 96tpi drive @ /T:40, /N:9 + ; 96tpi drive @ /T:40, /N:8 + ; + ; Look for this combo after we set everything up with the /T/N routine + ; 1.44 drive @ /T:80, /N:9 + +NT_Compatible: + cmp byte ptr deviceParameters.DP_DeviceType,DEV_5INCH96TPI + jne Goto_Got_BPB + + cmp TrackCnt,40 ;Look for 40 tracks + jne Got_BPB_Ok + + cmp NumSectors,9 ;9 sectors? + je Found_48tpi_Type + + cmp NumSectors,8 ;8 sectors? + jne Goto_Got_BPB ;Nope, different type, let it go thru + + or SwitchMap,SWITCH_8 ;Yes, turn on /8 switch + +Found_48tpi_Type: + and SwitchMap,not (SWITCH_N or SWITCH_T) ;Turn off /T/N + +;******End PTR fix + +; if we have a 96 tpi drive then we will be using it in 48 tpi mode +Use_48tpi: + cmp byte ptr deviceParameters.DP_DeviceType, DEV_5INCH96TPI + jne Not96tpi + + mov byte ptr deviceParameters.DP_MediaType, 1 + mov word ptr deviceParameters.DP_Cylinders, 40 +Not96tpi: + +; Since we know we are formatting in 48 tpi mode turn on /4 switch +; (We use this info in LastChanceToSaveIt) + or switchmap, SWITCH_4 + +; At this point we know that we will require a special BPB +; It will be one of: +; 0) 9 track 2 sides - if no switches +; 1) 9 track 1 side - if only /1 specified +; 2) 8 track 2 sides - if only /8 specified +; 3) 8 track 1 side - if /8 and /1 specified +; +Get_BPBs: +; ax is used to keep track of which of the above BPB's we want + xor ax, ax + +; /B implies /8 + test switchmap, SWITCH_B + jz NotSlashB + or switchmap, SWITCH_8 +NotSlashB: + + test switchmap, SWITCH_1 + jz NotSingleSided + add ax, 1 +NotSingleSided: + + test switchmap, SWITCH_8 + jz Not8SectorsPerTrack + add ax, 2 +; /8 implies Old_Dir = TRUE + mov Old_Dir,TRUE +Not8SectorsPerTrack: + +; Ok now we know which BPB to use so lets move it to the device parameters + + mov bx, size a_BPB + mul bx + lea si, CustomBPBs + add si, ax + lea di, deviceParameters.DP_BPB + mov cx, size a_BPB + push ds + pop es + repnz movsb + +;***************************************************************** +;* /N/T DCR stuff. Possible flaw exists if we are dealing with a +;* HardDisk. If they support the "custom format" features for +;* Harddisks too, then CheckForInterestingSwitches should +;* consider /n/t UNinteresting, and instead of returning +;* after setting up the custom BPB we fall through and do our +;* Harddisk Check. +Got_BPB_OK: + test switchmap,SWITCH_N+SWITCH_T + jnz Setup_Stuff + jmp EndSwitchCheck +Setup_Stuff: +; Set up NumSectors and SectorsPerTrack entries correctly + test switchmap,SWITCH_N + jz No_Custom_Seclim + mov ax,word ptr NumSectors + mov DeviceParameters.DP_BPB.BPB_SectorsPerTrack,ax + jmp short Handle_Cyln +No_Custom_Seclim: + mov ax,deviceParameters.DP_BPB.BPB_SectorsPerTrack + mov NumSectors,ax + +Handle_Cyln: + test switchmap,SWITCH_T + jz No_Custom_Cyln +; Set up TrackCnt and Cylinders entries correctly + mov ax,TrackCnt + mov DeviceParameters.DP_Cylinders,ax + jmp short Check_720 +No_Custom_Cyln: + mov ax,DeviceParameters.DP_Cylinders + mov TrackCnt,ax + +;****PTM P868 - Always making 3 1/2 media byte 0F0h. If 720, then set to +; 0F9h and use the DOS 3.20 BPB. Should check all drives +; at this point (Make sure not 5 inch just for future +; protection) +; We will use the known BPB info for 720 3 1/2 diskettes for +; this special case. All other new diskette media will use the +; calculations that follow Calc_Total for BPB info. +; Fix MT 11/12/86 + +Check_720: + + cmp byte ptr deviceParameters.DP_DeviceType,DEV_5INCH96TPI + je Calc_Total + + cmp byte ptr deviceParameters.DP_DeviceType,DEV_5INCH + je Calc_Total + + cmp TrackCnt,80 + jne Calc_Total + + cmp NumSectors,9 + jne Calc_Total + +; At this point we know we have a 3 1/2 720kb diskette to format. Use the +; built in BPB rather than the one handed to us by DOS, because the DOS one +; will be based on the default for that drive, and it can be different from +; what we used in DOS 3.20 for the 720's. Short sighted on our part to use +; 0F9h as the media byte, should have use 0F0h (OTHER) and then we wouldn't +; have this problem. + + SaveReg + + + mov cx,seg data ;Setup seg regs, just in case they ain't! + mov ds,cx + mov es,cx + + mov si,offset BPB720 ;Copy the BPB! + mov di,offset deviceParameters.DP_BPB + mov cx,size a_BPB + rep movsb + RestoreReg + jmp EndSwitchCheck + +;End PTM P868 fix **************************************** + +Calc_Total: + mov ax,NumSectors + mov bx,DeviceParameters.DP_BPB.BPB_Heads + mul bl ; AX = # of sectors * # of heads + mul TrackCnt ; DX:AX = Total Sectors + or dx,dx + jnz Got_BigTotalSectors + mov DeviceParameters.DP_BPB.BPB_TotalSectors,ax + jmp short Set_BPB +Got_BigTotalSectors: + mov DeviceParameters.DP_BPB.BPB_BigTotalSectors,ax + mov DeviceParameters.DP_BPB.BPB_BigTotalSectors+2,dx + push dx ; preserve dx for further use + xor dx,dx + mov DeviceParameters.DP_BPB.BPB_TotalSectors,dx + pop dx + +Set_BPB: +; We calculate the number of sectors required in a FAT. This is done as: +; # of FAT Sectors = TotalSectors / SectorsPerCluster * # of bytes in FAT to +; represent one cluster (i.e. 3/2) / BytesPerSector (i.e. 512) + xor bx,bx + mov bl,DeviceParameters.DP_BPB.BPB_SectorsPerCluster + div bx ; DX:AX contains # of clusters +; now multiply by 3/2 + mov bx,3 + mul bx + mov bx,2 + div bx + xor dx,dx ; throw away modulo +; now divide by 512 + mov bx,512 + div bx +; dx:ax contains number of FAT sectors necessary + inc ax ; Go one higher + mov DeviceParameters.DP_BPB.BPB_SectorsPerFAT,ax + mov DeviceParameters.DP_MediaType,0 + mov DeviceParameters.DP_BPB.BPB_MediaDescriptor,Custom_Media + + +EndSwitchCheck: + clc + return + +CheckSwitches endp + +;------------------------------------------------------------------------------- +; LastChanceToSaveIt: +; This routine is called when an error is detected in DiskFormat. +; If it returns with carry not set then DiskFormat is restarted. +; It gives the oem one last chance to try formatting differently. +; fLastChance gets set Then to prevent multiple prompts from being +; issued for the same diskette. +; +; Algorithm: +; IF (error_loc == Track_0_Head_1) & +; ( Device_type < 96TPI ) +; THEN +; fLastChance := TRUE +; try formatting 48TPI_Single_Sided +; ELSE return ERROR +; +LastChanceToSaveIt proc near + + cmp currentCylinder, 0 + jne WeCanNotIgnoreThisError + cmp currentHead, 1 + jne WeCanNotIgnoreThisError + + cmp deviceParameters.DP_DeviceType, DEV_5INCH + ja WeCanNotIgnoreThisError + + mov fLastChance, TRUE + + or switchmap, SWITCH_1 + call CheckSwitches + clc + ret + +WeCanNotIgnoreThisError: + stc + ret + +LastChanceToSaveIt endp + +;------------------------------------------------------------------------------- + +WriteBootSector proc near + +; Copy BPB to boot sector + lea si, deviceParameters.DP_BPB + lea di, bootBPB + mov cx, size a_BPB + push ds + pop es + repnz movsb + +; Write out the boot sector + mov al, drive + mov cx, 1 + xor dx, dx + lea bx, boot + int 26H + pop ax + jc CanNotWriteBoot + return + +CanNotWriteBoot: + lea dx, msgBootWriteError + call PrintString + stc + ret + +WriteBootSector endp + +;------------------------------------------------------------------------------- +; OemDone: +; +OemDone proc near + +; if /b write out a fake dos & bios + test switchmap, SWITCH_B + jz Switch8? + call WriteBogusDos + retc + +Switch8?: + test switchmap, SWITCH_8 + jz HardDisk? + call ConvertToOldDirectoryFormat + retc + +HardDisk?: + cmp deviceParameters.DP_DeviceType, DEV_HARDDISK + clc + retnz + call SetPartitionTable + + return + +OemDone endp + +;------------------------------------------------------------------------------ + +data segment + +biosFilename db "x:\io.sys",0 +dosFilename db "x:\msdos.sys",0 + +data ends + +; simple code to stuff bogus dos in old-style diskette. + + +BogusDos: + push cs + pop ds + mov al,20h + out 20h,al ; turn on the timer so the disk motor + mov si,mesofs ; shuts off +sys_mess_loop: + lodsb +end_sys_loop: + or al,al + jz end_sys_loop + mov ah,14 + mov bx,7 + int 16 + jmp sys_mess_loop + + include bootmes.inc + +mesofs equ no_sys_mess - BogusDos + +WriteBogusDos proc near + + mov al,driveLetter + mov biosFilename,al + mov dosFilename,al + mov cx, ATTR_HIDDEN or ATTR_SYSTEM + lea dx, biosFilename + mov ah,CREAT + int 21h + mov bx,ax + mov cx, BIOS_SIZE + push ds + push cs + pop ds + assume ds:code + lea dx, BogusDos + mov ah,WRITE + int 21h + pop ds + assume ds:data + mov ah,CLOSE + int 21h + mov cx, ATTR_HIDDEN or ATTR_SYSTEM + lea dx, dosFilename + mov ah,CREAT + int 21h + mov bx,ax + mov cx, DOS_SIZE + lea dx, BogusDos + mov ah,WRITE + int 21h + mov ah,CLOSE + int 21h +; Comunicate system size to the main format program + xor dx,dx + mov ax,DOS_SIZE + call AddToSystemSize + xor dx,dx + mov ax,BIOS_SIZE + call AddToSystemSize + + clc + return + +WriteBogusDos endp + +;------------------------------------------------------------------------------- + +ConvertToOldDirectoryFormat proc near + +; +; convert to 1.1 directory +; + mov al,drive ; Get 1st sector of directory + mov cx,1 ; 1.1 directory always starts on + mov dx,3 ; sector 3 + lea bx,scratchBuffer + int 25h + pop ax ; clean up stack + jnc DirectoryRead + lea dx, msgDirectoryReadError + call PrintString + stc + ret +DirectoryRead: + +; fix attribute of io.sys and msdos.sys + lea bx,scratchBuffer + mov byte ptr [bx].dir_attr, ATTR_HIDDEN or ATTR_SYSTEM + add bx, size dir_entry + mov byte ptr [bx].dir_attr, ATTR_HIDDEN or ATTR_SYSTEM + +wrtdir: + mov al,[drive] ; write out the directory + cbw + mov cx,1 + mov dx,3 + lea bx,scratchBuffer + int 26h + pop ax ; clean up stack + jnc DirectoryWritten + lea dx, msgDirectoryWriteError + call PrintString + stc + ret +DirectoryWritten: + + test switchmap, SWITCH_S ; Was system requested? + retnz ; yes, don't write old boot sector + mov al,drive + cbw + mov bx,offset boot2 ; no, write old boot sector + cmp deviceParameters.DP_BPB.BPB_Heads, 1 + je bootset8 + mov word ptr [bx+3],0103h ; start address for double sided drives +bootset8: + mov cx,1 + xor dx,dx + int 26h ; write out that boot sector + pop ax + retnc + + lea dx, msgBootWriteError + call PrintString + stc + ret + +ConvertToOldDirectoryFormat endp + +;------------------------------------------------------------------------------- + +a_PartitionTableEntry struc +BootInd db ? +BegHead db ? +BegSector db ? +BegCylinder db ? +SysInd db ? +EndHead db ? +EndSector db ? +EndCylinder db ? +RelSec dd ? +CSec dd ? +a_PartitionTableEntry ends + +; structure of the IBM hard disk boot sector: +IBMBoot STRUC + db 512 - (4*size a_PartitionTableEntry + 2) dup(?) +PartitionTable db 4*size a_PartitionTableEntry dup(?) +Signature dw ? +IBMBoot ENDS + + +SetPartitionTable proc near + + mov ax, 0 ; Head + mov bx, 0 ; Cylinder + mov cx, 0 ; Sector + lea dx, boot2 + call ReadSector + jnc PartitionTableRead + lea dx, msgPartitionTableReadError + call PrintString + stc + ret +PartitionTableRead: + +; Check to see if there is a partition table (by looking for its signature) + cmp boot2.signature, 0aa55H + jne BadPartitionTable + +; Scan all the partitions search for the FIRST DOS partition. We then set the +; appropriate FAT size in the FIRST DOS partition and return. + + lea bx, boot2.PartitionTable +partitionscan: + +; have we scanned all partitions? + cmp bx,(offset Boot2.PartitionTable)+4*size a_PartitionTableEntry + jae BadPartitionTable + + cmp [bx].sysind,1 + jz dochange + cmp [bx].sysind,4 + jz dochange + + add bx,size a_PartitionTableEntry + jmp partitionscan + +dochange: + mov [bx].sysind,4 ; assume 16 bit fat + cmp fbigfat,0 ; test assumption + jnz partitionset ; is 16 bit fat, assumption correct + mov [bx].sysind,1 ; 12 bit fat, pre 3.0 dos can read it + +partitionset: + mov ax, 0 ; Head + mov bx, 0 ; Cylinder + mov cx, 0 ; Sector + lea dx, boot2 + call WriteSector + retnc + + lea dx, msgPartitionTableWriteError + call PrintString + stc + ret + +BadPartitionTable: + lea dx, msgBadPartitionTable + call PrintString + stc + ret + +SetPartitionTable endp + +;------------------------------------------------------------------------------- +; ReadSector: +; Read one sector +; +; Input: +; ax - head +; bx - cylinder +; cx - sector +; dx - transfer address + +ReadSector proc near + + mov TrackReadWritePacket.TRWP_FirstSector, cx + mov cx,(RAWIO shl 8) or READ_TRACK + call SectorIO + return + +ReadSector endp + +;------------------------------------------------------------------------------- +; WriteSector: +; Write one sector +; +; Input: +; ax - head +; bx - cylinder +; cx - sector +; dx - transfer address + +WriteSector proc near + + mov TrackReadWritePacket.TRWP_FirstSector, cx + mov cx,(RAWIO shl 8) or WRITE_TRACK + call SectorIO + return + +WriteSector endp + +;------------------------------------------------------------------------------- +; SectorIO: +; Read/Write one sector +; +; Input: +; ax - head +; bx - cylinder +; cx - (RAWIO shl 8) or READ_TRACK +; - (RAWIO shl 8) or WRITE_TRACK +; dx - transfer address + +SectorIO proc near + + mov TrackReadWritePacket.TRWP_Head, ax + mov TrackReadWritePacket.TRWP_Cylinder, bx + mov WORD PTR TrackReadWritePacket.TRWP_TransferAddress, dx + mov WORD PTR TrackReadWritePacket.TRWP_TransferAddress + 2, ds + mov TrackReadWritePacket.TRWP_SectorsToReadWrite, 1 + + mov bl, drive + inc bl + mov ax, (IOCTL shl 8) or GENERIC_IOCTL + lea dx, trackReadWritePacket + int 21H + return + +SectorIO endp + +;------------------------------------------------------------------------------- + +data segment + +oldDrive db ? + +FCBforVolumeIdSearch db 0ffH + db 5 dup(0) + db 08H + db 0 + db "???????????" + db 40 DUP(0) + +data ends + +GetVolumeId proc near +; Input: +; dl = drive +; di = name buffer + +; Save current drive + mov ah,19H + int 21H + mov oldDrive, al + +; Change current drive to the drive that has the volume id we want + mov ah, 0eH + int 21H + +; Search for the volume id + mov ah, 11H + lea dx, FCBforVolumeIdSearch + int 21H + push ax + +; Restore current drive + mov ah, 0eH + mov dl,oldDrive + int 21H + +; Did the search succeed? + pop ax + or al,al + jz CopyVolumeId + stc + ret + +CopyVolumeId: +; Find out where the FCB for the located volume id was put + mov ah,2fH + int 21H + +; Copy the Volume Id + mov si, bx + add si, 8 + push es + push ds + pop es + pop ds + mov cx, 11 + rep movsb + push es + pop ds + + clc + ret + +GetVolumeId endp + +data segment +oldVolumeId db 11 dup(0) +data ends + +CheckVolumeId proc near + +; Get the volume id that's on the disk + lea di, oldVolumeId + mov dl, drive + call GetVolumeId + jnc Ask_User ;Did we find one? + clc ;No, return with no error + ret + +; Ask the user to enter the volume id that he/she thinks is on the disk +; (first blank out the input buffer) +Ask_User: + lea dx, ptr_msgWhatIsVolumeId? + call std_printf + call user_string + call crlf + +; If the user just pressed ENTER, then there must be no label + cmp inbuff+1, 0 + jne CompareVolumeIds + cmp oldVolumeId, 0 + jne BadVolumeId + ret + +CompareVolumeIds: +; pad the reponse with blanks +; The buffer is big enough so just add 11 blanks to what the user typed in + push ds + pop es + mov cx, 11 + xor bx,bx + mov bl, inbuff + 1 + lea di, inbuff + 2 + add di, bx + mov al, ' ' + rep stosb +; Make the reply all uppercase + mov cl, inbuff + 1 + xor ch,ch + lea si, inbuff + 2 +VolumeToUpper: + mov al, [si] + cmp al, 'a' + jb NextLetter + cmp al, 'z' + ja NextLetter + sub al, 'a' - 'A' + mov [si],al +NextLetter: + inc si + loop VolumeToUpper + +; Now compare what the user specified with what is really out there + mov cx, 11 + lea si, inbuff + 2 + lea di, oldVolumeId + repe cmpsb + jne BadVolumeId + ret + +BadVolumeId: + lea dx, msgBadVolumeId + call PrintString + stc + ret + +CheckVolumeId endp + +code ends + end diff --git a/SRC/CMD/MAKEFILE b/SRC/CMD/MAKEFILE new file mode 100644 index 0000000..646367a --- /dev/null +++ b/SRC/CMD/MAKEFILE @@ -0,0 +1,14 @@ +make=msmake /I makefile + +all: + cd format + $(make) + cd ..\print + $(make) + cd ..\sort + $(make) + cd ..\sys + $(make) + cd .. + + \ No newline at end of file diff --git a/SRC/CMD/PRINT/MAKEFILE b/SRC/CMD/PRINT/MAKEFILE new file mode 100644 index 0000000..725a25f --- /dev/null +++ b/SRC/CMD/PRINT/MAKEFILE @@ -0,0 +1,61 @@ +#** makefile for print + +DEST =print +MSG =messages + +# Path definitions + +BIOS =..\..\BIOS +DOS =..\..\DOS + +# Definitions for assembler + +ASM =masm +AFLAGS =-Mx -t +AINC =-I..\..\inc -I$(DOS) + +# Definitions for C compiler + +CC =cl +CFLAGS =-c -Ox -Zlp +CINC =-I..\..\h + +# Definitions for linker + +LINK =link +LIBC =..\..\libc + + +# Rules and Dependencies follow + +PRINT_RM.OBJ: PRINT_RM.ASM print_rm.inc PRIDEFS.inc \ + $(DOS)\DEVSYM.INC $(DOS)\SYSCALL.INC $(DOS)\ERROR.INC \ + $(DOS)\SYSVAR.INC $(DOS)\FIND.INC + masm $(AFLAGS) $(AINC) PRINT_RM; + +PRINT_R.OBJ: PRINT_R.ASM PRIDEFS.inc \ + $(DOS)\DEVSYM.INC $(DOS)\SYSCALL.INC $(DOS)\ERROR.INC \ + $(DOS)\SYSVAR.INC $(DOS)\FIND.INC + masm $(AFLAGS) $(AINC) PRINT_R; + +PRINT_T.OBJ: PRINT_T.ASM PRIDEFS.inc \ + $(DOS)\DEVSYM.INC $(DOS)\SYSCALL.INC $(DOS)\ERROR.INC \ + $(DOS)\SYSVAR.INC $(DOS)\FIND.INC + masm $(AFLAGS) $(AINC) PRINT_T; + +PRINT_TM.OBJ: PRINT_TM.ASM print_tm.inc PRIDEFS.inc \ + $(DOS)\DEVSYM.INC $(DOS)\SYSCALL.INC $(DOS)\ERROR.INC \ + $(DOS)\SYSVAR.INC $(DOS)\FIND.INC + masm $(AFLAGS) $(AINC) PRINT_TM; + +NPRINTF.OBJ: NPRINTF.ASM PRIDEFS.inc \ + $(DOS)\DEVSYM.INC $(DOS)\SYSCALL.INC $(DOS)\ERROR.INC \ + $(DOS)\SYSVAR.INC $(DOS)\FIND.INC + masm $(AFLAGS) $(AINC) NPRINTF; + +PRINT.EXE: PRINT_RM.OBJ PRINT_R.OBJ PRINT_T.OBJ \ + PRINT_TM.OBJ NPRINTF.OBJ + LINK @PRINT.LNK + CONVERT PRINT.EXE + DEL PRINT.EXE + \ No newline at end of file diff --git a/SRC/CMD/PRINT/NPRINTF.ASM b/SRC/CMD/PRINT/NPRINTF.ASM new file mode 100644 index 0000000..b80cef7 --- /dev/null +++ b/SRC/CMD/PRINT/NPRINTF.ASM @@ -0,0 +1,386 @@ +; SCCSID = @(#)nprintf.asm 4.1 85/07/17 + INCLUDE pridefs.inc + + +BREAK + +; +; MSDOS V3.00 PRINT +; +; Message Printing Routine +; + + +DATA SEGMENT PUBLIC BYTE + + extrn crlf_ptr:word + +Public NPR001S, NPR001E +NPR001S equ $ + +PRINTF_LEFT DB 0 +PRINTF_LONG DB 0 +PRINTF_HEX DB 0 +TABLE_INDEX DB 0 +S_FLAG DB 0 +PRINTF_WIDTH DW 0 +PRINTF_BASE DW 0 +PAD_CHAR DB " " + +PRINTF_TABLE DB "0123456789ABCDEFabcdef" + +PRINTF_STACK STRUC +OLDES DW ? +OLDDS DW ? +OLDSI DW ? +OLDDI DW ? +OLDAX DW ? +OLDBX DW ? +OLDCX DW ? +OLDBP DW ? +STRING DW ? +OLDCS DW ? +PRINTF_STACK ENDS + +PRINTF_ARGS STRUC +CONSTR DW ? +ARG DW ? +PRINTF_ARGS ENDS + +BUFSIZ EQU 20 +PRINTF_BUF DB BUFSIZ DUP (?) + db 0 ;This buffer is always nul terminated +BUFEND DW $-PRINTF_BUF + +NPR001E equ $ + +DATA ENDS + + +Code Segment public para + +ASSUME CS:DG,DS:nothing,ES:nothing,SS:Stack + + PUBLIC PRINTF,STD_PRINTF,PRINTF_CRLF + +PRINTF_CRLF: + CALL STD_PRINTF +crlf2: + mov dx,offset dg:crlf_ptr +STD_PRINTF: + PUSH DX +PRINTF: + PUSH BP ;Save the callers' registers + PUSH CX + PUSH BX + PUSH AX + PUSH DI + PUSH SI + PUSH ES + PUSH DS + MOV BP,SP + PUSH CS + POP ES ;ES points to Printf segment + CALL Clear_flags ; initialize the world + + MOV DI,DS + MOV SI,ES + CMP SI,DI + JZ S + HLT +S: + + MOV DI,OFFSET DG:PRINTF_BUF ;DI points to the output buffer + MOV BP,[BP.STRING] ;BP points to the argument list + MOV SI,DS:[BP] ;SI points to the control string + XOR BX,BX ;BX is the index into the arg list +GET_CHAR: + LODSB ;Get a character + CMP AL,"%" ;Is it a conversion specifier? + JZ CONV_CHAR ;Yes - find out which one + OR AL,AL ;Is it the end of the control string? + JZ PRINTF_DONE ;Yes - then we're done + CALL OUTCHR ;Otherwise store the character + JMP SHORT GET_CHAR ;And go get another + +PRINTF_DONE: + CALL FLUSH + POP DS + POP ES + POP SI + POP DI + POP AX + POP BX + POP CX + POP BP + POP DX + RET + +PRINTF_PERCENT: + CALL OUTCHR + JMP GET_CHAR + +CONV_CHAR: + ;Look for any format specifiers preceeding the conversion character + LODSB + CMP AL,"%" ;Just print the % + JZ PRINTF_PERCENT + CMP AL,"-" ;Right justify the field + JZ LEFT_ADJ + CMP AL,"+" ;Left justify the field + JZ NXT_CONV_CHAR + CMP AL,"L" ;Is it a long integer + JZ LONG_INT + CMP AL,"l" + JZ LONG_INT + CMP AL,"0" ;Is it a precision specification + JB LOOK_CONV_CHAR + CMP AL,"9" + JA LOOK_CONV_CHAR + CMP AL,"0" + JNZ NOT_PAD + CMP CS:[PRINTF_WIDTH],0 + JNZ NOT_PAD + MOV CS:BYTE PTR [PAD_CHAR],"0" +NOT_PAD: + PUSH AX ;Adjust decimal place on precision + MOV AX,10 + MUL CS:[PRINTF_WIDTH] + MOV CS:[PRINTF_WIDTH],AX + POP AX + XOR AH,AH + SUB AL,"0" + ADD CS:[PRINTF_WIDTH],AX ;And save the total + JMP SHORT NXT_CONV_CHAR + + ;Set the correct flags for the options in a conversion + +LEFT_ADJ: + INC CS:BYTE PTR[PRINTF_LEFT] + JMP SHORT NXT_CONV_CHAR + +LONG_INT: + INC CS:BYTE PTR[PRINTF_LONG] +NXT_CONV_CHAR: + JMP CONV_CHAR + + ;Look for a conversion character + +LOOK_CONV_CHAR: + CMP AL,"X" + JZ HEX_UP + + ;Make all other conversion characters upper case + + CMP AL,"a" + JB CAPS + CMP AL,"z" + JG CAPS + AND AL,0DFH +CAPS: + CMP AL,"X" + JZ HEX_LO + CMP AL,"D" + JZ DECIMAL + CMP AL,"C" + JZ C_PUT_CHAR + CMP AL,"S" + JZ S_PUT_STRG + + ;Didn't find any legal conversion character - IGNORE it + + call clear_flags + jmp get_char + +HEX_LO: + MOV CS:[TABLE_INDEX],6 ;Will print lower case hex digits +HEX_UP: + MOV CS:[PRINTF_BASE],16 ;Hex conversion + JMP CONV_TO_NUM + +DECIMAL: + MOV CS:[PRINTF_BASE],10 ;Decimal conversion + JMP CONV_TO_NUM + +S_PUT_STRG: + INC CS:[S_FLAG] ;It's a string specifier +C_PUT_CHAR: + PUSH SI ;Save pointer to control string + MOV SI,BX + ADD BX,2 + MOV SI,ds:[BP+SI.ARG] ;Point to the % string or character + CMP BYTE PTR CS:[S_FLAG],0 + JNZ S_PUT_1 + LODSB + cmp al,0 + jz short c_s_end + CALL OUTCHR ;Put it into our buffer + JMP SHORT C_S_END + +S_PUT_1: + mov cx,cs:[printf_width] + or cx,cx + jz s_put_2 + cmp cs:byte ptr[printf_left],0 + jnz s_put_2 + push si + call Pad_string + pop si +s_put_2: + push si +s_put_3: + LODSB ;Put them all in our buffer + CMP AL,0 + jz s_put_4 + CALL OUTCHR + jmp short S_PUT_3 +s_put_4: + pop si + cmp byte ptr[printf_left],0 + jz c_s_end + mov cx,cs:[printf_width] + or cx,cx + jz c_s_end + call Pad_string +C_S_END: + call clear_flags + POP SI ;Restore control string pointer + JMP GET_CHAR ;Go get another character + +pad_string: + xor dx,dx +count_loop: + lodsb + or al,al + jz count_done + inc dx + jmp short count_loop +count_done: + sub cx,dx + jbe count_ret + call pad +count_ret: + ret + +CONV_TO_NUM: + + PUSH SI ;Save pointer to control string + MOV SI,BX ;Get index into argument list + ADD BX,2 ;Increment the index + MOV AX,ds:[BP+SI.ARG] ;Lo word of number in SI + CMP BYTE PTR CS:[PRINTF_LONG],0 ;Is this is a short or long integer? + JZ NOT_LONG_INT + MOV SI,BX ;Copy index + ADD BX,2 ;Increment the index + MOV DX,ds:[BP+SI.ARG] ;Hi word of number in BP + JMP SHORT DO_CONV +NOT_LONG_INT: + XOR DX,DX ;Hi word is zero +DO_CONV: + PUSH BX ;Save index into arguemnt list + MOV si,CS:[PRINTF_BASE] + MOV cx,CS:[PRINTF_WIDTH] + CALL PNUM + CALL PAD +CONV_DONE: + call clear_flags + POP BX + POP SI + jmp get_char + +PNUM: + DEC CX + PUSH AX + MOV AX,DX + XOR DX,DX + DIV SI + MOV BX,AX + POP AX + DIV SI + XCHG BX,DX + PUSH AX + OR AX,DX + POP AX + JZ DO_PAD + PUSH BX + CALL PNUM + POP BX + JMP SHORT REM +DO_PAD: + CMP CS:BYTE PTR[PRINTF_LEFT],0 + JNZ REM + CALL PAD +REM: + MOV AX,BX + CMP AL,10 + JB NOT_HEX + CMP CS:BYTE PTR [PRINTF_HEX],0 + JNZ NOT_HEX + ADD AL,CS:BYTE PTR [TABLE_INDEX] +NOT_HEX: + MOV BX,OFFSET dg:PRINTF_TABLE + PUSH DS + PUSH CS + POP DS + XLAT 0 + POP DS + push cx + CALL OUTCHR + pop cx + RET + +PAD: + OR CX,CX + JLE PAD_DONE + MOV AL,CS:BYTE PTR [PAD_CHAR] +PAD_LOOP: + push cx + CALL OUTCHR + pop cx + LOOP PAD_LOOP +PAD_DONE: + RET + +OUTCHR: + STOSB + CMP DI,offset dg:bufend-1 ;Don't count the nul + jz foob2 + ret +foob2: + MOV CX,BUFSIZ +WRITE_CHARS: + push bx + MOV BX,1 + push ds + PUSH CS + POP DS + MOV DX,OFFSET dg:PRINTF_BUF + MOV AH,WRITE + INT 21H + pop ds + pop bx + MOV DI,OFFSET dg:PRINTF_BUF + RET + +FLUSH: + CMP DI,OFFSET dg:PRINTF_BUF + jnz foob1 + ret +foob1: + SUB DI,OFFSET dg:PRINTF_BUF + MOV CX,DI + call write_chars + ret + +CLEAR_FLAGS: + XOR ax,ax + MOV BYTE PTR CS:[PRINTF_LEFT],al ;Reset justifing flag + MOV BYTE PTR CS:[PRINTF_LONG],al ;Reset long flag + MOV BYTE PTR CS:[TABLE_INDEX],al ;Reset hex table index + MOV CS:[PRINTF_WIDTH],ax ;Reinitialize width to 0 + MOV BYTE PTR CS:[PAD_CHAR]," " ;Reset padding character + MOV BYTE PTR CS:[S_FLAG],al ;Clear the string flag + ret + +Code Ends + End diff --git a/SRC/CMD/PRINT/PRIDEFS.INC b/SRC/CMD/PRINT/PRIDEFS.INC new file mode 100644 index 0000000..00d5a99 --- /dev/null +++ b/SRC/CMD/PRINT/PRIDEFS.INC @@ -0,0 +1,213 @@ +; SCCSID = @(#)pridefs.asm 4.4 85/07/17 +title 3.00 Print Utility + +;MS-DOS PSPRINT/PRINT program for background printing of text files +; to the list device. +; +; IBM SERVER VERSION +; +; INT 28H is a software interrupt generated by the DOS +; in its I/O wait loops. This spooler can be assembled for +; operation using only this interrupt which is portable from +; system to system. It may also be assembled to use a hardware +; timer interrupt in addition to the software INT 28H. The +; purpose of using hardware interrupts is to allow printing to +; continue during programs which do not enter the system and +; therefore causes the INT 28H to go away. A timer interrupt is +; chosen in preference to a "printer buffer empty" interrupt +; because PRINT in the timer form is generic. It can be given +; the name of any currently installed character device as the +; "printer", this makes it portable to devices which are +; installed by the user even in the hardware case. It could be +; modified to use a buffer empty interrupt (no code is given for +; this case), if this is done the PROMPT and BADMES messages and +; their associated code should be removed as PRINT will then be +; device specific. +; +; V1.00 07/03/82 +; V2.00 07/05/83 A.Reynolds +; New INT 2FH interface, Pathnames, context switch. +; V2.50 09/14/83 M.A.Ulloa +; Turned it back to a print +; 11/21/83 M.A.Ulloa +; Repaired bug in file cancel code +; 11/28/83 M.A.Ulloa +; Added int 23 and 24 handlers to transient. +; 01/27/84 M.A.Ulloa +; Allways checks for valid drive. +; V3.00 02/03/84 M.A.Ulloa +; Partitioned so as to assemble on a PC +; By the by, it is V3.00 now. +; 05/23/85 K.G.Schulmeisters +; Chains into INT19 (bootstrap) to unhook +; INT_1C (timer) and INT_15 (AT's Wait On Event) +; + + +; Aaron's rambling: +; +; BEWARE ALL YEE WHO ENTER HERE. +; PRINT is an amazingly complex program. MS-DOS versions below 3.00 are +; NOT re-entrant, this means that this utility is basically not a +; possibility. It gets by on the fact that it is written by the same +; person who wrote the OS. Since you are not that person, you must be very +; careful about making any modification to this utility. There are a +; number of things which may seem to be unnecessary on first examination. +; BEWARE, almost every line of code is there for a very good reason. The +; order of things is very carefully chosen. PRINT is full of potential +; windows, make sure that you do not open one by careless modification. Do +; not look for a lot of help from the comments, a complete explanation +; would probably fill a book. A succesful modifier will have an in-depth +; knowledge of the internal function of MS-DOS, and of the PRINT utility +; itself through in depth study of the comments AND the code. + + +subttl General Definition +page + + +FALSE EQU 0 +TRUE EQU NOT FALSE + +;IBM EQU TRUE +;IBMVER EQU IBM +;MSVER EQU FALSE + +include version.inc + + IF MSVER +HARDINT EQU FALSE ;No hardware ints +AINT EQU FALSE ;No need to do interrupt acknowledge + ENDIF + + IF IBM +HARDINT EQU TRUE +INTLOC EQU 1CH ;Hardware interrupt location (Timer) +REBOOT EQU 19H ;ROM BIOS "Bootstrap" +AINT EQU TRUE ;Acknowledge interrupts +EOI EQU 20H ;End Of Interrupt "instruction" +AKPORT EQU 20H ;Interrupt Acknowledge port + ENDIF + +; The following values have to do with the ERRCNT variable and the CNTMES +; message. The values define levels at wich it is assumed an off-line error +; exists. ERRCNT1 defines the value of ERRCNT above which the CNTMES message +; is printed by the transient. ERRCNT2 defines the value of ERRCNT above +; which the resident will give up trying to print messages on the printer, it +; is much greater than ERRCNT1 because a much tighter loop is involved. The +; bounding event which determines the correct value is the time required to +; do a form feed. + + IF IBM +ERRCNT1 EQU 1500 +ERRCNT2 EQU 20000 + ELSE +ERRCNT1 EQU 1500 +ERRCNT2 EQU 20000 + ENDIF + + +;WARNING DANGER WARNING: +; PRINT is a systems utility. It is clearly understood that it may have +; to be entirely re-written for future versions of MS-DOS. The following +; TWO vectors are version specific, they may not exist at all in future +; versions. If they do exist, they may function differently. +; ANY PROGRAM WHICH IMITATES PRINTS USE OF THESE VECTORS IS ALSO A SYSTEMS +; UTILITY AND IS THEREFORE NOT VERSION PORTABLE IN ANY WAY SHAPE OR FORM. +; YOU HAVE BEEN WARNED, "I DID IT THE SAME WAY PRINT DID" IS NOT AN REASON +; TO EXPECT A PROGRAM TO WORK ON FUTURE VERSIONS OF MS-DOS. + +SOFTINT EQU 28H ;Software interrupt generated by DOS +ComInt EQU 2FH ;Communications interrupt used by PSPRINT + ; Multiplex number 0 and 1 + +;----- Default (and Minimal) Print queue length +DefQueueLen equ 10 ; 10 files worth +MinQueueLen equ 4 ; 4 files worth min +MaxQueueLen equ 32 ; 32 files worth max. + +;----- Maximum length of a file name (incl nul) +MaxFileLen equ 64 + +; **************** Bogosity Warning ***************** +; Below is the equate that MaxFile SHOULD be. Since the 3.0/3.1 documentation +; documents each queue entry as being 64 chars long. Yes it is known that +; that causes Print to misbehave on files deep in trees. But for +; compatibilities sake, IBM insisted that we change the code back to the +; way it was. +;MaxFileLen equ 63 + 2 + 12 ; 63 characters as Command.com's + ; max. path length + ; 2 character for the Drive ext. + ; 12 characters for the max. valid + ; DOS filename + + +.xlist +.xcref +BREAK MACRO subtitle + SUBTTL subtitle + PAGE +ENDM + +stdin EQU 0 +stdout EQU 1 +stderr EQU 2 +stdaux EQU 3 +stdprn EQU 4 + + INCLUDE DEVSYM.INC + INCLUDE SYSCALL.INC + INCLUDE ERROR.INC + INCLUDE SYSVAR.INC + INCLUDE FIND.INC + include dpl.inc + INCLUDE PDB.INC + INCLUDE SYSCALL.INC + INCLUDE MI.INC + include versiona.inc +.list +.cref + + +error_busy EQU 9 +error_queue_full EQU 8 +error_name_too_long EQU 12 + +IF1 + IF IBM + %out IBM VERSION + ELSE + %out MS-DOS VERSION + ENDIF +ENDIF + +BREAK + + +CodeR Segment public para +CodeR EndS + +Code Segment public para +Code EndS + +Data Segment public byte +Data EndS + +Stack Segment Stack +Stack Ends + +DG group Code,Data,Stack + +SaveReg MACRO reglist ;; push those registers +IRP reg, + PUSH reg +ENDM +ENDM +.xcref SaveReg + +RestoreReg MACRO reglist ;; pop those registers +IRP reg, + POP reg +ENDM +ENDM + \ No newline at end of file diff --git a/SRC/CMD/PRINT/PRINT.LNK b/SRC/CMD/PRINT/PRINT.LNK new file mode 100644 index 0000000..d93ea65 --- /dev/null +++ b/SRC/CMD/PRINT/PRINT.LNK @@ -0,0 +1,2 @@ +PRINT_RM PRINT_R PRINT_T PRINT_TM NPRINTF +PRINT.EXE /m; diff --git a/SRC/CMD/PRINT/PRINT_R.ASM b/SRC/CMD/PRINT/PRINT_R.ASM new file mode 100644 index 0000000..f220d40 --- /dev/null +++ b/SRC/CMD/PRINT/PRINT_R.ASM @@ -0,0 +1,2189 @@ +; SCCSID = @(#)print_r.asm 4.7 85/09/13 + INCLUDE pridefs.inc + + +BREAK + +; +; MSDOS V3.00 PRINT +; +; Resident Portion +; + +Code Segment public para + extrn TransRet:WORD,TransSize:WORD +Code EndS + + + +BREAK + +CodeR Segment public para + + extrn ERRMES:BYTE, ERRMEST:BYTE, BELMES:BYTE, ErrMesT2:BYTE + extrn CanMes:BYTE, CanFilNAm:BYTE, AllCan:BYTE, ERR0:BYTE + extrn ERR1:BYTE, ERR2:BYTE, ERR3:BYTE, ERR4:BYTE, ERR5:BYTE + extrn ERR6:BYTE, ERR7:BYTE, ERR8:BYTE, ERR9:BYTE, ERR10:BYTE + extrn ERR11:BYTE, ERR12:BYTE, FATMES:BYTE, BADDRVM:BYTE, + extrn BADMES:BYTE, badmeslen:WORD, GOODMES:BYTE, goodmeslen:WORD + +if hardint + public SliceCnt, BusyTick, MaxTick, TimeSlice +endif + + public EndRes, BlkSiz, QueueLen, PChar + public ListName, FileQueue, EndQueue, Buffer + public EndPtr, NxtChr, MoveTrans + +assume CS:CodeR + +public PRNR001S,PRNR001E +PRNR001S: + db "*** Microsoft/V310 ***" + + DB (362 - 80h) + 310 DUP (?) ; (362 - 80h) is IBM's New + ; recommended Stack Size - + ; Old recommended Stack Size + ; == New stack growth +ISTACK LABEL WORD ;Stack starts here and grows down the + +;Resident data + +; +; Due to flagrant bogosity by file servers, BUSY is *ALWAYS* relevant. +; +BUSY DB 0 ;Internal ME flag + + IF HARDINT +; +; WARNING!!! The *&^%(*&^ 286 chip hangs if you access a word that will wrap +; at the segment boundary. Make the initial INDOS point somewhere reasonable. +; +INDOS DD TimeSlice ;DOS buisy flag +NEXTINT DD ? ;Chain for int +NEXT_REBOOT DD ? ;Chain for ROM bootstrap + +fFake db 0 ; TRUE => do not diddle I/O ports +SOFINT DB 0 ;Internal ME flag +TICKCNT DB 0 ;Tick counter +TICKSUB DB 0 ;Tick miss counter +SLICECNT DB 8 ;Time slice counter, init to same val + ; as TIMESLICE + +TIMESLICE DB 8 ;The PRINT scheduling time slice. PRINT + ; lets this many "ticks" go by before + ; using a time slice to pump out characters. + ; Setting this to 3 for instance means PRINT + ; Will skip 3 slices, then take the fourth. + ; Thus using up 1/4 of the CPU. Setting it + ; to one gives PRINT 1/2 of the CPU. + ; The above examples assume MAXTICK is + ; 1. The actual PRINT CPU percentage is + ; (MAXTICK/(1+TIMESLICE))*100 + +MAXTICK DB 2 ;The PRINT in timeslice. PRINT will pump + ; out characters for this many clock ticks + ; and then exit. The selection of a value + ; for this is dependent on the timer rate. + +BUSYTICK DB 1 ;If PRINT sits in a wait loop waiting for + ; output device to come ready for this + ; many ticks, it gives up its time slice. + ; Setting it greater than or equal to + ; MAXTICK causes it to be ignored. + +;User gets TIMESLICE ticks and then PRINT takes MAXTICK ticks unless BUSYTICK +; ticks go by without getting a character out. + ENDIF + +QueueLen db DefQueueLen ; Actual length of print queue + even +EndQueue dw ? ; pointer to end of print queue +QueueTail dw offset CodeR:FileQueue ; pointer to next free entry + ; in the print queue +buffer dw ? ; pointer to data buffer + +I24_ERR DW ? ;Save location for INT 24H error code +Ctrlc DB ? ; saved ^C trapping state +SPNEXT DD ? ;Chain location for INT 28 +COMNEXT DD ? ;Chain location for INT 2F +SSsave DW ? ;Stack save area for INT 24 +SPsave DW ? +HERRINT DD ? ;Place to save Hard error interrupt +LISTDEV DD ? ;Pointer to Device +COLPOS DB 0 ;Column position for TAB processing +CURRFIL DB 0 +NXTCHR DW ? +CURRHAND DW -1 +PrinterNum DW -1 ; index for printer +QueueLock db 0 ; queue lock, 0=unlocked + + +PChar db ? ; path character +AmbCan db ? ; = 1 ambigous cancel +CanFlg db ? ; = 1 Current was already canceled +ACanOcrd db ? ; = 1 a file was found during an + ; ambigous cancel + +;--- Warnning: this is a FCB!! +ACBuf db ? +ACName db 8 dup(?) +ACExt db 3 dup(?) + db 4 dup(?) ; how big is an unopened fcb??? + + +CONTXTFLAG DB 0 ;0 means his context, NZ means me +HISPDB DW ? +PABORT DB 0 ;Abort flag +BLKSIZ DW 512 ;Size of the PRINT I/O block in bytes +ENDPTR DW ? + +COMDISP LABEL WORD ; Communications dispatch table + DW OFFSET CodeR:INST_REQ + DW OFFSET CodeR:ADDFIL + DW OFFSET CodeR:CANFIL + DW offset CodeR:CanAll + DW OFFSET CodeR:QSTAT + DW offset CodeR:EndStat + DW offset CodeR:QSTATDEV + +;Resident messages + +MESBAS DW OFFSET CodeR:ERR0 + DW OFFSET CodeR:ERR1 + DW OFFSET CodeR:ERR2 + DW OFFSET CodeR:ERR3 + DW OFFSET CodeR:ERR4 + DW OFFSET CodeR:ERR5 + DW OFFSET CodeR:ERR6 + DW OFFSET CodeR:ERR7 + DW OFFSET CodeR:ERR8 + DW OFFSET CodeR:ERR9 + DW OFFSET CodeR:ERR10 + DW OFFSET CodeR:ERR11 + DW OFFSET CodeR:ERR12 +ENDRES DW ? ; filled in at initialization time +PRNR001E: + +CodeR EndS + + + +BREAK + +CodeR Segment public para + +Break + +TestSetServer: +IF IBM + CLC + PUSH AX + MOV AX,8700h ; Can I run? + INT 2Ah + POP AX +ENDIF + ret + +LeaveServer: +IF IBM + PUSH AX + MOV AX,8701h + INT 2Ah + POP AX +ENDIF + ret + +;Interrupt routines +ASSUME CS:CodeR,DS:NOTHING,ES:NOTHING,SS:NOTHING +; +; PRINT is stimulated by a hardware interrupt. +; +; +; The Server may also stimulate us during timer ticks (if we handled the +; ticks ourselves, it would be disasterous. Therefore, we have a substitute +; entry here that simulates the timer stuff but does NOT muck with the ports. +; + IF HARDINT +FakeINT1C: + MOV fFake,-1 + JMP SHORT InnerHardInt + +HDSPINT: ;Hardware interrupt entry point + mov fFake,0 +InnerHardInt: + CALL TestSetServer + JNC TickTime + jmp ChainInt +TickTime: + INC [TICKCNT] ;Tick + INC [TICKSUB] ;Tick + CMP [SLICECNT],0 + JZ TIMENOW + DEC [SLICECNT] ;Count down + JMP SHORT HardIntDone ;Not time yet +TIMENOW: + CMP BUSY,0 ;See if interrupting ourself + JNZ HardIntDone + + IF IBM + push ax ; check for nested interrupts + mov al,00001011b ; select ISR in 8259 + out 20H,al + JMP x +x: + in al,20H ; get ISR register + and al,0FEH ; mask timer int + pop ax + jnz HardIntDone ; there was another int in service... + ENDIF + + PUSH DS + PUSH SI + LDS SI,[INDOS] ;Check for making DOS calls +; +; WARNING!!! Due to INT 24 clearing the INDOS flag, we must test both INDOS +; and ERRORMODE at once! These must be contiguous in MSDATA. +; + CMP WORD PTR [SI-1],0 + POP SI + POP DS + JNZ HardIntDone ;DOS is Busy + INC [BUSY] ;Exclude furthur interrupts + MOV [TICKCNT],0 ;Reset tick counter + MOV [TICKSUB],0 ;Reset tick counter + STI ;Keep things rolling + + IF AINT + TEST fFake,-1 + JNZ NoAck + PUSH AX + MOV AL,EOI ;Acknowledge interrupt + OUT AKPORT,AL + POP AX +NoAck: + ENDIF + + CALL DOINT + CLI + PUSH AX + MOV AL,[TIMESLICE] + MOV [SLICECNT],AL ;Either soft or hard int resets time slice + POP AX + DEC Busy ;Done, let others in +HardIntDone: + Call LeaveServer +CHAININT: + TEST fFake,-1 + JNZ DoIRET + JMP [NEXTINT] ;Chain to next clock routine +DoIRET: + IRET + ENDIF + + +; +; PRINT is stimulated by a spooler idle interrupt +; +SPINT: ;INT 28H entry point + CALL TestSetServer + JC NxtSp + + IF HARDINT + CMP [BUSY],0 + JNZ SpIntDone + INC [BUSY] ;Exclude hardware interrupt + INC [SOFINT] ;Indicate a software int in progress + ENDIF + + STI ;Hardware interrupts ok on INT 28H entry + CALL DOINT + + IF HARDINT + CLI + MOV [SOFINT],0 ;Indicate INT done + PUSH AX + MOV AL,[TIMESLICE] + MOV [SLICECNT],AL ;Either soft or hard int resets time slice + POP AX + DEC Busy + ENDIF +SpIntDone: + call LeaveServer + +NXTSP: JMP [SPNEXT] ;Chain to next INT 28 + +; +; Since we may be entering at arbitrary times, we need to get/set the extended +; error as we may end up blowing it away. We do not do this on spooler ints. +; + +public PRNR002S, PRNR002E +PRNR002S: + +SaveState DPL <> ; empty DPL + +PRNR002E: + +public enterprint +EnterPRINT: + IF HardInt + TEST SofInt,-1 + JNZ EnterDone + ENDIF + MOV AH,GetExtendedError + CALL DO_21 + MOV SaveState.DPL_AX,AX + MOV SaveState.DPL_BX,BX + MOV SaveState.DPL_CX,CX + MOV SaveState.DPL_DX,DX + MOV SaveState.DPL_SI,SI + MOV SaveState.DPL_DI,DI + MOV SaveState.DPL_DS,DS + MOV SaveState.DPL_ES,ES +EnterDone: + RET + +public leaveprint +LeavePRINT: + IF HardInt + TEST SofInt,-1 + JNZ LeaveDone + ENDIF + MOV AX,(ServerCall SHL 8) + 10 + PUSH CS + POP DS + MOV DX,OFFSET CodeR:SaveState + CALL Do_21 +LeaveDone: + RET + +public doint +DOINT: +ASSUME CS:CodeR,DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [CURRFIL],0 + JNZ GOAHEAD +SPRET: + ret ;Nothing to do + +GOAHEAD: + cmp [QueueLock],1 + je spret ; queue locked, do nothing... + PUSH AX ;Need a working register + MOV [SSsave],SS + MOV [SPsave],SP + MOV AX,CS + CLI +;Go to internal stack to prevent INT 24 overflowing system stack + MOV SS,AX + MOV SP,OFFSET CodeR:ISTACK + STI + PUSH ES + PUSH DS + PUSH BP + PUSH BX + PUSH CX + PUSH DX + PUSH SI + PUSH DI + PUSH CS + POP DS +ASSUME DS:CodeR + + Call EnterPRINT + + MOV BX,[NXTCHR] + CMP BX,[ENDPTR] + JB PLOOP + JMP READBUFF ;Buffer empty + +DONEJMPJP: + POPF +DONEJMPJ: + JMP DONEJMP + +FILEOFJ: +ASSUME DS:CodeR + JMP FILEOF + +PLOOP: + IF HARDINT + MOV BX,[NXTCHR] + CMP BX,[ENDPTR] + JAE DONEJMPJ ;Buffer has become empty + CMP [SOFINT],0 + JNZ STATCHK + PUSH AX + MOV AL,[MAXTICK] + CMP [TICKCNT],AL ;Check our time slice + POP AX + JAE DONEJMPJ +STATCHK: + ENDIF + + CALL PSTAT + PUSHF + CMP [CURRFIL],0 + JZ DONEJMPJP ;File got cancelled by error + POPF + + IF HARDINT + JZ DOCHAR ;Printer ready + CMP [SOFINT],0 + ENDIF + + JNZ DONEJMP ;If soft int give up + + IF HARDINT + PUSH AX + MOV AL,[BUSYTICK] + CMP [TICKSUB],AL ;Check our busy timeout + POP AX + JAE DONEJMP + JMP PLOOP + ENDIF + +DOCHAR: + MOV AL,BYTE PTR [BX] + CMP AL,1AH ;^Z? + JZ FILEOFJ ;CPM EOF + CMP AL,0DH ;CR? + JNZ NOTCR + MOV [COLPOS],0 +NOTCR: + CMP AL,9 ;TAB? + JNZ NOTABDO + MOV CL,[COLPOS] ;expand tab to # spaces + OR CL,0F8H + NEG CL + XOR CH,CH + JCXZ TABDONE ;CX contains # spaces to print +TABLP: + MOV AL," " + INC [COLPOS] + PUSH CX + CALL POUT + POP CX + DEC CX ;G + JZ TABDONE ;G We're done - get next char + JMP PLOOP ;G Keep processing tab + +;G LOOP TABLP +;G JMP TABDONE + +NOTABDO: + CMP AL,8 ;Back space? + JNZ NOTBACK + DEC [COLPOS] +NOTBACK: + CMP AL,20H ;Non Printing char? + JB NOCHAR + INC [COLPOS] ;Printing char +NOCHAR: + CALL POUT ;Print it +TABDONE: + INC [NXTCHR] ;Next char + + IF HARDINT + MOV [TICKSUB],0 ;Got a character out, Reset counter + CMP [SOFINT],0 ;Soft int does one char at a time + JNZ DONEJMP + JMP PLOOP + ENDIF + +DONEJMP: + CALL CONTEXT_BACK + Call LeavePRINT + + POP DI + POP SI + POP DX + POP CX + POP BX + POP BP + POP DS + POP ES +ASSUME DS:NOTHING,ES:NOTHING + CLI + MOV SS,[SSsave] ;Restore Entry Stack + MOV SP,[SPsave] + STI + POP AX + RET + +CONTEXT_BACK: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [CONTXTFLAG],0 + JZ CONTOK + SaveReg + MOV BX,[HISPDB] + MOV AH,SET_CURRENT_PDB + call do_21 + RestoreReg + MOV [CONTXTFLAG],0 +CONTOK: + RET + +CONTEXT_SWITCH: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [CONTXTFLAG],0 + JNZ RET45 + SaveReg + MOV AH,GET_CURRENT_PDB + call do_21 + MOV [HISPDB],BX + MOV BX,CS + sub bx,10h ; The 2.5 print is an exe program + MOV AH,SET_CURRENT_PDB + call do_21 + RestoreReg + MOV [CONTXTFLAG],1 +RET45: RET + + +;--- Refill the print buffer --- +READBUFF: +ASSUME DS:CodeR,ES:NOTHING,SS:NOTHING + + call Set24 ; switch Int24 vector + MOV [PABORT],0 ;No abort + MOV BX,[CURRHAND] + MOV CX,[BLKSIZ] + MOV DX,[BUFFER] + MOV AH,READ + call My21 + PUSHF + call Res24 ; reset Int 24 vector + CMP [PABORT],0 + JZ NOHERR + POP AX ;Flags from read + jmp FilClose ;Barf on this file, got INT 24 + + +NOHERR: + POPF + JC FILEOF + CMP AX,0 + JZ FILEOF ;Read EOF? + MOV BX,[BUFFER] ;Buffer full + MOV DI,BX + ADD DI,AX + MOV [NXTCHR],BX + MOV CX,[BLKSIZ] + SUB CX,AX + JCXZ DONEJ ; Buffer is completely full + PUSH CS + POP ES + MOV AL,1AH + cld + REP STOSB ; ^Z pad the buffer +DONEJ: + JMP DONEJMP + +FILEOF: + MOV AL,0CH ;Form feed + CALL POUT + +;--- Close file +; note: we came here from an i24 then PAbort is already = 1 +FilClose: + call Set24 + mov pAbort,-1 + MOV BX,[CURRHAND] + MOV AH,CLOSE + call My21 + call Res24 + MOV [CURRFIL],0 ; No file + MOV [CURRHAND],-1 ; Invalid handle + MOV AX,[ENDPTR] + MOV [NXTCHR],AX ; Buffer empty + +;--- Send close on output device + call Close_Dev + +;--- compact the print queue +CompQAgn: + call CompQ + +;--- Check if there are any more files to print + mov si,offset CodeR:FileQueue + cmp byte ptr [si],0 ; no more left if name starts with nul + je NoFilesLeft + call Set24 + MOV [PABORT],0 ;No abort + mov dx,si ; DS:DX points to file name + mov ax,(open shl 8) + call My21 ; try opening new file + pushf + call Res24 + cmp [PAbort],0 + je NoI24a + popf + jmp short CompQAgn ; try next file + +NoI24a: + popf + jnc GotNewFile + call PrtOpErr + jmp short CompQAgn + +GotNewFile: ; buffer was already marked as empty + mov [CurrHand],ax + mov [CurrFil],1 + +;--- Send Open on output device + call Open_Dev + +NoFilesLeft: + JMP DONEJMP + + +;--- Print open error --- +; preserves DS + +PrtOpErr: +assume ds:CodeR,es:Nothing + +; This stuff constitutes a "file" so it is bracketed by an open/close +; on the output device. + +;--- Send Open on output device + call Open_Dev + + push cs + pop es +assume es:CodeR + mov si,offset CodeR:ErrMes + call ListMes + mov si,offset CodeR:ErrMesT2 + call ListMes + mov si,offset CodeR:FileQueue + call ListMes2 + mov si,offset CodeR:BelMes + call ListMes + +;--- Send close on output device + call Close_Dev + + ret + + +;--- Compact File Queue --- +; modifies: AX,CX,SI,DI,ES + +CompQ: +assume ds:CodeR,es:nothing,ss:nothing + push cs + pop es +assume es:CodeR + mov di,offset CodeR:FileQueue ; ES:DI points to top of queue + mov si,(offset CodeR:FileQueue + MaxFileLen) ; DS:SI points to next entry + mov cx,[EndQueue] + sub cx,si ; length in bytes of the queue + cld + rep movsb ; compact the queue + mov ax,[QueueTail] ; normalize tail pointer as we + sub ax,MaxFileLen ; know have a new "next empty slot" + mov [QueueTail],ax + mov si,ax + mov byte ptr [si],0 ; nul first byte of last entry + ret + + +BREAK + +;--- Set Local Int 24 vector --- +; modifies: AX,DX + +Set24: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + push es + push bx + push dx + MOV AL,24H + MOV AH,GET_INTERRUPT_VECTOR + call do_21 + MOV WORD PTR [HERRINT+2],ES ; Save current vector + MOV WORD PTR [HERRINT],BX + MOV DX,OFFSET CodeR:DSKERR + MOV AL,24H + MOV AH,SET_INTERRUPT_VECTOR ; Install our own + call do_21 ; Spooler must catch its errors + pop dx + pop bx + pop es + ret + + +;--- Reset Old Int 24 vector --- +; modifies: none + +Res24: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + push ds + PUSH AX + push dx + LDS DX,[HERRINT] +ASSUME DS:NOTHING + MOV AL,24H + MOV AH,SET_INTERRUPT_VECTOR + call do_21 ;Restore Error INT + pop dx + POP AX + pop ds + ret + + +;--- INT 24 handler --- +DSKERR: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [PABORT],0 + JNZ IGNRET + STI + PUSH BX + PUSH CX + PUSH DX + PUSH DI + PUSH SI + PUSH BP + PUSH ES + PUSH DS + PUSH CS + POP DS + PUSH CS + POP ES +ASSUME DS:CodeR,ES:CodeR + ADD [BADDRVM],AL ;Set correct drive letter + MOV SI,OFFSET CodeR:ERRMES + CALL LISTMES + TEST AH,080H + JNZ FATERR + AND DI,0FFH + CMP DI,12 + JBE HAVCOD + MOV DI,12 +HAVCOD: + MOV [I24_ERR],DI + SHL DI,1 + MOV DI,WORD PTR [DI+MESBAS] ; Get pointer to error message + MOV SI,DI + CALL LISTMES ; Print error type + MOV SI,OFFSET CodeR:ERRMEST + CALL LISTMES + mov si,offset CodeR:FileQueue ; print filename + call ListMes2 ; print name + mov si,offset CodeR:BelMes + call ListMes +SETABORT: + INC [PABORT] ;Indicate abort + POP DS + POP ES + POP BP + POP SI + POP DI + POP DX + POP CX + POP BX +IGNRET: + XOR AL,AL ;Ignore + IRET + +FATERR: + MOV [I24_ERR],0FFH + MOV SI,OFFSET CodeR:FATMES + CALL LISTMES + JMP SHORT SETABORT + + +BREAK + +;--- Communications interrupt --- +SPCOMINT proc far +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP AH,1 + JBE MINE + JMP [COMNEXT] + +MINE: + CMP AL,0F8H + JAE RESERVED_RET +IF HardInt + CMP AX,0080h + JNZ CheckPSP + JMP FakeINT1C +ENDIF +CheckPSP: + OR AH,AH + JNE PSPDO + MOV AL,1 ; Tell PSPRINT to go away (AH = 1) +RESERVED_RET: + IRET + +PSPDO: + OR AL,AL + JNE PSPDISP +INST_REQ: + MOV AL,0FFH + IRET + +PSPDISP: + CMP [BUSY],0 + JZ SETCBUSY +ErrBusy: + MOV AX,error_busy +setcret: + push bp + mov bp,sp + or word ptr [bp+6],f_Carry + pop bp + iret + +SETCBUSY: + XOR AH,AH + CMP AX,6 ; check function within valid range + Jbe GoForIt + mov ax,error_invalid_function + jmp setcret +GoForIt: + INC [BUSY] ;Exclude + STI ;Turn ints back on + PUSH DI ;G + PUSH ES + PUSH DS + PUSH CS + POP DS +ASSUME DS:CodeR + mov [QueueLock],0 ; unlock the print queue + SHL AX,1 ;Turn into word index + mov di,ax + call ComDisp[DI] + assume ds:nothing + jc ErrRet +ASSUME DS:CodeR,ES:NOTHING + push ds + push cs + pop ds +ASSUME DS:CodeR,ES:NOTHING + CALL PSTAT ; Tweek error counter + pop ds + assume ds:nothing +ErrRet: + pushf + call Context_Back + popf + CLI + DEC BUSY ; leaves carry alone! + POP DS +ASSUME DS:NOTHING + POP ES + POP DI ;G + jc setcret + push bp + mov bp,sp + and word ptr [bp+6],NOT f_Carry + pop bp + iret +SpComInt Endp + +BREAK + +;--- Return pointer to file queue --- +QSTAT: +ASSUME DS:CodeR,ES:NOTHING + + mov [QueueLock],1 ; lock the print queue + CALL PSTAT ; Tweek error counter + push bp + mov bp,sp ; 0 2 4 + MOV [bp+ 2 + 2],cs ; + POP BP + mov si,offset CodeR:FileQueue + mov dx,[ErrCnt] ; return error count + clc + ret + +;--- Return pointer to device driver if active --- +QSTATDEV: +ASSUME DS:CodeR,ES:NOTHING + + xor ax,ax ;g assume not busy + mov [QueueLock],1 ;g lock the print queue + CALL PSTAT ;g Tweek error counter + cmp byte ptr FileQueue,0 ;g is there anything in the queue? + clc ;g + jz qstatdev_end ;g no - just exit + mov ax,error_queue_full ;g yes - set error queue full + mov si,word ptr [listdev+2] ;g get segment of list device + push bp ;g + mov bp,sp ;g 0 2 4 + MOV [bp+2+2],si ;g seg of device to DS + pop bp ;g + mov si,word ptr [listdev] ;g offset of device to SI + stc ;g + +qstatdev_end: ;g + mov [QueueLock],0 ;g unlock the print queue + ret ;g + +BREAK + +;--- Unlock the print queue --- +EndStat: +assume ds:CodeR,es:nothing + mov [QueueLock],0 + clc + ret + +BREAK + +; +; Note that we need to spin until the background is free +; +CanAll: +assume ds:CodeR,es:nothing + + cmp [CurrFil],0 ; are we currently printing? + jnz DoCanAll ; yes, go and cancel + ret ; carry is clear + +DoCanAll: + +;--- Cancel active file + mov bx,[CurrHand] ; close the current file + call Set24 + mov [PAbort],1 ; no Int24's + mov ah,Close + call My21 + call Res24 + mov [CurrFil],0 ; no files to print + mov [CurrHand],-1 ; invalidate handle + mov ax,[EndPtr] ; buffer empty + mov [NxtChr],ax + +;--- Cancel rest of files + mov si,offset CodeR:FileQueue + mov [QueueTail],si ; next free entry is the first + mov byte ptr [si],0 ; nul first byte of firts entry + mov si,offset CodeR:AllCan + call ListMes ; print cancelation message + mov si,offset CodeR:BelMes + call ListMes ; ring!! + +;--- Send close on output device + call Close_Dev + clc + ret + +BREAK + +CANFIL: +ASSUME DS:CodeR,ES:NOTHING + + CMP [CURRFIL],0 + JNZ DOCAN + ret ; carry is clear + +DOCAN: + +;--- find which file to cancel + push bp + mov bp,sp ; 0 2 4 + MOV ds,[bp+ 2 + 2] ; + POP BP + +assume ds:nothing + push cs + pop es +assume es:CodeR + mov CS:[CanFlg],0 ; reset message flag + mov CS:[ACanOcrd],0 ; no cancelation has ocured yet + mov bx,offset CodeR:FileQueue ; ES:BX points to 1st entry in queue + call AmbChk + +AnotherTry: + mov di,bx ; ES:DI points to 1st entry in queue + mov si,dx ; DS:SI points to filename to cancel +MatchLoop: + lodsb + cmp al,byte ptr es:[di] ; names in queue are all in upper case + je CharMatch + call UpConv ; did not match, try upper case + cmp al,byte ptr es:[di] + jne AnotherName ; a mismatch, try another name +CharMatch: + cmp es:byte ptr es:[di],0 ; was this the terminating nul? + je NameFound ; yes we got our file... + inc di + jmp MatchLoop + +AnotherName: + cmp CS:[AmbCan],1 ; ambigous file name specified? + jne AnName ; if not then no more work to do + cmp al,"?" + jne AnName + cmp byte ptr es:[di],"." + je FindPeriod + cmp byte ptr es:[di],0 ; if nul then file names match + jne CharMatch ; only if only ?'s are left... +FindNul: + lodsb + cmp al,"?" + je FindNul + cmp al,"." + je FindNul + or al,al + jne AnName ; found something else, no match + jmp short NameFound + +FindPeriod: ; ambigous files always have 8 chars + lodsb ; in name so we can not look for the + or al,al ; period twice (smart uh?) + je AnName ; no period found, files do not match + cmp al,"." + jne FindPeriod + jmp short CharMatch + +AnName: + add bx,MaxFileLen + cmp byte ptr es:[bx],0 ; end of queue? + jne AnotherTry ; no, continue... + cmp CS:[ACanOcrd],1 ; yes, was there a file found? + jne sk2 + push cs + pop ds +assume ds:CodeR ; StartAnFil likes it this way... + jmp StartAnFil ; restart printing + +sk2: +assume ds:nothing + + mov ax,error_file_not_found + stc + ret + + +;--- Name found, check if current file +NameFound: + push cs + pop ds +assume ds:CodeR + mov [ACanOcrd],1 ; remember we found a file + cmp bx,offset CodeR:FileQueue ; is the file being printed? + jne NotCurrent ; no, just compact the queue + cmp [CanFlg],0 + jne NotCurrent ; only cance current once + +;--- Cancel current file + mov [CanFlg],1 ; remeber we already canceled current + push bx + mov bx,[CurrHand] ; close the current file + call Set24 + mov [PAbort],1 ; no Int24's + mov ah,Close + call My21 + call Res24 + mov [CurrFil],0 ; no files to print + mov [CurrHand],-1 ; invalidate handle + mov ax,[EndPtr] ; buffer empty + mov [NxtChr],ax + pop bx + +;--- print cancelation message + push bx + mov si,offset CodeR:CanMes + call ListMes ; print cancelation message + mov si,bx ; points to filename + call ListMes2 ; print filename + mov si,offset CodeR:CanFilNam + call ListMes + mov si,offset CodeR:BelMes + call ListMes ; ring!! + pop bx + +;--- Send close on output device + call Close_Dev + +NotCurrent: + mov di,bx ; DI points to entry to cancel + mov si,bx + add si,MaxFileLen ; SI points to next entry + cmp si,[QueueTail] ; is the entry being canceled the last? + jne DoCompact ; no, do compaction + mov byte ptr [di],0 ; yes, just nul the first byte + jmp short CompactDone +DoCompact: + mov cx,[EndQueue] ; CX points to the end of the queue + sub cx,si ; length of the remainning of the queue + cld + rep movsb ; compact the queue +CompactDone: + mov ax,[QueueTail] ; remember new end of queue + sub ax,MaxFileLen + mov [QueueTail],ax + mov si,ax + mov byte ptr [si],0 ; nul first byte of last entry + + cmp byte ptr [bx],0 ; is there another file to consider? + je StartAnFil + push bp + mov bp,sp ; 0 2 4 + MOV ds,[bp+ 2 + 2] ; + POP BP +assume ds:nothing + jmp AnotherTry ; yes do it again... + + +;--- Start new file... +StartAnFil: +assume ds:CodeR + cmp [CurrHand],-1 ; was the canceled name the current? + jne NoneLeft ; no, just quit +StartAnFil2: + mov si,offset CodeR:FileQueue ; points to new current file + cmp byte ptr[si],0 ; is there one there? + je NoneLeft ; no, we canceled current and are none left + call Set24 + mov [PAbort],0 + mov dx,si + mov ax,(open shl 8) + call My21 + pushf + call Res24 + cmp [PAbort],0 + je NoI24b + popf + call CompQ ; compact file queue + jmp short StartAnFil2 + +NoI24b: + popf + jnc GoodNewCurr + call PrtOpErr ; print open error + call CompQ ; compact file queue + jmp short StartAnFil2 + +GoodNewCurr: + mov [CurrHand],ax ; save handle + mov [CurrFil],1 ; signal active (buffer is already empty) + +;--- Send Open on output device + call Open_Dev +NoneLeft: + clc + ret + +;--- Upper case conversion --- +UpConv: + CMP AL,'a' + JB NOCONV + CMP AL,'z' + JA NOCONV + SUB AL,20H +NOCONV: + RET + + +;--- Ambigous file name check --- +; entry: ds:dx points to filename +; preserves ds:dx and es +; +assume ds:nothing,es:CodeR +AmbChk: + mov CS:[AmbCan],0 ; assume not ambigous + mov si,dx + cld +AmbLoop: + lodsb + or al,al ; the nul? + jne AmbLoop + dec si ; points to nul + std ; scan backwards +ScanBack: + lodsb + cmp al,"*" + jne NotAStar + mov CS:[AmbCan],1 +NotAStar: + cmp al,"?" + jne NotAQues + mov CS:[AmbCan],1 +NotAQues: + cmp al,CS:[PChar] + jne ScanBack + cld ; be safe + cmp CS:[AmbCan],1 ; an ambigous cancel? + je AmbCanFnd ; no, just proceed + ret + +;--- transform * to ?'s +AmbCanFnd: + inc si + inc si ; points to actual name (past path char) + mov di,offset CodeR:ACBuf + push di + mov cx,12 + mov al,20h + cld + rep stosb ; fill fcb with blanks + pop di + push si + mov ax,(Parse_file_descriptor shl 8) and 0FF00h + call My21 + pop si + +;--- Copy name to expanded name + push ds + pop es +assume ds:nothing + push cs + pop ds +assume ds:CodeR + push es + mov di,si + mov si,offset CodeR:ACName + mov cx,8 +ACMovNam: + lodsb ; move name + cmp al,20h + je ACMovDn1 + stosb + loop ACMovNam + +ACMovDn1: + mov si,offset CodeR:ACExt + cmp byte ptr [si],20h ; if extension starts with blank + je ACMovDn2 ; then do not put period + mov al,"." + stosb + mov cx,3 + +ACMovExt: + lodsb ; move name + cmp al,20h + je ACMovDn2 + stosb + loop ACMovExt + +ACMovDn2: + mov byte ptr es:[di],0 ; nul terminate + pop ds +assume ds:nothing + push cs + pop es +assume es:CodeR + ret + + + +BREAK + +ADDFIL: +ASSUME DS:CodeR,ES:NOTHING + +;--- Check that queue is not full + mov di,[QueueTail] ; load pointer to next empty entry + cmp di,[EndQueue] ; queue full? + jb OkToQueue ; no, place in queue... + mov ax,error_queue_full + stc + ret + +;--- Copy name to empty slot in queue +OkToQueue: +; +; Retrieve old DS +; + push bp + mov bp,sp ; 0 2 4 + MOV ds,[bp+ 2 + 2] ; + POP BP + +assume ds:nothing + push cs + pop es ; ES:DI points to empty slot +assume es:CodeR + mov si,dx ; DS:SI points to submit packet + cmp byte ptr ds:[si],0 + jnz IncorrectLevel + lds si,dword ptr ds:[si+1] ; DS:SI points to filename + mov cx,MaxFileLen ; maximum length of file name +CopyLop: + lodsb + call UpConv ; convert to upper case + stosb + or al,al ; nul? + je CopyDone ; yes, done with move... + loop CopyLop + push cs + pop ds +assume ds:CodeR + mov ax,error_name_too_long ; if normal exit from the loop then + stc + ret + +IncorrectLevel: + mov ax,error_invalid_function + stc + ret + +assume ds:nothing,es:nothing ; es:nothing = not true but lets +CopyDone: ; avoid possible problems... + push cs + pop ds +assume ds:CodeR + +;--- advance queue pointer + mov si,[QueueTail] ; pointer to slot just used + push si ; save for test open later + add si,MaxFileLen + mov [QueueTail],si ; store for next round + mov byte ptr [si],0 ; nul next entry (maybe the EndQueue) + +;--- Check that file exists + call Set24 + mov [PAbort],0 + pop dx ; get pointer to filename + MOV AX,(OPEN SHL 8) + call My21 + pushf + PUSH DX + call Res24 + POP DX + popf + JNC GOTFIL +; +; See if brain damaged user entered an invalid drive +; + PUSH AX + MOV SI,DX + CMP BYTE PTR CS:[SI+1],':' + JZ GotDrive + POP AX + JMP SHORT i24bf +GotDrive: + MOV AH,Get_default_drive ; get current + CALL My21 + PUSH AX + MOV DL,CS:[SI] ; get drive letter to test + OR DL,20h + SUB DL,'a' + MOV AH,Set_Default_Drive ; set it + CALL My21 + MOV AH,Get_default_drive ; get it back + CALL My21 + CMP AL,DL ; same? + JNZ BadDrive ; no, bad drive + POP DX ; get original back + MOV AH,Set_Default_Drive ; set original + CALL My21 + POP AX + MOV DX,SI + JMP SHORT i24bf +BadDrive: + POP DX ; get original back + MOV AH,Set_Default_Drive ; set original + CALL My21 + POP AX + MOV AX,error_invalid_drive + MOV DX,SI +I24BF: + mov si,[QueueTail] ; take bad name out of queue + sub si,MaxFileLen ; SI points to the slot with bad name + mov [QueueTail],si + mov byte ptr [si],0 ; nul the first byte + stc + ret + + +;--- Check if print currently busy +GotFil: + CMP [CURRFIL],0 ; currently printing? + JZ OKAFIL ; no, start new print + mov bx,ax ; busy, close handle + call Set24 + mov [PAbort],1 ; no Int24's + mov ah,Close + call My21 + call Res24 + clc + ret + +;--- Save file data +OKAFIL: + MOV [CURRHAND],AX ; Valid handle + MOV AX,[ENDPTR] + MOV [NXTCHR],AX ; Buffer empty + MOV [CURRFIL],1 + +;--- Send Open on output device + call Open_Dev + clc + ret + +BREAK + +; +; perform a system call as myself +; +My21: + call Context_switch + call Do_21 + ret + +Public do_21 +DO_21: +ASSUME DS:NOTHING,ES:NOTHING + IF IBM + CMP BYTE PTR CS:[INT15FLAG],0 + JZ REAL_21 + PUSH DS + PUSH BX + LDS BX,CS:[INT15PTR] + INC BYTE PTR [BX] + POP BX + POP DS + CALL OffSave + INT 21H + Call OnSave + PUSH DS + PUSH BX + PUSHF ; Flags from system call + LDS BX,CS:[INT15PTR] + DEC BYTE PTR [BX] + POPF + POP BX + POP DS + RET + ENDIF + +REAL_21: + Call OffSave + INT 21H + CALL OnSave + RET + +OffSave: + ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSH AX + PUSH DX + MOV AX,Set_CTRL_C_Trapping SHL 8 + 2 + XOR DL,DL + INT 21h + MOV CtrlC,DL + POP DX + POP AX + ret + +OnSave: + ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSH AX + PUSH DX + MOV AX,Set_CTRL_C_Trapping SHL 8 + 2 + MOV DL,CtrlC + INT 21h + POP DX + POP AX + ret + +BREAK + +ListMes2: +ASSUME DS:CodeR,ES:NOTHING + LODSB + cmp al,0 + jz LMesDone + CALL LOUT + JMP short LISTMES2 + + +LISTMES: +ASSUME DS:CodeR,ES:NOTHING + LODSB + CMP AL,"$" + JZ LMESDONE + CALL LOUT + JMP short LISTMES + +LMESDONE: + RET + +LOUT: + PUSH BX +LWAIT: + CALL PSTAT + JZ PREADY + CMP [ERRCNT],ERRCNT2 + JA POPRET ;Don't get stuck + JMP SHORT LWAIT +PREADY: + CALL POUT +POPRET: + POP BX + RET + +;Stuff for BIOS interface +IOBUSY EQU 0200H +IOERROR EQU 8000H + +public PRNR003S, PRNR003E +PRNR003S: + +BYTEBUF DB ? + +CALLAD DD ? + +IOCALL DB 22 + DB 0 +IOREQ DB ? +IOSTAT DW 0 + DB 8 DUP(?) + DB 0 + DW OFFSET CodeR:BYTEBUF +INTSEG DW ? +IOCNT DW 1 + DW 0 + +PRNR003E: + +; Following two routines perform device open and close on output device. +; NO REGISTERS (including flags) are modified. No errors generated. + +public open_dev +Open_Dev: +ASSUME DS:NOTHING,ES:NOTHING +; +; We are now going to use the printer... We must lock down the printer so +; that the network does not intersperse output on us... +; We must also signal the REDIRector for stream open. +; We must ask DOS to set the Printer Flag to busy +; + PUSH BX + PUSHF + PUSH AX + PUSH DX + MOV DX,PrinterNum + CMP DX,-1 + JZ NoORop + MOV AX,0203h ; redirector lock + INT 2FH + MOV AX,0201H ; Redirector OPEN + INT 2FH +NoORop: + mov ax,(SET_PRINTER_FLAG SHL 8) + 01 + int 21H + POP DX + POP AX + MOV BL,DEVOPN ; Device OPEN + CALL OP_CL_OP + POPF + POP BX + RET + +OP_CL_OP: + PUSH DS + PUSH SI + LDS SI,[LISTDEV] +ASSUME DS:NOTHING + TEST [SI.SDEVATT],DEVOPCL + JZ NO_OP_CL + PUSH CS + POP DS +ASSUME DS:CodeR + MOV [IOCALL],DOPCLHL + CALL DOCALL +NO_OP_CL: + POP SI + POP DS +ASSUME DS:NOTHING + Ret + + +public close_dev +Close_Dev: +ASSUME DS:NOTHING,ES:NOTHING +; +; At this point, we release the ownership of the printer... +; and do a redirector CLOSE. +; Also tell DOS to reset the Printer Flag +; + PUSH BX + PUSHF + MOV BL,DEVCLS + CALL OP_CL_OP ; Device CLOSE + PUSH AX + PUSH DX + MOV DX,PrinterNum + CMP DX,-1 + JZ NoCRop + MOV AX,0202H ; redirector CLOSE + INT 2FH + MOV AX,0204h ; redirector clear + INT 2FH +NoCRop: + MOV AX,(SET_PRINTER_FLAG SHL 8) +00 + INT 21H + POP DX + POP AX + POPF + POP BX + RET + +PSTAT: +ASSUME DS:CodeR + PUSH BX + INC [ERRCNT] + MOV BL,DEVOST + MOV [IOCALL],DSTATHL + CALL DOCALL + TEST [IOSTAT],IOERROR + JZ NOSTATERR + OR [IOSTAT],IOBUSY ;If error, show buisy +NOSTATERR: + TEST [IOSTAT],IOBUSY + JNZ RET13P ;Shows buisy + MOV [ERRCNT],0 +RET13P: + POP BX + RET + +POUT: +ASSUME DS:CodeR + MOV [BYTEBUF],AL + MOV BL,DEVWRT + MOV [IOCALL],DRDWRHL +DOCALL: + PUSH ES + MOV [IOREQ],BL + MOV BX,CS + MOV ES,BX + MOV [IOSTAT],0 + MOV [IOCNT],1 + PUSH DS + PUSH SI + PUSH AX + call Context_Switch + MOV BX,OFFSET CodeR:IOCALL + LDS SI,[LISTDEV] +ASSUME DS:NOTHING + MOV AX,[SI+SDEVSTRAT] + MOV WORD PTR [CALLAD],AX + CALL [CALLAD] + MOV AX,[SI+SDEVINT] + MOV WORD PTR [CALLAD],AX + CALL [CALLAD] + POP AX + POP SI + POP DS +ASSUME DS:CodeR + POP ES + RET + + IF IBM +Public PRNR004S, PRNR004E +PRNR004S: + +REAL_INT_13 DD ? +INT_13_RETADDR DW OFFSET CodeR:INT_13_BACK + +PRNR004E: + +INT_13 PROC FAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSHF + INC [BUSY] ;Exclude if dumb program call ROM + PUSH CS + PUSH [INT_13_RETADDR] + PUSH WORD PTR [REAL_INT_13+2] + PUSH WORD PTR [REAL_INT_13] + RET +INT_13 ENDP + +INT_13_BACK PROC FAR + PUSHF + DEC [BUSY] + POPF + RET 2 ;Chuck saved flags +INT_13_BACK ENDP + ENDIF + + + IF IBM + +Public PRNR005S, PRNR005E +PRNR005S: + +REAL_INT_15 DD ? +INT15FLAG DB 0 ; Init to off +INT15PTR DD ? + +PRNR005E: + +INT_15 PROC FAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP AH,20H + JNZ REAL_15 ; Not my function + CMP AL,1 + JA REAL_15 ; I only know 0 and 1 + JE FUNC1 + INC [INT15FLAG] ; Turn ON + MOV WORD PTR [INT15PTR],BX ; Save counter loc + MOV WORD PTR [INT15PTR+2],ES + IRET + +FUNC1: + MOV [INT15FLAG],0 ; Turn OFF + IRET + +REAL_15: + JMP [REAL_INT_15] + +INT_15 ENDP + + +Public PRNR006S, PRNR006E +PRNR006S: + +FLAG17_14 DB 0 ; Flags state of AUX/PRN redir +REAL_INT_5 DD ? +REAL_INT_17 DD ? +INT_17_NUM DW 0 + +PRNR006E: + +INT_17: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [FLAG17_14],1 + JNZ DO_INT_17 ;The PRN device is not used + CMP [CURRFIL],0 + JZ DO_INT_17 ;Nothing pending, so OK + CMP DX,[INT_17_NUM] + JNZ DO_INT_17 ;Not my unit + CMP [BUSY],0 + JNZ DO_INT_17 ;You are me + STI + MOV AH,0A1H ;You are bad, get time out + IRET + +DO_INT_17: + JMP [REAL_INT_17] ;Do a 17 + +Public PRNR007S, PRNR007E +PRNR007S: +REAL_INT_14 DD ? +INT_14_NUM DW 0 + +PRNR007E: + +INT_14: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [FLAG17_14],2 + JNZ DO_INT_14 ;The AUX device is not used + CMP [CURRFIL],0 + JZ DO_INT_14 ;Nothing pending, so OK + CMP DX,[INT_14_NUM] + JNZ DO_INT_14 ;Not my unit + CMP [BUSY],0 + JNZ DO_INT_14 ;You are me + STI + OR AH,AH + JZ SET14_AX + CMP AH,2 + JBE SET14_AH +SET14_AX: + MOV AL,0 +SET14_AH: + MOV AH,80H ;Time out + IRET + +DO_INT_14: + JMP [REAL_INT_14] ;Do a 14 + +INT_5: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [FLAG17_14],1 + JNZ DO_INT_5 ;The PRN device is not used + CMP [CURRFIL],0 + JZ DO_INT_5 ;Nothing pending, so OK + CMP [INT_17_NUM],0 + JNZ DO_INT_5 ;Only care about unit 0 + IRET ;Pretend it worked + +DO_INT_5: + JMP [REAL_INT_5] ;Do a 5 + ENDIF + +Public PRNR008S, PRNR008E +PRNR008S: + +ERRCNT DW 0 + + IF IBM +;Reserved names for parallel card +INT_17_HITLIST LABEL BYTE + DB 8,"PRN ",0 + DB 8,"LPT1 ",0 + DB 8,"LPT2 ",1 + DB 8,"LPT3 ",2 + DB 0 +;Reserved names for Async adaptor +INT_14_HITLIST LABEL BYTE + DB 8,"AUX ",0 + DB 8,"COM1 ",0 + DB 8,"COM2 ",1 + DB 0 + ENDIF + +LISTNAME DB "PRN " ;Device name + +PRNR008E: + +SETDEV: +ASSUME CS:CodeR,DS:CodeR,ES:NOTHING,SS:NOTHING +; LISTNAME has the 8 char device name IN UPPER CASE +; CARRY set if bad device +; DS preserved, others destroyed. + + MOV AH,GET_IN_VARS + call My21 + PUSH ES + POP DS + LEA SI,ES:[BX.SYSI_DEV] +ASSUME DS:NOTHING + PUSH CS + POP ES +ASSUME ES:CodeR + MOV DI,OFFSET CodeR:LISTNAME +LOOKDEV: + TEST [SI.SDEVATT],DEVTYP + JZ NEXTDEV ; Skip Block devs + PUSH SI + PUSH DI + ADD SI,SDEVNAME ; Point at name + MOV CX,8 + REPE CMPSB + POP DI + POP SI + JE GOTDEV +NEXTDEV: + LDS SI,[SI.SDEVNEXT] + CMP SI,-1 + JNZ LOOKDEV + PUSH CS + POP DS + STC + RET + +GOTDEV: + MOV WORD PTR CS:[CALLAD+2],DS ;Get I/O routines + MOV WORD PTR CS:[LISTDEV+2],DS ;Get I/O routines + MOV WORD PTR CS:[LISTDEV],SI + PUSH CS + POP DS +ASSUME DS:CodeR + + IF IBM + MOV PrinterNum,-1 ; Assume not an INT 17 device + PUSH CS + POP ES +ASSUME ES:CodeR + MOV BP,OFFSET CodeR:LISTNAME + MOV SI,BP + MOV DI,OFFSET CodeR:INT_17_HITLIST +CHKHIT: + MOV SI,BP + MOV CL,[DI] + INC DI + JCXZ NOTONHITLIST + REPE CMPSB + LAHF + ADD DI,CX ;Bump to next position without affecting flags + MOV BL,[DI] ;Get device number + INC DI + SAHF + JNZ CHKHIT + XOR BH,BH + MOV [INT_17_NUM],BX + MOV PrinterNum,BX ; Set this as well to the INT 17 device + MOV [FLAG17_14],1 + JMP SHORT ALLSET + +NOTONHITLIST: + MOV DI,OFFSET CodeR:INT_14_HITLIST +CHKHIT2: + MOV SI,BP + MOV CL,[DI] + INC DI + JCXZ NOTONHITLIST2 + REPE CMPSB + LAHF + ADD DI,CX ;Bump to next position without affecting flags + MOV BL,[DI] ;Get device number + INC DI + SAHF + JNZ CHKHIT2 + XOR BH,BH + MOV [INT_14_NUM],BX + MOV [FLAG17_14],2 + JMP SHORT ALLSET + +NOTONHITLIST2: + MOV [FLAG17_14],0 +ALLSET: + ENDIF + CLC + RET + + + IF HARDINT + +BREAK + +ReBtINT: +ASSUME CS:CodeR,DS:NOTHING,ES:NOTHING,SS:Nothing + + CLI + push cs + pop ds + +IntWhileBusy: + INT ComInt + JNC NotBusy + JMP IntWhileBusy + ret +NotBusy: + + INC [BUSY] ; Exclude hardware interrupts + INC [SOFINT] ; Exclude software interrupts + + call CanAll ; Purge the Queue + + LDS DX,CodeR:COMNEXT + mov ax,(set_interrupt_vector shl 8) or comint + INT 21H ;Set int 2f vector + + LDS DX,CodeR:NEXTINT + mov ax,(set_interrupt_vector shl 8) or intloc + INT 21H ;Set hardware interrupt + + mov ax,(set_interrupt_vector shl 8) or 15h + lds dx,CodeR:Real_Int_15 ; Reset the wait on event on ATs + int 21h + + mov ax,(set_interrupt_vector shl 8) or 17h + LDS DX,CodeR:Real_Int_17 + INT 21H ;Set printer interrupt + + mov ax,(set_interrupt_vector shl 8) or 5h + LDS DX,CodeR:Real_Int_5 + INT 21H ;Set print screen interrupt + + mov ax,(set_interrupt_vector shl 8) or 14h + LDS DX,CodeR:Real_Int_14 + INT 21H ;Set printer interrupt + + mov ax,(set_interrupt_vector shl 8) or 24h + LDS DX,CodeR:HERRINT + INT 21H ;Set printer interrupt + + LDS DX,CodeR:NEXT_REBOOT + mov ax,(set_interrupt_vector shl 8) or reboot + INT 21H ;Set bootstrap interrupt + + STI + INT 19H + + ENDIF ; HARDINT + + + + +;----- File name Queue and data buffer goes here +Public PRNR009S +PRNR009S: +FileQueue Label byte + db 0 ; the file queue starts empty + + +BREAK + +BADSPOOL: +ASSUME CS:CodeR,DS:CodeR,ES:NOTHING,SS:Nothing + MOV DX,OFFSET CODER:BADMES + mov cx,badmeslen + mov bx,stdout + mov ah,write + INT 21H +;********************************************************************* + MOV AX,(SET_PRINTER_FLAG SHL 8) ; Set flag to Idle + int 21H +;********************************************************************* + MOV AX,(EXIT SHL 8) OR 0FFH + INT 21H + +;--- move transient out of the way +ContTrans dd ? ; transient continuation address after move + +MoveTrans label far +ASSUME CS:CodeR,DS:CodeR,ES:CodeR,SS:Nothing + cli + CLD + MOV [INTSEG],CS + CALL SETDEV +ASSUME ES:NOTHING + JC BADSPOOL + MOV DX,OFFSET CodeR:SPINT + MOV AL,SOFTINT + MOV AH,GET_INTERRUPT_VECTOR + INT 21H ;Get soft vector + MOV WORD PTR [SPNEXT+2],ES + MOV WORD PTR [SPNEXT],BX + MOV AL,SOFTINT + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set soft vector + MOV DX,OFFSET CodeR:SPCOMINT + MOV AL,ComInt + MOV AH,GET_INTERRUPT_VECTOR + INT 21H ;Get communication vector + MOV WORD PTR [COMNEXT+2],ES + MOV WORD PTR [COMNEXT],BX + MOV AL,ComInt + MOV AH,SET_INTERRUPT_VECTOR ;Set communication vector + INT 21H + + IF IBM + MOV AL,13H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_13+2],ES + MOV WORD PTR [REAL_INT_13],BX + MOV DX,OFFSET CodeR:INT_13 + MOV AL,13H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set diskI/O interrupt + + MOV AL,15H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_15+2],ES + MOV WORD PTR [REAL_INT_15],BX + MOV DX,OFFSET CodeR:INT_15 + MOV AL,15H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set INT 15 vector + + MOV AL,17H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_17+2],ES + MOV WORD PTR [REAL_INT_17],BX + MOV DX,OFFSET CodeR:INT_17 + MOV AL,17H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set printer interrupt + MOV AL,14H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_14+2],ES + MOV WORD PTR [REAL_INT_14],BX + MOV DX,OFFSET CodeR:INT_14 + MOV AL,14H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set RS232 port interrupt + MOV AL,5H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_5+2],ES + MOV WORD PTR [REAL_INT_5],BX + MOV DX,OFFSET CodeR:INT_5 + MOV AL,5H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set print screen interrupt + ENDIF + + IF HARDINT + MOV AH,GET_INDOS_FLAG + INT 21H +ASSUME ES:NOTHING + MOV WORD PTR [INDOS+2],ES ;Get indos flag location + MOV WORD PTR [INDOS],BX + MOV AL,INTLOC + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [NEXTINT+2],ES + MOV WORD PTR [NEXTINT],BX + + MOV AL,REBOOT ; We also need to chain + MOV AH,GET_INTERRUPT_VECTOR ; Into the INT 19 sequence + INT 21H ; To properly "unhook" + MOV WORD PTR [NEXT_REBOOT+2],ES ; ourselves from the TimerTick + MOV WORD PTR [NEXT_REBOOT],BX ; sequence + + IF IBM + MOV AX,0B800H + INT 2FH + CMP AL,0 + JE SET_HDSPINT ; No NETWORK, set hardware int + TEST BX,0000000011000100B + JNZ NO_HDSPINT ; DO NOT set HDSPINT if RCV|MSG|SRV + ENDIF + +SET_HDSPINT: + MOV DX,OFFSET CodeR:HDSPINT + MOV AL,INTLOC + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set hardware interrupt + + MOV DX,OFFSET CodeR:ReBtINT + MOV AL,REBOOT + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set bootstrap interrupt + +NO_HDSPINT: + ENDIF + MOV DX,OFFSET CODER:GOODMES + mov cx,goodmeslen + mov bx,stdout + mov ah,write + int 21h + +;--- Move transient +; Note: do not use stack, it may get trashed in move! +public RealMove +RealMove: + + mov ax,offset dg:TransRet + mov word ptr [ContTrans],ax ; store return offset + mov ax,CodeR + add ax,[endres] ; get start of moved transient, actually + ; this is 100 bytes more than need be + ; because of lack of pdb, but who cares? + mov word ptr [ContTrans+2],ax ; return segment + mov es,ax ; new location for dg group +assume es:nothing + mov ax,dg + mov ds,ax +assume ds:nothing + mov cx,offset dg:TransSize + mov si,cx ; start from the bottom and move up + mov di,cx + std + rep movsb ; move all code, data and stack + cld ; restore to expected setting... + +;--- normalize transient segment regs + mov ax,es + mov ds,ax + sub ax,dg ; displacement + mov dx,ss + add dx,ax ; displace stack segemnt + mov ss,dx + +assume ds:nothing,es:nothing,ss:nothing + jmp ContTrans ; back to the transient... + +PRNR009E: + +CodeR EndS + + End + \ No newline at end of file diff --git a/SRC/CMD/PRINT/PRINT_RM.ASM b/SRC/CMD/PRINT/PRINT_RM.ASM new file mode 100644 index 0000000..f58186b --- /dev/null +++ b/SRC/CMD/PRINT/PRINT_RM.ASM @@ -0,0 +1,34 @@ +; SCCSID = @(#)print_rmes.asm 4.1 85/07/17 + INCLUDE pridefs.inc + + +BREAK + +; +; MSDOS V3.00 PRINT +; +; Resident Portion Messages +; +; 02/15/84 MAU Created as a separate link module +; from the include file. should +; always be linked first!! +; + +CodeR Segment public para + + public ERRMES, ERRMEST, BELMES, ErrMesT2, CanMes, CanFilNAm + public AllCan, ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, + public ERR7, ERR8, ERR9, ERR10, ERR11, ERR12, FATMES + public BADDRVM, BADMES, badmeslen, GOODMES, goodmeslen + +;INT 24 messages A La COMMAND +Public PRMES001S, PRMES001E +PRMES001S equ $ + +include print_rm.inc + +PRMES001E equ $ + +CodeR EndS + + End diff --git a/SRC/CMD/PRINT/PRINT_RM.INC b/SRC/CMD/PRINT/PRINT_RM.INC new file mode 100644 index 0000000..a9a0492 --- /dev/null +++ b/SRC/CMD/PRINT/PRINT_RM.INC @@ -0,0 +1,34 @@ + +ERRMES DB 13,10,13,10,"**********",13,10,"$" +ERRMEST DB " error reading file",13,10,"$" +BELMES DB 13,0CH,7,"$" + +ErrMesT2 db "File not found",13,10,"$" + +CanMes DB 13,10,13,10,"File $" +CanFilNam DB " canceled by operator$" + +AllCan DB 13,10,13,10,"All files canceled by operator$" + +ERR0 DB "Write protect$" +ERR1 DB "Bad unit$" +ERR2 DB "Not ready$" +ERR3 DB "Bad command$" +ERR4 DB "Data$" +ERR5 DB "Bad call format$" +ERR6 DB "Seek$" +ERR7 DB "Non-DOS disk$" +ERR8 DB "Sector not found$" +ERR9 DB "No paper$" +ERR10 DB "Write fault$" +ERR11 DB "Read fault$" +ERR12 DB "Disk$" + +FATMES DB "File allocation table bad drive " +BADDRVM DB "A.",13,10,"$" + +BADMES DB "List output is not assigned to a device",13,10 +badmeslen dw $-badmes +GOODMES DB "Resident part of PRINT installed",13,10 +goodmeslen dw $-goodmes + \ No newline at end of file diff --git a/SRC/CMD/PRINT/PRINT_T.ASM b/SRC/CMD/PRINT/PRINT_T.ASM new file mode 100644 index 0000000..273fba4 --- /dev/null +++ b/SRC/CMD/PRINT/PRINT_T.ASM @@ -0,0 +1,1434 @@ +; SCCSID = @(#)print_t.asm 4.5 85/09/10 + INCLUDE pridefs.inc + +SaveReg MACRO reglist ;; push those registers +IRP reg, + PUSH reg +ENDM +ENDM + +RestoreReg MACRO reglist ;; pop those registers +IRP reg, + POP reg +ENDM +ENDM + +BREAK + +; +; MSDOS V3.00 PRINT +; +; Transient Portion +; + + +CodeR Segment public para + +if hardint + extrn SliceCnt:BYTE, BusyTick:BYTE, MaxTick:BYTE, TimeSlice:BYTE +endif + extrn EndRes:WORD, BlkSiz:WORD, QueueLen:BYTE, PChar:BYTE + extrn ListName:BYTE, FileQueue:BYTE, EndQueue:WORD, Buffer:WORD + extrn EndPtr:WORD, NxtChr:WORD, MoveTrans:FAR + +CodeR EndS + + +BREAK + +;Transient data + +DATA SEGMENT public BYTE + + extrn badver:byte,conflictmes_ptr:word,invparm_ptr:word,crlf_ptr:word + extrn fullmes_ptr:word,nofils_ptr:word,dispmes_ptr:word + extrn whichmes:word,fstmes:byte,secmes:byte,badnamemes_ptr:word + extrn namtmes_ptr:word,badcanmes_ptr:word,cntmes_ptr:word + extrn prompt_ptr:word,invdrvmes_ptr:word,AccDen_PTR:WORD + + public namebuf,arg_buf + + ORG 0 + +Public PRNT001S, PRNT001E +PRNT001S equ $ + +SWITCHAR DB ? +PathChar db "\" + +SubPack db 0 ; Level + dd ? ; pointer to filename + +;--- Ints used by print. These ints are loaded here before the +; resident is installed, just in case an error before print +; is installed cases it to be never installed and the ints +; have to be restored. + +i28vec dd ? ; SOFTINT +i2fvec dd ? ; COMINT + if IBM +i05vec dd ? +i13vec dd ? +i14vec dd ? +i15vec dd ? +i17vec dd ? + endif + if HARDINT +i1cvec dd ? ; INTLOC + endif + +;--- Temp stack for use durint int 23 and 24 processing + db 278 + 80H dup (?) ; 278 == IBM's ROM requirements +intStk dw ? + + +;--- Print installed flag: +; 0 = Not installed yet: process only configuration parameters +; during the command line parse +; 1 = Partially installed: process only print commands AND flag +; configuration parameters as errors AND finish by executing +; the keep process +; 2 = Already installed: process only print commands AND flag +; configuration parameters as errors +PInst db 0 ; defaults to not installed +CanFlag db 0 ; cancel mode flag (0= no cancel) +Ambig db ? ; =1 if a filename is ambigous +DevSpec db 0 ; =1 a device was specified with the + ; /d option, do not prompt +QFullMes db 0 ; =1 queue full message issued already +HARDCH DD ? ;Pointer to real INT 24 handler + +TOKBUF DB 64 DUP (?) ; token buffer for CPARSE +LastSI dw ? ; pointer to last token for lok-ahead + +NulPtr dw ? ; pointer to the nul in NameBuf +FNamPtr dw ? ; pointer to name portion of file name +NameBuf db (MaxFileLen+16) dup(?) ; full name buffer for file + ; plus room for ambigous expansion +Arg_buf db (MaxFileLen+16) dup (?) + +SearchBuf find_buf <> ; search buffer + +PRNT001E equ $ + +DATA ENDS + + + +BREAK + +Code Segment public para + extrn std_printf:near,printf_crlf:near +Code EndS + +Code Segment public para + public TransRet,TransSize + +ASSUME CS:DG,DS:nothing,ES:nothing,SS:Stack + +TRANSIENT: +;Install + CLD + +;Code to print header +; MOV DX,OFFSET DG:HEADER +; MOV AH,STD_CON_STRING_OUTPUT +; INT 21H + + MOV AH,GET_VERSION + INT 21H + + CMP AX,EXPECTED_VERSION + JE OKDOS + +; XCHG AH,AL ;Turn it around to AH.AL +; CMP AX,DOSVER_LOW +; JB GOTBADDOS +; CMP AX,DOSVER_HIGH +; JBE OKDOS + +GOTBADDOS: + PUSH CS + POP DS +assume ds:dg + MOV DX,OFFSET DG:BADVER + MOV AH,STD_CON_STRING_OUTPUT + INT 21H + push es + xor ax,ax + push ax + +foo proc far + ret ; Must use this method, version may be < 2.00 +foo endp + + +assume ds:nothing +OKDOS: + mov ax,ds:[pdb_environ] + or ax,ax + jz nofree + push es + mov es,ax + mov ah,dealloc + int 21h + pop es +nofree: + push cs + pop ds + push cs + pop es +assume ds:dg,es:dg + mov ax,0100H ; Ask if already installed + INT ComInt + OR AL,AL + jnz badinstal + +;--- save int vectors in case of error + + mov ax,(get_interrupt_vector shl 8) or SOFTINT ; (SOFTINT) + int 21h +assume es:nothing + mov word ptr [i28vec+2],es + mov word ptr [i28vec],bx + + mov ax,(get_interrupt_vector shl 8) or COMINT ; (COMINT) + int 21h + mov word ptr [i2fvec+2],es + mov word ptr [i2fvec],bx + + if IBM + + mov ax,(get_interrupt_vector shl 8) or 13h + int 21h + mov word ptr [i13vec+2],es + mov word ptr [i13vec],bx + + mov ax,(get_interrupt_vector shl 8) or 15h + int 21h + mov word ptr [i15vec+2],es + mov word ptr [i15vec],bx + + mov ax,(get_interrupt_vector shl 8) or 17h + int 21h + mov word ptr [i17vec+2],es + mov word ptr [i17vec],bx + + mov ax,(get_interrupt_vector shl 8) or 14h + int 21h + mov word ptr [i14vec+2],es + mov word ptr [i14vec],bx + + mov ax,(get_interrupt_vector shl 8) or 05h + int 21h + mov word ptr [i05vec+2],es + mov word ptr [i05vec],bx + + endif + + if HARDINT + + mov ax,(get_interrupt_vector shl 8) or INTLOC ; (INTLOC) + int 21h + mov word ptr [i1cvec+2],es + mov word ptr [i1cvec],bx + + endif + + push cs + pop es +assume es:dg + + jmp OKINST ; not installed yet... + +BADINSTAL: + CMP AL,1 + JZ PRINTCONFLICT + mov [PInst],2 ; remember print already installed + ; and that we only do one pass + jmp short okinst +ERREX: + call printf_crlf +ERREX2: + MOV AX,(EXIT SHL 8) OR 0FFH + INT 21H + +PRINTCONFLICT: + MOV DX,OFFSET DG:CONFLICTMES_ptr + JMP short ERREX + +Busy: + RestoreReg +IntWhileBusy: + SaveReg + INT ComInt + JNC NotBusy + CMP AX,error_busy + JZ Busy + add sp,2 ; clear off AX + stc + ret +NotBusy: + Add sp,2 ; clear off AX and clear carry + ret + +OKINST: + call GetHInt ; save current int 24 vector + call SetInts ; set int 23 and 24 vectors + MOV AX,CHAR_OPER SHL 8 + INT 21H + MOV [SWITCHAR],DL ; Get user switch character + cmp dl,"-" + jne RegPathChar + mov [PathChar],"/" ; alternate path character +RegPathChar: + MOV SI,81H ; Command line +ParseAgn1: ; come here when DI is trashed... + MOV DI,OFFSET DG:TOKBUF +ParseAgn: + CALL CPARSE + jc setbufj + jmp MORESTUFF ; End of command line? +SETBUFJ: + cmp [PInst],0 ; is print already installed? + jne setbufj2 + jmp NotYet +; +; Grab the pointer to the queue and lock it down. Remember that since there +; are threads in the background, we may get a busy return. We sit here in a +; spin loop until we can actually lock the queue. +; +setbufj2: + mov ax,0104H ; get status + call IntWhileBusy ; on return DS:SI points to queue +assume ds:nothing +;--- check for off-line + cmp dx,ErrCnt1 ; check count + jb CntOK + push ds + push cs + pop ds +assume ds:dg + mov dx,offset dg:CntMes_ptr ; printer might be off-line + call printf_crlf + pop ds +assume ds:nothing + +;--- display current queue +CntOk: + call copy_to_arg_buf + cmp byte ptr ds:[si],0 ; is the queue empty? + je QueueEmpty + mov di,offset dg:FstMes + push ds + push cs + pop ds +assume ds:dg + mov dx,offset dg:crlf_ptr + call std_printf +AnotherFile: + mov dx,offset dg:dispmes_ptr +assume ds:dg + mov whichmes,di ; print one of the two messages + mov di,offset dg:SecMes ; once 1st mes printed, always print second + call printf_crlf + pop ds +assume ds:nothing + add si,MaxFileLen ; point to next entry in queue + call copy_to_arg_buf + cmp byte ptr ds:[si],0 ; end of queue? + push ds + push cs + pop ds +assume ds:dg + jne AnotherFile + pop ax ; flush stack + jmp short quit_trans ; all done + +copy_to_arg_buf: + push di + push si + mov di,offset dg:arg_buf +copy_the_name: + lodsb + or al,al + jz name_copied + stosb + jmp short copy_the_name +name_copied: + stosb + pop si + pop di + ret + +QueueEmpty: +assume ds:nothing + push cs ; queue is empty, print message + pop ds +assume ds:dg + mov dx,offset dg:NoFils_ptr + call printf_crlf + +;--- exit transient +quit_trans: + mov ax,0105H ; unlock the print queue + call IntWhileBusy ; on return DS:SI points to queue + cmp [PInst],1 + jne RegQuit ; printer was installed when we arrived + mov ax,CodeR + mov ds,ax +assume ds:CodeR + XOR BX,BX + MOV CX,5 ; StdIN,StdOUT,StdERR,StdAUX,StdPRN +CLS_LP: ; Close STD handles before + ; keep process + MOV AH,CLOSE + INT 21H + INC BX + LOOP CLS_LP + MOV DX,[ENDRES] ; install print... + MOV AX,KEEP_PROCESS SHL 8 ; Exit code 0 + INT 21H + +assume ds:dg +RegQuit: + MOV AX,(EXIT SHL 8) ; quit with no error + INT 21H +NotYet: + JMP SETBUF + + +;--- Return the size of a filename in the queue --- +; Entry: DS:SI points to name +; Exit: CX = size of the name +GetNameSize: + push si + xor cx,cx +NSLoop: + lodsb + or al,al + jz NSDone + inc cx + jmp short NSLoop +NSDone: + pop si + ret + + + +ARGDEVJ: + JMP ARGDEV +MORESTUFF: + CMP AX,1 + jnz NotEOL + jmp SETBUF ; End of command line +NotEOL: + CMP AX,2 + jnz NotAFile + jmp PaFile ; Must be a filename to print +NotAFile: + CMP AX,4 + JNZ BADTOK ; Unknown return +; +; We have a switch. Figure out what it is... +; + OR [TOKBUF],20H ; Convert to lower case + CMP [TOKBUF],"b" + jnz NotSetSiz + jmp SETSIZ ; Buffer size +NotSetSiz: + CMP [TOKBUF],"d" + JZ ARGDEVJ ; Device + +if hardint + CMP [TOKBUF],"u" + jnz NotBusyVal + jmp BusyVal ; Set BUSYTICK +NotBusyVal: + CMP [TOKBUF],"m" + jnz NotMaxVal + jmp MAXVAL ; Set MAXTICK +NotMaxVal: + CMP [TOKBUF],"s" + jnz NotTimeVal + jmp TIMEVAL ; Set TIMESLICE and SLICECNT +NotTimeVal: +endif + cmp [TokBuf],"q" + jnz NotQVal + jmp QVal ; Set queue size +NotQVal: + cmp [TokBuf],"p" + jz SetPrintMode ; turn off cancel mode + cmp [TokBuf],"c" + jz SetCancelMode ; turn on cancel mode + cmp [TokBuf],"t" + jz CancelAll ; cancel all files +BADTOK: + MOV DX,OFFSET DG:INVPARM_ptr + call printf_crlf + cmp [PInst],0 ; print not installed? + jne OKParseAgn + jmp ERREX2 + + +;--- Turn Cancel mode off --- +SetPrintMode: + cmp [PInst],0 ; has print been installed? + jne OkSetPrintM + jmp SetBuf ; no, better do it now + +OkSetPrintM: + mov [CanFlag],0 + +OKParseAgn: + jmp ParseAgn + + +;--- Turn Cancel mode on --- +SetCancelMode: + cmp [PInst],0 ; has print been installed? + jne OkSetCancelM + jmp SetBuf ; no, better do it now + +OkSetCancelM: + mov [CanFlag],1 + jmp ParseAgn + + +;--- Cancel all files --- +CancelAll: + cmp [PInst],0 ; has print been installed? + jne OkCancelAll + jmp SetBuf ; no, better do it now + +OkCancelAll: + push si ; save parse pointer + mov ax,0103H ; cancel command + call IntWhileBusy + pop si ;restore parse pointer + jmp SetBufJ + + +if hardint +;--- Set value of BUSYTICK --- +BUSYVAL: + CALL CPARSE ; Get size + Jc BADTOK + CMP AX,2 + jnz BADTOK + cmp [PInst],0 + jne BadTok ; Allowed only before installing + CALL GETNUM ; Convert + JC BADTOK + OR AH,AH + JNZ BADTOK ; To big + push ds + mov dx,CodeR + mov ds,dx +assume ds:CodeR + MOV [BUSYTICK],AL + pop ds +assume ds:dg + JMP PARSEAGN + + +;--- Set value of MAXTICK --- +MAXVAL: + CALL CPARSE ; Get size + JC BADTOKJ2 + CMP AX,2 + JNZ BADTOKJ2 + cmp [PInst],0 + jne BadTokj2 ; Allowed only before installing + CALL GETNUM ; Convert + JC BADTOKJ2 + OR AH,AH + JNZ BADTOKJ2 ; To big + push ds + mov dx,CodeR + mov ds,dx +assume ds:CodeR + MOV [MAXTICK],AL + pop ds +assume ds:dg + JMP PARSEAGN + + +BadTokJ2: + jmp BadTok + +;--- Set value of Time parameters --- +TIMEVAL: + CALL CPARSE ; Get size + JC BADTOKJ2 + CMP AX,2 + JNZ BADTOKJ2 + cmp [PInst],0 + jne BadTokJ2 ; Allowed only before installing + CALL GETNUM ; Convert + JC BADTOKJ2 + OR AH,AH + JNZ BADTOKJ2 ; To big + push ds + mov dx,CodeR + mov ds,dx +assume ds:CodeR + MOV [TIMESLICE],AL + MOV [SLICECNT],AL + pop ds +assume ds:dg + JMP PARSEAGN +endif + +;--- Set Size of Buffer --- +SETSIZ: + CALL CPARSE ; Get size + JC BADTOKJ + CMP AX,2 + JNZ BADTOKJ + cmp [PInst],0 + jne BadTokJ ; Allowed only before installing + CALL GETNUM ; Convert + JC BADTOKJ + CMP AX,512 + JB BADTOKJ ; To small + CMP AX,1024 * 16 + JA BADTOKJ ; To Big + push ds + mov dx,CodeR + mov ds,dx +assume ds:CodeR + MOV [BLKSIZ],AX + pop ds +assume ds:dg + JMP PARSEAGN + + +;--- set file queue size --- +QVal: + CALL CPARSE ; Get size + JC BADTOKJ + CMP AX,2 + JNZ BADTOKJ + cmp [PInst],0 + jne BadTokJ ; Allowed only before installing + CALL GETNUM ; Convert + JC BADTOKJ + CMP AX,MinQueueLen + JB BADTOKJ ; To small + CMP AX,MaxQueueLen + JA BADTOKJ ; To Big + push ds + mov dx,CodeR + mov ds,dx +assume ds:CodeR + MOV [QueueLen],Al + pop ds +assume ds:dg + JMP PARSEAGN + +BADTOKJ: + JMP BADTOK + + +;--- process a file name --- +PaFile: + cmp [PInst],0 ; has print been installed? + jne OkPaFile + jmp SetBuf ; no, better do it now + +OkPaFile: + cld ; just in case... + mov [Ambig],0 ; assume not an ambigous file + +;--- Check for drive specifier + push si ; save parse pointer + mov si,di ; SI points to file token + mov di,offset dg:NameBuf ; buffer for full file name + cmp byte ptr [si+1],":" ; check if there is a drive designator + je DrvFound ; yes, use it... + mov ah,Get_Default_Drive ; no, get it... + int 21h + mov dl,al ; save for later (used in DoPath) + inc dl ; adjust to proper code (A=1,B=2,...) + add al,"A" ; conver to letter code + stosb ; store letter code + mov al,":" + stosb + jmp short DoPath + +DrvFound: + mov al,byte ptr [si] ; get drive letter + call UpConvt ; conver to upper case + sub al,"@" ; conver to proper code... + jbe BadDrvJ + mov dl,al ; save for later (used in DoPath) + movsb ; move the drive letter + movsb ; move the ":" + +;--- Check for full path +DoPath: + mov al,[PathChar] + cmp byte ptr [si],al ; does it start from the root? + je DrvChk ; yes, check for valid drive + stosb ; store path character + push si + mov si,di ; buffer for current directory + mov ah,Current_Dir ; get current directory + int 21h + jnc FEndLop + pop si +BadDrvJ: + jmp bad_drive + +FEndLop: ; find the terminating nul + lodsb + or al,al + jnz FEndLop + dec si ; adjust to point to nul + mov ax,di ; save pointer to beg. of path + mov di,si ; here is were the file name goes + pop si ; points to file name + cmp ax,di ; if equal then file is in the root + je PathFound ; if so, do not add another path char + mov al,[PathChar] + stosb ; put path separator before file name + jmp short PathFound + +;--- Check for valid drive. +; Done by getting current dir of the drive in question (already in +; DL) into NameBuf. If no error the valid drive and we throw +; away the current dir stuf by overwriting it with the filename. +; +DrvChk: ; DL has drive number (from DrvFound) + push si + mov si,di ; buffer for current directory + mov ah,Current_Dir ; get current directory + int 21h + pop si + jnc PathFound + jmp bad_drive + +PathFound: + mov cx,MaxFileLen ; lets not overflow file name buffer + mov ax,di ; CX := MaxFileLen - + ; long(&NameBuf - &PtrLastchar) + sub ax,offset dg:NameBuf ; size of the filename so far + sub cx,ax ; size left for the filename + jnc MovLop + + mov cx,1 ; Set cx to Fall through to FNTooLong + + +MovLop: ; WHILE (Length(FileName) <= MaxFileLen) + ; DO copy in the file name + lodsb + stosb + cmp al,"*" + je IsAmbig + cmp al,"?" + jne ContMov +IsAmbig: + mov [Ambig],1 ; ambigous filename found + +ContMov: + or al,al ; end of name? + jz MoveDone + loop MovLop ; END of Loop + + dec di + mov [NulPtr],di + jmp FNTooLong ; if we got here the name was too long + + +MoveDone: ; we have the full absolute name... + dec di + mov [NulPtr],di ; save pointer to termanting nul + +;--- check for an option following name + pop si ; restore pointer to parse line + mov di,offset dg:TokBuf ; get next token here + call CParse + cmp ax,4 ; an option? + jne NoOption ; no, do it later... + or [TokBuf],20h ; conver to lower case + cmp [TokBuf],"c" ; cancel option? + jne NotCancel + mov [CanFlag],1 ; set cancel flag + jmp short SkipTok + +NotCancel: + cmp [TokBuf],"p" + jne NoOption + mov [CanFlag],0 ; reset cancel flag + jmp short SkipTok + +NoOption: + mov si,[LastSI] ; whatever it is, lets do it later... + +;--- chose action on filename +SkipTok: + push si ; save pointer to parse line + cmp [CanFlag],1 ; are we in cancel mode + jne CheckName + jmp GoCancel ; yes, use name to cancel file + +;--- check file exists +CheckName: + cmp [Ambig],1 ; is this an ambigous name? + jne NotAmbig + +AnotherAmbig: ; do another ambigous name + call GetAbsN ; get abs name into NameBuf + jnc SubFile ; send it to resident + jmp bad_file ; an error + +NotAmbig: + mov dx,offset dg:NameBuf + mov ax,(open shl 8) ; open for reading... + int 21h + jc bad_file_open + mov bx,ax ; copy handle + mov ah,close + int 21h +SubFile: + mov dx,offset dg:NameBuf + mov word ptr [SubPack+1],dx ; store pointer to name in + mov word ptr [SubPack+3],ds ; submit packet + mov dx,offset dg:SubPack ; DS:DX address of packet + mov ax,0101H ; submit a file to resident + call IntWhileBusy + jnc Cont0 ; successfull, queue not full now... + cmp ax,error_queue_full + jne other_errs + cmp [QFullMes],1 ; Have wa already issued the message? + je Cont1 ; yes, not again... + mov [QFullMes],1 + mov dx,offset dg:FullMes_ptr + call printf_crlf + jmp short Cont1 + +other_errs: + +;***** PROCESS OTHER SUBMIT ERRORS + +Cont0: + mov [QFullMes],0 ; queue is not full +Cont1: + cmp [Ambig],1 ; are we processing an ambigous name? + jne Cont2 + call GetAbsN2 ; get another file name + jnc SubFile +Cont2: + pop si + jmp ParseAgn1 + + +;--- process file name errors +bad_drive: + mov dx,offset dg:InvDrvMes_ptr + jmp short BadName + +Bad_File_Open: + mov dx,offset dg:BadNameMes_ptr + PUSHF + SaveReg + MOV AH,GetExtendedError + INT 21h + RestoreReg ; restore original AX + MOV DX,OFFSET DG:AccDen_PTR + CMP AX,65 ; network access denied? + JZ NoMove ; Yes, return it. + MOV AX,BX + MOV DX,CX +NoMove: + RestoreReg + popf + Jmp short badname + +bad_file: + mov dx,offset dg:BadNameMes_ptr + jmp short BadName + +FNTooLong: + mov dx,offset dg:NamTMes_ptr + +BadName: + call printf_crlf + pop si + jmp ParseAgn1 + + +;--- Issue a cancel command --- +GoCancel: + mov dx,offset dg:NameBuf ; filename + mov ax,0102H + call IntWhileBusy + jc BadCancel + pop si + jmp ParseAgn1 + +BadCancel: + cmp ax,2 + je BadCanName + +;***** PROCESS CANCEL ERROR + +BadCanName: + mov dx,offset dg:BadCanMes_ptr + jmp badname + +;--- Calculate end of resident memory --- +SETBUF: + mov dl,[PathChar] + mov ax,CodeR + mov es,ax +assume es:CodeR + mov [PChar],dl ; sneaky, uh? + +;--- check device + cmp [DevSpec],1 ; was it already specified? + je DoQSize + mov dx,offset dg:prompt_ptr + call std_printf + mov dx,offset dg:TokBuf + mov [TokBuf],9 ; max of 9 chars + mov [TokBuf+1],0 ; assume zero in + mov ah,std_con_string_input + int 21h ; get dev name + mov dx,offset dg:crlf_ptr + call std_printf + mov cl,[TokBuf+1] ; check how many read in + or cl,cl + jz DoQSize ; a CR was typed + xor ch,ch + mov si,offset dg:TokBuf+2 + mov di,offset CodeR:ListName + push si + add si,cx + dec si + cmp byte ptr [si],':' + jne gdevn + dec cx ; get rid of trailing ':' +gdevn: + pop si +gdlop: + lodsb ; copy name + call UpConvT + stosb + loop gdlop + +;--- queue size +DoQSize: + push es + pop ds +assume ds:CodeR + mov ax,MaxFileLen ; maximum length of a file name + mul [QueueLen] ; AX = result + add ax,offset CodeR:FileQueue + mov [EndQueue],ax ; save pointer to last nul + inc ax + mov [buffer],ax ; beggining of buffer + +;--- buffer size + add ax,[BlkSiz] + mov [ENDPTR],AX ; Set end of buffer pointer + mov [NXTCHR],AX ; Buffer empty + add ax,100h ; allow for header + ADD AX,16 ; Convert to para + SHR AX,1 + SHR AX,1 + SHR AX,1 + SHR AX,1 + mov [EndRes],ax ; Add size of buffer to term res size + jmp MoveTrans + + +assume ds:dg,es:dg +TransRet: ; after moving the transient we come + ; here. Isn't this fun, uh? + sti ; Ints were off during initialization +;--- normalize int handlers for new location of dg + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H + MOV DX,OFFSET DG:INT_23 + INT 21H + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H + MOV DX,OFFSET DG:INT_24 + INT 21H + + mov [PInst],1 ; remember we just installed resident part + mov si,[LastSI] ; back up one token + jmp ParseAgn1 ; restart parse + + +ARGDEV: + push ds + mov ax,CodeR + sub ax,10h ; AX points to the header + mov ds,ax + LODSB ; mandatory colon before device + POP DS + CMP AL,':' + JZ DoCparse + dec si + jmp short xk00 +DoCparse: + CALL CPARSE ; Get device name, CX is size of token + jnc xk01 +xk00: + jmp BADTOK +xk01: + cmp [PInst],0 + jne xk00 + CMP AX,2 + jnz xk00 + PUSH SI + PUSH DI + MOV SI,DI + mov ax,CodeR + mov es,ax +assume es:CodeR + MOV WORD PTR [LISTNAME],2020H ; Nul out default + MOV [LISTNAME+2]," " + MOV DI,OFFSET CodeR:LISTNAME + ADD SI,CX + DEC SI ;Point to last char of name + CMP BYTE PTR [SI],':' + JNZ GOODCNT + DEC CX ;Chuck the trailing ':' +GOODCNT: + CMP CX,8 + JBE GOODCNT2 + MOV CX,8 ; Limit to 8 chars for device +GOODCNT2: + POP SI + PUSH SI +TRLOOP: + LODSB + CALL UPCONVt + STOSB + LOOP TRLOOP + POP DI + POP SI + push cs + pop es +assume es:dg + mov [DevSpec],1 ; remember that a device was specified + JMP PARSEAGN + +;--- Uper case convertion --- +UPCONVt: + CMP AL,'a' + JB NOCONVt + CMP AL,'z' + JA NOCONVt + SUB AL,20H +NOCONVt: + RET + +GETNUM: +; Return binary number in AX of number in ES:DI. DI,SI preserved + PUSH SI + PUSH DI + XOR BX,BX + MOV SI,DI + MOV CX,10 ; Base 10 multiplier + LODSB + CMP AL,':' + JNZ BADRET ; Must have leading ':' on numbers +NLP: + LODSB + OR AL,AL + JZ GOODRET + CMP AL,'0' + JB BADRET + CMP AL,'9' + JA BADRET + SUB AL,'0' + XOR AH,AH + XCHG AX,BX + MUL CX + ADD AX,BX + XCHG AX,BX + JMP NLP + +GOODRET: + CLC +MORERET: + MOV AX,BX + POP DI + POP SI + RET + +BADRET: + STC + JMP MORERET + + + +;-----------------------------------------------------------------------; +; Return first absolute name from ambigous name +; +; Entry: NameBuf has the ambigous File Name +; +; Exit: Carry Set if no files match +; else NameBuf has the absolute name +; +assume ds:dg, es:dg + +GetAbsN: + mov ah,Set_DMA ; buffer for ffirst / fnext + mov dx,offset dg:SearchBuf + int 21h + +;--- look for a match + mov dx,offset dg:NameBuf + mov cx,0 ; no attributes + mov ah,Find_First + int 21h + jnc FstFound + ret ; return with carry set + +;--- Place new name in NameBuf +FstFound: + mov si,[NulPtr] ; scan back + std +FstLoop: + lodsb + cmp al,PathChar + jne FstLoop + cld ; just in case... + inc si + inc si + mov [FnamPtr],si + call CopyName + clc + ret + + + +;-----------------------------------------------------------------------; +; Return next absolute name from ambigous +; +GetAbsN2: + mov ah,Set_DMA ; buffer for ffirst / fnext + mov dx,offset dg:SearchBuf + int 21h + mov ah,Find_Next + int 21h + jnc NxtFound + ret ; return with carry set + +NxtFound: + call CopyName + clc + ret + + + +;-----------------------------------------------------------------------; +; Copy name from search buf to NameBuf +; +CopyName: + mov di,[FNamPtr] + mov si,offset dg:SearchBuf.find_buf_pname + cld +CopyAgn: + lodsb + stosb + or al,al ; nul found? + jne CopyAgn + ret + + + +BREAK + +;-----------------------------------------------------------------------; +; ENTRY: ; +; (CodeR-10H):SI Points to input buffer ; +; ES:DI Points to the token buffer ; +; ; +; EXIT: ; +; DS:SI Points to next char in the input buffer ; +; ES:DI Points to the token buffer ; +; CX Character count ; +; AX Condition Code ; +; =1 same as carry set ; +; =2 normal token ; +; =4 switch character, char in token buffer ; +; Carry Flag Set if a CR was found, Reset otherwise ; +; ; +; MODIFIES: ; +; CX, SI, AX and the Carry Flag ; +; ; +;-----------------------------------------------------------------------; + +TAB equ 09h +CR equ 0dh + +CPARSE: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + pushf ; save flags + mov [LastSI],si ; remember last token in case of backup + push ds + mov ax,CodeR + sub ax,10h ; AX points to the header + mov ds,ax + push di ; save the token buffer addrss + xor cx,cx ; no chars in token buffer + call kill_bl + + cmp al,CR ; a CR? + jne sj2 ; no, skip +sj1: + mov ax,1 ; condition code + dec si ; adjust the pointer + pop di ; retrive token buffer address + pop ds + popf ;restore flags + stc ;set the carry bit + ret + +sj2: + mov dl,[SWITCHAR] + cmp al,dl ;is the char the switch char? + jne anum_char ;no, process... + call kill_bl + cmp al,CR ;a CR? + je sj1 ;yes, error exit + call move_char ;Put the switch char in the token buffer + mov ax,4 ;Flag switch + jmp short x_done2 + +anum_char: + call move_char ;just an alphanum string + lodsb + cmp al,' ' + je x_done + cmp al,tab + je x_done + cmp al,CR + je x_done + cmp al,',' + je x_done + cmp al,'=' + je x_done + cmp al,dl ;Switch character + jne anum_char +x_done: + dec si ;adjust for next round + mov ax,2 ;normal token +x_done2: + push ax ;save condition code + mov al,0 + stosb ;null at the end + pop ax + pop di ;restore token buffer pointer + pop ds + popf + clc ;clear carry flag + ret + + +kill_bl proc near + lodsb + cmp al,' ' + je kill_bl + cmp al,tab + je kill_bl + cmp al,',' ;a comma? + je kill_bl + cmp al,'=' + je kill_bl + ret +kill_bl endp + + +move_char proc near + stosb ;store char in token buffer + inc cx ;increment char count + ret +move_char endp + + +;-----------------------------------------------------------------------; +GetHInt: +assume ds:dg,es:dg + push es + MOV AX,(GET_INTERRUPT_VECTOR SHL 8) OR 24H + INT 21H +assume es:nothing + MOV WORD PTR [HARDCH],BX + MOV WORD PTR [HARDCH+2],ES + pop es +assume es:dg + ret + +;-----------------------------------------------------------------------; +SetInts proc near +assume ds:dg,es:dg + + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H + MOV DX,OFFSET DG:INT_23 + INT 21H + + MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H + MOV DX,OFFSET DG:INT_24 + INT 21H + + ret +SetInts endp + + +;-----------------------------------------------------------------------; +Public PRNT002S, PRNT002E +PRNT002s: + +INT_24_RETADDR DW OFFSET DG:INT_24_BACK +in_int_23 db 0 ; reentrancy flag + +PRNT002E: + +INT_24 PROC FAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSHF + PUSH CS + PUSH [INT_24_RETADDR] + PUSH WORD PTR [HARDCH+2] + PUSH WORD PTR [HARDCH] + RET +INT_24 ENDP + +INT_24_BACK: + CMP AL,2 ;Abort? + JNZ IRETI + inc [in_int_23] ; no int 23's allowed + push cs + pop ds +assume ds:dg + push cs + pop ss +assume ss:dg + mov sp, offset dg:intStk ; setup local int stack + cmp [PInst],2 + je DoNotUndo +DoUndo: + call Restore_ints +DoNotUndo: + MOV AH,EXIT + MOV AL,0FFH + INT 21H +IRETI: + IRET + +;-----------------------------------------------------------------------; + +INT_23: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + cmp [in_int_23],0 ; check for a re-entrant call + je do_int_23 + iret ; discard further int 23's + +do_int_23: + inc [in_int_23] ; make sure no more int 23's + push cs + pop ds +assume ds:dg + push cs + pop ss +assume ss:dg + mov sp, offset dg:intStk ; setup local int stack + cmp [PInst],2 + jne DoUndo +UnlockQueue: + mov ax,0105H + call IntWhileBusy ; unlock print queue (just in case) + jmp short DoNotUndo + + +;-----------------------------------------------------------------------; +; Restore all ints used by print to original values + +Restore_ints proc near + +assume ds:dg,es:nothing,ss:dg + + CLI + mov ax,(set_interrupt_vector shl 8) or SOFTINT ; (SOFTINT) + push ds + lds dx,[i28vec] + int 21h + pop ds + + mov ax,(set_interrupt_vector shl 8) or COMINT ; (COMINT) + push ds + lds dx,[i2fvec] + int 21h + pop ds + + if IBM + + mov ax,(set_interrupt_vector shl 8) or 13h + push ds + lds dx,[i13vec] + int 21h + pop ds + + mov ax,(set_interrupt_vector shl 8) or 15h + push ds + lds dx,[i15vec] + int 21h + pop ds + + mov ax,(set_interrupt_vector shl 8) or 17h + push ds + lds dx,[i17vec] + int 21h + pop ds + + mov ax,(set_interrupt_vector shl 8) or 14h + push ds + lds dx,[i14vec] + int 21h + pop ds + + mov ax,(set_interrupt_vector shl 8) or 05h + push ds + lds dx,[i05vec] + int 21h + pop ds + + endif + + if HARDINT + + mov ax,(set_interrupt_vector shl 8) or INTLOC ; (INTLOC) + push ds + lds dx,[i1cvec] + int 21h + pop ds + + endif + STI + ret + +Restore_ints endp + +CODE ENDS + + +Stack Segment Stack + +Public PRNT003S, PRNT003E +PRNT003S: + dw 100 dup(0) + +TransSize label byte ; end of transient + ; only because code is para algned +PRNT003E: + +Stack Ends + + END Transient diff --git a/SRC/CMD/PRINT/PRINT_TM.ASM b/SRC/CMD/PRINT/PRINT_TM.ASM new file mode 100644 index 0000000..4d92c26 --- /dev/null +++ b/SRC/CMD/PRINT/PRINT_TM.ASM @@ -0,0 +1,42 @@ +; SCCSID = @(#)print_tmes.asm 4.1 85/07/17 + INCLUDE pridefs.inc + + +BREAK + +; +; MSDOS V3.00 PRINT +; +; Transient Portion Message +; +; 02/13/84 MAU Fixed bug with BadCanMes +; + + +addr macro sym,name + public name + ifidn ,<> + + dw offset dg:sym + else + +name dw offset dg:sym + endif + endm + + +DATA SEGMENT public BYTE + + extrn namebuf:byte,arg_buf:byte + public whichmes,fstmes,secmes + +Public PRNTMES001S, PRNTMES001E +PRNTMES001S equ $ + + +include print_tm.inc + +PRNTMES001E equ $ + +data ends + end diff --git a/SRC/CMD/PRINT/PRINT_TM.INC b/SRC/CMD/PRINT/PRINT_TM.INC new file mode 100644 index 0000000..22c7b45 --- /dev/null +++ b/SRC/CMD/PRINT/PRINT_TM.INC @@ -0,0 +1,53 @@ + +CONFLICTMES DB "Cannot use PRINT - Use NET PRINT",0 + addr conflictmes,conflictmes_ptr + +INVPARM DB "Invalid parameter",0 + addr invparm,invparm_ptr + +FULLMES DB "PRINT queue is full",0 + addr fullmes,fullmes_ptr + +NoFils db "PRINT queue is empty",0 + addr nofils,nofils_ptr + +Dispmes db " %s%s",0 + addr dispmes,dispmes_ptr + addr arg_buf +whichmes dw ? + +FstMes db " is currently being printed",0 +SecMes db " is in queue",0 + +BadNameMes db "%s File not found",0 + addr badnamemes,badnamemes_ptr + addr namebuf + +AccDen db "Access denied",0 + addr AccDen,AccDen_ptr + +InvDrvMes db "Invalid drive specification",0 + addr invdrvmes,invdrvmes_ptr + +NamTMes db "%s Pathname too long",0 + addr namtmes,namtmes_ptr + addr namebuf + +BadCanMes db "%s File not in PRINT queue",0 + addr badcanmes,badcanmes_ptr + addr namebuf + +;This message must be $ terminated and printed using std_con_string_output + public badver +BADVER DB "Incorrect DOS version$" + +CRLF DB 13,10,0 + addr crlf,crlf_ptr + +CNTMES DB "Errors on list device indicate that it",13,10 + DB "may be off-line. Please check it.",13,10,0 + addr cntmes,cntmes_ptr + +PROMPT DB "Name of list device [PRN]: ",0 + addr prompt,prompt_ptr + \ No newline at end of file diff --git a/SRC/CMD/SORT/MAKEFILE b/SRC/CMD/SORT/MAKEFILE new file mode 100644 index 0000000..cb3f7ea --- /dev/null +++ b/SRC/CMD/SORT/MAKEFILE @@ -0,0 +1,42 @@ +#** makefile for SORT + +DEST =sort +MSG =messages + +# Path definitions + +BIOS =..\..\BIOS +DOS =..\..\DOS + +# Definitions for assembler + +ASM =masm +AFLAGS =-Mx -t +AINC =-I..\..\inc -I$(DOS) + +# Definitions for C compiler + +CC =cl +CFLAGS =-Ox -Zlp +CINC =-I..\..\h + +# Definitions for linker + +LINK =link +LIBC =..\..\libc + + +# Rules and Dependencies follow + + + +SORT.OBJ: SORT.ASM $(DOS)\SYSCALL.INC + masm $(AFLAGS) $(AINC) SORT; + +$(MSG).OBJ: $(MSG).ASM $(MSG).inc + masm $(AFLAGS) $(AINC) $(MSG); + +SORT.COM: SORT.OBJ $(MSG).OBJ + LINK @SORT.LNK + EXEFIX SORT.EXE 1 1 + \ No newline at end of file diff --git a/SRC/CMD/SORT/MESSAGES.ASM b/SRC/CMD/SORT/MESSAGES.ASM new file mode 100644 index 0000000..685a62e --- /dev/null +++ b/SRC/CMD/SORT/MESSAGES.ASM @@ -0,0 +1,91 @@ +TITLE SORT Messages + +false equ 0 +true equ not false +msver equ true +ibm equ false +internat equ true + +;include version.inc + +msg Macro lbl,msg +local a +public lbl,lbl&len +lbl&len dw a - lbl +lbl db msg +a label byte +endm + +CONST SEGMENT PUBLIC BYTE + + PUBLIC BADVER + +include messages.inc + +if internat + public table +;This table defibes the coalating sequence to be used for +;international characters. This table also equates +;lower case character to upper case unlike a straight ASCII sort. +;If your character set is like the IBM PC simply turn +;on the IBM conditional. If it is different simply modify the +;table appropriately. Note: to insert a foreign language character +;between two ASCII characters it will be necessary to +;"shift" all the ASCII characters to make room for a new character. +;If this is done be sure to equate the foreign characters to the new +;values instead of the old values which have been set here to the +;upper case ASCII values. + +table db 0,1,2,3,4,5,6,7 + db 8,9,10,11,12,13,14,15 + db 16,17,18,19,20,21,22,23 + db 24,25,26,27,28,29,30,31 + db " ","!",'"',"#","$","%","&","'" + db "(",")","*","+",",","-",".","/" + db "0","1","2","3","4","5","6","7" + db "8","9",":",";","<","=",">","?" + db "@","A","B","C","D","E","F","G" + db "H","I","J","K","L","M","N","O" + db "P","Q","R","S","T","U","V","W" + db "X","Y","Z","[","\","]","^","_" + db "`","A","B","C","D","E","F","G" + db "H","I","J","K","L","M","N","O" + db "P","Q","R","S","T","U","V","W" + db "X","Y","Z","{","|","}","~",127 +if msver + db 128,129,130,131,132,133,134,135 + db 136,137,138,139,140,141,142,143 + db 144,145,146,147,148,149,150,151 + db 152,153,154,155,156,157,158,159 + db 160,161,162,163,164,165,166,167 + db 168,169,170,171,172,173,174,175 + endif +if ibm + db "C","U","E","A","A","A","A","C" + db "E","E","E","I","I","I","A","A" + db "E","A","A","O","O","O","U","U" + db "Y","O","U","$","$","$","$","$" + db "A","I","O","U","N","N",166,167 + db "?",169,170,171,172,"!",'"','"' + endif + db 176,177,178,179,180,181,182,183 + db 184,185,186,187,188,189,190,191 + db 192,193,194,195,196,197,198,199 + db 200,201,202,203,204,205,206,207 + db 208,209,210,211,212,213,214,215 + db 216,217,218,219,220,221,222,223 +if ibm + db 224,"S" +endif +if msver + db 224,225 +endif + db 226,227,228,229,230,231 + db 232,233,234,235,236,237,238,239 + db 240,241,242,243,244,245,246,247 + db 248,249,250,251,252,253,254,255 + endif + +CONST ENDS + END + \ No newline at end of file diff --git a/SRC/CMD/SORT/MESSAGES.INC b/SRC/CMD/SORT/MESSAGES.INC new file mode 100644 index 0000000..47d1d32 --- /dev/null +++ b/SRC/CMD/SORT/MESSAGES.INC @@ -0,0 +1,10 @@ + +BADVER DB "SORT: Incorrect DOS version",13,10,"$" + + msg NoMem,<"SORT: Insufficient memory",13,10> + + msg NoDisk,<"SORT: Insufficient disk space",13,10> + + msg BadParm,<"Invalid parameter",13,10> + + \ No newline at end of file diff --git a/SRC/CMD/SORT/SORT.ASM b/SRC/CMD/SORT/SORT.ASM new file mode 100644 index 0000000..3d7e99c --- /dev/null +++ b/SRC/CMD/SORT/SORT.ASM @@ -0,0 +1,470 @@ +TITLE SORT FILTER FOR MS-DOS +; 0 +; Sort /R /+n +; /R -> reverse sort +; /+n -> sort on column n +; +; Written by: Chris Peters +; +; Modification History: +; 3-18-83 MZ Fix CR-LF at end of buffer +; Fix small file sorting +; Fix CR-LF line termination bug +; Comment the Damn source +; +; 6-23-86 Russ Whitehead Add DOS 3.30 support for multiple languages +; Inclusion of common DOS VERSION check equate +; +; +FALSE EQU 0 +TRUE EQU NOT FALSE + +internat equ true +.xlist +.xcref + +;include version.inc + +BREAK MACRO subtitle + SUBTTL subtitle + PAGE +ENDM + + INCLUDE SYSCALL.INC + include versiona.inc +.cref +.list + +sys MACRO name ; system call macro + MOV AH,name + INT 21h + ENDM +save MACRO reglist ; push those registers +IRP reg, + PUSH reg +ENDM +ENDM +restore MACRO reglist ; pop those registers +IRP reg, + POP reg +ENDM +ENDM + +MAXREC EQU 256 ; MAXIMUM NUL RECORD SIZE + +SPACE EQU 0 ; Offset zero in the allocated block +BUFFER EQU MAXREC ; Offset MAXREC in the allocated block + +SUBTTL Segments used in load order + + +CODE SEGMENT +CODE ENDS + +CONST SEGMENT PUBLIC BYTE +CONST ENDS + +CSTACK SEGMENT STACK + DB 128 DUP (0) ; initial stack to be clear +;;; DB 100H DUP (0) ; This is a "trial" change IBM hasn't +;;; ; made up their minds about +CSTACK ENDS + +DG GROUP CODE,CONST,CSTACK + +CODE SEGMENT +ASSUME CS:DG,DS:NOTHING,ES:NOTHING,SS:CSTACK + +COLUMN DW 0 ; COLUMN TO USE FOR KEY + 1 +SWITCH DB '/' +;------------------------------------------RW +CTRY_INFO db ? +CTRY_TABLE_OFF dw ? +CTRY_TABLE_SEG dw ? +;------------------------------------------ + + +SORT: +; +; check for proper version number of system +; + sys GET_VERSION + cmp ax,expected_version + je okdos + + MOV DX,OFFSET DG:BADVER ; Get error message + PUSH CS ; Get DS addressability + POP DS + sys STD_CON_STRING_OUTPUT ; Send to STDOUT + PUSH ES ; long segment + PUSH COLUMN ; offset zero +LONG_RET PROC FAR + RET ; long return to OS +LONG_RET ENDP +; +; get proper switch character +; +OKDOS: + MOV AL,0 ; Get current switch character + sys CHAR_OPER + MOV SWITCH,DL +; +; parse command line +; + MOV SI,80H ; pointer to command line + CLD ; go left to right + XOR CX,CX + LODSB + MOV CL,AL ; CX = length of command line +SWITCH_LOOP: + CALL GET_CHAR ; get a character + CMP AL,SWITCH ; beginning of switch? + JNZ SWITCH_LOOP ; No, get next character + CALL GET_CHAR ; get 1st char of switch + CMP AL,'+' ; Column to sort? + JZ SWITCH_NUMBER ; Yes, parse a number + OR AL,20h ; convert to lower case + CMP AL,'r' ; Reverse sort? + JNZ SwitchError ; No, get next switch + MOV CS:CODE_PATCH,72h ; sleaze JAE into JB + JMP SWITCH_LOOP ; get next switch +SwitchError: + MOV SI,OFFSET DG:BadParmLen + JMP Error_Exit +SWITCH_NUMBER: + MOV COLUMN,0 ; start off at 0 +SWITCH_NEXT_NUMBER: + CALL GET_CHAR ; get supposed digit + SUB AL,'0' ; convert to number + JB SWITCH_LOOP ; less than '0' + CMP AL,9 ; is it a valid digit? + JA SWITCH_LOOP ; nope, get next switch + CBW ; make it a full word + MOV BX,AX ; save byte away + MOV AX,10 ; decimal number system + MUL COLUMN ; take previous result + ADD AX,BX ; add in low order digit + MOV COLUMN,AX ; save away value + JMP SWITCH_NEXT_NUMBER ; get next character +GET_CHAR: + JCXZ END_GET ; End of line + DEC CX ; dec char count + LODSB ; get the character + RET ; return +END_GET: + POP AX ; nuke return on stack +; +; set up column for proper sort offset +; +END_SWITCH: + ADD COLUMN,2 + CMP COLUMN,2 + JZ GOT_COL + DEC COLUMN + +; +; Get sorting area, no more than 64K +; +GOT_COL: + MOV BX,1000H ; 64K worth of paragraphs +GET_MEM: + sys ALLOC ; allocate them from somewhere + JNC GOT_MEM ; if error, BX has amount free, try to get it + OR BX,BX ; but, is BX = 0? + JNZ GET_MEM ; nope, try to allocate it + JMP SIZERR ; complain + +GOT_MEM: +;------------------------------------------Following add in DOS 3.3 for Nat Lang Support. -RW + push ax + push ds + push es ; Save ES + mov ah,065h ; Get extended country information + mov al,6 ; Function for Get collating sequence + mov bx,-1 ; Get active code page + mov dx,-1 ; Get info from active country + mov cx,5 ; Number of bytes to be returned + push cs ; Place DS + pop es ; in ES + mov di,offset ctry_info ; Return area for 5 byte requested information + int 021h ; Do it ! + ; Copy the table in DOS to our segment + lds si,dword ptr cs:ctry_table_off + mov di,seg dg + mov es,di + mov di,offset dg:table + mov cx,word ptr [si] + add si,2 + mov ax,256 + sub ax,cx + add di,ax + cld + rep movsb + + pop es ; Restore ES + pop ds ; Restore DS + pop ax ; Restore AX +;------------------------------------------ + MOV DS,AX ; Point DS to buffer + MOV ES,AX ; and point ES to buffer + MOV CL,4 ; 2^4 bytes per paragraph + SHL BX,CL ; Find out how many bytes we have + +; +; clear out temporary record area +; + MOV CX,MAXREC/2 ; Size of temporary buffer (words) + MOV AX,' ' ; Character to fill with + MOV DI,SPACE ; Beginning of temp buffer + REP STOSW ; Blam. +; +; read in file from standard input +; + MOV DX,BUFFER + 2 ; DX = place to begin reading + MOV CX,BX ; CX is the max number to read + SUB CX,MAXREC + 2 ; remember offset of temp buffer +SORTL: + XOR BX,BX ; Standard input + sys READ ; Read it in + ADD DX,AX ; Bump pointer by count read + SUB CX,AX ; subtract from remaining the count read + JZ SIZERR ; if buffer is full then error + OR AX,AX ; no chars read -> end of file + JNZ SORTL ; there were chars read. go read again + JMP SHORT SIZOK ; trim last ^Z terminated record +SIZERR: + MOV SI,OFFSET DG:NoMemLen ; not enough memory error +ERROR_EXIT: + PUSH CS ; DS addressability + POP DS + LODSW ; get length + MOV CX,AX ; put into appropriate register + MOV DX,SI ; get output destination + MOV BX,2 ; output to standard error + sys WRITE ; and write it out + MOV AL,1 ; return an error code + sys EXIT + +; +; Look for a ^Z. Terminate buffer at 1st ^Z. +; +SIZOK: + MOV BX,DX ; save end pointer + MOV CX,DX ; get pointer to end of text + SUB CX,BUFFER+2 ; dif in pointers is count + MOV AL,1AH ; char is ^Z + MOV DI,BUFFER+2 ; point to beginning of text + REPNZ SCASB ; find one + JNZ NoBack ; nope, try to find CRLF + DEC BX ; pretend that we didn't see ^Z +NoBack: + SUB BX,CX ; sub from endpointer the number left + SUB BX,2 ; Hope for a CR LF at end + CMP WORD PTR [BX],0A0Dh ; Was there one there? + JZ GOTEND ; yep, here is the end + ADD BX,2 ; nope, bump back to SCASB spot + CMP BYTE PTR [BX],AL ; Was there ^Z there? + JZ GOTEND ; yep, chop it + INC BX ; Nope, skip last char +GOTEND: + MOV BP,BX ; BP = filesize-2(CRLF)+temp buffer+2 + MOV WORD PTR DS:[BP],0 ; 0 at end of the file +; +; We now turn the entire buffer into a linked list of chains by +; replacing CRLFs with the length of the following line (with 2 for CRLF) +; + MOV BX,BUFFER ; pointer to line head (length) + MOV DI,BUFFER+2 ; pointer to line text +REPLACE_LOOP: + MOV AL,13 ; char to look for is CR + MOV CX,BP ; count = end pointer + SUB CX,DI ; chop off start point to get length + INC CX ; add 1??? +REPLACE_SCAN: + REPNZ SCASB ; look for CR + JNZ REPLACE_SKIP ; count exhausted + CMP BYTE PTR [DI],10 ; LF there? + JNZ REPLACE_SCAN ; nope, continue scanning +REPLACE_SKIP: + MOV AX,DI ; AX to point after CR + DEC AX ; AX to point to CR + save ; save pointer + SUB AX,BX ; AX is length of line found + MOV [BX],AX ; stuff it in previous link + restore ; get pointer to next + INC DI ; skip LF??? + JCXZ END_REPLACE_LOOP ; no more to scan -> go sort + JMP REPLACE_LOOP ; look for next + +END_REPLACE_LOOP: + MOV WORD PTR [BX],0 ; terminate file with nul + LEA BP,[BX+2] ; remember the null line at end + MOV DI,BUFFER ; DI is start of unsorted section + +; +; begin sort. Outer loop steps over all unsorted lines +; +OUTER_SORT_LOOP: + MOV BX,DI ; BX is start of unsorted section + MOV SI,BX ; SI is scanning place link + CMP WORD PTR [BX],0 ; are we at the end of the buffer? + JNZ INNER_SORT_LOOP ; No, do inner process + JMP END_OUTER_SORT_LOOP ; yes, go dump out + +; +; BX points to best guy found so far. We scan through the sorted section +; to find an appropriate insertion point +; +INNER_SORT_LOOP: + ADD SI,[SI] ; link to next fellow + MOV AX,[SI] ; get length of comparison guy + OR AX,AX ; test for end of buffer + JZ END_INNER_SORT_LOOP ; if zero then figure out insertion + save ; save SI,DI + MOV DI,BX ; DI = pointer to tester link + SUB AX,COLUMN ; adjust length for column + JA AXOK ; more chars in tester than column? + MOV SI,SPACE ; point SI to blank area + MOV AX,MAXREC ; make AX be max length +AXOK: + MOV DX,[DI] ; get length of best guy + SUB DX,COLUMN ; adjust length for column + JA DXOK ; there are more chars after column + MOV DI,SPACE ; point air to a space + MOV DX,MAXREC ; really big record +DXOK: + MOV CX,AX ; AX is shortest record + CMP AX,DX ; perhaps DX is shorter + JB SMALL ; nope, leace CX alone + MOV CX,DX ; DX is shorter, put length in CX +SMALL: + ADD DI,COLUMN ; offset into record + ADD SI,COLUMN ; offset into other record +if not internat + REPZ CMPSB ; compare every one + endif +if internat + push bx + push ax + mov bx,offset dg:table +tloop: lodsb + xlat byte ptr cs:[bx] + mov ah,al + mov al,es:[di] + inc di + xlat byte ptr cs:[bx] + cmp ah,al + loopz tloop + pop ax + pop bx + endif + restore ; get head pointers back + JNZ TESTED_NOT_EQUAL ; didn't exhaust counter, conditions set + CMP AX,DX ; check string lengths +TESTED_NOT_EQUAL: +; +; note! jae is patched to a jbe if file is to be sorted in reverse! +; +CODE_PATCH LABEL BYTE + JAE INNER_SORT_LOOP ; if this one wasn't better then go again + MOV BX,SI ; it was better, save header + JMP INNER_SORT_LOOP ; and scan again + +END_INNER_SORT_LOOP: + MOV SI,BX ; SI is now the best person + CMP SI,DI ; check best for current + JZ END_INSERT ; best equals current, all done + +; +; SI points to best line found so far +; DI points to a place to insert this line +; DI is guaranteed to be < SI +; make room for line at destination +; + MOV DX,[SI] ; get length of line + save ; save positions of people + STD ; go right to left + MOV CX,BP ; get end of file pointer + SUB CX,DI ; get length from destination to end + MOV SI,BP ; start from end + DEC SI ; SI points to end of file + MOV DI,SI ; destination is end of file + ADD DI,DX ; DI points to new end of file + REP MOVSB ; blam. Move every one up + CLD ; back left to right + restore ; get old source and destination +; +; MOVE NEW LINE INTO PLACE +; + save ; save destination + ADD SI,DX ; adjust for previous movement + save ; save this value + MOV CX,DX ; get number to move + REP MOVSB ; blam. move the new line in + restore ; get back destination and new source +; +; DELETE LINE FROM OLD PLACE +; + save ; save destination + MOV CX,BP ; pointer to end + ADD CX,DX ; remember bump + SUB CX,SI ; get count of bytes to move + INC CX ; turn it into a word + SHR CX,1 ; or a count of words + MOV DI,SI ; new destination of move + ADD SI,DX ; offset of block + REP MOVSW ; blam, squeeze out the space + restore ; get back original destination + MOV WORD PTR DS:[BP-2],0 ; remake the end of file mark + +END_INSERT: + ADD DI,[DI] ; link to next guy + JMP OUTER_SORT_LOOP ; and continue +; +; PUT BACK IN THE CR-LF +; +END_OUTER_SORT_LOOP: + MOV DI,BUFFER ; start at beginning (where else) + MOV CX,[DI] ; count of butes + +INSERT_LOOP: + ADD DI,CX ; point to next length + MOV CX,[DI] ; get length + MOV WORD PTR [DI],0A0DH ; replace length with CRLF + CMP CX,0 ; check for end of file + JNZ INSERT_LOOP ; nope, try again + +WRITE_FILE: + MOV DX,BUFFER+2 ; get starting point + MOV CX,BP ; pointer to end of buffer + SUB CX,DX ; dif in pointers is number of bytes + MOV BX,1 ; to standard output + sys WRITE ; write 'em out + JC BADWRT ; some bizarre error -> flag it + CMP AX,CX ; did we write what was expected? + JZ WRTOK ; yes, say bye bye +BADWRT: + MOV SI,OFFSET dg:NoDiskLen ; strange write error + JMP ERROR_EXIT ; bye bye +WRTOK: + XOR AL,AL ; perfect return (by convention) + sys EXIT ; bye! + +CODE ENDS + +CONST SEGMENT PUBLIC BYTE + EXTRN BADVER:BYTE,NoMemLen:WORD,NoDiskLen:WORD,BadParmLen:WORD +if internat + extrn table:byte + endif +CONST ENDS + +SUBTTL Initialized Data +PAGE +CSTACK SEGMENT STACK + DB (362 - 80h) + 96 dup (0) ; (362 - 80h) == New - Old IBM + ; interrupt reqs. == size of growth +CSTACK ENDS + + END SORT + \ No newline at end of file diff --git a/SRC/CMD/SORT/SORT.LNK b/SRC/CMD/SORT/SORT.LNK new file mode 100644 index 0000000..4c18522 --- /dev/null +++ b/SRC/CMD/SORT/SORT.LNK @@ -0,0 +1,2 @@ +SORT messages +SORT.EXE /m; diff --git a/SRC/CMD/SYS/MAKEFILE b/SRC/CMD/SYS/MAKEFILE new file mode 100644 index 0000000..70827a6 --- /dev/null +++ b/SRC/CMD/SYS/MAKEFILE @@ -0,0 +1,52 @@ +#** makefile for SYS + +DEST =sys +MSG =messages + +# Path definitions + +BIOS =..\..\BIOS +BOOT =..\..\BOOT +DOS =..\..\DOS +LIBC =..\..\libc + +# Definitions for assembler + +ASM =masm +AFLAGS =-Mx -t +AINC =-I..\..\inc -I$(DOS) + +# Definitions for C compiler + +CC =cl +CFLAGS =-Ox -Zlp +CINC =-I..\..\h + +# Definitions for linker + +LINK =link +LIBC =..\..\libc + + +# Rules and Dependencies follow + + +SYS.OBJ: SYS.ASM $(DOS)\DOSSYM.INC $(DOS)\DOSMAC.INC \ + $(DOS)\BPB.INC $(DOS)\BUFFER.INC $(DOS)\SYSVAR.INC \ + $(DOS)\MULT.INC $(DOS)\DIRENT.INC $(DOS)\DPB.INC \ + $(DOS)\CURDIR.INC $(DOS)\CPMFCB.INC $(DOS)\FIND.INC \ + $(DOS)\PDB.INC $(DOS)\SF.INC $(DOS)\ARENA.INC $(DOS)\INTNAT.INC \ + $(DOS)\ERROR.INC $(DOS)\SYSCALL.INC $(DOS)\IOCTL.INC \ + $(BOOT)\BOOT.INC + masm $(AFLAGS) $(AINC) SYS; + +$(MSG).OBJ: $(MSG).ASM $(MSG).inc + masm $(AFLAGS) $(AINC) $(MSG); + +$(LIBC)\printf.obj: $(LIBC)\printf.asm + masm $(AFLAGS) $(AINC) $(LIBC)\printf,$(LIBC)\printf; + +SYS.EXE: SYS.OBJ $(MSG).OBJ + link @sys.lnk + convert sys.exe + del sys.exe diff --git a/SRC/CMD/SYS/MESSAGES.ASM b/SRC/CMD/SYS/MESSAGES.ASM new file mode 100644 index 0000000..d6a40e5 --- /dev/null +++ b/SRC/CMD/SYS/MESSAGES.ASM @@ -0,0 +1,95 @@ +; SCCSID = @(#)sysmes.asm 1.4 85/10/03 + TITLE Message file for MS-DOS SYS Program + +FALSE EQU 0 +TRUE EQU NOT FALSE + +;IBMJAPVER EQU FALSE +;IBMVER EQU TRUE +;MSVER EQU FALSE +;IBMCOPYRIGHT EQU FALSE + +include version.inc + +addr macro sym,name + public name + ifidn ,<> + + dw offset dg:sym + else + +name dw offset dg:sym + endif + endm + +CODE SEGMENT BYTE PUBLIC +CODE ENDS + +CONST SEGMENT BYTE PUBLIC +CONST ENDS + +DATA SEGMENT BYTE PUBLIC +DATA ENDS + +DG GROUP CODE,DATA,CONST + + +CONST SEGMENT PUBLIC BYTE + + PUBLIC BadVer, sysdrv, TargDrv, GetTarg_ptr + + PUBLIC NotNetM_ptr + +include messages.inc + + IF IBMJAPVER + Public Baddisk_ptr + ENDIF + +; +; In order to allow SYS to work on disks that have been formatted on another +; MSDOS system, we use the following variables which can be set up accordingly +; before assembling and linking the variuos files for SYS. + +; +; Name of system files to be written to the disk +; File names must be terminated with a NULL. +; +Public SourceBIOSFile,SourceDOSFile + +IF IBMCOPYRIGHT +SourceBIOSFile db "IBMBIO.COM",0 +SourceDOSFile db "IBMDOS.COM",0 +ELSE +SourceBIOSFile db "IO.SYS",0 +SourceDOSFile db "MSDOS.SYS",0 +ENDIF + +; +; Tables of files to search for on destination disk +; NOTES: Each entry MUST be exactly 12 bytes long, with extra fields filled with +; NULLs. +; The files should be in corresponding order in the two tables. +; The end-of-table is indicated by an entry of -1. +; +Public BIOSNamesTable,DOSNamesTable + +IF IBMCOPYRIGHT +BIOSNamesTable db "IBMBIO.COM",0,0 + db -1 + +DOSNamesTable db "IBMDOS.COM",0,0 + db -1 +ELSE +BIOSNamesTable db "IO.SYS",0,0,0,0,0,0 + db -1 + +DOSNamesTable db "MSDOS.SYS",0,0,0 + db -1 +ENDIF + + +CONST ENDS + + END + \ No newline at end of file diff --git a/SRC/CMD/SYS/MESSAGES.INC b/SRC/CMD/SYS/MESSAGES.INC new file mode 100644 index 0000000..9cca608 --- /dev/null +++ b/SRC/CMD/SYS/MESSAGES.INC @@ -0,0 +1,48 @@ + +NotNetM db "Cannot SYS to a Network drive",0 + addr NotNetM,NotNetM_ptr + + IF IBMJAPVER +BadDisk db "Destination disk cannot be booted",0 + addr baddisk,baddisk_ptr + ENDIF + +;This message must be terminated by a $ and printed with std_con_output +BADVER DB "Incorrect DOS version",13,10,"$" + +BadDrv db "Invalid drive specification",0 + addr Baddrv,baddrv_ptr + +BadParm db "Invalid parameter",0 + addr BadParm,BadParm_ptr + +NoDest db "No room for system on destination disk",0 + addr NoDest,NoDest_ptr + +BadSiz db "Incompatible system size",0 + addr BadSiz,BadSiz_ptr + +Done db "System transferred",13,10,0 + addr done,done_ptr + +NoSys db "No system on default drive",13,10,0 + addr NoSys,NoSys_ptr + +GETSYS DB "Insert system disk in drive %c",13,10 + db "and strike any key when ready",0 + addr getsys,getsys_ptr + addr sysdrv + +SYSDRV DB "A",0 + +GetTarg DB "Insert destination disk in drive %c",13,10 + db "and strike any key when ready",0 + addr GetTarg,GetTarg_ptr + addr Targdrv + +TargDrv DB "B",0 + +crlf db 13,10,0 + addr crlf,crlf_ptr + + \ No newline at end of file diff --git a/SRC/CMD/SYS/SYS.ASM b/SRC/CMD/SYS/SYS.ASM new file mode 100644 index 0000000..d36e859 --- /dev/null +++ b/SRC/CMD/SYS/SYS.ASM @@ -0,0 +1,1168 @@ +; SCCSID = @(#)sys.asm 1.12 85/10/06 +TITLE MS-DOS SYS Program +; SYS - Copies system programs IBMBIO.COM/IO.SYS and IBMDOS.COM/MSDOS.SYS +; 1.6 05/21/82 Added rev number message +; 1.61 06/04/82 Allow SYS to blank disk TimP at SCP +; 1.70 06/30/82 NON contiguous DOS allowed on 2.00 IBM. Allows SYS to +; 1.0 1.1 disks. +; 1.71 07/02/82 Put in CHDIRs to make sure everything done in root dir. +; 1.80 04/26/83 MZ make sys work in small machines; use full 2.0 +; system calls +; 1.81 07/22/83 ARR Added check in IBM version for valid FAT ID on +; destination because of IBM problem with SYSing to +; unformatted disks which are really formatted. Prints +; NoDest message for ridic IBM reasons, should have a +; better message. +; 1.82 08/12/83 ARR ZIBOed again. Mark fails to check for errors on +; his file I/O. Results in SYS saying system +; transferred when it hasn't been. +; 1.83 09/08/83 EKE Added code to quit if sys called on a drive across +; a net. +; 1.84 09/09/83 CHRISP grabbed against his will to make this stupid +; program write out a boot sector +; 1.85 10/18/83 NP Printf to print messages and it's now an .EXE file +; 1.86 11/8/83 MZ fix hard file output of boot sector +; 1.87 5/1/84 MZ make sys prompt for system disk in default drive. +; 3.20 11/9/84 RS make sys write out a correct boot sector for the +; version of DOS. It grabs the boot sector off the system +; disk and inserts the correct BPB. +; Uses IOCTL Get Device Parms to get BPB for a Hard drive. +; 3.20 08/5/85 RS Allow FAT ID byte of 0F0H for 'strange' media +; layouts. These come about because of /T /N switches in +; FORMAT. +; 3.20 09/16/85 Incorporate tables of filenames to allow system files +; used by other OEMs to be SYSed onto disks formatted on +; other MSDOS systems. Allows the flexibility to replace +; system files for one OEM by system files for another. +; +; +; 3.30 06/04/86 MT removes initial check for IBMBIO and DOS - not needed +; because of later search of dirs +; 3.30 06/16/86 MT only force part of IBMBIO contig - do this by assuming +; contig part smaller than 1.10 BIOS +; 3.30 06/16/86 MT Check diks space for enough room to install BIO and DOS +.xlist +.xcref + include version.inc + INCLUDE DOSSYM.INC ;also defines version of dos + include ioctl.INC +.cref +.list + +;IBMJAPVER EQU FALSE ; this and the following are mutually +;IBMVER EQU TRUE ; exclusive +;IBMCOPYRIGHT EQU FALSE + +printf_code segment public + extrn printf:far +printf_code ends + +CODE SEGMENT PARA PUBLIC +CODE ENDS + +CONST SEGMENT BYTE PUBLIC + EXTRN BIOSNamesTable:byte, DOSNamesTable:byte + EXTRN SourceBIOSFile:byte, SourceDOSFile:byte +CONST ENDS + +cstack segment stack + db 278 + 80h dup (?) ; 278 == IBM's ROM requirements +cstack ends + +DATA SEGMENT BYTE PUBLIC + +DG GROUP CODE,DATA,CONST,cstack + + EXTRN BADDRV_ptr:byte, BADPARM_ptr:byte, GETSYS_ptr:byte + EXTRN SYSDRV:byte, NODEST_ptr:byte, BADSIZ_ptr:byte, DONE_ptr:byte + EXTRN BADVER:byte, Crlf_ptr:byte, NoSYS_PTR:byte, GetTarg_ptr:byte + EXTRN TargDrv:byte + + EXTRN NotNetM_ptr:byte + + +DEFALT DB 0 + + IF IBMCOPYRIGHT +BIOSName DB "A:\IBMBIO.COM",0 +DOSName DB "A:\IBMDOS.COM",0 + +SourceBIOSName DB "A:\IBMBIO.COM",0 +SourceDOSName DB "A:\IBMDOS.COM",0 + ELSE +BIOSName DB "A:\IO.SYS",0 +DOSName DB "A:\MSDOS.SYS",0 + +SourceBIOSName DB "A:\IO.SYS",0 +SourceDOSName DB "A:\MSDOS.SYS",0 + ENDIF + +IBMBIO_LOW DW 0 ;length of IBMBIO on disk +IBMBIO_HIGH DW 0 +IBMDOS_LOW DW 0 ;length of old IBMDOS on disk +IBMDOS_HIGH DW 0 + +SIZE_OLD_HIGH DW 0 +SIZE_OLD_LOW DW 0 + +NEWBIO_SIZE_LOW DW 0 +NEWBIO_SIZE_HIGH DW 0 +NEWDOS_SIZE_LOW DW 0 +NEWDOS_SIZE_HIGH DW 0 + + +Need_Clusters dw 0 +Bytes_Per_Cluster dw 0 +Number_Free_Clusters dw 0 + + +;*** WARNING *** +; KEEP THE FOLLOWING ITEMS IN THE EXACT ORDER BELOW!!! +DOSEntFree DB 1 +BIOSEntFree DB 1 + +BIOSInFH DW ? ; file handle of source BIOS +BIOSLenLow DW 2 DUP (?) ; 32-bit length of BIOS +BIOSLenHigh DW 2 DUP (?) ; 32-bit length of BIOS +BIOSTime DW 2 DUP (?) ; place to store time of BIOS write +BIOSOutFH DW ? ; fh of BIOS destination + +DOSInFH DW ? ; file handle of source DOS +DOSLenLow DW 2 DUP (?) ; 32-bit length of DOS +DOSLenHigh DW 2 DUP (?) ; 32-bit length of DOS +DOSTime DW 2 DUP (?) ; place to store time of DOS write +DOSOutFH DW ? ; fh of DOS destination + + +AllName DB "A:\*.*",0 + +;****************************************** +;FCB SNOT + +fcb_copy db 32 dup(?) + + IF IBMCOPYRIGHT +FCBDOS DB "IBMDOS COM" +FCBBIO DB "IBMBIO COM" + ELSE +FCBDOS DB "MSDOS SYS" +FCBBIO DB "IO SYS" + ENDIF + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +DOSFile_Offset dw 0 ; Index for system file names in Tables + +DirEnt DB 80h DUP (?) +cbBuf DW ? ; number of bytes in buffer +pDOS DW ? ; offset of beginning of DOS in buffer +pDOSEnd DW ? ; offset of end of DOS in buffer + +BIOSEG EQU 70H ; STARTING LOCATION OF BIOS +BPBLEN EQU 19 + +BPB LABEL DWORD ; POINTER TO HARDFILE BPB + DW 0000 + DW BIOSEG + +public boot +BOOT DB 0,0,0 ; SKIP THE THREE BYTE JUMP + DB "MSDOS3.3" +SECSIZ DW 512 ; SECTOR SIZE +SECALL DB 1 ; SECTOS PER ALLOCATION UNIT +RESNUM DW 1 ; RESERVED SECTORS +FATNUM DB 2 ; NUMBER OF FATS +DIRNUM DW 64 ; NUMBER OF DIRECTORY ENTRIES +SECNUM DW 1*8*40 ; NUMBER OF SECTORS +FATID DB 0FEH +FATSIZE DW 1 +SECLIM DW 8 +HDLIM DW 1 +HIDDEN DW 0 +PHYDRV DB 0 + DB 510-($-boot) dup (?) + DB 55H,0AAH ; MAGIC WORD +REORG LABEL BYTE + ORG BOOT + INCLUDE ..\BOOT\BOOT.INC + ORG REORG +FATID_TABLE LABEL WORD + DW 0 ; F8 FIXED DISK + DW -2 ; F9 + DW -1 ; FA + DW -1 ; FB + DW OFFSET DG:BPB91 ; FC + DW OFFSET DG:BPB92 ; FD + DW OFFSET DG:BPB81 ; FE + DW OFFSET DG:BPB82 ; FF + +; BIOS PARAMETER BLOCKS FOR THE VARIOUS MEDIA + +BPB81 DB 1 + DW 1 + DB 2 + DW 64 + DW 1*8*40 + DB 0FEH + DW 1 + DW 8 + DW 1 + DW 0 + DB 0 + +BPB82 DB 2 + DW 1 + DB 2 + DW 112 + DW 2*8*40 + DB 0FFH + DW 1 + DW 8 + DW 2 + DW 0 + DB 0 + +BPB91 DB 1 + DW 1 + DB 2 + DW 64 + DW 1*9*40 + DB 0FCH + DW 2 + DW 9 + DW 1 + DW 0 + DB 0 + +BPB92 DB 2 + DW 1 + DB 2 + DW 112 + DW 2*9*40 + DB 0FDH + DW 2 + DW 9 + DW 2 + DW 0 + DB 0 + +BPB96T DB 1 ; mjb001 + DW 1 + DB 2 + DW 224 + DW 2*15*80 + DB 0f9H + DW 7 + DW 15 + DW 2 + DW 0 + DB 0 +BPBSIZ = $-BPB96T + +BPB325 DB 2 ; mjb001 + DW 1 + DB 2 + DW 70h +cSec325 DW 2*9*80 + DB 0f9H + DW 3 + DW 9 + DW 2 + DW 0 + DB 0 + + + +; +; Following structure used by Generic IOCTL call Get Device Parameters to get +; the BPB of a hard disk. It 'overflows' into area of BUF. +; +DeviceParameters a_DeviceParameters <0,DEV_HARDDISK> + +BUF LABEL BYTE ; beginning of area for file reads + +DATA ENDS + +CODE SEGMENT PUBLIC PARA + + ASSUME CS:DG,DS:NOTHING,ES:NOTHING,SS:CSTACK + +start: + JMP SHORT CheckVersion + + DW OFFSET DG:BOOT + +HEADER DB "SYS 3.30" + +CheckVersion: + PUSH AX ; save drive letter validity + MOV AH,GET_VERSION + INT 21H ; get dos version + + cmp ax,expected_version + jne gotbaddos + +; XCHG AH,AL ; Turn it around to AH.AL +; CMP AX,DOSVER_LOW ; is it too low? +; JNE GOTBADDOS ; yes, error + + pop ax +ASSUME DS:NOTHING,ES:NOTHING + push cs + pop es +ASSUME ES:DG + mov si,5ch + mov di,offset dg:fcb_copy + mov cx,32 + rep movsb + push cs + pop ds +ASSUME DS:DG + MOV DX,OFFSET DG:DirEnt + MOV AH,SET_DMA + INT 21h + jmp sys + +GOTBADDOS: + push cs + pop ds +ASSUME DS:DG + MOV DX,OFFSET DG:BADVER ; message to dump + mov ah,std_con_string_output + int 21h + push es + xor ax,ax + push ax + +foo proc far + ret ; Must use this method, version may be < 2.00 +foo endp + +ERR0: +ASSUME DS:DG,ES:DG + MOV DX,OFFSET DG:BADPARM_ptr ; no drive letter + JMP xerror + +ERR1: +ASSUME DS:DG,ES:DG + MOV DX,OFFSET DG:BADDRV_ptr ; drive letter invalid + JMP xerror + +; +; We do not have a disk that has an available system in the root. See if the +; media is removable and if so, ask the user for a replacement. If the media +; is not removable, then die gracefully. +; +ERR2: +ASSUME DS:DG,ES:DG + MOV AH,GET_DEFAULT_DRIVE ;Will find out the default drive + INT 21H ;Default now in AL + MOV BL,AL + INC BL ; A = 1 + Call IsRemovable + jnc DoPrompt + MOV DX,OFFSET DG:NoSys_PTR + PUSH DX + CALL PRINTF + MOV AX,4C01h + INT 21h +DoPrompt: + MOV AL,DEFALT ; get default drive number + ADD AL,'A'-1 ; turn into letter + MOV SYSDRV,AL + MOV DX,OFFSET DG:GETSYS_ptr + push dx + call printf + CALL GetKeystroke ; wait for him to type simething + XOR AL,AL ; valid drive spec now... +SYS: +ASSUME DS:DG,ES:DG + mov DOSEntFree,1 + mov BIOSEntFree,1 + CMP BYTE PTR fcb_copy+1," " ; Was file specified? + JNZ ERR0 ; yes, no files are allowed -> error + CMP AL,-1 ; Invalid drive spec? + JZ ERR1 ; yes, must have valid drive -> error + CMP BYTE PTR fcb_copy,0 ; No drive specified? + JZ ERR1 ; yes, cannot sys to default drive error + MOV AH,GET_DEFAULT_DRIVE ; Get default drive + INT 21H + INC AL ; turn from phys drive to logical drive + MOV DEFALT,AL ; save it for possible printing + CMP BYTE PTR fcb_copy,AL ; did he specify the default drive? + JZ ERR1 ; yes, default drive not allowed + +;------Code to quit if sys called on a drive across a net----------------------- +CheckNet: + MOV BL,BYTE PTR fcb_copy ; x = IOCTL (getdrive, Drive+1); + MOV AX,(IOCTL SHL 8) + 9 + INT 21H + JC NotNet + TEST DX,1200H ; if(x & 0x1000)(redirected or shared) + JZ NotNet + MOV DX,OFFSET DG:NotNetM_ptr ; Fatal ("Can't do over net"); + JMP xerror + +;-------Load up BIOS and DOS at this point --------------------------------- +NotNet: + MOV AL,DEFALT + ADD AL,'A'-1 ; turn into letter + MOV SourceBIOSName,AL ; twiddle source name + MOV SourceDOSName,AL ; twiddle source name + CLD + MOV DX,OFFSET DG:SourceBIOSName ; source name + MOV CX,7 + MOV AH,4Eh + INT 21h + JC ERR2J + MOV AX,WORD PTR DG:DIRENt+26 + MOV WORD PTR NEWBIO_SIZE_LOW,AX + MOV AX,WORD PTR DG:DIRENt+28 + MOV WORD PTR NEWBIO_SIZE_HIGH,AX + MOV DX,OFFSET DG:SourceBIOSName ; source name + MOV DI,OFFSET DG:BIOSInFH ; pointer to block of data + CALL OpenFile + JNC NotERR2 +ERR2J: + JMP Err2 ; not found, go and try again + +NotERR2: + MOV DX,OFFSET DG:SourceDOSName ; source name + MOV CX,7 + MOV AH,4Eh + INT 21h + JC ERR2J + MOV AX,WORD PTR DG:DIRENt+26 + MOV WORD PTR NEWDOS_SIZE_LOW,AX + MOV AX,WORD PTR DG:DIRENt+28 + MOV WORD PTR NEWDOS_SIZE_HIGH,AX + MOV DX,OFFSET DG:SourceDOSName ; source of DOS + MOV DI,OFFSET DG:DOSInFH ; pointer to block of data + CALL OpenFile ; Look for DOS + JC ERR2J ; not there, go ask for a system disk + MOV CX,SP ; get lowest available spot + SUB CX,0200h+(OFFSET DG:BUF); leave room for all sorts of things + MOV cbBuf,CX ; store length away + CALL FillMem ; load up memory with files + JC ERR2J ; Some kind of error reading system + + +CheckDest: +;------------Check for "valid" destination----------------------------------- + MOV AH,0Dh + INT 21h + MOV AL,BYTE PTR fcb_copy + DEC AL + MOV BX,OFFSET DG:buf ; Temp space + MOV DX,1 ; Sector 1 (first sec of FAT) + MOV CX,DX ; One sector + INT 25H ; Read Fat sector + POP AX ; Flags + JC PromptDest ; Issue prompt to insert Destination + ; disk + CMP BYTE PTR [BUF],0F8H + JAE OKFAT +;---------Treat 0F0H as a valid 'IBM' FAT ID byte-------------------------------- + cmp BYTE PTR [BUF],0F0H + je OKFAT + JMP ERR3 + + +PromptDest: + push ax + + mov al,Byte ptr fcb_copy ; Get destination ID + ADD AL,'A'-1 ; turn into letter + MOV TargDrv,AL + + MOV DX,OFFSET DG:GetTarg_ptr + push dx + call printf + + CALL GetKeystroke ; wait for him to type simething + + pop ax + jmp CheckDest + +;-------The Fat appears to be OK... See if DOS/Bios there----------------- + + + + +OKFAT: +; +;Set up drive letter in destignation filespecs +; + + MOV AL,BYTE PTR fcb_copy + ADD AL,'A'-1 ; convert to letter + MOV BIOSName,AL ; point names at destination drive + MOV DOSName,AL + +; +; Read in first sector of directory +; +; The reason that we do the direct read of the directory is the find first/next +; or search first/next do an exclusive search for volume labels. By using these +; calls, there is no way to determine if a volume label occupies the first +; location in the directory. Hence we get sleazy and read the directory directly +; (no pun intended) to get this info. While its in there, go ahead and grab the file +; sizes. -MT +; +GetDir: + MOV DL,Byte PTR fcb_copy + MOV AH,Get_DPB + PUSH DS + INT 21h + +; DS:BX point to DPB + + MOV DX,[BX.dpb_dir_sector] + POP DS + MOV AL,BYTE PTR fcb_copy + DEC AL + MOV BX,OFFSET DG:BUF ; Temp space + MOV CX,1 ; Sector 1 (first sec of FAT) + INT 25H ; Read Fat sector + POP AX ; Flags + JNC Skip + +; +;NOTE!!!! This next jump is actually a bug left over from the MS days - if the +;dir is not read successfully then the SYS should be canned at that point - +;however, up thru 3.20 this would just jump to the actual sys. To make things +; a little better I jump to an error - this needs to be DCR'd for a real error +; + + JMP Err3 +Skip: + +; +; Now see if the first two directory entries are available... First check +; for being free: +; + MOV SI,OFFSET DG:BUF + CMP BYTE PTR [SI],0 ; empty dir? + JE Get_Space ; yes, go check for conflicts + CLD + CMP BYTE PTR [SI],0E5h + JE SecondFree +; +; The first entry is not free. See if the BIOS is there +; + MOV DI,OFFSET DG:FCBBIO + MOV CX,11 + REP CMPSB + JNE Err3jj ; not BIOS + DEC BIOSEntFree + +; added by dcl 8/24/86 - most cases solution + + mov ax,0002 ; is ibmbio allocated the 1st cluster? + cmp ax,word ptr DG:BUF+26 ; that being cluster 2??? + JNE Err3jj ; not cluster 2 - error; go display + +; end added by dcl 8/24/86 + +; +; IBM change - MT 6/16/86 +; Get the size of the file for IBMBIO +; + MOV ax,word ptr DG:BUF+28 + MOV word ptr IBMBIO_Low,ax + MOV ax,word ptr DG:BUF+30 + MOV word ptr IBMBIO_High,ax + +; Check the second entry +; + SecondFree: + MOV SI,OFFSET DG:BUF+32 + CMP BYTE PTR [SI],0 ; empty dir? + JE Get_Space ; yes, go check for conflicts + CMP BYTE PTR [SI],0E5h ; how about second? + JE Get_Space +; +; This entry is not free. Check it for IBMDOS +; + MOV DI,OFFSET DG:FCBDOS + MOV CX,11 + REP CMPSB +Err3jj: JNZ Err3j1 ; not DOS + DEC DOSEntFree +; +; IBM change - MT 6/16/86 +; Get the file size for IBMDOS +; + MOV ax,word ptr DG:BUF+60 + MOV word ptr IBMDOS_Low,ax + MOV ax,word ptr DG:BUF+62 + MOV word ptr IBMDOS_High,ax + +; +; We now have the following: +; Whether or not there is a DOS/BIOS on the disk +; Whether or not the appropriate entry is free +; We are guaranteed that if the entry is free, then it has the correct file in + + +; +;IBM CHANGE - MT 6/16/86 +; +; Here we make some VERY IMPORTANT assumptions. +; +;1) If IBMBIO exists on the disk currently, we assume it is in the correct +; place, i.e. at the front of the data area and contiguous. +;2) The stub loader portion of IBMBIO is less than 2048 bytes long. This +; number comes about by assuming we will never overlay anything smaller +; than 1920 bytes (DOS 1.10 IBMBIO size). This can be expanded to 2048 if +; we also assume the smallest possible cluster length is 512 bytes. +; +; Therefore, if we have an empty disk or IBMBIO exists, then we have enough +; contiguous room to install the portion of IBMBIO that requires itself to +; be contiguous. + + +; +;IBM CHANGE - MT 6/16/86 +; +;See if enough free space for IBMBIO and IBMDOS +; + +GET_SPACE: + MOV AH,36H ;Get free space + MOV DL,byte ptr fcb_copy ;Get the drive letter + INT 21h + +;16 bit math okay here, no danger of overflow + + MUL CX ;Get bytes/cluster + ;Result left in AX + PUSH AX ;Save it for later + MOV Bytes_Per_Cluster,AX + MOV Number_Free_Clusters,BX + +;Low result in AX, High result in DX +;Get IBMBIO size + + MOV AX,IBMBIO_Low + MOV DX,IBMBIO_High + + CALL Get_Clusters + ADD Number_Free_Clusters,AX + +;Low result in AX, High result in DX +;Get IBMDOS size + + MOV AX,IBMDOS_Low + MOV DX,IBMDOS_High + CALL Get_Clusters + ADD Number_Free_Clusters,AX + + +;Find the total size of new DOS and BIOS + + MOV AX,NEWBIO_Size_Low + MOV DX,NEWBIO_Size_High + + CALL Get_Clusters + +Got_NEW_BIO_Clusters: + MOV Need_Clusters,AX + + MOV AX,NEWDOS_Size_Low + MOV DX,NEWDOS_Size_High + CALL Get_Clusters + ADD AX,Need_Clusters + +;Now see if there is enough room for all of it on the disk + + CMP AX,Number_Free_Clusters + JBE PUT_SYS + +ERR3J1: + JMP ERR3 + +;Go do the sys +PUT_SYS: + CMP BIOSEntFree,0 + JNE GetRidDOS + MOV DX,OFFSET DG:BIOSName ; who to change mode + MOV CX,0 ; undo attributes + MOV AX,(ChMod SHL 8) + 1 ; set the attributes + INT 21h + MOV DX,OFFSET DG:BIOSName + MOV AX,(UNLINK SHL 8) + INT 21H ; Delete BIOS file +GetRidDOS: + CMP DOSEntFree,0 + JNE CreateBIOS + MOV DX,OFFSET DG:DOSName ; who to change mode + MOV CX,0 ; undo attributes + MOV AX,(ChMod SHL 8) + 1 ; set the attributes + INT 21h + MOV DX,OFFSET DG:DOSName + MOV AX,(UNLINK SHL 8) + INT 21H ; Delete DOS file +CreateBIOS: + MOV DX,OFFSET DG:BIOSName ; destination of BIOS + MOV CX,7 ; fancy attributes + MOV AH,Creat ; make a new one + INT 21h + JC err3j2 + MOV BIOSOutFH,AX ; save handle + MOV DX,OFFSET DG:DOSName ; destination of DOS + MOV AH,Creat ; make a new one + INT 21h + JC err3j2 + MOV DOSOutFH,AX ; save handle + PUSH DS + MOV AH,GET_DPB + MOV DL,BYTE PTR fcb_copy ; Target drive + INT 21H + MOV [BX.dpb_next_free],0 ; Reset Allocation to start of disk + ; so BIOS goes in right place! + POP DS +Copy: + CALL DumpMem ; flush out memory + JC ERR3J2 ; Disk full or some other error + MOV AX,DOSLenHigh ; more DOS? + OR AX,DOSLenLow ; more low dos + OR AX,BIOSLenHigh ; more high BIOS + OR AX,BIOSLenLow ; more low BIOS + JZ AllDone ; nope, all done + CALL FillMem ; reload world + JNC Copy + JMP ERR2 ; Start over again + +ERR3J2: + JMP ERR3 + +ERR4: + MOV DX,OFFSET DG:BADSIZ_ptr + JMP xerror + +AllDone: + MOV CX,BIOSTime ; get time and date + MOV DX,BIOSTime+2 + MOV BX,BIOSOutFH ; where to stuff the time + MOV AX,(File_Times SHL 8) + 1 + INT 21h + MOV AH,Close + INT 21h + MOV CX,DOSTime ; get time and date + MOV DX,DOSTime+2 + MOV BX,DOSOutFH ; where to stuff the time + MOV AX,(File_Times SHL 8) + 1 + INT 21h + MOV AH,Close + INT 21h + + CALL PUTBOOT ; copy the boot sector also + + MOV DX,OFFSET DG:DONE_ptr ; all finished message + push dx + call printf + XOR AL,AL ; ok error code + jmp short rexit + +xerror: + push dx + call printf + mov dx,offset dg:crlf_ptr + push dx + call printf + mov al,0ffh +rexit: + MOV AH,EXIT ; bye and return error code + INT 21h + +POPRET: + POP CX +SETERR: + STC + return + + +Get_Clusters: +;Round up to the next cluster size + + MOV BX,Bytes_Per_Cluster ;Bytes/cluster + DIV BX ;If there is a remainder in DX, then + ;we have another cluster to round up + CMP DX,0 + JE Got_CLUSTERS + INC AX ;Round up to next cluster +Got_Clusters: + RET + + +FillMem: + MOV CX,cbBuf ; get length of buffer + MOV BX,BIOSInFH ; get bios source handle + MOV DX,OFFSET DG:BUF+512 ; point to beginning of buffer + ; past area to read in boot rec + PUSH CX ; save away total length + CMP BIOSLenHigh,0 ; > 64K to read? + JA UseCX ; use CX + CMP BIOSLenLow,CX ; more left to read? + JA UseCX ; use CX + MOV CX,BIOSLenLow ; move new +UseCX: + MOV AH,Read + INT 21h ; read in what we can + JC POPRET ; Error + CMP AX,CX ; Did we get it all? + JNZ POPRET ; No, error + ADD DX,AX ; update pointer for DOS Read + MOV pDOS,DX ; point to beginning of DOS + SUB BIOSLenLow,AX ; decrement remaining + SBB BIOSLenHigh,0 ; do 32 bit + POP CX ; get original length + SUB CX,AX ; this much is left + MOV BX,DOSInFH ; get bios source handle + CMP DOSLenHigh,0 ; > 64K to read? + JA UseCXDOS ; use CX + CMP DOSLenLow,CX ; more left to read? + JA UseCXDOS ; use CX + MOV CX,DOSLenLow ; move new +UseCXDOS: + MOV AH,Read + INT 21h ; read in what we can + retc ; error + CMP AX,CX + JNZ SETERR ; Didn't read it all + ADD DX,AX ; update pointer for DOS Read + MOV pDOSEnd,DX ; point to End of dos DOS + SUB DOSLenLow,AX ; decrement remaining + SBB DOSLenHigh,0 ; do 32 bit arithmetic + CLC + return + +OpenFile: + MOV AX,(OPEN SHL 8) + 0 ; open for reading only + INT 21H ; Look for BIOS + retc ; not found, go and try again + STOSW ; stash away handle + MOV BX,AX ; get ready for seeks + MOV AX,(LSeek SHL 8) + 2 ; seek relative to eof + XOR CX,CX ; zero offset + XOR DX,DX ; zero offset + INT 21h ; get offsets + STOSW ; save low part of size + STOSW ; save low part of size + MOV AX,DX + STOSW ; save high part of size + STOSW ; save high part of size + XOR DX,DX ; zero offset + MOV AX,(LSeek SHL 8) + 0 ; seek relative to beginning + INT 21h + MOV AX,(File_Times SHL 8) + 0 + INT 21h ; get last write times + MOV AX,CX + STOSW ; save time + MOV AX,DX + STOSW ; save date + return + +ERR3: + MOV DX,OFFSET DG:NODEST_ptr + JMP xerror + +DumpMem: + MOV DX,OFFSET DG:BUF+512 ; get offset of bios start + MOV CX,pDOS ; beginning of next guy + SUB CX,DX ; difference is length + JZ DumpDos ; no bios to move + MOV BX,BIOSOutFH ; where to output + MOV AH,Write + INT 21h ; wham + retc ; error + CMP AX,CX ; Did it work? + JNZ WRERR ; No +DumpDos: + MOV DX,pDOS ; beginning of dos + MOV CX,pDOSEnd ; end of dos + SUB CX,DX ; difference is length + retz ; if zero no write + MOV BX,DOSOutFH ; where to output + MOV AH,Write + INT 21h ; wham + retc ; error + CMP AX,CX ; Did it work? + retz ; Yes, carry clear +WRERR: + STC + return + + + +; +; Output a boot sector apporpriate to the supposed version of DOS. We do this +; by reading in the boot sector for the drive and getting the BPB from there. +; This works fine until we get a 1.x diskette, when we have to grab the media +; descriptor byte and select the correct BPB using that. +; +public putboot +PUTBOOT: + mov ax,dg ; initialize DS. + mov ds,ax + mov al,byte ptr fcb_copy ; target drive 1-based + dec al ; convert to 0-based + mov dx,0000H ; get relative sector 0 + call Read_Sec + jc Do_Media_Byte + cmp word ptr DG:[Buf+1FEH], 0AA55H ; Is it a 1.x disk? + jnz Do_Media_Byte +PB0: + mov si,(offset DG:Buf)+13 ; Set up SI to point to 'SECALL' in + ; the BPB just read in. + jmp PB7 +; +; We were unable to use the BPB in the boot sector, so we must now get a +; valid BPB by examining the media descriptor byte. +; +Do_Media_Byte: + MOV AH,GET_DPB + MOV DL,BYTE PTR fcb_copy ; Target drive + INT 21H + MOV AL,[BX.dpb_media] ; Media byte + PUSH CS + POP DS + SUB AL,0F8H + CBW + MOV BX,AX ; BX has offset into bpb table + SHL BX,1 ; Word table, mult by 2 + MOV SI,[BX+FATID_TABLE] ; get pointer to bpb + OR SI,SI ; hardfile? + JNZ PB3 ; nope. + +; +; We have a hard drive. We can use the IOCTL Get Device Parameters to get the +; BPB for the hard drive. +; + mov bl,byte ptr fcb_copy ; Drive number + mov dx,offset DeviceParameters + mov ah,IOCTL + mov al,GENERIC_IOCTL + mov ch,RAWIO + mov cl,Get_Device_Parameters + int 21H + mov bx,dx ; ds:bx-> DeviceParameters + lea si,byte ptr [bx].DP_BPB ; SI -> BPB returned + inc si + inc si ; si-> secall in BPB + +PB3: CMP SI,-1 ; weird internal error? + JZ PB9 + CMP SI,-2 ; new multi-value FAT ID? + JNZ PB7 ; nope. +; +; We may have a FAT ID of F9. This may represent TWO different media in two +; incompatible drives. We do a get free space to determine which. +; + MOV AH,Get_Drive_freespace + MOV DL,BYTE PTR FCB_copy + INT 21h + MOV BX,DX + MUL BX ; compute total sectors + CMP AX,cSec325 + MOV SI,OFFSET DG:BPB325 + JB PB7 + MOV SI,OFFSET DG:BPB96T + +PB7: PUSH DS ; COPY IN THE NEW STUFF + POP ES + MOV DI,OFFSET DG:SECALL + MOV CX,BPBSIZ + CLD + REP MOVSB + +PB8: + cmp dg:FATID,0F8H ; Hard drive? + jnz not_hard +; NOTE: +; The physical hard drive number is placed in the third byte from the end in the +; boot sector in DOS 3.2. This is a change from the previous DOS versions. +; + mov byte ptr dg:[boot+1FDH],80H ; set physical hard drive number +not_hard: + MOV AL,BYTE PTR fcb_copy + DEC AL + MOV BX,OFFSET DG:BOOT ; Boot sector + XOR DX,DX ; Sector 0 + MOV CX,DX + INC CX ; One sector + INT 26H ; Write out 8 sector boot sector + jnc pb9 +PB9: POP AX ; Flags + RET + +; +; Read_Sec reads the sector and track specified in DX from the drive in AL. +; The sector is read into location Buf. Carry set if error. +; + +READ_SEC: + push ax ; save registers + mov cx,0001H + mov bx,Offset DG:Buf ; temp. buffer + int 25H + pop ax ; Pop flags pushed by Int 25 +Read_Ret: + pop ax + ret + + + +GetKeystroke: + MOV AX,(Std_CON_Input_Flush SHL 8) + Std_CON_Input_No_Echo + INT 21H + MOV AX,(Std_CON_Input_Flush SHL 8) + 0 + INT 21H + mov dx,offset dg:crlf_ptr + push dx + call printf + return + +; +; Determine if the drive indicated in BX is removable or not. +; +; Inputs: BX has drive (0=default, 1=A) +; Outputs: Carry clear => removable +; Carry set => non-removable +; +; Registers modified: none +; +IsRemovable: + SaveReg + mov AX,(IOCTL SHL 8) OR 8 ; do a media check + INT 21H + jnc CheckRemove + MOV AX,(IOCTL SHL 8) OR 9 ; Is it a net drive + INT 21H + jc NotRemove ; Yipe! Say non-removable + TEST DX,1000H + jnz NotRemove ; Is NET drive. Say non-removable. + JMP IsRemove +CheckRemove: + TEST ax,1 + jnz NotRemove +IsRemove: + CLC + RestoreReg + return +NotRemove: + STC + RestoreReg + return + +; +; Moves the name at the current locations in the system file name tables into +; the relevant system variables for later use. +; Preserves all registers (except flags). +; +MoveNames: + push bx + push cx + push di + push si + cld + mov bx,word ptr DOSFile_Offset + mov si,offset DG:BIOSNamesTable + add si,bx + mov di,offset DG:BIOSName + add di,3 ; skip over drive,colon,back-slash + mov cx,11 + repe movsb + mov si,offset DG:DOSNamesTable + add si,bx + mov di,offset DG:DOSName + add di,3 ; skip over drive,colon,back-slash + mov cx,11 + repe movsb + pop si + pop di + pop cx + pop bx + ret + +; +; Set up filename in FCB variables for searching directory entries. +; +SetUpFCB: + push si + push di + push bx + mov si,offset DG:BIOSNamesTable + mov bx,word ptr DOSFile_Offset + add si,bx + mov di,offset DG:FCBBIO + call MoveToFCB + mov si,offset DG:DOSNamesTable + mov bx,word ptr DOSFile_Offset + add si,bx + mov di,offset DG:FCBDOS + call MoveToFCB + pop bx + pop di + pop si + ret + +; +; Move ASCIZ filename to FCB-type filename from [SI] to [DI]. +; +MoveToFCB: + xor cx,cx +NextChar: + lodsb + cmp al,'.' + jz Fill_Blanks + stosb + inc cx + jmp short NextChar + +Fill_Blanks: + mov al,' ' + cmp cx,8 + jge See_Ext + stosb + inc cx + jmp short Fill_Blanks + +See_Ext: + mov cx,3 +Next_Ext: + lodsb + stosb + dec cx + jnz Next_Ext + RET + +; +; Gets source file names from SourceBIOSFile and SourceDOSFile and puts them +; into the ASCIZ strings SourceBIOSName and SourceDOSName. +; +GetSourceNames: + push si + push di + push cx + mov si,offset DG:SourceBIOSFile + mov di,offset DG:SourceBIOSName + add di,3 ; skip over drive,colon,back-slash + mov cx,12 + repe movsb + mov si,offset DG:SourceDOSFile + mov di,offset DG:SourceDOSName + add di,3 ; skip over drive,colon,back-slash + mov cx,12 + repe movsb + pop cx + pop di + pop si + ret + + + +CODE ENDS + END START + \ No newline at end of file diff --git a/SRC/CMD/SYS/SYS.LNK b/SRC/CMD/SYS/SYS.LNK new file mode 100644 index 0000000..efdb89b --- /dev/null +++ b/SRC/CMD/SYS/SYS.LNK @@ -0,0 +1,3 @@ +SYS messages+ +..\..\libc\PRINTF +SYS.EXE /m; diff --git a/SRC/DOS/ABORT.OBJ b/SRC/DOS/ABORT.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..8f8a0b387d4df00bc2396509519bf6097c32f167 GIT binary patch literal 452 zcmYL`y-QnR6o-H3=DzpCN)m%yanMpIL69OU4OFmjKaJJq#{0ew#UY3vIMfD`IF<@_ z(kLB@h-8R=frE>5>Cg+AT!qrjF48WggX{H;O1qr%9L_n<8P4`2m|n;$wi8C;^soS^ zZs_^U4NF{@chN2hu6nkx4LLXyg^Oi%-sXaFVMl@q+nM+O9_bhX41-1_6{RFaefPu| zrSH3@N%<~qLQ$wAX#>!8`gNR!mQbQ3sYFd!qPa~6J?>Vmw)U=3_8e%hc+rl0=;bJM zE3+Q7`g$X99T+lKmRDD6&_!{U^FTmfSkI#qtF2<5!xf;LhuD(`(4(z|z3MaC7;g4^zd`EhB zI?u2EO#a~KtpR)_i;OsvBPENt-y$`BVo~aAvlk{0f?9Qx2PMq4pMiPZD@%3ymfx91 pWAL9d^FU({cK7$?Su1-dHsg$x#e){7%g5T57tTkqPj^K)3JqNaz2ZQ4qepw&ug(kdH!p;4ST^=?p`Ml#0THX$LY zcGoEgAw{r)xLH|7l@K5wj4CdiBEbQ;G)-0<3I{52NK#ZTNCgZzAn{iYX5QMCsvbNu ze)GNgX1@2{u10{W>2xM3zOMj;lbMu8lbK1~5Cf}D8hSXT8mf@W=r3e5(^KKJsvA@{ z)T}`bbu_L0@j(Oz00e;yU~~?PaHP8#QA!fctSAzhMPHCmh`fQ(96%&Oe*Gu`e1kMX z4XzPx&<3CMUWAysxVT)HFrB&O%Mi_5=2AX4XXY=1IBMFC%Kk$%S+p>4rc$HOp!!1_}jM0{~yUQckK5;XFS_*%UF;AXWKd@7NUD|8Wh z4BSKL4ud-qxGgURf>yBRoeA?*7_XfII?MVvxw-z2atqsP{ia&|Sv}Yu5;;d1bAole zf8l<009+yw!51aM`*DeIez!y-zQkw`G-;0qd`~mJbek_#6M=e+ZzFP~$_GWnFTDiB z^ox2fs~I^|5boAGfxZX7U^j1{1%Tqhf7Mukjru$ie(QBZ;;QN7ineLxY$sn>fVXO2 z0j;vimrAoCMj+H5qO*Qr`pgX7T?wt<%MR^c-)hyQir3dBa1y*y<^kkE#70(HDVDF_ zRLbaBjpN^VdydB4D{qaxyIVg}QC6`xa{b2uVA02MJL}&$z1%h)-dL#*52l3MKbv^x zpuBcaW~W@S<<{ zBtrZZ26>YuK9xw={Txf2^5PI}OPU#n-r6fbvji1IHoSb^<~a;(4j0NhOr^irgy)BL zS3Y?HV?~3G5mUc|W<$jMFtIwE9_4FPjBb$n?@A5exu5C}lr^T<-=*sLV44m$j90{s zH?KnvIuG2Zg4x_>&{e@5V1Q?vfFU;e2s4^QqW+XbsDF{o_c9u@asUYJX}-cMmTBg$ zS<3~}w()xGR=P3QdZA0^YtCVO)D;QWItz1VVIgPFUtP*OMaw(}@LQ!56GC!1zi8S8 z^EAMtN*q`C{^0X73$WNM*B?Cp%r(>ckU&>+SAR+iP_GlXQ|ZE8V!y5#qxj;-r}6FH I2mv_%13P<55C8xG literal 0 HcmV?d00001 diff --git a/SRC/DOS/ARENA.INC b/SRC/DOS/ARENA.INC new file mode 100644 index 0000000..42b0b3f --- /dev/null +++ b/SRC/DOS/ARENA.INC @@ -0,0 +1,27 @@ +; SCCSID = @(#)arena.asm 1.1 85/04/09 +BREAK + +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +; +; arena item +; +arena STRUC +arena_signature DB ? ; 4D for valid item, 5A for last item +arena_owner DW ? ; owner of arena item +arena_size DW ? ; size in paragraphs of item +arena ENDS + +; +; CAUTION: The routines in ALLOC.ASM rely on the fact that arena_signature +; and arena_owner_system are all equal to zero and are contained in DI. Change +; them and change ALLOC.ASM. + +arena_owner_system EQU 0 ; free block indication + +arena_signature_normal EQU 4Dh ; valid signature, not end of arena +arena_signature_end EQU 5Ah ; valid signature, last block in arena +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; diff --git a/SRC/DOS/BPB.INC b/SRC/DOS/BPB.INC new file mode 100644 index 0000000..867a380 --- /dev/null +++ b/SRC/DOS/BPB.INC @@ -0,0 +1,39 @@ +; SCCSID = @(#)BPB.ASM 1.1 85/04/29 +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + +; BIOS PARAMETER BLOCK DEFINITION +; THIS STRUCTURE IS USED TO BUILD A FULL DPB + +BPBLOCK STRUC +BPSECSZ DW ? ; SIZE IN BYTES OF PHYSICAL SECTOR +BPCLUS DB ? ; SECTORS/ALLOC UNIT +BPRES DW ? ; NUMBER OF RESERVED SECTORS +BPFTCNT DB ? ; NUMBER OF FATS +BPDRCNT DW ? ; NUMBER OF DIRECTORY ENTRIES +BPSCCNT DW ? ; TOTAL NUMBER OF SECTORS +BPMEDIA DB ? ; MEDIA DESCRIPTOR BYTE +BPFTSEC DW ? ; NUMBER OF SECTORS TAKEN UP BY ONE FAT +BPBLOCK ENDS + +A_BPB STRUC +BPB_BYTESPERSECTOR DW ? +BPB_SECTORSPERCLUSTER DB ? +BPB_RESERVEDSECTORS DW ? +BPB_NUMBEROFFATS DB ? +BPB_ROOTENTRIES DW ? +BPB_TOTALSECTORS DW ? +BPB_MEDIADESCRIPTOR DB ? +BPB_SECTORSPERFAT DW ? +BPB_SECTORSPERTRACK DW ? +BPB_HEADS DW ? +BPB_HIDDENSECTORS DW ? + DW ? +BPB_BIGTOTALSECTORS DW ? + DW ? + DB 6 DUP(?) +A_BPB ENDS +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; diff --git a/SRC/DOS/BUF.OBJ b/SRC/DOS/BUF.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..caf26ee63c297e78e504af3d9d922296e1defe6b GIT binary patch literal 1364 zcmY+ET}&KR6vxkUj=K6#>U#UXwvJM8Hn*=&Ybz* zbI<+X-<_EP2fn^^eECWQfQ=5vWG*^9q-p^-N<*5;#w1Ph$A;B@WjLK;lai`&swOEK zr%8QD`H!~+I1J$Tlf#%Lu!)Z}c^Su%25&SFAYmu#V;F|q$Lt({Adq|SGyqQtWvGv` zl%ssql0cA>$>EF~1Am`6HI>Nc&H^7bb$kFJE)67QMS);4H)lA*c^!n5o>!bIE|ZdV z9Wv!!-~b}k=K)fy-?z(LwRfIUvzB$G3g*V&HJNKSxm1W`E7jiZUwQlZF93Yo;$xxm z<4QBwK9MlCh@tpQBjLK>HLD(ibGcXZlNV?8>9cUCJO(J^B)fiohZ=)cwN;2zks(TE zC{k)b2c@S0wp*-?#qX-e9Qonpjl~D0P-&X+wE4%>(Ml(+ekQ!mQ5s&C8A?}Io`NC~ ziQjH=478wuTVNk_9JMzShJj*-D_yl3pQP1 zI20}&4_gyVq=a}P77y@0f9nFJ>-}iLnc4G~`Ok=AeQSNz^X2$hb9I_6@ zP*0jSg>IQOnQhaB>j)eQ#)!xKcUK)%(meJPCdNY;%Pb-d!}fX8D1ODY6s;p?n9pgj)gQlc)9W zQkpN#1T8t_Y`rA2YXs1+AD{4=+ESg#*LP& z$L5~cR=_bZNoA+9F0&N2x1P(h#)Ix33?3OiGVkJBddj$+q9%(SvN~Vb{1gpjD{Bz^wl?(XY~M-W#R*qzP9$AJB8GvV-dLL@$0a<~pUNQbcI2C*|D5$u;m!WNf2#_v1A z7a}3{O$=XI0pMd9Wk8eRO8Fpg9SmA;8-Fo7HmQ?--#0(qsiP*@nXHWNvJZW@v=0d9 zeC!$hypi7`ATKqc5{xF~=wLjVRueY}ta?@PX>;xzmcB{gJx}SEHT-?Wl}&&rml|6 literal 0 HcmV?d00001 diff --git a/SRC/DOS/BUFFER.INC b/SRC/DOS/BUFFER.INC new file mode 100644 index 0000000..af7b422 --- /dev/null +++ b/SRC/DOS/BUFFER.INC @@ -0,0 +1,61 @@ +; SCCSID = @(#)buffer.asm 1.1 85/04/09 +BREAK +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; + +; Field definition for I/O buffer information + +BUFFINFO STRUC +buf_link DD ? ; Pointer to next buffer in list +buf_ID DB ? ; Drive of buffer (bit 7 = 0) + ; SFT table index (bit 7 = 1) + ; = FFH if buffer free +buf_flags DB ? ; Bit 7 = 1 if Remote file buffer + ; = 0 if Local device buffer + ; Bit 6 = 1 if buffer dirty + ; Bit 5 = Reserved + ; Bit 4 = Search bit (bit 7 = 1) + ; Bit 3 = 1 if buffer is DATA + ; Bit 2 = 1 if buffer is DIR + ; Bit 1 = 1 if buffer is FAT + ; Bit 0 = Reserved +buf_sector DW ? ; Sector number of buffer (bit 7 = 0) +; The next two items are often refed as a word (bit 7 = 0) +buf_wrtcnt DB ? ; For FAT sectors, # times sector written out +buf_wrtcntinc DB ? ; " " " , # sectors between each write +buf_DPB DD ? ; Pointer to drive parameters +buf_fill DW ? ; How full buffer is (bit 7 = 1) +BUFFINFO ENDS + +buf_offset EQU DWORD PTR buf_sector + ;For bit 7 = 1, this is the byte + ;offset of the start of the buffer in + ;the file pointed to by buf_ID. Thus + ;the buffer starts at location + ;buf_offset in the file and contains + ;buf_fill bytes. + +BUFINSIZ EQU SIZE BUFFINFO + ; Size of structure in bytes + +buf_Free EQU 0FFh ; buf_id of free buffer + +;Flag byte masks +buf_isnet EQU 10000000B +buf_dirty EQU 01000000B +;*** +buf_visit EQU 00100000B +;*** +buf_snbuf EQU 00010000B + +buf_isDATA EQU 00001000B +buf_isDIR EQU 00000100B +buf_isFAT EQU 00000010B +buf_type_0 EQU 11110001B ; AND sets type to "none" + +buf_NetID EQU BUFINSIZ + +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; diff --git a/SRC/DOS/CLOSE.OBJ b/SRC/DOS/CLOSE.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..4000a1d70e53047a265481a004538fd4798551e9 GIT binary patch literal 1157 zcmYLJU5Fc16h3z{cP8mo&6cDSW+t1p+J@L2*kHH2 zPA2|=5Ft>SNnszPN}0+aB8V?rvAFbUVM5y%K@faX`y%-Jpat8$81J177B2Ukx%WH& z-`t)6DOER{N<}xdYnO`vtfH$LR`ipmm5O%xq-C!1L(0E7QP@(U=)0#_Sl6 zIc0bnc)3#18=4B7?7B|-HQSrSd(|wkB z8RbR9B!)APskYp+8Pt6c9 z=c#ETM5(9a~ptyHO-WjbXh$N>JBBAPsD7P{|$8Uu6JhFM6f_M1)R+*ZeK(#d`pWC4Fp z(N|ygSGo!5V)~01KC?>)S^0mE-v>_uz8*nCU-EFdi^|dkd^Nnu0We%c^6HNpN8%C= zj%G!~eoebxk}X4%)hOH?CBt`7`p(lw_NnFE?bu{?bU;KXq{S?27Ad7Amdk{6Fi3#Qm_zhYtx!X!2J~OPGjg;0J{SEQ&wTRtryiZq@XC)12)teJ5>2w^79q&9KmV4DU+ zDQQ5Wf(V&bs%V73ihwQw!Gi1&5=$ghB%}%ii;5r+qAXx#?(>@@v@1sP=)E)N+#_8B_+T1^eA`B6_N4~uS!67x3aOCLZYp-som9%wd3uC z*6IZTZGPhL)^>vuh(p1{{8Iq_C0Ys45Op0)wT3{q5tMy5J@>BkqsJ)L$_>3-pTkul zIKV~^yqmz67*dpFL9n(6R|MfcCfpMd=XixLxzOqctx*c`)>;a5nYOL1uJj?P z8{?*v&Sx+nqWh#1v54XQ=(zDS&D{X?sg+8#m<=1H>daokugw&L-Ku3d6NX+O{L$RW zKuuNsbm&D(PH$iSWAQXslwds(y|z7I7HL8v09wjph!vlN1~`J>{P! zoZdz}&Gy;O*=;0mn?9?~Y$M~Qo_(3Hvh9lzcj7g|@V2i>RcFgTH3!&NLQ~zG6foWWPP6SyF8^{ zp3!{Q(gMO#UXRaMv1TbHDJW7?=|_#YE&87U*4FYK-n=caSF60-fz z2@n1kak3u}%*d0FdH#olW$DS7pUH+NpCo)O?HaXOwU({UghvQ(Nho}w+$a#n2Gnx2y!WVZ z(y94bb-G$>l;=;JBpjFFXH?T-$K3RP$=k@3Yf)qPgp>?!*5g78dDvZ(B2%{v)AlQ( zF#9=(xG8FCmxAv$w>++S?p&5~(-EDuLRgPJJKRB+2>#}0m#>2N|7`9>_q-=sw^Q|| z<9UYGB3$2;b5pDmEO{s^h~k|jEXnx9e}rNCPZ55UlB{FbrNNx*Xa!T}DS1s=sLwWn=?b^P4>AaEAt;8KN^oMD@TN4{ z`H$ju-KlWvbq15S7%UXj%3| + +; +; Field definition for FCBs +; The FCB has the following structure: +; +; +---------------------------+ +; | Drive indicator(byte) | +; +---------------------------+ +; | Filename (8 chars) | +; +---------------------------+ +; | Extension (3 chars) | +; +---------------------------+ +; | Current Extent(word) | +; +---------------------------+ +; | Record size (word) | +; +---------------------------+ +; | File Size (2 words) | +; +---------------------------+ +; | Date of write | +; +---------------------------+ +; | Time of write | +; +---------------------------+ +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +; +---------------------------+ +; | 8 bytes reserved | +; +---------------------------+ +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; | next record number | +; +---------------------------+ +; | random record number | +; +---------------------------+ +; + +sys_fcb STRUC +fcb_drive DB ? +fcb_name DB 8 DUP (?) +fcb_ext DB 3 DUP (?) +fcb_EXTENT DW ? +fcb_RECSIZ DW ? ; Size of record (user settable) +fcb_FILSIZ DW ? ; Size of file in bytes; used with the + ; following word +fcb_DRVBP DW ? ; BP for SEARCH FIRST and SEARCH NEXT +fcb_FDATE DW ? ; Date of last writing +fcb_FTIME DW ? ; Time of last writing +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +fcb_reserved DB 8 DUP (?) ; RESERVED +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +fcb_NR DB ? ; Next record +fcb_RR DB 4 DUP (?) ; Random record +sys_fcb ENDS + +FILDIRENT = fcb_FILSIZ ; Used only by SEARCH FIRST and SEARCH + ; NEXT + +fcb_sfn EQU BYTE PTR fcb_reserved + +; Note that fcb_net_handle, fcb_nsl_drive, fcb_nsld_drive and fcb_l_drive +; all must point to the same byte. Otherwise, the FCBRegen will fail. +; NOTE about this byte (fcb_nsl_drive) +; The high two bits of this byte are used as follows to indicate the FCB type +; 00 means a local file or device with sharing loaded +; 10 means a remote (network) file +; 01 means a local file with no sharing loaded +; 11 means a local device with no sharing loaded + +; +; Network FCB +; +fcb_net_drive EQU BYTE PTR fcb_reserved+1 +fcb_net_handle EQU WORD PTR fcb_reserved+2 +fcb_netID EQU DWORD PTR fcb_reserved+4 + +; +; No sharing local file FCB +; +fcb_nsl_drive EQU BYTE PTR fcb_reserved+1 +fcb_nsl_bits EQU BYTE PTR fcb_reserved+2 +fcb_nsl_firclus EQU WORD PTR fcb_reserved+3 +fcb_nsl_dirsec EQU WORD PTR fcb_reserved+5 +fcb_nsl_dirpos EQU BYTE PTR fcb_reserved+7 + +; +; No sharing local device FCB +; +fcb_nsld_drive EQU BYTE PTR fcb_reserved+1 +fcb_nsld_drvptr EQU DWORD PTR fcb_reserved+2 + +; +; Sharing local FCB +; +fcb_l_drive EQU BYTE PTR fcb_reserved+1 +fcb_l_firclus EQU WORD PTR fcb_reserved+2 +fcb_l_mfs EQU WORD PTR fcb_reserved+4 +fcb_l_attr EQU BYTE PTR fcb_reserved+6 + +; +; Bogusness: the four cases are: +; +; local file 00 +; local device 40 +; local sharing C0 +; network 80 +; +; Since sharing and network collide, we cannot use a test instruction for +; deciding whether a network or a share check in involved +; +FCBDEVICE EQU 040h +FCBNETWORK EQU 080h +FCBSHARE EQU 0C0h + +; FCBSPECIAL must be able to mask off both net and share +FCBSPECIAL EQU 080h +FCBMASK EQU 0C0h diff --git a/SRC/DOS/CPMIO.OBJ b/SRC/DOS/CPMIO.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..267c9a900566213820608834d8029d5c6febdcc2 GIT binary patch literal 2230 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 literal 0 HcmV?d00001 diff --git a/SRC/DOS/CREATE.OBJ b/SRC/DOS/CREATE.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..01f3dec122119495cf4697e6e4367a3a01c5df74 GIT binary patch literal 808 zcmY*XOK8+k6g@AKH_3D|zpB$J(iX*`JFAGFO(9J({Ww38*oq=?Xd^8xR%bFOxS8rK zqz*VJsK^wu?9zp3!Id<+QrziEaN)vFS8l|O@g*aI@OYe@cizdp_noGMKDBIEimu6~ zcJ;w=fLF?@MwN2OFk|5^mrR3KWm6WJa#Am!sqh8aFsWh6x=BrWqM-eFBw!Q}MKa3J z6f=pCOb<~?lEJBfSd0t@=pi_cY%sJ42m<-`IEkoFe9n*fyifh8(zYQga-lFgtrij0 z&YGI8L(;B0TCHZStj;&;h|U;`)f&^4Rt?)xmue8oSM19ZjY|*=*);X(2?*xYw4ta* z4;Xn9(rme)OqC|Bd_kVXj#~l+j(*;3Hl$6_;hu=n$Y#aq+oE_K1<3btZybnvY$&&W z`;C}T*&58eJ$!yU_fu8S6dbX#HP9p0iX4Ye-88&`EQxqSSrYROW{Ei0mJrkCYfG%g z`Z7Mc0_Y6B00+8Jv`Ci3pSR->i`8Yjw7Ov9f|~>_27-DrsKI~JjfXnP6SAc5RbW^6 zXZPMsfX)T#7r=*K+b{o$6CS^t@bBC>cmPzdMCi!Pc0W@2YTXIuWU2Ow?bujzhe0m} z1}?xxFc37HTR+s?k#FY^@P2n+`2VEGXNllRtS2waDrxOywP)H%#Pd~0x2p?QFzGw) zAn1+Y9$Q-+0y}>w{5sLy9~z}v%qZc-g9)Yj34ao;en#ZlDM*H9TI`*yB1<4PTnY3p zz5-7P+fH>8;r($-Z_ExZl~u_^^oL>5^)()SUy4t#g3$2Tx|r0RR91 literal 0 HcmV?d00001 diff --git a/SRC/DOS/CRIT.OBJ b/SRC/DOS/CRIT.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..802df964c4b7f46cfbb9ce7669600221fbb68b5d GIT binary patch literal 367 zcmYj}KTE?v7>9qC=JKaPt>U1YgGh03baS}oq84IPa#!e9p#%(Kg)});DOqWi zwbCwm=>)eMs0WvMo{o#2Y@^ +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +; CDS items are used bu the internal routines to store cluster numbers and ; +; network identifiers for each logical name. The ID field is used dually, ; +; both as net ID and for a cluster number for local devices. In the case ; +; of local devices, the cluster number will be -1 if there is a potential ; +; of the disk being changed or if the path must be recracked. The END ; +; field is the location of the end of the definition. No .. is allowed ; +; past this point ; + +DIRSTRLEN EQU 64+3 ; Max length in bytes of directory strings +TEMPLEN EQU DIRSTRLEN*2 + +curdir_list STRUC +curdir_text DB DIRSTRLEN DUP (?) ; text of assignment and curdir +curdir_flags DW ? ; various flags +curdir_devptr DD ? ; local pointer to DPB or net device +curdir_ID DW ? ; cluster of current dir (net ID) + DW ? +curdir_user_word DW ? +curdir_end DW ? ; end of assignment +curdir_list ENDS + +curdirLen EQU Size curdir_list ; Needed for screwed up + ; ASM87 which doesn't allow + ; Size directive as a macro + ; argument +curdir_netID EQU DWORD PTR curdir_ID + +;Flag word masks +curdir_isnet EQU 1000000000000000B +curdir_inuse EQU 0100000000000000B +curdir_splice EQU 0010000000000000B +curdir_local EQU 0001000000000000B +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; diff --git a/SRC/DOS/DELETE.OBJ b/SRC/DOS/DELETE.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..d046f8109256702acb1a478fb0ca953566fd809e GIT binary patch literal 1480 zcmZ8hZ)jUp6hHSR_r3gYnzXNTc8!~w)hbm~`lajYOY)M`WiKJ`rR^v*r0v6&)~uv2 zC?c5B;6@uy4yKg}PO4+Fc<*Z*A|&^o_wG5r z^EY2!%ag&eM-UD9JwCqR(98zwa=7}ByN3^6DjJe`Vz(;f0NG=XMB`u{=;EflSjP#;j z)CyAzIymAd%f*?Pz5x7->TIDz-zX?Kd_f~G(myh)Im-));T%QqIx$Qi4UlcZn zhcDRS&gbRsQ};K9`iILM8$-jxWuFP~Sm;QojIE4pLH>HkO50Abh-}0yqBbIl$VHBc z2$PJ6oP)JC@Fa92Q!r*NDWG8n0Z&^M1j`=RWy7(_!QDUVyoD4v&$y=^aR1)S11>S| z#- zh0}-ExQ7pkgG@S14p9Bbqs%%iB0G6XM5sFGM>vegae6dW zbAgbh9V@9aOqqVb*BH5yLKo5x@OM36p>qgG(1-xS+KEvww z8;98DFuF4Q7@?|!S0AtZDxIbpeOBLZ@#|tR0`bxE$UYId$srN>F4lbDj!RlrFU;gw zhh8zC1KfsaZFymwu8lo)Z9fChU(Z-Z9TkOvHJV}V&cItebi1+A;I`|1R*rpDnj=U& zG*LA`)hI%>lWtWY2U(-^29TYDH)~GdRil*Bi{Ld~fRD0tBeuIYThcuAF{@RbpIeL+ zrsv^==>QyKK8YJGkNqDpj|@Fk3NPzWFb@DuGLOj#$}iNUylV7sH9tJNeYO6GMekwa z4j{+#K-vPx%K-_B$V)l{h`Z9`C8ew^D>3LY2LLa#fWO!`pPU%a zhZ^-!HN(dBBEWfDGtZ4rOrCAj)eL*KThC`3ms_8-hw!vBNC(rlOGG?tVE%*kc0l+) z_beTrv2~HYYy0==%G3KwH}o?Ie)``*ZgHky=e42fzqaVj1ijB(*mB1sd; zP&`SKq293e=Z69u1`tJZ7_EK`Vkh2)MJaK!SsyqY#Lq03&1NH=XiWkL0(tbY8~8e@ z+v@f@SEqGeG2Q@&GCDo2re;IqAS$77IH5$6ARxeS5HZ(*XzySj@amaRXnY)}V!i#T z(Q)7hqHI0Tf#?}cWq;#Jf1GJ61j5516@=vE)C{^bj6`1&_@Pv~Z+Zesl_Nj_f`*J@ zjR*W$ia_vFfNhmRE_(r04l)xx<^5pVeZ*x0QQKo7z10LES8=Y`FMYWHUDADZRf{sFl8c7X29ODO*?`#>i$X)^cvh+qe^ zT_)le6&W}H*)2;=?mU;LbK;ycFXZX_6$PjUg?ok10Pg%&Tm<+U;8Fm`QGkWJxLdIJ zJZ8Rzi9ccdw6Kxep;^8Ha223{%l`T$w`DtBehy5|kJ&ptgyX@KWFnYeCR#8F8|ZBw zLa!0Cqmj}vnK;Z7tlE)V{8Tttc@}7iE$<;&9@Rs1%wc{zwKeBf=E;B8GZcrnTFY4h zWxo~2r*pWzndqYBc7Y|z+~OKi2P%_5e`GGM+bDu~lG#62+p57uBnt!T*h39r;BCqs z^Z38$2AIdOTi2SH$KzpnV!5bSr5a_*{d9TO%BNZ9t$Z5%^2@}gw=#b0m$A?TK0=Xy z0Uwc2JtY&#>}pW*L}TV8V`dLq`XXayAG({T8&eTP^|N?p<`4^d9)s$ypt!;+9+<(t zh@>)bxzY->n_x=WspDILZ4JpEFy9oio|nqJm7xDiMs;N}HTGI!ax|R+qw*@yKIW1c z3KUW#P>|5WhrS$$8HMjCZp*?qcpksTR;A_P{QYJ80&CcKG4u%(-?B5lX7+8X94hX5 zzQz@9TxYaEcG!n&H;2)z-pU9&*n+HCTFefa*!5@doR$bH$*aGNb+sFAaA{-dsSG|H zQ)4OcvmRVxi4|3zb##zjQm~GqsEQWA?3?8SR#=(!H8CY0A$YhxX76JHTar9vvBSG! zOO;bVzh|+l=g!8y;#Os=#^vGVSmDNU_qQwWtcg~sW~^9UF*a7t53jtta(V8~2zIRH zA_i?plG=A8;MFn raH5;Q=Oqadd{g@dBZ{>v=0$~smSiomP9WECLBMLYI)Qry8 MUST BE 1 +; 14 -> 1 IF THE DEVICE UNDERSTANDS IOCTL CONTROL STRINGS +; 13 -> 1 IF THE DEVICE SUPPORTS OUTPUT-UNTIL-BUSY +; 12 -> UNUSED +; 11 -> 1 IF THE DEVICE UNDERSTANDS OPEN/CLOSE +; 10 -> MUST BE 0 +; 9 -> MUST BE 0 +; 8 -> UNUSED +; 7 -> UNUSED +; 6 -> UNUSED +; 5 -> UNUSED +; 4 -> 1 IF DEVICE IS RECIPIENT OF INT 29H +; 3 -> 1 IF DEVICE IS CLOCK DEVICE +; 2 -> 1 IF DEVICE IS NULL DEVICE +; 1 -> 1 IF DEVICE IS CONSOLE OUTPUT +; 0 -> 1 IF DEVICE IS CONSOLE INPUT +; +; BLOCK DEVICES: +; +; BIT 15 -> MUST BE 0 +; 14 -> 1 IF THE DEVICE UNDERSTANDS IOCTL CONTROL STRINGS +; 13 -> 1 IF THE DEVICE DETERMINES MEDIA BY EXAMINING THE FAT ID BYTE. +; THIS REQUIRES THE FIRST SECTOR OF THE FAT TO *ALWAYS* RESIDE IN +; THE SAME PLACE. +; 12 -> UNUSED +; 11 -> 1 IF THE DEVICE UNDERSTANDS OPEN/CLOSE/REMOVABLE MEDIA +; 10 -> MUST BE 0 +; 9 -> MUST BE 0 +; 8 -> UNUSED +; 7 -> UNUSED +; 6 -> IF DEVICE HAS SUPPORT FOR GETMAP/SETMAP OF LOGICAL DRIVES. +; IF THE DEVICE UNDERSTANDS GENERIC IOCTL FUNCTION CALLS. +; 5 -> UNUSED +; 4 -> UNUSED +; 3 -> UNUSED +; 2 -> UNUSED +; 1 -> UNUSED +; 0 -> UNUSED +; + +DEVTYP EQU 8000H ; BIT 15 - 1 IF CHAR, 0 IF BLOCK +CHARDEV EQU 8000H +DEVIOCTL EQU 4000H ; BIT 14 - CONTROL MODE BIT +ISFATBYDEV EQU 2000H ; BIT 13 - DEVICE USES FAT ID BYTES, + ; COMP MEDIA. +OUTTILBUSY EQU 2000H ; OUTPUT UNTIL BUSY IS ENABLED +ISNET EQU 1000H ; BIT 12 - 1 IF A NET DEVICE, 0 IF + ; NOT. CURRENTLY BLOCK ONLY. +DEVOPCL EQU 0800H ; BIT 11 - 1 IF THIS DEVICE HAS + ; OPEN,CLOSE AND REMOVABLE MEDIA + ; ENTRY POINTS, 0 IF NOT + +EXTENTBIT EQU 0400H ; BIT 10 - CURRENTLY 0 ON ALL DEVS + ; THIS BIT IS RESERVED FOR FUTURE USE + ; TO EXTEND THE DEVICE HEADER BEYOND + ; ITS CURRENT FORM. + +; NOTE BIT 9 IS CURRENTLY USED ON IBM SYSTEMS TO INDICATE "DRIVE IS SHARED". +; SEE IOCTL FUNCTION 9. THIS USE IS NOT DOCUMENTED, IT IS USED BY SOME +; OF THE UTILITIES WHICH ARE SUPPOSED TO FAIL ON SHARED DRIVES ON SERVER +; MACHINES (FORMAT,CHKDSK,RECOVER,..). + +DEV320 EQU 0040H ;BIT 6 - FOR BLOCK DEVICES, THIS + ;DEVICE SUPPORTS SET/GET MAP OF + ;LOGICAL DRIVES, AND SUPPORTS + ;GENERIC IOCTL CALLS. + ;FOR CHARACTER DEVICES, THIS + ;DEVICE SUPPORTS GENERIC IOCTL. + ;THIS IS A DOS 3.2 DEVICE DRIVER. +ISSPEC EQU 0010H ;BIT 4 - THIS DEVICE IS SPECIAL +ISCLOCK EQU 0008H ;BIT 3 - THIS DEVICE IS THE CLOCK DEVICE. +ISNULL EQU 0004H ;BIT 2 - THIS DEVICE IS THE NULL DEVICE. +ISCOUT EQU 0002H ;BIT 1 - THIS DEVICE IS THE CONSOLE OUTPUT. +ISCIN EQU 0001H ;BIT 0 - THIS DEVICE IS THE CONSOLE INPUT. + +;STATIC REQUEST HEADER +SRHEAD STRUC +REQLEN DB ? ;LENGTH IN BYTES OF REQUEST BLOCK +REQUNIT DB ? ;DEVICE UNIT NUMBER +REQFUNC DB ? ;TYPE OF REQUEST +REQSTAT DW ? ;STATUS WORD + DB 8 DUP(?) ;RESERVED FOR QUEUE LINKS +SRHEAD ENDS + +;STATUS WORD MASKS +STERR EQU 8000H ;BIT 15 - ERROR +STBUI EQU 0200H ;BIT 9 - BUISY +STDON EQU 0100H ;BIT 8 - DONE +STECODE EQU 00FFH ;ERROR CODE + +;FUNCTION CODES +DEVINIT EQU 0 ;INITIALIZATION +DINITHL EQU 26 ;SIZE OF INIT HEADER +DEVMDCH EQU 1 ;MEDIA CHECK +DMEDHL EQU 15 ;SIZE OF MEDIA CHECK HEADER +DEVBPB EQU 2 ;GET BPB +DEVRDIOCTL EQU 3 ;IOCTL READ +DBPBHL EQU 22 ;SIZE OF GET BPB HEADER +DEVRD EQU 4 ;READ +DRDWRHL EQU 22 ;SIZE OF RD/WR HEADER +DEVRDND EQU 5 ;NON DESTRUCTIVE READ NO WAIT (CHARACTER DEVS) +DRDNDHL EQU 14 ;SIZE OF NON DESTRUCTIVE READ HEADER +DEVIST EQU 6 ;INPUT STATUS +DSTATHL EQU 13 ;SIZE OF STATUS HEADER +DEVIFL EQU 7 ;INPUT FLUSH +DFLSHL EQU 15 ;SIZE OF FLUSH HEADER +DEVWRT EQU 8 ;WRITE +DEVWRTV EQU 9 ;WRITE WITH VERIFY +DEVOST EQU 10 ;OUTPUT STATUS +DEVOFL EQU 11 ;OUTPUT FLUSH +DEVWRIOCTL EQU 12 ;IOCTL WRITE +DEVOPN EQU 13 ;DEVICE OPEN +DEVCLS EQU 14 ;DEVICE CLOSE +DOPCLHL EQU 13 ;SIZE OF OPEN/CLOSE HEADER +DEVRMD EQU 15 ;REMOVABLE MEDIA +REMHL EQU 13 ;SIZE OF REMOVABLE MEDIA HEADER +GENIOCTL EQU 19 +; THE NEXT THREE ARE USED IN DOS 4.0 +; 20 +; 21 +; 22 +DEVGETOWN EQU 23 ;GET DEVICE OWNER +DEVSETOWN EQU 24 ;SET DEVICE OWNER +OWNHL EQU 13 ;SIZE OF DEVICE OWNER HEADER + +DEVOUT EQU 16 ; OUTPUT UNTIL BUSY. +DEVOUTL EQU DEVWRT ; LENGTH OF OUTPUT UNTIL BUSY + +; GENERIC IOCTL REQUEST STRUCTURE +; SEE THE DOS 4.0 DEVICE DRIVER SPEC FOR FURTHER ELABORATION. +; +IOCTL_REQ STRUC + DB (SIZE SRHEAD) DUP(?) + ; GENERIC IOCTL ADDITION. +MAJORFUNCTION DB ? ;FUNCTION CODE +MINORFUNCTION DB ? ;FUNCTION CATEGORY +REG_SI DW ? +REG_DI DW ? +GENERICIOCTL_PACKET DD ? ; POINTER TO DATA BUFFER +IOCTL_REQ ENDS + +; DEFINITIONS FOR IOCTL_REQ.MINORFUNCTION +GEN_IOCTL_WRT_TRK EQU 40H +GEN_IOCTL_RD_TRK EQU 60H +GEN_IOCTL_FN_TST EQU 20H ; USED TO DIFF. BET READS AND WRTS diff --git a/SRC/DOS/DINFO.OBJ b/SRC/DOS/DINFO.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..51e147cd2f0179e4775aa2b8e461fc1d2eb47e7f GIT binary patch literal 467 zcmZqRX5e)34EB!q^mFsyHqDHIfyLS1#g*0B-!C|X6HGe#g#@#>IEFZKxcCRV2l+w*QR(nf^2XXZg?ipUt^PlYz}SG{`B`je*BCBE&T)DBj24 zIW(AoJ;cK^*x3cdNG&e$OD$nIvp|G_m4V>}14A*}4j#d?`iGCPF)%Q-%;9EeVH9Iz zIl?Q($aKDkhk?^IxhS*5C9^o2;qC%<237%(o|rjoU}da(d-xc*-5f)LTpeBFK^AB) z;9+1D2B|4>+|9)B1gem2PY)*pTc}@vqq8@|;ss6&tkPgLmPdgB*Oek5Ca>1*$E(&I zCfEGye+i5A#Uf?nOP(N8#7h~SoF9Gl_Ezh1WBGRgsEkRiGfeJB%^U%+6WEWii!m~` xD2p+&bAp`f19$E`TB(j)F~XhCI~PvvLYgnfq`Lm7ZU?R2><~ldI10c literal 0 HcmV?d00001 diff --git a/SRC/DOS/DIR.OBJ b/SRC/DOS/DIR.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..7ada25655a2b518189fd7043c162524ff823c5ea GIT binary patch literal 1335 zcmXX_T})eL7=FICr{|OcEyxa&3-AXz7MyWlNCY!h+EXB7E%qG9j0sD{ZV>sIr(ffC zv7}~PNZTzn@n;&cbuKe8F(D>;;l&uP-*)4TW=0c8luS%i?j+(CmHK||l5^hoIq&)2 z=X;*_oG+um86Js$_P5{gAl%TtNLsAamsK`W?*W9CpiHa_MW4Vso>TEV!b zSi!+j3n{52Ge}mdpL*HZ{Z~@z_EN zsx>{63Xcs!nOK+|3ByxyZpK5y_@KB91^5jp0_|5`)Y4AEbfuiX1Fe@@f$V{rE#BAL z7XWzA?vPjGO7ET<$p3KZZf@rm(3?2|{F-+6-leKSy}YwcJX>YCxjojFs|Wh&PPvvS zR(Ligdbs_3_L;UU@n*KJT;#spI~w=w3XN}eZ*4bZ{?+)8H<#bQBGXx;aOsRK*7=!| zW{ZAGwQO-8rOzN*8kypN=+K#4bnC1^^y{on9F<|1!r~|`TY)fj=3ks3yb5trXSHHV zXC5&l!<=kQ>8wVar(KMEBYejbd}_M-4bwcC!a(sDl*@83T-_y`W&Vw{7|5Q2u9m*? zV&@aC1~TW%1N^VjHS$Yqc*oI;C!gqFx7)Hb#=TM>MSFja;-Te(6$)R(JuVsu$|lOg@>iWw_lpA>;Y9k|Y(+Z7_o0bvBO0f%yi;=&cjqN~z z91z>*%DuJRw;h}1x9+zgkehU5e%btcC%0}sx9qQw?-L$LSxaFpUjvnnVB83XFzE!cp>W@a`oN8^}gnduty96LOr6wA%DYur4%GC|Y!;iKpcd zI(6o~k@vto9vusYj^TQ-8OjMso^ni&;$EM+-G19`qB8zUn_aU+B; zi-(}RE*mG8NYjH-&l;H|3B!~ExrjHAoA7ttrb6}gf6MI^m-~fVXR4@^ifEWV(InZQ zl-lU0Q%eOunBs}d%)drw(LM)YwNOVT_mE*3QOn1WDfsAFt3JnHu4VYX&`1^U@gz@# z7Us?*?BohCR;Z_<8Z}PHzL$WXs?^csS$WLubF0ApDz#|@Ne5OBT}%Zx+0?&}G_F)6KvaSqJ@~{{v<@YY+ec literal 0 HcmV?d00001 diff --git a/SRC/DOS/DIR2.OBJ b/SRC/DOS/DIR2.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..dcfddfd63667a26c88ad75a2085cea712ccfb30f GIT binary patch literal 3188 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 AE&u=k literal 0 HcmV?d00001 diff --git a/SRC/DOS/DIRCALL.OBJ b/SRC/DOS/DIRCALL.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..4ad978afaf3739c7afea3ae267cc13f07d76a9ea GIT binary patch literal 1572 zcmZWpZD?Cn7=BNZb8oU_ZJM>GP1hw8rB>8vTTm)Yy-9A`+I)HMOOjH$nDtM5&uP{P26FD3lauFp z-sgQzR(+r*Cyj)bPFLS~2EdcZC3Tv}WlhT`S1oIqo}^}J-ek@kH*$r%C#{(lH7(7s zsHMfz`d^zW3;}q(WC*JX1aXtDgNjnpaqz9rM+Qap6LGmn0jqNWs!D!;w*!$6-xE21vIN=^kML3UpI@DEcDwZqRVg*d+7*K#;0m|J?ch}cX?KCOuZ#ERL2_s#f)C1s4zgk*GvhsQO z-thzN6sLFa{ZYd&PlasCNNB&_2?0~L7Bf@XtMYe)Eg0r-py% zph`cVazo`i9s~INd4R|7O}DBFi?%QnquZAO78?B$xQ7QA>EJ;|+JaY`=7$&|b{`{Q9zi8`EJ*14U=QO1qxCEX(2g_G%~OmV;ZuwRc%BiZSU&>l zc(IaSs+@xx&Uv6Mp;Xc}-B41i&()CdZ`>0yP!ai`BHS+ps-YUXx;Sy9!Wmt^Z~snu*+Mk=n7P?h`HC0X0#o|h{y~*9GquY%)!vpx@PKd#u)?p zq13iHCnJ22miqm)%)4*xs<$I7ny=wayos*5TZ^vQC>qWhgHmLaW73I@$q4gqVbUNY xL7`K%M`bcjza0cZefS5yn3%vT`U}AJgRRVzxU~QmA8Z*J-0CIp=7tNP@-I_4ix2<+ literal 0 HcmV?d00001 diff --git a/SRC/DOS/DIRENT.INC b/SRC/DOS/DIRENT.INC new file mode 100644 index 0000000..a6db992 --- /dev/null +++ b/SRC/DOS/DIRENT.INC @@ -0,0 +1,58 @@ +; SCCSID = @(#)dirent.asm 1.1 85/04/10 +; SCCSID = @(#)dirent.asm 1.1 85/04/10 +Break + +; +; +---------------------------+ +; | (12 BYTE) filename/ext | 0 0 +; +---------------------------+ +; | (BYTE) attributes | 11 B +; +---------------------------+ +; | (10 BYTE) reserved | 12 C +; +---------------------------+ +; | (WORD) time of last write | 22 16 +; +---------------------------+ +; | (WORD) date of last write | 24 18 +; +---------------------------+ +; | (WORD) First cluster | 26 1A +; +---------------------------+ +; | (DWORD) file size | 28 1C +; +---------------------------+ +; +; First byte of filename = E5 -> free directory entry +; = 00 -> end of allocated directory +; Time: Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour +; Date: Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980 +; + +dir_entry STRUC +dir_name DB 11 DUP (?) ; file name +dir_attr DB ? ; attribute bits +dir_pad DB 10 DUP (?) ; reserved for expansion +dir_time DW ? ; time of last write +dir_date DW ? ; date of last write +dir_first DW ? ; first allocation unit of file +dir_size_l DW ? ; low 16 bits of file size +dir_size_h DW ? ; high 16 bits of file size +dir_entry ENDS + +attr_read_only EQU 1h +attr_hidden EQU 2h +attr_system EQU 4h +attr_volume_id EQU 8h +attr_directory EQU 10h +attr_archive EQU 20h +attr_device EQU 40h ; This is a VERY special bit. + ; NO directory entry on a disk EVER + ; has this bit set. It is set non-zero + ; when a device is found by GETPATH + +attr_all EQU attr_hidden+attr_system+attr_directory + ; OR of hard attributes for FINDENTRY + +attr_ignore EQU attr_read_only+attr_archive+attr_device + ; ignore this(ese) attribute(s) during + ; search first/next + +attr_changeable EQU attr_read_only+attr_hidden+attr_system+attr_archive + ; changeable via CHMOD diff --git a/SRC/DOS/DISK.OBJ b/SRC/DOS/DISK.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..b8322b3c548b45f852ae148eda39015c6aa50383 GIT binary patch literal 2701 zcmZ8jeQaCR6+hR{_dVNjlIH6rO%pp!Gq1FSPRX#g$v_={BqqjA{a)&{6Z5JjEzt@^ z$+O1(nzg>s)%GfHLsJv91gY_M`LJ2U@f%~=d7tV>vS?7jZOze@kor^Cs0oFuEY}>MPNBj&Fq;@J`OH4MY4&5^B}2XF-3{0pc(f7 z2e>2xKt)W`o0<0m9KpMY9~r4apT2y=HqabkS)sYS5loxR9HxsN%`)pS+hiu0ovlo= zf$2fP6U8QIP$Ft37z$-DOkjotd<(n}5G;$JGnvV!iVonYGdTf^h7n3ZmZm>_-;pd4zkS@vu#tk!Lr+BcFL^z#iARW zk-c-XT6lK;JMb>KkJI0Mb@S^_ka>brDuS!kO$td;=&dVsA14#>|C(4dz79M^8Wr+q z_vIhvRG4aIyCzjDc8w1$V0zU`U)E8rFfE23qPMU#yimAuSJ`95w!suJHY!<@?peq9 z5YxBf>k)Re=mH6AVa4)IqY?OF^5pSfM5veQne~_wmi8oth4_diErk5Vkb##-x$xHS zp7a+mqT8=QPFugf+-UjiHC?T&L4e;-zM-*T3a>B>7~Q~Muzvg0wVKE{zm6OGVqkqSAuNE%sc$tyqT~_oL zHAyRXSfO}Lr_5}6kIZ_^ezg30u@PKhWgIE0hQ`KWmKI@&e*JNM5&B-RRKCb|2#y*1 zfiIIvdTq9yD9HFFAXiMv}XK=FgBL;di+N{0D129ucDHr2{0Py)_9=t z`swW}-cu(7jalK6-4$?M|2QiRS8tWKSwU|!omTzyR+)LsE=<6@n;!SJG6B(kpUebv z#L{>S=^`X2RhTz60go_@$<1UhzK-B3%3fkr)@hL`H^cw9SnjqQ^y`jx#!a`(oF@8c zAs-$8Dmp>Lq7y@lh7b5OnXBMkKwAyf?D-s8%V{FzoLk)?rvCu&HZqf_wMplQDiNsM zPP0X3BH0wpK75G9F6bCg)Nls7PexHwvBYR5mYBe>-!vWu{v`RyNV{G|vw`lcai;rZ z@{9{*!_}1&YZ?J$1zde(pbevteAS4ZWj{hSyfpEglL%U;r)tp?<=4tzvBDcLrB)`| zK<|)QzuAk~>RYfM=mD8^>JP}Q%T$mhdRk`dPg!6`lBQEJH3BDy8A}u)UX|g6n{}Xm zNw>>v!+V5qtXWO>1LJ<+H%Yg~A{-z?4*!oK?IigJg1?~#{%cd1(3JOi07|p)r+3PO zR=7Tkb~-k@UbC$R1w^n%AH*8}7R(_6gCCO!(vo58O+`X*!T1~Sej7zucmvJWI!5jx zzMa~}@WPEHPrh=|gKj<>zIwb*v#lIEZp%J?+@8HsxR86GTl@3>a|li0m0p{GjDoeG z$5he+Ao!-L7J5CW5(B5)&YU_D|EYA9? zh^^IZtLzoi$@2HDVtiSbFzr`tW&<@c1XPp0U1mNrN~;)`S)ZPi*+w&6tJAlMGW&@0 z^R;4qkBapJqRf#ReV(c*K8MpiHvL6>;qGt-aiPDAq|jfn4prOC|)W!CyO zE%sz$A{ZKnUm6X-zadZ@mkuv|(Yo$>n)bKYd?Xo#H;gvmLDHDFE#D$Xg}3tWOxMx7 zg?QTfELn`kMhQN@H=2M?kUjyYYiJ=*SKVrInX$73^wEflM}=q#+{QNGyDj&>^6aDy zBNylPZ+R*vBJn6tx|k2VkeGyh>~$3)@s>*aM;j(3w|mx(lFFVO~st=QUtW{h6o zKO~D&yR<&x%JRQ=7cS$McFi&gpV$8%)Nv;pq(ZfwA)?aGf}4FR4X2HE;Lni-?8YAj zggaUGNo9BC>3Ung=c!T?FfQS#hK?qp0B1|hD4?TThC=88SS+nWiIXH2p`T~4RC1$; zBg2B>p9!$H_D?jZ;<+X@eL#S(mD*6j9gU?FH58vz@PwoYFkWgwscZj?mYF@6nct^f vx50y@4wPBj8dfnAR5IaMDkDI#W|NL(Beb@7_N#?T66~0`9AC}buoV9RERowE literal 0 HcmV?d00001 diff --git a/SRC/DOS/DISK2.OBJ b/SRC/DOS/DISK2.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..d4021577902defebd33d2b2fc9da17f8fed6389b GIT binary patch literal 2180 zcmZ8iYit`;7Cv|EJ7dR*lQ_+!ZI+}h>`*YzhBdEHb>bNlD~@eEL<15C74ayn7A+M{|ByXrY$QOk zXU;wM-0!@;b7xKgZX~U-b$yS<0Q~WcVe)t;ZP`KZsi$qrZ|JrjFf!KlxlBImPwAG; zEnCmo+}1}@=KuC9uofT?U~5qtMGznBZc3c9aC0{pWEx3tNs`2NptK!8QP}Cn!yqrQ zC27gG4T2 z+L$zQ6QIOza|&tac2Ep+BdH-sNzNqlD9XmTt{Vmf%o}Ypm&@9qq&62kTqTV<+LLqJ zHgC<`0d44ou*j24^3J07rnO>kzqMdwM_R({E)+(SmX)x9+q0W@7T{p56F9&P+Wal5 zHlJXYd|$Z@6w9=8rf$Gg?NZ<&_y*v+3o7_@SUvWp48TwxX2t&u`xYH`w*IT*FIHDT ziK(owq;xSJ1<|Rp&QcG`lkjdi1ObGe$R%wPPLt~xVV4&M2i70i6=7A`JG=ZJhu@HL_;8~cf4|h5}0~=#UkRP$~06zAjG(GrS z^;{2cg=kZmEP5g==mW7vWr{dI!rCPe7pbg$4<$UR=M1bgCj33{JIPaBJK`uFnmR~u zF5>RRKcx?vYxZhxzHhGz@ONA`Og=Z~#AI;^F6O6U4;pIjv~=x>Lagy4T9Bdpfwm^$ ze+q@e+I*UyI892$J?b9zA!eZ+lWClE*r#j?aSiQ{sBD?Ys4OBZm2q*C z%DTjMl?B9|bZ{3v9#C1E*hjkuR3?e%RMstCP?=A>Ld!QvdYg3bBRdw#-4IS?;$t(| z@RV*RGig{}8wS3KXjb@q=-4Z(;jEVi`|e{beYfV`+!Mu`^<$Z5FLT(TAs7`s2LxF-L;j#AMzZ@LE%*viGV3 z9?Ty~G7@+_6CId-sSD+wK`g_Jdx<-Vv=L9`EwF1L;Li|L=vc9LON-3s94H4tp2*Q4 z!+o{2zz?!-0h+%}o2Jx3%#UM!#0DbR{p*onMgDM$yaOda`nyN+=4rnq`c&2-`l;H3 zSjwx)0pKI~M9zRSwJzWvlKa_HO^g#m)sPqepir>b|D<5)`moG6Bq{IDJnQ2g(dLPv zm^1NwPj#htZWWzVMLRXPi`qpw|BI$LleLrM$w?D_sPzFq0_cZ!a@?fM)4Zn-J;aGfh!WmJ2g4`tnU-Ne&D56(bm*jSH;Gpm9*ijS{nE= zGMyXetFAHqj(&Aso*lmWX1Q?XPbS|`yyV90L@t__8=trhchP-AbJJ4e3*X{{#jfMu z%CUVI){h4Y>}h3khWzZPc6hO!D~7$W?kcxK(2DEnY)X%t@KFuFIn(5?y%o@TfAuWJ zlG$cNk5REVlZEqdbr9QlD*Q~#^p8(aj>&?VNx<>iH1ONWte`y)OBez7_1)DmFA+@ykr$67u)Y#Z)0$9Uczbo EKZJ5O9{>OV literal 0 HcmV?d00001 diff --git a/SRC/DOS/DISK3.OBJ b/SRC/DOS/DISK3.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..b8609cb94b0bc1bb4505f7ca2f4625fb466b654f GIT binary patch literal 1815 zcmXw4Z)_7~7=PYt-@A6*pSBw}Hs<~?JRy@AC`?d-+^$zv+qGTqx(&!&rp#c11KSSb zH-si;YeR?zf>`Cm_%|d*Ln82H|K7mB_+`XI;0wtV(fPqh0)El@yw{Rk?w)(^`SW{z z@9%luliwAY8#bbu)w(n}pG@L=zR9(Tiu{#-0C7e;!FsWgxNt2pt zZ&d&LtOV-;TrRR6tv*cRAilCiDXA@gb-Rhet&kuHB~lVfj*_!P zOQKe|0FoMw#)tGENWE`owTbMeC&p$FaV2pm18#g8KyFhV9! zGd(tej)P+d(Fe9#GEe~Jk?wS59lrw%cy3HOu9QmaiY~~xyo7!Y-a-vjMdMmzRO{2V z2pqMlfcoJ9z@Cizcu|BLkxBhGg+^!?N`_5+)bllF)d+Mo_s=XZUOME>@^UQj)qF3C4$FFmFu&?c&j&0OVzW<=-50Cze3T zzaqSNE3@zM!~D;lrAgAKOvmW02Z^M}c4CdZ?o;xqdP#YFM943Cma=5mrvQOjyx}$6 zbvwNyyD@+BedY1%Lf71hJK$Krq$}PSM1Cg7~)26~#~T(0@GLW+E`-~kucfTo%{v{)N}p0kN?1#WPd|17M8 zPa!2;^GDo)B?LBw4G!mPai!R4qiAGqteo>9KbHt==Cxbx+N@J1;3@P ztzMurJbn89RBJg`*L-&E^4vgv5m$%PEWgMZ>UqmSvsrlD&Pwwi&~5RU8YHS{Obh?FDZY`j-&wu75FDj%zs zNj39w7!8$UL|ne525$Yga6rQgU9td~8@M>J3#(VaHV6sHkS%p_`R zo@?O|uaB24DtulomFkL3HWh1gPMoXrz+5tsa@Dro!TU_=(cWl;kJJ{RlEC3zTlq0? zw|urtjWj7!BWsj*M?8|}ZnjlSB?glGJX59zA^*cA;lGO3JGoN5Ou + +AsmVars Macro varlist +IRP var, +AsmVar var +ENDM +ENDM + +AsmVar Macro var +IFNDEF var +var = FALSE +ENDIF +ENDM + +BREAK + +; +; declare a variable external and allocate a size +; +AsmVar InstalledData +I_NEED MACRO sym,len +IF NOT InstalledData + DATA SEGMENT WORD PUBLIC 'DATA' + IFIDN , + EXTRN &sym:WORD + ELSE + IFIDN , + EXTRN &sym:DWORD + ELSE + EXTRN &sym:BYTE + ENDIF + ENDIF + DATA ENDS +ENDIF +ENDM + .xcref I_need + +; +; call a procedure that may be external. The call will be short. +; +invoke MACRO name +.xcref + IF2 + IFNDEF name + EXTRN name:NEAR + ENDIF + ENDIF +.cref + CALL name +ENDM +.xcref invoke + +PAGE +; +; jump to a label that may be external. The jump will be near. +; +transfer MACRO name +.xcref + IF2 + IFNDEF name + EXTRN name:NEAR + ENDIF + ENDIF +.cref + JUMP name +ENDM +.xcref transfer + +; +; get a short address in a word +; +short_addr MACRO name + IFDIF , +.xcref + IF2 + IFNDEF name + EXTRN name:NEAR + ENDIF + ENDIF +.cref + DW OFFSET DOSGROUP:name + ELSE + DW ? + ENDIF +ENDM +.xcref short_addr + +; +; get a long address in a dword +; +long_addr MACRO name +.xcref + IF2 + IFNDEF name + EXTRN name:NEAR + ENDIF + ENDIF +.cref + DD name +ENDM +.xcref long_addr + +; +; declare a PROC near or far but PUBLIC nonetheless +; +.xcref ?frame +.xcref ?aframe +.xcref ?stackdepth +.xcref ?initstack +?frame = 0 ; initial +?aframe = 0 ; initial +?stackdepth = 0 ; initial stack size +?initstack = 0 ; initial stack size + +procedure MACRO name,distance + ?frame = 0 + ?aframe = 2 ;; remember the pushed BP + PUBLIC name + IF1 +;; %OUT name... pass 1 + ENDIF + IF2 +;; %OUT name... pass 2 + ENDIF +name PROC distance + ?initstack = ?stackdepth ;; beginning of procedure +ENDM +.xcref procedure + +; +; end a procedure and check that stack depth is preserved +; +EndProc MACRO name, chk + IFDIF , ;; check the stack size + IF2 + IF ?initstack NE ?stackdepth ;; is it different? + %OUT ***** Possible stack size error in name ***** + ENDIF + ENDIF + ENDIF +name ENDP +ENDM +.xcref endproc +PAGE +; +; define a data item to be public and of an appropriate size/type +; + +I_AM MACRO name,size,init +;; declare the object public + PUBLIC name +;; declare the type of the object + IFIDN , +name LABEL WORD + I_AM_SIZE = 1 + I_AM_LEN = 2 + ELSE + IFIDN , +name LABEL DWORD + I_AM_SIZE = 2 + I_AM_LEN = 2 + ELSE + IFIDN , +name LABEL BYTE + I_AM_SIZE = 1 + I_AM_LEN = 1 + ELSE +name LABEL BYTE + I_AM_SIZE = size + I_AM_LEN = 1 + ENDIF + ENDIF + ENDIF +;; if no initialize then allocate blank storage + IFB + DB I_AM_SIZE*I_AM_LEN DUP (?) + ELSE +IF NOT InstalledData + IRP itm, + IF I_AM_LEN EQ 1 + DB itm + ELSE + DW itm + ENDIF + I_AM_SIZE = I_AM_SIZE - 1 + ENDM + IF I_AM_SIZE NE 0 + %out ***** initialization of name not complete ***** + ENDIF +ELSE + DB I_AM_SIZE*I_AM_LEN DUP (?) +ENDIF + ENDIF +ENDM +.xcref I_AM +.xcref I_AM_SIZE +.xcref I_AM_LEN +I_AM_SIZE = 0 +I_AM_LEN = 0 + +PAGE + +; +; define an entry in a procedure +; +entry macro name + PUBLIC name +name: +endm +.xcref entry + +BREAK + +error macro code +.xcref + MOV AL,code + transfer SYS_RET_ERR +.cref +ENDM +.xcref error + +BREAK +; +; given a label either 2 byte jump to another label _J +; if it is near enough or 3 byte jump to +; + +jump macro lbl + local a +.xcref + + ifndef lbl&_J ;; is this the first invocation +a: JMP lbl + ELSE + IF (lbl&_J GE $) OR ($-lbl&_J GT 126) +a: JMP lbl ;; is the jump too far away? + ELSE +a: JMP lbl&_J ;; do the short one... + ENDIF + ENDIF + lbl&_j = a +.cref +endm +.xcref jump + +BREAK + +return macro x + local a +.xcref +a: + RET +ret_l = a +.cref +endm +.xcref return + +BREAK + +condret macro cc,ncc + local a +.xcref +.xcref a +.cref + ifdef ret_l ;; if ret_l is defined + if (($ - ret_l) le 126) and ($ gt ret_l) + ;; if ret_l is near enough then + a: j&cc ret_l ;; a: j to ret_l + ret_&cc = a ;; define ret_ to be a: + exitm + endif + endif + ifdef ret_&cc ;; if ret_ defined + if (($ - ret_&cc) le 126) and ($ gt ret_&cc) + ;; if ret_ is near enough + a: j&cc ret_&cc ;; a: j to ret_ + ret_&cc = a ;; define ret_ to be a: + exitm + endif + endif + j&ncc a ;; j a: + return ;; return + a: ;; a: + ret_&cc = ret_l ;; define ret_ to be ret_l +endm +.xcref condret + +BREAK + +retz macro + condret z,nz +endm +.xcref retz + +BREAK + +retnz macro + condret nz,z +endm +.xcref retnz + +BREAK + +retc macro + condret c,nc +endm +.xcref retc + +BREAK + +retnc macro + condret nc,c +endm +.xcref retnc + +BREAK + +context macro r + PUSH SS + POP r + ASSUME r:DOSGROUP +endm +.xcref context + +BREAK + +SaveReg MACRO reglist ;; push those registers +IRP reg, + ?stackdepth = ?stackdepth + 1 + PUSH reg +ENDM +ENDM +.xcref SaveReg + +BREAK + +RestoreReg MACRO reglist ;; pop those registers +IRP reg, + ?stackdepth = ?stackdepth - 1 + POP reg +ENDM +ENDM +.xcref RestoreReg + +BREAK + +EnterCrit MACRO section + Invoke E§ion +ENDM + +LeaveCrit MACRO section + Invoke L§ion +ENDM + +Break + +AsmVars + +if debug +fmt MACRO typ,lev,fmts,args +local a,b,c + PUSHF +IFNB + TEST BugTyp,typ + JZ c + CMP BugLev,lev + JB c +ENDIF + PUSH AX + PUSH BP + MOV BP,SP +If (not sharef) and (not redirector) +Table segment +a db fmts,0 +Table ends + MOV AX,OFFSET DOSGROUP:a +else + jmp short b +a db fmts,0 +if sharef +b: mov ax,offset share:a +else +b: mov ax,offset netwrk:a +endif +endif + PUSH AX +cargs = 2 +IRP item, +IFIDN , + MOV AX,[BP+2] +ELSE + MOV AX,item +ENDIF + PUSH AX +cargs = cargs + 2 +ENDM + invoke PFMT + ADD SP,Cargs + POP BP + POP AX +c: + POPF +ENDM +else +fmt macro +endm +endif + +Break + +AsmVar Debug,$temp + +IF debug +DOSAssume Macro reg,reglist,message +local a,b + IFIDN , + $temp = 1 + ELSE + IFIDN , + $temp = 0 + ELSE + %out ***** Invalid DOS register reg in DOSAssume ***** + ENDIF + ENDIF + IRP r, + IFIDN , + $temp = $temp OR 2 + ELSE + IFIDN , + $temp = $temp OR 4 + ELSE + %out ***** Invalid register reg in DOSAssume ***** + ENDIF + ENDIF + ENDM + PUSH AX + MOV AX,$temp + PUSH AX +IF SHAREF + MOV AX,OFFSET a +ELSE + MOV AX,OFFSET DOSGroup:a +ENDIF + PUSH AX + Invoke SegCheck + POP AX +IF NOT SHAREF +Table SEGMENT +a DB message,0 +Table ends +ELSE + JMP SHORT a +b DB message,0 +a: +ENDIF +IRP r, + ASSUME r:DOSGroup +ENDM +ENDM +ELSE +DOSAssume Macro reg,reglist,message +IRP r, + ASSUME r:DOSGroup +ENDM +ENDM +ENDIF + +BREAK + +IF DEBUG +Assert MACRO kind, objs, message + LOCAL a,b + IFIDN , + CMP objs,0 + JZ a + fmt <>,<>, +a: + ELSE + IFIDN , + CMP objs,0 + JNZ a + fmt <>,<>, +a: + ELSE + PUSH AX + IRP obj, + PUSH obj + ENDM + IF SHAREF + MOV AX,OFFSET b + ELSE + MOV AX,OFFSET DOSGroup:b + ENDIF + PUSH AX + IFIDN , + Invoke BUFCheck + ENDIF + IFIDN , + Invoke SFTCheck + ENDIF + IFIDN , + Invoke DPBCheck + ENDIF + POP AX + IF SHAREF + JMP SHORT a +b DB Message,0 +a: + ELSE +Table segment +b db Message,0 +Table ends + ENDIF + ENDIF + ENDIF +ENDM +ELSE +Assert Macro +ENDM +ENDIF + +Break + +CallInstall MACRO name,mpx,fn,save,restore +IF Installed + IFNB + SaveReg + ENDIF + MOV AX,(mpx SHL 8) + fn + INT 2Fh + IFNB + RestoreReg + ENDIF +ELSE + Invoke name +ENDIF +ENDM + +Break + +localvar macro name,length +local a + ifidn , + ?frame = ?frame + 1 + a = ?frame + name EQU BYTE PTR [BP-a] + else + ifidn , + ?frame = ?frame + 2 + a = ?frame + name EQU WORD PTR [BP-a] + else + ifidn , + ?frame = ?frame + 4 + a = ?frame + name EQU DWORD PTR [BP-a] + name&l EQU WORD PTR [BP-a] + name&h EQU WORD PTR [BP-a+2] + else + ?frame = ?frame + length + a = ?frame + name EQU BYTE PTR [BP-a] + endif + endif + endif +endm + +enter macro + push bp + mov bp,sp + sub sp,?frame +endm + +leave macro + mov sp,bp + pop bp +endm + +Argvar macro name,length +local a + ifidn , + a = ?aframe + ?aframe = ?aframe + 1 + name EQU BYTE PTR [BP+a] + else + ifidn , + a = ?aframe + ?aframe = ?aframe + 2 + name EQU WORD PTR [BP+a] + else + ifidn , + a = ?aframe + ?aframe = ?aframe + 4 + name EQU DWORD PTR [BP+a] + name&l EQU WORD PTR [BP+a] + name&h EQU WORD PTR [BP+a+2] + else + a = ?aframe + ?aframe = ?aframe + length + name EQU BYTE PTR [BP+a] + endif + endif + endif +endm + +BREAK + +errnz macro x +if x NE 0 + %out ***** FATAL error: x <> 0 +foobar +endif +endm diff --git a/SRC/DOS/DOSMES.INC b/SRC/DOS/DOSMES.INC new file mode 100644 index 0000000..61d65ef --- /dev/null +++ b/SRC/DOS/DOSMES.INC @@ -0,0 +1,485 @@ +; SCCSID = @(#)dosmes.asm 1.7 85/10/23 +; SCCSID = @(#)dosmes.asm 1.7 85/10/23 +; +; Message file for Internationalized messages. There is +; only one message here available for translation. +; + +IFNDEF KANJI +KANJI EQU FALSE +ENDIF + +IFNDEF Rainbow +Rainbow EQU FALSE +ENDIF + +include dosmac.inc +include intnat.inc +include doscntry.inc + +CONSTANTS SEGMENT WORD PUBLIC 'CONST' + + PUBLIC UserNum, OEMNum + Public DMES001S,DMES001E +DMES001S Label byte +USERNUM DW ? ; 24 bit user number + DB ? + IF IBM +OEMNUM DB 0 ; 8 bit OEM number + ELSE +OEMNUM DB 0FFH ; 8 bit OEM number + ENDIF + +; +; The next variable points to the country table for the current country +; ( the table returned by the AL=0 INTERNATIONAL call). +; + PUBLIC Current_Country + + IF KANJI +Current_Country DW OFFSET DOSGROUP:JAPTABLE + ELSE +Current_Country DW OFFSET DOSGROUP:USTABLE + ENDIF + +DMES001E label byte +CONSTANTS ENDS + +TABLE SEGMENT BYTE PUBLIC 'TABLE' +Public DMES002S +DMES002S label byte + +; +; The international tabel(s). Used for DOS 3.x (x < 3) +; This is simply a sequence of tables of the following form: +; +; Offset +; BYTE Size of this table excluding this byte and the next +; WORD Country code represented by this table +; A sequence of n bytes, where n is the number specified +; by the first byte above and is not > internat_block_max, +; in the correct order for being returned by the +; INTERNATIONAL call as follows: +; WORD Date format 0=mdy, 1=dmy, 2=ymd +; 5 BYTE Currency symbol null terminated +; 2 BYTE thousands separator null terminated +; 2 BYTE Decimal point null terminated +; 2 BYTE Date separator null terminated +; 2 BYTE Time separator null terminated +; 1 BYTE Bit field. Currency format. +; Bit 0. =0 $ before # =1 $ after # +; Bit 1. no. of spaces between # and $ (0 or 1) +; Bit 2. =1 imbedded at decimal point, & no spaces; +; 1 BYTE No. of significant decimal digits in currency +; 1 BYTE Bit field. Time format. +; Bit 0. =0 12 hour clock =1 24 hour +; WORD Segment offset for address of case conversion routine +; WORD RESERVED. Filled in by DOS. Segment value for above routine +; 2 BYTE Data list separator null terminated. +; NOTE: The segment part of the DWORD Map_call is set +; by the INTERNATIONAL call. Do not try to initialize +; it to anything meaningful. +; +; The list of tables is terminated by putting a byte of -1 after the last +; table (a table with length -1). + + PUBLIC international_table + +international_table LABEL BYTE + + IF KANJI + DB SIZE internat_block ; Size in bytes of this table + DW 81 ; Country code +JAPTABLE internat_block <2,'\',0,0,0,0,',',0,'.',0,'-',0,':',0,0,0,1,OFFSET DOSGROUP:MAP_CASE , 0,',',0> + ENDIF + + DB SIZE internat_block ; Size in bytes of this table + DW 1 ; Country code +USTABLE internat_block <0,'$',0,0,0,0,',',0,'.',0,'-',0,':',0,0,2,0,OFFSET DOSGROUP:MAP_CASE,0,',',0> +; Tables for the IBM PC character set follow. The values +; associated with some of the currency symbols may change with +; other character sets. You may wish to add or delete country +; entries. NOTE: It is not a mistake that the JAPANESE entry +; has different currency symbols for the KANJI and +; non-KANJI versions. + + DB -1 ; end of table + +; The following table is used for DOS 3.3 +;DOS country and code page information is defined here for DOS 3.3. +;The initial value for ccDosCountry is 1 (USA). +;The initial value for ccDosCodepage is 850. +; +; + PUBLIC COUNTRY_CDPG,UCASE_TAB,FILE_UCASE_TAB + PUBLIC FILE_CHAR_TAB +; +; country and code page infomation +; +COUNTRY_CDPG label byte + + db 0,0,0,0,0,0,0,0 ; reserved words + db '\COUNTRY.SYS',0 ; path name of country.sys + db 51 dup (?) + dw 437 ; system code page id + dw 5 ; number of entries + db SetUcase ; Ucase type + dw OFFSET DOSGROUP:UCASE_TAB ;pointer to upper case table + dw 0 ; segment of poiter + db SetUcaseFile ; Ucase file char type + dw OFFSET DOSGROUP:FILE_UCASE_TAB ;pointer to file upper case table + dw 0 ; segment of poiter + db SetFileList ; valid file chars type + dw OFFSET DOSGROUP:FILE_CHAR_TAB ;pointer to valid file char tab + dw 0 ; segment of poiter + db SetCollate ; collate type + dw OFFSET DOSGROUP:COLLATE_TAB ;pointer to collate table + dw 0 ; segment of poiter + db SetCountryInfo ; country info type + dw NEW_COUNTRY_SIZE ; extended country info size + dw 1 ; USA country id + dw 437 ; USA system code page id + dw 0 ; date format + db '$',0,0,0,0 ; currency symbol + db ',',0 ; thousand separator + db '.',0 ; decimal separator + db '-',0 ; date separator + db ':',0 ; time separator + db 0 ; currency format flag + db 2 ; # of disgit in currency + db 0 ; time format + dw OFFSET DOSGROUP:MAP_CASE ;mono case routine entry point + dw 0 ; segment of entry point + db ',',0 ; data list separator + dw 0,0,0,0,0 ; reserved + + + +; +; +; +; +; +; upper case table +; +UCASE_TAB label byte + dw 128 + db 128,154,069,065,142,065,143,128 + db 069,069,069,073,073,073,142,143 + db 144,146,146,079,153,079,085,085 + db 089,153,154,155,156,157,158,159 + db 065,073,079,085,165,165,166,167 + db 168,169,170,171,172,173,174,175 + db 176,177,178,179,180,181,182,183 + db 184,185,186,187,188,189,190,191 + db 192,193,194,195,196,197,198,199 + db 200,201,202,203,204,205,206,207 + db 208,209,210,211,212,213,214,215 + db 216,217,218,219,220,221,222,223 + db 224,225,226,227,228,229,230,231 + db 232,233,234,235,236,237,238,239 + db 240,241,242,243,244,245,246,247 + db 248,249,250,251,252,253,254,255 + +; +; file upper case table +; +FILE_UCASE_TAB label byte + dw 128 + db 128,154,069,065,142,065,143,128 + db 069,069,069,073,073,073,142,143 + db 144,146,146,079,153,079,085,085 + db 089,153,154,155,156,157,158,159 + db 065,073,079,085,165,165,166,167 + db 168,169,170,171,172,173,174,175 + db 176,177,178,179,180,181,182,183 + db 184,185,186,187,188,189,190,191 + db 192,193,194,195,196,197,198,199 + db 200,201,202,203,204,205,206,207 + db 208,209,210,211,212,213,214,215 + db 216,217,218,219,220,221,222,223 + db 224,225,226,227,228,229,230,231 + db 232,233,234,235,236,237,238,239 + db 240,241,242,243,244,245,246,247 + db 248,249,250,251,252,253,254,255 + +; +; file char list +; +FILE_CHAR_TAB label byte + dw 22 ; length + db 1,0,255 ; include all + db 0,0,20h ; exclude 0 - 20h + db 2,14,'."/\[]:|<>+=;,' ; exclude 14 special + db 24 dup (?) ; reserved +; +; collate table +; +COLLATE_TAB label byte + dw 256 + db 0,1,2,3,4,5,6,7 + db 8,9,10,11,12,13,14,15 + db 16,17,18,19,20,21,22,23 + db 24,25,26,27,28,29,30,31 + db " ","!",'"',"#","$","%","&","'" + db "(",")","*","+",",","-",".","/" + db "0","1","2","3","4","5","6","7" + db "8","9",":",";","<","=",">","?" + db "@","A","B","C","D","E","F","G" + db "H","I","J","K","L","M","N","O" + db "P","Q","R","S","T","U","V","W" + db "X","Y","Z","[","\","]","^","_" + db "`","A","B","C","D","E","F","G" + db "H","I","J","K","L","M","N","O" + db "P","Q","R","S","T","U","V","W" + db "X","Y","Z","{","|","}","~",127 + db "C","U","E","A","A","A","A","C" + db "E","E","E","I","I","I","A","A" + db "E","A","A","O","O","O","U","U" + db "Y","O","U","$","$","$","$","$" + db "A","I","O","U","N","N",166,167 + db "?",169,170,171,172,"!",'"','"' + db 176,177,178,179,180,181,182,183 + db 184,185,186,187,188,189,190,191 + db 192,193,194,195,196,197,198,199 + db 200,201,202,203,204,205,206,207 + db 208,209,210,211,212,213,214,215 + db 216,217,218,219,220,221,222,223 + db 224,"S" + db 226,227,228,229,230,231 + db 232,233,234,235,236,237,238,239 + db 240,241,242,243,244,245,246,247 + db 248,249,250,251,252,253,254,255 +; +; dbcs is not supported in DOS 3.3 +; DBCS_TAB CC_DBCS <> +; +; +include divmes.inc + +TABLE ENDS + +CODE SEGMENT BYTE PUBLIC 'CODE' +ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING + +;CASE MAPPER ROUTINE FOR 80H-FFH character range, DOS 3.3 +; ENTRY: AL = Character to map +; EXIT: AL = The converted character +; Alters no registers except AL and flags. +; The routine should do nothing to chars below 80H. +; +; Example: + +Procedure MAP_CASE,FAR +IF NOT KANJI +IF IBM + CMP AL,80H + JAE Map1 ;Map no chars below 80H ever + RET +Map1: + SUB AL,80H ;Turn into index value + PUSH DS + PUSH BX + MOV BX,OFFSET DOSGROUP:UCASE_TAB + 2 +FINISH: + PUSH CS ;Move to DS + POP DS + XLAT ds:[bx] ;Get upper case character + POP BX + POP DS +ENDIF +ENDIF +L_RET: RET +EndProc MAP_CASE + +SUBTTL EDIT FUNCTION ASSIGNMENTS AND HEADERS +PAGE +; The following two tables implement the current buffered input editing +; routines. The tables are pairwise associated in reverse order for ease +; in indexing. That is; The first entry in ESCTAB corresponds to the last +; entry in ESCFUNC, and the last entry in ESCTAB to the first entry in ESCFUNC. + + +TABLE SEGMENT + PUBLIC CANCHAR +CANCHAR DB CANCEL ;Cancel line character + PUBLIC ESCCHAR +ESCCHAR DB ESCCH ;Lead-in character for escape sequences + IF NOT Rainbow +ESCTAB LABEL BYTE + IF NOT IBM + IF WANG + DB 0C0h ; ^Z inserter + DB 0C1H ; Copy one char + DB 0C1H ; Copy one char + DB 0C7H ; Skip one char + DB 08AH ; Copy to char + DB 088H ; Skip to char + DB 09AH ; Copy line + DB 0CBH ; Kill line (no change in template) + DB 08BH ; Reedit line (new template) + DB 0C3H ; Backspace + DB 0C6H ; Enter insert mode + DB 0D6H ; Exit insert mode + DB 0C6H ; Escape character + DB 0C6H ; End of table + ELSE + ; VT52 equivalences + DB "Z" ; ^Z inserter + DB "S" ; F1 Copy one char + DB "S" ; F1 Copy one char + DB "V" ; F4 Skip one char + DB "T" ; F2 Copy to char + DB "W" ; F5 Skip to char + DB "U" ; F3 Copy line + DB "E" ; SHIFT ERASE Kill line (no change in template) + DB "J" ; ERASE Reedit line (new template) + DB "D" ; LEFT Backspace + DB "P" ; BLUE Enter insert mode + DB "Q" ; RED Exit insert mode + DB "R" ; GRAY Escape character + DB "R" ; End of table + ENDIF + ENDIF + IF IBM + DB 64 ; Ctrl-Z - F6 + DB 77 ; Copy one char - --> + DB 59 ; Copy one char - F1 + DB 83 ; Skip one char - DEL + DB 60 ; Copy to char - F2 + DB 62 ; Skip to char - F4 + DB 61 ; Copy line - F3 + DB 61 ; Kill line (no change to template ) - Not used + DB 63 ; Reedit line (new template) - F5 + DB 75 ; Backspace - <-- + DB 82 ; Enter insert mode - INS (toggle) + DB 82 ; Exit insert mode - INS (toggle) + DB 65 ; Escape character - F7 + DB 65 ; End of table + ENDIF +ESCEND LABEL BYTE +ESCTABLEN EQU ESCEND-ESCTAB + +ESCFUNC LABEL WORD + short_addr GETCH ; Ignore the escape sequence + short_addr TWOESC + short_addr EXITINS + short_addr ENTERINS + short_addr BACKSP + short_addr REEDIT + short_addr KILNEW + short_addr COPYLIN + short_addr SKIPSTR + short_addr COPYSTR + short_addr SKIPONE + short_addr COPYONE + short_addr COPYONE + short_addr CTRLZ + ENDIF +TABLE ENDS + +; +; OEMFunction key is expected to process a single function +; key input from a device and dispatch to the proper +; routines leaving all registers UNTOUCHED. +; +; Inputs: CS, SS are DOSGROUP +; Outputs: None. This function is expected to JMP to one of +; the following labels: +; +; GetCh - ignore the sequence +; TwoEsc - insert an ESCChar in the buffer +; ExitIns - toggle insert mode +; EnterIns - toggle insert mode +; BackSp - move backwards one space +; ReEdit - reedit the line with a new template +; KilNew - discard the current line and start from scratch +; CopyLin - copy the rest of the template into the line +; SkipStr - read the next character and skip to it in the template +; CopyStr - read next char and copy from template to line until char +; SkipOne - advance position in template one character +; CopyOne - copy next character in template into line +; CtrlZ - place a ^Z into the template +; Registers that are allowed to be modified by this function are: +; AX, CX, BP + +Procedure OEMFunctionKey,NEAR + ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP + invoke $std_con_input_no_echo ; Get the second byte of the sequence + + IF NOT Rainbow + MOV CL,ESCTABLEN ; length of table for scan + PUSH DI ; save DI (cannot change it!) + MOV DI,OFFSET DOSGROUP:ESCTAB ; offset of second byte table + REPNE SCASB ; Look it up in the table + POP DI ; restore DI + SHL CX,1 ; convert byte offset to word + MOV BP,CX ; move to indexable register + JMP [BP+OFFSET DOSGROUP:ESCFUNC] ; Go to the right routine + ENDIF + IF Rainbow + +TransferIf MACRO value,address + local a + CMP AL,value + JNZ a + transfer address +a: +ENDM + + CMP AL,'[' ; is it second lead char + JZ EatParm ; yes, go walk tree +GoGetCh: + transfer GetCh ; no, ignore sequence +EatParm: + invoke $std_con_input_no_echo ; get argument + CMP AL,'A' ; is it alphabetic arg? + JAE EatAlpha ; yes, go snarf one up + XOR BP,BP ; init digit counter + JMP InDigit ; jump into internal eat digit routine +EatNum: + invoke $std_con_input_no_echo ; get next digit +InDigit: + CMP AL,'9' ; still a digit? + JA CheckNumEnd ; no, go check for end char + SUB AL,'0' ; turn into potential digit + JL GoGetCh ; oops, not a digit, ignore + MOV CX,BP ; save BP for 10 multiply + CBW ; make AL into AX + SHL BP,1 ; 2*BP + SHL BP,1 ; 4*BP + ADD BP,CX ; 5*BP + SHL BP,1 ; 10*BP + ADD BP,AX ; 10*BP + digit + JMP EatNum ; continue with number +CheckNumEnd: + CMP AL,7Eh ; is it end char ~ + JNZ GoGetCh ; nope, ignore key sequence + MOV AX,BP + transferIf 1,SkipStr ; FIND key + transferIf 2,EnterIns ; INSERT HERE key + transferIf 3,SkipOne ; REMOVE + transferIf 4,CopyStr ; SELECT + transferIf 17,TwoEsc ; INTERRUPT + transferIf 18,ReEdit ; RESUME + transferIf 19,KilNew ; CANCEL + transferIf 21,CtrlZ ; EXIT + transferIf 29,CopyLin ; DO + JMP GoGetCh +EatAlpha: + CMP AL,'O' ; is it O? + JA GoGetCh ; no, after assume bogus + JZ EatPQRS ; eat the rest of the bogus key + transferIf 'C',CopyOne ; RIGHT + transferIf 'D',BackSp ; LEFT + JMP GoGetCh +EatPQRS: + invoke $std_con_input_no_echo ; eat char after O + JMP GoGetCh + ENDIF + +EndProc OEMFunctionKey + +CODE ENDS + + END diff --git a/SRC/DOS/DOSSEG.INC b/SRC/DOS/DOSSEG.INC new file mode 100644 index 0000000..a84d79b --- /dev/null +++ b/SRC/DOS/DOSSEG.INC @@ -0,0 +1,25 @@ +; SCCSID = @(#)dosseg.asm 1.1 85/04/10 +; SCCSID = @(#)dosseg.asm 1.1 85/04/10 +; +; segment ordering for MSDOS +; + +START SEGMENT BYTE PUBLIC 'START' +START ENDS + +CONSTANTS SEGMENT WORD PUBLIC 'CONST' +CONSTANTS ENDS + +DATA SEGMENT WORD PUBLIC 'DATA' +DATA ENDS + +TABLE SEGMENT BYTE PUBLIC 'TABLE' +TABLE ENDS + +CODE SEGMENT BYTE PUBLIC 'CODE' +CODE ENDS + +LAST SEGMENT PARA PUBLIC 'LAST' +LAST ENDS + +DOSGROUP GROUP START,CONSTANTS,DATA,TABLE,CODE,LAST diff --git a/SRC/DOS/DOSSYM.INC b/SRC/DOS/DOSSYM.INC new file mode 100644 index 0000000..26a9485 --- /dev/null +++ b/SRC/DOS/DOSSYM.INC @@ -0,0 +1,155 @@ +; SCCSID = @(#)dossym.asm 1.1 85/04/10 +; SCCSID = @(#)dossym.asm 1.1 85/04/10 + PAGE 80,132 +TRUE EQU 0FFFFh +FALSE EQU 0 + +Installed = TRUE +IFNDEF DEBUG + DEBUG = FALSE +ENDIF + +include dosmac.INC + +include VERSIONA.INC + +;;IF2 +;; %OUT DOSSYM in Pass 2 +;;ENDIF + +BREAK + +c_DEL EQU 7Fh ; ASCII rubout or delete previous char +c_BS EQU 08h ; ^H ASCII backspace +c_CR EQU 0Dh ; ^M ASCII carriage return +c_LF EQU 0Ah ; ^J ASCII linefeed +c_ETB EQU 17h ; ^W ASCII end of transmission +c_NAK EQU 15h ; ^U ASCII negative acknowledge +c_ETX EQU 03h ; ^C ASCII end of text +c_HT EQU 09h ; ^I ASCII tab + +BREAK + +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; ; +; C A V E A T P R O G R A M M E R ; +; ; +; Certain structures, constants and system calls below are private to ; +; the DOS and are extremely version-dependent. They may change at any ; +; time at the implementors' whim. As a result, they must not be ; +; documented to the general public. If an extreme case arises, they ; +; must be documented with this warning. ; +; ; +; Those structures and constants that are subject to the above will be ; +; marked and bracketed with the flag: ; +; ; +; C A V E A T P R O G R A M M E R ; +; ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +include bpb.INC + +include buffer.INC + +BREAK +; Location of user registers relative user stack pointer + +user_environ STRUC +user_AX DW ? +user_BX DW ? +user_CX DW ? +user_DX DW ? +user_SI DW ? +user_DI DW ? +user_BP DW ? +user_DS DW ? +user_ES DW ? +user_IP DW ? +user_CS DW ? +user_F DW ? +user_environ ENDS + +include sysvar.INC + +include vector.INC + +include mult.INC + +BREAK +; MSDOS partitions the disk into 4 sections: +; +; phys sector 0: +-------------------+ +; | | boot/reserved | +; | +-------------------+ +; | | File allocation | +; v | table(s) | +; | (multiple copies | +; | are kept) | +; +-------------------+ +; | Directory | +; +-------------------+ +; | File space | +; +-------------------+ +; | Unaddressable | +; | (to end of disk) | +; +-------------------+ +; +; All partition boundaries are sector boundaries. The size of the FAT is +; adjusted to maximize the file space addressable. + +include dirent.INC + +BREAK +; +; The File Allocation Table uses a 12-bit entry for each allocation unit on +; the disk. These entries are packed, two for every three bytes. The contents +; of entry number N is found by 1) multiplying N by 1.5; 2) adding the result +; to the base address of the Allocation Table; 3) fetching the 16-bit word +; at this address; 4) If N was odd (so that N*1.5 was not an integer), shift +; the word right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry +; number zero is used as an end-of-file trap in the OS and is passed to the +; BIOS to help determine disk format. Entry 1 is reserved for future use. +; The first available allocation unit is assigned entry number two, and even +; though it is the first, is called cluster 2. Entries greater than 0FF8H +; (12-bit fats) or 0FFF8H (16-bit fats) are end of file marks; entries of zero +; are unallocated. Otherwise, the contents of a FAT entry is the number of +; the next cluster in the file. +; +; Clusters with bad sectors are tagged with FF7H. Any non-zero number would +; do because these clusters show as allocated, but are not part of any +; allocation chain and thus will never be allocated to a file. A particular +; number is selected so that disk checking programs know what to do (ie. a +; cluster with entry FF7H which is not in a chain is not an error). + +include dpb.INC + +include curdir.INC + +include cpmfcb.INC + +include find.INC + +include pdb.INC + +include exe.INC + +include sf.INC + +include arena.INC + +include intnat.INC + +include mi.INC + +fChk equ 1 +fDelim equ 2 +fSpChk equ 4 +fFCB equ 8 + +include filemode.INC + +include error.INC + +include syscall.INC + +SUBTTL diff --git a/SRC/DOS/DPB.INC b/SRC/DOS/DPB.INC new file mode 100644 index 0000000..92fb7fe --- /dev/null +++ b/SRC/DOS/DPB.INC @@ -0,0 +1,34 @@ +; SCCSID = @(#)dpb.asm 1.1 85/04/10 +; SCCSID = @(#)dpb.asm 1.1 85/04/10 +BREAK +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +dpb STRUC +dpb_drive DB ? ; Logical drive # assoc with DPB (A=0,B=1,...) +dpb_UNIT DB ? ; Driver unit number of DPB +dpb_sector_size DW ? ; Size of physical sector in bytes +dpb_cluster_mask DB ? ; Sectors/cluster - 1 +dpb_cluster_shift DB ? ; Log2 of sectors/cluster +dpb_first_FAT DW ? ; Starting record of FATs +dpb_FAT_count DB ? ; Number of FATs for this drive +dpb_root_entries DW ? ; Number of directory entries +dpb_first_sector DW ? ; First sector of first cluster +dpb_max_cluster DW ? ; Number of clusters on drive + 1 +dpb_FAT_size DB ? ; Number of records occupied by FAT +dpb_dir_sector DW ? ; Starting record of directory +dpb_driver_addr DD ? ; Pointer to driver +dpb_media DB ? ; Media byte +dpb_first_access DB ? ; This is initialized to -1 to force a media + ; check the first time this DPB is used +dpb_next_dpb DD ? ; Pointer to next Drive parameter block +dpb_next_free DW ? ; Cluster # of last allocated cluster +dpb_free_cnt DW ? ; Count of free clusters, -1 if unknown +dpb ENDS + +DPBSIZ EQU SIZE dpb ; Size of the structure in bytes + +DSKSIZ = dpb_max_cluster ; Size of disk (temp used during init only) +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; diff --git a/SRC/DOS/DPL.INC b/SRC/DOS/DPL.INC new file mode 100644 index 0000000..c51676b --- /dev/null +++ b/SRC/DOS/DPL.INC @@ -0,0 +1,15 @@ +; SCCSID = @(#)dpl.inc 1.1 85/04/10 +; SCCSID = @(#)dpl.inc 1.1 85/04/10 +DPL STRUC +DPL_AX DW ? ; AX register +DPL_BX DW ? ; BX register +DPL_CX DW ? ; CX register +DPL_DX DW ? ; DX register +DPL_SI DW ? ; SI register +DPL_DI DW ? ; DI register +DPL_DS DW ? ; DS register +DPL_ES DW ? ; ES register +DPL_reserved DW ? ; Reserved +DPL_UID DW ? ; User (Machine) ID (0 = local macine) +DPL_PID DW ? ; Process ID (0 = local user PID) +DPL ENDS diff --git a/SRC/DOS/DUP.OBJ b/SRC/DOS/DUP.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..ae9ea4aa88b6a571a4fe19ef281993d42e3fcae6 GIT binary patch literal 302 zcmXw#%}T>S6ot=CGD)VDNEh}26lzy4T^6R9XbU9?ovGU_q@XK*nyz)>O0uXM5mD%y zDA=d)2}E$?3yc%1o6E;NABW4m<_Kh_3OUL9_xpesXEI@NmMYDEr%1K(q|hR?+Tl2x z=Epb;X3?IPU{j$mpwaIy{ zHnAa-qaw?bw5Xe&mrbxnt#u50yZ95`mqi3({~rLbyV$aeNS@6KIX^Gt>E-mev?sjZ HIzagY2xmqC literal 0 HcmV?d00001 diff --git a/SRC/DOS/ERROR.INC b/SRC/DOS/ERROR.INC new file mode 100644 index 0000000..e43017a --- /dev/null +++ b/SRC/DOS/ERROR.INC @@ -0,0 +1,151 @@ +; SCCSID = @(#)error.asm 1.1 85/04/10 +; SCCSID = @(#)error.asm 1.1 85/04/10 +BREAK + +; +; XENIX calls all return error codes through AX. If an error occurred then +; the carry bit will be set and the error code is in AX. If no error occurred +; then the carry bit is reset and AX contains returned info. +; +; Since the set of error codes is being extended as we extend the operating +; system, we have provided a means for applications to ask the system for a +; recommended course of action when they receive an error. +; +; The GetExtendedError system call returns a universal error, an error +; location and a recommended course of action. The universal error code is +; a symptom of the error REGARDLESS of the context in which GetExtendedError +; is issued. +; + +; +; These are the 2.0 error codes +; +error_invalid_function EQU 1 +error_file_not_found EQU 2 +error_path_not_found EQU 3 +error_too_many_open_files EQU 4 +error_access_denied EQU 5 +error_invalid_handle EQU 6 +error_arena_trashed EQU 7 +error_not_enough_memory EQU 8 +error_invalid_block EQU 9 +error_bad_environment EQU 10 +error_bad_format EQU 11 +error_invalid_access EQU 12 +error_invalid_data EQU 13 +;**** reserved EQU 14 ; ***** +error_invalid_drive EQU 15 +error_current_directory EQU 16 +error_not_same_device EQU 17 +error_no_more_files EQU 18 +; +; These are the universal int 24 mappings for the old INT 24 set of errors +; +error_write_protect EQU 19 +error_bad_unit EQU 20 +error_not_ready EQU 21 +error_bad_command EQU 22 +error_CRC EQU 23 +error_bad_length EQU 24 +error_Seek EQU 25 +error_not_DOS_disk EQU 26 +error_sector_not_found EQU 27 +error_out_of_paper EQU 28 +error_write_fault EQU 29 +error_read_fault EQU 30 +error_gen_failure EQU 31 +; +; These are the new 3.0 error codes reported through INT 24 +; +error_sharing_violation EQU 32 +error_lock_violation EQU 33 +error_wrong_disk EQU 34 +error_FCB_unavailable EQU 35 +error_sharing_buffer_exceeded EQU 36 +; +; New OEM network-related errors are 50-79 +; +error_not_supported EQU 50 +; +; End of INT 24 reportable errors +; +error_file_exists EQU 80 +error_DUP_FCB EQU 81 ; ***** +error_cannot_make EQU 82 +error_FAIL_I24 EQU 83 +; +; New 3.0 network related error codes +; +error_out_of_structures EQU 84 +error_Already_assigned EQU 85 +error_invalid_password EQU 86 +error_invalid_parameter EQU 87 +error_NET_write_fault EQU 88 + +BREAK + +error_I24_write_protect EQU 0 +error_I24_bad_unit EQU 1 +error_I24_not_ready EQU 2 +error_I24_bad_command EQU 3 +error_I24_CRC EQU 4 +error_I24_bad_length EQU 5 +error_I24_Seek EQU 6 +error_I24_not_DOS_disk EQU 7 +error_I24_sector_not_found EQU 8 +error_I24_out_of_paper EQU 9 +error_I24_write_fault EQU 0Ah +error_I24_read_fault EQU 0Bh +error_I24_gen_failure EQU 0Ch +; NOTE: Code 0DH is used by MT-DOS. +error_I24_wrong_disk EQU 0Fh + +; THE FOLLOWING ARE MASKS FOR THE AH REGISTER ON Int 24 + +Allowed_FAIL EQU 00001000B +Allowed_RETRY EQU 00010000B +Allowed_IGNORE EQU 00100000B +;NOTE: ABORT is ALWAYS allowed + +I24_operation EQU 00000001B ;Z if READ,NZ if Write +I24_area EQU 00000110B ; 00 if DOS + ; 01 if FAT + ; 10 if root DIR + ; 11 if DATA +I24_class EQU 10000000B ;Z if DISK, NZ if FAT or char + +BREAK + +; Values for error CLASS + +errCLASS_OutRes EQU 1 ; Out of Resource +errCLASS_TempSit EQU 2 ; Temporary Situation +errCLASS_Auth EQU 3 ; Permission problem +errCLASS_Intrn EQU 4 ; Internal System Error +errCLASS_HrdFail EQU 5 ; Hardware Failure +errCLASS_SysFail EQU 6 ; System Failure +errCLASS_Apperr EQU 7 ; Application Error +errCLASS_NotFnd EQU 8 ; Not Found +errCLASS_BadFmt EQU 9 ; Bad Format +errCLASS_Locked EQU 10 ; Locked +errCLASS_Media EQU 11 ; Media Failure +errCLASS_Already EQU 12 ; Collision with Existing Item +errCLASS_Unk EQU 13 ; Unknown/other + +; Values for error ACTION + +errACT_Retry EQU 1 ; Retry +errACT_DlyRet EQU 2 ; Delay Retry, retry after pause +errACT_User EQU 3 ; Ask user to regive info +errACT_Abort EQU 4 ; abort with clean up +errACT_Panic EQU 5 ; abort immediately +errACT_Ignore EQU 6 ; ignore +errACT_IntRet EQU 7 ; Retry after User Intervention + +; Values for error LOCUS + +errLOC_Unk EQU 1 ; No appropriate value +errLOC_Disk EQU 2 ; Random Access Mass Storage +errLOC_Net EQU 3 ; Network +errLOC_SerDev EQU 4 ; Serial Device +errLOC_Mem EQU 5 ; Memory diff --git a/SRC/DOS/EXE.INC b/SRC/DOS/EXE.INC new file mode 100644 index 0000000..e768f6b --- /dev/null +++ b/SRC/DOS/EXE.INC @@ -0,0 +1,78 @@ +; SCCSID = @(#)exe.asm 1.1 85/04/10 +; SCCSID = @(#)exe.asm 1.1 85/04/10 +BREAK +; +; EXEC arg block - load/go program +; + +; +; The following get used as arguments to the EXEC system call. They indicate +; whether or not the program is executed or whether or not a program header +; gets created. +; +exec_func_no_execute EQU 1 ; no execute bit +exec_func_overlay EQU 2 ; overlay bit + +Exec0 STRUC +Exec0_environ DW ? ; seg addr of environment +Exec0_com_line DD ? ; pointer to asciz command line +Exec0_5C_FCB DD ? ; default fcb at 5C +Exec0_6C_FCB DD ? ; default fcb at 6C +Exec0 ENDS + +Exec1 STRUC +Exec1_environ DW ? ; seg addr of environment +Exec1_com_line DD ? ; pointer to asciz command line +Exec1_5C_FCB DD ? ; default fcb at 5C +Exec1_6C_FCB DD ? ; default fcb at 6C +Exec1_SP DW ? ; stack pointer of program +Exec1_SS DW ? ; stack seg register of program +Exec1_IP DW ? ; entry point IP +Exec1_CS DW ? ; entry point CS +Exec1 ENDS + +Exec3 STRUC +Exec3_load_addr DW ? ; seg address of load point +Exec3_reloc_fac DW ? ; relocation factor +Exec3 ENDS + +; +; Exit codes in upper byte +; +Exit_terminate EQU 0 +Exit_abort EQU 0 +Exit_Ctrl_C EQU 1 +Exit_Hard_Error EQU 2 +Exit_Keep_process EQU 3 + +; +; EXE file header +; + +EXE_file STRUC +exe_signature DW ? ; must contain 4D5A (yay zibo!) +exe_len_mod_512 DW ? ; low 9 bits of length +exe_pages DW ? ; number of 512b pages in file +exe_rle_count DW ? ; count of reloc entries +exe_par_dir DW ? ; number of paragraphs before image +exe_min_BSS DW ? ; minimum number of para of BSS +exe_max_BSS DW ? ; max number of para of BSS +exe_SS DW ? ; stack of image +exe_SP DW ? ; SP of image +exe_chksum DW ? ; checksum of file (ignored) +exe_IP DW ? ; IP of entry +exe_CS DW ? ; CS of entry +exe_rle_table DW ? ; byte offset of reloc table +exe_iov DW ? ; overlay number (0 for root) +exe_sym_tab DD ? ; offset of symbol table in file +EXE_file ENDS + +exe_valid_signature EQU 5A4Dh +exe_valid_old_signature EQU 4D5Ah + +symbol_entry STRUC +sym_value DD ? +sym_type DW ? +sym_len DB ? +sym_name DB 255 dup (?) +symbol_entry ENDS diff --git a/SRC/DOS/FAT.OBJ b/SRC/DOS/FAT.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..5ea1b29e8b18966304b388996b8a4d4bf7b448d2 GIT binary patch literal 2083 zcmZ8iTWk|o5S_dB?mCVi!N5&;d4mM2RH#&h643$`8+)C&IJVc+xw~oAR(|a4 z+}W8kXU@Gl$b%!I=pUVI18{~CVU-Uh;+kG({VQ=@bA}aNafK6FM=Fs{I%A5a^O~-t zbY555W9p+*BD4UwT%-l9PE6t;3v7$$iO*iGt0OYAat@9oU!nCHfGCoCXM7--#N}yg7F``6c z%q67u?R_P22t>Uzs)ZRQ%SiQrrza5$b;djTA~B@{&Q^PY2apR#z0>}~^@Ya|{5fag z@vOf#^mw)=Z`$pBOTG(`4VJd#eR8SaTX-_<&wA?3DbI~R?N8x%(@&+EJP`?+X7a-E zwyOdXeZ}-=DqbiC8wh_Bj07d*OxXoI4pE7LS$zZeG+^e;4$v{UE^5 z)rRA%sFW;GfUgO(j@_@cK#@>Fiyj-yCQ7_Um=X_z~=AWwvlKK->h3(`@NmN)~-lt^=VX zp)*OHt*XGkORxp})`aa?O`Wf1`})M}-TcP&W1YbfA3*DUc|5PS8Azi%gUTMvH?n62 z)c5D-(^Pcge4Y>^fQ5>SDQPM;*$$bKI%6FrE{)A6nTW>qP@*ddpI0{kKgJOBiFvpD zo*Kv8c(4(jc2gvA=aIx z&~@-#btCW(S#FkRvm?*V)u?pdFOTdepMsT)Ot8rV_DqpsA$S?>@&15#a=xLZ2G7z{ zN_@uB0P&&7B)mAlXraVuJdOT?WiPmKKSvX6N4LVM>Z`!7=CCT2#1c|9Gl4{%YyC|= zw!aaPZ^Vju7wg3Q1Hdf<9C1wT9?fl;tqEz_I1rF$B2IAa5_58JJC&@K1x9%p9}$Pq zxahaBk5oby2g?kXjj0g{FqToWn2BR?aWzu^Gsn2$jTad~NlFAm50D0IqnDBfV-F>P z(Xt!FP9+s)htAIGv%nu`;QOS_jvPgVY|}iiI`h71mEW3kQE3)QoU4s*88XfMq&=H# zC14?0UUb{z_EExl%JtyVRJ|vv;n6o)T><<>mKk?oGfUWDCFG_~OsGz?nXd>|iWO&> zK(vq&PsWsx3O`jv;BT~a&G`l@UFMjq zvzJ&0Q$8Wx#tgaAXw{L56rnbPv7Bv^)rfbT;l*QPdn&4{FjsvU_{S{kE-`x#PmH#5 zkd2fL;5_}8gt-4nNH+Ty;V*zv+AWFryhx>gWFRx8u_FL^TMqDcWvd0I+3*I4h*Mce ziO3N7jAmPHtL@3IWopAi&sS6^S!Q(F-X2OEzq0YILYmor9;iyd_d2ks-Rnrig-HFw zDxPz#V>O(nV}4RA4FO9PmmmkX$@0+v5WXI_O$y(FefTmvM&RUsomxcC5%_R)5k`73 zvhU!bec8Ra*AE`JO<>Qc2i<)1uzGMmZl|Hq1$gW3Qj+Y|hcCFBIGfRW^f{ACXxkou UTccjQ6Vh>Z-w1GYgagR^1@Ey#9{>OV literal 0 HcmV?d00001 diff --git a/SRC/DOS/FCB.OBJ b/SRC/DOS/FCB.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..c3000e77aaccc5de47df510054ff45dc87f3d3c2 GIT binary patch literal 1060 zcmY+DVQ3p=7{~u_a_?OtHEXIy_CX1gZq?Rqtr(@=R&SSF8~P77@{%Qqf&nK7)O_=QyQhcR_#3TXvlbh#A>jW?@Fxtjq#60d5wbER7&) zoiCm)8BY|?;OF`&a3FO}1~B^7ddQOwUgMb9ieO#3yqR>R@a_Yj>@?mAxBbXo^2)}> z#b0{cK69f#0`z*4(G}%HMIH0v#?Yf>rSQSp0W`x2CRfLL8GjSiqXd~%^=@VmuH)*Z z9z-Wf?qf?UX{U_u>zBc2#GJD$p|^vEkvByzlvmVYPcgQ_La%=8hj&e%RQY$4qH~Ye zlWNlv0(ZZf^zQiKW>&q=lQze98Vz;a`>ygSyZOy#a;IVXSIF-EY5JWNvxM>?aPqxm za*Ly}voZS7>KBa#a-=H9fNk&Fj*I)-YgtrTf+^KFHT^8AcM)Dd^-yOC)%!bWro>X` zN%yg4iFET^g7NC}R9HmwBI)MK6ux{T28lMCF))E3Tj!95@%NzM0kp>j52HOQIFB|L zoI_g{d>m~_a15<`1y!^T2|kC`4Z&k*^$QN7^|0VkvVRck1j<-KU;L{3+GF;HxJf&z&KB5 za@i@F;YKY+28Ax+ks~7++P!!FTd-)rdhJ#kAk%TmmE7yp9vK){y7}lfu-h$670;E7 z(~C6Xvsy1XqT*iIPH}nVT_8?S$;fj|%d literal 0 HcmV?d00001 diff --git a/SRC/DOS/FCBIO.OBJ b/SRC/DOS/FCBIO.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..2c4e7836a09ae819e3f54ac063f396078bf6a0b6 GIT binary patch literal 2763 zcmZWreM}tJ5udlWyZ6Pneakmz$7EwG4iTiLv2g+iyBODCPIm|R1AHa%+Qz|P?d`gi z5~6E4OULbz5Gi)u>QY_WG_oAGa^+g`N9EAmVxr1Xs?hY0w5sZmwn@)vrJ@9rw7$;U zgMO$I?3V^hz?<(YrSoa#~;C-cXR0d?BAh>J9D+ z^!EALZeK9O1w+0-hzt4JyXC*1v%_Wphl6ZJstb+SNNJwpI8v0~bvlVisgGHPAzerv z1F+l4U%poae2(OpoGr)ZxE$Y+{5jZt-QB$dvIM+O)6|itfRp5Ye+YPaUq}uFps;f| zqV=9s#zMnSjVi#S``v*);J+3;HmoY(+@mNbJI3`f4Y<9-CzM98Q{i^~NS>gwcE39Q zba*!&5m?>9H9XMi2R?E{LxW%sb?pvHeo7o0i3B@C;OdJgYIyfp*tZXyC>oAv!>R`E zU5X}uQ&YwcD~Dk^jc@{d3^1DFAw~qU{wK)-aIVQ{FrOBHvr&mDX=6OJY4W+EwumjR z)hAXJJU>nrf(u;;2NW&by9bKXF5o=y3Ba2GFQ?p=S;1rl;<}l1gCnF4k431qG$r32UXv3W&qY8p`WE@VU4*=In zjiBb4tEFzy*|J@(%6lHZtLUNU}pV3FqtOun~@jq7vmr-)4UV$&>Y zYqo@xYyN@dj+zw{GTZc#e@m*|@}nx&O8w{(2ou{=Lb!9RjfUNEOnLg5d|4#Z+kiVm z-OwG)X#g=Uvxc-@oRW(TNx-GhkVmACv#b+jx*SmOg@na1(XSyA-%rMdV)^ml>mgufZd=mZRtZOcMrx;t2!Ajw%BCd^f{rrGn$IiOu zfX<6wq?)XFHqdxVV*>RT`>HJV2z-H&eN9c92q+trZ>_X>Enc(pw`wj(dM5F zsTSj`HKb}>-1uLez}Ab)UNOf_Yh-$2!! zak%+|38?}@J-F{b#U3d}M*fe+qkh|pv>`_m@S@z9xw;7&XdWF6CU)+d1dMk@qu;Hj zzHU{@rdYE;Hk$kC6d0uyk;GxK6;4-Tk$BkC8*y2%&EZ%soqNP;g40+--qYKVe}_5! zxIi|{;iP8gI;aGW>w>vHfsna_0x2n@rPAdKNc3@YFzp0xkwr&WGV`lRttB3Idzs*8HUJ7{u<)|`thk>8X6rvQ5 zZy;nc44lbJU|T90GT$cf@=O^@xam+s5qg6^M4&ZqJg8XjF5gk*E`jf?@;XDE>i7wi zJ;%b)Jg**q+7xe16r`&5Z%hyQSI1P b05Vg7yQTl$^^ZqJw2|>K0PrRloSXjwf;BNN literal 0 HcmV?d00001 diff --git a/SRC/DOS/FCBIO2.OBJ b/SRC/DOS/FCBIO2.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..4712d7ba3426c41eab3141a3e75a0ef38a6e0d5d GIT binary patch literal 1971 zcmZWqeN0AG5)df$F^i!GFUW@!5AZ>Be>ObUpwP8Y0f$C zoO93D@7&vj2@FC@bDOXJ;=3*YeT$Fxuq{4sAZXU8+Zzn%d3Vrl;(dXgeqU#YzTF)N zvVox6A7q2>=627G_l>Xtz+@sDP-?{>I$|$KEK95ftJzGPRJzG93~55C7rmt=xlEX1OKGk9f?2*X76r^ieX6vT1mI>IkB%G`NePq zkDzW>^dOpPJMI2XFjAN1_yI7)4oIj2W3cyNEFc8olk6p60TjMg2|hTqx+BWeFHfZS z^-8ex)TPt2r_QBjQfE-r;a7gCdu5nkpO{XZo<2R5`Z+Zt^QC)sPbfDM+w*bV&`D$C zjR|F+)p9<5>)Qm#`>Ye4%G}Ug#jr4UQpm%f0L#LhDXtqMAbW4)C;sHF94Z+}M`d9} z4y~e~2&=iv$}L4$$z9f+m4ziabW;&-=Pt{_qDyB07@7j6u1u|#yfj&cC0`=yW{$AxR*o3d$2me&Kayj#u0VJ|#M;{W4)jAj`ysGR z1nY9X<*9Tk9=nV+DV}nfcPPRF&TSwk3-d%+849gJqi|btARzj<$(i%835e@yCzdJ6 zIV7wQ>O!qjRbH4!gHG}09{II?+@)f(A!lprr)1NbGz-q!8nXetj6?@sb zBc>ac>S&y}rTW#3Lu;x`4dd*SFKJ*rI%39c$Nk>of<(3w*fX?&8kw(QF#gL}<_K?W)lx6|3qP^^ayOT7J8FKSxTwq^X+^hhq}G zl!G*NgO<8U4-(r{2XVIJTCrcpDBV!Z)f$dQ=hzc3{7w z(MDU4T)lvRH;khs=~8?iAsj8C#7c>t5}?FD34>&B244ld-<3%NM;xk!Bf6vwR}x>2 zDrA3=`0^3qxE{$c=r9fB~TWs@%0J3Qtewww<&6~G)Q1#QjssO5v zryb~J!RdQmki@=-7-kPQk)o7~xpQ&*6ECVa)3Unyb90KC=TFPk#D$;9FZT&~B N#ruPS!4!k2{tXRpWFG(k literal 0 HcmV?d00001 diff --git a/SRC/DOS/FILE.OBJ b/SRC/DOS/FILE.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..ae7d4d704d3ec90bef6e665914c37e65ed2ef26d GIT binary patch literal 1850 zcmY*aeP~-%6hAk4H($+1o33vk?V363sB>Vq&J3jrS@N=VYm+qZwYJPPWcAe+*RH(0 zPAxb$jIb^N0|OZ|!W*JU#nGW-A1HR~>#9Rhm`MG{KV-r*RixlLx8n2MmsAuU@7{aP zxxe!}ANStlHsGS|9YW7rK>#isj|emzkBO4g{D)$a$VEa@$PtN)dy?_)1lJJ~B`Qjx zq(r6A?haw;j2)T*91hZqv%LsnB{k(4rNmp-I-O(-n*}Tu3#rA~5P;oIem(02n?VeV zVKq2|8n$r$BG7?OSxtirJ*L7*AtVXlHRp<)R^?PoehCN@|fy~ zhr31aMAI2HJ|>S!=|hKQa14q=X=Qly1+eam;+}nMDTAF^>>eKkZp;)X%PTvMsb`}J zu#0I`RfZ3NRm5F(X=peTj)>)nIH-aXjZ&hTR#dp5`G5jk=)d z&!XFS!s+=ca0mm+uqs9+cvZ6ltpc=87j2LwJXv!-??R8!SX7Z^xX<)nrth!l>po%t z9jgFGwRJ#in1Qk;IN1mgoO}jwZ7+Ti^n7fuWi%tlFbM zA7Ka?>o5P^Uxv#e=9ZHib4#BCbp2LrHX+w$Z5YwVpjYw4tylYr+X8wWPn`M&=4vxf zs@n5za7s#gG?PfHLvT|&0CXSoav(T|9j3T~$C0R^(rHU6T2sk@v@Ej5~ShVvPs9{_!K4$V-r`uVSUY-zrBTIH0 zTedS|F+Xv&fG#4x%XtsD#8)z@q^zdm`{8XZ0Q4MS@CW8O#AL2+a7M}Ups#|TC{~;J z>&pSJMUW5kUZ`3H5flYnT0PKD8A=ycK6nF(*>HhrOLXOyW{V9b!Umo4#G<=+;>&t5 zhgG20V7B~uAGrU`mME)mMr#IoizTeDS83$~X12z+GFW~aQL0p)P02JV&2<**Oze8b zj_7{GX3^U&<*UK72V;y5AC^zWtn3NxIHaHV&0*Yt|@#`p4d;75jK)R1{H##I>}*R}$+5!|70r9Y>wrP~-bM$aNp z{wP;_+{*_p+EB7sNk^mZ!|1a}xt_HS$u^lM#my?j&UQpTEF<=uwjb!W3ibkGFLX5~ zZGqf!89!)X#e#2QKKcWF%GHXmg|1caijnj`?+tHe`uXqIv?M1 zN-%OozsYfv?&OIz>qY{z5M>0|aS9J9;gK;ot@(j|!3e0<>F1^v^occO=(hD$qr?}H3xH;=WZYN0AR~{O0m>~MYJfSRs>$AIfvVomL zhaSboyjk!8p$_)aw6ts&&Jwu(KZ%HvPYN|?dpqNiuK-q7*X(`3(!WutL%p{tY`z!xT(Dy>L13!Dquf`KOY+DVQ=s35 qf*TdIi9H7Z@NU72OM6pNh=n?ZT?9fEL3ga9J+{AwK + +stdin EQU 0 +stdout EQU 1 +stderr EQU 2 +stdaux EQU 3 +stdprn EQU 4 + +BREAK + +access_mask EQU 0FH +open_for_read EQU 00h +open_for_write EQU 01h +open_for_both EQU 02h + +sharing_mask EQU 0F0H +sharing_compat EQU 000H +sharing_deny_both EQU 010H +sharing_deny_write EQU 020H +sharing_deny_read EQU 030H +sharing_deny_none EQU 040H +sharing_net_FCB EQU 070h +sharing_no_inherit EQU 080H diff --git a/SRC/DOS/FIND.INC b/SRC/DOS/FIND.INC new file mode 100644 index 0000000..4c8610e --- /dev/null +++ b/SRC/DOS/FIND.INC @@ -0,0 +1,25 @@ +; SCCSID = @(#)find.asm 1.1 85/04/10 +; SCCSID = @(#)find.asm 1.1 85/04/10 +Break + +find_buf STRUC +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +find_buf_drive DB ? ; drive of search +find_buf_name DB 11 DUP (?) ; formatted name +find_buf_sattr DB ? ; attribute of search +find_buf_LastEnt DW ? ; LastEnt +find_buf_DirStart DW ? ; DirStart +find_buf_NetID DB 4 DUP (?) ; Reserved for NET +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +find_buf_attr DB ? ; attribute found +find_buf_time DW ? ; time +find_buf_date DW ? ; date +find_buf_size_l DW ? ; low(size) +find_buf_size_h DW ? ; high(size) +find_buf_pname DB 13 DUP (?) ; packed name +find_buf ENDS diff --git a/SRC/DOS/FINFO.OBJ b/SRC/DOS/FINFO.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..ac03fb15cafebe69da27f24d66726c2f35642854 GIT binary patch literal 777 zcmX|9O=uHA7=4puHoMs*O@CMvw2FsP^dKmT7sbu)CJn}H*qvy!N(ePJrBZ9NK?M&z z1)cltgz=1%ZsYXdONunRZYa2nNabr%`Y{()0EFy+DulIHhp~oRTx*xdb9w zo@s_rkQJ8FGYI#o;tXK!v9zw_Oz@f8X30`#77%0;DN|9+U7#A598juQnUaNPtpQNr z8&Kie1B2_wJFLl}MkK<&X@ntYQwuYWM`adYTVYVqRler{@~|m-GQp-2p&N}5g2|GV zEm~!~ZViJDd!ED9aOi`@w|&@F`@W&J>zm&5{oJ|>dc;+C+J1EZgtqSe7+oF(>c38Y zsqfU&Ql0HPv9+X%&tp}t{@_6U+UTLb-HjKUJ!`}p#VtX%1lkna9XAV~ZAYCjlP<}6 zBDd?G>@J74?sIvEbnX1d<|!|NXvc;K@xeYLk$`0hi67Vp!ib#Ddo4!!^4{}4 z|L*tvp67WFcz_>~HC5I=I6MTvN{O({Nr||swK%63*HktvYN98cP)C$RD#^w~RpV4m zR5VT#hhy^fx81M~z~dq7P#VP~E)r-+97lW&YfB61r_wftVaPd@rU2Y-^5+pB@HVj- z+hwyhXY*3A3?3=0N_%p<4e+F=)V({6^c3piniPqNBhV%#QgKb0(4}y41b8W>gq3mN z!(*Zt4g)W5(PTvdPve`^puHjKqNGI=acFB^B`ibz_ZCY?DHZrJbzD|daBEXLrx66W zQ>v`QQ)9rRJ`x*&3zYzH07B4Q3t;*H-T@dWcY?)s5+4JWM<71SE0DHAF#x_D8AH!a zXR`XVu{Hey9IU(sTs!;$Ff+-_#Ml|OHdFzq^^u`>@e{HQcJ|_cz1FShLNIUJ##Zk_ zj{63nK70~rSawVP7UVXVztlsh-8h*x&YBkn7pln>{x~LY6 z<2P$_c755LOk>Q6URXNT0ASYcDL()OB9IQtClJ5YLyw0A!WJIwAe;hL1ZC^xPQvbh z!a;OXi|x>=PN=#fYkFcctgdtccNne#oFo+9^b(ff@|N43tbu~tN%LjV2i`kTv^8fd zSAlz@HnKfEkjIF(O{50UuV@0(XS^ym}#fV_=b%squ6saWdK3oPVV3b+Y#q zS`p-u14tTnI!}9eyYdKdU(oofZP%|3(RCQ2`#=-X;qIsn%?PL~qMM8@x>*9_u;U<>#@%gQik?Wy$|?pX zOI@gI>q9o=mkepQk=^$(z^YO&Y6DGeX7~2Yb~&5flYNqbS4y2|@=_B{kF-6xBSc`h zv=Wt_efZkzVL2kEV)#{}nHn<5J>G?nGO9TQ<*p6*XJV!um0;8I{fiVo6X#%6>yMSTSmu49N F;~zBb3?Bdh literal 0 HcmV?d00001 diff --git a/SRC/DOS/HANDLE.OBJ b/SRC/DOS/HANDLE.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..4ca2a495741043731ac7f8c75aa5ab2961a9ea27 GIT binary patch literal 1642 zcmYjRZ){Ul6hHU1_x0bpty|ZD$`+tLiG+X~K8B@1Aq+K{K#Do_=3IxO|icFnU8i0eeIJV#K14p8kkv^m!s4vo9oW3x}cu#(+nR zU@_teM{vZ`9T5I`&jjlL%x1KXSUm*9fE*PIV^mw&wO9~Gtvw9Gpl^va4q!5&Ki;ne zRzn)288oAYHP)Nk307}XmZd3Wz}F3|FX-`%jR6fG3rizoV4>CyIj%@hBMe1^a5xqS zd7~nj{3G!RL6(8tE{>1L5||?6@r3A)fGL`go{H09>jQ zDOPS)VBB{*_A91*(Fti(kMICfwz!bFY;Qnj1~NGZ)b8Kz@Au35CVNJv#wH|qrep)$ zN&&gcSQ{>~#&*o|>JiQb95)!zn7pI5Cr@NM_UbZtiJ6Oe66GWF13-!SVB@^Hc z@H;?P)urakTrJohxlnD^k_+%A>O(~|J{Iv@ait#Ho;FsP*HGs5I`bcBAbM@yP%zjV zflw(1xLZdso*q|kt9RP}N*B1xVQpDwWW}Hs3~vW7gGy$pBt}UnYp92Mt>>VbT+l+6)uF%oMI0TkQtplU0qg*l^|rv$R!FY=pV`NZ(x`fuj6<&(N+ zs%tYq(jIML^DGZ97wh#nb!9t=Q+|OAr*bwhyM00>TyNv^#)mC$jaYbR$!jK3!Pg*!JV5RdGqXQ$9EeO7t~KW82PcVyHx8T>wL25 z0hbNhxoouVAq5W@DgK9z#b#ZdqfEr$be~Qxz1xKx9W;N!C~0uox^I-$0M;liE<;c< z(Yp3|UL!Zm%}Ds7#?1sVZ2h%p*TEWSy_;Ty6om*pf;d3CZxurz)En7_=c}#N_*u>h zCcT>_2@Iu1z;5azH?uo-w;rLE{bm){nYQWt=IFiAKJq2^$9!>F8dYFJX*J+>dXoIO z*;R+0Qg5lp#KG(mneQATgZiVp*rfAoN*iewolc^7C9&Sh)j^Hu|KEFZtMmkrXNR0h zpoIbcIDywDt*#YP* z)RMW$?cFyy8CTi?-YM9~g3;}Z4y<9|*+LDOVK + +; +; Current structure of the data returned by the international call +; +internat_block STRUC +Date_tim_format DW ? ; 0-USA, 1-EUR, 2-JAP +Currency_sym DB ? ; Currency Symbol 5 bytes + DB ? + DB ? + DB ? + DB ? +Thous_sep DB ? ; Thousands separator 2 bytes + DB ? +Decimal_sep DB ? ; Decimal separator 2 bytes + DB ? +Date_sep DB ? ; Date separator 2 bytes + DB ? +Time_sep DB ? ; Decimal separator 2 bytes + DB ? +Bit_field DB ? ; Bit values + ; Bit 0 = 0 if currency symbol first + ; = 1 if currency symbol last + ; Bit 1 = 0 if No space after currency symbol + ; = 1 if space after currency symbol +Currency_cents DB ? ; Number of places after currency dec point +Time_24 DB ? ; 1 if 24 hour time, 0 if 12 hour time +Map_call DW ? ; Address of case mapping call (DWORD) + DW ? ; THIS IS TWO WORDS SO IT CAN BE INITIALIZED + ; in pieces. +Data_sep DB ? ; Data list separator character + DB ? +internat_block ENDS + +; +; Max size of the block returned by the INTERNATIONAL call +; +internat_block_max EQU 32 diff --git a/SRC/DOS/IOCTL.INC b/SRC/DOS/IOCTL.INC new file mode 100644 index 0000000..902cd7d --- /dev/null +++ b/SRC/DOS/IOCTL.INC @@ -0,0 +1,169 @@ +;; +;;%OUT IOCTL.INC... +;; THESE ARE ALL THE IMPORTANT STRUCTURES AND EQUATES FOR IOCTL + +;General Guide - +;Category Code: +; 0... .... DOS Defined +; 1... .... User defined +; .xxx xxxx Code + +;Function Code: +; 0... .... Return error if unsupported +; 1... .... Ignore if unsupported +; .0.. .... Intercepted by DOS +; .1.. .... Passed to driver +; ..0. .... Sends data/commands to device +; ..1. .... Quries data/info from device +; ...x .... Subfunction +; +; Note that "Sends/queries" data bit is intended only to regularize the +; function set. It plays no critical role; some functions may contain both +; command and query elements. The convention is that such commands are +; defined as "sends data". + +;*****************************;* +; BLOCK DRIVERS ;* +;*****************************;* + +; IOCTL SUB-FUNCTIONS +IOCTL_GET_DEVICE_INFO EQU 0 +IOCTL_SET_DEVICE_INFO EQU 1 +IOCTL_READ_HANDLE EQU 2 +IOCTL_WRITE_HANDLE EQU 3 +IOCTL_READ_DRIVE EQU 4 +IOCTL_WRITE_DRIVE EQU 5 +IOCTL_GET_INPUT_STATUS EQU 6 +IOCTL_GET_OUTPUT_STATUS EQU 7 +IOCTL_CHANGEABLE? EQU 8 +IOCTL_SHARING_RETRY EQU 11 +GENERIC_IOCTL_HANDLE EQU 12 +GENERIC_IOCTL EQU 13 + +; GENERIC IOCTL CATEGORY CODES +IOC_OTHER EQU 0 ; Other device control 4/29/86 +IOC_SE EQU 1 ; SERIAL DEVICE CONTROL +IOC_TC EQU 2 ; TERMINAL CONTROL +IOC_SC EQU 3 ; SCREEN CONTROL +IOC_KC EQU 4 ; KEYBOARD CONTROL +IOC_PC EQU 5 ; PRINTER CONTROL +IOC_DC EQU 8 ; DISK CONTROL (SAME AS RAWIO) + +; GENERIC IOCTL SUB-FUNCTIONS +RAWIO EQU 8 + +; RAWIO SUB-FUNCTIONS +GET_DEVICE_PARAMETERS EQU 60H +SET_DEVICE_PARAMETERS EQU 40H +READ_TRACK EQU 61H +WRITE_TRACK EQU 41H +VERIFY_TRACK EQU 62H +FORMAT_TRACK EQU 42H + +; SPECIAL FUNCTION FOR GET DEVICE PARAMETERS +BUILD_DEVICE_BPB EQU 000000001B + +; SPECIAL FUNCTIONS FOR SET DEVICE PARAMETERS +INSTALL_FAKE_BPB EQU 000000001B +ONLY_SET_TRACKLAYOUT EQU 000000010B +TRACKLAYOUT_IS_GOOD EQU 000000100B + +; SPECIAL FUNCTION FOR FORMAT TRACK +STATUS_FOR_FORMAT EQU 000000001B +; CODES RETURNED FROM FORMAT STATUS CALL +FORMAT_NO_ROM_SUPPORT EQU 000000001B +FORMAT_COMB_NOT_SUPPORTED EQU 000000010B + +; DEVICETYPE VALUES +MAX_SECTORS_IN_TRACK EQU 63 ; MAXIMUM SECTORS ON A DISK.(Was 40 in DOS 3.2) +DEV_5INCH EQU 0 +DEV_5INCH96TPI EQU 1 +DEV_3INCH720KB EQU 2 +DEV_8INCHSS EQU 3 +DEV_8INCHDS EQU 4 +DEV_HARDDISK EQU 5 +DEV_OTHER EQU 7 + +MAX_DEV_TYPE EQU 7 ; MAXIMUM DEVICE TYPE THAT WE + ; CURRENTLY SUPPORT. +IFNDEF A_BPB + INCLUDE BPB.INC +ENDIF + +A_SECTORTABLE STRUC +ST_SECTORNUMBER DW ? +ST_SECTORSIZE DW ? +A_SECTORTABLE ENDS + +A_DEVICEPARAMETERS STRUC +DP_SPECIALFUNCTIONS DB ? +DP_DEVICETYPE DB ? +DP_DEVICEATTRIBUTES DW ? +DP_CYLINDERS DW ? +DP_MEDIATYPE DB ? +DP_BPB DB SIZE A_BPB DUP(?) +DP_TRACKTABLEENTRIES DW ? +DP_SECTORTABLE DB MAX_SECTORS_IN_TRACK * SIZE A_SECTORTABLE DUP(?) +A_DEVICEPARAMETERS ENDS + +A_TRACKREADWRITEPACKET STRUC +TRWP_SPECIALFUNCTIONS DB ? +TRWP_HEAD DW ? +TRWP_CYLINDER DW ? +TRWP_FIRSTSECTOR DW ? +TRWP_SECTORSTOREADWRITE DW ? +TRWP_TRANSFERADDRESS DD ? +A_TRACKREADWRITEPACKET ENDS + +A_FORMATPACKET STRUC +FP_SPECIALFUNCTIONS DB ? +FP_HEAD DW ? +FP_CYLINDER DW ? +A_FORMATPACKET ENDS + +A_VERIFYPACKET STRUC +VP_SPECIALFUNCTIONS DB ? +VP_HEAD DW ? +VP_CYLINDER DW ? +A_VERIFYPACKET ENDS + + +;********************************;* +; CHARACTER DEVICES (PRINTERS) ;* +;********************************;* + +;RAWIO SUB-FUNCTIONS +GET_RETRY_COUNT EQU 65H +SET_RETRY_COUNT EQU 45H + +A_RETRYCOUNT STRUC +RC_COUNT DW ? +A_RETRYCOUNT ENDS + +;********************************;* ; 4/29/86 +; CHARACTER DEVICES (SCREEN) ;* +;********************************;* ; 4/29/86 +; +;SC_MODE_INFO struc +;SC_INFO_LENGTH DW 9 +;SC_MODE DB 0 +;SC_COLORS DW 0 +;SC_WIDTH DW 0 +;SC_LENGTH DW 0 +;SC_MODE_INFO ends +; +;SC_INFO_PACKET_LENGTH EQU 9 ;LENGTH OF THE INFO PACKET. + +;SUBFUNCTIONS FOR CON$GENIOCTL +;GET_SC_MODE EQU 60h +;SET_SC_MODE EQU 40h +;The following subfunctions are reserved for installable CODE PAGE switch +;console devices. - 4/29/86 +;Get_active_codepage equ 6Ah +;Invoke_active_codepage equ 4Ah +;Start_designate_codepage equ 4Ch +;End_designate_codepage equ 4Dh +;Get_list_of_designated_codepage equ 6Bh +; 4/29/86 *** End of Con$genioctl equates & structures + + diff --git a/SRC/DOS/IOCTL.OBJ b/SRC/DOS/IOCTL.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..afeef941ba4524d3dfe06ce1d9b4909c59de9430 GIT binary patch literal 1814 zcmYLKYm5_B6h3#_JJarN+wCF)qS*qGh7iJ!N@^gh(rsti)!Htd*`@q|N^o%#g*EMz zRima$M&0e!2Sy2)nw0es{2{4|LgFLDz2Rj{eEcDzh6quxzC|8C+;}0o?I)LgVptN;kar97`FxI}tNtoqQV33pyI-%Ib>Wno`r% zbT@fZj#oB;tUYRK`8>2~SwqWYa>;ajKnEG4j3tv4?R{E;KJ|FYpwDb90ZO`GOLY(Q zKuc!G%s&<%DQ-8xYwO98kw-u=di(TvLWhmDHsAo2AJkBnYcxMz2|%0P(~}?B*1LK8 z0}l_unOZAw51a=m@VXqS%3v{-wH~VYp;h0Y=Q5g+!>Hh7Z3XZETma~j3cXzrE^FNE zY`J7AbzkEGF7GdySC7g_N9klKJU+mCs~t8}n>D|k@opv-s!Tdu@j=Tq*z~<{OKlPG zRfI}MrN}u%@!2S0@uU(i5An$_PgUD(AfMofAlh;It`Y?QgF|MnSQyIZ3g+f555dmb zoxlg_A`^z(I32#M@e&kWv(RqBi=4(U{LLJnIo{>k@o$%02pwe0-KKQV)xWj6(01du zf=;}1(UBEG{UWm#qxgf}PtmVMLi*AO zXCM`aeYGEf?;+drnR>G*%^YbQGL_{@(d)!yhh>L5bKD%k(Tbz9OB($Nckoo+#0x>G zIDDO*M!@E*^q;4wqd_r+S9Y%fvqxS}8}n$IGu{a>z5<6IdBKXGxC@8s=pO;7%BB$F zM<;N*^=q>=N_$Q~b>>Kd{)eE!V>Y4$8mRlqXQQtJ+Lm@UQ9#n}Bxf zCL~~-S@Tfb!>k1;x|y{I#of$WiQ)~(x&zBhBq*h6Vmgbf&q`ugWiGL;gSjLSc@zx9 z4ir8RkE8H|cnU=T#7-1J5YM2P1EP##E{Nywu=O$mMI^CTWnM9*GLQA9%6!&-T>YL| z@2ITJs-upXdf)N*8JB9)@sm%wzgCQN8LeYHyOF(+p z`_1{r!Sb|cHt#{9*yoSV)(JIXA~OgZYA1k~>1e(Wr|{%}yL>7tFcrva97?8p>?E|S zp-%xy)3Nbek0sb@I1H{UUo0!omSmf?+h!#MpaMTo4>*NUaM$I=Ma1NdbIwZfik+@C z=ATsPrb0PuYj6^-x>`PKXAY++M53~oEr;uQL=Vx+XpGe+(@h&MMJF-Vv7ehTdF+Gg zn4RJdOGf&#k_f7-MJ!gCVy#t~-&#im8<<*a3+`jmw>m6S_K@WISxfxWQ`Y^IGN3Uiop(W^*N@w7`+7$4# zgm+j$p;!9L)2Qc{L{8iHzd<@a2wKs8You^_Bg4;*D_Pq%Ag{k+mQ$v)P9rpG2vod8 z++vsgevR4r4zu&9DXuYloyyKZJcIQzOXtVYn%!RB>ZncP9D3524lHxaIS(RE^`?&_*w7VJ``92?dhmpZO) zyVTWl!`5Hd<2V7RDmfw0phyxWz59q#lHQLd5+p0pSrUnmCjyNF@i_VO(=?QT1d$*b z!~z;9Mr#p@?z;9+4ysYFjd~MP??N#ucCM0#Y7W_9WhmxFT{lhfr7<}PSg>12ZtQFHw0!m*8%n=BrfO6 zRmU5xdpPeO1qJvyU@iz6%G$x+Uryi2KD7+Yddk`h^6l-m0v=%`)o7)Vu*T{WqQLZf zxbLSx58)B8p#bDsJBcP?q=!>Rl0UUH#0xdAJnD_(TfYzVxMWWEHB#Eop1PL7-^WB= zxuN%KnRoc#yubR(pl?d{owX=-o@iS$+NP)w1kc1Or7nnRuDp6-S>nQXz*2VhT0k2# zyI}>}>l${Kd|dcak2GwD*>fYa^={+^v{Dnl6vXXO|XBBrAwJ3D@7^aobu=)<6Je|NR@Pd3o=|Kt~suh;;uiQWV$j8{p|;Mg)?!CGS{Oek25s=Ocjk E52iUd5C8xG literal 0 HcmV?d00001 diff --git a/SRC/DOS/LOCK.OBJ b/SRC/DOS/LOCK.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..76c71a61bf3f49e6886cc3036b0682ad307f2f31 GIT binary patch literal 669 zcmYMyPiWIn90&04>++H%?P@z%tl;J!wCo_$(?A?TmZr8gHZ$*S-Pj?HS(!{XsTtxy zDB{T$RuG0rk$UyC<2M zf^Ovus#|5o<>;xEITLak*9LPIyJB0jGlHoxP8rv1PPsO18o!@Q7zYLi$#{?o0Wv_+ z{X{8A_IG8OWW%(DSd6?3(h49+Wg}_3`sLht77CJ8uQ$+Z6x}u z6SO(YAl_mtOSLM*tNm56t8VR~zP_>MLgIxY%gs#p1Iu&V=*XbJ6nT)STxuRcg5~qI z^}B_owVQXU_|{2)QtSiwQ_i-y+ZOSJs6>9#Od`$}m}48<30v6hTmT)y0WkSN1jsh& z{ZZb{yQA5^21VVKXLjQ0Pv;kVbkZLSv{>)!W_vio6i-yifR`O6^f+EOhoD4o)pe{A z_B!W4FNW@aNQt2R2!|cgC9l-V!uEXB%_zFYQ#MCA_psh^MMV`q)$;6*M~+4!zjP zfIbeL1xGqDMclo^?nM1EfUeMvN1qOPDU}HCTWJug=quIb)#y?-fuH?a_-i?O!O%+_ q7-@|J?&vUwy=pBuA^9{0xc>kEZ?6FW literal 0 HcmV?d00001 diff --git a/SRC/DOS/MACRO.OBJ b/SRC/DOS/MACRO.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..268e9a904594c10a3ad96eb68fb51f99ebe6cc5a GIT binary patch literal 1002 zcmXw1O>Em_7=At{{z=+8%a|+>QnE>FHi5M&o|1x=o@Ee?7N@H zI1MNYJ5A^u6^XI*AreKV9!3)hmW$8=69o1np;bVZ+3%mJkov4I^ke;aU+ha}YZJ0* zdB)OG0EK|LS>FgDnf1U5wjf)D$;pyYB;cMsXB!q2tG>SeCJ8ZYSA4r%uFg2-tOw;4 zZ}md3wy^@KI8PZitvO$sEkdND;6V0Q*J@Fk))|2axVxG3?Z*~^*mP?INpIe(mTkZ4 zOyl7WIh4R}z)L$48cbs&-?mf?{V$=G_@VOw#NkMz-yj#?J?MwYiFloLZ-fu_{@U+; zGvSWq^(Q5uqVs2g+)djAf~Rs#(cOIkxuz{ta+iuG@)U7|C|($-rfIOu+?eqzsg+!_ zZs%GrPAz6DU3ZLCf^>N1X>scr{d+3RzGBoqBX9q!Z>zu)JC6)zRk@@wk)P1m5I?1{ z;l{!dCZ@pO(wN-1s4>q99HYK<)B&%FTDIJ-s#+e_%Wz+b0)53uK`z6 z`1|tXdsm`0o77|bt|nh6d_e7cKfAkGGVuAD(A(?%6wP}%GdFPKzGdS0VmAD6znk2v zOL_-5*gLpI(P(Z#zei_3JmE^`^_v8#AlZv}v~%u0`IN89l~C*wzM68lqc(lzL<3>m)gPxsNCa9~D?Cp4C59HT4b57FBEIQ{Zb zjl~<|WXm1!JXyp&jm7vP8N`<~rtr;(dtGA^-#W^M1vK6!?I;@C^ciRT(@6M*#svPQ z#u&dEsjm%$opuULR3-~0t4hx`1^m%IM$E|6a!4<4GT25 z*FHjAg1ET>bsLb{Dp7J_V=YP_1-@$^C1U8LQLC-3Y&fqi2jt$F!^D%bbd?eH25{+p H0SNyC9W4(K literal 0 HcmV?d00001 diff --git a/SRC/DOS/MACRO2.OBJ b/SRC/DOS/MACRO2.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..747644a98317ce8641b73c4b48a6f65eabe141c3 GIT binary patch literal 2725 zcmZ8jeQaA-6+ibqKii3&&o-}X)5aMermR`orkypCmDPE6veGopV&`LO6XPW>bC%Yz zo}WWoN(swbrNz$31e&H{n71($yiD~ULmC<%20vCJu?g5TB&w-nXc8rXu~v|zg_?8T zGnIy9oqON8=bU>!e&_hk+QE9vEAtV37hozaRyAgP{t8dV51bi_aVK+I@jw zcYk1@&(h-!hJ;|q+aD4_-p(HXwP$Rw8^CU7yK(mb8sS-;xf29dZJt(CFgNYq<~fdy z;w}ncv$4NETMgC{D{&>hWGM+HtCZHjE=40s=uBJ&VeFW!M!+d06(#JORKot)I9UCs z)h?+M>=Qwhn~XgIwuxZ;f8YHe<P5$_l890-5fzU$AN(++L0ed_TZ`{l@Zm`a=?nF7fy zmu0qGBr83)t-PCU0-;C}dA?YV{dF1t_EWa)1d@Ci}sWlirPgCjoB5G8M zD$=Pqd@I`k!h2-p!uv>)uJ-qnjl(Z3_aI!T>J6F|$+ff{gaIj%km2d)X3Y7)5 z8kf|ST=E~dimqaA^~Uh*eUP-|xy@qV!1HAXM9ofyYK;s%oUVr&DJqXm8R(H`s0$Xd z%^=iMfkuWCJI$)%hlyO=t~p9FM3nRbz+% zewbv#wow<#Uu_!n{0ecDy276b5aM1c=W7S`m~%N@3AV1XJFjIAGT}HW2l6M}_xejJ z%LPVV_?@i79M-08F5_Ok(Tg8^{zMKxl$Q~v2ur$xc zAIt7_zXY=?EB@JmI_3`{LYE|M9sfye&#hkXJy5vUlHB2*{aUF#Dd45^dTyhL5_w+b zsCu|nZn)#wd8B z(UM+H+eIL{%K(wyMs0>o>D0b}j6AP-@lX#?gAUNqaq7Sb9$^PQLSjjg)oZ6kwnh7@ z$hK;ak*)9J`3kRH#ATGzeu>LbPJ0U%yzCtkxI*M_L^hE;E*eLV-)SsugeDqXAte$^ zz`NOlAfz}9qGQIY-fs?|WbNz+%mX68*Y8eRDu1u;#o$EO&u|)@ucUy(-_GnXg50S) z5X&^0Io&NXn|8Oz>fSD6x<`&dRrVMNuao^Fd@tA03kgSRT|ZBZja3KLBhMviOpXvj zpPSREHIIC+Se}HBdP)c-gES3>Z3hZBGrNt8cWLz^Yt*)5Oqhxmk?qnCip-(khe^}D z^~}k^Khw2Pg?)pK(4|bDqJjV2>>LOd8lTG1TZMI>1kLI-3P|O{t5*r6Nqad3AEnl< zt}q^Xo(FIgPTToQd*1N82tb3P4EH(RGP}Z7ot|&v*fz+46{EfMbAEHUr}3aj*!j7E zXo@kxU(Gyd#L#4nmOQUFc9$ z=nCyCs5cJn)cV1Pg5iEy4f_=ZzC>eUj=u_kWfQ4ux$+;POSh074%fzOG*$nn6*vl) zvu+TcB&D_j#;N{s_8eg3_Irxsr_9>GyGL3xR-+w)0r}(ds>yE5(no@ zZg4CTGyj+($_fu3ndX91lkrY`A{^!5)?yW!vzo7=H4c3+f*>bNT%y-YJWMS%pjh=M z*!y!lcua#vyV7F}5oiWsaOmc7fZ?(-^)#`JXIUKJA=Ag(qWD;g0(@$*4zH^G% + +mi_INT EQU 0CDh +mi_Long_JMP EQU 0EAh +mi_Long_CALL EQU 09Ah +mi_Long_RET EQU 0CBh +mi_Near_RET EQU 0C3h + +; xxxxoditszxaxpxc +f_Overflow EQU 0000100000000000B +f_Direction EQU 0000010000000000B +f_Interrupt EQU 0000001000000000B +f_Trace EQU 0000000100000000B +f_Sign EQU 0000000010000000B +f_Zero EQU 0000000001000000B +f_Aux EQU 0000000000010000B +f_Parity EQU 0000000000000100B +f_Carry EQU 0000000000000001B diff --git a/SRC/DOS/MISC.OBJ b/SRC/DOS/MISC.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..e438f6421d8d216a2a99faf1c6091406dbe870a0 GIT binary patch literal 1575 zcmYjRZERCz6h7~5@9oF>wJ|PV(haSbC5zK+xF|;B?fq!Wy0+=PBcNzmpa|hZQd<2( z$iV(syQcP+QBpz^T%y}B8%7-=0bDN>U6w5H2PGzGh$2KIkZk^tUC-?ry0o#_J@fMt54@jzk660H8 zd!-3z2JQk(x>Md2Wd^c@B~9NH9AFbeN?#%rk)!Z=r3GlGfl4h7a{!kBy6@~Qd+K0^ zW?_k0v!nQ_&<|R|OX| z$$~!-M?WbZhl`b7pgZArFnnqv1yE2u)hG4kQVcfFXs-cqi;@6CnN@F>eRV>vteGWF z&BhWY>oK&IEU{*v#psM=bRBG{9lxXN*mC-3`EL-B6ol)h_3F-)k(d|woU42sy5oyoMn(xb`4A1 zy@e*Q%HaVeh=T;G@-xuKj1U)eJ?F(B_`8CSby{!FiRLStUU`(ZHI&Ss2%FaR>GtNi z=c^-+Kd4b>$4BNTmadI0UGBc~8Obn9+Wg)73wdoUe{*zVEdTe}@hSSoy`X7k02%*H*uY^bMa<=_Qu`U@#y4g@>AI2n(Wo}YS&c; zK<_Fdv90&*NTIl+Rqv&sIMcH*vUGk39*v%Fg-ff!d!=_1Jo>b)Yr$|x_qp17Zs85H zru;&EL@k=Ng;*%i94xVDI3$wA(KKtPSwd-}EHP!rjls?1@j<~24n>wz?;Z>e9@>2% z3AZa7fqs)<`bjs9eSjDO8!$!I6L}>*O+R@lBLQoR= z92CrzoM>efN$r>VM+y8|+JNV^J|Qmgs+5Suqk^Ph3vpv6{Nbq3*FoT5sRc1jzWUyX zOX&MPz-Y;hMypTE98Ta)TT9^U(kirge7J=Yq9pSJVf>HzWq_RxZ2czY4+2~-v50lo zvGu)|ki&eS3*h21>&8U_H=nW@;AqK(aElL9W5g)~woFM0OZ*#>JP;88;N?;)qMW|} Njba$L%$Yoj^uOG)#}EJj literal 0 HcmV?d00001 diff --git a/SRC/DOS/MISC2.OBJ b/SRC/DOS/MISC2.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..c0c1c3099754c587755694eca4618c26383a555e GIT binary patch literal 1225 zcmZWoO>7%w5PhG$KmLiGq?C=|5Q{2`dcg?O1{9!@Sv!t}iCym|byZ@^Eej5563bo_ z`4%ZgD7Gamfe=DI7`Q>jfeREQ+OS)GR6vv);u56-A(T@^2<6aacDJPhq}A-3w=-{M z_WNc-1piE0kz>*uQvfGt6G>jq&MB(jvGF-o;SzB*?n`8qR6aYO<1%qY@jO%X={pN}0SG)p30HtHgtXJPlN-_Is(6lWd}vok7yD6-$)3PZ4%<*~dLXYrOG zch5pd7Sv=ukI+oHu4k*-s#-pKUW4y>rBbdft-b(%UejyM%-UKNLrSxrUR~1N5K*0_ zQ4$Ko`MOpsDLDjggHmkf4ym9q2!aO|PUSBA3S8>@(BelJKaI_92!UK#ugH~}yi&z$ zgGa%OprH27WSdVBpl5og!38cielC=XhND2-dqn(RAlC+e6^sx2<7hF71zG_|xfQbU zxQibkT<8WMrZhdH=`rjLE`Z9Dj&Uk?(XwKfZ+viYtxz)Df;K-cM8sDPjHy2az-k%NnZe7$??^zNUhjrq==(kTkjcI2@lS08H^xtMkBy6h#Y6WJ;XXBIb2&N#F9 zxqzs70@$=H-9LGdl(ErZ#=b$2$A)nUh<1`(_v+(@?zw4v3Uq&rZe_XX*1E^|*s^Y3 zZEt_sKjsVjYZ&Ii5KwF|YZM#5i+VVuJay#60HfWQtuM_=#*TIfv1~ z82DXh;HX9S&M`D*=gP(Yn4>*piV_peA&L20!=&qFk**)YL`F#_pT@U?C&BOA`O#PD zhd9QFzD?*|YWOSL8lRDOS5M}@G!N~XTb=1TER%g4tFc>c;6up+wRx`j#Pa5H0&nB-gR!$7k)N@)SQRtfE; z%u-!H#8B=9iR04Go!1tDjovVMzI0ugQRg)MBj6i1XD*|ZQc0Co?+J$e-UvncZO)lB z!tml<$~l5xfcIT3JIX%P9Z+6~@&vmd+8*H6UBB8q0(}3EPxI3q-0mHw_>i-_iKTkA ste>l_1E08asajp99^V1>dP5Y)H{^0%o2FxR-GV%u$}Ip}Z4aRT4TIWR5C8xG literal 0 HcmV?d00001 diff --git a/SRC/DOS/MKNODE.OBJ b/SRC/DOS/MKNODE.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..7b2d7b2df2a9b73a22b5aa53933fd7b3041973f4 GIT binary patch literal 2351 zcmX|CeQX3F_JD?=oQg83Lj<(p;Y(7ff51S9j|y5rs(pAvw1KqQ0P{ZQ z6zO#LzVAIBzvuUSyt7u|29HFd0rASKJpdLzTTy>BA|)D(w=a^AECFA_XAMN9{&;jK zW(oVG1eFrLc!DN;ePQv=w|VFSuv$qMTMaNHX3|_=QA(WkzYPtWfJ3S+M#u>6AQm z`Xq4vT&6E~0=U3bMoLeB6~A&SBLgpBqqunU>NrvkbP#jEray1TXm#iFl|FY|Jqp#-_8t zCnl$|fmk0~41^>pm;lFcD4rPdg_F^k7y&vweJT`ysOkm^@I8Rf)M~QnUS;mH0FX0n zRg?|@`*oRmOD@ofKpJ$1K&<*M_Ik0{09?PA5TilRR0q&K@E$uA~3_h$u<71WH&_Hbe`G#S+SAf7ZZU{T#EY#;2Bi_`YA)> z&ubh&tyVoGAtu7`poex;bLuXESbkBo0u5!w=@W2HeGq6Ls*PvbUSi@$V?$Snr!WkP z6F{l1ZENq*txVB~=B;82H2t6Zq34dLF$JCrAb(tZyh7jDth{63`jc%9_S1 z9wlPpbjG@8c92>|=GI)^@;mQuXj!tD#G_t*tnaVaSb}=*RkURb{Is)kLt9*OEzYgk z6xJ$Apixr-O`7sc&0E&Aib2+`7~+8M1H4h%Z_w3&Ksfy{awZC7mp&#Cs((=+F8#Pb zTFw-kz|o(UV<~ykC^D$1L7;y@l!bSctE1W09G(4mR_2y0-RoNw1nezuRmbP$fhF@M z2AzA-_R&ncZ9RA6=*w*HDNNfpS4eLEfl{l1z^%8T--7}%=})u}&IHrQ{9sC+n5;Kg zPEKdxbLt+TorL)v%elMD-RrTVgX!S=+q5^ZI6wQ zX5Wh$=~(4&8T{*qF_<7+D|H#J_vYJ~>o-Y$ANvdv{b3eRzFQ!B^{0^GkU(}WW4?o| z6DM&b^rfI6PYO)`}C_=dgoEx^GzBX;Yz>XF1>vh zQBJDIc^pR6MxZ5>`!1jKyh0t@V*4+kSoprVGwNeN7f=kTV4uuuEYuRJv0y70T~?T7 z? zaa<=cPybP`0S%*9>@||)*@`{mqsIz2GqZ(%qO-X*OLy6}Im5rqd=>ibi{5f!)zPbU ztn|0DW7@OARJGzC+}iNM+~2u{h0B+ftCww?XD!~ca`l{c&gf|-`Dsn*Z`V2mHxg=* zos2^zK(vBo(OqqwclXpM0jDXIxmDMp)z>>WZ!cEOb8Eb^v22HpOUDHFy-LRlgQPf= zAnmoePx>1^0e+9QaY z(_0vLoHGKJ>aMR9UCjo^Ltc{H5lFN{_`*>0Lc-O~J zFqY>9cGBb@5dBAzcy}5XXO9`q&Ns3jTp)@U>4XU$op-W5AB>Bl7)jhUfmF9OnEG-$ zGJQP#D}dR$N<i>3t*{>e literal 0 HcmV?d00001 diff --git a/SRC/DOS/MSDOS.LNK b/SRC/DOS/MSDOS.LNK new file mode 100644 index 0000000..fe062ff --- /dev/null +++ b/SRC/DOS/MSDOS.LNK @@ -0,0 +1,13 @@ +nibdos.obj const2.obj stddata.obj stdtable.obj + +stddisp.obj stdcode.obj stddosmes.obj time.obj + +getset.obj parse.obj misc.obj misc2.obj crit.obj + +cpmio.obj cpmio2.obj fcbio.obj fcbio2.obj + +search.obj path.obj ioctl.obj delete.obj rename.obj + +finfo.obj dup.obj create.obj open.obj dinfo.obj+ +isearch.obj abort.obj close.obj dircall.obj+ +disk.obj disk2.obj disk3.obj dir.obj dir2.obj + +dev.obj mknode.obj rom.obj fcb.obj stdctrlc.obj + +fat.obj buf.obj proc.obj alloc.obj srvcall.obj + +util.obj macro.obj macro2.obj handle.obj file.obj + +lock.obj share.obj +MSDOS.exe /m; diff --git a/SRC/DOS/MULT.INC b/SRC/DOS/MULT.INC new file mode 100644 index 0000000..9dfe1f3 --- /dev/null +++ b/SRC/DOS/MULT.INC @@ -0,0 +1,158 @@ +; SCCSID = @(#)mult.asm 1.2 85/04/12 +Break + +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +; Critical section definitions +; +; These below are subject to leave-all sections +critDisk EQU 1 ; Disk I/O critical section +critDevice EQU 2 ; Device I/O critical section +critShare EQU 1 ; Sharer I/O critical section +critMem EQU 1 ; memory maintenance critical section +critNet EQU 5 ; network critical section +critSFT EQU 1 ; sft table allocation +; These below are not subject to leave-all sections +critASSIGN EQU 8 ; Assign has munged a system call +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +; +; The current set of defined multiplex channels is (* means documented): +; +; Channel(h) Issuer Receiver Function +; 00 server PSPRINT print job control +; *01 print/apps PRINT Queueing of files +; 02 BIOS REDIR signal open/close of printers +; +; 05 command REDIR obtain text of net int 24 message +; *06 server/assign ASSIGN Install check +; +; 08 external driver IBMBIO interface to internal routines +; +; 10 sharer/server Sharer install check +; 11 DOS/server Redir install check/redirection funcs +; 12 sharer/redir DOS dos functions and structure maint +; 13 MSNET MSNET movement of NCBs +; 14 DOS NLSFUNC down load NLS country info,DOS 3.3 +; 14 Apps Popup DOS 4.XX popup screen functions +; ***> NOTE <*** Yes there are 2 users of 14h but since DOS 4.XX +; doesn't use NLSFUNC, there is no conflict +; 15 Apps MSCDEX CD-ROM redirector interface +; 16 Winoldap (?) WIN386 Private Windows communication +; 17 Winoldap (?) WIN386 Win386 clipboard interface +; 18 Apps MS-Manager Toggle interface to manager +; 19,(13h) external driver IBMBIO Reset_Int_13, allows installation +; of alternative INT_13 drivers after +; boot_up +; B0 GRAFTABL GRAFTABL +; + +MultSHARE EQU 10h ; sharer + ; 1 MFT_enter + ; 2 MFTClose + ; 3 MFTclU + ; 4 MFTCloseP + ; 5 MFTCloN + ; 6 set_block + ; 7 clr_block + ; 8 chk_block + ; 9 MFT_get + ; 10 ShSave + ; 11 ShChk + ; 12 ShCol + ; 13 ShCloseFile + +MultNET EQU 11h ; Network support + ; 1 NET_RMDIR + ; 2 NET_SEQ_RMDIR + ; 3 NET_MKDIR + ; 4 NET_SEQ_MKDIR + ; 5 NET_CHDIR + ; 6 NET_CLOSE + ; 7 NET_COMMIT + ; 8 NET_READ + ; 9 NET_WRITE + ; 10 NET_LOCK + ; 11 NET_UNLOCK + ; 12 NET_DISK_INFO + ; 13 NET_SET_FILE_ATTRIBUTE + ; 14 NET_SEQ_SET_FILE_ATTRIBUTE + ; 15 NET_GET_FILE_INFO + ; 16 NET_SEQ_GET_FILE_INFO + ; 17 NET_RENAME + ; 18 NET_SEQ_RENAME + ; 19 NET_DELETE + ; 20 NET_SEQ_DELETE + ; 21 NET_OPEN + ; 22 NET_SEQ_OPEN + ; 23 NET_CREATE + ; 24 NET_SEQ_CREATE + ; 25 NET_SEQ_SEARCH_FIRST + ; 26 NET_SEQ_SEARCH_NEXT + ; 27 NET_SEARCH_FIRST + ; 28 NET_SEARCH_NEXT + ; 29 NET_ABORT + ; 30 NET_ASSOPER + ; 31 Printer_SET_STRING + ; 32 NetFlushBuf + ; 33 NetBufWrite + ; 34 NetResetEnvironment + ; 35 NetSpoolCheck + ; 36 NetSpoolClose + +MultDOS EQU 12h ; DOS call back + ; 1 DOS_CLOSE + ; 2 RECSET + ; 3 Get DOSGROUP + ; 4 PATHCHRCMP + ; 5 OUT + ; 6 NET_I24_ENTRY + ; 7 PLACEBUF + ; 8 FREE_SFT + ; 9 BUFWRITE + ; 10 SHARE_VIOLATION + ; 11 SHARE_ERROR + ; 12 SET_SFT_MODE + ; 13 DATE16 + ; 14 SETVISIT + ; 15 SCANPLACE + ; 16 SKIPVISIT + ; 17 StrCpy + ; 18 StrLen + ; 19 Ucase + ; 20 POINTCOMP + ; 21 CHECKFLUSH + ; 22 SFFromSFN + ; 23 GetCDSFromDrv + ; 24 Get_User_Stack + ; 25 GetThisDrv + ; 26 DriveFromText + ; 27 SETYEAR + ; 28 DSUM + ; 29 DSLIDE + ; 30 StrCmp + ; 31 initcds + ; 32 pjfnfromhandle + ; 33 $NameTrans + ; 34 CAL_LK + ; 35 DEVNAME + ; 36 Idle + ; +NLSFUNC EQU 14h ; NLSFUNC CALL , DOS 3.3 + ; 0 NLSInstall + ; 1 ChgCodePage + ; 2 GetExtInfo + ; 3 SetCodePage + ; 4 GetCntry + ; +;FASTOPEN is not chained through INT 2F ; DOS 3.3 F.C. +; it calls Multdos 42 to set up an entry routine address + ; 0 Install status (reserved) + ; 1 Lookup + ; 2 Insert + ; 3 Delete + ; 4 Purge (reserved) + diff --git a/SRC/DOS/NIBDOS.OBJ b/SRC/DOS/NIBDOS.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..32ed62c6e6bfec2ec0e4f150f88ec1eb2ee6c252 GIT binary patch literal 1035 zcmbVLOKTHR6#iy1nVGaTt*7g_1rg-gLj=zs7hvs5iUQ(ArFP2IE)OXVRR@PCwHOfUe)j#4JcGITgbXl zE#EuvNrG(WLX+IBx!&UjjJ^T^xByybGF}J?LHyRAhX^9Qw3%ctry&s#A#cX%9 z2$4o#g?Kx3NiiJ~LiAZ*hPZ@dd}K@p((%d37!;>avdnZDI@4}ZNPH9^A2D-wWVZSi zM2pNMCmA6K)Bh)YI(rm$r3@w#f-sm$2oh^t8q6~B27@Gnn+z5hEHZ0~amx%=7_2ef zI^#@&i{L6Cj(Huw=~e2!S4{$|!4=ZUx?$Ny?hf!g7$;fM=?v}xlffiOs$SaI$fPxM z8Tc{s-+yZP2P!S&uk0SSW#D%ZrwGL`9nCb0E5IU8K?=hz6%re-Mv^OcNNFs*cvdX4Z2?Y7^fiD+%- zyxpST>l}t7B!D^IZm6?bt@bSNn%C;qdbEo*`cQnsBv(8dh_3pQXLj0+y(fOR45WBw SXE*#Uk8W|K`?W9wnJsDwoqtsbf(N@r(gcVp8`oS9wJg@$E~-KAx_ zBokJ_!xVF{X^@;mG-C8(51vFc^ddD=L9j?K;>E+(qPs>Uh`7dr<9n0X%kc5N_vZio z{_p=h8ByJ|OJ>n19K3x3h-jv6P|YmZPAvSY1;>u)s-yCKikIwR>>&nh%c;FU30sYRqYB8zU&7^KTy4uSg=o&o9js9=!weN*5WQbH3rwE-U{$z&4 z{UaG7Uu`Og8S9lz7O8p;KXw$*r+5u70nqo_anwnMC_c@Q$c?59X|e1U*W3+!-Z=`Y zhG~w~4$I%TQ(XbWN5Y81@v%ui&5nJ^OXTmC_`dTJ=n6l$4|FHc|Gi7m-*<=d?N?8} z#R#*F#rTzIZT|{!k58{$XLOhI!of9oHMw!qyEX9s*{;Pd?hb-Wd7-a(yGd^dH*#jC z|HYY^i|wOf;6y#bKm+(k(u4@`A7Z>hGX_yN`8=V+IX~ecE;G*OZ;k^eIcMy8Gl96h zq*_KvTQam$c(@~je#UpdSiSGNwiuR}`m`w_l6(1l8U4-)(5rm?)}Q=hn5h0TY6X-1 zxfa9ZelQK(wYhPB`-$*hDPLj%>oUs>;-^^C>i1+w!k^*S^gx=3Pr{$&?i_cIGdI;t zLeY(t@OhN@jJ)5O1O1KH&K?*7>lW#K$n+)SF*XmOp=2AU1#fr2`cssV zjpPVVUCubJ$ZRcsw!-UiP+&zY2?<2r&{NVjG@HkA3dUv*6_BpvT$=#%PN7$KI z{kzvyusZDh)t(C34*Bs6iTaF(e$~o=(4@9eUOzV;{F3^@G{Fb0BwH9gclIdQl)v6O h#2m#o91d4H&7MBX@o_87-0|HQmStKX7&HXH{SQrPG7ta& literal 0 HcmV?d00001 diff --git a/SRC/DOS/PARSE.OBJ b/SRC/DOS/PARSE.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..6722a8a6381379b8b3f522733345b15bdd40d160 GIT binary patch literal 267 zcmXYsu}i~19EIN{_e(Am0tM~nCQ@;Czvix5j7`X$u0cXE;$|bRB2H4!Nkkm_e>f-z z{w?C@=5(g5%j1Lh@!(yDpj;M4|32;lJjs-%BpVwWEmMxI;YwO5RA%;y>?r4{G?t8& zg(WKoss4Ei(FcTJ{g(FI5ubHeM8x7%8%1nuK^=G=+is}_!jOGG#|RvAp7R}da3}1gopA#50e3Q<^lwK0mthv0d853dGE6>;?qe}UQQ<$<+M4e&T%vEfcV0@ kSK{OIU-jP}Ho&O2xjb49N2xBAHc2tcZB_tyz4L(P4^y5%0RR91 literal 0 HcmV?d00001 diff --git a/SRC/DOS/PATH.OBJ b/SRC/DOS/PATH.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..416800b93ba04c034694dc53cc628b8369cc3464 GIT binary patch literal 1196 zcmX|=Z)h839LIl8lIQ-UX_EfCmZ?p_uFMyX(H9e?h}m7bmNiXwcWvw#J3@Cep=%fJ zF3Mmp0u883l!74QB19MiM}_)E_sWHGc5H|*D}o3Ugl!oPB2q-~{5{uWZ^G|+?)&>b zpWpX+QsW?!PwR8@pPmGW$T=lL<=mpCi~etVQP(0$T2Bi~PCKpUmhzE>w5C%{PpdlB z)29|Pz0Y_!1|SIJ7*=y=5+(zO6{RG8_*E3i6sr^x3Xx}6l>m62Jo!8hoJYKn7xp3^ z^*Fit4$#%C=@cO*S1rp>%9fGYxCkPiZ)DeSd049JtmH3gmCNN-6NJSpn(6pkxr(`Q zs(J}{y;QbkMFX)gn>RG4XgMHeR;@D1>@|3;Edm921aN(Kyv0GCNF;iv83XaO=`5FR z#d;SWG7V)KTX+&^`o3eDh37u|OcQ0Aoy3=cCiZPJ4t?5+W~dq6$fznjXpaL;z+-^% z<>NnK(g%tRwJIFn;{f0;z_r$hkI?T55)s^CiE!?iMED<>({k~0`C`#A*))arTR>l7 z=W&G#DTBB6H}@dyYr~$CxDs^RUL2i5UucUpieM1-fa#*T(^oFcE0G8 z{M_N^_KQF(49c*%)VZB-_mh*gHvzorpu|siehmzgZbBktx0!@~3>l}HwXUqQpub=t ze!%*zL@@|);G3ohoaR{adIe(b37{V_ffM^U*s#Y;fHVqSIxNgo}8{_P^~rsp|NZ?%%X(U9ARw9HMo&m7nb zluPW5<=bOGcYWN)tZnKbBg2Gqlq;M)5sW(Q^4NEmWrd>}OSWmTH@Lb6zqelny3d*$ z*SL?*$8m)B52iZ>+_>PI-OJ2--ipCXsRlljv#Hh*A7{jkV)}K&NxGx#jZ8^IeAmj`Q{{fe^ BP!IqB literal 0 HcmV?d00001 diff --git a/SRC/DOS/PDB.INC b/SRC/DOS/PDB.INC new file mode 100644 index 0000000..25cc981 --- /dev/null +++ b/SRC/DOS/PDB.INC @@ -0,0 +1,47 @@ +; SCCSID = @(#)pdb.asm 1.1 85/04/10 +BREAK + +; +; Process data block (otherwise known as program header) +; + +FilPerProc EQU 20 + +Process_data_block STRUC +PDB_Exit_Call DW ? ; INT int_abort system terminate +PDB_block_len DW ? ; size of execution block + DB ? +PDB_CPM_Call DB 5 DUP (?) ; ancient call to system +PDB_Exit DD ? ; pointer to exit routine +PDB_Ctrl_C DD ? ; pointer to ^C routine +PDB_Fatal_abort DD ? ; pointer to fatal error +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +PDB_Parent_PID DW ? ; PID of parent (terminate PID) +PDB_JFN_Table DB FilPerProc DUP (?) + ; indices into system table +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +PDB_environ DW ? ; seg addr of environment +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +PDB_User_stack DD ? ; stack of self during system calls +PDB_JFN_Length DW ? ; number of handles allowed +PDB_JFN_Pointer DD ? ; pointer to JFN table +PDB_Next_PDB DD ? ; pointer to nested PDB's +PDB_PAD1 DB 14h DUP (?) +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +PDB_Call_system DB 5 DUP (?) ; portable method of system call +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +PDB_PAD2 DB 7h DUP (?) +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +Process_data_block ENDS diff --git a/SRC/DOS/PROC.OBJ b/SRC/DOS/PROC.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..d64a5e649e47229ea2d20e5611f6058bdd08fee3 GIT binary patch literal 2861 zcma)8dvFuy5#N*UPEWsuc!XFabqyJyA$F=xYaqyafP*XvNjBzTsR};84Y56^lLPr9 zG3A^fpCbFOP9|{^WkNccx}~NwX?e^91)XdtlSzTLz;i}2de<|dS(@JThNG>sVH(B$CQ$%PlCa~u!OtJYBWp) zx%~h-9W(iMDewiRpebkzY=JBA&Qt^pPEm+SLcrAsMrT44g)WKkdRJ$MGaU3ffp;}K z94;3agoB+@bWeAO00uW1u%Y*Fe%UYsyNS(%JgLslsb@+1cZXu_iHh zJTbTZ&GrgyWby=iWr}}dcqz?isa#Uda8EOGB_--QE2FtiBXM}KbnvIlo51~oL}J?! z*G@@8=`1>^pHm**Id+nPk$mq>#W#89nALV_8Jq^-tBI;k^kWQLH!Oq1(yuY=g+hYG z6c*kG*wDOF(r?(=ENKx8?oV)6uB}Fuq~|UHB&}9oeNd}#NzZhx;?^WRb5p&e`YFw* zNr`-erVkEpq;Z$2E6W*H5Aqs}n`PAvxU+z|r6_Dc;eL(UhC4H;KSWXv@*60uVjEH> z(0iR?r_?OG1RWUzaNlLnaG+&yp%Uf4rudy+f5;6NGp_;n1ESF0h5-l86bck!8&?iT z<}1WMHsoHuG>6aTiehvXER)8Q@=gYPe<}0_9^N6?_>o;6a5m(4O0$2`msg)^HYY|f=sOyU4StJ&a z-Q>x>B3g>U8*;n1!e^OR817?&!4@Z3S0Z;0&qKMWJ#($>smR?By8KGHSe=ec*I(X- zT03mwmWK1YB>n31hwp(V-oQkrzxLe4BIXs}9M(+x=?AoSxT**hNh(Wa^%n>R5_f&} zKkf)DY>iVgLsF;PDNde>!CBPnoikmQ7S-k-PfcjY(i6=0j*PRuh5ras3o@kcwt zj4l34OwY+eVQLNLA8nYvkgj7!L&)wbCKR97X9=n}ujCNWwY9(mFc6IB5{+fYzu`q_ z5*o&&cj*bLQ9RRF0z0Cxk0Tmj4v#$qdlKg`k)tCV$EK0IjHx1?c7r&>X6Mxp^VfMf}%Aq&H* z+mT-m>P{pqs4*lstVmT?fZStcD&=0Zu$EC@K~X8FuUZ*{++Q?0NciK(|3f36K=KqL zU%;M_|3H=p_-;SxA(rhoBU#JjS5V{mZzEwLzYe|UNh@ife-kQHvHdP9Q_+v1ayGU< zjMMijIXyM5L{F651%JtG25z+$GqSVLJ6k)*uK}!8b!%SYPnluc+1)U({LZoZ?8wND zh>eJi1MBY`8ySh%@{*?SLZ5Q)&asCV2FB|OLknlG>Q^Z<7&Z%1YiHag_QLgy6}T?q zA+8y?H;}9QqR9UF>adBX)gqg%jAbTO0j2u{DVm52Vl*zr_Phu`&I|(AM_w&RmV#7S zTro%^;9|zRCp|I9AB91Fpjh}mpd-|t!a0f+W~7z&JT?KDN2&I5pD($*Hkl~3=dnjn zV5v>ID~l~a)$HmDl69cX&klc zvz4^|&ym81Xc^=f=2_iKdG$pik6Rf%t#B24lU^o4x5EW1Gv&aUShP)AG8Z}nuyMGA zI!@@KCV5@gK{;*e>QBV9v90j=_ppkYG~v#%FC5jrd(c*{6t_iurjd;s!g&UbCfa@T!*>;IK90$1%G|)CxdlH^Ga<1&s)f3t)lY19> zWXaFTz3cQhH#>YToZvy=4zqX?>u%UzuLUsPD3(Ctix)oHv=^|BgD%UIzAjsQXdggL za=h_rdbb68A^V9D&K`vi>0jf*%w4MLt&CPJBT+BLMSjf6EK*mH!mS~)IKYXQNskA^CN;Y_g?xuz%YoFkM8HF2JI6YK_n&$r!#@DjYI#h;Iy}QlrT(|BSw-LbiKavniHZ4dF3VVV= ztOF1D^FtN*mQg@SGu}KN$Xqg|Z+FC_GsJI6qZ?t i7md_x6@;E>kJ!COh{wGw%r0nccQl2`7vF#eK>8P>d|xgA literal 0 HcmV?d00001 diff --git a/SRC/DOS/RENAME.OBJ b/SRC/DOS/RENAME.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..e1c3f69c14f714e81911ef92107711d68f4155d5 GIT binary patch literal 1687 zcmYjSU5pb|6#nkCccy>)({^`&BFp09hF}1NfJVS&wlm$WblXj53adWU&04c$1*<9 z^L^jB?eQ2QX2C8Ot-LX29e!&U5KI?Li>C{D+X;KKk$3E%X*foRJV%O!(s(du*bcWH zqv&wQ7|vOLzN29i5DKwPWR21#0T%Zy&RM5_8V<8TX?@QWg*`>qG@xnhk9RwvwpdGP z1zN!tZ>j0VH&6}7DQ1TeGD;JaC%qq`bkQ=LY<>i4x>Ou4We}rpv213GWh-wYY+APC zm4p!O`Ic&q8HQ;hW=%L2Ip+%Lk_|0mWOKAcI8!L)&9Z470GIe5^gr7X_W7V_Xk?ZT zX2zj8qggv`Qn)nC@!_^nJm4F4#zB}I%YJIjsmxXLl`3Z3G&t}(FsClY$Kzptae{}EB;i*c+hwP;_CMjvp690BQ$H<}Nj&UDr*I&>Bm37z!_U1wcl zbAp8wh^;yciS53}9;%v$=4SAVtAP*6a<(*8?@IkbBZ+R= z1-4}r)1&2#qz^~k6!@@LckkW=YJo)sE3Z*4ax6C!UhFE-EtBedBrDoKNUM<2@;Kz+_bV!y>D_2fWSEgpb+)nTrFE?N8$MVnD z+qJIwu#rGlW^%4tc&>7!Y*wDFR4aJFT?<~5?vmA$G$eDamN(z{t(o$&r39CRQOX`k zA{R-W1+F!^5F4pf$0w`P`J*=JwdAe_Z^+AL2dcry_2(a;>Q|cME^xD5_gcw+;%p;| zP$pNhM`brE?j*P?!zO&Ff%lfrOe_Yle5w}pcY=|tHI;T&mQU*1=fG#c#VBr_dmlIp z=-MUV&hCXhLp5byJD>jbFR8ySrjf4N=vHa!&wVT)qeA(>wQmhl2yeX=)_@|8y zM2H#l(5yW>HH{bDFnEMXf?lq)b?G}Nwa;Yprj>V!kK=;76TD0M%$@MTZzhzx2}IQ< zB0uP^rOx<0P9%7OnTmoPSC2J!dFj{7^bskOD&mBu3qq$)Kg2o-WkZ4`sp&T+nDTW? zY|>fstwtxJ{;MsI8T%~^N^twU3IaC)TTuTUZg*{eUF~N4ZAf^@XQYhw^yF;CI`T9Q zx+U;28TO=%7(714_buE$aV1K1UhE~YB<%eQw_hbFAKf^=oRsU`{#v?7J>|3Z0%?Pe zrF2l6Sr6C-DP2$`JuvmPRK_JH1`;f&pnku<+TpDPz2cY{lFlRK%us(!XS&Ffh~M3X zHBY~6)OXv!PkV~=ymBl>Iq9dS9|W6Bn*XNpzrga4EzPxgzPC=#VNE?wnNOkKqq9_f z71=+*EA14-dY}9O>Vx{A&icNRI@{IB*{atIU$_zQt1>gm`){+u!#E&<6xD$Foe literal 0 HcmV?d00001 diff --git a/SRC/DOS/ROM.OBJ b/SRC/DOS/ROM.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..d833c1b47e4fc25531a061bdd38cc82edb5163a2 GIT binary patch literal 1600 zcmYLJU2GIp6h3!$XJ)tCpKVzuAWf-JCcuUeXadFsVLCh8zwPcaGfPW1MH7{v4;pv3 zYz)CPVMy)Hwl)w6(W0xU@l6sQMD(FBBQ@1%N<&ndSgj8tRTGPWR+5hA?qGen_xyb4 z-0z-q?-^vlqb9qHXLbU35?y+)Y{Z!I^~T^n$Bvvr0T3L zwZ@gjvpj49@cGCll-e-Q6pO2-(6A)lah1c2ws?Kf+IbBMz@9>?pj z4kwq6124tn$sQ#NeCt77PUzdgkAkMisiX$H98YVBbT@EvT5V0ofQxoZQZx!&Owths zJmptGCX`;Cda5v#Mo}a8UmCr=L(^h9u(~QG(0)LQqYLWGj{yt7*-rw9X8(H8Os@;f z<~N3?az4*g%XPE`_+LVG;~dx?fmG*9e&EuHlq7e-`Em`g&2S4KM=Z^pQxRkkfz(|r z`GD=nDaja2mqlPVQ%oku4$ZaB|Gs4LQsfNLDUD_{LU{BG}0do-`Oy}tHPt+<^@t?R|~{% zHwc8GjQo@lYi|;W$JmavB4F=sARGgBH`)(VimA9HE3{1;XmQ@5M~ac7OxE+tgW@z? zC{=^M0&7>KDBLQC3HuSnEeRW}cLDaD2Z$iO3#7p8nBeFgFOOoO{-=t{V3OT8QV51u z%zNhj)iWL>xr@1)JT)d^vanB2&4RqAf@6=NGz$F-v$_HLr;G4l}gko@>apw=aB?peKX5%^#Pn z6SjBR3QukMdFAWZL^Mq;Ozszp3AVFyX1;1h^c)Brw6vC4L{lD_?BagSoDt1KjVJCi z1;02MYh>Uv0#pITNRKD&Tk<8^BLklHTNW?!Pq z1bPj-@&@hiC}@#_?h1rIxeld0B_6z$-_TjU0PMGf5^fexyxQdCy`qz7IyH3Dyh@FM z)8@?lSC<_JmCV8HIchsgm(xRY0cT*u{er{&0dcs0J#S%(MrPnt#trBVUqR@yrKvqF zv-Inr_EcZSYPn7`EamT-lPXGm**^l;2Lh|d$C}LV+w(tA%nggK|KK;pJ(K&(oLl(w z*KxH{&5$7oBxF2Fmo0cHV;kOgD`W4*4{zuw?`4cW*Yq4-oYpR6yi9?|sPqP{=UY@g zk5Xu?4hZX`GfkFsYzT03hZ9a2nu*d7gnCE`W|d%=kAzn@b^?(mT34`jm|XK6fFi5^s%n tX?q!9R}G4!DSH@rXsjMjsZte9cL(cM2G+Unl#}EJj literal 0 HcmV?d00001 diff --git a/SRC/DOS/SEARCH.OBJ b/SRC/DOS/SEARCH.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..ac153bff1ef8fe38e843dc168dd266d58c6754e4 GIT binary patch literal 1384 zcmaKr--{bn6vw}JCU<6%?B{|zWHQb@nIJV^gl1>5qa4cpMtMeCGVoS*ZZF)W)}wqe@T zHj-yD+gDUf1DZyrd6eUu$Rz4Tl#-BF_4~<`h=xRx$ax-}15}m#_E`vuLmbJG9iKxT zCDnWmN~&5;m*0kxe%>(7o`sTm(axrlP>XLZEhnq5L$wUsHuFjNJ@n*!7OI`gTcYb) z=O`$U_(12c<`LlX_UcKeD%Xap^OUZB3%t{gfyp{inHD3e1a?p-z7Ly0Xm)vVc|~mU zQ6~U;2)_a=zJ&{I1$Ckm?OHR0ATO89rAjGNF5_b75a`3W4d_Q5E}wXADd0cx;duL) z`#(QZbt17~jL!}h7I9Q33OnE?e9ik1;o_FOSxVWwY1w$Q^9txQ0^no5pLkZ}g{>cN z0Bjbx!`DtluH8}>0zX%k2LIUZU}J4?svp2kcWuzyZwhTXz1^FAik)5u=rsnteuVcd zw4Zj_0*rcC{(UT=43|V^(>fvSSy7l3%Yshm#pXBye@jq2jc{ikbX_R0FL+`oB=Fv@ z;NA(0*M`bQ;tO8c4FMZ-jr9FJm-k-U9dGAcz93Ts4%bc`RD=^SU9cP$0?vr#6Jluy z$c#5hUc{$Gz33+XXvPp85xBtZ#9eX%^p{b6%Q7EgUpH6WsY?&> zmuhTOwR$K*XbvnUKm}a=m`?ocQ33ZDcUHI=#+d7@xy8ykYpH@OogiqG2zSv%BrimXqInW96ANCschP3t5o;CUhu=C{$jdZYA8|vL|HrwsK$~%8= zXI%2o|9Y`Lp_2eR?CBU6IzFY(2nBk + +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +; +; system file table +; + +SF STRUC +SFLink DD ? +SFCount DW ? ; number of entries +SFTable DW ? ; beginning of array of the following +SF ENDS + +; +; system file table entry +; + +sf_entry STRUC +sf_ref_count DW ? ; number of processes sharing entry + ; if FCB then ref count +sf_mode DW ? ; mode of access or high bit on if FCB +sf_attr DB ? ; attribute of file +sf_flags DW ? ;Bits 8-15 + ; Bit 15 = 1 if remote file + ; = 0 if local file or device + ; Bit 14 = 1 if date/time is not to be + ; set from clock at CLOSE. Set by + ; FILETIMES and FCB_CLOSE. Reset by + ; other reseters of the dirty bit + ; (WRITE) + ; Bit 13 = Pipe bit (reserved) + ; + ; Bits 0-7 (old FCB_devid bits) + ; If remote file or local file, bit + ; 6=0 if dirty Device ID number, bits + ; 0-5 if local file. + ; bit 7=0 for local file, bit 7 + ; =1 for local I/O device + ; If local I/O device, bit 6=0 if EOF (input) + ; Bit 5=1 if Raw mode + ; Bit 0=1 if console input device + ; Bit 1=1 if console output device + ; Bit 2=1 if null device + ; Bit 3=1 if clock device +sf_devptr DD ? ; Points to DPB if local file, points + ; to device header if local device, + ; points to net device header if + ; remote +sf_firclus DW ? ; First cluster of file (bit 15 = 0) +sf_time DW ? ; Time associated with file +sf_date DW ? ; Date associated with file +sf_size DD ? ; Size associated with file +sf_position DD ? ; Read/Write pointer or LRU count for FCBs +; +; Starting here, the next 7 bytes may be used by the file system to store an +; ID +; +sf_cluspos DW ? ; Position of last cluster accessed +sf_lstclus DW ? ; Last cluster accessed +sf_dirsec DW ? ; Sector number of directory sector for this file +sf_dirpos DB ? ; Offset of this entry in the above +; +; End of 7 bytes of file-system specific info. +; +sf_name DB 11 DUP (?) ; 11 character name that is in the + ; directory entry. This is used by + ; close to detect file deleted and + ; disk changed errors. +; SHARING INFO +sf_chain DD ? ; link to next SF +sf_UID DW ? +sf_PID DW ? +sf_MFT DW ? +sf_entry ENDS + +sf_netid EQU BYTE PTR sf_cluspos +sf_OpenAge EQU WORD PTR sf_position+2 +sf_LRU EQU WORD PTR sf_position + +sf_default_number EQU 5h + +; +; Note that we need to mark an SFT as being busy for OPEN/CREATE. This is +; because an INT 24 may prevent us from 'freeing' it. We mark this as such +; by placing a -1 in the ref_count field. +; + +sf_busy EQU -1 + + +; mode mask for FCB detection +sf_isfcb EQU 1000000000000000B + +; Flag word masks +sf_isnet EQU 1000000000000000B +sf_close_nodate EQU 0100000000000000B +sf_pipe EQU 0010000000000000B +sf_no_inherit EQU 0001000000000000B +sf_net_spool EQU 0000100000000000B + +; Local file/device flag masks +devid_file_clean EQU 40h ; true if file and not written +devid_file_mask_drive EQU 3Fh ; mask for drive number + +devid_device EQU 80h ; true if a device +devid_device_EOF EQU 40h ; true if end of file reached +devid_device_raw EQU 20h ; true if in raw mode +devid_device_special EQU 10h ; true if special device +devid_device_clock EQU 08h ; true if clock device +devid_device_null EQU 04h ; true if null device +devid_device_con_out EQU 02h ; true if console output +devid_device_con_in EQU 01h ; true if consle input +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +; +; structure of devid field as returned by IOCTL is: +; +; BIT 7 6 5 4 3 2 1 0 +; |---|---|---|---|---|---|---|---| +; | I | E | R | S | I | I | I | I | +; | S | O | A | P | S | S | S | S | +; | D | F | W | E | C | N | C | C | +; | E | | | C | L | U | O | I | +; | V | | | L | K | L | T | N | +; |---|---|---|---|---|---|---|---| +; ISDEV = 1 if this channel is a device +; = 0 if this channel is a disk file +; +; If ISDEV = 1 +; +; EOF = 0 if End Of File on input +; RAW = 1 if this device is in Raw mode +; = 0 if this device is cooked +; ISCLK = 1 if this device is the clock device +; ISNUL = 1 if this device is the null device +; ISCOT = 1 if this device is the console output +; ISCIN = 1 if this device is the console input +; +; If ISDEV = 0 +; EOF = 0 if channel has been written +; Bits 0-5 are the block device number for +; the channel (0 = A, 1 = B, ...) +; +devid_ISDEV EQU 80h +devid_EOF EQU 40h +devid_RAW EQU 20h +devid_SPECIAL EQU 10H +devid_ISCLK EQU 08h +devid_ISNUL EQU 04h +devid_ISCOT EQU 02h +devid_ISCIN EQU 01h + +devid_block_dev EQU 1Fh ; mask for block device number diff --git a/SRC/DOS/SHARE.OBJ b/SRC/DOS/SHARE.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..01e699b3db00a4dce22006ade85bceaa0ea7773f GIT binary patch literal 499 zcmXYuF>BjU6ot=~_1=?JVml$I8CnNgFo8fQ1TvLUMN(q7!b+sqq@hCySk#4*6k8p- zb@0;KgQrr02M_rZnOd;u+8@xVnM%5KDVfwKxy#|>ynD~(-uGUBMNK>O=+hRUJAvyl zCum2qT&Ufak?z{kHrycE4TEQUx^G94MbZu>llHdn{rN1g1{emdDQc>a5-rY&F{;d8 z%Vlch6hhPJN>LXOg09ai;2C9FR?75@W!xD(hOm7 + +c_DEL EQU 7Fh ; ASCII rubout or delete previous char +c_BS EQU 08h ; ^H ASCII backspace +c_CR EQU 0Dh ; ^M ASCII carriage return +c_LF EQU 0Ah ; ^J ASCII linefeed +c_ETB EQU 17h ; ^W ASCII end of transmission +c_NAK EQU 15h ; ^U ASCII negative acknowledge +c_ETX EQU 03h ; ^C ASCII end of text +c_HT EQU 09h ; ^I ASCII tab + +BREAK + +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; ; +; C A V E A T P R O G R A M M E R ; +; ; +; Certain structures, constants and system calls below are private to ; +; the DOS and are extremely version-dependent. They may change at any ; +; time at the implementors' whim. As a result, they must not be ; +; documented to the general public. If an extreme case arises, they ; +; must be documented with this warning. ; +; ; +; Those structures and constants that are subject to the above will be ; +; marked and bracketed with the flag: ; +; ; +; C A V E A T P R O G R A M M E R ; +; ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + +include bpb.INC + +include buffer.INC + +BREAK +; Location of user registers relative user stack pointer + +user_environ STRUC +user_AX DW ? +user_BX DW ? +user_CX DW ? +user_DX DW ? +user_SI DW ? +user_DI DW ? +user_BP DW ? +user_DS DW ? +user_ES DW ? +user_IP DW ? +user_CS DW ? +user_F DW ? +user_environ ENDS + +include sysvar.INC + +include vector.INC + +;include mult.INC + +BREAK +; MSDOS partitions the disk into 4 sections: +; +; phys sector 0: +-------------------+ +; | | boot/reserved | +; | +-------------------+ +; | | File allocation | +; v | table(s) | +; | (multiple copies | +; | are kept) | +; +-------------------+ +; | Directory | +; +-------------------+ +; | File space | +; +-------------------+ +; | Unaddressable | +; | (to end of disk) | +; +-------------------+ +; +; All partition boundaries are sector boundaries. The size of the FAT is +; adjusted to maximize the file space addressable. + +include dirent.INC + +BREAK +; +; The File Allocation Table uses a 12-bit entry for each allocation unit on +; the disk. These entries are packed, two for every three bytes. The contents +; of entry number N is found by 1) multiplying N by 1.5; 2) adding the result +; to the base address of the Allocation Table; 3) fetching the 16-bit word +; at this address; 4) If N was odd (so that N*1.5 was not an integer), shift +; the word right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry +; number zero is used as an end-of-file trap in the OS and is passed to the +; BIOS to help determine disk format. Entry 1 is reserved for future use. +; The first available allocation unit is assigned entry number two, and even +; though it is the first, is called cluster 2. Entries greater than 0FF8H +; (12-bit fats) or 0FFF8H (16-bit fats) are end of file marks; entries of zero +; are unallocated. Otherwise, the contents of a FAT entry is the number of +; the next cluster in the file. +; +; Clusters with bad sectors are tagged with FF7H. Any non-zero number would +; do because these clusters show as allocated, but are not part of any +; allocation chain and thus will never be allocated to a file. A particular +; number is selected so that disk checking programs know what to do (ie. a +; cluster with entry FF7H which is not in a chain is not an error). + +include dpb.INC + +include curdir.INC + +;include cpmfcb.INC + +;include find.INC + +include pdb.INC + +include exe.INC + +include sf.INC + +include arena.INC + +include intnat.INC + +include mi.INC + +fChk equ 1 +fDelim equ 2 +fSpChk equ 4 +fFCB equ 8 + +;include filemode.INC + +;include error.INC + +include syscall.INC + +include doscntry.inc ;J.K. 5/26/86 + +SUBTTL diff --git a/SRC/DOS/SRVCALL.OBJ b/SRC/DOS/SRVCALL.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..4c1dd74e703eae39762d8f6352535e93bc5f76e3 GIT binary patch literal 1264 zcmZ9MO>Epm6vzML_+!7a+1(^gLexeoO=wjK0zoUN!iTeV($ZCSwRX}(+16UZw!3OR zD#wWcrBX$6U|B2lRME1kEJ04RP;Rsr4vY{&LMR-l1mf#PSh%!ET#(Gz4hQhz{hr5f z-u&mi@m!8V(o3^BC7++amIe4+LDhs@VOlq$fmNmromUk@iKqpAs#KUM@_9u!1l>?d zhF~ZYdF{bF5{>|o2sy&M6D&ywNr#>wkfi^05YZ@!``#GgI0EL?07)Xh-AF?8h{t&y z9`6aBm~*Z})LykU%R(e%(MD(JnaZMFUtK{$n=`ah$;=mWGdd#Y^jgKLubhYYlJ8X^ z6)sj+Cf3hEDwYa4^P~z?~%B6@f1}ZSLKqZE!L8A;8K;sM>pq&htK)V>W zK+_CAfOazwLVH8>g&1JyBDQ-J0x&LF{CIRD(|ph@XR?ihK(pKvFzc}%2Bx^s>H|&5 zq>J{;Btj1`Q5@)@9>Q0g6grK{%S%n(oH}Z#UAk4*!S|#XiE&D(;qu=*0x2fZu^zHT?aX-X*bmYo&um_m+?Cz1jGy#{_}h3#ag|`xu0pzrC!-%4>1$Kil^LxBW20@8O5Nw_Aq-T{0CjMC@T* zWJrMaGo;|_6c6KdCynHJmU?}yYME;2v84dnLIqcVxn$7K?wV=@tHP84EEQ%~we+;q=C_|D(FEPV>x z1?~aIzCLz;ckjwBc7I_jJ8H7A8EF_|`&#jn;q+HeEU*%7vl&f3`yR7uEJQK{7lO~e zIl>Oijn?r%!+?LZI%!lU37U{eeCrXm(JiJXO`nz7AMm0~I69SK7Y69GOgiW+JBixW tE_T60{5xxO^hs?H82QhL&VI?Us~Hd>eps(s8&xY;Sz2O)*|#{r{s(-4KM()_ literal 0 HcmV?d00001 diff --git a/SRC/DOS/STDCODE.OBJ b/SRC/DOS/STDCODE.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..41bb42467ee63bff7a4a67a0a8cda9e2707badba GIT binary patch literal 1748 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 literal 0 HcmV?d00001 diff --git a/SRC/DOS/STDDATA.OBJ b/SRC/DOS/STDDATA.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..9e91302a4235c0dc409e36c3a6fd268f6ca71d7b GIT binary patch literal 3519 zcmY)we{d9M^}XG@y}KkN;hHX#(j-+pQJf3}Ol8nc_jdP^tM`lBy(55fb0$kcLSQbJ zOes@`HaHS;#?-;cVEzcAgTpx#Y^}tWl9s)MX>|&=)#yxHWybzMDO$8t26Db{zbmxK z?EBvLzW3vMzrK5WeBd!mO;b!|+gKZbOO0!~TaCvI)8{}XW*RPb?A78%dorF%xFU*S zx(!oFnr>4GM)VI3dSEGl*NaOD>mVf}&SzMY&+W#y`Kix`0ged*t|Dy9nCS7~+C#M< zm9Z?8#j>mHE=y`5gpv|8w4??ewysN>P^ILo-fX7B%65YkRC{)GZ39dwPP2Ab1&)>fM@$DpiR@GJ4ERt_P1Ak4BZ41~qCt#V8q7OSFSe%~{#JmC%C3 z-Jc^fd4_v5YoLqNfLjZv<7tqzsG@Xt6Fm`hta-J*ZCzV(Rvsk1w>xTWhk2oFUp~Im z>NT_9>an0Iq?>9-IAbd9ATbdu2kvmpYz=`coYYN_9yGROa~4R^?8ALl7f7-G9nWKn~^^`RuMt&g$FRO?QPFV^?38e61L*?9$mBs1p*1 zm#|#!o$!KqTmt$#{L@+x0qPL}X^XIWVi$<@42PBxnZR%W;OftA1cqocO!W{bke~zh z*8;R&4ivOSfoW|)d2qV<;s=B8HwR|4Mdh+|2H?V57p}1X!jw2OGPSbIB!})N=^5Qs zCg?7g2^Gp^j}&C8zdarT+f$FCAMF}i>d|iSW4!?OLK)}V_xN!>;h*ti6DRkI*;GyzgLW{+a7u(CEiXScz6|!FjGwh78Rywm4AjY3W8W#GXfGv`cB>y7 zC9qe^c<<_o*MQW#a{WdNi(1Q2fIxw;!nu+2&jGX*8VL-M$BiqeMrKa|9Qg&E9XSR~ zbjftBr(${TT(NcP*om{n;pt*wwzzVtSS)rFiw_iwgEOAN>8eQ=T>be;@kI00W1IFw zT%x1WQC?a_iayj_-u!=W6Hfz_Rt?UT^IPcfn&yH%{a4y}68A-_+V;~0TR&_A%4%b} ztwdKGzE4#H`_d5DH-N_4vCE;Ef@3z0tfYRPC z6TL^U*YLpPWpvxS{OA^7?|1mgkc=*S#E&i#dxA(~;@+R|lcO?v?UO9Srx-XRqvu$m z3Oq{;-K2(tM<>>xbRNi$z;H-tTSL(vaJ5l3H>}@SnBCMA7#i>g3Y!`l({s~vFOJL( zmYOe~-PH7tCu*C9Zw|LmVgbaGyB3a3u!dv1;?X2-qNvi+hKmBt2ai^M> zutHvB*E8@H2G&s8Y?bv|m|-a=C-yg33La;9-^aiY{OA|Ko{+K5en!TH_Ny{3u-}x? zXTKxkJ@#c8tL&RHVo8)yDEVY;E|H15N{tODmRhKFN-IgvM8O9Vr8BBW;n2i>kURpV zv$pBXLZCuFcB0JUcC6OJdgXb_b3u#KXVSNxzD@M)=46RbfupVfi+Zke!#CFxVfcQ4 zWv{H68}Nk1|B3%rZjO}RqrPL^zQ}>RedcoKM$g%ePAvJ;C*+8Z%ea2%vwG&`S1$TnBL^;)Yj%9i#Om;iJ8wt3;wVbCk=dk(3cq z)ZZeE-zLOT(HjV>xM9X&C~5sXLep&)((?y|KCahcNkqctvk0$`){rT8SJcX9Pa{0d zZ^Gt>&G}{lmQ_^5X_hd*{u07N6)Q33swg{5zslbsefR97hd+qdshHREdt zt=wlCK0--d_Y1J*7J+SJFPPall*pir%CQS zdCR?!Vp3lJ$j+Uz;Cp=*VJFub+R@+Jtyw+4Lii!q>QFM>*1%H;5@*`XCXlVY5B(aU zm+RSV?CjavWj&4X1}D(Ow~h*Kp#Y1xOgI=#C^Xs7K(T?dgkwgOhQ{X*3Kc?}7p(;H zXcc8qd@vOIC&G{TDf6DH@jAkNj39aFNifW$IVMthI{rrunm3m(U!gbo=o+6Q8T9sD z`e9^))&-EvH*8+hvNx7MwRCUlJFB#^$r>m zGuf^#tFP}Q!ri0QM06!6Nbe)DIQdK@b?Oc6HH1C95fVw79ra`;6j9nK^f!4~FrIkg z6vEp)07;#BLbGa%0Ea3pRxgdn^h;9dePYS13nl);s?E6#jgt8tIV+RjzH_MnId0$J zFVP8v5w6C_4p_m?B?48t^HQkTqN+1<^rX?BDSYPX9BUAGA| zG5ikU(N7SP=}Ck~ZWE}L-oBMxrh}&IHxbMVM>wi;D-m7}W>Se6zd=~c&-?qVT*gRD zBb@&v!8nKTGWRO2M96uXbH;e`(&40;QX&~v2`41@YlRw*s2#C(C#6qHP{)m>s#40|I9qhC)XHCHTbn37?JbyG6K zy)pHV^B&j_;Pv8uLPsfy6Wg0ek}%Y?`h3_e(A(&6;2NO`0FMWMyAT3*9qW#|v+k-( zb+=OXqc=Qr+OX53FN0Uf*-BqFeG)uMK4;9Pr@^nx6bhM~twnml8<{Llr|r=RLdF1< zqzr&hEfn&Fsr*<5f@;cCb=`_3l%xTkzVu|4RPc@$C(?z<93_p8Wi!#74N^2tzejqa znZz@gKCPs)S#S%Gp8{_@Z)EJqWC5IULleS)phijTOu=dvs1@>~Rx|>ELZ)cv3mMCv zng+L#K9%WBHP;C3kStOFdHI_lXN6PuNJ`tZQfg^f6P4~>eH0}Cd0{WWhP))C|JsaO zUSxz0J7$?3&`Up}JWu-Z4S`-4mMirQ`4X*HVYBNBY@|~1TW)}r+nQXbBbE<^0A_D3 z{;=th4|Nl~S*i`$Yo*#t_DZRy+2=~N9{YT$HfDeF3wf7m*G2*5>&xHXr93^?E(5Fq z{7W1jy?Y0TlYxrvP_EiYM#y&jJV<1rXoj%^N?}{6E{QR2#96 zlxo4*V2Nm$IY2?1kI_aA_eLrq>e|(_Up|s*=;ZO2plnGywXzP}$i&PS%c-CrqmqcH@j=SPmeXr0*Sk?Z8!pxk?t!^iX? zgQi1JRT_~m)Rhx3hYa^{4?~FuL|a-#gE|G;DH^m-{CJmW0kyZC9}tLo+`*qA!`xwN z>NxUVhFiHNL{f-RAtuPvQE3O1{7N_$v(&h$k30w9tb~a3D2c(ra6B>s@ONb^5uuYA z+nN!#rYN3-GQzD&fOuC_S52CdUn{Mod1Gq$m`Zo}2*T%0`%p4!J`M1FrG@NnT@`O! z72tZMlk}GRmvlB?$c~L83^yw((si{O+!=(6l@4+Z7$b(M4qBpE%J*?)8om;@Z3DfwBJk Nr1St>T66%|{{V1bj1T|- literal 0 HcmV?d00001 diff --git a/SRC/DOS/STDDOSME.ASM b/SRC/DOS/STDDOSME.ASM new file mode 100644 index 0000000..6a7ee0d --- /dev/null +++ b/SRC/DOS/STDDOSME.ASM @@ -0,0 +1,16 @@ +; SCCSID = @(#)stddosmes.asm 1.1 85/04/10 +; +; Standard device IO for MSDOS (first 12 function calls) +; +debug=0 +.xlist +.xcref +include stdsw.inc +include dosseg.inc +.cref +.list + +TITLE STDDOSMES - DOS OEM dependancies +NAME STDDOSMES + +include dosmes.inc diff --git a/SRC/DOS/STDSW.INC b/SRC/DOS/STDSW.INC new file mode 100644 index 0000000..2217ad4 --- /dev/null +++ b/SRC/DOS/STDSW.INC @@ -0,0 +1,33 @@ +; SCCSID = @(#)stdsw.asm 1.1 85/04/10 +TRUE EQU 0FFFFH +FALSE EQU 0 + +; Use the switches below to produce the standard Microsoft version of the IBM +; version of the operating system +;MSVER EQU FALSE +;IBM EQU TRUE +WANG EQU FALSE +;ALTVECT EQU FALSE + +include version.inc + +; Set this switch to cause DOS to move itself to the end of memory +HIGHMEM EQU FALSE + +; Turn on switch below to allow testing disk code with DEBUG. It sets +; up a different stack for disk I/O (functions > 11) than that used for +; character I/O which effectively makes the DOS re-entrant. + + IF IBM +ESCCH EQU 0 ; character to begin escape seq. +CANCEL EQU 27 ;Cancel with escape +TOGLPRN EQU TRUE ;One key toggles printer echo +ZEROEXT EQU TRUE + ELSE +ESCCH EQU 1BH +CANCEL EQU "X"-"@" ;Cancel with Ctrl-X +TOGLPRN EQU FALSE ;Separate keys for printer echo on + ;and off +ZEROEXT EQU TRUE + ENDIF + \ No newline at end of file diff --git a/SRC/DOS/STDTABLE.OBJ b/SRC/DOS/STDTABLE.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..b1fa149580bebad1dcf8549e30821e7790966668 GIT binary patch literal 6374 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 AOaK4? literal 0 HcmV?d00001 diff --git a/SRC/DOS/SYSCALL.INC b/SRC/DOS/SYSCALL.INC new file mode 100644 index 0000000..e95691a --- /dev/null +++ b/SRC/DOS/SYSCALL.INC @@ -0,0 +1,160 @@ +; SCCSID = @(#)syscall.asm 1.1 85/04/10 +BREAK + +Abort EQU 0 ; 0 0 +Std_Con_Input EQU 1 ; 1 1 +Std_Con_Output EQU 2 ; 2 2 +Std_Aux_Input EQU 3 ; 3 3 +Std_Aux_Output EQU 4 ; 4 4 +Std_Printer_Output EQU 5 ; 5 5 +Raw_Con_IO EQU 6 ; 6 6 +Raw_Con_Input EQU 7 ; 7 7 +Std_Con_Input_No_Echo EQU 8 ; 8 8 +Std_Con_String_Output EQU 9 ; 9 9 +Std_Con_String_Input EQU 10 ; 10 A +Std_Con_Input_Status EQU 11 ; 11 B +Std_Con_Input_Flush EQU 12 ; 12 C +Disk_Reset EQU 13 ; 13 D +Set_Default_Drive EQU 14 ; 14 E +FCB_Open EQU 15 ; 15 F +FCB_Close EQU 16 ; 16 10 +Dir_Search_First EQU 17 ; 17 11 +Dir_Search_Next EQU 18 ; 18 12 +FCB_Delete EQU 19 ; 19 13 +FCB_Seq_Read EQU 20 ; 20 14 +FCB_Seq_Write EQU 21 ; 21 15 +FCB_Create EQU 22 ; 22 16 +FCB_Rename EQU 23 ; 23 17 +Get_Default_Drive EQU 25 ; 25 19 +Set_DMA EQU 26 ; 26 1A +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +Get_Default_DPB EQU 31 ; 31 1F +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +FCB_Random_Read EQU 33 ; 33 21 +FCB_Random_Write EQU 34 ; 34 22 +Get_FCB_File_Length EQU 35 ; 35 23 +Get_FCB_Position EQU 36 ; 36 24 +Set_Interrupt_Vector EQU 37 ; 37 25 +Create_Process_Data_Block EQU 38 ; 38 26 +FCB_Random_Read_Block EQU 39 ; 39 27 +FCB_Random_Write_Block EQU 40 ; 40 28 +Parse_File_Descriptor EQU 41 ; 41 29 +Get_Date EQU 42 ; 42 2A +Set_Date EQU 43 ; 43 2B +Get_Time EQU 44 ; 44 2C +Set_Time EQU 45 ; 45 2D +Set_Verify_On_Write EQU 46 ; 46 2E +; Extended functionality group +Get_DMA EQU 47 ; 47 2F +Get_Version EQU 48 ; 48 30 +Keep_Process EQU 49 ; 49 31 +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +Get_DPB EQU 50 ; 50 32 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +Set_CTRL_C_Trapping EQU 51 ; 51 33 +Get_InDOS_Flag EQU 52 ; 52 34 +Get_Interrupt_Vector EQU 53 ; 53 35 +Get_Drive_Freespace EQU 54 ; 54 36 +Char_Oper EQU 55 ; 55 37 +International EQU 56 ; 56 38 +; Directory Group +MKDir EQU 57 ; 57 39 +RMDir EQU 58 ; 58 3A +CHDir EQU 59 ; 59 3B +; File Group +Creat EQU 60 ; 60 3C +Open EQU 61 ; 61 3D +Close EQU 62 ; 62 3E +Read EQU 63 ; 63 3F +Write EQU 64 ; 64 40 +Unlink EQU 65 ; 65 41 +LSeek EQU 66 ; 66 42 +CHMod EQU 67 ; 67 43 +IOCtl EQU 68 ; 68 44 +XDup EQU 69 ; 69 45 +XDup2 EQU 70 ; 70 46 +Current_Dir EQU 71 ; 71 47 +; Memory Group +Alloc EQU 72 ; 72 48 +Dealloc EQU 73 ; 73 49 +Setblock EQU 74 ; 74 4A +; Process Group +Exec EQU 75 ; 75 4B +Exit EQU 76 ; 76 4C +Wait EQU 77 ; 77 4D +Find_First EQU 78 ; 78 4E +; Special Group +Find_Next EQU 79 ; 79 4F +; SPECIAL SYSTEM GROUP +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +Set_Current_PDB EQU 80 ; 80 50 +Get_Current_PDB EQU 81 ; 81 51 +Get_In_Vars EQU 82 ; 82 52 +SetDPB EQU 83 ; 83 53 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +Get_Verify_On_Write EQU 84 ; 84 54 +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +Dup_PDB EQU 85 ; 85 55 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +Rename EQU 86 ; 86 56 +File_Times EQU 87 ; 87 57 +AllocOper EQU 88 ; 88 58 +; Network extention system calls +GetExtendedError EQU 89 ; 89 59 +CreateTempFile EQU 90 ; 90 5A +CreateNewFile EQU 91 ; 91 5B +LockOper EQU 92 ; 92 5C Lock and Unlock +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +ServerCall EQU 93 ; 93 5D CommitAll, ServerDOSCall, + ; CloseByName, CloseUser, + ; CloseUserProcess, + ; GetOpenFileList +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +UserOper EQU 94 ; 94 5E Get and Set +AssignOper EQU 95 ; 95 5F On, Off, Get, Set, Cancel +xNameTrans EQU 96 ; 96 60 +PathParse EQU 97 ; 97 61 +GetCurrentPSP EQU 98 ; 98 62 +Hongeul EQU 99 ; 99 63 +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +Set_Printer_Flag EQU 100 ; 100 64 +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +GetExtCntry EQU 101 ; 101 65 +GetSetCdPg EQU 102 ; 102 66 +ExtHandle EQU 103 ; 103 67 +Commit EQU 104 ; 104 68 +; +; +Set_Oem_Handler EQU 248 ; 248 F8 +OEM_C1 EQU 249 ; 249 F9 +OEM_C2 EQU 250 ; 250 FA +OEM_C3 EQU 251 ; 251 FB +OEM_C4 EQU 252 ; 252 FC +OEM_C5 EQU 253 ; 253 FD +OEM_C6 EQU 254 ; 254 FE +OEM_C7 EQU 255 ; 255 FF + \ No newline at end of file diff --git a/SRC/DOS/SYSVAR.INC b/SRC/DOS/SYSVAR.INC new file mode 100644 index 0000000..ecd3e48 --- /dev/null +++ b/SRC/DOS/SYSVAR.INC @@ -0,0 +1,24 @@ +; SCCSID = @(#)sysvar.asm 1.1 85/04/10 +SysInitVars STRUC +SYSI_DPB DD ? ; DPB chain +SYSI_SFT DD ? ; SFT chain +SYSI_CLOCK DD ? ; CLOCK device +SYSI_CON DD ? ; CON device +SYSI_MAXSEC DW ? ; maximum sector size +SYSI_BUF DD ? ; buffer chain +SYSI_CDS DD ? ; CDS list +SYSI_FCB DD ? ; FCB chain +SYSI_Keep DW ? ; keep count +SYSI_NUMIO DB ? ; Number of block devices +SYSI_NCDS DB ? ; number of CDS's +SYSI_DEV DD ? ; device list +SysInitVars ENDS + +;This is added for more information exchage between DOS, BIOS. +;DOS will give the pointer to SysInitTable in ES:DI. - J.K. 5/29/86 +SysInitVars_Ext struc +SYSI_InitVars DD 0 ; Points to the above structure. +SYSI_Country_Tab DD 0 ; DOS_Country_cdpg_info +SysInitVars_Ext ends + + \ No newline at end of file diff --git a/SRC/DOS/TIME.OBJ b/SRC/DOS/TIME.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..d411890ecf7ad2072607ea8b4cfc7a7bb925730f GIT binary patch literal 1332 zcmYjRe`p(39RI%L-d&O=X;$zM(M3>aK^*%b5nZdjCbur^l52CyCI3CCA za1M3&cu57mKdz|ptZO%E{S`fxJKe#_R*%jExuLoB0YlZFLBz2dm zxh>1m`5A>fbORF#4<0q{74G*K{}i@+jP=5QZyBwjj2QhI;5rY7SBgtor1BJ)L?j(n zSR_7kKN?IC^99$Z`69#L5Q*?tDFA{d>ls-}z-ToH)L;hp)^Yo8S2|pUAS;X9Dup1B zkWVDlxTGkD;6l|8^nFH-j!sl~ml>Kbb$}1$MlwlVhP7&r&;p};$hTi6i$knIj1KV_ z35{l>X}eEjJ+NG~@uObhR#xrRYyfj=-(drALfb72lU#S$M@LVwJqY6~0vthVez`aH zmC^eJrVM2cuUwy}n|Ey#vsa5Z7u}`pmcgA}y2)HzA#G?H1^TB^0kPMzr)pQ>@{z{) zz2_RzpBrp$;~VeX;}f3k8yC?Ka%R6pH$T0+H0O-p!Ql*M+AX_vZJri?-fYfdMxp6N z>0-lfGWsoylPvfl>9s#%-n7BpdNiEbEeHqfTkQg@LM%jpzP`=7%p`uhtMJ>_WpCrx zt=hFpCt;f$wrCd-II#TKdB6(chM5tOgv`g<2XntjcMXz7eO zf=u@~Sf|_hV{Nr}MZ#GIYolfSBj8>mk;sBBADIE@WL~@|RHF{1SmhVlA?Z z@O>Ad1k7cG`iS)-jvUAQrJdbmUhXi~29th(s7>k~)STkmaVM@@e*}$AJ&8u^&!Ew% zZZtaeJl0!3h!gb~!?3DQ{Z&R*@SqpVAs`elw=N%yeGJgMGgcXrB5-nNtSQNae1O1v zgEt1N#pw04U`!BJ7H=-#`z6t#Skb|I-7qo@1JLJR1)|EUg#d Y+zy0!F6#+^OAkSel?E7__28NPA4VF05C8xG literal 0 HcmV?d00001 diff --git a/SRC/DOS/UTIL.OBJ b/SRC/DOS/UTIL.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..f244718290d99ec7cc7a451429a7808fe0798248 GIT binary patch literal 546 zcmXxc!E4h{0LSs)Yu-!Rsdb_jCphpDCc?^At%`JzCXJiaru3yCl)4RD@Ss&<>QM&m z#W^G=mEpmEKD0KJIXaD+%c*6!M%r@tt%lRA)2hK;#$BV~GS?_qEBkLXECA^=S&+3VM-*}@DaJ@P zdCg>q9@iJ7QskMe2Y{xL-@93;f{2t*1QkrE=FTO|n0?Rd_WZh4hE{Jl=K7k2G`HP# zqto%AHF>2G)5iO+V8G%l70_?aFTK{$pIqO*uq-6D z#*5)f{H0C3lltX0)x*+2i2k30=tTX~Rs8*-OzsZ$)XBK;J>JN~8$L6m{SlSKvSJtjn=FWUKOEVah>-(5qf + +Asmvar AltVect + +INTTAB EQU 20H +INTBASE EQU 4 * inttab +ENTRYPOINT EQU INTBASE+40H + + IF ALTVECT +ALTTAB EQU 0F0H +ALTBASE EQU 4 * ALTTAB + ENDIF + +; +; interrupt assignments +; + IF NOT ALTVECT +int_abort EQU INTTAB ; abort process +int_command EQU int_abort+1 ; call MSDOS +int_terminate EQU int_abort+2 ; int to terminate address +int_ctrl_c EQU int_abort+3 ; ^c trapper +int_fatal_abort EQU int_abort+4 ; hard disk error +int_disk_read EQU int_abort+5 ; logical sector disk read +int_disk_write EQU int_abort+6 ; logical sector disk write +int_keep_process EQU int_abort+7 ; terminate program and stay + ; resident +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +int_spooler EQU int_abort+8 ; spooler call +int_fastcon EQU int_abort+9 ; fast CON interrupt +int_IBM EQU int_abort+10; critical section maintenance +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + ELSE +int_abort EQU INTTAB ; abort process +int_command EQU int_abort+1 ; call MSDOS +int_terminate EQU ALTTAB ; int to terminate address +int_ctrl_c EQU int_terminate+1 ; ^c trapper +int_fatal_abort EQU int_terminate+2 ; hard disk error +int_disk_read EQU int_abort+5 ; logical sector disk read +int_disk_write EQU int_abort+6 ; logical sector disk write +int_keep_process EQU int_abort+7 ; terminate program and stay resident +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +int_spooler EQU int_terminate+3 ; spooler call +int_fastcon EQU int_abort+9 ; fast CON interrupt +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; + ENDIF + +addr_int_abort EQU 4 * int_abort +addr_int_command EQU 4 * int_command +addr_int_terminate EQU 4 * int_terminate +addr_int_ctrl_c EQU 4 * int_ctrl_c +addr_int_fatal_abort EQU 4 * int_fatal_abort +addr_int_disk_read EQU 4 * int_disk_read +addr_int_disk_write EQU 4 * int_disk_write +addr_int_keep_process EQU 4 * int_keep_process +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P R O G R A M M E R ; +; ; +addr_int_spooler EQU 4 * int_spooler +addr_int_fastcon EQU 4 * int_fastcon +addr_int_IBM EQU 4 * int_IBM +; ; +; C A V E A T P R O G R A M M E R ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; diff --git a/SRC/INC/MACRO.INC b/SRC/INC/MACRO.INC new file mode 100644 index 0000000..cf11a24 --- /dev/null +++ b/SRC/INC/MACRO.INC @@ -0,0 +1,19 @@ + PAGE +;***************************************************************************; +; MACRO DEFINITION ; +;***************************************************************************; + +PRINT MACRO MESSAGE + MOV DX,OFFSET MESSAGE&_PTR + PUSH DX + PUSH CS + CALL PRINTF +ENDM + + + +INPUT MACRO MESSAGE + PRINT MESSAGE + CALL PROMPT +ENDM + \ No newline at end of file diff --git a/SRC/INC/STRUC.INC b/SRC/INC/STRUC.INC new file mode 100644 index 0000000..7a81ed6 --- /dev/null +++ b/SRC/INC/STRUC.INC @@ -0,0 +1,573 @@ +;;STRUC.INC--Stucture Macro Library +;;Version 2.10 03/07/86 + +if1 +$noconj equ 0 +$and equ 1 +$or equ 2 +$short equ 3 +$near equ 4 +$andor = 0 +$temp = 0 +$temp2 = 0 +$dist = 0 + +$notype equ 10 +$conjif equ 11 +$iftype equ 12 +$elsetype equ 13 +$whiletype equ 14 +$conjwhile equ 15 +$repeattype equ 16 +$conjuntil equ 17 +$fortype equ 18 +$conjleave equ 19 + +jbuild macro c1,c2,blank +j&c1 macro tgt +.xcref j&c1 + j&c2 tgt + blank&endm + endm + + irp x,<,,,,,,,> + jbuild x + endm + + irp x, + jbuild nn&x,x + endm + +jncxz macro tgt + local skip + jcxz skip + jmp short tgt +skip: + endm + + purge jbuild + +$getconj macro p1 + ifidn , + $andor = $and + endif + ifidn , + $andor = $and + endif + ifidn , + $andor = $or + endif + ifidn , + $andor = $or + endif + endm + +$getdist macro p1 + ifidn , + $dist = $short + endif + ifidn , + $dist = $short + endif + ifidn , + $dist = $near + endif + ifidn , + $dist = $near + endif + endm + + +$poke macro num,value + $st&num = value +.xcref $st&num + endm + +$peek macro sym,num + sym = $st&num + endm + +$push macro value + $st = $st+1 + $poke %$st,value + endm + +$pop macro sym + $peek sym,%$st + $st = $st-1 + endm + +$labl macro num +$l&num: + endm + +$cjump macro lnum,tf,cond,d1,d2 + local skip + $dist = $defdist + ifnb + $getdist d1 + ifnb + $getdist d2 + endif + endif + + if $dist eq $short + ifb + jmp short $l&lnum + else + ifidn , + jn&cond $l&lnum + else + j&cond $l&lnum + endif + endif + else + ifnb + ifidn , + j&cond skip + else + jn&cond skip + endif + endif + jmp $l&lnum + ifnb +skip: + endif + endif + endm + +$cloop macro lnum,cond + loop&cond $l&lnum + endm +;;***************************************************************************** +.if macro tst,p2,p3 + $if_2 p2,p3,tst + endm +$if_2 macro p1,p2,a1,a2,a3 + ifb + $if_3 ,a1,,p1,p2 + else + $if_3 ,a2,,p1,p2 + endif + endm +$if_3 macro arg1,cond,arg2,p4,p5 + $peek $temp,%$st + if $temp eq $conjif + $pop $temp + else + $push $elseiffound + $elseiffound = 0 + $orfound = 0 + $sn = $sn+1 + $push $sn + $sn = $sn+1 + $push $sn + $sn = $sn+1 + $push $sn + endif + + $andor = $noconj + ifnb + $getconj p4 + ifnb + $getconj p5 + endif + endif + + ifnb + cmp arg1,arg2 + endif + + if $andor eq $noconj + $cjump %$sn-1,f,cond,p4,p5 + $pop $temp + if $orfound + $labl %$temp + endif + $push $iftype + else + if $andor eq $and + $cjump %$sn-1,f,cond,p4,p5 + else + $orfound = 1 + $cjump %$sn,t,cond,p4,p5 + endif + $push $conjif + endif + endm +;;***************************************************************************** +.then macro + $peek $temp,%$st + if $temp ne $iftype + structure error--then without if + endif + endm +;;***************************************************************************** +.elseif macro tst,p2,p3 + $elseif_2 p2,p3,tst + endm +$elseif_2 macro p1,p2,a1,a2,a3 + ifb + $elseif_3 ,a1,,p1,p2 + else + $elseif_3 ,a2,,p1,p2 + endif + endm +$elseif_3 macro arg1,cond,arg2,p4,p5 + $pop $temp + if $temp ne $iftype + structure error--elseif without if + exitm + endif + $elseiffound = 1 + $orfound = 0 + $pop $temp + $peek $temp2,%$st + $cjump %$temp2,,,near + $labl %$temp + $sn = $sn+1 + $push $sn + $sn = $sn+1 + $push $sn + + $andor = $noconj + ifnb + $getconj p4 + ifnb + $getconj p5 + endif + endif + + ifnb + cmp arg1,arg2 + endif + + if $andor eq $noconj + $cjump %$sn-1,f,cond,p4,p5 + $pop $temp + if $orfound + $labl %$temp + endif + $push $iftype + else + if $andor eq $and + $cjump %$sn-1,f,cond,p4,p5 + else + $orfound = 1 + $cjump %$sn,t,cond,p4,p5 + endif + $push $conjif + endif + endm +;;***************************************************************************** +.else macro dist + $pop $temp + if $temp ne $iftype + structure error--else without if + exitm + endif + $sn = $sn+1 + $cjump %$sn,,,dist + $pop $temp + $labl %$temp + $push $sn + $push $elsetype + endm +;;***************************************************************************** +.endif macro + $pop $temp + if $temp ne $iftype + if $temp ne $elsetype + structure error--endif without if + exitm + endif + endif + $pop $temp + $labl %$temp + $pop $temp + if $elseiffound + $labl %$temp + endif + $pop $elseiffound + endm +;;***************************************************************************** +.while macro tst,p2,p3 + $while_2 p2,p3,tst + endm +$while_2 macro p1,p2,a1,a2,a3 + ifb + $while_3 ,a1,,p1,p2 + else + $while_3 ,a2,,p1,p2 + endif + endm +$while_3 macro arg1,cond,arg2,p4,p5 + $peek $temp,%$st + if $temp eq $conjwhile + $pop $temp + else + $push $endloop + $orfound = 0 + $sn = $sn + 1 + $push $sn + $labl %$sn + $sn = $sn + 2 + $push $sn + $endloop = $sn - 1 + endif + + $andor = $noconj + ifnb + $getconj p4 + ifnb + $getconj p5 + endif + endif + + ifnb + cmp arg1,arg2 + endif + + if $andor eq $noconj + $cjump %$sn-1,f,cond,p4,p5 + $pop $temp + if $orfound + $labl %$temp + endif + $push $whiletype + else + if $andor eq $and + $cjump %$sn-1,f,cond,p4,p5 + else + $orfound = 1 + $cjump %$sn,t,cond,p4,p5 + endif + $push $conjwhile + endif + endm +;;***************************************************************************** +.endwhile macro + $pop $temp + if $temp ne $whiletype + structure error -- endwhile without while + exitm + endif + $pop $temp + $cjump %$temp,,,near + $labl %$temp+1 + $pop $endloop + endm +;;***************************************************************************** +.repeat macro + $push $endloop + $push $leavefound + $sn = $sn+1 + $labl %$sn + $push $sn + $push $repeattype + $sn = $sn+1 + $endloop = $sn + $leavefound = 0 + endm +;;***************************************************************************** +.until macro tst,p2,p3 + $until_2 p2,p3,tst + endm +$until_2 macro p1,p2,a1,a2,a3 + ifb + $until_3 ,,,near + else + ifb + $until_3 ,a1,,p1,p2 + else + $until_3 ,a2,,p1,p2 + endif + endif + endm +$until_3 macro arg1,cond,arg2,p4,p5 + $pop $temp + if $temp ne $repeattype + if $temp ne $conjuntil + structure error -- until without repeat + exitm + endif + else + $orfound = 0 + endif + + ifnb + cmp arg1,arg2 + endif + + $andor = $noconj + ifnb + $getconj p4 + ifnb + $getconj p5 + endif + endif + + if $andor eq $noconj + $pop $temp + $cjump %$temp,f,cond,p4,p5 + if $orfound or $leavefound + $labl %$temp+1 + endif + $pop $leavefound + $pop $endloop + else + $peek $temp,%$st + if $andor eq $and + $cjump %$temp,f,cond,p4,p5 + else + $orfound = 1 + $cjump %$temp+1,t,cond,p4,p5 + endif + $push $conjuntil + endif + endm +;;***************************************************************************** +.loop macro cond + $pop $temp + if $temp ne $repeattype + structure error -- loop without repeat + exitm + endif + $pop $temp + $cloop %$temp,cond + if $leavefound + $labl %$temp+1 + endif + $pop $leavefound + $pop $endloop + endm +;;***************************************************************************** +.for macro index,equals,start,to,stop,by,step,dist + mov index,start + $push $endloop + $sn = $sn+1 + $push $sn + $labl %$sn + $sn = $sn+1 + $endloop = $sn + cmp index,stop + + ifb + $push 1 + $cjump %$sn,t,gt,by + else + $push %(step) + if step lt 0 + $cjump %$sn,t,lt,dist + else + $cjump %$sn,t,gt,dist + endif + endif + $push $fortype + endm +;;***************************************************************************** +.next macro index + $pop $temp + if $temp ne $fortype + structure error -- next without for + exitm + endif + $pop $temp + if $temp eq 1 + inc index + else + if $temp eq -1 + dec index + else + add index,$temp + endif + endif + $pop $temp + $cjump %$temp,,,near + $labl %$temp+1 + $pop $endloop + endm +;;***************************************************************************** +.leave macro tst,p2,p3 + $leave_2 p2,p3,tst + endm + +$leave_2 macro p1,p2,a1,a2,a3 + $dist = 0 + $getdist + if $dist + $leave_3 ,,,a1 + else + ifb + $leave_3 ,a1,,p1,p2 + else + $leave_3 ,a2,,p1,p2 + endif + endif + endm + +$leave_3 macro arg1,cond,arg2,p4,p5 + ife $endloop + structure error--leave outside a loop + exitm + endif + $leavefound = 1 + $peek $temp,%$st + if $temp eq $conjleave + $pop $temp + else + $orfound = 0 + $sn = $sn + 1 + endif + + $andor = $noconj + ifnb + $getconj p4 + ifnb + $getconj p5 + endif + endif + + ifnb + cmp arg1,arg2 + endif + + if $andor eq $noconj + $cjump %$endloop,t,cond,p4,p5 + if $orfound + $labl %$sn + endif + else + if $andor eq $and + $orfound = 1 + $cjump %$sn,f,cond,p4,p5 + else + $cjump %$endloop,t,cond,p4,p5 + endif + $push $conjleave + endif + endm +;;***************************************************************************** +else + $pop $temp + if $temp ne $notype + structure error -- open structure(s) + endif + .xcref $noconj,$and,$or,$short,$near,$andor,$temp,$temp2,$dist + .xcref $notype,$conjif,$iftype,$elsetype,$whiletype,$conjwhile + .xcref $repeattype,$conjuntil,$fortype,$conjleave,jncxz + .xcref jeq,jgt,jlt,jneq,jngt,jnlt,jnna,jnnae,jnnb,jnnbe,jnnc,jnncxz + .xcref jnne,jnng,jnnge,jnnl,jnnle,jnno,jnnp,jnns,jnnz,jnpe,jnpo,jbuild + .xcref $getconj,$getdist,$poke,$peek,$push,$pop,$labl,$cjump,$cloop + .xcref $if_2,$if_3,$elseif_2,$elseif_3,$while_2,$while_3 + .xcref $until_2,$until_3,$leave_2,$leave_3 + .xcref $st,$sn,$orfound,$elseiffound,$endloop,$leavefound,$defdist +endif +$st = 0 +$sn = 0 +$orfound = 0 +$elseiffound = 0 +$endloop = 0 +$leavefound = 0 +$defdist = $short +$push %$notype diff --git a/SRC/INC/VERSION.INC b/SRC/INC/VERSION.INC new file mode 100644 index 0000000..96febeb --- /dev/null +++ b/SRC/INC/VERSION.INC @@ -0,0 +1,92 @@ +TRUE EQU 0FFFFh +TRUEBYTE EQU 0FFh +FALSE EQU 0 +; +; Use the following switches to control cmacros.inc +; +?PLM = 0 +?WIN = 0 + +memS EQU 1 ; Small model +; +; Use the switches below to produce the standard Microsoft version or the IBM +; version of the operating system +; +; The below chart will indicate how to set the switches to build the various +; versions +; +; IBMVER IBMCOPYRIGHT +; -------------------------------------------------------- +; IBM Version | TRUE TRUE +; -------------------------------------------------------- +; MS Version | FALSE FALSE +; -------------------------------------------------------- +; Clone Version | TRUE FALSE +; +IBMVER EQU TRUE +IBMCOPYRIGHT EQU FALSE + +MSVER EQU NOT IBMVER +IBM EQU IBMVER +; +; + IF1 + IF IBMVER + IF IBMCOPYRIGHT + %OUT ... IBM version build switch on ... + ELSE + %OUT ... CLONE version build switch on ... + ENDIF + ELSE + IF NOT IBMCOPYRIGHT + %OUT ... MS version build switch on ... + ELSE + %OUT !!!!!!!!! VERSION SWITCHES SET INCORECTLY !!!!!!!!! + %OUT !!!!!!!!! CHECK SETTINGS IN INC\VERSION.INC !!!!!!!!! + ENDIF + ENDIF + ENDIF +; +; +;*************************************************************************** +;* The following switches are for DBCS or SBCS support * +;* * +;* Set INTERNAT EQU TRUE FOR DBCS * +;* Set INTERNAT EQU FALSE FOR SBCS * +;* * +;*************************************************************************** +; +IBMJAPVER EQU FALSE ;If TRUE set KANJI true also + +; +; Switch INTERNAT for DBCS support +; +INTERNAT EQU FALSE +; + IF INTERNAT +ALTVECT EQU FALSE ;Switch to build ALTVECT version +KANJI EQU TRUE +IBMJAPAN EQU TRUE + ELSE +ALTVECT EQU FALSE ;Switch to build ALTVECT version +KANJI EQU FALSE +IBMJAPAN EQU FALSE + ENDIF +; +; Country code switches +; The default contry code is assumed as USA. +; + IF INTERNAT + KOREA EQU TRUE + JAPAN EQU FALSE + ELSE + KOREA EQU FALSE + JAPAN EQU FALSE + ENDIF +; + IF1 + IF INTERNAT +%OUT Internat(ECS) version build switch on + ENDIF + ENDIF + \ No newline at end of file diff --git a/SRC/INC/VERSIONA.INC b/SRC/INC/VERSIONA.INC new file mode 100644 index 0000000..20435f3 --- /dev/null +++ b/SRC/INC/VERSIONA.INC @@ -0,0 +1,19 @@ + +major_version equ 3 ;Major DOS version +minor_version equ 30 ;Minor DOS Version + +expected_version equ (MINOR_VERSION SHL 8)+MAJOR_VERSION + + if1 + %OUT ... for DOS Version 3.30 ... + endif + + ;****************************** + ;Each assembler program should: + ; mov ah,030h ;DOS Get Version function + ; int 021h ;Version ret. in AX,minor version first + ; cmp ax,expected_version ;ALL utilities should check for an + ; jne error_handler ; EXACT version match. + ;****************************** + + \ No newline at end of file diff --git a/SRC/LIBC/CDS.C b/SRC/LIBC/CDS.C new file mode 100644 index 0000000..fe0a1d9 --- /dev/null +++ b/SRC/LIBC/CDS.C @@ -0,0 +1,129 @@ +/* cds utilities */ +#include "types.h" +#include "sysvar.h" +#include "cds.h" +#include "dpb.h" +#include + +extern struct sysVarsType SysVars ; + +char fGetCDS(i, pLCDS) +int i ; +struct CDSType *pLCDS ; +{ + struct CDSType far *cptr ; + int j ; + + if (i >= 0 && i < SysVars.cCDS) { + *(long *)(&cptr) = SysVars.pCDS + (i * sizeof(*pLCDS)) ; + + for (j=0 ; j <= sizeof(*pLCDS) ; j++) + *((char *)pLCDS+j) = *((char far *)cptr+j) ; + + return TRUE ; + } ; + return FALSE ; +} + + + + +char fPutCDS(i, pLCDS) +int i ; +struct CDSType *pLCDS ; +{ + struct CDSType far *cptr ; + int j ; + + if (i >= 0 && i < SysVars.cCDS) { + *(long *)(&cptr) = SysVars.pCDS + (i * sizeof(*pLCDS)) ; + + for (j=0 ; j <= sizeof(*pLCDS) ; j++) + *((char far *)cptr+j) = *((char *)pLCDS+j) ; + + return TRUE ; + } ; + return FALSE ; +} + +/* returns TRUE if drive i is a physical drive. Physical means that logical + * drive n corresponds with physical drive n. This is the case ONLY if the + * CDS is inuse and the DPB corresponding to the CDS has the physical drive + * equal to the original drive. + */ + +char fPhysical(i) +int i ; +{ + struct DPBType DPB ; + struct DPBType *pd = &DPB ; + struct DPBType far *dptr ; + int j ; + + struct CDSType CDS ; + + if (!fGetCDS(i, &CDS)) + return FALSE ; + + if (TESTFLAG(CDS.flags,CDSNET | CDSSPLICE | CDSLOCAL)) + return FALSE ; + + *(long *)(&dptr) = CDS.pDPB ; + + for (j=0 ; j <= sizeof(DPB) ; j++) + *((char *)pd+j) = *((char far *)dptr+j) ; + + return(i == DPB.drive) ; +} + +/* return TRUE if the specified drive is a network drive. i is a 0-based + * quantity + */ + +/* MODIFICATION HISTORY + * + * M000 June 5/85 Barrys + * Removed extra net check. + */ + +char fNet(i) +int i ; +{ + union REGS ir ; + register union REGS *iregs = &ir ; /* Used for DOS calls */ + + struct CDSType CDS ; + + if (!fGetCDS(i, &CDS)) + return FALSE ; + + iregs->x.ax = IOCTL9 ; /* Function 0x4409 */ + iregs->x.bx = i + 1 ; + intdos(iregs, iregs) ; + +/*** M000 + return(TESTFLAG(CDS.flags,CDSNET) || TESTFLAG(iregs->x.dx,0x1000)) ; +***/ + return(TESTFLAG(CDS.flags,CDSNET)) ; +} + + +/* return TRUE if the specified drive is a shared drive. i is a 0-based + * quantity + */ +char fShared(i) +int i ; +{ + struct CDSType CDS ; + union REGS ir ; + register union REGS *iregs = &ir ; /* Used for DOS calls */ + + if (!fGetCDS(i, &CDS)) + return FALSE ; + + iregs->x.ax = IOCTL9 ; /* Function 0x4409 */ + iregs->x.bx = i + 1 ; + intdos(iregs, iregs) ; + + return TESTFLAG(CDS.flags,CDSNET) || TESTFLAG(iregs->x.dx,0x0200) ; +} diff --git a/SRC/LIBC/DPB.C b/SRC/LIBC/DPB.C new file mode 100644 index 0000000..1776f5d --- /dev/null +++ b/SRC/LIBC/DPB.C @@ -0,0 +1,37 @@ +/* dpb.c - retrieve DPB for physical drive */ + +#include "types.h" +#include "sysvar.h" +#include "dpb.h" +#include "cds.h" + +extern char NoMem[], ParmNum[], BadParm[] ; +extern struct sysVarsType SysVars ; + + +/* Walk the DPB list trying to find the appropriate DPB */ + +long GetDPB(i) +int i ; +{ + struct DPBType DPB ; + struct DPBType *pd = &DPB ; + struct DPBType far *dptr ; + int j ; + + *(long *)(&dptr) = DPB.nextDPB = SysVars.pDPB ; + DPB.drive = -1 ; + + while (DPB.drive != i) { + if ((int)DPB.nextDPB == -1) + return -1L ; + + *(long *)(&dptr) = DPB.nextDPB ; + + for (j=0 ; j <= sizeof(DPB) ; j++) + *((char *)pd+j) = *((char far *)dptr+j) ; + + } ; + return (long)dptr ; +} + diff --git a/SRC/LIBC/ERRTST.C b/SRC/LIBC/ERRTST.C new file mode 100644 index 0000000..e253779 --- /dev/null +++ b/SRC/LIBC/ERRTST.C @@ -0,0 +1,271 @@ +#include "types.h" +#include "dpb.h" +#include + +/* #define KANJI TRUE */ + +/* return FALSE if drive is valid AND the path is not a prefix of a non-root + * current directory. + */ +char fPathErr(p) +char *p ; +{ + char buf[MAXARG] ; + int d ; +#ifdef KANJI + char *p1; +#endif + + if (p[1] == ':') + d = *p-'A'+1 ; + else + d = 0 ; + + if (curdir(buf, d) == -1) /* drive is invalid => error */ + return(TRUE) ; + + if (strlen(buf) == 3) /* current directory is root => OK */ + return(FALSE) ; + + if (strpre(p, buf)) { +#ifdef KANJI + p1 = p; + while (*p1 != NULL) { + if(testkanj(*p1 & 0xFF)) + p1 += 2 ; + else + if((*p1++ == '\\') && (*p1 == NULL)) + return(TRUE) ; + } +#else + if (p[strlen(p)-1] == '\\') /* prefix matched, prefix had...*/ + return(TRUE) ; /* ...trailing / => valid ... */ + /* ...prefix => ERROR */ +#endif + d = buf[strlen(p)] ; + if (d == 0 || d == '\\') /* prefix matched,... */ + return(TRUE) ; /* ...prefix had no trailing /, */ + /* ...next char was / => ... */ + /* ...valid prefix => ERROR */ + } ; + + return(FALSE) ; /* drive letter good and not valid prefix => OK */ +} + + +strpre(pre, tot) + char *pre; + char *tot; +{ + return(!strncmp(pre, tot, strlen(pre))); +} + + + +Fatal(p) +char *p ; +{ + printf("%s\n", p) ; + exit(1) ; +} + + + + +ffirst(pb, attr, pfbuf) +char *pb ; +int attr ; +struct findType *pfbuf ; +{ + union REGS regs ; + + /* set DMA to point to buffer */ + + regs.h.ah = 0x1A ; + regs.x.dx = (unsigned) pfbuf ; + intdos (®s, ®s) ; + + /* perform system call */ + + regs.h.ah = 0x4E ; + regs.x.cx = attr ; + regs.x.dx = (unsigned) pb ; + intdos (®s, ®s) ; + + return (regs.x.cflag ? -1 : 0) ; +} + +fnext (pfbuf) +struct findType *pfbuf; +{ + union REGS regs; + + /* set DMA to point to buffer */ + regs.h.ah = 0x1A; + regs.x.dx = (unsigned) pfbuf; + intdos (®s, ®s); + /* perform system call */ + regs.h.ah = 0x4F; + intdos (®s, ®s); + return (regs.x.cflag ? -1 : 0) ; +} + + +char *strbscan(str, class) +char *str ; +char *class ; +{ + char *p ; + char *strpbrk() ; + + p = strpbrk(str, class) ; + return((p == NULL) ? (str + strlen(str)) : p) ; +} + + + + + +/* curdir.c - return text of current directory for a particular drive */ + + +curdir (dst, drive) +char *dst ; +int drive ; +{ + union REGS regs ; + + *dst++ = PathChr ; + regs.h.ah = 0x47 ; + regs.h.dl = drive ; + regs.x.si = (unsigned) dst ; + intdos (®s, ®s) ; + return(regs.x.cflag ? -1 : 0) ; +} + + + + +/* + rootpath +*/ + +/*** rootpath -- convert a pathname argument to root based cannonical form + * + * rootpath determines the current directory, appends the path argument (which + * may affect which disk the current directory is relative to), and qualifies + * "." and ".." references. The result is a complete, simple, path name with + * drive specifier. + * + * If the relative path the user specifies does not include a drive spec., the + * default drive will be used as the base. (The default drive will never be + * changed.) + * + * entry: relpath -- pointer to the pathname to be expanded + * fullpath -- must point to a working buffer, see warning + * exit: fullpath -- the full path which results + * return: true if an error occurs, false otherwise + * + * calls: curdir, getdrv + * + * warning: fullpath must point to a working buffer large enough to hold the + * longest possible relative path argument plus the longest possible + * current directory path. + * + */ +int rootpath(relpath, fullpath) +char *relpath ; +char *fullpath ; +{ + int drivenum ; + char tempchar, getdrv() ; + register char *lead, *follow ; + char *p1, *p2; + + + /* extract drive spec */ + drivenum = getdrv() ; + if ((*relpath != NULL) && (relpath[1] == COLON)) { + drivenum = toupper(*relpath) - 'A' ; + relpath += 2 ; + } + fullpath[0] = (char) ('A' + drivenum) ; + fullpath[1] = COLON ; + + /* append relpath to fullpath/base */ + if (*relpath == PathChr) { + /* relpath starts at base */ + strcpy(fullpath+2, relpath) ; + } + else { + /* must get base path first */ + if (curdir(fullpath+2, drivenum+1)) + return(TRUE) ; /* terrible error */ + if ((*relpath != ASCNULL) && (strlen(fullpath) > 3)) + strcat(fullpath, "\\") ; + strcat(fullpath, relpath) ; + } + + + /* convert path to cannonical form */ + lead = fullpath ; + while(*lead != ASCNULL) { + /* mark next path segment */ + follow = lead ; + lead = (char *) strpbrk(follow+1, "\\") ; + if (lead == NULL) + lead = fullpath + strlen(fullpath) ; + tempchar = *lead ; + if (tempchar == PathChr) + tempchar = BACKSLASH ; /* make breaks uniform */ + *lead = ASCNULL ; + + /* "." segment? */ + if (strcmp(follow+1, ".") == 0) { + *lead = tempchar ; + strcpy(follow, lead) ; /* remove "." segment */ + lead = follow ; + } + + /* ".." segment? */ + else if (strcmp(follow+1, "..") == 0) { + *lead = tempchar ; + tempchar = *follow ; + *follow = NULL ; + p2 = fullpath - 1 ; + while(*(p2=strbscan(p1=p2+1,"\\")) != NULL) ; + /* p1 now points to the start of the previous element */ + *follow = tempchar ; + if(p1 == fullpath) + return(TRUE) ; /* tried to .. the root */ + follow = p1 - 1 ; /* follow points to path sep */ + strcpy(follow, lead) ; /* remove ".." segment */ + lead = follow ; + } + + /* normal segment */ + else + *lead = tempchar ; + } + if (strlen(fullpath) == 2) /* 'D:' or some such */ + strcat(fullpath, "\\") ; + + /* shift to upper case */ + strupr(fullpath) ; + + return(FALSE) ; +} + + +/* getdrv - return current drive as a character */ + + +char getdrv() +{ + union REGS regs ; + + regs.h.ah = CURDISK ; /* Function 0x19 */ + intdos (®s, ®s) ; + return(regs.h.al) ; +} + \ No newline at end of file diff --git a/SRC/LIBC/ITOUPPER.ASM b/SRC/LIBC/ITOUPPER.ASM new file mode 100644 index 0000000..481f44b --- /dev/null +++ b/SRC/LIBC/ITOUPPER.ASM @@ -0,0 +1,34 @@ +.xlist +include cmacros.inc +.list + +sBegin code +assumes cs,code + +; +; c = IToupper (c, routine); +; +; c is char to be converted +; routine is case map call in international table +; + +cProc IToupper, +parmW c +parmD routine +cBegin + mov ax,c + or ah,ah + jnz donothing + cmp al,'a' + jb noconv + cmp al,'z' + ja noconv + sub al,20H +noconv: + call routine +donothing: +cEnd + +sEnd + +end diff --git a/SRC/LIBC/JOIN.C b/SRC/LIBC/JOIN.C new file mode 100644 index 0000000..b741e63 --- /dev/null +++ b/SRC/LIBC/JOIN.C @@ -0,0 +1,253 @@ +/*** MSDOS JOIN Utility Vers 4.0 + * + * This utility allows the splicing of a physical drive to a pathname + * on another physical drive such that operations performed using the + * pathname as an arguement take place on the physical drive. + * + * MODIFICATION HISTORY + * + * Converted to CMERGE 03/26/85 by Greg Tibbetts + * + * M000 May 23/85 Barrys + * Disallow splicing similar drives. + * + * M001 May 24/85 Barrys + * The original IBM version of JOIN allowed the delete splice switch + * "/D" immediately after the drive specification. The argument parsing + * code has been modified to allow this combination. + * + * M002 June 5/85 Barrys + * Changed low version check for specific 320. + * + * M003 July 15/85 Barrys + * Checked for any possible switch characters in the other operands. + * + * M004 July 15/85 Barrys + * Moved check for physical drive before check for NET and SHARED tests. + * + * 33D0016 July 16/86 Rosemarie Gazzia + * Put SHARED test on an equal basis with physical drive check. + * Last fix (M004) erroneously allowed joining physical or local shared + * drives. This is because it only performed the SHARED test if the drive + * failed the physical test. + */ + +#include "types.h" +#include "versionc.h" +#include "sysvar.h" +#include "cds.h" +#include +#include + +extern char NoMem[], ParmNum[], BadParm[], DirNEmp[], NetErr[], BadVer[] ; +extern char *strchr(); /* M003 */ + +struct sysVarsType SysVars ; + + +/*** main - program entry point + * + * Purpose: + * To test arguements for validity and perform the splice + * + * int main(int c, char *v[]) + * + * Args: + * c - the number of command line arguements + * v - pointer to pointers to the command line arguements + * + * Links: + * ERRTST.C - Drive and path validity testing functions + * SYSVAR.C - Functions to get/set DOS System Variable structures + * CDS.C - Functions to get/set DOS CDS structures + * + * Returns: + * Appropriate return code with error message to stdout if + * necessary. + * + */ + +main(c, v) +int c ; +char *v[] ; +{ + char *strbscan() ; + + union REGS ir; + register union REGS *iregs = &ir ; /* Used for DOS calls */ + struct findType findbuf ; + char path [MAXPATHLEN],*p ; + struct CDSType CDS ; + int i ; + int dstdrv; /* dest. drive number M000 */ + int delflag = FALSE; /* delete splice flag M001 */ + int arglen; /* length of argument M001 */ + + /* check os version */ + iregs->h.ah = GETVERS ; /* Function 0x30 */ + intdos(iregs, iregs) ; + + if ( (iregs->h.al != expected_version_major) || (iregs->h.ah != expected_version_minor) ) + Fatal(BadVer); + + /* i = (iregs->h.al * 100) + iregs->h.ah; */ + /* if (i < LowVersion || i > HighVersion) */ + /* Fatal(BadVer) ; */ + + SHIFT(c,v) ; + + for (i=0 ; i < c ; i++) /* Convert to upper case */ + strupr(v[i]) ; + + GetVars(&SysVars) ; /* Access to DOS data structures */ + + if (c > 2) /* M001 */ + Fatal(ParmNum); /* M001 */ + + if (c == 0) + DoList() ; /* list splices */ + else { + /* Process drive letter */ + i = **v - 'A' ; + if ((*v)[1] != ':') { + if (c == 1) { + Fatal(ParmNum); + } + else { + Fatal(BadParm) ; + } + } + if (!fGetCDS(i, &CDS)) { + Fatal(BadParm) ; + } + + /* Accept arguments separate or mixed with drive spec M001 */ + arglen = strlen(*v); + if (arglen != 2) { + if ((*v)[2] != SwitChr) { + Fatal(ParmNum); + } + if (arglen != 4) { + if (c == 1) { + Fatal(BadParm); + } + else { + Fatal(ParmNum); + } + } + /* Advance arg pointer to possible switches */ + (*v)++; (*v)++; + } + else { + SHIFT(c,v) ; + } + /* Check for splice deletion switch */ + if (**v == SwitChr) { + if ((*v)[1] == 'D') + delflag = TRUE; + else { + Fatal(BadParm); + } + } + + if (delflag == TRUE) { /* Deassigning perhaps? */ + + if (!TESTFLAG(CDS.flags, CDSSPLICE)) { + Fatal(BadParm) ; /* If NOT spliced */ + } + + if (fPathErr(CDS.text)) { + Fatal(BadParm) ; /* If prefix of curdir */ + } + + CDS.text[0] = i + 'A' ; + CDS.text[1] = ':' ; + CDS.text[2] = '\\' ; + CDS.text[3] = 0 ; + CDS.cbEnd = 2 ; + + if (i >= SysVars.cDrv) + CDS.flags = FALSE ; + else + CDS.flags = CDSINUSE ; + GetVars(&SysVars) ; + SysVars.fSplice-- ; + PutVars(&SysVars) ; + fPutCDS(i, &CDS) ; + } + else { + /* Test if there are any other possible switches + * in the operand M003 + */ + if (strchr(v[0], SwitChr)) { + Fatal(ParmNum); + } + + if (TESTFLAG(CDS.flags,CDSSPLICE)) { + Fatal(BadParm) ; /* If now spliced */ + } + + rootpath(*v, path) ; /* Get root path */ + strupr(path) ; /* Upper case */ + + /* M004 Start */ + if (i == getdrv() || /* Can't mov curdrv */ + fPathErr(path) || /* or curdir prefix */ + *strbscan(path+3, "/\\") != 0 || + !fPhysical(i) || + fShared(i)) { /* 33D0016 RG */ + /* Determine if it was a NET error */ + if (fNet(i) || fShared(i)) { + Fatal(NetErr) ; + } + Fatal(BadParm) ; + } + + if (fNet(path[0] - 'A') || fNet(path[0] - 'A')) { + Fatal(NetErr) ; /* Same for dest */ + } + /* M004 End */ + + + /* Check src and dst drives are not same */ + dstdrv = *path - 'A'; /* M000 */ + if (i == dstdrv) /* M000 */ + Fatal (BadParm); /* M000 */ + if (mkdir(path) == -1) { /* If can't mkdir */ + /* or if no dir or */ + /* if node is file */ + if (ffirst(path, A_D, &findbuf) == -1 || + !TESTFLAG(findbuf.attr,A_D)) + Fatal(BadParm) ; + + p = path + strlen(path) ; + strcat(p, "\\*.*") ; + + if (ffirst(path, 0, &findbuf) != -1) + Fatal(DirNEmp) ; /* if dir */ + /* not empty */ + *p = 0 ; + } ; + + strcpy(CDS.text, path) ; + CDS.flags = CDSINUSE | CDSSPLICE ; + fPutCDS(i, &CDS) ; + GetVars(&SysVars) ; + SysVars.fSplice++ ; + PutVars(&SysVars) ; + } ; + } + exit(0) ; +} + +DoList() +{ + int i ; + struct CDSType CDS ; + + for (i=0 ; fGetCDS(i, &CDS) ; i++) { + if (TESTFLAG(CDS.flags,CDSSPLICE)) + printf("%c: => %s\n", i+'A', CDS.text) ; + } ; +} + \ No newline at end of file diff --git a/SRC/LIBC/KSTRING.C b/SRC/LIBC/KSTRING.C new file mode 100644 index 0000000..f686ea3 --- /dev/null +++ b/SRC/LIBC/KSTRING.C @@ -0,0 +1,118 @@ +#include "internat.h" +#include +#define NULL 0 +#define TRUE 0xffff +#define FALSE 0 +#define KANJI TRUE +char haveinttab = FALSE; +/* + * ECS Support - This module provides support for international >7FH and + * TWO-BYTE character sets. The toupper routine uses the DOS MAP_CASE call. + * In addition, STRING.C contains a default_tab containing a default lead + * byte table for two byte character sets. If single byte operation is + * desired, modify this table as follows: ="\000". If this utility + * is run on a DOS with Function 63H support, the default table will + * be replaced by the table in the DOS. The lbtbl_ptr is the far ptr to + * which ever table is in use. +*/ +long lbtbl_ptr; +char *default_tab="\201\237\340\374\000\000"; +char have_lbtbl = FALSE; + +struct InterTbl Currtab; + +int toupper(c) +int c; +{ + union REGS regs ; + + if(!haveinttab) { + regs.x.ax = 0x3800 ; + regs.x.dx = (unsigned) &Currtab ; + intdos (®s, ®s) ; /* INIT the table */ + + haveinttab = TRUE; + } + + return(IToupper(c,Currtab.casecall)); + +} + +char *strupr(string) +char *string; +{ + register char *p1; + + p1 = string; + while (*p1 != NULL) { + /* + * A note about the following " & 0xFF" stuff. This is + * to prevent the damn C compiler from converting bytes + * to words with the CBW instruction which is NOT correct + * for routines like toupper + */ +#ifdef KANJI + if(testkanj(*p1 & 0xFF)) + p1 += 2 ; + else + *p1++ = toupper(*p1 & 0xFF); +#else + *p1++ = toupper(*p1 & 0xFF); +#endif + } + return(string); +} + +char *strpbrk(string1,string2) +char *string1; +char *string2; +{ + register char *p1; + + while (*string1 != NULL) { + /* + * A note about the following " & 0xFF" stuff. This is + * to prevent the damn C compiler from converting bytes + * to words with the CBW instruction which is NOT correct + * for routines like toupper + */ +#ifdef KANJI + if(testkanj(*string1 & 0xFF)) + string1 += 2 ; + else { +#endif + p1 = string2; + while (*p1 != NULL) { + if(*p1++ == *string1) + return(string1); + } + string1++; +#ifdef KANJI + } +#endif + + } + return(NULL); /* no matches found */ +} + +#ifdef KANJI +testkanj(c) +unsigned char c; +{ + long *p1; + union REGS regs ; + int i; + + p1 = &lbtbl_ptr ; + if (!have_lbtbl ) { + lbtbl_ptr = default_tab ; /* Load offset in pointer */ + get_lbtbl( p1 ); + have_lbtbl=TRUE; + } + + if ( test_ecs( c, lbtbl_ptr )) + return(TRUE); + else + return(FALSE); +} +#endif diff --git a/SRC/LIBC/PRINTF.ASM b/SRC/LIBC/PRINTF.ASM new file mode 100644 index 0000000..4aabc21 --- /dev/null +++ b/SRC/LIBC/PRINTF.ASM @@ -0,0 +1,414 @@ +TITLE PRINTF ROUTINE FOR MS-DOS +; +; PRINTF(Control String, arg1, arg2,...,argn-1,argn) +; +; Characters are output to PFHandle according to the +; specifications contained in the Control String. +; +; The conversion characters are as follow: +; +; %c - output the next argument as a character +; %s - output the next argument as a string +; %x - output the next argument as a hexidecimal number +; using abcedf +; %X - output the next argument as a hexidecimal number +; using ABCDEF +; %d - output the next argument as a decimal number +; +; +; Other format specifiers that may precede the conversion character are: +; +; - (minus sign) - causes the field to be left-adjusted +; + (plus sign) - causes the field to be right-adjusted (default) +; n - digit specifing the minimum field width (default to 1) +; L - specifing a long integer +; +; On entry to PRINTF the stack contains the return address and a pointer +; to an argument list. +; +; ____________________ +; | Ret Addr | <= SP +; -------------------- +; | Ptr to Arg List | +; -------------------- +; +; And the argument list contains the following: +; +; String_ptr (a pointer to the control string) +; Arg 1 +; Arg 2 +; . +; . +; . +; Arg n-1 +; Arg n +; +; If the argument is a %s or %c the arg contains a pointer to the string +; or character. +; +; The arguments are used in one-to-one correspondence to % specifiers. + +.xlist +.xcref + INCLUDE dossym.inc +.cref +.list + +printf_CODE SEGMENT public byte +ASSUME CS:PRINTF_CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING + + PUBLIC PRINTF, PFHandle + PUBLIC PRINTF_LAST + +PFHandle DW 1 +PRINTF_LEFT DB 0 +PRINTF_LONG DB 0 +PRINTF_HEX DB 0 +TABLE_INDEX DB 0 +S_FLAG DB 0 +PRINTF_WIDTH DW 0 +PRINTF_BASE DW 0 +PAD_CHAR DB " " + +PRINTF_TABLE DB "0123456789ABCDEFabcdef" + +PRINTF_STACK STRUC +OLDES DW ? +OLDDS DW ? +OLDSI DW ? +OLDDI DW ? +OLDAX DW ? +OLDBX DW ? +OLDCX DW ? +OLDDX DW ? +OLDBP DW ? +OLDCS DW ? +OLDIP DW ? +STRING DW ? +PRINTF_STACK ENDS + +PRINTF_ARGS STRUC +CONSTR DW ? +ARG DW ? +PRINTF_ARGS ENDS + +RET_ADDR1 DW ? +RET_ADDR2 DW ? + +BUFSIZ = 20 +PRINTF_BUF DB BUFSIZ DUP (?) + db 0 ;This buffer is always nul terminated +BUFEND DW $-PRINTF_BUF + +PRINTF proc far + PUSH BP ;Save the callers' registers + PUSH DX + PUSH CX + PUSH BX + PUSH AX + PUSH DI + PUSH SI + PUSH ES + PUSH DS + MOV BP,SP + PUSH CS + POP ES ;ES points to Printf segment + MOV DI,OFFSET PRINTF_BUF ;DI points to the output buffer + MOV BP,[BP.STRING] ;BP points to the argument list + MOV SI,DS:[BP] ;SI points to the control string + XOR BX,BX ;BX is the index into the arg list + CALL Clear_flags ; initialize the world +GET_CHAR: + LODSB ;Get a character + CMP AL,"%" ;Is it a conversion specifier? + JZ CONV_CHAR ;Yes - find out which one + OR AL,AL ;Is it the end of the control string? + JZ PRINTF_DONE ;Yes - then we're done + CALL OUTCHR ;Otherwise store the character + JMP SHORT GET_CHAR ;And go get another + +PRINTF_DONE: + CALL FLUSH + POP DS + POP ES + POP SI + POP DI + POP AX + POP BX + POP CX + POP DX + POP BP + POP CS:[RET_ADDR1] ;Fix up the stack + POP CS:[RET_ADDR2] + POP AX + PUSH CS:[RET_ADDR2] + PUSH CS:[RET_ADDR1] + RET + +printf endp + +PRINTF_PERCENT: + CALL OUTCHR + JMP GET_CHAR + +CONV_CHAR: + ;Look for any format specifiers preceeding the conversion character + LODSB + CMP AL,"%" ;Just print the % + JZ PRINTF_PERCENT + CMP AL,"-" ;Right justify the field + JZ LEFT_ADJ + CMP AL,"+" ;Left justify the field + JZ NXT_CONV_CHAR + CMP AL,"L" ;Is it a long integer + JZ LONG_INT + CMP AL,"l" + JZ LONG_INT + CMP AL,"0" ;Is it a precision specification + JB LOOK_CONV_CHAR + CMP AL,"9" + JA LOOK_CONV_CHAR + CMP AL,"0" + JNZ NOT_PAD + CMP CS:[PRINTF_WIDTH],0 + JNZ NOT_PAD + MOV CS:BYTE PTR [PAD_CHAR],"0" +NOT_PAD: + PUSH AX ;Adjust decimal place on precision + MOV AX,10 + MUL CS:[PRINTF_WIDTH] + MOV CS:[PRINTF_WIDTH],AX + POP AX + XOR AH,AH + SUB AL,"0" + ADD CS:[PRINTF_WIDTH],AX ;And save the total + JMP SHORT NXT_CONV_CHAR + + ;Set the correct flags for the options in a conversion + +LEFT_ADJ: + INC CS:BYTE PTR[PRINTF_LEFT] + JMP SHORT NXT_CONV_CHAR + +LONG_INT: + INC CS:BYTE PTR[PRINTF_LONG] +NXT_CONV_CHAR: + JMP CONV_CHAR + + ;Look for a conversion character + +LOOK_CONV_CHAR: + CMP AL,"X" + JZ HEX_UP + + ;Make all other conversion characters upper case + + CMP AL,"a" + JB CAPS + CMP AL,"z" + JG CAPS + AND AL,0DFH +CAPS: + CMP AL,"X" + JZ HEX_LO + CMP AL,"D" + JZ DECIMAL + CMP AL,"C" + JZ C_PUT_CHAR + CMP AL,"S" + JZ S_PUT_STRG + + ;Didn't find any legal conversion character - IGNORE it + + call clear_flags + jmp get_char + +HEX_LO: + MOV CS:[TABLE_INDEX],6 ;Will print lower case hex digits +HEX_UP: + MOV CS:[PRINTF_BASE],16 ;Hex conversion + JMP CONV_TO_NUM + +DECIMAL: + MOV CS:[PRINTF_BASE],10 ;Decimal conversion + JMP CONV_TO_NUM + +S_PUT_STRG: + INC CS:[S_FLAG] ;It's a string specifier +C_PUT_CHAR: + PUSH SI ;Save pointer to control string + MOV SI,BX + ADD BX,2 + MOV SI,ds:[BP+SI.ARG] ;Point to the % string or character + CMP BYTE PTR CS:[S_FLAG],0 + JNZ S_PUT_1 + LODSB + cmp al,0 + jz short c_s_end + CALL OUTCHR ;Put it into our buffer + JMP SHORT C_S_END + +S_PUT_1: + mov cx,cs:[printf_width] + or cx,cx + jz s_put_2 + cmp cs:byte ptr[printf_left],0 + jnz s_put_2 + push si + call Pad_string + pop si +s_put_2: + push si +s_put_3: + LODSB ;Put them all in our buffer + CMP AL,0 + jz s_put_4 + CALL OUTCHR + jmp short S_PUT_3 +s_put_4: + pop si + cmp byte ptr[printf_left],0 + jz c_s_end + mov cx,cs:[printf_width] + or cx,cx + jz c_s_end + call Pad_string +C_S_END: + call clear_flags + POP SI ;Restore control string pointer + JMP GET_CHAR ;Go get another character + +pad_string: + xor dx,dx +count_loop: + lodsb + or al,al + jz count_done + inc dx + jmp short count_loop +count_done: + sub cx,dx + jbe count_ret + call pad +count_ret: + ret + +CONV_TO_NUM: + + PUSH SI ;Save pointer to control string + MOV SI,BX ;Get index into argument list + ADD BX,2 ;Increment the index + MOV AX,ds:[BP+SI.ARG] ;Lo word of number in SI + CMP BYTE PTR CS:[PRINTF_LONG],0 ;Is this is a short or long integer? + JZ NOT_LONG_INT + MOV SI,BX ;Copy index + ADD BX,2 ;Increment the index + MOV DX,ds:[BP+SI.ARG] ;Hi word of number in BP + JMP SHORT DO_CONV +NOT_LONG_INT: + XOR DX,DX ;Hi word is zero +DO_CONV: + PUSH BX ;Save index into arguemnt list + MOV si,CS:[PRINTF_BASE] + MOV cx,CS:[PRINTF_WIDTH] + CALL PNUM + CALL PAD +CONV_DONE: + call clear_flags + POP BX + POP SI + jmp get_char + +PNUM: + DEC CX + PUSH AX + MOV AX,DX + XOR DX,DX + DIV SI + MOV BX,AX + POP AX + DIV SI + XCHG BX,DX + PUSH AX + OR AX,DX + POP AX + JZ DO_PAD + PUSH BX + CALL PNUM + POP BX + JMP SHORT REM +DO_PAD: + CMP CS:BYTE PTR[PRINTF_LEFT],0 + JNZ REM + CALL PAD +REM: + MOV AX,BX + CMP AL,10 + JB NOT_HEX + CMP CS:BYTE PTR [PRINTF_HEX],0 + JNZ NOT_HEX + ADD AL,CS:BYTE PTR [TABLE_INDEX] +NOT_HEX: + MOV BX,OFFSET PRINTF_TABLE + PUSH DS + PUSH CS + POP DS + XLAT 0 + POP DS + push cx + CALL OUTCHR + pop cx + RET + +PAD: + OR CX,CX + JLE PAD_DONE + MOV AL,CS:BYTE PTR [PAD_CHAR] +PAD_LOOP: + push cx + CALL OUTCHR + pop cx + LOOP PAD_LOOP +PAD_DONE: + RET + +OUTCHR: + STOSB + CMP DI,offset bufend-1 ;Don't count the nul + RETNZ + MOV CX,BUFSIZ +WRITE_CHARS: + push bx + MOV BX,PFHandle + push ds + PUSH CS + POP DS + MOV DX,OFFSET PRINTF_BUF + MOV AH,WRITE + INT 21H + pop ds + pop bx + MOV DI,OFFSET PRINTF_BUF + RET + +FLUSH: + CMP DI,OFFSET PRINTF_BUF + RETZ + SUB DI,OFFSET PRINTF_BUF + MOV CX,DI + call write_chars + ret + +CLEAR_FLAGS: + XOR ax,ax + MOV BYTE PTR CS:[PRINTF_LEFT],al ;Reset justifing flag + MOV BYTE PTR CS:[PRINTF_LONG],al ;Reset long flag + MOV BYTE PTR CS:[TABLE_INDEX],al ;Reset hex table index + MOV CS:[PRINTF_WIDTH],ax ;Reinitialize width to 0 + MOV BYTE PTR CS:[PAD_CHAR]," " ;Reset padding character + MOV BYTE PTR CS:[S_FLAG],al ;Clear the string flag + ret + +PRINTF_LAST LABEL WORD +printf_CODE ENDS + END diff --git a/SRC/LIBC/PRINTF.OBJ b/SRC/LIBC/PRINTF.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..0d9d0165cfe896f003206d773b9a1a36e4c11737 GIT binary patch literal 1159 zcmX|>U1$_n7>3_Do88r&7;8|kG>M{%KXq7LjV7K%^J7#9?V640#$Y6Byb{qcMp4j6 zb`%|G_e#7F3@s=~z#9c^FB+Vgtw}1twf1%v?s1OctQ)bM#>>G&4Q)k7p ze`!_9RR6q&tfPX%lRT*_M2fxG};5g81g%ajY^oC zRnxVGtwj*N$ zUs^Q;H~b4wRZ;z`km;8`v(z*`-GSc_rCxI zA_Dil4=YS86<#?Jg|~nZuoe+RniUUXs$BuEmWaY?2x41_w6I!asXL>S&AQ4Z@d!9M>XbXd;< zOKqhd-b|UMc^^2BgU_}PJwR~$=NHmiBl7AN1oBIW5c123F!Jh7qR6XF>c}UF2-3N^ sfHo`DwxjRJ!NdLh9}ec`&{KT9Gyv_nO4_AYOnXzh^Qge7OM=hOXD*r{5C8xG literal 0 HcmV?d00001 diff --git a/SRC/LIBC/STRING.C b/SRC/LIBC/STRING.C new file mode 100644 index 0000000..3a2d74a --- /dev/null +++ b/SRC/LIBC/STRING.C @@ -0,0 +1,94 @@ +#include "types.h" +#include "internat.h" +#include + +/* #define KANJI TRUE */ + +char haveinttab = FALSE; + +struct InterTbl Currtab; + +int toupper(c) +int c; +{ + union REGS regs ; + + if(!haveinttab) { + regs.x.ax = 0x3800 ; + regs.x.dx = (unsigned) &Currtab ; + intdos (®s, ®s) ; /* INIT the table */ + + haveinttab = TRUE; + } + + return(IToupper(c,Currtab.casecall)); + +} + +char *strupr(string) +char *string; +{ + register char *p1; + + p1 = string; + while (*p1 != NULL) { + /* + * A note about the following " & 0xFF" stuff. This is + * to prevent the damn C compiler from converting bytes + * to words with the CBW instruction which is NOT correct + * for routines like toupper + */ +#ifdef KANJI + if(testkanj(*p1 & 0xFF)) + p1 += 2 ; + else + *p1++ = toupper(*p1 & 0xFF); +#else + *p1++ = toupper(*p1 & 0xFF); +#endif + } + return(string); +} + +char *strpbrk(string1,string2) +char *string1; +char *string2; +{ + register char *p1; + + while (*string1 != NULL) { + /* + * A note about the following " & 0xFF" stuff. This is + * to prevent the damn C compiler from converting bytes + * to words with the CBW instruction which is NOT correct + * for routines like toupper + */ +#ifdef KANJI + if(testkanj(*string1 & 0xFF)) + string1 += 2 ; + else { +#endif + p1 = string2; + while (*p1 != NULL) { + if(*p1++ == *string1) + return(string1); + } + string1++; +#ifdef KANJI + } +#endif + + } + return(NULL); /* no matches found */ +} + +#ifdef KANJI +testkanj(c) +unsigned char c; +{ + if((c >= 0x81 && c <= 0x9F) || (c >= 0xE0 && c <= 0xFC)) + return(TRUE); + else + return(FALSE); +} +#endif diff --git a/SRC/LIBC/SYSVAR.C b/SRC/LIBC/SYSVAR.C new file mode 100644 index 0000000..bc649ed --- /dev/null +++ b/SRC/LIBC/SYSVAR.C @@ -0,0 +1,48 @@ +/* return the system variables in sysVars */ + +#include "types.h" +#include "sysvar.h" +#include + +GetVars(pSVars) +struct sysVarsType *pSVars ; +{ + struct sysVarsType far *vptr ; + int i ; + + union REGS ir ; + register union REGS *iregs = &ir ; /* Used for DOS calls */ + struct SREGS syssegs ; + + iregs->h.ah = GETVARS ; /* Function 0x52 */ + intdosx(iregs, iregs, &syssegs) ; + + *(long *)(&vptr) = (((long)syssegs.es) << 16)+(iregs->x.bx & 0xffffL) ; + + for (i=0 ; i <= sizeof(*pSVars) ; i++) + *((char *)pSVars+i) = *((char far *)vptr+i) ; + +} + + + + +PutVars(pSVars) +struct sysVarsType *pSVars ; +{ + struct sysVarsType far *vptr ; + int i ; + + union REGS ir ; + register union REGS *iregs = &ir ; /* Used for DOS calls */ + struct SREGS syssegs ; + + iregs->h.ah = GETVARS ; /* Function 0x52 */ + intdosx(iregs, iregs, &syssegs) ; + + *(long *)(&vptr) = (((long)syssegs.es) << 16)+(iregs->x.bx & 0xffffL) ; + + for (i=0 ; i <= sizeof(*pSVars) ; i++) + *((char far *)vptr+i) = *((char *)pSVars+i) ; + +} diff --git a/SRC/MAKEFILE b/SRC/MAKEFILE new file mode 100644 index 0000000..993334d --- /dev/null +++ b/SRC/MAKEFILE @@ -0,0 +1,13 @@ +make=msmake /I makefile + +all: + cd boot + $(make) + cd ..\dos + $(make) + cd ..\bios + $(make) + cd ..\cmd + $(make) + + \ No newline at end of file diff --git a/SRC/TOOLS/CONVERT.EXE b/SRC/TOOLS/CONVERT.EXE new file mode 100644 index 0000000000000000000000000000000000000000..0511410b2349fb47ccb5b8b5bacbdc9c2d4ab289 GIT binary patch literal 16340 zcmeHu3w%`7wf8=cnM`IT!w^CmV+;cdN+W4>6fGebAs+D+B1lRVr;W(~DIrN`&J3hN zARXY# z$tK40?_q0t3VJr*ynD3&6YaG2>P_R;Uyiu|bG57Pb?sW`*1a$> zUifY1|Ky-2-ppbzikmh%+ao6q9P3gbh*95Y^Q>UoTG&DH_+#TbZOlGOpCxIBlj58? zn{VAcI(Z^{)N?;{ZyCX!G?MA}JvWhU$zxBRuGlKF&853X&q?l^9XldwM`F!(A>vBZ zvkG0y!}6~u*ku*^H96YhRqY$<7^YTXs*$GhHN`$XuGm+#t0OeUQCg}UHLi*)4n3V= z_CRc>cy|YorfElvs7udG*AA~$#0t7k*tElm2U!I@>n}S9cf?5(`vt7LB=N8{^~8{= zOhTHTcoe%IyHGnE+nEOJEl1Wd?Z{e1t{`;Av-dN7l&l^0x10Bi)3n3!)hk(PBumdt z<70_3p+bKO2>Nao07gsoUhpZtdNl_-Zs%i(Zvw21z%CXDhEOLOF&4#GqQ+T~FpLWQ zf(!8AWfh4nwE1eLuebBFNPX`!;+rwCjv3FcWO^mWN>n(UGKR;Pxaq~Y(H#|#-!kN!OF z*KZP`bWlJof1^;`(|keqeys{d-P( zr~Ls(dzbyE4uL)ONSFQR4v{@4u$hl8ay}Yxwt9Z%X!ShkXwARZ*_vPH)cauxV^=WM z^+=tw=un2t9<6gGo+it1=u=5pI0tRleQ--cjQ?PhK*x(Z+T@}`uoJ0oxL`6Y;!ZpV z`#A*L?E9Qq5G7++WZ`-X!G4WAPJGpwD8K>rYJwA!g{f6@S>&R&GJ)?PCci@F%;}j6 zYa-sgK>s{HK!v&#&z&+$s@MwrK8gjzrL9ksguaPI+EJ6 z?jm*)7oEca#_3B4LJDG5h=0UzqO6GFpK;m86-_G$s8Tj52w-&V%Oi3YAK?JP_3|TVqj;?Q+EE>A4gCEIG z+d2_%M9^Bg^<8WV8ua%8Kd5UW_I-!;mGwOwp=?A!s;ECeV01=Vi@L2dy7dL;Zf573 zArNxr*!7hL(dE!f04gZp7yfV8`%hDlNkur2W^&u92WX!G)faI{*q`D&ALaftK_dsi zbx^DKLB?QB0agtm^?6ehhVliZ>e-?efPUMxa>wTD^enM&w5W@GtlWX&HpRJls{XkU zmYy?=`?Y<2qNpE)^Ghu$)!!5PJ`f;PoS{pR89c4ry`Ri4_QzLjOub~_S^L>8TXFsZ z3LBAhZRIPr*iH~&D01>ogD@+*%wfG*fYG%n_RS^wa-naH0JpC-%UcZN%Jx&o9`E0K z(@okAa2lggJ0{FjM(dhxj&VqT`?1GoU^+E7g9i)}jI2Ll1hki~zrB)VvBCJ3_EKQe zvB$r;{{yYl#6U3G5SZlyFz*e(m^*L1&wk~hQ=9(WrnlK{{PR~|jHEl?j~qpGzq@0_ zGJ~lf``bB9rwHY>PzLQKf4dfywPyQ4_wiqK7$nHX{N`Zj-?TYzrAJW698GOOu!t* zpM*Q52fY|Nzcw&I>M+OcpIhS>r^e%}pN32FnbUj}=^e-OlRrRvd9rsk-(@doF}E=_ zkNnL$z*kzK@6I5fF2jwcV-&d=hM`|v*-Xa<-=zhd#XZrB3VMnI?r^pia7!K2wQ{HQ z%1yIwuh2(ekE92t#0|=!zlqJya9){Oz^j#ev`V+W*4cbb!M+Q3XysY{H&*Rx5^j!{ z%i7COUOnVomZvFM(~W2r97?7U_2NQkbw(THU>s@InKMuFtxShy`bmGUzgP3jWBxaQ zc#D_J2gf;RhmpN;;DlDrq?bnQ(>k=hv7K0^E2p(e$L8GKqY+;V=IbzN12)T=t)1Wp&1qCX=b0wwNxqW9SlG25?S(T*+I;C6f_fFuCh z1CEq`a9VgS1)h`}CqyHMB7#jJ50;Y$W6g3_#6u`^$Sd%)*7D)NsU2M(b&X{!U?l#I zxZ=evC2=+sI!V#rp0R>b%~qVxJ62*zcxaxPW|Xp4IXRO?k;d5)4inhN^HKzVS5IqR z(w_qUHUW>t6Os+0BYS|35|OEUO9ZAqQ^J_~XtGy}daTTM7{Qkb0(S?<#Jdzb#VdPB z4qJB3RwwIE+79uw)uZ2bf+sJqUpt>bNM3o!p*1^NZx~okK6ZzRlIn}GOjHruJ^C2< zGxKm{@A?XIKv74$OpHx|da74(SVXL^@{3g?kM=?GW>dvQmz0z*cQPh8%U-l|Z7mjR^(hqY*~bi7k`CNFN|!?`Sy z#!)0QAsY+eDCVFKk0+cc?jJ$`z*KA}XiGekzxAR~am5o4c$4nL4WqW+V?7bo*k-Jk zsS{FqP^{!F%dxNqa;2VlfEkq@)NjDOKZSA#FbdAM34#;c_Y6y9pw_5F-9U8k8!Upq zE~P_68BT$8mD7bL2~(egj$81))J2-oH_)WBjWYH9PBerO8n1Z1y>xOSA*vq{Kc1`=G(wB)szDnJ*=-wS;c zZrLI*6w;(<$kHK2CqHp=JMIihXK5uD_3xk`>aR<3nYs;)qGl&jO3qUW=S?k3Dd^jo zpL<`+{Mqo=GLe*?wuRHW|AwRfXhiZ|I8d*p^@Z<~jpUrA^Q57a=lGJks(^(7{N$DQ?uGZ3?C# zE!-yCIU}vzh`DednL|1~AT1xM#2_B^GVsobW|Nrae0GkQ2os40*G@%3G=LaW60)0w zHlByj;cbe4uE>m0aHl)9K?hm08C}oE#x# zeS73k5l2TRdm!ReY`Y~%xxYv60(SCY4)h`oV{0mYAq<)Q3pL%}?(gMJ6v8+2Gt22- z%n7r{1G0If;RCT}01aFgX3z4#um1;ajhfinTDBAk1rRR=+U5$>#GukTi}*ILAAXtJ z7fvr41`;#`I@F)0vo>p(=LUgr4#ISIM}>dKoQfsG3U)+1{`TU1s$;PIARiF%h75Q}@l!`f~{4nkdxm?C%sa$@yoI#1|7y_!9@{n)79dI2Fl! zVk#&uS=S5}0@yT)Es@=FmF%K9H1bN$P{YlcZomlyDA8=~{B*sbM#Z z438}Z_g#kSG*r9Zf%ZJl`Cbx8n%cvdyoLoF_GeEipS<) z)4TO<9o9@otI#K)<4VRY4?>~VhPx^gwNAJ@o6J(inZoNQ(iKntJTDqTqP_-tP8jTi z7|<^&#WsjxKpYPszR5 zfW&ChnbexGXPrVT6Q=_Pm5N)F4H*rKi;9dSZ(MysM%+Vm`$2>8mK!aIB)Js9X@h>~lK#_Hq6OZL zigkS{HETFILza(~nR;!k*=r2AhZJS$MMjsBE}-|BzP4PxeHIcN{b9K1F2!pYamCgb zgOwpwCIdlvV#;C&W|J^NtzH>hDzoOxwf~C3eVk!@1EALA0x(`lSF^bhfetRm3qS+5 zPa=}o$e-Jc2xlb`VhS{wttqx*EQC-^0y9jZ0w+|XOg06ocuNdJ^=WhETjF!&RlQ4` zTAm@drWGAZx-6F6lybv#$N|CQkg?{pp&Uy~xsO!+`ouxfdpq|I!%ZGJEJMdjKx1N? zi@%HnNF0s`b*@={y3Gs#AnV(peB?yT#m5aOYRYYyMQ+OxuV5MF_1JCg>TJ9h@o3Lx z308S1^&Ms8BN%UV$4-uoug(%+?W)xGTZYmEMJNU%R~Z(SB9)f349yYpuLOOP2pAlH9+`dsv(hr`w8Ke0I`}Qfu!LrQVI^2YV)V@*0>o3G^!NT~prdIS#pRqtH{KxA zdy#m+ZXLw*#i=^U&Y{pU&GPT^zoD=DcsY;8yt2qbaMc3Ycr`phpx4AOB{U`j^y*n= z`k$TKLM{z2Q#|oJHJLE;{7SHT*yx*;<#!M$RNHzuqPFfZfF)3+VvWE#NM%FL7XEFfK!)ci+1t zWe>3sN$q*KnCh{#bHF?;kjuF^{U6IswczD_4u)eL=o;q5x>+nK#P))dZf%Fj#{1II z%b+AeD|bt;pvNXaNr|&KZDzb2oemkCg(C1*z5C#}tfT`cDfbk=gp-6Xpg2tpIGz=8 zzS3d%?s758-0{Rct=S#Fh)V{YTInUNGIPY6@!LeL>&yl2V#OXF24p0FRLu=mVK|~t zXBm{JP#6z7?&pFb6v+Zo1_Bz+fg(=rMv;cnDDg~Dh1?4?fu|0%!Q;s2^HAqQ5ug(2 zj~|VrQ^!w(PM|{A(SEL-yCaZMG*witRlhzSb`cm46@0#mXy-lmlS-ireyQhAweQ^v>Y79 zB(y`blie0L-eE?r!7OM)9cJ!&Hj2#ip~xIWfe&g1DED+Jc>{?0ej`$@tbRp{PSNC; zEOR{o1IzQ{0bddtz=uT=w13yC-X`Iuc)2egz&ANQc&VxVmA?K!ek|Yv*SyFhulO=- zS!ZBtk1K=-F%55&(A%Mx$1qTz7RZMRI~jc#@v=SkLJ`!Pnrk!144KrQL<(ck;ZpJ= z+mH|mkqi@0=hQKfntiP@2I?U7BwVb38W_%aAg}K=;lD$n!=g|N__XqTe{ais!WEKNil4YoHQ2O zQ3Q|Ldh?hq`2OY`a?on}B65au=P4w9nFgtE=1Yh+PAdGJS|AgxscfxzigvX&S^Bii z#tU`y_??JlLlgx3O*Z0~Scr-l6L~RN)WC_n*77mQ$}S}r)$|NpPy|iK1^RM5neN29 zJLWO*(jYrIZa(|RxN5d70zXzq+a1KaNoy(v`C{>WII>#&7JZXwGyP0|&29WYV6PDo16SFHkSvsmU=NU>~ zn+@&TcY%aMWG}gWD1?%Q$%BKF15IUGo|^oxaie%DC5JkxlplJ4*LGri)>2zy1aE|A zg2K|Zfibhz2E6#oL4zQ-0{k?t((CA3mgtn2?7+NMp0jEf=`{t)ye6qXV2?HDiji#U zbgE8-P5V;#MtoP%UK&?&`KV-+=O8;l0BlB2TS6v?CFrbaN@gip3j%QtC9C!&65=Ju zV(Jx?E?y1*o1F<{qSXGB`+KNopHouJ;B1=-QA@Mq?-IWwZX-A-*>LX7Ky8N@2AKz6 zKG{$vbG{Mk!<>|KbF@>QKmp zDJ9wFG$F$${D7uUu~Je&8q9Yc6!!K(xXoA%#-PZ%?8{c{9bEA$XUzc7g+qxELChC# z`_>?mm%j{d0C!Pp!QduePG(PPK~ZuyZd1&=!4mD{rVM;}Mhu$JAIM1#>{9@{CC}pI zt{5$x97L6e`cJ|IbLX3bd+--(l)ij#tT~58-UM)oi!HNwOTBlL9b;fCe}f7L{|71n z9XZoB@G_Qvu_Nohe9QVEgWgO#caJ`!4*B_8JYm+*Z1K!xTK1hxACqk6xhB5JT0aM_ z&>`f{VdLpT*K+3t07CQT?3{KE$HH@3eLc!~s6V+9-eBOVikaM|3YqZ$Uth^I;4SE} zqN0Eeh6DSCIn2b4x@8`|Orf{Jc$;p1gn`ec;^oZsGBpMKy?s9=T3j7?LXOy}$P&!)T%=GiH+w_xV3UMD%}xj|bBFyZiUW_8O6kR=u(0g6%#=`D*vu z#m7QY!LeyG@cqXw?d{~~?cUVHMB+>MV$o&P0LJGXW_LY`W&>E$WNRtM(y_+!$O!FI*HSs+b}bbnX|Bl;DY@)Ee6*}j zI4x1x>_%3J{)DF5{cmiyvF;DLd%AnO_jd1_5jmcL7rwlLh?hI!m1y)+|32!`US0Kx zTHEA}bxKP{Y!jG%1)Pf~d02l$G!%Do*f!KaXwP3L=_f>^+})3wXho#UDEH`3i^-4t zpAc!K{#|sq(g>W7>_Uc#OxNL3oa%7>MRC=xh%Zi%w6?YMYu>-t-|T zGs?ZOW;8Q|>$T>ITGZ?B#Z;?p+Kt6~mksCmKYX&N)pp~w;y~fj{uK8eCY{1`EqWD& z2IQ4j#$`UJijd=u*v`wi#zPR~x1lmfNAV>p(oy=XjWS)usb3*ZE{del(S6BdlP5$R zTtIp*hL>JD`RmKC;#0_ApKj=ul$S~^T;(&0M{9x2j#e`QC`+Ec&o=eNcWrYy10&3@(0&b9q=>r=`Ir$No z1nFG3WVodX!v*~)X57g?>&uXwyOXa0D_r^YB}UrvYv>Dl(nNfbhuVNXv2eD%-S$!2 z?zUvxU)w%y+qqq0XboFR`7!w5g0^KOjxMLK5b#+ItPipwDp#ly=`6ZubLIH0Vmymp z3=BQZwo<$-<6m;%qZ)h$;Ozc;_Z!{a-EVfkjyHKBd4iMOSRVNgs=W}hD;@D>C%V&4 z`dFA=es;eOX~GlI6=7DUtK6Z%#h@1Nra!3z$uQk?_;+o$Gi{n2zeU#HF|@m6J{6xP z&zRAq1L@#tQ->>$d_2_L&}+M#sb~dU-lbg5Scg$rgv!t;FO1kpR~#L5Vl=hj|2km* zcivOGuwij{VXbePFRWID)JUUmT0>(~sCNDW)py0$ul4&bn>OBeTWxiyA>1%e#bl`Q ztMv2DQmd*L`esCfp?P%;i+y}B1F7W?-Sj`;9{9N=^LBQ)YJPAMP}F0Q>bq-RZC&tg zCo6AIeZl&M$ovJqMZrZ4p(ZCQtZrDu3WH06tnh|8H~1PtzQSoUZu5nL-;LCUf;CRo z$C!mCSTnE>Zgj@(s#w!*^D@noFGw%NXPneLU#=J5&f8J}sMOK|yEn{t_;W#s)aHM7(rEa2T2*~LPSDU8toMx#`zGKYC$k2tL%}LFI5>>?k}34a)P@FMT~%m) z(8=zaaSOPxI8+PBU?|iOGFei)sIe}%C|Ix3dH?kT2MSqXA@ij}$*S467FE^OPx9RX zHZH2FZ}Nea5n>j2f8AGEgER@ybH6qTy51OSs1An1z6Dib9|M^SD{BfTFF@+ zX0`Rvs=C@5-@HhDwOZRy&qzD@f_VV1VU1Plf+3G2KfW=SJHduoRW;wJCRkq!txO?Y zP*q=37i3kTV11QO4ON8~VA3RHh|Ujy-&5C6y^!5gRRcn!wV{T3Iu(DO*AQA%r49g^ zyA3?nRH;>r8)hgN4u+yQ9X$=shiaoiRvig}4%Jr!Gpbf$Yn+mB)uN!UCK#=)4&vDd z8w~o)BbizW7ODUT%9`4+NnE79R%JDWlQRW+Uem;>gyn)SHT-_s%xU~eb{h<}YM!sLsxcU{Ok-YEq)uhD5m3fO4I!M{REDZLeoS9*No`mSo6IhoUEyn}_YpSE?rPH;EUH>ajHwAS=tqcC<68^` zv<`0_FSTb_4MnO|oFU9iDfm)bRfWT~^XrFbQzJ$|XAO(gFRX7^TyLr`jN_0f;6E)C zS)L@Z0!e0*BpWN2>};--#uiEr)+FJ-tCEoUOD^^s$;~z+=ygaQ_PR8T9hAK6BWXC3 zGS-S!|*_l3gcfvl;SN*j;iCtClZd4RS8KSH2KmMCGxExGIrdhmyQ2w!Q~SQzgBd` zmHw-)o_Ni*U!PPwxn#<9rB(M-*97OyUr_s{SS8ydeG3agRm;w4SryKC;1wJ6`D6`C@0+OS@iv=J~&P{{M;d8|P}o zKRqH;H`F5z;3rI*QEuLejUj7HteBY^s|%~v?5(rzudb%)$#aLihPG3zc=6S8J!md&*88Y32cQpIeGKDj<&&~KRriTy<8OZ_gRU+Q7-I^BEbZ{@(x8gJo0;XFSR;QRb1 Yp65sNgB$%1?N3ZUrxu`!;(zw{pG>EPwEzGB literal 0 HcmV?d00001 diff --git a/SRC/TOOLS/DBOF.EXE b/SRC/TOOLS/DBOF.EXE new file mode 100644 index 0000000000000000000000000000000000000000..1d46e71368e3dc77d689a2f6a009e83dace1ca47 GIT binary patch literal 10262 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 literal 0 HcmV?d00001 diff --git a/SRC/TOOLS/EXE2BIN.EXE b/SRC/TOOLS/EXE2BIN.EXE new file mode 100644 index 0000000000000000000000000000000000000000..5535f7e664f508bc0093ee6fa5c036a4402ee7a8 GIT binary patch literal 3050 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 D*dez( literal 0 HcmV?d00001 diff --git a/SRC/TOOLS/MASM.EXE b/SRC/TOOLS/MASM.EXE new file mode 100644 index 0000000000000000000000000000000000000000..c6cd283db04f9b6d85207261b06b4c9cc5dbc7d7 GIT binary patch literal 85566 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 AdjJ3c literal 0 HcmV?d00001 diff --git a/SRC/TOOLS/MASM401.EXE b/SRC/TOOLS/MASM401.EXE new file mode 100644 index 0000000000000000000000000000000000000000..9515fce6f2776a28d50bc967c04b0941ddb018f0 GIT binary patch literal 102120 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
;3.30 + call GETBOOT ;rd master boot rec 7c0:BootBias ;3.30 + jc DoMiniNext ;3.30 + call FIND_MINI_PARTITION ;3.30 +DoMiniNext: ;3.30 + dec numh ;3.30 + jz DoMiniRet ;3.30 + inc Rom_MiniDsk_Num ;Next hard file ;3.30 + mov dl, Rom_MiniDsk_Num ;look at next hard drive ;3.30* + mov ah, 8h ;get drive parameters ;3.30* + int 13h ;call ROM-Bios ;3.30* + jmp DoMiniBegin ;3.30 + ;3.30 +DoMiniRet: ;3.30 + pop ax ;3.30 + ret ;3.30 + ;3.30 + ;3.30 +;Find_Mini_Partition tries to find every Extended partition on a disk. ;3.30 +;At entry: DI -> BDSM entry ;3.30 +; ES:BX -> 07c0:BootBias - Master Boot Record ;3.30 +; Rom_MiniDsk_Num - ROM drive number ;3.30 +; MiniNum - Logical drive number ;3.30 +; Mini_HDLIM, Mini_SECLIM ;3.30 +; ;3.30 +;Called routine: SETMINI which uses SET1 (in SETHARD routine) ;3.30 +;Variables & equates used from orig BIOS - flags, fNon_Removable, fBigfat ;3.30 +; ;3.30 +; ;3.30 +FIND_MINI_PARTITION: ;3.30 + ;3.30 + add bx, 1C2h ;BX -> system id. ;3.30 + ;3.30 +FmpNext: ;3.30 + cmp byte ptr ES:[BX], 5 ; 5 = extended partition ID. ;3.30 + jz FmpGot ;3.30 + add bx, 16 ; for next entry ;3.30 + cmp bx, 202h+BootBias ;3.30 + jnz FmpNext ;3.30 + jmp FmpRet ;not found extended partition ;3.30 + ;3.30 +FmpGot: ;found my partition. ;3.30 + Message ftestHard,<"Found my partition...",cr,lf> ;3.30 + xor ax,ax ;3.30 + or al, fNon_Removable ;3.30 + or word ptr [DI].Flags, ax ;3.30 + mov byte ptr [DI].FormFactor, ffHardFile ;3.30 + mov fBigFat, 0 ;assume 12 bit Fat. ;3.30 + mov ax, Mini_HDLIM ;3.30 + mov [DI].HDLIM, ax ;3.30 + mov ax, Mini_SECLIM ;3.30 + mov [DI].SECLIM, ax ;3.30 + mov al, Rom_MiniDsk_Num ;3.30 + mov [DI].DriveNum, al ;set physical number ;3.30 + mov al, Mininum ;3.30 + mov [DI].DriveLet, al ;set logical number ;3.30 + ;3.30 + cmp word ptr ES:[BX+8], 64 ;**With current BPB, only lower word ;3.30 + ; is meaningful. ;3.30 + je FmpRet ;should be bigger than 64 sectors at least ;3.30 + sub bx, 4 ;let BX point to the start of the entry ;3.30 + mov dh, byte ptr ES:[BX+2] ;3.30 + and dh, 11000000b ;get higher bits of cyl ;3.30 + rol dh, 1 ;3.30 + rol dh, 1 ;3.30 + mov dl, byte ptr ES:[BX+3] ;cyl byte ;3.30 + mov [DI].Hidden_Trks, dx ;set hidden trks ;3.30 +;** Now, read the volume boot record into BootBias. ;3.30 + mov cx,ES:[BX+2] ;cylinder,cylinder/sector ;3.30* + mov dh,ES:[BX+1] ;head ;3.30* + mov dl,Rom_MiniDsk_Num ;drive ;3.30* + mov ax,7c0h ; ;3.30* + mov es,ax ;buffer segment ;3.30* + mov bx,BOOTBIAS ;buffer offset ;3.30* + mov ax,0201h ;read,1 sector ;3.30* + int 13h ;call ROM-Bios routine ;3.30* + jc FmpRet ;cannot continue. ;3.30 + mov bx, 1c2h+BootBias ;3.30 + ;3.30 + call SetMini ;install a mini disk. BX value saved. ;3.30 + jc FmpnextChain ;3.30 + ;3.30 + call Install_BDSM ;install the BDSM into the BDS table ;3.30 +; call Show_Installed_Mini ;show the installed message. 3/35/86 - Don't show messages. ;3.30 + inc mininum ;increase the logical drive number for next ;3.30 + inc num_mini_dsk ;increase the number of mini disk installed. ;3.30 + ;3.30 + push bx ;now, set the DskDrvs pointer to BPB info. ;3.30 + mov bx, Mini_BPB_ptr ;3.30 + lea si, [di].BytePerSec ;points to BPB of BDSM ;3.30 + mov [bx], si ;3.30 + inc Mini_BPB_ptr ;advance to the next address ;3.30 + inc Mini_BPB_ptr ;3.30 + pop bx ;3.30 + ;3.30 + add DI, type BDSM_type ;adjust to the next BDSM table entry. ;3.30 + mov End_OF_BDSM, DI ;set the ending address of BDSM table to this. ;3.30 +; Message fTestHard,<"Mini disk installed.",cr,lf> ;3.30 +FmpnextChain: jmp FmpNext ;let's find out if we have any chained partition ;3.30 +FmpRet: ;3.30 + ret ;3.30 + ;3.30 +SetMini: ;3.30 + push di ;3.30 + push bx ;3.30 + push ds ;3.30 + jmp SET1 ;will be returned to Find mini partition routine. ;3.30 + ;Some logic has been added to SET1 to ;3.30 + ;deal with Mini disks. ;3.30 + ;3.30 +; ;3.30 +;Install BDSM installs a BDSM (pointed by DS:DI) into the end of the current ;3.30 +;linked list of BDS. ;3.30 +;Also, set the current BDSM pointer segment to DS. ;3.30 +;At entry: DS:DI -> BDSM ;3.30 +; ;3.30 +Install_BDSM: ;3.30 + ;3.30 + push ax ;3.30 + push si ;3.30 + push es ;3.30 + ;3.30 + les si, dword ptr cs:Start_BDS ;start of the beginning of list ;3.30 +I_BDSM_Next: ;3.30 + cmp word ptr es:[si], -1 ;end of the list? ;3.30 + jz I_BDSM_New ;3.30 + mov si, word ptr es:[si].link ;3.30 + mov ax, word ptr es:[si].link+2 ;next pointer ;3.30 + mov es, ax ;3.30 + jmp short I_BDSM_Next ;3.30 +I_BDSM_New: ;3.30 + mov ax, ds ;3.30 + mov word ptr ds:[di].link+2, ax ;BDSM segment had not been initialized. ;3.30 + mov word ptr es:[si].link+2, ax ;3.30 + mov word ptr es:[si].link, di ;3.30 + mov word ptr ds:[di].link, -1 ;make sure it is a null ptr. ;3.30 + ;3.30 +I_BDSM_ret: ;3.30 + pop es ;3.30 + pop si ;3.30 + pop ax ;3.30 + ret ;3.30 + ;3.30 +;***The following code is not needed any more. Don't show any ;3.30 +;***messages to be compatible with the behavior of IO.SYS. ;3.30 +;;Show the message "Mini disk installed ..." ;3.30 +;;This routine uses WRMSG procedure which will call OUTCHR. ;3.30 +;Show_Installed_Mini: ;3.30 +; push ax ;3.30 +; push bx ;3.30 +; push ds ;3.30 +; ;3.30 +; mov al, Mininum ;logical drive number ;3.30 +; add al, Drv_Letter_Base ;='A' ;3.30 +; mov Mini_Drv_Let, al ;3.30 +; mov si, offset Installed_Mini ;3.30 +; call WRMSG ;3.30 +; ;3.30 +; pop ds ;3.30 +; pop bx ;3.30 +; pop ax ;3.30 +; ret ;3.30 +;**End of mini disk initialization** ; 4/7/86 ;3.30 + ;3.30 + ;3.30 +CMOS_Clock_Read proc near ;3.30 + ;3.30 +; IN ORDER TO DETERMINE IF THERE IS A CLOCK PRESENT IN THE SYSTEM, THE FOLLOWING ;3.30 +; NEEDS TO BE DONE. ;3.30 + PUSH AX ;3.30 + PUSH CX ;3.30 + PUSH DX ;3.30 + PUSH BP ;3.30 + ;3.30 + XOR BP,BP ;3.30 +LOOP_CLOCK: ;3.30 + XOR CX,CX ;3.30 + XOR DX,DX ;3.30 + MOV AH,2 ;READ REAL TIME CLOCK ;3.30 + INT 1Ah ;CALL ROM-BIOS ROUTINE ;3.30 + CMP CX,0 ;3.30 + JNZ CLOCK_PRESENT ;3.30 + ;3.30 + CMP DX,0 ;3.30 + JNZ CLOCK_PRESENT ;3.30 + ;3.30 + CMP BP,1 ; READ AGAIN AFTER A SLIGHT DELAY, IN CASE CLOCK ;3.30 + JZ NO_READDATE ; WAS AT ZERO SETTING. ;3.30 + ;3.30 + INC BP ; ONLY PERFORM DELAY ONCE. ;3.30 + MOV CX,4000H ;3.30 +DELAY: ;3.30 + LOOP DELAY ;3.30 + JMP LOOP_CLOCK ;3.30 + ;3.30 +CLOCK_PRESENT: ;3.30 + mov cs:HaveCMOSClock, 1 ; Set the flag for cmos clock ;3.30 + ;3.30 + call CMOSCK ; Reset CMOS clock rate that may be ;3.30 + ;possibly destroyed by CP DOS and POST routine did not ;3.30 + ;restore that. ;3.30 + ;3.30 + PUSH SI ;3.30 + MESSAGE FTESTINIT,<"CLOCK DEVICE",CR,LF> ;3.30 + CALL READ_REAL_DATE ;MJB002 READ REAL-TIME CLOCK FOR DATE ;3.30 + ;3.30 + CLI ;MJB002 ;3.30 + MOV DAYCNT,SI ;MJB002 SET SYSTEM DATE ;3.30 + STI ;MJB002 ;3.30 + POP SI ;MJB002 ;3.30 +NO_READDATE: ;3.30 + POP BP ;3.30 + POP DX ;3.30 + POP CX ;3.30 + POP AX ;3.30 + RET ;3.30 + ;3.30 +CMOS_Clock_Read endp ;3.30 +; ;3.30 +; 10/28/86 ;3.30 +; THE FOLLOWING CODE IS WRITTEN BY JACK GULLEY IN ENGINEERING GROUP. ;3.30 +; CP DOS IS CHANGING CMOS CLOCK RATE FOR ITS OWN PURPOSES AND IF THE ;3.30 +; USE COLD BOOT THE SYSTEM TO USE PC DOS WHILE RUNNING CP DOS, THE CMOS ;3.30 +; CLOCK RATE ARE STILL SLOW WHICH SLOW DOWN DISK OPERATIONS OF PC DOS ;3.30 +; WHICH USES CMOS CLOCK. PC DOS IS PUT THIS CODE IN MSINIT TO FIX THIS ;3.30 +; PROBLEM AT THE REQUEST OF CP DOS. ;3.30 +; THE PROGRAM IS MODIFIED TO BE RUN ON MSINIT. Equates are defined in CMOSEQU.INC. ;3.30 +; This program will be called by CMOS_Clock_Read procedure. ;3.30 +; ;3.30 +; The following code CMOSCK is used to insure that the CMOS has not ;3.30 +; had its rate controls left in an invalid state on older AT's. ;3.30 +; ;3.30 +; It checks for an AT model byte "FC" with a submodel type of ;3.30 +; 00, 01, 02, 03 or 06 and resets the periodic interrupt rate ;3.30 +; bits incase POST has not done it. This initilization routine ;3.30 +; is only needed once when DOS loads. It should be ran as soon ;3.30 +; as possible to prevent slow diskette access. ;3.30 +; ;3.30 +; This code exposes one to DOS clearing CMOS setup done by a ;3.30 +; resident program that hides and re-boots the system. ;3.30 +; ;3.30 +CMOSCK PROC NEAR ; CHECK AND RESET RTC RATE BITS ;3.30 + ;3.30 +;Model byte and Submodel byte were already determined in MSINIT. ;3.30 + push ax ;3.30 + cmp cs:Model_byte, 0FCh ;check for PC-AT model byte ;3.30 + ; EXIT IF NOT "FC" FOR A PC-AT ;3.30 + JNE CMOSCK9 ; Exit if not an AT model ;3.30 + ;3.30 + CMP cs:Secondary_Model_Byte,06H ; Is it 06 for the industral AT ;3.30 + JE CMOSCK4 ; Go reset CMOS periodic rate if 06 ;3.30 + CMP cs:Secondary_Model_Byte,04H ; Is it 00, 01, 02, or 03 ;3.30 + JNB CMOSCK9 ; EXIT if problem fixed by POST ;3.30 + ; Also,Secondary_model_byte = 0 when AH=0c0h, int 15h failed. ;3.30 +CMOSCK4: ; RESET THE CMOS PERIODIC RATE ;3.30 + ; Model=FC submodel=00,01,02,03 or 06 ;3.30 + + mov al,CMOS_REG_A or NMI ;NMI disabled on return + mov ah,00100110b ;Set divider & rate selection + call CMOS_WRITE + + + mov al,CMOS_REG_B or NMI ;NMI disabled on return + call CMOS_READ + and al,00000111b ;clear SET,PIE,AIE,UIE,SQWE + mov ah,al + mov al,CMOS_REG_B ;NMI enabled on return + call CMOS_WRITE + +CMOSCK9: ; EXIT ROUTINE ;3.30 + pop ax ;3.30 + RET ; RETurn to caller ;3.30 + ; Flags modifyied ;3.30 +CMOSCK ENDP ;3.30 +PAGE ;3.30 +;--- CMOS_READ ----------------------------------------------------------------- ;3.30 +; READ BYTE FROM CMOS SYSTEM CLOCK CONFIGURATION TABLE : ;3.30 +; : ;3.30 +; INPUT: (AL)= CMOS TABLE ADDRESS TO BE READ : ;3.30 +; BIT 7 = 0 FOR NMI ENABLED AND 1 FOR NMI DISABLED ON EXIT : ;3.30 +; BITS 6-0 = ADDRESS OF TABLE LOCATION TO READ : ;3.30 +; : ;3.30 +; OUTPUT: (AL) VALUE AT LOCATION (AL) MOVED INTO (AL). IF BIT 7 OF (AL) WAS : ;3.30 +; ON THEN NMI LEFT DISABLED. DURING THE CMOS READ BOTH NMI AND : ;3.30 +; NORMAL INTERRUPTS ARE DISABLED TO PROTECT CMOS DATA INTEGRITY. : ;3.30 +; THE CMOS ADDRESS REGISTER IS POINTED TO A DEFAULT VALUE AND : ;3.30 +; THE INTERRUPT FLAG RESTORED TO THE ENTRY STATE ON RETURN. : ;3.30 +; ONLY THE (AL) REGISTER AND THE NMI STATE IS CHANGED. : ;3.30 +;------------------------------------------------------------------------------- ;3.30 + ;3.30 +CMOS_READ PROC NEAR ; READ LOCATION (AL) INTO (AL) ;3.30 + PUSHF ; SAVE INTERRUPT ENABLE STATUS AND FLAGS ;3.30 + + cli + push bx + push ax ;save user NMI state + or al,NMI ;disable NMI for us + out CMOS_PORT,al + nop ;undocumented delay needed + in al,CMOS_DATA ;get data value + + ;set NMI state to user specified + mov bx,ax ;save data value + pop ax ;get user NMI + and al,NMI + or al,CMOS_SHUT_DOWN + out CMOS_PORT,al + nop + in al,CMOS_DATA + + mov ax,bx ;data value + pop bx + + PUSH CS ; *PLACE CODE SEGMENT IN STACK AND ;3.30 + CALL CMOS_POPF ; *HANDLE POPF FOR B- LEVEL 80286 ;3.30 + RET ; RETURN WITH FLAGS RESTORED ;3.30 + ;3.30 +CMOS_READ ENDP ;3.30 + ;3.30 +CMOS_POPF PROC NEAR ; POPF FOR LEVEL B- PARTS ;3.30 + IRET ; RETURN FAR AND RESTORE FLAGS ;3.30 + ;3.30 +CMOS_POPF ENDP ;3.30 + ;3.30 +;--- CMOS_WRITE ---------------------------------------------------------------- ;3.30 +; WRITE BYTE TO CMOS SYSTEM CLOCK CONFIGURATION TABLE : ;3.30 +; : ;3.30 +; INPUT: (AL)= CMOS TABLE ADDRESS TO BE WRITTEN TO : ;3.30 +; BIT 7 = 0 FOR NMI ENABLED AND 1 FOR NMI DISABLED ON EXIT : ;3.30 +; BITS 6-0 = ADDRESS OF TABLE LOCATION TO WRITE : ;3.30 +; (AH)= NEW VALUE TO BE PLACED IN THE ADDRESSED TABLE LOCATION : ;3.30 +; : ;3.30 +; OUTPUT: VALUE IN (AH) PLACED IN LOCATION (AL) WITH NMI LEFT DISABLED : ;3.30 +; IF BIT 7 OF (AL) IS ON. DURING THE CMOS UPDATE BOTH NMI AND : ;3.30 +; NORMAL INTERRUPTS ARE DISABLED TO PROTECT CMOS DATA INTEGRITY. : ;3.30 +; THE CMOS ADDRESS REGISTER IS POINTED TO A DEFAULT VALUE AND : ;3.30 +; THE INTERRUPT FLAG RESTORED TO THE ENTRY STATE ON RETURN. : ;3.30 +; ONLY THE CMOS LOCATION AND THE NMI STATE IS CHANGED. : ;3.30 +;------------------------------------------------------------------------------- ;3.30 + ;3.30 +CMOS_WRITE PROC NEAR ; WRITE (AH) TO LOCATION (AL) ;3.30 + PUSHF ; SAVE INTERRUPT ENABLE STATUS AND FLAGS ;3.30 + PUSH AX ; SAVE WORK REGISTER VALUES ;3.30 + + cli + push ax ;save user NMI state + or al,NMI ;disable NMI for us + out CMOS_PORT,al + nop + mov al,ah + out CMOS_DATA,al ;write data + + ;set NMI state to user specified + pop ax ;get user NMI + and al,NMI + or al,CMOS_SHUT_DOWN + out CMOS_PORT,al + nop + in al,CMOS_DATA + + POP AX ; RESTORE WORK REGISTERS ;3.30 + PUSH CS ; *PLACE CODE SEGMENT IN STACK AND ;3.30 + CALL CMOS_POPF ; *HANDLE POPF FOR B- LEVEL 80286 ;3.30 + RET ;3.30 + ;3.30 +CMOS_WRITE ENDP ;3.30 +; ;3.30 + +END$: +code ends +end diff --git a/UPDSRC/BIOS/MSIOCTL.INC b/UPDSRC/BIOS/MSIOCTL.INC new file mode 100644 index 0000000..dd67b14 --- /dev/null +++ b/UPDSRC/BIOS/MSIOCTL.INC @@ -0,0 +1,1039 @@ + include ioctl.inc + +; +; Generic IOCTL dispatch tables +; +IOReadJumpTable db 2 + dw offset GetDeviceParameters + dw offset ReadTrack + dw offset VerifyTrack + +IOWriteJumpTable db 2 + dw offset SetDeviceParameters + dw offset WriteTrack + dw offset FormatTrack + +MAX_SECTORS_CURR_SUP EQU 63 ; CURRENT MAXIMUM SEC/TRK THAT ;3.30 + ; WE SUPPORT (Was 40 in DOS 3.2) ;3.30 +; +; TrackTable is an area for saving information passwd by the set device +; parameter function for laster use my Read/Write/Format/Verify. +; +; Entries are 4-Tuples (C,H,R,N) where: +; C = Cylinder, H = Head, R = Sector, N = Bytes/Sector +; +; fixed for bug0016 - initialised table with values - sp +TrackTable db 0,0,1,2 + db 0,0,2,2 + db 0,0,3,2 + db 0,0,4,2 + db 0,0,5,2 + db 0,0,6,2 + db 0,0,7,2 + db 0,0,8,2 + db 0,0,9,2 + db 0,0,10,2 + db 0,0,11,2 + db 0,0,12,2 + db 0,0,13,2 + db 0,0,14,2 + db 0,0,15,2 + db 0,0,16,2 + db 0,0,17,2 + db 0,0,18,2 + db MAX_SECTORS_CURR_SUP * size a_SectorTable - ($-tracktable) dup (0) + +sectorsPerTrack dw 15 + + +; This is a real ugly place to put this +; it should really go in the BDS +mediaType db 0 + +Media_Set_For_Format db 0 ; 1 if we have done an Int 13 Set Media + ; Type for Format call +; Rev 3.30 ***************************************************************** +Had_Format_Error db 0 ; 1 if the previous format operation + ; failed. +Dsk_time_out_Err equ 80h ; Time out error (No media present). +Dsk_change_line_Err equ 6h ; Change line error +Dsk_illegal_combination equ 0Ch ; Return code of ah=18h function. +; Rev 3.30 ***************************************************************** + +; +; TempDPT is a temporary place to hold a pointer to the original +; Disk Parameter Table while DPT is made to point to a table returned +; by a BIOS call. A value of -1 indicateds no value has been saved. +; + +TempDPT DD -1 + +; +; Generic$IOCTL: +; Perform Generic IOCTL request +; Input: +; al - unit number +; Output: +; if carry set then al contains error code +; + Public Generic$IOCTL +Generic$IOCTL: + Message ftestdisk,<"Generic IOCTL",cr,lf> + les bx,cs:[PTRSAV] ; es:bx points to request header. + call SetDrive ; ds:di points to BDS for drive. +; +; At this point: +; es:bx - points to the Request Header +; ds:di points to the BDS for the drive +; + cmp es:[bx].MajorFunction, RAWIO + jne IOCTL_Func_Err + mov al, es:[bx].MinorFunction + mov si, offset IOReadJumpTable + test al, GEN_IOCTL_FN_TST ; Test of req. function + jnz NotGenericIoctlWrite ; function is a Read. + mov si, offset IOWriteJumpTable +NotGenericIoctlWrite: + and al, 0fH + cmp al, cs:[si] + ja IOCTL_Func_Err + cbw + shl ax, 1 + inc si + add si,ax + les bx, es:[bx].GenericIOCTL_Packet + call cs:[si] + jc FailGeneric$IOCTL + jmp exit + +FailGeneric$IOCTL: + jmp err$exit + +IOCTL_Func_Err: + jmp CMDERR + + + + + +; +; GetDeviceParameters: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to device parameter packet +; + + PUBLIC GETDEVICEPARAMETERS ;3.30 +GetDeviceParameters proc near +; Copy info from BDS to the device parameters packet + mov al, byte ptr ds:[di].FormFactor + mov byte ptr es:[bx].DP_DeviceType, al + mov ax, word ptr ds:[di].Flags + and ax,fNon_Removable+fChangeline ; mask off other bits + mov word ptr es:[bx].DP_DeviceAttributes, ax + mov ax, word ptr ds:[di].cCyln + mov word ptr es:[bx].DP_Cylinders, ax + +; Set media type to default + xor al, al + mov byte ptr es:[bx].DP_MediaType, al + +; Copy recommended BPB + lea si, byte ptr [di].RBytePerSec + test byte ptr es:[bx].DP_SpecialFunctions, BUILD_DEVICE_BPB + jz use_BPB_present +; Get the correct disk in the drive + call CheckSingle +; Build the BPB from scratch + call GETBP + jc Get_Parm_Ret + lea si,byte ptr [di].BytePerSec +use_BPB_present: + lea di, byte ptr [bx].DP_BPB + mov cx, size BPB_Type ; for now use 'small' BPB + rep movsb + clc +Get_Parm_Ret: + ret +GetDeviceParameters endp + + + + + +; +; SetDeviceParameters: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to device parameter packet +; + + PUBLIC SETDEVICEPARAMETERS ;3.30 +SetDeviceParameters proc near + +; Make sure the fChanged_By_Format flag gets set to kick DOS into looking at +; the BPB + or word ptr ds:[di].Flags, fChanged_By_Format or fChanged + test byte ptr es:[bx].DP_SpecialFunctions, ONLY_SET_TRACKLAYOUT + jz short SetDevParm_1 + jmp SetTrackTable ; Originally TrackLayout + +SetDevParm_1: +; Copy info from the device parameters packet to BDS + mov al, byte ptr es:[bx].DP_DeviceType + mov byte ptr ds:[di].FormFactor, al + + mov ax, word ptr es:[bx].DP_Cylinders + mov word ptr ds:[di].cCyln, ax + +; If change line is not loaded then ignore changeling flag + mov ax, word ptr es:[bx].DP_DeviceAttributes + cmp cs:[fHave96],0 + jnz Have_Change + and ax,not fChangeline +Have_Change: +; ignore all bits except Non_removable and Changeline + and ax,fNon_Removable or fChangeline + mov cx, word ptr ds:[di].Flags + and cx, not (fNon_Removable or fChangeline or GOOD_TRACKLAYOUT) + or ax, cx + mov word ptr ds:[di].Flags, ax + +; Set media type + mov al, byte ptr es:[bx].DP_MediaType + mov cs:mediaType, al +; the media changed (maybe) so we will have to do a SetDASD the next time +; we format a track + or word ptr ds:[di].Flags, SET_DASD_true + + SaveReg +; Figure out what we are supposed to do with the BPB + +; Were we asked to install a fake BPB? + test byte ptr es:[bx].DP_SpecialFunctions, INSTALL_FAKE_BPB + jnz short InstallFakeBPB + +; Were we returning a fake BPB when asked to build a BPB? + test word ptr ds:[di].Flags, RETURN_FAKE_BPB + jz short InstallRecommendedBPB + +; We were returning a fake BPB but we can stop now + and word ptr ds:[di].Flags, not RETURN_FAKE_BPB + jmp DoneWithBPBstuff + +InstallRecommendedBPB: + mov cx, size a_BPB + lea di, byte ptr [di].RBytePerSec + jmp short CopyTheBPB + +InstallFakeBPB: + mov cx, size BPB_Type ; move 'smaller' BPB + lea di, byte ptr [di].BytePerSec +CopyTheBPB: + lea si, byte ptr [bx].DP_BPB +; exchange es and ds + push es + push ds + pop es + pop ds + + rep movsb + +DoneWithBPBstuff: + Call RestoreOldDPT + RestoreReg + +; Set up track table (if neccessary) +SetTrackTable: + mov cx, word ptr es:[bx].DP_TrackTableEntries + mov cs:sectorsPerTrack, cx + and word ptr ds:[di].Flags, not GOOD_TRACKLAYOUT + test byte ptr es:[bx].DP_SpecialFunctions, TRACKLAYOUT_IS_GOOD + jz UglyTrackLayout + or word ptr ds:[di].Flags, GOOD_TRACKLAYOUT + +UglyTrackLayout: + cmp cx, MAX_SECTORS_IN_TRACK + ja TooManySectorsPerTrack + jcxz SectorInfoSaved ; if no value don't copy table + ; save information in the track table + + push BX ; get ES:BX to point to sector + add BX, DP_SectorTable ; table in Device param. struct + + push DI + mov DI, offset TrackTable + 2 ; CS:DI now points to sector id + ; of the first track table entry + push AX ; preserve AX value + + ; For MAX_SECTORS_IN_TRACK +TrackLoop: ; DO: + mov AX, word ptr ES:[BX] ; get sector number + mov byte ptr CS:[DI], AL ; save in track table + + mov AX, word ptr ES:[BX]+2 ; get sector size + call SectorSizeToSectorIndex ; convert size to index number + mov byte ptr CS:[DI]+1, AL ; save size in track table + + add BX, size a_sectorTable ; advance pointers to next + add DI, size a_sectorTable ; entries + loopnz TrackLoop ; End FOR + + pop AX ; restore the saved values + pop DI + pop BX + +SectorInfoSaved: + clc + ret + +TooManySectorsPerTrack: + mov al, 0cH + stc + ret + +SetDeviceParameters endp + + +; +; FormatTrack: +; If SpecialFunction byte is 1, then this is a status call to see if there is +; ROM support for the combination of sec/trk and # of cyln, and if the +; combination is legal. If SpecialFunction byte is 0, then format the track. +; +; Input: DS:DI points to BDS for drive +; ES:BX points to format packet +; +; Output: +; For status call: +; SpecialFunction byte set to: +; 0 - ROM support + legal combination +; 1 - No ROM support +; 2 - Illegal Combination +; 3 - no media present ;Rev 3.30 +; Carry cleared. +; +; For format track: +; Carry set if error +; +; +; Flags also may be altered. All other registers preserved. +; If the call to ROM returns no error, then the current DPT is "replaced" by +; the one returned by the ROM. This is done by changing the pointer in [DPT] +; to the one returned. The original pointer to the disk base table is stored +; in TempDPT, until it is restored. +; +; This proc was changed to force a status for format call if we are on the +; new ROM. +; +; +FormatTrack proc near + test byte ptr es:[bx].DP_SpecialFunctions,Status_For_Format + jz SkipStatusOnly + +Do_Status_Only: + call FormatStatus + mov byte ptr es:[bx].DP_SpecialFunctions,al + ret + +SkipStatusOnly: ; for a hard disk only do the verify + cmp byte ptr ds:[di].FormFactor, DEV_HARDDISK + jnz SkipVerify + jmp DoVerifyTrack +SkipVerify: + SaveReg ; Format a Track + call FormatStatus ; SetDASD checks media_set_for_format + cmp al,3 ; Check for time out + je Format_Failed ; Fail if time out + call SetDASD +; +; Store Cylinder,Head in track table +; ***** ASSUMPTION ******* +; Since format requests on Fixed Media are converted to Verifies, we +; assume that we are formatting a floppy and hence have 255 or less +; tracks and heads. We therefore must change the Cylinder, Head data +; from the Request Packet Size to that of the TrackTable (see Int 13 +; interface in IBM's Tech Ref.). + +; Check to ensure correct disk is in drive + call CheckSingle + + mov ax, word ptr es:[bx].FP_Cylinder + mov word ptr cs:[TRKNUM],ax + mov cx, word ptr es:[bx].FP_Head + mov byte ptr cs:[HDNUM],cl + mov ah,cl + ; this next piece of code copies the correct head + ; and cylinder numbers to the tracktable + push di ; preserve DI + mov di, offset TrackTable + mov CX, cs:SectorsPerTrack ; get number of sectors + jcxz EndSetUpTrackTable ; if nothing to do skip down +SetUpLoop: + mov cs:[di], AX ; set head and track value + add di, 4 ; move to next entry + loopnz SetUpLoop ; loop if not done yet +EndSetUpTrackTable: + pop di ; restore DI (BDS pointer) + mov cx, MAXERR ; Set up retry count +FormatRetry: + push cx + ; set up registers for format call to TO_ROM + mov AX, word ptr CS:SectorsPerTrack ; set number of sectors + mov AH, ROMFormat + push cs ; set ES:BX to point to + pop es ; the track table + mov BX, offset TrackTable + ; don't need to set CL on format + call to_rom + jnc FormatOk + pop cx + mov cs:[Had_Format_Error],1 ; Mark the error + push ax ;3.30 + push cx ;3.30 + push dx ;3.30 + call ResetDisk + call FormatStatus ;3.30 + cmp al, 1 ;3.30 + jnz While_Err ;3.30 + call SetDASD ;3.30 +While_Err: ;3.30 + pop dx ;3.30 + pop cx ;3.30 + pop ax ;3.30 + loop FormatRetry + +; Format failed +Format_Failed: + mov cs:[Had_Format_Error],1 ; Indicate a format error + cmp ah,Dsk_Change_Line_Err ; Convert change line to + jne Map_Err ; to time out. + mov ah,Dsk_Time_Out_Err +Map_Err: + call MapError + RestoreReg + ret + +FormatOk: + mov cs:[Had_Format_Error],0 ; Reset format error flag + pop cx ; clean up stack after bailing out + ; of FormatRetry loop early + RestoreReg + +DoVerifyTrack: + call VerifyTrack ; Will reset DPT entries. + ret + +FormatTrack endp + +; +; FormatStatus: +; If SpecialFunction byte is 1, then this routine is called to see if there is +; ROM support for the combination of sec/trk and # of cyln, and if the +; combination is legal. +; +; Input: DS:DI points to BDS for drive +; ES:BX points to format packet +; +; Output: +; SpecialFunction byte set to: +; 0 - ROM support + legal combination +; 1 - No ROM support +; 2 - Illegal Combination +; 3 - No media present, ROM support exists but can't determine +; media +; Carry cleared. +; +; For format track: +; Carry set if error +; +; +; Flags also may be altered. All other registers preserved. +; If the call to ROM returns no error, then the current DPT is "replaced" by +; the one returned by the ROM. This is done by changing the pointer in [DPT] +; to the one returned. The original pointer to the disk base table is stored +; in TempDPT, until it is restored. +; +; +FormatStatus proc near + SaveReg + cmp cs:[Had_Format_Error],1 ; Are we here because of a format err + je Fstat01 + cmp byte ptr cs:[Media_Set_For_Format],1 + jnz FStat03 + jmp Stat_Ret +Fstat03: + mov byte ptr cs:[Media_Set_For_Format],0 +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; modification - sp001 +; +; remove check for new rom from here. we shall just assume the +; prescence of the new rom and go ahead and issue the int13 call +; anyway. later on if there is an error we shall check this to +; see if it is there because of lack of rom support, in which +; case the appropriate error will be indicated by setting al to 1 +; +; I would ideally like to see the new rom testing code shifted to +; msinit and this code reintroduced. however for this version we +; are aiming to stick close to the IBM variety. +; +; More changes to support this commenting out will follow. All +; will be marked as modification sp001 +; +; mov al,1 ; No ROM support available error code +; test byte ptr cs:[New_ROM],1 +; jnz FStat01 +; jmp Stat_Ret +Fstat01: + SaveReg + + xor ax,ax + mov ds,ax + lds si, dword ptr ds:[DskAdr] ; DS:SI := pDPT + + mov word ptr cs:[DPT],si ; cs:[DPT] := pDPT + mov word ptr cs:[DPT + 2],ds + + RestoreReg + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; modification sp001 +; +; the following instruction introduced for the new rom modification +; + mov cs:[New_Rom],1 ; assume new rom +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + mov ax,word ptr [di].cCyln + mov cx,word ptr [di].Seclim + ; set up registers for format status call + and AH, 03h ; 'and' out unneeded track bits + ror AH, 1 ; get track and sector values correct + ror AH, 1 + or AH, CL ; set sector number + xchg AH, AL + mov CX, AX + dec CH + mov DL, byte ptr [DI].DriveNum ; get drive number + mov AH, 18h ; set command to "sec/trk supported?" + + SaveReg + int 13h ; call rom bios to see if supported + jc Format_Stat_Err ; if carry, combination is not supported + + ; ES:DI points to new Disk Base Table + ; combination for this drive replace + ; current (DskAdr) pointer with new one, + ; saving the old one in TempDPT. + + cmp cs:[Had_Format_Error],1 ; Are we here because of a format err + jnz Fstat02 ; Then skip the disk base setup + + xor al,al ; Supported and OK + mov cs:[Had_Format_Error],al ; Clear format error + jmp Pop_Stat_Ret ; Back to work + +Fstat02: + xor ax,ax + mov ds,ax + lds si, dword ptr ds:[DskAdr] ; DS:SI := pDPT + + mov word ptr cs:[TempDPT],si + mov word ptr cs:[TempDPT + 2],ds ; Save pDPT + + mov word ptr ds:[DskAdr],DI ; Setup New DPT returned by + mov word ptr ds:[DskAdr + 2],ES ; ROM + + mov byte ptr cs:[Media_Set_For_Format],1 ; set flag + xor al,al ; Legal combination + ROM support code + jmp short Pop_Stat_Ret + +Format_Stat_Err: + mov al,3 ; Assume a time out + cmp ah,Dsk_Time_Out_Err ; Was it a time out??? + jz Pop_Stat_Ret ; Yes - then done + dec al ; Assume an illegal comb. + cmp ah,Dsk_illegal_combination ; Was it an illegal comb??? + jz Pop_Stat_Ret ; Yes - then done + dec al ; Assume No ROM Support +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; modification sp001 +; +; the following instruction was introduced for the new_rom modification +; + mov cs:[New_Rom],0 ; the old rom +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Return result of status call +Pop_Stat_Ret: + RestoreReg +Stat_Ret: + clc + RestoreReg + ret +FormatStatus endp + + + +; +; VerifyTrack: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to verify packet +; + PUBLIC VERIFYTRACK ;3.30 +VerifyTrack proc near + mov cs:RFLAG, ROMverify + mov ax, word ptr es:[bx].VP_Cylinder + mov cs:curtrk, ax + mov ax, word ptr es:[bx].VP_Head + +; ****** ASSUMPTION ****** +; we assume that we have less than 256 heads, and that the Request +; Header Data Structure is unneccessarily big + mov cs:curhd, al + xor ax, ax + mov cx, cs:sectorsPerTrack +; Use 0:0 as the transfer address for verify + xor bx, bx + mov es, bx + call TrackIO + ret +VerifyTrack endp + +; +; ReadTrack: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to read packet +; + PUBLIC READTRACK ;3.30 +ReadTrack: + mov cs:RFLAG, ROMread + jmp ReadWriteTrack + +; +; WriteTrack: +; +; Input: DS:DI points to BDS for drive +; ES:BX points to write packet +; + PUBLIC WRITETRACK ;3.30 +WriteTrack: + mov cs:RFLAG, ROMwrite + jmp ReadWriteTrack +; +; ReadWriteTrack: +; +; Input: +; DS:DI points to BDS for drive +; ES:BX points to write packet +; RFLAG - 2 for read, 3 for write +; + PUBLIC READWRITETRACK ;3.30 +ReadWriteTrack proc near + mov ax, word ptr es:[bx].TRWP_Cylinder + mov cs:curtrk, ax + mov ax, word ptr es:[bx].TRWP_Head + +; ****** ASSUMPTION ****** +; we assume that we have less than 256 heads, and that the Request +; Header Data Structure is unneccessarily big + mov cs:curhd, al + mov ax, word ptr es:[bx].TRWP_FirstSector + mov cx, word ptr es:[bx].TRWP_SectorsToReadWrite + les bx, es:[bx].TRWP_TransferAddress + call TrackIO + ret +ReadWriteTrack endp + + +; +; TrackIO: +; Performs Track Read/Write/Verify +; +; Input: +; RFLAG - 2 = Read +; 3 = Write +; 4 = Verify +; ax - Index into track table of first sector to IO +; cx - number of sectors to IO +; es:bx - Transfer address +; ds:di - pointer to BDS +; curtrk - current cylinder +; curhd - current head +; + public trackio +TrackIO proc near +; procedure `disk' will pop stack to SPsav and return if error + mov cs:SPsav, sp +; Ensure correct disk is in drive + call CheckSingle +; +; Set up tables and variables for I/O +; + cmp byte ptr cs:[Media_Set_For_Format],1 + jz DPTAlreadySet + +; ;3.30 +; SET UP TABLES AND VARIABLES FOR I/O ;3.30 +; ;3.30 + SaveReg + call IOSetUp + RestoreReg +; +; point si at the table entry of the first sector to be IO'd +; +DPTAlreadySet: + mov si, offset trackTable + shl ax, 1 + shl ax, 1 + add si, ax +; +; we want: +; cx to be the number of times we have to loop +; dx to be the number of sectors we read on each iteration + mov dx, 1 + test word ptr ds:[di].Flags, GOOD_TRACKLAYOUT + jz IOnextSector + +; Hey! we can read all the sectors in one blow + xchg dx, cx + +IOnextSector: + push cx + push dx +; skip over the cylinder and head in the track table + inc si + inc si + +; Get sector id from track table + mov AL, byte ptr cs:[si] ; get current sector value + mov cs:[cursec], AL ; save cursec value + +;*** For a Fixed disk multi-track disk I/O - 4/14/86 ;3.30 +;Assumptions: 1). In the input CX (# of sectors to go) to TRACKIO, only CL;3.30 is +;valid. 2). Sector size should be set to 512 bytes. 3). GOODTRACKLAYOUT. ;3.30 +; ;3.30 + test word ptr [di].Flags, fNon_Removable ;Fixed disk? - J.K;3.30 . + jz IOREMOVABLE ;no - ;3.30 + mov cs:[seccnt], dx ;# of sectors to I;3.30 /O - + mov ax, dx ; ;3.30 + call disk ; ;3.30 + pop dx ; ;3.30 + pop cx ; ;3.30 + clc ; ;3.30 + ret ; ;3.30 +IOREMOVABLE: ; ;3.30 + + mov AL, byte ptr cs:[si]+1 ; get sector size index + + ; The next eight lines put sector size index in DPT + push ES ; save value while getting pointer + push SI ; to DPT + push AX + + les SI, cs:DPT ; ES:SI points to DPT + ; put size in DPT + mov byte ptr ES:[si].Disk_Sector_Siz, AL + mov AX, word ptr [di].seclim ; get number of sector/track + mov byte ptr ES:[si].Disk_EOT,AL ; patch in DPT + + pop AX ; restore register values + pop SI + pop ES + ; convert index to byte value + call SectorSizeIndexToSectorSize + push AX ; save number of bytes in sector + mov AX, DX ; get number of sector for I/0 + +DoTheIO: + mov cs:[SECCNT],ax ; set up the count of sectors to I/O + call disk + ; advance buffer pointer by adding + ; sector size + pop ax + add bx, ax + pop dx + pop cx + loop IOnextSector + call DONE ; Set time of last access, and reset + clc ; entries in DPT. + ret + +TrackIO endp +; +; The sector size in bytes needs to be converted to an index value for the IBM +; ROM. (0=>128, 1=>256,2=>512,3=>1024). It is assumed that only these values +; are permissible. +; On Input AX contains sector size in bytes +; On Output AL contains index +; + public SectorSizeToSectorIndex +SectorSizeToSectorIndex proc near + and AH, 07h ; very simple error correction + mov AL, AH ; shift left 8 bits + cmp AL, 4 ; size 1024? + jnz SecToIndexRet ; no, then we are done + sub AL, 1 ; if 1024, adjust index to 3 +SecToIndexRet: + ret +SectorSizeToSectorIndex endp + +SectorSizeIndexToSectorSize proc near +; value in AH on entry is not important + push CX ; save CX value + mov CL, AL ; use index number as shift size + mov AX, 0080h ; set AX to 128 + shl AX, CL ; shift by index to get proper value + pop CX ; restore CX value + ret +SectorSizeIndexToSectorSize endp + + + +; +; Set up the ROM for formatting. +; we have to tell the ROM BIOS what type of disk is in the drive. +; On Input - DS:DI - points to BDS +; +SetDASD proc near +; See if we have new ROM and have issues Set Media Type For Format call + test byte ptr cs:[Media_Set_For_Format],1 + jnz DasdHasBeenSet +; See if we have previously set DASD type + cmp cs:[Had_Format_Error],1 + je DoSetDasd + test word ptr ds:[di].Flags, SET_DASD_true + jz DASDhasBeenSet + and word ptr ds:[di].Flags, not SET_DASD_true + ; the next nine lines determine and put the DASD type in AL +DoSetDasd: + mov cs:[Had_Format_Error],0 + mov cs:[GAP_PATCH], 50h ; assume 48tpi or 3.5" drive + cmp [di].FormFactor, ffSmall; is 3.5" drive? + jnz not35Drive ; no, skip down + mov AL, 04h ; yes set proper DASD value + jmp short Do_Set ; jump down + +Not35Drive: + mov AL, 01h ; + cmp [di].FormFactor, ff96tpi; 96tpi disk drive? + jnz Do_Set ; no skip down to rom call + inc AL ; reflect 96tpi drive in DASD type + cmp [di].seclim, 15 ; 96tpi media in drive? + jnz Do_Set ; no, skip down to rom call + inc AL ; reflect 96tpi media in DASD type + mov cs:[GAP_PATCH], 54h ; and in the GAP_PATCH +Do_Set: + mov AH, 17h ; set command to Set DASD type + mov DL, [di].DriveNum ; set drive number + int 13h ; call rom-bios +DASDhasBeenSet: + mov ah,byte ptr [di].seclim + mov cs:[FORMT_EOT],ah + ret +SetDasd endp + + +; +; This routine is called if an error occurs while formatting or verifying. +; It resets the drive, and decrements the retry count. +; On Entry - DS:DI - points to BDS for the drive +; BP - contains retry count +; On Exit Flags indicate result of decrementing retry count +; +; +; There are some drives that "lose" the changeline indication if another +; floppy drive is accessed before the changeline is recorded by the device +; driver. In this situation, it is possible for the ROM to also not detect +; that the medium has changed. So, the end result is that we could have a +; diskette in the drive for which we can not even read the boot sector. +; We "fix" this by setting the byte at location DISK_STATE_MACHINE_DRV_0 (hex) +; for physical drive 0 (or DISK_STATE_MACHINE_DRV_1 for drive 1) to 0 (See +; IBM PC/AT "blessed" addresses Document for explanation) . This tells the ROM +; that the medium is 'unknown'. The ROM actually uses these locations for +; itself. Note that we do this only for internal drives; we do not do this for +; fixed disks or for physical drives > 1. We may end up corrupting some +; other bytes in memory that may be used for something else. +; NOTE: We do not stuff this byte if the last operation was a FORMAT because +; the ROM loses track of what it is trying to format!! +; +; This routine was changed to only stuff 61H when the drive indicated it +; supported changeline. The Phoenix ROM was taking a very long time +; to figure out what the media was which caused disk time outs to take +; forever +; +; We assume that DS:DI points to the current BDS for this drive. +; no registers should be touched +; + +AGAIN: + call ResetDisk + dec bp ; decrement retry count + RET + + PUBLIC RESETDISK +ResetDisk: + push ax + xor AH, AH ; set command to reset disk + int 13h ; call the rom-bios + pop ax + mov cs:[STEP_DRV],-1 ; zap up the speed + ret + +; +; This routine sets up the Drive Parameter Table with the values needed for +; Format, does an Int 13. Values in DPT are restored after a VERIFY is done. +; +; On Entry - DS:DI - points to BDS for the drive +; ES:BX - points to TRKBUF +; AL - number of sectors +; AH - Int 13 function code +; CL - Sector number for verify +; On Exit - DS,DI,ES,BX remain unchanged. +; ax and flags are the results of the int 13 +; + Public To_ROM +To_ROM: + SAVEREG ;3.30 + +; The below line was replaced because saving the DPT is predicated upon +; whether the functionality of the new ROM was used, not if it exists. +; test byte ptr cs:[New_ROM],1 + + test byte ptr cs:[Media_Set_For_Format],1 + jnz Got_Valid_DPT + +; Set up values in the DPT +; Set up motor start correctly for 3.5" drives. + push ax + push ds + + xor ax,ax + mov ds,ax + lds si,dword ptr ds:[DskAdr] ; DS:SI := pDPT + + mov word ptr cs:[DPT],si + mov word ptr cs:[DPT+2],ds ; Save pDPT + + pop ds + push ES ; save value in ES + LES SI, CS:DPT + + mov DX, [di].seclim ; set the sector per track in + mov es:[si].DISK_EOT, DL ; the Disk Parameter Table + cmp DX, 15 ; 96tip media? + jz To_ROM1 ; yes, skip down + ; no - set Format Gap to 320/360 media value + mov CL, cs:[Gap_Patch] + mov byte ptr ES:[si].DISK_FORMT_GAP, CL +To_ROM1: ; 3.5" floppy drive? + cmp byte ptr [di].FormFactor, ffSmall + jnz To_ROM2 ; no, skip down + ; yes - reset disk moter start value + mov byte ptr ES:[si].DISK_MOTOR_STRT, 4 +To_ROM2: + pop ES ; restore ES value + pop ax + +Got_Valid_DPT: + ; now set up the registers + mov DL, [di].DriveNum ; set drive number + mov DH, CS:[HDNUM] ; set head number + mov CX, CS:[TRKNUM] ; set track number + ror CH,1 + ror CH,1 + xchg CH, CL + int 13h ; call the rom-bios disk routines + RestoreReg + ret + + +; +; Get the owner of the physical drive represented by the logical drive in BL. +; The assumption is that we **ALWAYS** keep track of the owner of a drive!! +; If this is not the case, the system may hang, just following the linked list. +; + PUBLIC IOCTL$GETOWN +IOCTL$GETOWN: + call SetDrive + mov al,byte ptr [di].DriveNum ; Get physical drive number + push cs + pop ds + mov di,word ptr Start_BDS +Own_Loop: + cmp byte ptr [di].DriveNum,al + jne GetNextBDS + test word ptr [di].flags,fI_Own_Physical + jnz Done_GetOwn +GetNextBDS: + mov bx,word ptr [di].link+2 + mov di,word ptr [di].link + mov ds,bx + jmp short Own_Loop +Done_GetOwn: + JMP SHORT EXIT_OWN + +; +; Set the ownership of the physical drive represented by the logical drive in +; BL. +; + PUBLIC IOCTL$SETOWN +IOCTL$SETOWN: + call SetDrive + mov byte ptr cs:[fSetOwner],1 ; set flag for CheckSingle to + ; look at. + call CheckSingle ; Set ownership of drive + mov byte ptr cs:[fSetOwner],0 ; reset flag + xor bx,bx + mov es,bx + mov cl,-1 + mov byte ptr es:[LSTDRV],cl ; Set up SDSB as well + +EXIT_OWN: +; If there is only one logical drive assigned to this physical drive, return +; 0 to user to indicate this. + xor cl,cl + test word ptr [di].flags,fI_Am_Mult + jz EXIT_NO_MULT + mov cl,byte ptr [di].DriveLet ; Get logical drive number + inc cl ; get it 1-based +EXIT_NO_MULT: + LDS BX,CS:[PtrSav] + mov byte ptr [BX].UNIT,CL + jmp EXIT + + + + +; +; Moves the old DPT that had been saved in TempDPT back to DPT. This is done +; only if the first byte of TempDPT is not -1. +; All registers (including flags) are preserved. +; + Public RestoreOldDPT +RestoreOldDPT: +; If we have already restored the disk base table earlier, do not do it +; again. + push ax + xor al,al +; Reset flag and get current flag setting + mov cs:[Had_Format_Error],al + xchg byte ptr cs:[Media_Set_For_Format],al + or al,al + jz DontRestore + SaveReg + LDS SI,CS:[TempDPT] + xor ax,ax + mov es,ax ; have ES -> segment 0 + MOV WORD PTR ES:[DskAdr],SI + MOV WORD PTR ES:[DskAdr+2],DS +GotCurrentDPT: + RestoreReg +DontRestore: + pop ax + clc ; clear carry + ret ; (7/31/86) + +;end of file msioctl.asm diff --git a/UPDSRC/BIOS/MSSTACK.INC b/UPDSRC/BIOS/MSSTACK.INC new file mode 100644 index 0000000..edf01c9 --- /dev/null +++ b/UPDSRC/BIOS/MSSTACK.INC @@ -0,0 +1,306 @@ +; MSStack.inc +; +; Interrupt level 2, 3, 4, 5, 6, 7,(10, 11, 12, 14, 15 - AT level) +; should follow the standard Interrupt Sharing Scheme which has +; a standard header structure. +; Fyi, the following shows the relations between +; the interrupt vector and interrupt level. +; VEC(Hex) 2 8 9 A B C D E 70 72 73 74 76 77 +; LVL(Deci) 9 0 1 2 3 4 5 6 8 10 11 12 14 15 +; MSSTACK module modifies the following interrupt vectors +; to meet the standard Interrupt Sharing standard; +; A, B, C, D, E, 72, 73, 74, 76, 77. +; Also, for interrupt level 7 and 15, the FirstFlag in a standard header +; should be initialized to indicat whether this interrupt handler is +; the first (= 80h) or not. The FirstFlag entry of INT77h's +; program header is initialized in STKINIT.INC module. +; FirstFlag is only meaningful for interrupt level 7 and 15. +; + +; User specifies the number of stack elements - default = 9 +; minimum = 8 +; maximum = 64 +; +; Intercepts Asynchronous Hardware Interrupts only +; +; Picks a stack from pool of stacks and switches to it +; +; Calls the previously saved interrupt vector after pushing flags +; +; On return, returns the stack to the stack pool +; + + +; This is a modification of STACKS: +; 1. To fix a bug which was causing the program to take up too much space. +; 2. To dispense stack space from hi-mem first rather than low-mem first. +; . Clobbers the stack that got too big instead of innocent stack +; . Allows system to work if the only stack that got too big was the most +; deeply nested one +; 3. Disables NMI interrupts while setting the NMI vector. +; 4. Does not intercept any interupts on a PCjr. +; 5. Double checks that a nested interrupt didn't get the same stack. +; 6. Intercepts Ints 70, 72-77 for PC-ATs and other future products + +;The following variables are for MSSTACK.inc + EVEN + dw 0 ; SPARE FIELD BUT LEAVE THESE IN ORDER +StackCount dw 0 +StackAt dw 0 +StackSize dw 0 +Stacks dw 0 + dw 0 + +FirstEntry dw Stacks +LastEntry dw Stacks+(DefaultCount*EntrySize)-EntrySize +NextEntry dw Stacks+(DefaultCount*EntrySize)-EntrySize + +;End of variables defined for MSSTACK. + +;******************************************************************* +;Macro Interrupt handler for the ordinary interrupt vectors and +;the shared interrupt vectors. +;***************************** +Stack_Main MACRO AA + ASSUME DS:NOTHING + ASSUME ES:NOTHING + ASSUME SS:NOTHING +PUBLIC Int&AA +PUBLIC Old&AA +;----------------------------- + ife IntSharingFlag ;if not IntSharingFlag +;----------------------------- + Old&AA DD 0 +Int&AA PROC FAR +;----------------------------- + else ;for shared interrupt. A Header exists. + +PUBLIC FirstFlag&AA +Int&AA PROC FAR + jmp short Entry_Int&AA&_Stk + Old&AA dd 0 ;Forward pointer + dw 424Bh ;compatible signature for Int. Sharing + FirstFlag&AA db 0 ;the firstly hooked. + jmp short Intret_&AA ;Reset routine. We don't care this. + db 7 dup (0) ;Reserved for future. +Entry_Int&AA&_Stk: +;----------------------------- + endif +;----------------------------- + +; +; Keyboard interrupt must have a three byte jump, a NOP and a zero byte +; as its first instruction for compatibility reasons + ifidn <&aa>,<09> + jmp Keyboard_lbl + nop + db 0 +Keyboard_lbl label near + endif + +; This patches INTERRUPT 75h to be "unhooked". We do this Wierdness, +; rather than never hooking INT 75h, to maintain maximum compat. with IBMs +; post production patch. + push ax + + ifidn <&aa>,<02> + +; ********************************************************************* +; +; This is special support for the P12 / NMI handler +; +; On the P12, there is a situation where an NMI can be caused by +; using the "OUT" instructions to certain ports. When this +; occurs, the P12 hardware *GUARANTEES* that **NOTHING** can stop +; the NMI or interfere with getting to the NMI handler. This +; includes other type of interrupts (hardware and software), and +; also includes other type of NMI's. When any NMI has occured, +; no other interrtupt (hardware, software or NMI) can occur until +; the software takes specific steps to allow further interrupting. +; +; For P12, the situation where the NMI is generated by the "OUT" +; to a control port requires "fixing-up" and re-attempting. In +; otherwords, it is actually a "restartable exception". In this +; case, the software handler must be able to get to the stack in +; order to figure out what instruction caused the problem, where +; it was "OUT"ing to and what value it was "OUT"ing. Therefore, +; we will not switch stacks in this situation. This situation is +; detected by interrogating port 62h, and checking for a bit value +; of 80h. If set, *****DO NOT SWITCH STACKS*****. +; +; ********************************************************************* + + push ds + mov ax,0f000h + mov ds,ax + cmp byte ptr ds:[0fffeh],0f9h ;check if P12 + pop ds + jne Normal&aa + + in al,62h + test al,80h + jz Normal&aa + +Special&aa: + pop ax + jmp dword ptr Old&aa + +Normal&aa: + +; ********************************************************************* + + endif + + push bp + push es + mov es, cs:[STACKS+2] ; Get segment of stacks + + mov bp,NextEntry ; get most likely candidate + mov al,Allocated + xchg AllocByte,al ; grab the entry + cmp al,Free ; still avail? + jne NotFree&aa + + sub NextEntry,EntrySize ; set for next interrupt + +Found&aa: + mov SavedSP,sp ; save sp value + mov SavedSS,ss ; save ss also +; mov IntLevel,aa&h ; save the int level + + mov ax,bp ; temp save of table offset + + mov bp,NewSP ; get new SP value + cmp es:[bp],ax ; check for offset into table + jne FoundBad&aa + + mov ax,es ; point ss,sp to the new stack + mov ss,ax + mov sp,bp + + pushf ; go execute the real interrupt handler + call dword ptr old&aa ; which will iret back to here + + mov bp,sp ; retrieve the table offset for us + mov bp,es:[bp] ; but leave it on the stack + mov ss,SavedSS ; get old stack back + mov sp,SavedSP + +; cmp AllocByte,Allocated ; If an error occured, +; jne NewError&aa ; do not free us + + mov AllocByte,Free ; free the entry + mov NextEntry,bp ; setup to use next time + +NewError&aa: + pop es + pop bp ; saved on entry + pop ax ; saved on entry + +INTRET_&AA: ;3.30 + iret ; done with this interrupt + +NotFree&aa: + cmp al,Allocated ; error flag + je findnext&aa ; no, continue + xchg AllocByte,al ; yes, restore error value + +FindNext&aa: + call LongPath + jmp Found&aa + +FoundBad&aa: + cmp bp,FirstEntry + jc findnext&aa + mov bp,ax ; flag this entry + mov AllocByte,Clobbered +; add bp,EntrySize ; and previous entry +; mov AllocByte,Overflowed +; sub bp,EntrySize + jmp findnext&aa ; keep looking + +int&aa endp + + + endm + +;***************************** ;3.30 +;End of Macro definition ;3.30 +;******************************************************************** ;3.30 +; THESE ARE THE INDIVIDUAL INTERRUPT HANDLERS ;3.30 + ;3.30 + IRP A,<02,08,09,70> ;3.30 + IntSharingFlag=0 ;3.30 + Stack_Main &A ;3.30 + ENDM ;3.30 + ;3.30 + IRP A,<0A,0B,0C,0D,0E,72,73,74,76,77> ;3.30 + IntSharingFlag=1 ;3.30 + Stack_Main &A ;3.30 + ENDM ;3.30 + ;3.30 +;******************************************************************** ;3.30 +;Common routines ;3.30 + +longpath: + mov bp,LastEntry ; start with last entry in table + +LPLOOPP: ;3.30 + cmp AllocByte,Free ; is entry free? + jne inuse ; no, try next one + + mov al,Allocated + xchg AllocByte,al ; allocate entry + cmp al,Free ; is it still free? + je found ; yes, go use it + + cmp al,Allocated ; is it other than Allocated or Free? + je inuse ; no, check the next one + + mov AllocByte,al ; yes, put back the error state + +inuse: + cmp bp,FirstEntry + je Fatal + sub bp,EntrySize + JMP LPLOOPP ;3.30 + +found: + ret + + page + +fatal proc near + push ds ;3.30 + mov ax, 0f000h ;loook at the model byte ;3.30 + mov ds, ax ;3.30 + cmp ds:byte ptr [0fffeh], 0f9h ;convertible ;3.30 + pop ds ;3.30 + jne Skip_NMIS ;3.30 + ;3.30 + mov al,07h ; disable p12 NMIs + out 72h,al + +Skip_NMIS: ;3.30 + cli ; disable and mask + mov al,0ffh ; all other ints + out 021h,al + out 0a1h,al + + mov si,cs + mov ds,si + mov si,offset fatal_msg + +fatal_loop: + lodsb + cmp al,'$' + je fatal_done + + mov bl,7 ;3.30* + mov ah,14 ;3.30* + int 010h ; whoops, this enables ints ;3.30* + jmp fatal_loop + +fatal_done: + jmp fatal_done +fatal endp diff --git a/UPDSRC/BIOS/SYSINIT2.ASM b/UPDSRC/BIOS/SYSINIT2.ASM new file mode 100644 index 0000000..e2356da --- /dev/null +++ b/UPDSRC/BIOS/SYSINIT2.ASM @@ -0,0 +1,1276 @@ +TITLE BIOS SYSTEM INITIALIZATION +TRUE EQU 0FFFFh +FALSE EQU 0 + +;IBMVER EQU TRUE +;IBM EQU IBMVER +STACKSW EQU TRUE ;Include Switchable Hardware Stks ;3.30 +;IBMJAPVER EQU FALSE ;If TRUE set KANJI true also +;MSVER EQU FALSE +;ALTVECT EQU FALSE ;Switch to build ALTVECT version +;KANJI EQU FALSE + +include version.inc + + IF IBMJAPVER +NOEXEC EQU TRUE + ELSE +NOEXEC EQU FALSE + ENDIF + +DOSSIZE EQU 0A000H + +.xlist + include smdossym.inc ; Reduced version of DOSSYM.INC ;3.30 + INCLUDE devsym.inc + include ioctl.inc +.list + + IF NOT IBM + IF NOT IBMJAPVER + EXTRN RE_INIT:FAR + ENDIF + ENDIF + +SYSINITSEG SEGMENT PUBLIC 'SYSTEM_INIT' BYTE + +ASSUME CS:SYSINITSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING + + EXTRN BADOPM:BYTE,CRLFM:BYTE,BADCOM:BYTE,BADMEM:BYTE,BADBLOCK:BYTE + EXTRN BADSIZ_PRE:BYTE,BADLD_PRE:BYTE + EXTRN BADSIZ_POST:BYTE,BADLD_POST:BYTE + EXTRN SYSSIZE:BYTE,BADCOUNTRY:BYTE + + EXTRN dosinfo:dword,entry_point:dword, + EXTRN MEMORY_SIZE:WORD,fcbs:byte,keep:byte + EXTRN DEFAULT_DRIVE:BYTE,confbot:word,alloclim:word + EXTRN BUFFERS:WORD,zero:byte,sepchr:byte + EXTRN FILES:BYTE,stall:near + EXTRN count:word,chrptr:word + EXTRN bufptr:byte,memlo:word,prmblk:byte,memhi:word + EXTRN ldoff:word,area:word,PACKET:BYTE,UNITCOUNT:BYTE, + EXTRN BREAK_ADDR:DWORD,BPB_ADDR:DWORD,drivenumber:byte + + PUBLIC Int24,Open_Dev,Organize,Mem_Err,Newline,CallDev,Badload + PUBLIC PrnDev,AuxDev,Config,Commnd,Condev,GetNum,BadFil,PrnErr + PUBLIC Round,Delim,Print,Set_Break + PUBLIC SetParms, ParseLine, DiddleBack + PUBLIC Skip_delim,SetDOSCountryInfo,Set_Country_Path,Move_Asciiz ;3.30 + PUBLIC Cntry_Drv,Cntry_Root,Cntry_Path ;3.30 + PUBLIC Delim ;3.30 + +ASSUME DS:SYSINITSEG +; +; The following set of routines is used to parse the DRIVPARM = command in +; the CONFIG.SYS file to change the default drive parameters. +; +SetParms: + push ds + push ax + push bx + push cx + push dx + xor bx,bx + mov bl,byte ptr drive + inc bl ; get it correct for IOCTL call (1=A,2=B...) + push cs + pop ds + mov dx,offset DeviceParameters + mov ah, IOCTL + mov al, GENERIC_IOCTL + mov ch, RAWIO + mov cl, SET_DEVICE_PARAMETERS + int 21H + pop dx + pop cx + pop bx + pop ax + pop ds + ret + +; +; Replace default values for further DRIVPARM commands +; +DiddleBack: + mov word ptr DeviceParameters.DP_Cylinders,80 + mov byte ptr DeviceParameters.DP_DeviceType, DEV_3INCH720KB + mov word ptr DeviceParameters.DP_DeviceAttributes,0 + mov word ptr switches,0 ; zero all switches + ret + +; +; Entry point is ParseLine. AL contains the first character in command line. +; +ParseLine: ; don't get character first time + push ds + push cs + pop ds +NextSwtch: + cmp al,13 ; carriage return? + jz done_line + cmp al,10 ; linefeed? + jz put_back ; put it back and done +; Anything less or equal to a space is ignored. + cmp al,' ' ; space? + jbe get_next ; skip over space + cmp al,'/' + jz getparm + stc ; mark error invalid-character-in-input + jmp short exitpl + +getparm: + call Check_Switch + mov word ptr Switches,BX ; save switches read so far + jc swterr +get_next: + invoke getchr + jc done_line + jmp NextSwtch +swterr: + jmp exitpl ; exit if error + +done_line: + test word ptr Switches,flagdrive ; see if drive specified + jnz okay + stc ; mark error no-drive-specified + jmp short exitpl + +okay: + mov ax,word ptr switches + and ax,0003H ; get flag bits for changeline and non-rem + mov word ptr DeviceParameters.DP_DeviceAttributes,ax + mov word ptr DeviceParameters.DP_TrackTableEntries, 0 + clc ; everything is fine + call SetDeviceParameters +exitpl: + pop ds + ret + +put_back: + inc count ; one more char to scan + dec chrptr ; back up over linefeed + jmp short done_line +; +; Processes a switch in the input. It ensures that the switch is valid, and +; gets the number, if any required, following the switch. The switch and the +; number *must* be separated by a colon. Carry is set if there is any kind of +; error. +; +Check_Switch: + invoke getchr + jc err_check + and al,0DFH ; convert it to upper case + cmp al,'A' + jb err_check + cmp al,'Z' + ja err_check + push es + push cs + pop es + mov cl,byte ptr switchlist ; get number of valid switches + mov ch,0 + mov di,1+offset switchlist ; point to string of valid switches + repne scasb + pop es + jnz err_check + mov ax,1 + shl ax,cl ; set bit to indicate switch + mov bx,word ptr switches ; get switches so far + or bx,ax ; save this with other switches + mov cx,ax + test ax,7cH ; test against switches that require number to follow + jz done_swtch + invoke getchr + jc err_Swtch + cmp al,':' + jnz err_swtch + invoke getchr + push bx ; preserve switches + mov byte ptr cs:sepchr,' ' ; allow space separators + call GetNum + mov byte ptr cs:sepchr,0 + pop bx ; restore switches +; Because GetNum does not consider carriage-return or line-feed as OK, we do +; not check for carry set here. If there is an error, it will be detected +; further on (hopefully). + call Process_Num + +done_swtch: + clc + ret + +err_swtch: + xor bx,cx ; remove this switch from the records +err_check: + stc + ret + +; +; This routine takes the switch just input, and the number following (if any), +; and sets the value in the appropriate variable. If the number input is zero +; then it does nothing - it assumes the default value that is present in the +; variable at the beginning. Zero is OK for form factor and drive, however. +; +Process_Num: + test word ptr Switches,cx ; if this switch has been done before, + jnz done_ret ; ignore this one. + test cx,flagdrive + jz try_f + mov byte ptr drive,al + jmp short done_ret + +try_f: + test cx,flagff + jz try_t +; Ensure that we do not get bogus form factors that are not supported + ;cmp al,Max_Dev_Type + ;ja done_ret + mov byte ptr DeviceParameters.DP_DeviceType,al + jmp short done_ret + +try_t: + or ax,ax + jz done_ret ; if number entered was 0, assume default value + test cx,flagcyln + jz try_s + mov word ptr DeviceParameters.DP_Cylinders,ax + jmp short done_ret + +try_s: + test cx,flagseclim + jz try_h + mov word ptr slim,ax + jmp short done_ret +; +; Must be for number of heads +try_h: + mov word ptr hlim,ax + +done_ret: + clc + ret + +; +; SetDeviceParameters sets up the recommended BPB in each BDS in the +; system based on the form factor. It is assumed that the BPBs for the +; various form factors are present in the BPBTable. For hard files, +; the Recommended BPB is the same as the BPB on the drive. +; No attempt is made to preserve registers since we are going to jump to +; SYSINIT straight after this routine. +; +SetDeviceParameters: + push es + push cs + pop es +ASSUME ES:SYSINITSEG + xor bx,bx + mov bl,byte ptr DeviceParameters.DP_DeviceType + cmp bl,DEV_5INCH + jnz Got_80 + mov cx,40 ; 48tpi has 40 cylinders + mov word ptr DeviceParameters.DP_Cylinders,cx +Got_80: + shl bx,1 ; get index into BPB table + mov si,offset BPBTable + mov si,word ptr [si+bx] ; get address of BPB +Set_RecBPB: + mov di,offset DeviceParameters.DP_BPB ; es:di -> BPB + mov cx,size a_BPB + cld + repe movsb + pop es +ASSUME ES:NOTHING + test word ptr switches,flagseclim + jz see_heads + mov ax,word ptr slim + mov word ptr DeviceParameters.DP_BPB.BPB_SectorsPerTrack,ax +see_heads: + test word ptr switches,flagheads + jz Set_All_Done + mov ax,word ptr hlim + mov word ptr DeviceParameters.DP_BPB.BPB_Heads,ax +; +; We need to set the media byte and the total number of sectors to reflect the +; number of heads. We do this by multiplying the number of heads by the number +; of 'sectors per head'. This is not a fool-proof scheme!! +; + mov cx,ax ; cx has number of heads + dec cl ; get it 0-based + mov ax,DeviceParameters.DP_BPB.BPB_TotalSectors ; this is OK for two heads + sar ax,1 ; ax contains # of sectors/head + sal ax,cl + jc Set_All_Done ; We have too many sectors - overflow!! + mov DeviceParameters.DP_BPB.BPB_TotalSectors,ax +; Set up correct Media Descriptor Byte + cmp cl,1 + mov bl,0F0H + mov al,2 ; AL contains sectors/cluster + ja Got_Correct_Mediad + mov bl,byte ptr DeviceParameters.DP_BPB.BPB_MediaDescriptor + je Got_Correct_Mediad +; We have one head - OK for 48tpi medium + mov al,1 ; AL contains sectors/cluster + mov ch,DeviceParameters.DP_DeviceType + cmp ch,DEV_5INCH + jz Dec_Mediad + mov bl,0F0H + jmp short Got_Correct_Mediad +Dec_Mediad: + dec bl ; adjust for one head +Got_Correct_Mediad: + mov byte ptr DeviceParameters.DP_BPB.BPB_MediaDescriptor,bl + mov byte ptr DeviceParameters.DP_BPB.BPB_SectorsPerCluster,al + clc +Set_All_Done: + RET + +ASSUME DS:NOTHING, ES:NOTHING + +NOCHAR1: STC + return + +ORGANIZE: + MOV CX,[COUNT] + JCXZ NOCHAR1 + CALL MAPCASE + XOR SI,SI + MOV DI,SI + +ORG1: CALL GET ;SKIP LEADING CONTROL CHARACTERS + CMP AL,' ' + JB ORG1 + + PUSH CX + PUSH SI + PUSH DI + MOV BP,SI + DEC BP + MOV SI,OFFSET COMTAB ;Prepare to search command table + MOV CH,0 +FINDCOM: + MOV DI,BP + MOV CL,[SI] + INC SI + JCXZ NOCOM + REPE CMPSB + LAHF + ADD SI,CX ;Bump to next position without affecting flags + SAHF + LODSB ;Get indicator letter + JNZ FINDCOM + POP DI + POP SI + POP CX + JMP SHORT GOTCOM + +NOCOM: + POP DI + POP SI + POP CX + MOV AL,'Z' +GOTCOM: STOSB ;SAVE INDICATOR CHAR IN BUFFER + +ORG2: CALL GET2 ;SKIP NAME UNTIL DELIMITER + CALL DELIM ; + JNZ ORG2 + +;--------------------------------------------------------------bug330a03 +; - isp +;* the following two lines in the parsing caused the drivparm line to break +;* we cannot let the "/" character be counted as a delimiter here. +; CALL GET ;GET CHARS TO RIGHT OF EQUALS SIGN +; STOSB +;--------------------------------------------------------------bug330a03 + +;--------------------------------------------------------------bug330a03 +; - isp +;* the following lines replaced the lines taken out +ORG3: CALL GET2 + call delim1 + jz ORG3 + cmp al,'/' + jz ORG_EXT + stosb +;--------------------------------------------------------------bug330a03 + +ORG4: CALL GET2 + call delim ; 5/30/86. "device=filename/p..." ;3.30 + jz ORG_EXT ; 5/30/86 ;3.30 + STOSB + CMP AL,' ' + JA ORG4 + CMP AL,10 + JZ ORG1 + + MOV BYTE PTR ES:[DI-1],0 +ORG5: CALL GET2 + STOSB + CMP AL,10 + JNZ ORG5 + JMP ORG1 + +ORG_EXT: ;3.30 + mov byte ptr es:[di], 0 ;put 0 at DI to make it an ASCIIZ ;3.30 + inc DI ; ;3.30 + stosb ;and copy the delimeter char. ;3.30 + jmp short ORG5 ;and continue as usual. ;3.30 + +GET2: + JCXZ NOGET + MOV AL,ES:[SI] + INC SI + DEC CX + return + +GET: JCXZ NOGET + MOV AL,ES:[SI] + INC SI + DEC CX + CALL DELIM + JZ GET + return + + +;--------------------------------------------------------------bug330a03 +; isp - small changes here, new entry point into routine +DELIM: + CMP AL,'/' ; 5/30/86. IBM will assume "/" delim ;3.30 + retz ;3.30 +DELIM1: + CMP AL,' ' + retz + CMP AL,9 + retz + CMP AL,'=' + retz + CMP AL,',' + retz + CMP AL,';' + retz ; 5/23/86 ;3.30 + cmp al, 0 ; 5/23/86 Special case for sysinit!!! ;3.30 + return + +;--------------------------------------------------------------bug330a03 + +NOGET: POP CX + MOV COUNT,DI + XOR SI,SI + MOV CHRPTR,SI + return +; +; NEWLINE RETURNS WITH FIRST CHARACTER OF NEXT LINE +; +NEWLINE:invoke GETCHR ;SKIP NON-CONTROL CHARACTERS + retc + CMP AL,10 ;LOOK FOR LINE FEED + JNZ NEWLINE + invoke GETCHR + return + +MAPCASE: + PUSH CX + PUSH SI + PUSH DS + PUSH ES + POP DS + XOR SI,SI +CONVLOOP: + LODSB + + IF KANJI + CALL TESTKANJ + JZ NORMCONV + INC SI ;Skip next char + DEC CX + JCXZ CONVDONE ;Just ignore 1/2 kanji error +;Fall through, know AL is not in 'a'-'z' range +NORMCONV: + ENDIF + + CMP AL,'a' + JB NOCONV + CMP AL,'z' + JA NOCONV + SUB AL,20H + MOV [SI-1],AL +NOCONV: + LOOP CONVLOOP +CONVDONE: + POP DS + POP SI + POP CX + return + + IF KANJI +TESTKANJ: + CMP AL,81H + JB NOTLEAD + CMP AL,9FH + JBE ISLEAD + CMP AL,0E0H + JB NOTLEAD + CMP AL,0FCH + JBE ISLEAD +NOTLEAD: + PUSH AX + XOR AX,AX ;Set zero + POP AX + return + +ISLEAD: + PUSH AX + XOR AX,AX ;Set zero + INC AX ;Reset zero + POP AX + return + ENDIF + +ASSUME DS:NOTHING + +Yes_Break_Failed: ;dev drv Init failed and aborted. ;3.30 + stc ;3.30 + pop ax ;3.30 + return ;3.30 + +SET_BREAK: +; 8/14/86 For DOS 3.3, this routine is modified to take care of the ;3.30 +;Device driver's initialization error and abort. ;3.30 +;If [break_addr+2] == [memhi] && [break_addr] = 0 then assume ;3.30 +;that the device driver's initialization has an error and wanted to ;3.30 +;abort the device driver. In this case, this routine will set carry ;3.30 +;and return to the caller. ;3.30 +; ;3.30 + PUSH AX + MOV AX,WORD PTR [BREAK_ADDR+2] ;REMOVE THE INIT CODE + cmp ax, [MEMHI] ;3.30 + jne Set_Break_Continue ;if not same, then O.K. ;3.30 + ;3.30 + cmp word ptr [BREAK_ADDR],0 ;3.30 + je Yes_Break_failed ;[Break_addr+2]=[MEMHI] & [Break_addr]=0 ;3.30 + ;3.30 +Set_Break_Continue: ;3.30 + MOV [MEMHI],AX + MOV AX,WORD PTR [BREAK_ADDR] + MOV [MEMLO],AX + POP AX ; NOTE FALL THROUGH + +; +; Round the values in MEMLO and MEMHI to paragraph boundary. +; Perform bounds check. +; +ROUND: + PUSH AX + MOV AX,[MEMLO] + + invoke ParaRound ; para round up + + ADD [MEMHI],AX + MOV [MEMLO],0 + mov ax,memhi ; ax = new memhi + CMP AX,[ALLOCLIM] ; if new memhi >= alloclim, error + JAE MEM_ERR + POP AX + clc ;clear carry ;3.30 + return + +MEM_ERR: + MOV DX,OFFSET BADMEM + PUSH CS + POP DS + CALL PRINT + JMP STALL + +CALLDEV:MOV DS,WORD PTR CS:[ENTRY_POINT+2] + ADD BX,WORD PTR CS:[ENTRY_POINT] ;Do a little relocation + MOV AX,DS:[BX] + PUSH WORD PTR CS:[ENTRY_POINT] + MOV WORD PTR CS:[ENTRY_POINT],AX + MOV BX,OFFSET PACKET + CALL [ENTRY_POINT] + POP WORD PTR CS:[ENTRY_POINT] + return + +BADNUM: + MOV sepchr,0 + XOR AX,AX ; Set Zero flag, and AX = 0 + pop bx ; ;3.30 + stc ; AND carry set + return + +ToDigit: + SUB AL,'0' + JB NotDig + CMP AL,9 + JA NotDig + CLC + return +NotDig: STC + return + +; GetNum parses a decimal number. +; Returns it in AX, sets zero flag if AX = 0 (MAY BE considered an +; error), if number is BAD carry is set, zero is set, AX=0. +GETNUM: push bx ; ;3.30 + XOR BX,BX ; running count is zero +B2: CALL ToDigit ; do we have a digit + JC BadNum ; no, bomb + XCHG AX,BX ; put total in AX + PUSH BX ; save digit + MOV BX,10 ; base of arithmetic + MUL BX ; shift by one decimal di... + POP BX ; get back digit + ADD AL,BL ; get total + ADC AH,0 ; make that 16 bits + JC BADNUM ; too big a number + XCHG AX,BX ; stash total + + invoke GETCHR ;GET NEXT DIGIT + JC B1 ; no more characters + cmp al, ' ' ; 5/23/86 space? ;3.30 + jz B15 ; 5/23/86 then end of digits ;3.30 + cmp al, ',' ; 5/23/86 ',' is a seperator! ;3.30 + jz B15 ; 5/23/86 then end of digits. ;3.30 + cmp al, 9 ; 5/23/86 TAB ;3.30 + jz B15 ; ;3.30 + CMP AL,SepChr ; allow , separators + JZ b15 + cmp al,SWTCHR ; See if another switch follows + JZ b15 + cmp al,10 ; Line-feed? + jz b15 + cmp al,13 ; Carriage return? + jz b15 + OR AL,AL ; end of line separator? + JNZ B2 ; no, try as a valid char... +b15: INC COUNT ; one more character to s... + DEC CHRPTR ; back up over separator +B1: MOV AX,BX ; get proper count + OR AX,AX ; Clears carry, sets Zero accordingly + pop bx ;3.30 + return + +SKIP_DELIM proc near ; ;3.30 +;Skip the delimeters pointed by CHRPTR. AL will contain the first non delimete;3.30r +;character encountered and CHRPTR will point to the next character. ;3.30 +;This rouitne will assume the second "," found as a non delimiter character. So;3.30 +;in case if the string is " , , ", this routine will stop at the second ",". At;3.30 +;this time, Zero flag is set. ;3.30 +;If COUNT is exhausted, then carry will be set. ;3.30 +Skip_delim_char: ;3.30 + call getchr ;3.30 + jc Skip_delim_exit ;3.30 + cmp al, ',' ;the first comma? ;3.30 + je Skip_delim_next ;3.30 + call delim ;check the charater in AL. ;3.30 + jz Skip_delim_char ;3.30 + jmp short Skip_delim_exit ;found a non delim char ;3.30 +Skip_delim_next: ;3.30 + call getchr ;3.30 + jc Skip_delim_exit ;3.30 + cmp al, ',' ;the second comma? ;3.30 + je Skip_delim_exit ;done ;3.30 + call delim ;3.30 + jz Skip_delim_next ;3.30 +Skip_delim_exit: ;3.30 + return ;3.30 +SKIP_DELIM endp ;3.30 + ;3.30 +; 5/26/86 *****************************************************************;3.30 +SetDOSCountryInfo proc near ;3.30 +;Input: ES:DI -> pointer to DOS_COUNTRY_CDPG_INFO ;3.30 +; DS:0 -> buffer. ;3.30 +; SI = 0 ;3.30 +; AX = country id ;3.30 +; DX = code page id. (If 0, then use ccSysCodePage as a default.) ;3.30 +; BX = file handle ;3.30 +; This routine can handle maxium 72 COUNTRY_DATA entries. ;3.30 +;Output: DOS_country_cdpg_info set. ;3.30 +; Carry set if any file read failure or wrong information in the file. ;3.30 +; Carry set and CX = -1 if cannot find the matching COUNTRY_id, CODEPAGE;3.30 +; _id in the file. ;3.30 + ;3.30 + push di ;3.30 + push ax ;3.30 + push dx ;3.30 + ;3.30 + xor cx,cx ;3.30 + xor dx,dx ;3.30 + mov ax, 512 ;read 512 bytes ;3.30 + call ReadInControlBuffer ;Read the file header ;3.30 + jc SetDOSData_fail ;3.30 + push es ;3.30 + push si ;3.30 + push cs ;3.30 + pop es ;3.30 + mov di, offset COUNTRY_FILE_SIGNATURE ;3.30 + mov cx, 8 ;length of the signature ;3.30 + repz cmpsb ;3.30 + pop si ;3.30 + pop es ;3.30 + jnz SetDOSData_fail ;signature mismatch ;3.30 + ;3.30 + add si, 18 ;SI -> county info type ;3.30 + cmp byte ptr ds:[si], 1 ;Only accept type 1 (Currently only 1 h;3.30eader type) + jne SetDOSData_fail ;cannot proceed. error return ;3.30 + inc si ;SI -> file offset ;3.30 + mov dx, word ptr ds:[si] ;Get the INFO file offset. ;3.30 + mov cx, word ptr ds:[si+2] ;3.30 + mov ax, 1024 ;read 1024 bytes. ;3.30 + call ReadInControlBuffer ;Read INFO ;3.30 + jc SetDOSData_fail ;3.30 + mov cx, word ptr ds:[si] ;get the # of country, codepage combina;3.30tion entries + cmp cx, 72 ;cannot handle more than 72 entries. ;3.30 + ja SetDOSData_fail ;3.30 + inc si ;3.30 + inc si ;SI -> entry information packet ;3.30 + pop dx ;restore code page id ;3.30 + pop ax ;restore country id ;3.30 + pop di ;3.30 + ;3.30 +SetDOSCntry_find: ;Search for desired country_id,codepage;3.30_id. + cmp ax, word ptr ds:[si+2] ;compare country_id ;3.30 + jne SetDOSCntry_next ;3.30 + cmp dx, 0 ;No user specified code page ? ;3.30 + je SetDOSCntry_any_codepage;then no need to match code page id. ;3.30 + cmp dx, word ptr ds:[si+4] ;compare code page id ;3.30 + je SetDOSCntry_got_it ;3.30 +SetDOSCntry_next: ;3.30 + add si, word ptr ds:[si] ;next entry ;3.30 + inc si ;3.30 + inc si ;take a word for size of entry itself ;3.30 + loop SetDOSCntry_find ;3.30 + mov cx, -1 ;signals that bad country id entered. ;3.30 +SetDOSCntry_fail: ;3.30 + stc ;3.30 + ret ;3.30 + ;3.30 +SetDOSData_fail: ;3.30 + pop si ;3.30 + pop cx ;3.30 + pop di ;3.30 + jmp short SetDOSCntry_fail ;3.30 + ;3.30 +SetDOSCntry_any_CodePage: ;use the code_page_id of the country_id;3.30 found. + mov dx, word ptr ds:[si+4] ;3.30 +SetDOSCntry_got_it: ;found the matching entry ;3.30 + mov cs:CntryCodePage_Id, dx ;save code page ID for this country. ;3.30 + mov dx, word ptr ds:[si+10] ;get the file offset of country data ;3.30 + mov cx, word ptr ds:[si+12] ;3.30 + mov ax, 512 ;read 512 bytes ;3.30 + call ReadInControlBuffer ;3.30 + jc SetDOSCntry_fail ;3.30 + mov cx, word ptr ds:[si] ;get the number of entries to handle. ;3.30 + inc si ;3.30 + inc si ;SI -> first entry ;3.30 + ;3.30 +SetDOSCntry_data: ;3.30 + push di ;ES:DI -> DOS_COUNTRY_CDPG_INFO ;3.30 + push cx ;save # of entry left ;3.30 + push si ;si -> current entry in Control buffer ;3.30 + ;3.30 + mov al, byte ptr ds:[si+2] ;get data entry id ;3.30 + call GetCountryDestination ;get the address of destination in ES:D;3.30I + jc SetDOSCntry_data_next ;No matching data entry id in DOS ;3.30 + ;3.30 + ;3.30 + mov dx, word ptr ds:[si+4] ;get offset of data ;3.30 + mov cx, word ptr ds:[si+6] ;3.30 + mov ax, 4200h ;3.30 + stc ;3.30 + int 21h ;move pointer ;3.30 + jc SetDOSData_fail ;3.30 + mov dx, 512 ;start of data buffer ;3.30 + mov cx, word ptr es:[di] ;length of the corresponding data in DO;3.30S. + add cx, 10 ;Signature + A word for the length itse;3.30lf + mov ah, 3fh ;3.30 + stc ;3.30 + int 21h ;read the country.sys data ;3.30 + jc SetDOSData_fail ;read failure ;3.30 + cmp ax, cx ;3.30 + jne SetDOSData_fail ;3.30 + ;3.30 + mov al, byte ptr ds:[si+2] ;save Data id for future use. ;3.30 + mov si, (512+8) ;SI-> data buffer + id tag field ;3.30 + mov cx, word ptr ds:[si] ;get the length of the file ;3.30 + inc cx ;Take care of a word for lenght of tab ;3.30 + inc cx ;itself. ;3.30 + cmp cx, (2048 - 512 - 8) ;Fit into the buffer? ;3.30 + ja SetDOSData_fail ;3.30 + cmp al, SetCountryInfo ;is the data for SetCountryInfo table? ;3.30 + jne SetDOSCntry_Mov ;no, don't worry ;3.30 + push word ptr es:[di+24] ;Cannot destroy ccMono_ptr address. Sav;3.30e them. + push word ptr es:[di+26] ;3.30 + push di ;save DI ;3.30 + ;3.30 + push ax ;3.30 + mov ax,cs:CntryCodePage_Id ;Do not use the Code Page info in Count;3.30ry_Info + mov ds:[si+4], ax ;Use the saved one for this !!!! ;3.30 + pop ax ;3.30 + ;3.30 +SetDOSCntry_Mov: ;3.30 + rep movsb ;copy the table into DOS ;3.30 + cmp al, SetCountryInfo ;was the ccMono_ptr saved? ;3.30 + jne SetDOSCntry_data_next ;3.30 + pop di ;restore DI ;3.30 + pop word ptr es:[di+26] ;restore ccMono_ptr in DOS. ;3.30 + pop word ptr es:[di+24] ;3.30 + ;3.30 +SetDOSCntry_data_next: ;3.30 + pop si ;restore control buffer pointer ;3.30 + pop cx ;restore # of entries left ;3.30 + pop di ;restore pointer to DSO_COUNTRY_CDPG ;3.30 + add si, word ptr ds:[si] ;try to get the next entry ;3.30 + inc si ;3.30 + inc si ;take a word of entry length itself ;3.30 + loop SetDOSCntry_data ;3.30 + ret ;3.30 +SetDOSCountryInfo endp ;3.30 +; ;3.30 + ;3.30 +GetCountryDestination proc near ;3.30 +;Get the destination address in the DOS country info table. ;3.30 +;Input: AL - Data ID ;3.30 +; ES:DI -> DOS_COUNTRY_CDPG_INFO ;3.30 +;On return: ;3.30 +; ES:DI -> Destination address of the matching data id ;3.30 +; carry set if no matching data id found in DOS. ;3.30 + ;3.30 + push cx ;3.30 + add di, ccNumber_of_entries ;skip the reserved area, syscodepage et;3.30c. + mov cx, word ptr es:[di] ;get the number of entries ;3.30 + inc di ;3.30 + inc di ;SI -> the first start entry id ;3.30 +GetCntryDest: ;3.30 + cmp byte ptr es:[di], al ;3.30 + je GetCntryDest_OK ;3.30 + cmp byte ptr es:[di], SetCountryInfo ;was it SetCountryInfo entry? ;3.30 + je GetCntryDest_1 ;3.30 + add di, 5 ;next data id ;3.30 + jmp short GetCntryDest_loop ;3.30 +GetCntryDest_1: ;3.30 + add di, NEW_COUNTRY_SIZE + 3 ;next data id ;3.30 +GetCntryDest_loop: ;3.30 + loop GetCntryDest ;3.30 + stc ;3.30 + jmp short GetCntryDest_exit ;3.30 +GetCntryDest_OK: ;3.30 + cmp al, SetCountryInfo ;select country info? ;3.30 + jne GetCntryDest_OK1 ;3.30 + inc di ;now DI -> ccCountryInfoLen ;3.30 + jmp short GetCntryDest_exit ;3.30 +GetCntryDest_OK1: ;3.30 + les di, dword ptr es:[di+1] ;get the destination in ES:DI ;3.30 +GetCntryDest_Exit: ;3.30 + pop cx ;3.30 + ret ;3.30 +GetCountryDestination endp ;3.30 + ;3.30 +; ;3.30 +ReadInControlBuffer proc near ;3.30 +;Move file pointer to CX:DX ;3.30 +;Read AX bytes into the control buffer. (Should be less than 2 Kb) ;3.30 +;SI will be set to 0 hence DS:SI points to the control buffer. ;3.30 +;Entry: CX,DX offset from the start of the file where the read/write pointer ;3.30 +; be moved. ;3.30 +; AX - # of bytes to read ;3.30 +; BX - file handle ;3.30 +; DS - buffer seg. ;3.30 +;Return: The control data information is read into DS:0 - DS:0200. ;3.30 +; CX,DX value destroyed. ;3.30 +; Carry set if error in Reading file. ;3.30 +; ;3.30 + push ax ;# of bytes to read ;3.30 + mov ax, 4200h ;3.30 + stc ;3.30 + int 21h ;move pointer ;3.30 + pop cx ;# of bytes to read ;3.30 + jc RICB_exit ;3.30 + xor dx,dx ;ds:dx -> control buffer ;3.30 + xor si,si ;3.30 + mov ah,3fh ;read into the buffer ;3.30 + stc ;3.30 + int 21h ;should be less than 1024 bytes. ;3.30 +RICB_exit: ;3.30 + ret ;3.30 +ReadInControlBuffer endp ;3.30 + ;3.30 +; ;3.30 +SET_COUNTRY_PATH proc near ;3.30 +;In: DS - SYSINITSEG, ES - CONFBOT, SI -> start of the asciiz path string ;3.30 +; DOSINFO_EXT, CNTRY_DRV, CNTRY_ROOT, CNTRY_PATH ;3.30 +; Assumes current directory is the ROOT directory. ;3.30 +;Out: DS:DI -> full path (CNTRY_DRV). ;3.30 +; Set the CNTRY_DRV string from the COUNTRY=,,path command. ;3.30 +; DS, ES, SI value saved. ;3.30 + ;3.30 + push si ;3.30 + push ds ;switch ds, es ;3.30 + push es ;3.30 + pop ds ;3.30 + pop es ;now DS -> CONFBOT, ES -> SYSINITSEG ;3.30 + ;3.30 + call chk_drive_letter ;current DS:[SI] is a drive letter? ;3.30 + jc SCP_Default_drv ;no, use current default drive. ;3.30 + mov al, byte ptr DS:[SI] ;3.30 + inc si ;3.30 + inc si ;SI -> next char after ":" ;3.30 + jmp short SCP_SetDrv ;3.30 +SCP_Default_drv: ;3.30 + mov ah, 19h ;3.30 + int 21h ;3.30 + add al, "A" ;convert it to a character. ;3.30 +SCP_SetDrv: ;3.30 + mov cs:CNTRY_DRV, al ;set the drive letter. ;3.30 + mov di, offset CNTRY_PATH ;3.30 + mov al, byte ptr DS:[SI] ;3.30 + cmp al, "\" ;3.30 + je SCP_Root_Dir ;3.30 + cmp al, cs:SWTCHR ;let's accept "/" as an directory delim;3.30 + je SCP_Root_Dir ;3.30 + jmp short SCP_Path ;3.30 +SCP_Root_Dir: ;3.30 + dec di ;DI -> CNTRY_ROOT ;3.30 +SCP_Path: ;3.30 + call MOVE_ASCIIZ ;copy it ;3.30 + mov di, offset CNTRY_DRV ;3.30 +SCPath_Exit: ;3.30 + push ds ;switch ds, es ;3.30 + push es ;3.30 + pop ds ;3.30 + pop es ;DS, ES value restored ;3.30 + pop si ;3.30 + RET ;3.30 +SET_COUNTRY_PATH endp ;3.30 + ;3.30 +; ;3.30 +CHK_DRIVE_LETTER proc near ;3.30 +;Check if DS:[SI] is a drive letter followed by ":". ;3.30 +;Assume that every alpha charater is already converted to UPPER CASE. ;3.30 +;Carry set if not. ;3.30 +; ;3.30 + push ax ;3.30 + cmp byte ptr ds:[si], "A" ;3.30 + jb CDLetter_NO ;3.30 + cmp byte ptr ds:[si], "Z" ;3.30 + ja CDLetter_NO ;3.30 + cmp byte ptr ds:[si+1], ":" ;3.30 + jne CDLetter_NO ;3.30 + jmp short CDLetter_exit ;3.30 +CDLetter_NO: ;3.30 + stc ;3.30 +CDLetter_exit: ;3.30 + pop ax ;3.30 + ret ;3.30 +CHK_DRIVE_LETTER endp ;3.30 + ;3.30 +; ;3.30 +MOVE_ASCIIZ proc near ;3.30 +;In: DS:SI -> source ES:DI -> target ;3.30 +;Out: copy the string until 0. ;3.30 +;Assumes there exists a 0. ;3.30 +MASCIIZ_loop: ;3.30 + movsb ;3.30 + cmp byte ptr DS:[SI-1], 0 ;Was it 0? ;3.30 + jne MASCIIZ_loop ;3.30 + ret ;3.30 +MOVE_ASCIIZ endp ;3.30 + +; +; DS:DX POINTS TO STRING TO OUTPUT (ASCIZ) +; +; PRINTS +; +; +; +BADFIL: + PUSH CS + POP ES + MOV SI,DX +BADLOAD: + MOV DX,OFFSET BADLD_PRE ;WANT TO PRINT CONFIG ERROR + MOV BX,OFFSET BADLD_POST +PRNERR: + PUSH CS + POP DS + MOV AH,STD_CON_STRING_OUTPUT + INT 21H +PRN1: MOV DL,ES:[SI] + OR DL,DL + JZ PRN2 + MOV AH,STD_CON_OUTPUT + INT 21H + INC SI + JMP PRN1 +PRN2: MOV DX,BX +PRINT: MOV AH,STD_CON_STRING_OUTPUT + INT 21H + return + + + IF NOEXEC +; +; LOAD NON EXE FILE CALLED [DS:DX] AT MEMORY LOCATION ES:BX +; +LDFIL: + PUSH AX + PUSH BX + PUSH CX + PUSH DX + PUSH SI + PUSH DS + PUSH BX + XOR AX,AX ;OPEN THE FILE + MOV AH,OPEN + STC ;IN CASE OF INT 24 + INT 21H + POP DX ;Clean stack in case jump + JC LDRET + PUSH DX + MOV BX,AX ;Handle in BX + XOR CX,CX + XOR DX,DX + MOV AX,(LSEEK SHL 8) OR 2 + STC ;IN CASE OF INT 24 + INT 21H ; Get file size in DX:AX + JC LDCLSP + OR DX,DX + JNZ LDERRP ; File >64K + POP DX + PUSH DX + MOV CX,ES ; CX:DX is xaddr + ADD DX,AX ; Add file size to Xaddr + JNC DOSIZE + ADD CX,1000H ; ripple carry +DOSIZE: + mov ax,dx + call ParaRound + mov dx,ax + + ADD CX,DX + CMP CX,[ALLOCLIM] + JB OKLD + JMP MEM_ERR + +OKLD: + XOR CX,CX + XOR DX,DX + MOV AX,LSEEK SHL 8 ;Reset pointer to beginning of file + STC ;IN CASE OF INT 24 + INT 21H + JC LDCLSP + POP DX + PUSH ES ;READ THE FILE IN + POP DS ;Trans addr is DS:DX + MOV CX,0FF00H ; .COM files arn't any bigger than + ; 64k-100H + MOV AH,READ + STC ;IN CASE OF INT 24 + INT 21H + JC LDCLS + MOV SI,DX ;CHECK FOR EXE FILE + CMP WORD PTR [SI],"ZM" + CLC ; Assume OK + JNZ LDCLS ; Only know how to do .COM files + STC + JMP SHORT LDCLS + +LDERRP: + STC +LDCLSP: + POP DX ;Clean stack +LDCLS: + PUSHF + MOV AH,CLOSE ;CLOSE THE FILE + STC + INT 21H + POPF + +LDRET: POP DS + POP SI + POP DX + POP CX + POP BX + POP AX + return + ENDIF + +; +; OPEN DEVICE POINTED TO BY DX, AL HAS ACCESS CODE +; IF UNABLE TO OPEN DO A DEVICE OPEN NULL DEVICE INSTEAD +; +OPEN_DEV: + CALL OPEN_FILE + JNC OPEN_DEV3 +OPEN_DEV1: + MOV DX,OFFSET NULDEV + CALL OPEN_FILE + return + +OPEN_DEV3: + MOV BX,AX ; Handle from open to BX + XOR AX,AX ; GET DEVICE INFO + MOV AH,IOCTL + INT 21H + TEST DL,10000000B + retnz + MOV AH,CLOSE + INT 21H + JMP OPEN_DEV1 + +OPEN_FILE: + MOV AH,OPEN + STC + INT 21H + return + +INT24: ADD SP,6 ;RESTORE MACHINE STATE + POP AX + POP BX + POP CX + POP DX + POP SI + POP DI + POP BP + POP DS + POP ES + PUSH AX + MOV AH,GET_DEFAULT_DRIVE ;INITIALIZE DOS + INT 21H + POP AX + IRET ;BACK TO USER + + IF ALTVECT +BOOTMES DB 13,10,"MS-DOS version " + DB MAJOR_VERSION + "0" + DB "." + DB (MINOR_VERSION / 10) + "0" + DB (MINOR_VERSION MOD 10) + "0" + DB 13,10 + DB "Copyright 1981,82 Microsoft Corp.",13,10,"$" + ENDIF + +NULDEV DB "NUL",0 +CONDEV DB "CON",0 +AUXDEV DB "AUX",0 +PRNDEV DB "PRN",0 + +CONFIG DB "\CONFIG.SYS",0 + +CNTRY_DRV DB "A:" ;3.30 +CNTRY_ROOT DB "\" ;3.30 +CNTRY_PATH DB "COUNTRY.SYS",0 ;3.30 + DB 52 DUP (0) ;3.30 + ;3.30 +COUNTRY_FILE_SIGNATURE db 0FFh,'COUNTRY' ;3.30 + ;3.30 +CntryCodePage_Id DW ? ;3.30 + +COMMND DB "\COMMAND.COM",0 + DB 20 dup (0) ;3.30 + +COMTAB LABEL BYTE +;;;; DB 8,"AVAILDEV",'A' ; NO LONGER SUPPORTED + DB 7,"BUFFERS", 'B' + DB 5,"BREAK", 'C' + DB 6,"DEVICE", 'D' + DB 5,"FILES", 'F' + DB 4,"FCBS", 'X' + DB 9,"LASTDRIVE",'L' + DB 8,"DRIVPARM", 'P' ; RS for DOS 3.2 + IF STACKSW ;3.30 + DB 6,"STACKS", 'K' ; BAS for DOS 3.2 ;3.30 + ENDIF ;3.30 + DB 7,"COUNTRY", 'Q' + DB 5,"SHELL", 'S' +;;;; DB 8,"SWITCHAR",'W' ; NO LONGER SUPPORTED + DB 0 + +public DeviceParameters +DeviceParameters a_DeviceParameters <0,DEV_3INCH720KB,0,80> + +hlim dw 2 +slim dw 9 + +public drive +drive db ? + +public switches +Switches dw ? + +; +; The following are the recommended BPBs for the media that we know of so +; far. + +; 48 tpi diskettes + +BPB48T DW 512 + DB 2 + DW 1 + DB 2 + DW 112 + DW 2*9*40 + DB 0FDH + DW 2 + DW 9 + DW 2 + Dd 0 ;hidden sectors - sp + Dd 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved - sp + +; 96tpi diskettes + +BPB96T DW 512 + DB 1 + DW 1 + DB 2 + DW 224 + DW 2*15*80 + DB 0f9H + DW 7 + DW 15 + DW 2 + Dd 0 ;hidden sectors - sp + Dd 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved - sp + +; 3 1/2 inch diskette BPB + +BPB35 DW 512 + DB 2 + DW 1 ; Double sided with 9 sec/trk + DB 2 + DW 70h + DW 2*9*80 + DB 0f9H + DW 3 + DW 9 + DW 2 + Dd 0 ;hidden sectors - sp + Dd 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved - sp + + +BPBTable dw BPB48T ; 48tpi drives + dw BPB96T ; 96tpi drives + dw BPB35 ; 3.5" drives +; The following are not supported, so default to 3.5" media layout + dw BPB35 ; Not used - 8" drives + dw BPB35 ; Not Used - 8" drives + dw BPB35 ; Not Used - hard files + dw BPB35 ; Not Used - tape drives + dw BPB35 ; Not Used - Other + +switchlist db 7,"FHSTDCN" ; Preserve the positions of N and C. + +; The following depend on the positions of the various letters in SwitchList + +flagdrive equ 0004H +flagcyln equ 0008H +flagseclim equ 0010H +flagheads equ 0020H +flagff equ 0040H + +SWTCHR EQU "/" ; switch follows this character + +SYSINITSEG ENDS + END diff --git a/UPDSRC/CMD/PRINT/PRINT_R.ASM b/UPDSRC/CMD/PRINT/PRINT_R.ASM new file mode 100644 index 0000000..91beec1 --- /dev/null +++ b/UPDSRC/CMD/PRINT/PRINT_R.ASM @@ -0,0 +1,2192 @@ +; SCCSID = @(#)print_r.asm 4.7 85/09/13 + INCLUDE pridefs.inc + + +BREAK + +; +; MSDOS V3.00 PRINT +; +; Resident Portion +; + +Code Segment public para + extrn TransRet:WORD,TransSize:WORD +Code EndS + + + +BREAK + +CodeR Segment public para + + extrn ERRMES:BYTE, ERRMEST:BYTE, BELMES:BYTE, ErrMesT2:BYTE + extrn CanMes:BYTE, CanFilNAm:BYTE, AllCan:BYTE, ERR0:BYTE + extrn ERR1:BYTE, ERR2:BYTE, ERR3:BYTE, ERR4:BYTE, ERR5:BYTE + extrn ERR6:BYTE, ERR7:BYTE, ERR8:BYTE, ERR9:BYTE, ERR10:BYTE + extrn ERR11:BYTE, ERR12:BYTE, FATMES:BYTE, BADDRVM:BYTE, + extrn BADMES:BYTE, badmeslen:WORD, GOODMES:BYTE, goodmeslen:WORD + +if hardint + public SliceCnt, BusyTick, MaxTick, TimeSlice +endif + + public EndRes, BlkSiz, QueueLen, PChar + public ListName, FileQueue, EndQueue, Buffer + public EndPtr, NxtChr, MoveTrans + +assume CS:CodeR + +public PRNR001S,PRNR001E +PRNR001S: + db "*** Microsoft/V310 ***" + + DB (362 - 80h) + 310 DUP (?) ; (362 - 80h) is IBM's New + ; recommended Stack Size - + ; Old recommended Stack Size + ; == New stack growth +ISTACK LABEL WORD ;Stack starts here and grows down the + +;Resident data + +; +; Due to flagrant bogosity by file servers, BUSY is *ALWAYS* relevant. +; +BUSY DB 0 ;Internal ME flag + + IF HARDINT +; +; WARNING!!! The *&^%(*&^ 286 chip hangs if you access a word that will wrap +; at the segment boundary. Make the initial INDOS point somewhere reasonable. +; +INDOS DD TimeSlice ;DOS buisy flag +NEXTINT DD ? ;Chain for int +NEXT_REBOOT DD ? ;Chain for ROM bootstrap + +fFake db 0 ; TRUE => do not diddle I/O ports +SOFINT DB 0 ;Internal ME flag +TICKCNT DB 0 ;Tick counter +TICKSUB DB 0 ;Tick miss counter +SLICECNT DB 8 ;Time slice counter, init to same val + ; as TIMESLICE + +TIMESLICE DB 8 ;The PRINT scheduling time slice. PRINT + ; lets this many "ticks" go by before + ; using a time slice to pump out characters. + ; Setting this to 3 for instance means PRINT + ; Will skip 3 slices, then take the fourth. + ; Thus using up 1/4 of the CPU. Setting it + ; to one gives PRINT 1/2 of the CPU. + ; The above examples assume MAXTICK is + ; 1. The actual PRINT CPU percentage is + ; (MAXTICK/(1+TIMESLICE))*100 + +MAXTICK DB 2 ;The PRINT in timeslice. PRINT will pump + ; out characters for this many clock ticks + ; and then exit. The selection of a value + ; for this is dependent on the timer rate. + +BUSYTICK DB 1 ;If PRINT sits in a wait loop waiting for + ; output device to come ready for this + ; many ticks, it gives up its time slice. + ; Setting it greater than or equal to + ; MAXTICK causes it to be ignored. + +;User gets TIMESLICE ticks and then PRINT takes MAXTICK ticks unless BUSYTICK +; ticks go by without getting a character out. + ENDIF + +QueueLen db DefQueueLen ; Actual length of print queue + even +EndQueue dw ? ; pointer to end of print queue +QueueTail dw offset CodeR:FileQueue ; pointer to next free entry + ; in the print queue +buffer dw ? ; pointer to data buffer + +I24_ERR DW ? ;Save location for INT 24H error code +Ctrlc DB ? ; saved ^C trapping state +SPNEXT DD ? ;Chain location for INT 28 +COMNEXT DD ? ;Chain location for INT 2F +SSsave DW ? ;Stack save area for INT 24 +SPsave DW ? +HERRINT DD ? ;Place to save Hard error interrupt +LISTDEV DD ? ;Pointer to Device +COLPOS DB 0 ;Column position for TAB processing +CURRFIL DB 0 +NXTCHR DW ? +CURRHAND DW -1 +PrinterNum DW -1 ; index for printer +QueueLock db 0 ; queue lock, 0=unlocked + + +PChar db ? ; path character +AmbCan db ? ; = 1 ambigous cancel +CanFlg db ? ; = 1 Current was already canceled +ACanOcrd db ? ; = 1 a file was found during an + ; ambigous cancel + +;--- Warnning: this is a FCB!! +ACBuf db ? +ACName db 8 dup(?) +ACExt db 3 dup(?) + db 4 dup(?) ; how big is an unopened fcb??? + + +CONTXTFLAG DB 0 ;0 means his context, NZ means me +HISPDB DW ? +PABORT DB 0 ;Abort flag +BLKSIZ DW 512 ;Size of the PRINT I/O block in bytes +ENDPTR DW ? + +COMDISP LABEL WORD ; Communications dispatch table + DW OFFSET CodeR:INST_REQ + DW OFFSET CodeR:ADDFIL + DW OFFSET CodeR:CANFIL + DW offset CodeR:CanAll + DW OFFSET CodeR:QSTAT + DW offset CodeR:EndStat + DW offset CodeR:QSTATDEV + +;Resident messages + +MESBAS DW OFFSET CodeR:ERR0 + DW OFFSET CodeR:ERR1 + DW OFFSET CodeR:ERR2 + DW OFFSET CodeR:ERR3 + DW OFFSET CodeR:ERR4 + DW OFFSET CodeR:ERR5 + DW OFFSET CodeR:ERR6 + DW OFFSET CodeR:ERR7 + DW OFFSET CodeR:ERR8 + DW OFFSET CodeR:ERR9 + DW OFFSET CodeR:ERR10 + DW OFFSET CodeR:ERR11 + DW OFFSET CodeR:ERR12 +ENDRES DW ? ; filled in at initialization time +PRNR001E: + +CodeR EndS + + + +BREAK + +CodeR Segment public para + +Break + +TestSetServer: +IF IBM + CLC + PUSH AX + MOV AX,8700h ; Can I run? + INT 2Ah + POP AX +ENDIF + ret + +LeaveServer: +IF IBM + PUSH AX + MOV AX,8701h + INT 2Ah + POP AX +ENDIF + ret + +;Interrupt routines +ASSUME CS:CodeR,DS:NOTHING,ES:NOTHING,SS:NOTHING +; +; PRINT is stimulated by a hardware interrupt. +; +; +; The Server may also stimulate us during timer ticks (if we handled the +; ticks ourselves, it would be disasterous. Therefore, we have a substitute +; entry here that simulates the timer stuff but does NOT muck with the ports. +; + IF HARDINT +FakeINT1C: + MOV fFake,-1 + JMP SHORT InnerHardInt + +HDSPINT: ;Hardware interrupt entry point + mov fFake,0 +InnerHardInt: + CALL TestSetServer + JNC TickTime + jmp ChainInt +TickTime: + INC [TICKCNT] ;Tick + INC [TICKSUB] ;Tick + CMP [SLICECNT],0 + JZ TIMENOW + DEC [SLICECNT] ;Count down + JMP SHORT HardIntDone ;Not time yet +TIMENOW: + CMP BUSY,0 ;See if interrupting ourself + JNZ HardIntDone + + IF IBM + push ax ; check for nested interrupts + mov al,00001011b ; select ISR in 8259 + out 20H,al + JMP x +x: + in al,20H ; get ISR register + and al,0FEH ; mask timer int + pop ax + jnz HardIntDone ; there was another int in service... + ENDIF + + PUSH DS + PUSH SI + LDS SI,[INDOS] ;Check for making DOS calls +; +; WARNING!!! Due to INT 24 clearing the INDOS flag, we must test both INDOS +; and ERRORMODE at once! These must be contiguous in MSDATA. +; + CMP WORD PTR [SI-1],0 + POP SI + POP DS + JNZ HardIntDone ;DOS is Busy + INC [BUSY] ;Exclude furthur interrupts + MOV [TICKCNT],0 ;Reset tick counter + MOV [TICKSUB],0 ;Reset tick counter + STI ;Keep things rolling + + IF AINT + TEST fFake,-1 + JNZ NoAck + PUSH AX + MOV AL,EOI ;Acknowledge interrupt + OUT AKPORT,AL + POP AX +NoAck: + ENDIF + + CALL DOINT + CLI + PUSH AX + MOV AL,[TIMESLICE] + MOV [SLICECNT],AL ;Either soft or hard int resets time slice + POP AX + DEC Busy ;Done, let others in +HardIntDone: + Call LeaveServer +CHAININT: + TEST fFake,-1 + JNZ DoIRET + JMP [NEXTINT] ;Chain to next clock routine +DoIRET: + IRET + ENDIF + + +; +; PRINT is stimulated by a spooler idle interrupt +; +SPINT: ;INT 28H entry point + CALL TestSetServer + JC NxtSp + + IF HARDINT + CMP [BUSY],0 + JNZ SpIntDone + INC [BUSY] ;Exclude hardware interrupt + INC [SOFINT] ;Indicate a software int in progress + ENDIF + + STI ;Hardware interrupts ok on INT 28H entry + CALL DOINT + + IF HARDINT + CLI + MOV [SOFINT],0 ;Indicate INT done + PUSH AX + MOV AL,[TIMESLICE] + MOV [SLICECNT],AL ;Either soft or hard int resets time slice + POP AX + DEC Busy + ENDIF +SpIntDone: + call LeaveServer + +NXTSP: JMP [SPNEXT] ;Chain to next INT 28 + +; +; Since we may be entering at arbitrary times, we need to get/set the extended +; error as we may end up blowing it away. We do not do this on spooler ints. +; + +public PRNR002S, PRNR002E +PRNR002S: + +SaveState DPL <> ; empty DPL + +PRNR002E: + +public enterprint +EnterPRINT: + IF HardInt + TEST SofInt,-1 + JNZ EnterDone + ENDIF + MOV AH,GetExtendedError + CALL DO_21 + MOV SaveState.DPL_AX,AX + MOV SaveState.DPL_BX,BX + MOV SaveState.DPL_CX,CX + MOV SaveState.DPL_DX,DX + MOV SaveState.DPL_SI,SI + MOV SaveState.DPL_DI,DI + MOV SaveState.DPL_DS,DS + MOV SaveState.DPL_ES,ES +EnterDone: + RET + +public leaveprint +LeavePRINT: + IF HardInt + TEST SofInt,-1 + JNZ LeaveDone + ENDIF + MOV AX,(ServerCall SHL 8) + 10 + PUSH CS + POP DS + MOV DX,OFFSET CodeR:SaveState + CALL Do_21 +LeaveDone: + RET + +public doint +DOINT: +ASSUME CS:CodeR,DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [CURRFIL],0 + JNZ GOAHEAD +SPRET: + ret ;Nothing to do + +GOAHEAD: + cmp [QueueLock],1 + je spret ; queue locked, do nothing... + PUSH AX ;Need a working register + MOV [SSsave],SS + MOV [SPsave],SP + MOV AX,CS + CLI +;Go to internal stack to prevent INT 24 overflowing system stack + MOV SS,AX + MOV SP,OFFSET CodeR:ISTACK + STI + PUSH ES + PUSH DS + PUSH BP + PUSH BX + PUSH CX + PUSH DX + PUSH SI + PUSH DI + PUSH CS + POP DS +ASSUME DS:CodeR + + Call EnterPRINT + + MOV BX,[NXTCHR] + CMP BX,[ENDPTR] + JB PLOOP + JMP READBUFF ;Buffer empty + +DONEJMPJP: + POPF +DONEJMPJ: + JMP DONEJMP + +FILEOFJ: +ASSUME DS:CodeR + JMP FILEOF + +PLOOP: + IF HARDINT + MOV BX,[NXTCHR] + CMP BX,[ENDPTR] + JAE DONEJMPJ ;Buffer has become empty + CMP [SOFINT],0 + JNZ STATCHK + PUSH AX + MOV AL,[MAXTICK] + CMP [TICKCNT],AL ;Check our time slice + POP AX + JAE DONEJMPJ +STATCHK: + ENDIF + + CALL PSTAT + PUSHF + CMP [CURRFIL],0 + JZ DONEJMPJP ;File got cancelled by error + POPF + + IF HARDINT + JZ DOCHAR ;Printer ready + CMP [SOFINT],0 + ENDIF + + JNZ DONEJMP ;If soft int give up + + IF HARDINT + PUSH AX + MOV AL,[BUSYTICK] + CMP [TICKSUB],AL ;Check our busy timeout + POP AX + JAE DONEJMP + JMP PLOOP + ENDIF + +DOCHAR: + MOV AL,BYTE PTR [BX] + CMP AL,1AH ;^Z? + JZ FILEOFJ ;CPM EOF + CMP AL,0DH ;CR? + JNZ NOTCR + MOV [COLPOS],0 +NOTCR: + CMP AL,9 ;TAB? + JNZ NOTABDO + MOV CL,[COLPOS] ;expand tab to # spaces + OR CL,0F8H + NEG CL + XOR CH,CH + JCXZ TABDONE ;CX contains # spaces to print +TABLP: + MOV AL," " + INC [COLPOS] + PUSH CX + CALL POUT + POP CX + DEC CX ;G + JZ TABDONE ;G We're done - get next char + JMP PLOOP ;G Keep processing tab + +;G LOOP TABLP +;G JMP TABDONE + +NOTABDO: + CMP AL,8 ;Back space? + JNZ NOTBACK + DEC [COLPOS] +NOTBACK: + CMP AL,20H ;Non Printing char? + JB NOCHAR + INC [COLPOS] ;Printing char +NOCHAR: + CALL POUT ;Print it +TABDONE: + INC [NXTCHR] ;Next char + + IF HARDINT + MOV [TICKSUB],0 ;Got a character out, Reset counter + CMP [SOFINT],0 ;Soft int does one char at a time + JNZ DONEJMP + JMP PLOOP + ENDIF + +DONEJMP: + CALL CONTEXT_BACK + Call LeavePRINT + + POP DI + POP SI + POP DX + POP CX + POP BX + POP BP + POP DS + POP ES +ASSUME DS:NOTHING,ES:NOTHING + CLI + MOV SS,[SSsave] ;Restore Entry Stack + MOV SP,[SPsave] + STI + POP AX + RET + +CONTEXT_BACK: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [CONTXTFLAG],0 + JZ CONTOK + SaveReg + MOV BX,[HISPDB] + MOV AH,SET_CURRENT_PDB + call do_21 + RestoreReg + MOV [CONTXTFLAG],0 +CONTOK: + RET + +CONTEXT_SWITCH: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [CONTXTFLAG],0 + JNZ RET45 + SaveReg + MOV AH,GET_CURRENT_PDB + call do_21 + MOV [HISPDB],BX + MOV BX,CS + sub bx,10h ; The 2.5 print is an exe program + MOV AH,SET_CURRENT_PDB + call do_21 + RestoreReg + MOV [CONTXTFLAG],1 +RET45: RET + + +;--- Refill the print buffer --- +READBUFF: +ASSUME DS:CodeR,ES:NOTHING,SS:NOTHING + + call Set24 ; switch Int24 vector + MOV [PABORT],0 ;No abort + MOV BX,[CURRHAND] + MOV CX,[BLKSIZ] + MOV DX,[BUFFER] + MOV AH,READ + call My21 + PUSHF + call Res24 ; reset Int 24 vector + CMP [PABORT],0 + JZ NOHERR + POP AX ;Flags from read + jmp FilClose ;Barf on this file, got INT 24 + + +NOHERR: + POPF + JC FILEOF + CMP AX,0 + JZ FILEOF ;Read EOF? + MOV BX,[BUFFER] ;Buffer full + MOV DI,BX + ADD DI,AX + MOV [NXTCHR],BX + MOV CX,[BLKSIZ] + SUB CX,AX + JCXZ DONEJ ; Buffer is completely full + PUSH CS + POP ES + MOV AL,1AH + cld + REP STOSB ; ^Z pad the buffer +DONEJ: + JMP DONEJMP + +FILEOF: + MOV AL,0CH ;Form feed + CALL POUT + +;--- Close file +; note: we came here from an i24 then PAbort is already = 1 +FilClose: + call Set24 + mov pAbort,-1 + MOV BX,[CURRHAND] + MOV AH,CLOSE + call My21 + call Res24 + MOV [CURRFIL],0 ; No file + MOV [CURRHAND],-1 ; Invalid handle + MOV AX,[ENDPTR] + MOV [NXTCHR],AX ; Buffer empty + +;--- Send close on output device + call Close_Dev + +;--- compact the print queue +CompQAgn: + call CompQ + +;--- Check if there are any more files to print + mov si,offset CodeR:FileQueue + cmp byte ptr [si],0 ; no more left if name starts with nul + je NoFilesLeft + call Set24 + MOV [PABORT],0 ;No abort + mov dx,si ; DS:DX points to file name + mov ax,(open shl 8) + call My21 ; try opening new file + pushf + call Res24 + cmp [PAbort],0 + je NoI24a + popf + jmp short CompQAgn ; try next file + +NoI24a: + popf + jnc GotNewFile + call PrtOpErr + jmp short CompQAgn + +GotNewFile: ; buffer was already marked as empty + mov [CurrHand],ax + mov [CurrFil],1 + +;--- Send Open on output device + call Open_Dev + +NoFilesLeft: + JMP DONEJMP + + +;--- Print open error --- +; preserves DS + +PrtOpErr: +assume ds:CodeR,es:Nothing + +; This stuff constitutes a "file" so it is bracketed by an open/close +; on the output device. + +;--- Send Open on output device + call Open_Dev + + push cs + pop es +assume es:CodeR + mov si,offset CodeR:ErrMes + call ListMes + mov si,offset CodeR:ErrMesT2 + call ListMes + mov si,offset CodeR:FileQueue + call ListMes2 + mov si,offset CodeR:BelMes + call ListMes + +;--- Send close on output device + call Close_Dev + + ret + + +;--- Compact File Queue --- +; modifies: AX,CX,SI,DI,ES + +CompQ: +assume ds:CodeR,es:nothing,ss:nothing + push cs + pop es +assume es:CodeR + mov di,offset CodeR:FileQueue ; ES:DI points to top of queue + mov si,(offset CodeR:FileQueue + MaxFileLen) ; DS:SI points to next entry + mov cx,[EndQueue] + sub cx,si ; length in bytes of the queue + cld + rep movsb ; compact the queue + mov ax,[QueueTail] ; normalize tail pointer as we + sub ax,MaxFileLen ; know have a new "next empty slot" + mov [QueueTail],ax + mov si,ax + mov byte ptr [si],0 ; nul first byte of last entry + ret + + +BREAK + +;--- Set Local Int 24 vector --- +; modifies: AX,DX + +Set24: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + push es + push bx + push dx + MOV AL,24H + MOV AH,GET_INTERRUPT_VECTOR + call do_21 + MOV WORD PTR [HERRINT+2],ES ; Save current vector + MOV WORD PTR [HERRINT],BX + MOV DX,OFFSET CodeR:DSKERR + MOV AL,24H + MOV AH,SET_INTERRUPT_VECTOR ; Install our own + call do_21 ; Spooler must catch its errors + pop dx + pop bx + pop es + ret + + +;--- Reset Old Int 24 vector --- +; modifies: none + +Res24: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + push ds + PUSH AX + push dx + LDS DX,[HERRINT] +ASSUME DS:NOTHING + MOV AL,24H + MOV AH,SET_INTERRUPT_VECTOR + call do_21 ;Restore Error INT + pop dx + POP AX + pop ds + ret + + +;--- INT 24 handler --- +DSKERR: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [PABORT],0 + JNZ IGNRET + STI + PUSH BX + PUSH CX + PUSH DX + PUSH DI + PUSH SI + PUSH BP + PUSH ES + PUSH DS + PUSH CS + POP DS + PUSH CS + POP ES +ASSUME DS:CodeR,ES:CodeR + ADD [BADDRVM],AL ;Set correct drive letter + MOV SI,OFFSET CodeR:ERRMES + CALL LISTMES + TEST AH,080H + JNZ FATERR + AND DI,0FFH + CMP DI,12 + JBE HAVCOD + MOV DI,12 +HAVCOD: + MOV [I24_ERR],DI + SHL DI,1 + MOV DI,WORD PTR [DI+MESBAS] ; Get pointer to error message + MOV SI,DI + CALL LISTMES ; Print error type + MOV SI,OFFSET CodeR:ERRMEST + CALL LISTMES + mov si,offset CodeR:FileQueue ; print filename + call ListMes2 ; print name + mov si,offset CodeR:BelMes + call ListMes +SETABORT: + INC [PABORT] ;Indicate abort + POP DS + POP ES + POP BP + POP SI + POP DI + POP DX + POP CX + POP BX +IGNRET: + XOR AL,AL ;Ignore + IRET + +FATERR: + MOV [I24_ERR],0FFH + MOV SI,OFFSET CodeR:FATMES + CALL LISTMES + JMP SHORT SETABORT + + +BREAK + +;--- Communications interrupt --- +SPCOMINT proc far +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP AH,1 + JBE MINE + JMP [COMNEXT] + +MINE: + CMP AL,0F8H + JAE RESERVED_RET +IF HardInt + CMP AX,0080h + JNZ CheckPSP + JMP FakeINT1C +ENDIF +CheckPSP: + OR AH,AH + JNE PSPDO + MOV AL,1 ; Tell PSPRINT to go away (AH = 1) +RESERVED_RET: + IRET + +PSPDO: + OR AL,AL + JNE PSPDISP +INST_REQ: + MOV AL,0FFH + IRET + +PSPDISP: + CMP [BUSY],0 + JZ SETCBUSY +ErrBusy: + MOV AX,error_busy +setcret: + push bp + mov bp,sp + or word ptr [bp+6],f_Carry + pop bp + iret + +SETCBUSY: + XOR AH,AH + CMP AX,6 ; check function within valid range + Jbe GoForIt + mov ax,error_invalid_function + jmp setcret +GoForIt: + INC [BUSY] ;Exclude + STI ;Turn ints back on + PUSH DI ;G + PUSH ES + PUSH DS + PUSH CS + POP DS +ASSUME DS:CodeR + mov [QueueLock],0 ; unlock the print queue + SHL AX,1 ;Turn into word index + mov di,ax + call ComDisp[DI] + assume ds:nothing + jc ErrRet +ASSUME DS:CodeR,ES:NOTHING + push ds + push cs + pop ds +ASSUME DS:CodeR,ES:NOTHING + CALL PSTAT ; Tweek error counter + pop ds + assume ds:nothing +ErrRet: + pushf + call Context_Back + popf + CLI + DEC BUSY ; leaves carry alone! + POP DS +ASSUME DS:NOTHING + POP ES + POP DI ;G + jc setcret + push bp + mov bp,sp + and word ptr [bp+6],NOT f_Carry + pop bp + iret +SpComInt Endp + +BREAK + +;--- Return pointer to file queue --- +QSTAT: +ASSUME DS:CodeR,ES:NOTHING + + mov [QueueLock],1 ; lock the print queue + CALL PSTAT ; Tweek error counter + push bp + mov bp,sp ; 0 2 4 + MOV [bp+ 2 + 2],cs ; + POP BP + mov si,offset CodeR:FileQueue + mov dx,[ErrCnt] ; return error count + clc + ret + +;--- Return pointer to device driver if active --- +QSTATDEV: +ASSUME DS:CodeR,ES:NOTHING + + xor ax,ax ;g assume not busy + mov [QueueLock],1 ;g lock the print queue + CALL PSTAT ;g Tweek error counter + cmp byte ptr FileQueue,0 ;g is there anything in the queue? + clc ;g + jz qstatdev_end ;g no - just exit + mov ax,error_queue_full ;g yes - set error queue full + mov si,word ptr [listdev+2] ;g get segment of list device + push bp ;g + mov bp,sp ;g 0 2 4 + MOV [bp+2+2],si ;g seg of device to DS + pop bp ;g + mov si,word ptr [listdev] ;g offset of device to SI + stc ;g + +qstatdev_end: ;g + mov [QueueLock],0 ;g unlock the print queue + ret ;g + +BREAK + +;--- Unlock the print queue --- +EndStat: +assume ds:CodeR,es:nothing + mov [QueueLock],0 + clc + ret + +BREAK + +; +; Note that we need to spin until the background is free +; +CanAll: +assume ds:CodeR,es:nothing + + cmp [CurrFil],0 ; are we currently printing? + jnz DoCanAll ; yes, go and cancel + ret ; carry is clear + +DoCanAll: + +;--- Cancel active file + mov bx,[CurrHand] ; close the current file + call Set24 + mov [PAbort],1 ; no Int24's + mov ah,Close + call My21 + call Res24 + mov [CurrFil],0 ; no files to print + mov [CurrHand],-1 ; invalidate handle + mov ax,[EndPtr] ; buffer empty + mov [NxtChr],ax + +;--- Cancel rest of files + mov si,offset CodeR:FileQueue + mov [QueueTail],si ; next free entry is the first + mov byte ptr [si],0 ; nul first byte of firts entry + mov si,offset CodeR:AllCan + call ListMes ; print cancelation message + mov si,offset CodeR:BelMes + call ListMes ; ring!! + +;--- Send close on output device + call Close_Dev + clc + ret + +BREAK + +CANFIL: +ASSUME DS:CodeR,ES:NOTHING + + CMP [CURRFIL],0 + JNZ DOCAN + ret ; carry is clear + +DOCAN: + +;--- find which file to cancel + push bp + mov bp,sp ; 0 2 4 + MOV ds,[bp+ 2 + 2] ; + POP BP + +assume ds:nothing + push cs + pop es +assume es:CodeR + mov CS:[CanFlg],0 ; reset message flag + mov CS:[ACanOcrd],0 ; no cancelation has ocured yet + mov bx,offset CodeR:FileQueue ; ES:BX points to 1st entry in queue + call AmbChk + +AnotherTry: + mov di,bx ; ES:DI points to 1st entry in queue + mov si,dx ; DS:SI points to filename to cancel +MatchLoop: + lodsb + cmp al,byte ptr es:[di] ; names in queue are all in upper case + je CharMatch + call UpConv ; did not match, try upper case + cmp al,byte ptr es:[di] + jne AnotherName ; a mismatch, try another name +CharMatch: + cmp es:byte ptr es:[di],0 ; was this the terminating nul? + je NameFound ; yes we got our file... + inc di + jmp MatchLoop + +AnotherName: + cmp CS:[AmbCan],1 ; ambigous file name specified? + jne AnName ; if not then no more work to do + cmp al,"?" + jne AnName + cmp byte ptr es:[di],"." + je FindPeriod + cmp byte ptr es:[di],0 ; if nul then file names match + jne CharMatch ; only if only ?'s are left... +FindNul: + lodsb + cmp al,"?" + je FindNul + cmp al,"." + je FindNul + or al,al + jne AnName ; found something else, no match + jmp short NameFound + +FindPeriod: ; ambigous files always have 8 chars + lodsb ; in name so we can not look for the + or al,al ; period twice (smart uh?) + je AnName ; no period found, files do not match + cmp al,"." + jne FindPeriod + jmp short CharMatch + +AnName: + add bx,MaxFileLen + cmp byte ptr es:[bx],0 ; end of queue? + jne AnotherTry ; no, continue... + cmp CS:[ACanOcrd],1 ; yes, was there a file found? + jne sk2 + push cs + pop ds +assume ds:CodeR ; StartAnFil likes it this way... + jmp StartAnFil ; restart printing + +sk2: +assume ds:nothing + + mov ax,error_file_not_found + stc + ret + + +;--- Name found, check if current file +NameFound: + push cs + pop ds +assume ds:CodeR + mov [ACanOcrd],1 ; remember we found a file + cmp bx,offset CodeR:FileQueue ; is the file being printed? + jne NotCurrent ; no, just compact the queue + cmp [CanFlg],0 + jne NotCurrent ; only cance current once + +;--- Cancel current file + mov [CanFlg],1 ; remeber we already canceled current + push bx + mov bx,[CurrHand] ; close the current file + call Set24 + mov [PAbort],1 ; no Int24's + mov ah,Close + call My21 + call Res24 + mov [CurrFil],0 ; no files to print + mov [CurrHand],-1 ; invalidate handle + mov ax,[EndPtr] ; buffer empty + mov [NxtChr],ax + pop bx + +;--- print cancelation message + push bx + mov si,offset CodeR:CanMes + call ListMes ; print cancelation message + mov si,bx ; points to filename + call ListMes2 ; print filename + mov si,offset CodeR:CanFilNam + call ListMes + mov si,offset CodeR:BelMes + call ListMes ; ring!! + pop bx + +;--- Send close on output device + call Close_Dev + +NotCurrent: + mov di,bx ; DI points to entry to cancel + mov si,bx + add si,MaxFileLen ; SI points to next entry + cmp si,[QueueTail] ; is the entry being canceled the last? + jne DoCompact ; no, do compaction + mov byte ptr [di],0 ; yes, just nul the first byte + jmp short CompactDone +DoCompact: + mov cx,[EndQueue] ; CX points to the end of the queue + sub cx,si ; length of the remainning of the queue + cld + rep movsb ; compact the queue +CompactDone: + mov ax,[QueueTail] ; remember new end of queue + sub ax,MaxFileLen + mov [QueueTail],ax + mov si,ax + mov byte ptr [si],0 ; nul first byte of last entry + + cmp byte ptr [bx],0 ; is there another file to consider? + je StartAnFil + push bp + mov bp,sp ; 0 2 4 + MOV ds,[bp+ 2 + 2] ; + POP BP +assume ds:nothing + jmp AnotherTry ; yes do it again... + + +;--- Start new file... +StartAnFil: +assume ds:CodeR + cmp [CurrHand],-1 ; was the canceled name the current? + jne NoneLeft ; no, just quit +StartAnFil2: + mov si,offset CodeR:FileQueue ; points to new current file + cmp byte ptr[si],0 ; is there one there? + je NoneLeft ; no, we canceled current and are none left + call Set24 + mov [PAbort],0 + mov dx,si + mov ax,(open shl 8) + call My21 + pushf + call Res24 + cmp [PAbort],0 + je NoI24b + popf + call CompQ ; compact file queue + jmp short StartAnFil2 + +NoI24b: + popf + jnc GoodNewCurr + call PrtOpErr ; print open error + call CompQ ; compact file queue + jmp short StartAnFil2 + +GoodNewCurr: + mov [CurrHand],ax ; save handle + mov [CurrFil],1 ; signal active (buffer is already empty) + +;--- Send Open on output device + call Open_Dev +NoneLeft: + clc + ret + +;--- Upper case conversion --- +UpConv: + CMP AL,'a' + JB NOCONV + CMP AL,'z' + JA NOCONV + SUB AL,20H +NOCONV: + RET + + +;--- Ambigous file name check --- +; entry: ds:dx points to filename +; preserves ds:dx and es +; +assume ds:nothing,es:CodeR +AmbChk: + mov CS:[AmbCan],0 ; assume not ambigous + mov si,dx + cld +AmbLoop: + lodsb + or al,al ; the nul? + jne AmbLoop + dec si ; points to nul + std ; scan backwards +ScanBack: + lodsb + cmp al,"*" + jne NotAStar + mov CS:[AmbCan],1 +NotAStar: + cmp al,"?" + jne NotAQues + mov CS:[AmbCan],1 +NotAQues: + cmp al,CS:[PChar] + jne ScanBack + cld ; be safe + cmp CS:[AmbCan],1 ; an ambigous cancel? + je AmbCanFnd ; no, just proceed + ret + +;--- transform * to ?'s +AmbCanFnd: + inc si + inc si ; points to actual name (past path char) + mov di,offset CodeR:ACBuf + push di + mov cx,12 + mov al,20h + cld + rep stosb ; fill fcb with blanks + pop di + push si + mov ax,(Parse_file_descriptor shl 8) and 0FF00h + call My21 + pop si + +;--- Copy name to expanded name + push ds + pop es +assume ds:nothing + push cs + pop ds +assume ds:CodeR + push es + mov di,si + mov si,offset CodeR:ACName + mov cx,8 +ACMovNam: + lodsb ; move name + cmp al,20h + je ACMovDn1 + stosb + loop ACMovNam + +ACMovDn1: + mov si,offset CodeR:ACExt + cmp byte ptr [si],20h ; if extension starts with blank + je ACMovDn2 ; then do not put period + mov al,"." + stosb + mov cx,3 + +ACMovExt: + lodsb ; move name + cmp al,20h + je ACMovDn2 + stosb + loop ACMovExt + +ACMovDn2: + mov byte ptr es:[di],0 ; nul terminate + pop ds +assume ds:nothing + push cs + pop es +assume es:CodeR + ret + + + +BREAK + +ADDFIL: +ASSUME DS:CodeR,ES:NOTHING + +;--- Check that queue is not full + mov di,[QueueTail] ; load pointer to next empty entry + cmp di,[EndQueue] ; queue full? + jb OkToQueue ; no, place in queue... + mov ax,error_queue_full + stc + ret + +;--- Copy name to empty slot in queue +OkToQueue: +; +; Retrieve old DS +; + push bp + mov bp,sp ; 0 2 4 + MOV ds,[bp+ 2 + 2] ; + POP BP + +assume ds:nothing + push cs + pop es ; ES:DI points to empty slot +assume es:CodeR + mov si,dx ; DS:SI points to submit packet + cmp byte ptr ds:[si],0 + jnz IncorrectLevel + lds si,dword ptr ds:[si+1] ; DS:SI points to filename + mov cx,MaxFileLen ; maximum length of file name +CopyLop: + lodsb + call UpConv ; convert to upper case + stosb + or al,al ; nul? + je CopyDone ; yes, done with move... + loop CopyLop + push cs + pop ds +assume ds:CodeR + mov ax,error_name_too_long ; if normal exit from the loop then + stc + ret + +IncorrectLevel: + mov ax,error_invalid_function + stc + ret + +assume ds:nothing,es:nothing ; es:nothing = not true but lets +CopyDone: ; avoid possible problems... + push cs + pop ds +assume ds:CodeR + +;--- advance queue pointer + mov si,[QueueTail] ; pointer to slot just used + push si ; save for test open later + add si,MaxFileLen + mov [QueueTail],si ; store for next round + mov byte ptr [si],0 ; nul next entry (maybe the EndQueue) + +;--- Check that file exists + call Set24 + mov [PAbort],0 + pop dx ; get pointer to filename + MOV AX,(OPEN SHL 8) + call My21 + pushf + PUSH DX + call Res24 + POP DX + popf + JNC GOTFIL +; +; See if brain damaged user entered an invalid drive +; + PUSH AX + MOV SI,DX + CMP BYTE PTR CS:[SI+1],':' + JZ GotDrive + POP AX + JMP SHORT i24bf +GotDrive: + MOV AH,Get_default_drive ; get current + CALL My21 + PUSH AX + MOV DL,CS:[SI] ; get drive letter to test + OR DL,20h + SUB DL,'a' + MOV AH,Set_Default_Drive ; set it + CALL My21 + MOV AH,Get_default_drive ; get it back + CALL My21 + CMP AL,DL ; same? + JNZ BadDrive ; no, bad drive + POP DX ; get original back + MOV AH,Set_Default_Drive ; set original + CALL My21 + POP AX + MOV DX,SI + JMP SHORT i24bf +BadDrive: + POP DX ; get original back + MOV AH,Set_Default_Drive ; set original + CALL My21 + POP AX + MOV AX,error_invalid_drive + MOV DX,SI +I24BF: + mov si,[QueueTail] ; take bad name out of queue + sub si,MaxFileLen ; SI points to the slot with bad name + mov [QueueTail],si + mov byte ptr [si],0 ; nul the first byte + stc + ret + + +;--- Check if print currently busy +GotFil: + CMP [CURRFIL],0 ; currently printing? + JZ OKAFIL ; no, start new print + mov bx,ax ; busy, close handle + call Set24 + mov [PAbort],1 ; no Int24's + mov ah,Close + call My21 + call Res24 + clc + ret + +;--- Save file data +OKAFIL: + MOV [CURRHAND],AX ; Valid handle + MOV AX,[ENDPTR] + MOV [NXTCHR],AX ; Buffer empty + MOV [CURRFIL],1 + +;--- Send Open on output device + call Open_Dev + clc + ret + +BREAK + +; +; perform a system call as myself +; +My21: + call Context_switch + call Do_21 + ret + +Public do_21 +DO_21: +ASSUME DS:NOTHING,ES:NOTHING + IF IBM + CMP BYTE PTR CS:[INT15FLAG],0 + JZ REAL_21 + PUSH DS + PUSH BX + LDS BX,CS:[INT15PTR] + INC BYTE PTR [BX] + POP BX + POP DS + CALL OffSave + INT 21H + Call OnSave + PUSH DS + PUSH BX + PUSHF ; Flags from system call + LDS BX,CS:[INT15PTR] + DEC BYTE PTR [BX] + POPF + POP BX + POP DS + RET + ENDIF + +REAL_21: + Call OffSave + INT 21H + CALL OnSave + RET + +OffSave: + ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSH AX + PUSH DX + MOV AX,Set_CTRL_C_Trapping SHL 8 + 2 + XOR DL,DL + INT 21h + MOV CtrlC,DL + POP DX + POP AX + ret + +OnSave: + ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSH AX + PUSH DX + MOV AX,Set_CTRL_C_Trapping SHL 8 + 2 + MOV DL,CtrlC + INT 21h + POP DX + POP AX + ret + +BREAK + +ListMes2: +ASSUME DS:CodeR,ES:NOTHING + LODSB + cmp al,0 + jz LMesDone + CALL LOUT + JMP short LISTMES2 + + +LISTMES: +ASSUME DS:CodeR,ES:NOTHING + LODSB + CMP AL,"$" + JZ LMESDONE + CALL LOUT + JMP short LISTMES + +LMESDONE: + RET + +LOUT: + PUSH BX +LWAIT: + CALL PSTAT + JZ PREADY + CMP [ERRCNT],ERRCNT2 + JA POPRET ;Don't get stuck + JMP SHORT LWAIT +PREADY: + CALL POUT +POPRET: + POP BX + RET + +;Stuff for BIOS interface +IOBUSY EQU 0200H +IOERROR EQU 8000H + +public PRNR003S, PRNR003E +PRNR003S: + +BYTEBUF DB ? + +CALLAD DD ? + +IOCALL DB 22 + DB 0 +IOREQ DB ? +IOSTAT DW 0 + DB 8 DUP(?) + DB 0 + DW OFFSET CodeR:BYTEBUF +INTSEG DW ? +IOCNT DW 1 + DW 0 + +PRNR003E: + +; Following two routines perform device open and close on output device. +; NO REGISTERS (including flags) are modified. No errors generated. + +public open_dev +Open_Dev: +ASSUME DS:NOTHING,ES:NOTHING +; +; We are now going to use the printer... We must lock down the printer so +; that the network does not intersperse output on us... +; We must also signal the REDIRector for stream open. +; We must ask DOS to set the Printer Flag to busy +; + PUSH BX + PUSHF + PUSH AX + PUSH DX + MOV DX,PrinterNum + CMP DX,-1 + JZ NoORop + MOV AX,0203h ; redirector lock + INT 2FH + MOV AX,0201H ; Redirector OPEN + INT 2FH +NoORop: + mov ax,(SET_PRINTER_FLAG SHL 8) + 01 + int 21H + POP DX + POP AX + MOV BL,DEVOPN ; Device OPEN + CALL OP_CL_OP + POPF + POP BX + RET + +OP_CL_OP: + PUSH DS + PUSH SI + LDS SI,[LISTDEV] +ASSUME DS:NOTHING + TEST [SI.SDEVATT],DEVOPCL + JZ NO_OP_CL + PUSH CS + POP DS +ASSUME DS:CodeR + MOV [IOCALL],DOPCLHL + CALL DOCALL +NO_OP_CL: + POP SI + POP DS +ASSUME DS:NOTHING + Ret + + +public close_dev +Close_Dev: +ASSUME DS:NOTHING,ES:NOTHING +; +; At this point, we release the ownership of the printer... +; and do a redirector CLOSE. +; Also tell DOS to reset the Printer Flag +; + PUSH BX + PUSHF + MOV BL,DEVCLS + CALL OP_CL_OP ; Device CLOSE + PUSH AX + PUSH DX + MOV DX,PrinterNum + CMP DX,-1 + JZ NoCRop + MOV AX,0202H ; redirector CLOSE + INT 2FH + MOV AX,0204h ; redirector clear + INT 2FH +NoCRop: + MOV AX,(SET_PRINTER_FLAG SHL 8) +00 + INT 21H + POP DX + POP AX + POPF + POP BX + RET + +PSTAT: +ASSUME DS:CodeR + PUSH BX + INC [ERRCNT] + MOV BL,DEVOST + MOV [IOCALL],DSTATHL + CALL DOCALL + TEST [IOSTAT],IOERROR + JZ NOSTATERR + OR [IOSTAT],IOBUSY ;If error, show buisy +NOSTATERR: + TEST [IOSTAT],IOBUSY + JNZ RET13P ;Shows buisy + MOV [ERRCNT],0 +RET13P: + POP BX + RET + +POUT: +ASSUME DS:CodeR + MOV [BYTEBUF],AL + MOV BL,DEVWRT + MOV [IOCALL],DRDWRHL +DOCALL: + PUSH ES + MOV [IOREQ],BL + MOV BX,CS + MOV ES,BX + MOV [IOSTAT],0 + MOV [IOCNT],1 + PUSH DS + PUSH SI + PUSH AX + call Context_Switch + MOV BX,OFFSET CodeR:IOCALL + LDS SI,[LISTDEV] +ASSUME DS:NOTHING + MOV AX,[SI+SDEVSTRAT] + MOV WORD PTR [CALLAD],AX + CALL [CALLAD] + MOV AX,[SI+SDEVINT] + MOV WORD PTR [CALLAD],AX + CALL [CALLAD] + POP AX + POP SI + POP DS +ASSUME DS:CodeR + POP ES + RET + + IF IBM +Public PRNR004S, PRNR004E +PRNR004S: + +REAL_INT_13 DD ? +INT_13_RETADDR DW OFFSET CodeR:INT_13_BACK + +PRNR004E: + +INT_13 PROC FAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + PUSHF + INC [BUSY] ;Exclude if dumb program call ROM + PUSH CS + PUSH [INT_13_RETADDR] + PUSH WORD PTR [REAL_INT_13+2] + PUSH WORD PTR [REAL_INT_13] + RET +INT_13 ENDP + +INT_13_BACK PROC FAR + PUSHF + DEC [BUSY] + POPF + RET 2 ;Chuck saved flags +INT_13_BACK ENDP + ENDIF + + + IF IBM + +Public PRNR005S, PRNR005E +PRNR005S: + +REAL_INT_15 DD ? +INT15FLAG DB 0 ; Init to off +INT15PTR DD ? + +PRNR005E: + +INT_15 PROC FAR +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP AH,20H + JNZ REAL_15 ; Not my function + CMP AL,1 + JA REAL_15 ; I only know 0 and 1 + JE FUNC1 + INC [INT15FLAG] ; Turn ON + MOV WORD PTR [INT15PTR],BX ; Save counter loc + MOV WORD PTR [INT15PTR+2],ES + IRET + +FUNC1: + MOV [INT15FLAG],0 ; Turn OFF + IRET + +REAL_15: + JMP [REAL_INT_15] + +INT_15 ENDP + + +Public PRNR006S, PRNR006E +PRNR006S: + +FLAG17_14 DB 0 ; Flags state of AUX/PRN redir +REAL_INT_5 DD ? +REAL_INT_17 DD ? +INT_17_NUM DW 0 + +PRNR006E: + +INT_17: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [FLAG17_14],1 + JNZ DO_INT_17 ;The PRN device is not used + CMP [CURRFIL],0 + JZ DO_INT_17 ;Nothing pending, so OK + CMP DX,[INT_17_NUM] + JNZ DO_INT_17 ;Not my unit + CMP [BUSY],0 + JNZ DO_INT_17 ;You are me + STI + MOV AH,0A1H ;You are bad, get time out + IRET + +DO_INT_17: + JMP [REAL_INT_17] ;Do a 17 + +Public PRNR007S, PRNR007E +PRNR007S: +REAL_INT_14 DD ? +INT_14_NUM DW 0 + +PRNR007E: + +INT_14: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [FLAG17_14],2 + JNZ DO_INT_14 ;The AUX device is not used + CMP [CURRFIL],0 + JZ DO_INT_14 ;Nothing pending, so OK + CMP DX,[INT_14_NUM] + JNZ DO_INT_14 ;Not my unit + CMP [BUSY],0 + JNZ DO_INT_14 ;You are me + STI + OR AH,AH + JZ SET14_AX + CMP AH,2 + JBE SET14_AH +SET14_AX: + MOV AL,0 +SET14_AH: + MOV AH,80H ;Time out + IRET + +DO_INT_14: + JMP [REAL_INT_14] ;Do a 14 + +INT_5: +ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + CMP [FLAG17_14],1 + JNZ DO_INT_5 ;The PRN device is not used + CMP [CURRFIL],0 + JZ DO_INT_5 ;Nothing pending, so OK + CMP [INT_17_NUM],0 + JNZ DO_INT_5 ;Only care about unit 0 + IRET ;Pretend it worked + +DO_INT_5: + JMP [REAL_INT_5] ;Do a 5 + ENDIF + +Public PRNR008S, PRNR008E +PRNR008S: + +ERRCNT DW 0 + + IF IBM +;Reserved names for parallel card +INT_17_HITLIST LABEL BYTE + DB 8,"PRN ",0 + DB 8,"LPT1 ",0 + DB 8,"LPT2 ",1 + DB 8,"LPT3 ",2 + DB 0 +;Reserved names for Async adaptor +INT_14_HITLIST LABEL BYTE + DB 8,"AUX ",0 + DB 8,"COM1 ",0 + DB 8,"COM2 ",1 +;--------------------------------------------------------------bug330a09 + DB 8,"COM3 ",2 + DB 8,"COM4 ",3 +;--------------------------------------------------------------bug330a09 + DB 0 + ENDIF + +LISTNAME DB "PRN " ;Device name + +PRNR008E: + +SETDEV: +ASSUME CS:CodeR,DS:CodeR,ES:NOTHING,SS:NOTHING +; LISTNAME has the 8 char device name IN UPPER CASE +; CARRY set if bad device +; DS preserved, others destroyed. + + MOV AH,GET_IN_VARS + call My21 + PUSH ES + POP DS + LEA SI,ES:[BX.SYSI_DEV] +ASSUME DS:NOTHING + PUSH CS + POP ES +ASSUME ES:CodeR + MOV DI,OFFSET CodeR:LISTNAME +LOOKDEV: + TEST [SI.SDEVATT],DEVTYP + JZ NEXTDEV ; Skip Block devs + PUSH SI + PUSH DI + ADD SI,SDEVNAME ; Point at name + MOV CX,8 + REPE CMPSB + POP DI + POP SI + JE GOTDEV +NEXTDEV: + LDS SI,[SI.SDEVNEXT] + CMP SI,-1 + JNZ LOOKDEV + PUSH CS + POP DS + STC + RET + +GOTDEV: + MOV WORD PTR CS:[CALLAD+2],DS ;Get I/O routines + MOV WORD PTR CS:[LISTDEV+2],DS ;Get I/O routines + MOV WORD PTR CS:[LISTDEV],SI + PUSH CS + POP DS +ASSUME DS:CodeR + + IF IBM + MOV PrinterNum,-1 ; Assume not an INT 17 device + PUSH CS + POP ES +ASSUME ES:CodeR + MOV BP,OFFSET CodeR:LISTNAME + MOV SI,BP + MOV DI,OFFSET CodeR:INT_17_HITLIST +CHKHIT: + MOV SI,BP + MOV CL,[DI] + INC DI + JCXZ NOTONHITLIST + REPE CMPSB + LAHF + ADD DI,CX ;Bump to next position without affecting flags + MOV BL,[DI] ;Get device number + INC DI + SAHF + JNZ CHKHIT + XOR BH,BH + MOV [INT_17_NUM],BX + MOV PrinterNum,BX ; Set this as well to the INT 17 device + MOV [FLAG17_14],1 + JMP SHORT ALLSET + +NOTONHITLIST: + MOV DI,OFFSET CodeR:INT_14_HITLIST +CHKHIT2: + MOV SI,BP + MOV CL,[DI] + INC DI + JCXZ NOTONHITLIST2 + REPE CMPSB + LAHF + ADD DI,CX ;Bump to next position without affecting flags + MOV BL,[DI] ;Get device number + INC DI + SAHF + JNZ CHKHIT2 + XOR BH,BH + MOV [INT_14_NUM],BX + MOV [FLAG17_14],2 + JMP SHORT ALLSET + +NOTONHITLIST2: + MOV [FLAG17_14],0 +ALLSET: + ENDIF + CLC + RET + + + IF HARDINT + +BREAK + +ReBtINT: +ASSUME CS:CodeR,DS:NOTHING,ES:NOTHING,SS:Nothing + + CLI + push cs + pop ds + +IntWhileBusy: + INT ComInt + JNC NotBusy + JMP IntWhileBusy + ret +NotBusy: + + INC [BUSY] ; Exclude hardware interrupts + INC [SOFINT] ; Exclude software interrupts + + call CanAll ; Purge the Queue + + LDS DX,CodeR:COMNEXT + mov ax,(set_interrupt_vector shl 8) or comint + INT 21H ;Set int 2f vector + + LDS DX,CodeR:NEXTINT + mov ax,(set_interrupt_vector shl 8) or intloc + INT 21H ;Set hardware interrupt + + mov ax,(set_interrupt_vector shl 8) or 15h + lds dx,CodeR:Real_Int_15 ; Reset the wait on event on ATs + int 21h + + mov ax,(set_interrupt_vector shl 8) or 17h + LDS DX,CodeR:Real_Int_17 + INT 21H ;Set printer interrupt + + mov ax,(set_interrupt_vector shl 8) or 5h + LDS DX,CodeR:Real_Int_5 + INT 21H ;Set print screen interrupt + + mov ax,(set_interrupt_vector shl 8) or 14h + LDS DX,CodeR:Real_Int_14 + INT 21H ;Set printer interrupt + + mov ax,(set_interrupt_vector shl 8) or 24h + LDS DX,CodeR:HERRINT + INT 21H ;Set printer interrupt + + LDS DX,CodeR:NEXT_REBOOT + mov ax,(set_interrupt_vector shl 8) or reboot + INT 21H ;Set bootstrap interrupt + + STI + INT 19H + + ENDIF ; HARDINT + + + + +;----- File name Queue and data buffer goes here +Public PRNR009S +PRNR009S: +FileQueue Label byte + db 0 ; the file queue starts empty + + +BREAK + +BADSPOOL: +ASSUME CS:CodeR,DS:CodeR,ES:NOTHING,SS:Nothing + MOV DX,OFFSET CODER:BADMES + mov cx,badmeslen + mov bx,stdout + mov ah,write + INT 21H +;********************************************************************* + MOV AX,(SET_PRINTER_FLAG SHL 8) ; Set flag to Idle + int 21H +;********************************************************************* + MOV AX,(EXIT SHL 8) OR 0FFH + INT 21H + +;--- move transient out of the way +ContTrans dd ? ; transient continuation address after move + +MoveTrans label far +ASSUME CS:CodeR,DS:CodeR,ES:CodeR,SS:Nothing + cli + CLD + MOV [INTSEG],CS + CALL SETDEV +ASSUME ES:NOTHING + JC BADSPOOL + MOV DX,OFFSET CodeR:SPINT + MOV AL,SOFTINT + MOV AH,GET_INTERRUPT_VECTOR + INT 21H ;Get soft vector + MOV WORD PTR [SPNEXT+2],ES + MOV WORD PTR [SPNEXT],BX + MOV AL,SOFTINT + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set soft vector + MOV DX,OFFSET CodeR:SPCOMINT + MOV AL,ComInt + MOV AH,GET_INTERRUPT_VECTOR + INT 21H ;Get communication vector + MOV WORD PTR [COMNEXT+2],ES + MOV WORD PTR [COMNEXT],BX + MOV AL,ComInt + MOV AH,SET_INTERRUPT_VECTOR ;Set communication vector + INT 21H + + IF IBM + MOV AL,13H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_13+2],ES + MOV WORD PTR [REAL_INT_13],BX + MOV DX,OFFSET CodeR:INT_13 + MOV AL,13H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set diskI/O interrupt + + MOV AL,15H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_15+2],ES + MOV WORD PTR [REAL_INT_15],BX + MOV DX,OFFSET CodeR:INT_15 + MOV AL,15H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set INT 15 vector + + MOV AL,17H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_17+2],ES + MOV WORD PTR [REAL_INT_17],BX + MOV DX,OFFSET CodeR:INT_17 + MOV AL,17H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set printer interrupt + MOV AL,14H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_14+2],ES + MOV WORD PTR [REAL_INT_14],BX + MOV DX,OFFSET CodeR:INT_14 + MOV AL,14H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set RS232 port interrupt + MOV AL,5H + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [REAL_INT_5+2],ES + MOV WORD PTR [REAL_INT_5],BX + MOV DX,OFFSET CodeR:INT_5 + MOV AL,5H + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set print screen interrupt + ENDIF + + IF HARDINT + MOV AH,GET_INDOS_FLAG + INT 21H +ASSUME ES:NOTHING + MOV WORD PTR [INDOS+2],ES ;Get indos flag location + MOV WORD PTR [INDOS],BX + MOV AL,INTLOC + MOV AH,GET_INTERRUPT_VECTOR + INT 21H + MOV WORD PTR [NEXTINT+2],ES + MOV WORD PTR [NEXTINT],BX + + MOV AL,REBOOT ; We also need to chain + MOV AH,GET_INTERRUPT_VECTOR ; Into the INT 19 sequence + INT 21H ; To properly "unhook" + MOV WORD PTR [NEXT_REBOOT+2],ES ; ourselves from the TimerTick + MOV WORD PTR [NEXT_REBOOT],BX ; sequence + + IF IBM + MOV AX,0B800H + INT 2FH + CMP AL,0 + JE SET_HDSPINT ; No NETWORK, set hardware int + TEST BX,0000000011000100B + JNZ NO_HDSPINT ; DO NOT set HDSPINT if RCV|MSG|SRV + ENDIF + +SET_HDSPINT: + MOV DX,OFFSET CodeR:HDSPINT + MOV AL,INTLOC + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set hardware interrupt + + MOV DX,OFFSET CodeR:ReBtINT + MOV AL,REBOOT + MOV AH,SET_INTERRUPT_VECTOR + INT 21H ;Set bootstrap interrupt + +NO_HDSPINT: + ENDIF + MOV DX,OFFSET CODER:GOODMES + mov cx,goodmeslen + mov bx,stdout + mov ah,write + int 21h + +;--- Move transient +; Note: do not use stack, it may get trashed in move! +public RealMove +RealMove: + + mov ax,offset dg:TransRet + mov word ptr [ContTrans],ax ; store return offset + mov ax,CodeR + add ax,[endres] ; get start of moved transient, actually + ; this is 100 bytes more than need be + ; because of lack of pdb, but who cares? + mov word ptr [ContTrans+2],ax ; return segment + mov es,ax ; new location for dg group +assume es:nothing + mov ax,dg + mov ds,ax +assume ds:nothing + mov cx,offset dg:TransSize + mov si,cx ; start from the bottom and move up + mov di,cx + std + rep movsb ; move all code, data and stack + cld ; restore to expected setting... + +;--- normalize transient segment regs + mov ax,es + mov ds,ax + sub ax,dg ; displacement + mov dx,ss + add dx,ax ; displace stack segemnt + mov ss,dx + +assume ds:nothing,es:nothing,ss:nothing + jmp ContTrans ; back to the transient... + +PRNR009E: + +CodeR EndS + + End diff --git a/UPDSRC/DOS/DISK2.OBJ b/UPDSRC/DOS/DISK2.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..54f40f57d5456442b36e7e241d6b5c3843958b9c GIT binary patch literal 2182 zcmZ8ieQaCR6+idc_dPpKoWyBfXfu+wu(z@RQ$H}HWEC%d&%}yj8^7m! z5c>u8$3!%&jpmuk@W;d|1LmVbz=R6oOQM?A`Ifa~8k91vVSn&Z4MEv7G*F%XLpbN! zNPuL&cka38{?6C$+_#_sw^Gi;rh(tZ0fLFFW%EQfp=~GTW2~mivzI(m z>4FZdODap1*#r;Ow*WWE^w5$v6ZfM4vmQsqA$k60TAnTrimZKSf>KwN}YAyM+uLcc?&Cz3I7N9o#d%uobWV> zrVkUGkGKc%Pw9i<+x>=L7&xc{Jb}xm%@-EDxGJv3#o|u54-E}}r*i$7V!Zh|T9Bdt zma#q=d>n=2#$tw_IZsN>Kj|M2AZD=>lWCsy*tmc4T)3faJ|zo1v)n+vzZCgXDQb)) zmFC%zv&CSbvH4$!>NhsOZ8YbVwu1=bd2juMf%k^tC%@J@zy*ld?{W^)@hHgMIo>EPb!x-_kdNH5|IA;%1f4@9whw;{z!yxOMkP&tSmf2GKYI;@BR zopp&ps`oG!b4w)ze5{bnTku7_2lzWOfO9R3GaG9WnZdBou-wm5xO9Oyb^=nA`TNrP zw4~Z1aTK#ArvIk4MxI+s=XB9YE$*R)QPzK;InL(X)MRSfhR^B)z%NLg<5M|@pniM^ zA@VouCO%=#H_70>>y`OWrP8y%%^`!Gg_9&pjP@7cU@qv0b$F_4Z}4J>{fa z_^6%%u9NA)BwxGL4tnNw1$A!px?9xZwHIuDL+R?9b5r?|g4%r7Z~DvrpAA2wG(QL| z-(TuE{fQbsgkgPtq{yDsrf12|{#uue?J_Yc!@9fD31KH;W^!pWVZ%S__|^Ft`Riy0 zbonFFVj`7mMf7_r_HMH9p4W%5jpw3A+NR%sm~u=N?Q9ZG*LMQHoy>~H3$TJwVBc|~ zk+M3DE$Zi@e?hGjivipe*nMil2>#{80$vmk7zgda)@${-u)!w#je83Nu-x!!6EYD) zgpn8JPNd2OtTj!Tj`S$w9Iqv!@bcw48!lgg`^Oj!bHCU~BYq8y>kY)F8}a2HO~JN*DO?piz57fd^ZFsKBq; zVFf;{cH(J{>q5>0aH=s}MsPW6CK9tad4FWErP`0m=r@$JmUE23*6JYYSIOAE<9aWH K=N1*5#;*X|C^#Pg literal 0 HcmV?d00001

$t7wXM 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 literal 0 HcmV?d00001 diff --git a/SRC/TOOLS/MSMAKE.EXE b/SRC/TOOLS/MSMAKE.EXE new file mode 100644 index 0000000000000000000000000000000000000000..20d494944db9837bfe7498c31cb1a290dde3fdcc GIT binary patch literal 24300 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 literal 0 HcmV?d00001 diff --git a/UPDSRC/BIOS/MSBIO2.ASM b/UPDSRC/BIOS/MSBIO2.ASM new file mode 100644 index 0000000..03a80f2 --- /dev/null +++ b/UPDSRC/BIOS/MSBIO2.ASM @@ -0,0 +1,649 @@ + TITLE MSBIO2 - DOS 3.3 + +;------------------------------------------------------------------------------- +; : +; Microsoft Bio : +; : +; The file msbio.asm is the main file in the Mircosoft bio. This file : +; includes the other main files in the bio. Most of the routines are : +; in these include files. The main files included are: : +; : +; File Contains : +; : +; msdisk.inc Disk device driver routines : +; ms96tpi.inc Routines for 96tpi drives : +; msaux.inc Device driver for the rs-232 serial ports : +; msclock.inc Device driver for "clock$" device : +; mscon.inc Device driver for "con" : +; mslpt.inc Device driver for the printers : +; : +; Each of these files contain a header section documenting the code : +; in that file. : +; Msbio also includes several files for equ's, structure definition, : +; macro definitions, etc. These are: : +; : +; msbiomes.inc msmacro.inc devsym.inc : +; dskprm.inc error.inc : +; : +; Each of these file contains explanitory notes. : +; : +; The actual code in msbio can be broken down into several piece: : +; : +; macro definitions Several marco are defined in msbio. They : +; are a few odds and end that did not fit : +; anywhere else. : +; : +; Command Jump Table List of entry points in the device drivers. : +; See notation below for full explination. : +; : +; Interrupt and Strategy : +; Entry points Calls on the device driver first come to here. : +; There is common code with pushes registers and : +; the like before jumping to routines in the : +; driver files. The common exit points are also : +; in this file. : +; : +; Miscellaneous Code There are several routines and data structure : +; declarations. See below for details. : +; : +;------------------------------------------------------------------------------- + + + +; +; If the variable TEST is non-zero then code for debugging is included. +; The extra code will make the binary file nuch larger. +; The symbol is also defined in msequ.inc. Both must be changed to +; turn debugging on or off. +; +; The level of the debugging is controled by the variable fTestBits in +; this file. See the comment preceeding the variable for more information. +; The actual routines which print the messages are in msmacro.inc +; See the header comment in this file for more information. +; + + +; +; Revision History +; +; REV 2.1 5/1/83 ARR added timer int handler and changed order of AUX +; PRN init for HAL0 +; +; REV 2.15 7/13/83 ARR Because of IBM design issues, and that BASCOM +; is ill behaved with respect to the 1CH timer interrupt, +; the timer handler has to be backed out! The intended +; code is commented out and has an ARR 2.15 annotation. +; This means the BIOS will go back to the multiple roll +; over bug. +; +; REV 2.20 8/5/83 ARR IBM makes hardware change. Now wants to use half +; height drives for HAL0, and back fit for PC/PC XT. Problem +; with head settle time. Previous drives got by on a 0 +; settle time, 1/2 hight drives need 15 head settle when +; doing WRITEs (0 ok on READ) if the head is being stepped. +; This requires a last track value to be kept so that BIOS +; knows when head is being moved. To help out +; programs that issue INT 13H directly, the head settle will +; normally be set to 15. It will be changed to 0 on READs, +; or on WRITEs which do not require head step. +; +; REV 2.21 8/11/83 MZ IBM wants write with verify to use head settle 0. +; Use same trick as above. +; +; REV 2.25 6/20/83 mjb001 added support for 96tpi and salmon +; +; REV 2.30 6/27/83 mjb002 added real-time clock +; +; REV 2.40 7/8/83 mjb003 added volume-id checking and int 2f macro +; definitions push* and pop* +; +; REV 2.41 7/12/83 ARR more 2.X enhancements. Open/Close media change +; +; REV 2.42 11/3/83 ARR more 2.X enhancements. Disk OPEN/CLOSE, FORMAT +; code and other misc hooked out to shrink BIOS. Code for +; Disk OPEN/CLOSE, FORMAT included only with 96tpi disks. +; +; Rev 2.43 12/6/83 MZ Examine boot sectors on hard disks for 16-bit fat +; check. Examine large fat bit in BPB for walk of media for +; DOS +; +; Rev 2.44 12/9/83 ARR Change to error reporting on INT 17H +; +; Rev 2.45 12/22/83 MZ Make head settle change only when disk parm is 0. + +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +; IBM ADDRESSES FOR I/O +; +;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +;Below was moved from sysinit1 +ROMSEGMENT EQU 0F000H +MODELBYTE EQU DS:BYTE PTR [0FFFEH] +MODELPCJR EQU 0FDH + + test=0 +;;Rev 3.30 modification ---------------------------- + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + INCLUDE MSEQU.INC + INCLUDE DEVSYM.INC + INCLUDE PUSHPOP.INC + INCLUDE MSMACRO.INC + + ASSUME DS:NOTHING,ES:NOTHING + + EXTRN DSK$IN:NEAR + EXTRN SETPTRSAV:NEAR + EXTRN OUTCHR:NEAR + EXTRN SETDRIVE:NEAR + EXTRN FLUSH:NEAR + EXTRN HARDERR:NEAR + EXTRN HARDERR2:NEAR + EXTRN MAPERROR:NEAR + EXTRN GETBP:NEAR + EXTRN CHECKSINGLE:NEAR + EXTRN CHECK_TIME_OF_ACCESS:NEAR + EXTRN EXIT:NEAR + EXTRN HAS1:NEAR + EXTRN HAS1_res:NEAR + EXTRN READ_SECTOR:NEAR + EXTRN INT_2F_13:FAR + + EXTRN OLD13:DWORD + +;DATA + EXTRN PTRSAV:DWORD + EXTRN START_BDS:WORD + EXTRN FDRIVE1:WORD + EXTRN FDRIVE2:WORD + EXTRN FDRIVE3:WORD + EXTRN FDRIVE4:WORD + EXTRN FLAGBITS:WORD + EXTRN TIM_DRV:BYTE + EXTRN MEDBYT:BYTE + EXTRN DRVMAX:BYTE + + PATHSTART 005,DISK + EVENB + PUBLIC ORIG19 +ORIG19 DD ? + + PUBLIC INT19SEM +INT19SEM DB 0 ; INDICATE THAT ALL INT 19 + ; INITIALIZATION IS COMPLETE + + IRP AA,<02,08,09,0A,0B,0C,0D,0E,70,72,73,74,76,77> + public Int19OLD&AA +Int19OLD&AA dd -1 ;Orignal hw int. vec for INT 19h. + ENDM + + EVENB + PUBLIC DSKDRVS +DSKDRVS DW FDRIVE1 + DW FDRIVE2 + DW FDRIVE3 + DW FDRIVE4 + PUBLIC HDSKTAB +HDSKTAB DW HDRIVE + DW DRIVEX +;* Next area is reseved for mini disk BPB pointers *** 4/7/86 +;* Don't change this pos. Should be add. from DskDrvs *** 4/7/86 +MINI_DISK_BPB_PTRS DB 40 dup (?) ;4/7/86 - mem res for Mini disk. + + EVENB + PUBLIC INT_2F_NEXT +INT_2F_NEXT DD ? + +RET_ADDR DD ? + + PATHEND 005,DISK +;;End of modification ---------------------------- + +; INT19 +; +; We "hook" the INT_REBOOT vector, because contrary to IBM documentation, +; it does NOT "bootstrap" the machine. It leaves memory almost untouched. +; Since the BIOS_INIT code assumes that certain Interrupt Vectors point to +; the ROM_BIOS we must "unhook" them before issuing the actual INT_REBOOT. +; Currently the following vectors need to be unhooked: +; 02,08,09,0A,0B,0C,0D,0E,70,72,73,74,75,76,77 +; + +Public Int19 +Int19 proc FAR + xor AX,AX ; get data segment to + mov DS,AX ; point to the vector table + assume ds:nothing + assume es:nothing + les DI,Old13 ; get ES to point to this segment + mov DS:[13h*4],DI ; restore old int13 value + mov DS:[13h*4+2],ES + + cmp Byte ptr Int19Sem, 0 + jnz int19vecs + jmp doint19 + +;;Dos 3.30 Will not support the PC-Jr +;;Rev 3.30 modification ---------------------------- +; ON THE PCJR, DON'T REPLACE ANY VECTORS +; MODEL BYTE DEFINITIONS FROM MSSTACK.ASM +; MOV AX,ROMSEGMENT +; MOV DS,AX +; MOV AL,MODELPCJR +; +; CMP AL,MODELBYTE +; JNE INT19VECS +; JMP DOINT19 + + +;Stacks code has changed these hardware interrupt vectors +;STKINIT in SYSINIT1 will initialzie Int19hOLDxx values. +int19vecs: + +; +; we now need to unhook all the vector replace to prevent stack overflow +; + +;;Rev 3.30 modification ---------------------------- + XOR AX,AX + MOV DS,AX + + IRP AA,<02,08,09,0A,0B,0C,0D,0E,70,72,73,74,76,77> + + LES DI,Int19OLD&AA + + mov ax,es ; Put segment where we can compare it + cmp ax,-1 ; OPT 0ffffh is not likely + je skip_int&AA ; OPT could get away without checking + cmp di,-1 ; OPT offset here. + je skip_int&AA + + MOV DS:[AA&H*4],DI + MOV DS:[AA&H*4+2],ES +skip_int&AA: + ENDM +;;End of modification ---------------------------- + +doint19: + LES DI,Orig19 + MOV DS:[19h*4],DI + MOV DS:[19h*4+2],ES + + INT 19h +INT19 ENDP +ASSUME DS:CODE + +;***************************************************************************** +PUBLIC DSK$INIT +DSK$INIT PROC NEAR + PUSH CS + POP DS + MOV AH,BYTE PTR DRVMAX + MOV DI,OFFSET DskDrvs + JMP SetPTRSAV +DSK$INIT ENDP + + +; +; Int 2f handler for external block drivers to communicate with the internal +; block driver in msdisk. The multiplex number chosen is 8. The handler +; sets up the pointer to the request packet in [PTRSAV] and then jumps to +; DSK$IN, the entry point for all disk requests. +; On exit from this driver (at EXIT), we will return to the external driver +; that issued this Int 2F, and can then remove the flags from the stack. +; This scheme allows us to have a small external device driver, and makes +; the maintainance of the various drivers (DRIVER and msBIO) much easier, +; since we only need to make changes in one place (most of the time). +; +; AL contains the Int2F function: +; 0 - Check for installed handler - RESERVED +; 1 - Install the BDS into the linked list +; 2 - DOS request +; + +MYNUM EQU 8 + +Public Int2F_Disk +Int2F_Disk PROC FAR + cmp ah,MYNUM + je Mine + jmp cs:[Int_2F_Next] ; chain to next Int 2F handler +Mine: + cmp al,0F8H ; IRET on reserved functions + jb Do_Func + IRET +Do_Func: + or al,al ; A GET INSTALLED STATE request? + jne Disp_Func + mov al,0FFH + IRET +Disp_Func: + Message fTestInit,<"Int2F_disk",cr,lf> + cmp al,1 ; Request for installing BDS? + jne Do_DOS_Req + call Install_BDS + IRET + +Do_DOS_Req: +; Set up pointer to request packet + MOV WORD PTR CS:[PTRSAV],BX + MOV WORD PTR CS:[PTRSAV+2],ES + jmp DSK$IN + +Int2F_Disk ENDP + +; +; Install_BDS installs a BDS a location DS:DI into the current linked list of +; BDS maintained by this device driver. It places the BDS at the END of the +; list. +Public Install_BDS +INSTALL_BDS PROC NEAR + message ftestinit,<"Install BDS",cr,lf> +; ds:di point to BDS to be installed + les si,dword ptr cs:[Start_BDS] ; Start at beginning of list + push es ; Save pointer to current BDS + push si +; es:si now point to BDS in linked list +Loop_Next_BDS: + cmp si,-1 ; got to end of linked list? + jz Install_Ret +; If we have several logical drives using the same physical drive, we must +; set the I_Am_Mult flag in each of the appropriate BDSs. + mov al,byte ptr ds:[di].DriveNum + cmp byte ptr es:[si].DriveNum,al + jnz Next_BDS + message ftestinit,<"Logical Drives",cr,lf> + xor bx,bx + mov bl,fI_Am_Mult + or word ptr ds:[di].flags,bx ; set flags in both BDSs concerned + or word ptr es:[si].flags,bx + mov bl,fI_Own_Physical + xor bx,-1 + and word ptr ds:[di].flags,bx ; reset that flag for 'new' BDS +; We must also set the fChangeline bit correctly. + mov bx,word ptr es:[si].flags ; determine if changeline available + and bl,fChangeline + xor bh,bh + or word ptr ds:[di].flags,bx + +Next_BDS: +; Before moving to next BDS, preserve pointer to current one. This is needed at +; the end when the new BDS is linked into the list. + pop bx ; discard previous pointer to BDS + pop bx + push es + push si + mov bx,word ptr es:[si].link + 2 + mov si,word ptr es:[si].link + mov es,bx + jmp short Loop_Next_BDS + +Install_Ret: + pop si ; Retrieve pointer to last BDS + pop es ; in linked list. + mov ax,ds + mov word ptr es:[si].link+2,ax ; install BDS + mov word ptr es:[si].link,di + mov word ptr ds:[di].link,-1 ; set NEXT pointer to NULL + RET +INSTALL_BDS ENDP + +; +; RE_INIT installs the Int 2F vector that will handle communication between +; external block drivers and the internal driver. It also installs the +; Reset_Int_13 interface. It is called by SYSYINIT +; +PUBLIC RE_INIT +RE_INIT PROC FAR + Message ftestinit,<"REINIT",CR,LF> + PUSH AX + PUSH DS + PUSH DI + XOR DI,DI + MOV DS,DI + MOV DI,2FH*4 ; point it to Int 2F Vector + MOV AX,WORD PTR DS:[DI] + MOV WORD PTR CS:[INT_2F_NEXT],AX + MOV AX,WORD PTR DS:[DI+2] ; preserve old Int 2F vector + MOV WORD PTR CS:[INT_2F_NEXT+2],AX + +; INSTALL the Reset_Int_13 +; interface + + + CLI + MOV Word Ptr DS:[DI],Offset Int_2f_13 ; install new vectors + MOV Word Ptr DS:[DI+2],CS + STI + POP DI + POP DS + POP AX + RET + +RE_INIT ENDP + +;------------------------------------------------- +; +; Ask to swap the disk in drive A: +; Using a different drive in a one drive system so +; request the user to change disks +; +Public SWPDSK +SWPDSK PROC NEAR + mov al,byte ptr ds:[di].drivelet ; get the drive letter + add al,"A" + mov cs:DRVLET,AL + push ds ; preserve segment register + push cs + pop ds + mov SI,OFFSET SNGMSG ; ds:si -> message + push BX + call WRMSG ;Print disk change message + call FLUSH + ; wait for a keyboard character + xor AH, AH ; set command to read character + int 16h ; call rom-bios + POP BX + pop ds ; restore segment register +WRMRET: + ret +SWPDSK ENDP + +;---------------------------------------------- +; +; WrMsg writes out message pointed to by [SI] +; +Public WrMsg +WRMSG PROC NEAR + lodsb ; get the next character of the message + or AL,AL ; see fi end of message + jz WRMRET + pushf + push CS + call OUTCHR + jmp SHORT WRMSG +WRMSG ENDP + + INCLUDE BIOMES.INC + +; +; End of support for multiple floppies with no logical drives +; This is not 'special' any more because we now have the capability of +; defining logical drives in CONFIG.SYS. We therefore keep the code for +; swapping resident ALL the time. +; + +;;Rev 3.30 modification ---------------------------- +;Variables for Dynamic Relocatable modules +;These should be stay resident. + + public INT6C_RET_ADDR +INT6C_RET_ADDR DD ? ;ret add from INT 6C for P12 mach + + PATHSTART 001,CLK +; +; DATA STRUCTURES FOR REAL-TIME DATE AND TIME +; + public BIN_DATE_TIME + public MONTH_TABLE + public DAYCNT2 + public FEB29 +BIN_DATE_TIME: + DB 0 ; CENTURY (19 OR 20) OR HOURS (0-23) + DB 0 ; YEAR IN CENTURY (0-99) OR MINUTES (0-59) + DB 0 ; MONTH IN YEAR (1-12) OR SECONDS (0-59) + DB 0 ; DAY IN MONTH (1-31) +MONTH_TABLE: + DW 0 ;MJB002 JANUARY + DW 31 ;MJB002 FEBRUARY + DW 59 ;MJB002 + DW 90 ;MJB002 + DW 120 ;MJB002 + DW 151 ;MJB002 + DW 181 ;MJB002 + DW 212 ;MJB002 + DW 243 ;MJB002 + DW 273 ;MJB002 + DW 304 ;MJB002 + DW 334 ;MJB002 +DAYCNT2 DW 0000 ;MJB002 TEMP FOR CNT OF DAYS SINCE 1-1-80 +FEB29 DB 0 ;MJB002 FEBRUARY 29 IN A LEAP YEAR FLAG + PATHEND 001,CLK + +;;End of modification modification ---------------------------- + +Public EndFloppy +EndFloppy Label Byte +; +; End of code for virtual floppy drives +; +Public EndSwap +EndSwap Label Byte + + PATHSTART 004,BIO + +Public HNUM +HNUM DB 0 ; number of hardfile (hard drives) + +Public HardDrv +HARDDRV DB 80H ;Physical drive number of first hardfile + + +; +; "HDRIVE" is a hard disk with 512 byte sectors +; + + EVENB +Public BDSH +BDSH DW -1 ; Link to next structure + DW Code + DB 80h ; physical drive number + DB "C" ; Logical Drive Letter +Public HDRIVE +HDRIVE: + DW 512 + DB 1 ; Sectors/allocation unit + DW 1 ; Reserved sectors for DOS + DB 2 ; No. of allocation tables + DW 16 ; Number of directory entries + DW 0000 ; Number of sectors (at 512 bytes each) + DB 11111000B ; Media descriptor + DW 1 ; Number of FAT sectors + DW 00 ; Sector limit + DW 00 ; Head limit + DW 00 ; Hidden sector count + DB 0 ; TRUE => bigfat +OPCNTH DW 0 ; Open Ref. Count +VOLIDH DB "NO NAME ",0 ; Volume ID for this disk + DB 3 ; Form Factor +FLAGSH DW 0020H ; Various Flags + dw 40 ; number of cylinders +RecBPBH db 31 dup (?) ; Recommended BPB for drive +TRACKH DB -1 ; Last track accessed on this drive +TIM_LOH DW -1 ; Keep these two contiguous (?) +TIM_HIH DW -1 +; +; End of single hard disk section +; + + +Public EndOneHard +EndOneHard Label Byte + + + + +; +;"DRIVEX" is an extra type of drive usually reserved for an +; additional hard file +; + + EVENB +Public BDSX +BDSX DW -1 ; Link to next structure + DW Code + DB 81h ; physical drive number + DB "D" ; Logical Drive Letter +Public DRIVEX +DRIVEX: + DW 512 + DB 00 ; Sectors/allocation unit + DW 1 ; Reserved sectors for DOS + DB 2 ; No. of allocation tables + DW 0000 ; Number of directory entries + DW 0000 ; Number of sectors (at 512 bytes each) + DB 11111000B ; Media descriptor + DW 0000 ; Number of FAT sectors + DW 00 ; Sector limit + DW 00 ; Head limit + DW 00 ; Hidden sector count + DB 0 ; TRUE => bigfat +OPCNTD DW 0 ; Open Ref. Count +VOLIDD DB "NO NAME ",0 ; Volume ID for this disk + DB 3 ; Form Factor +FLAGSD DW 0020H ; Various Flags + dw 40 ; number of cylinders +RecBPBD db 31 dup (?) ; Recommended BPB for drive +TRACKD DB -1 ; Last track accessed on this drive +TIM_LOD DW -1 ; Keep these two contiguous +TIM_HID DW -1 + +; +; End of section for two hard disks +Public EndTwoHard +EndTwoHard Label Byte + + PATHEND 004,BIO + + +Public TwoHard +TWOHARD LABEL BYTE + +PAGE +include ms96tpi.inc + +;;Rev 3.30 modification ---------------------------- +;Memory allocation for BDSM table. + PUBLIC BDSMs +BDSMs BDSM_type Max_mini_dsk_num dup (<>) ;currently max. 23 + +;** End_of_BDSM defined in MSINIT.ASM will be used to set the appropriate +;** ending address of BDSM table. +;;End of modification ---------------------------- + +; +;;3.3 BUG FIX -SP ------------------------------ +;Paragraph buffer between the BDSMs and MSHARD +; +;The relocation code for MSHARD needs this. this cannot be used for +;anything. nothing can come before this or after this.....IMPORTANT!!!! +;don't get too smart and using this buffer for anything!!!!!! +; + db 16 dup(0) +; +;end of bug fix buffer +;; +;;3.3 BUG FIX -SP------------------------------ + +CODE ENDS + END diff --git a/UPDSRC/BIOS/MSDISK.ASM b/UPDSRC/BIOS/MSDISK.ASM new file mode 100644 index 0000000..0afeb4d --- /dev/null +++ b/UPDSRC/BIOS/MSDISK.ASM @@ -0,0 +1,2410 @@ + TITLE MSDISK - DOS 3.3 +;------------------------------------------------------------------------ +; : +; DISK INTERFACE ROUTINES : +; : +; : +; This file contains the Disk Device Driver. : +; : +; The routines in this files are: : +; : +; routine function : +; ------- -------- : +; : +; MEDIA$CHK Determine if media in drive has changed : +; : +; GET$BPB Build a valid BPB for drive : +; : +; DSK$REM Determine if disk has removable media : +; : +; DSK$WRTV Disk write with verify : +; : +; DSK$WRT Disk write : +; : +; DSK$READ Read disk : +; : +; : +; These routines are not called directly. Call are made via : +; the strategy and interrupt entry point (see Device Header). : +; : +; Data structures: : +; There are two main types of data structures associated with : +; the disk drives. The first is the BDS. BDS is the Bios Data : +; structure. There is one BDS for each logical drive in the system. : +; All the BDS's are linked together in a list with the pointer to the : +; first BDS being found in Start_BDS. The BDS hold various values : +; important to the disk drive. For example there is a field for last : +; time accesses. As actions take place in the system the BDS are : +; update to reflect the actions. For example if there is a read to : +; a disk the last access field for the BDS for that drive is updated : +; to the current time. : +; The second data structure associated with disk drives is the : +; BPB. A BPB is a Bios Parameter Block. The BPB contains information : +; about the media inside a disk drive. Some on the fields in the BPB : +; are Sectors per track, number of FATs, and number of tracks. This : +; information is used to tell where sectors are on the disk. For : +; example, if we need to read logical sector 52: : +; : +; Diskette Track Sector Side : +; single density : +; eight sectors per track 6 5 0 : +; : +; double density : +; nine sectors per track 2 7 1 : +; : +; The BPB for the media in the drive is stored in the BDS for the : +; drive. If the user changes the floppy in the drive a call is : +; made to GET$BPB to build a new BPB in the BDS. See this routine : +; for the algorithm. : +; : +; : +;------------------------------------------------------------------------ +;;Rev 3.30 Modification +;for testing, set test to 1. So as MSBIO1.ASM. + test=0 + EXTRN NUMERR:ABS ;MSDATA + + INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT + INCLUDE MSEQU.INC + INCLUDE PUSHPOP.INC + INCLUDE MSMACRO.INC + INCLUDE DEVSYM.INC + INCLUDE DSKPRM.INC + + EXTRN INT2F_DISK:FAR ;MSBIO2 + EXTRN MEDIACHECK:NEAR ;96TPI + EXTRN HASCHANGE:NEAR ;96TPI + EXTRN MEDIA_SET_VID:NEAR ;96TPI + EXTRN HIDENSITY:NEAR ;96TPI + EXTRN CHECKLATCHIO:NEAR ;96TPI + EXTRN CHECKIO:NEAR ;96TPI + EXTRN SET_CHANGED_DL:NEAR ;96TPI + EXTRN SET_VOLUME_ID:NEAR ;MSVOLID + EXTRN SWPDSK:NEAR ;MSBIO2 + EXTRN CMDERR:NEAR ;MSBIO1 + EXTRN STRATEGY:NEAR ;MSBIO1 + EXTRN ERR$CNT:NEAR ;MSBIO1 + EXTRN DSK$IN:NEAR ;MSBIO1 + EXTRN EXIT:NEAR ;MSBIO1 + EXTRN BUS$EXIT:NEAR ;MSBIO1 + EXTRN ERR$EXIT:NEAR ;MSBIO1 + +;DATA + EXTRN OLD13:DWORD ;MSBIO2 + EXTRN PTRSAV:DWORD ;MSBIO1 + EXTRN COM1DEV:WORD ;MSAUX + EXTRN DAYCNT:WORD ;MSCLOCK + EXTRN TIM_DRV:BYTE ;MSDATA + EXTRN ACCESSCOUNT:BYTE ;MSDATA + EXTRN SM92:BYTE ;MSDATA + EXTRN DISKSECTOR:BYTE ;MSDATA + EXTRN MEDIABYTE:BYTE ;MSDATA + EXTRN SECPERCLUSINSECTOR:BYTE ;MSDATA + EXTRN BPB_IN_SECTOR:WORD ;MSDATA + EXTRN DISKSECTOR:BYTE ;MSDATA + EXTRN STEP_DRV:BYTE ;MSDATA + EXTRN START_BDS:WORD ;MSDATA + EXTRN PHYS_DRV:BYTE ;MSDATA + EXTRN WRTVERIFY:WORD ;MSDATA + EXTRN FSETOWNER:BYTE ;MSDATA + EXTRN SINGLE:BYTE ;MSDATA + EXTRN RFLAG:BYTE ;MSDATA + EXTRN MEDBYT:BYTE ;MSDATA + EXTRN SPSAV:WORD ;MSDATA + EXTRN SECCNT:WORD ;MSDATA + EXTRN DPT:DWORD ;MSDATA + EXTRN CURSEC:BYTE,CURHD:BYTE ;MSDATA + EXTRN CURTRK:WORD ;MSDATA + EXTRN EOT:BYTE ;MSDATA + EXTRN MOTORSTARTUP:BYTE,SETTLECURRENT:BYTE,SETTLESLOW:BYTE ;MSDATA + EXTRN CURHD:BYTE ;MSDATA + EXTRN LSTERR:BYTE ;MSDATA + EXTRN ERRIN:BYTE,ERROUT:BYTE ;MSDATA + EXTRN PREVOPER:WORD ;MSDATA + EXTRN ORIG13:DWORD ;MSDATA + EXTRN FLAGBITS:WORD ;MSDATA + EXTRN NUMBER_OF_SEC:BYTE ;MSDATA + EXTRN FHAVE96:BYTE ;MSDATA + EXTRN NEW_ROM:BYTE ;MSDATA + EXTRN FORMT_EOT:BYTE,HDNUM:BYTE,TRKNUM:WORD,GAP_PATCH:BYTE ;MSDATA + EXTRN NEXT2F_13:WORD ;MSDATA + extrn Save_head_sttl:byte ;MSdata + extrn Secrete_Code:word ;MSdata +;;Rev 3.30 Modification + + +; +; Maximum number of retries in case of error +; + +MAXERR = 5 +LSTDRV = 504H + + +; +; Some floppy drives do not have changeline support. The result is a +; large amount of inefficiency in the code. A media-check always returns +; "I don`t know". This cause DOS to reread the FAT on every access and +; always discard any cached data. +; We get around this inefficiency by implementing a "Logical Door Latch". +; The following three items are used to do this. The logical door latch is +; based on the premise that it is not physically possible to change floppy +; disks in a drive in under two seconds (most people take about 10). The +; logical door latch is implemented by saving the time of the last successful +; disk operation (in the value TIM_DRV). When a new request is made the +; current time is compared to the saved time. If less than two seconds have +; passed then the value "No Change" is returned. If more than two seconds +; have passed the value "Don't Know" is returned. +; There is one complecation to this algorithm. Some programs change the +; value of the timer. In this unfortunate case we have an invalid timer. +; This possiblity is detected by counting the number of disk operations +; which occur without any time passing. If this count exceeds the value of +; "AccessMax" we assume the counter is invalid and always return "Don't +; Know". The variable "AccessCount" is used to keep track of the number +; of disk operation which occur without the time changing. +; + +AccessMax = 5 + + +; +; Some of the older versions of the IBM rom-bios always assumed a seek would +; have to be made to read the diskette. Consequently a large head settle +; time was always used in the I/O operations. To get around this problem +; we need to continually adjust the head settle time. The following +; algorithm is used: +; +; Get the current head settle value. +; If it is 1, then +; set slow = 15 +; else +; set slow = value +; ... +; if we are seeking and writing then +; use slow +; else +; use fast +; ... +; restore current head settle value +; +; +; flags for size of FAT +; +fTOOBIG EQU 80h +fBIG EQU 40h + +error_unknown_media equ 7 ; for use in BUILD BPB call + +BPB_TYPE STRUC +SECSIZE DW ? +SECALL DB ? +RESNUM DW ? +FATNUM DB ? +DIRNUM DW ? +SECNUM DW ? +FATID DB ? +FATSIZE DW ? +SLIM DW ? +HLIM DW ? +HIDDEN DW ? +BPB_TYPE ENDS +;------------------------------------------------------------------------ +; : +; The next 100 or so lines of code do the Media Check. Media Check : +; determines if the diskette (media) in the drive has been changed. : +; : +; SI is used to hold media check code: : +; -1 media changed : +; 0 Don't know : +; 1 media has not been changed : +; : +; The algorithm used is a follows: : +; if (hard disk) : +; if (changed by format) : +; return (not changed) : +; if not (changed by format) : +; return (changed) : +; else we have a floppy : +; if floppy has change line support go ask the floppy : +; if floppy does not have change line do the following : +; read the time : +; if more than two second have passed return don't know : +; if no time has passed then might be unreliable : +; counter (some program fool with the counter when : +; they should not). See note below for procedure with : +; unreliable counter : +; if sometime has passed but not two second return : +; media has not changed. This is based on the : +; assumption that it is not physically possilbe to : +; change a disk in less the two seconds (most people : +; take about 10 seconds). : +; : +;------------------------------------------------------------------------ + + public media$chk +MEDIA$CHK PROC NEAR + Message ftestdisk,<"Disk Media Check "> + MNUM ftestdisk,AX + Message ftestdisk, + Call SetDrive ; point DS:DI to BDS for specified drive + + cmp cs:Secrete_Code, 'jk' ; Secrete code for + jne media$done ; DOS 3.3 MSBIO. +; +; For non-removable disks only return changed if changed by format, +; otherwise return 'not changed'. +; + + mov si,1 ; assume no change + test word ptr [di].flags,fChanged_By_Format + jz WeAreNotFakingIt + ; reset flag + and word ptr [di].flags,NOT fChanged_By_Format + +; +; If media has been changed by format, must use the ROM. +; Cannot rely on the 2 second time check. +; + mov cs:[TIM_DRV],-1 ; Ensure that we ask the ROM if media + ; has changed + test word ptr [di].flags,fNon_Removable + jz WeHaveAFloppy + mov SI,-1 ; Indicate media changed + jmp short Media$Done +; +; return 'not changed' if disk is a hard file. +; + +WeAreNotFakingIt: + test word ptr [di].flags,fNon_Removable + jnz Media$Done + +; +; If this code is reached disk is a diskette drive +; + +WeHaveAFloppy: + + xor si,si ; Presume "I don't know" + +; +; If drive is a floppy with changeline support the rom is called to +; determine if the media has changed. It is not necessary to do the 2 +; second check on these drives. +; +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in MSINIT ;| + Public Media_Patch ;| +Media_Patch: ;| + CALL MediaCheck ;| + jc Err$Exitj ;| + call HasChange ;| + jnz Media$Done ;| +;----------------------------------------| +; +; If this code is reached the drive is a floppy with no changeline support +; + MOV SI,1 ; PRESUME NO CHANGE + mov al,cs:[TIM_DRV] ; last drive accessed + ;is drive of last access the same? + CMP AL,byte ptr [di].DriveNum + JNZ Media$Unk ; no, then return don't know +; +; CHECK TO SEE IF THIS DRIVE HAS BEEN ACCESSED IN THE LAST 2 SECONDS. +; + call Check_Time_of_Access + jmp short Media$Done + + +Media$Unk: + DEC SI ; RETURN "I DON'T KNOW" + +; +; SI now contains the correct value for media change. Clean up the left overs +; +Media$Done: + les bx,cs:[ptrsav] ; get original packet + mov WORD PTR es:[BX].Trans,SI + or SI,SI + js Init_Patch + jmp EXIT + +MEDIA$CHK ENDP + +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| + Public Init_Patch ;| +INIT_PATCH PROC NEAR ;| + CALL Media_Set_VID ;| +;----------------------------------------| + mov cs:[Tim_Drv],-1 ; make sure we ask ROM for media check +VOLIDOK: + jmp EXIT +INIT_PATCH ENDP + + + +ERR$EXITJ PROC NEAR + + MESSAGE FTESTCOM,<"ERR$EXITJ: "> + MNUM FTESTCOM,AX + MESSAGE FTESTCOM,<" == "> + CALL MAPERROR + MNUM FTESTCOM,AX + MESSAGE FTESTCOM, + JMP ERR$EXIT +ERR$EXITJ ENDP + +; +; PERFORM A CHECK ON THE TIME PASSED SINCE THE LAST ACCESS FOR THIS +; PHYSICAL DRIVE. +; WE ARE ACCESSING THE SAME DRIVE. IF THE TIME OF LAST SUCCESSFUL ACCESS +; WAS LESS THAN 2 SECONDS AGO, THEN WE MAY PRESUME THAT THE DISK WAS NOT +; CHANGED +; RETURNS IN SI: +; 0 - IF TIME OF LAST ACCESS WAS >= 2 SECONDS +; 1 - IF TIME WAS < 2 SECONDS (I.E NO MEDIA CHANGE ASSUMED) +; REGISTERS AFFECTED AX,CX,DX, FLAGS. +; +CHECK_TIME_OF_ACCESS PROC NEAR + PUBLIC CHECK_TIME_OF_ACCESS + mov si,1 ; Presume no change +;;Rev 3.30 Modification + xor AH, AH ; set command to read time + int 1Ah ; call rom-bios clock routine + +; +; Once time is read, must make sure the date wrap is not lost. The ROM will +; return the value only once, it must check for day wrap on each call. +; + SHR AL,1 + ADC CS:[DAYCNT],0 ; ADD IT TO OUR SAVED DAY COUNT +; +; Compute elapsed time +; + MOV AX,WORD PTR DS:[DI].TIM_LO ; GET STORED TIME + SUB DX,AX + MOV AX,WORD PTR DS:[DI].TIM_HI + SBB CX,AX +;;End of Modification +; +; CX:DX is the elapsed time +; + JNZ TimeCheck_Unk ; CX <> 0 => > 1 hour + OR DX,DX ; did some time pass? + JNZ TimePassed ; yes, examine max value +; +; No noticeable time has passed. There are two possiblities. First there +; could be two driver calls with in one clock tick (55 milliseconds). The +; second possiblity is the program has reprogramed the counter -- this is +; the unreliable counter case. To distinguish between the case a count is +; kept of the number of calls that happen without a clock tick (the variable +; is AccessCount). If this count exceeds a set limit (MaxAccess) it is +; assumed the counter is unreliable and the value don't know is returned. +; If AccessCount is less than MaxAccess we assume the time is valid and +; therefor the media has not changed. +; + inc byte ptr cs:AccessCount + ; Exceeded threshold for count? + cmp byte ptr cs:AccessCount,AccessMax + jb TimeCheck_Ret ; no, return media unchanged + dec byte ptr cs:AccessCount ; don't let the count wrap + jmp short TimeCheck_Unk ; "I don't know" if media changed + + +; +; If this code is reached some time has passed. Need to determine if +; 2 seconds have passed. Note: 18.2 ticks per second. +; +TimePassed: + CMP DX,18 * 2 ; IF ( Time_passed <= 2secs ) + JBE TimeCheck_Ret ; presume no change + + +; Everything indicates that we do not know what has happened. +; +TimeCheck_Unk: + DEC SI ; Presume I don't know +TimeCheck_Ret: + RET + +CHECK_TIME_OF_ACCESS ENDP + +ERR$EXITJ2: JMP ERR$EXITJ + + +;------------------------------------------------------------------------ +; : +; Get Bios Parameter Block : +; : +; GET$BPB is called to build a valid BPB for the media in the disk : +; drive. A BPB (Bios Parameter Block) contains information about : +; the media which is currently in the drive. The values stored is : +; information like number of fat sectors, size of drive, 8 or 9 sectors,: +; etc. : +; : +; This routine is called by the device drive code. : +; : +; On entry AL contains the logical drive number which needs : +; the BPB built. : +; ES:[di] points to a buffer; the first byte of the buffer is a : +; media decriptor byte. : +; : +;------------------------------------------------------------------------ +; +; Build a valid BPB for the disk in the drive. +; + + public GET$BPB +GET$BPB PROC NEAR + Message fTestDisk,<"Disk Build BPB "> ; print debug messages + MNUM fTestDisk,AX + Message fTestDisk, + mov AH,byte ptr ES:[DI] ; get FAT IB byte read by DOS + call SetDrive ; get the correct BDS for the drv +;;Rev 3.30 Modification + TEST WORD PTR [DI].FLAGS,FNON_REMOVABLE + JNZ ALREADY_GOTBPB ; NO NEED TO BUILD FOR FIXED DISKS +;;End of Modification + call GETBP ; build a BPB if necessary. + jc Err$exitj2 ; if error exit +GET$BPB ENDP +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| + Public SET_PATCH ;| +SET_PATCH PROC NEAR ;| + CALL set_volume_id ;| +;----------------------------------------| + ; print debug messages + message ftestdisk,<"Set Volume ID"> + mnum ftestdisk,di + message ftestdisk,<" "> + mnum ftestdisk,ds + message ftestdisk, +ALREADY_GOTBPB: + add di,BytePerSec ; return the BPB that is in the current BDS + + PUBLIC SetPTRSAV +SetPTRSAV: ; return point for DSK$INIT + les BX,cs:[PTRSAV] + mov ES:[BX].MEDIA,AH + mov ES:[BX].COUNT,DI + mov ES:[BX].COUNT+2,DS + jmp EXIT +SET_PATCH ENDP + + + + +; +; +; GETBP fills the BDS with the BPB for the media currently in the drive. +; The following steps are followed: +; If the Return_Fake_BPB flag is set then the GETBP just returns. +; If the BDS is for a hard disk (non-removable) then GETBP returns since +; the BPB cannot change on a hard disk drive. +; For all other cases GETBP reads the boot sector and looks for a BPB +; in the boot sector. (All DOS 2.X and about disks should have a valid +; BPB in the boot sector.) +; If no valid BPB is found (DOS 1.X disk) then GETBP reads the FAT +; sector and gets the FAT ID byte. With this byte a valid BPB is build. +; +; Inputs: +; DS:DI points to correct BDS +; +; Outputs: +; Fills in BPB in current BDS if valid BPB or FAT ID on disk. +; Carry set, and AL=7 if invalid disk. +; Carry set and error code in AL if other error. +; + + Public GETBP +GETBP PROC NEAR + ; if non-removable or returning + ; fake BPB then return BPB as is. + TEST WORD PTR [DI].FLAGS,RETURN_FAKE_BPB OR FNON_REMOVABLE + jz GETBP1 + JMP GETRET_EXIT + + +GETBP1: + message ftestdisk,<"Building BPB from scratch",CR,LF> + SaveReg +; +; Attempt to read in boot sector and determine BPB. +; We assume that the 2.x and greater DOS disks all have a valid boot sector. +; +Rdboot: + call ReadBootSec + jnc NoRdErr + jmp GetBP_Err_Ret ; Carry set if there was error. +NoRdErr: + cmp bx,0 ; BX is 0 if boot sector is valid. + jnz DoFatBPB ; if not go read FAT + + call MovBPB ; Move BPB into registers. + jmp Has1 + +; +; At this point the drive contains a 1.X diskette. We read the FAT byte +; and fill in the BPB from there. +; + +DoFatBPB: + call ReadFat ; puts media descriptor byte in AH + jc GetBP_Err_Ret ; if carry set, there was error, get out + +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| +Public GETBP1_PATCH ;| +GETBP1_PATCH: ;| + call hidensity ;| +;----------------------------------------| +; Test for a valid 3.5" medium + cmp [di].FormFactor, ffsmall + jnz Is_Floppy + cmp ah,0F9H ; is it a valid fat ID byte for 3.5" ? + jnz Got_Unknown_Medium + mov bx,offset sm92 ; pointer to correct BPB + push cs + pop es +ASSUME ES:CODE +;--------------------------------------------------------------bug330a08 + mov al,es:[bx.spf] + mov cx,es:[bx.csec] + mov dx,word ptr es:[bx.spa] + mov bx,word ptr es:[bx.spt] +;--------------------------------------------------------------bug330a08 + jmp short HAS1_res ; Need to load reserved sectors +; +; must be a 5.25" floppy if we come here +; +Is_Floppy: + mov CL,AH ; save media + and CL,0F8H ; normalize + cmp CL,0F8H ; cmopare with good media byte + jnz Got_Unknown_Medium + +GOODID: mov AL,1 ; set number of FAT sectors + mov BX,64*256+8 ; set dir entries and sector max + mov CX,40*8 ; set size of drive + mov DX,01*256+1 ; set head limit and sec/all unit + test AH,00000010B ; test for 8 or 9 sectors + jnz HAS8 ; NZ = has 8 sectors + inc AL ; inc number of FAT sectors + inc BL ; inc sector max + add CX,40 ; increase size +HAS8: test AH,00000001B ; test for 1 or 2 heads + jz HAS1_res ; Z = 1 head + add CX,CX ; double size of disk + mov BH,112 ; increase number of directory entries + inc DH ; inc sec/all unit + inc DL ; inc head limit + +PUBLIC HAS1_res +HAS1_res: + mov si,word ptr ds:[di].RESSEC +PUBLIC HAS1 ; save values in BDS +HAS1: mov byte ptr ds:[DI].SecPerClus,DH + mov byte ptr ds:[DI].cDir,BH + mov word ptr ds:[DI].Drvlim,CX + mov byte ptr ds:[DI].Mediad,AH + mov byte ptr ds:[DI].csecFat,AL + mov byte ptr ds:[DI].SecLim,BL + mov byte ptr ds:[DI].HdLim,DL + mov word ptr ds:[DI].RESSEC,SI +GETRET: pop BX + RestoreReg +ASSUME ES:NOTHING +GETRET_Exit: + RET + +GetBP_Err_Ret: + CALL MapError + JMP SHORT GETRET + +; +; We have a 3.5" diskette for which we cannot build a BPB. We do not assume any +; type of BPB for this medium. +; +Got_Unknown_Medium: + mov al,error_unknown_media + stc + jmp short GETRET + +GETBP ENDP + +bpbType struc +spf db ? +spt db ? +cdire db ? +csec dw ? +spa db ? +chead db ? +bpbType ends + +; +; end of GET$BPB code +;------------------------------------------------- + +; +; Read in the boot sector. Set carry if error in reading sector. +; BX is set to 1 if the boot sector is invalid, otherwise it is 0. +; +READBOOTSEC PROC NEAR + mov CX, 0001h ; set track and sector number + xor DH, DH ; set head number for read_sector + call read_sector + jc Err_Ret ; error - get out + xor bx,bx ; assume valid boot sector. + + ; at this point the boot sector has been + ; read in from the disk. We now need to + ; determine if the boot sector contains + ; a valid BPB. Currently there are only + ; a few simple checks. Expanding the + ; number or types of checks would not be + ; a bad idea. +;******************************************************************************* +; Put a sanity check for the boot sector in here to detect boot sectors that +; do not have valid BPBs. +; We examine the first two bytes - they must contain a long jump or a short +; jump followed by a NOP. +; If this test is passed, we further check by examining the signature at +; the end of the boot sector for the word AA55H. +; If the signature is not present, we examine the media descriptor byte to +; see if it is valid. +;****************************************************************************** + cmp byte ptr cs:[DiskSector],069H ; Is it a direct jump? + JE Check_bpb_MediaByte ; DON'T NEED TO FIND A NOP + cmp byte ptr cs:[DiskSector],0E9H ; DOS 2.0 jump? + JE Check_bpb_MediaByte ; NO NEED FOR NOP + cmp byte ptr cs:[DiskSector],0EBH ; How about a short jump. + JNE INVALIDBOOTSEC + cmp byte ptr cs:[DiskSector]+2,090H ; Is next one a NOP? + JNE INVALIDBOOTSEC + + +; Don't have to perform the following signature check since +; we need to check the media byte even with the good signatured diskette. +;CHECK_SIGNATURE: +; CMP WORD PTR CS:[DISKSECTOR+1FEH],0AA55H ; SEE IF NON-IBM +; ; DISK OR 1.X MEDIA. +; JZ CHECKSINGLESIDED ; GO SEE IF SINGLE SIDED MEDIUM. +; ; MAY NEED SOME SPECIAL HANDLING +; +; CHECK FOR NON-IBM DISKS WHICH DO NOT HAVE THE SIGNATURE AA55 AT THE +; END OF THE BOOT SECTOR, BUT STILL HAVE A VALID BOOT SECTOR. THIS IS DONE +; BY EXAMINING THE MEDIA DESCRIPTOR IN THE BOOT SECTOR. +; + +;;Rev 3.30 Modification +Check_bpb_MediaByte: + + MOV AL,BYTE PTR CS:MEDIABYTE + AND AL,0F0H + CMP AL,0F0H ; ALLOW FOR STRANGE MEDIA + JNZ INVALIDBOOTSEC +; +; THERE WERE SOME (APPARENTLY A BUNCH) DISKETTES THAT HAD BEEN FORMATTED +; UNDER DOS 3.1 AND EARLIER VERSIONS WHICH HAVE INVALID BPBS IN THEIR BOOT +; SECTORS. THESE ARE SPECIFICALLY DISKETTES THAT WERE FORMATTED IN DRIVES +; WITH ONE HEAD, OR WHOSE SIDE 0 WAS BAD. THESE CONTAIN BPBS IN THE BOOT +; SECT THAT HAVE THE SEC/CLUS FIELD SET TO 2 INSTEAD OF 1, AS IS STANDARD +; IN DOS. TO SUPPORT THEM, WE HAVE TO INTRODUCE A "HACK" THAT WILL +; HELP OUR BUILD BPB ROUTINE TO RECOGNISE THESE SPECIFIC CASES, AND TO +; SET UP OUT COPY OF THE BPB ACCORDINGLY. +; WE DO THIS BY CHECKING TO SEE IF THE BOOT SECTOR IS OFF A DISKETTE THAT +; IS SINGLE-SIDED AND IS A PRE-DOS 3.20 DISKETTE. IF IT IS, WE SET THE +; SEC/CLUS FIELD TO 1. IF NOT, WE CARRY ON AS NORMAL. +CHECKSINGLESIDED: + MOV AL,BYTE PTR CS:MEDIABYTE + TEST AL,0001H ; IS LOW BIT SET? - INDICATES DOUBLE SIDED + JNZ GOODDSK + CMP WORD PTR CS:[DISKSECTOR+8],"." SHL 8 + "3" + JNZ MUSTBEEARLIER + CMP BYTE PTR CS:[DISKSECTOR+10],"2" + JAE GOODDSK + +; WE MUST HAVE A PRE-3.20 DISKETTE. SET THE SEC/CLUS FIELD TO 1 +MUSTBEEARLIER: + MOV BYTE PTR CS:[SECPERCLUSINSECTOR],1 + JMP SHORT GOODDSK + +INVALIDBOOTSEC: + INC BX ; SET THAT BOOT SECTOR INVALID +;;End of Modification + +GoodDsk: ; carry already reset + clc + ret + +Err_Ret: ; carry is already set on entry here + message ftestdisk,<"error in readboot",cr,lf> + ret + +READBOOTSEC ENDP + +; +; MovBPB moves the BPB read from the Boot sector into registers for use by +; GETBP routine at Has1 +; +MOVBPB PROC NEAR + SaveReg + push cs + pop ds + mov di,offset BPB_In_Sector + mov dh,Byte Ptr [di].secall ;sectors per unit + mov bh,Byte Ptr [di].dirnum ;number of directory entries + mov cx,Word Ptr [di].secnum ;size of drive + mov ah,Byte Ptr [di].fatid ;media descriptor + mov al,Byte Ptr [di].fatsize ;number of FAT sectors + mov bl,Byte Ptr [di].slim ;sectors per track + mov dl,Byte Ptr [di].hlim ;number of heads + mov si,word ptr [di].resnum ;reserved sectors + RestoreReg + ret +MOVBPB ENDP + + + +; +; Read in the FAT sector and get the Media Byte from it. +; Input : AL contains logical drive. +; Output: +; Carry set if an error occurs, AX contains error code. +; Otherwise, AH contains media byte on exit. AL is preserved. + +READFAT PROC NEAR + push ax ; preserve logical drive in AL + MOV DH,0 ; HEAD 0 + mov CX,0002 ; set track and sector number + call read_sector ; CS:BX points to fat sector + jc Bad_FAT_Ret ; error, get out + pop ax ; reset logical drive + mov ah,Byte Ptr CS:[BX] ; media byte + ret + +Bad_FAT_Ret: ; carry set on entry + message ftestdisk,<"error in FAT read",cr,lf> + pop cx ; clear stack + ret +READFAT ENDP + + + +; +; Read_sector reads a single sector into the tempory buffer 'DiskSector'. +; Up to three retries are done in case of error. +; +; Inputs: +; DS:DI points to BDS for drive +; CH - track number +; CL - sector number +; DH - head number +; +; Outputs: +; If carry is clear -- successful read +; CS:BX points to buffer holding sector +; AX, BX are not preserved, CX, DX, BP, and ES are preserved +; +; If carry is set -- error on read +; AX, BX, and DX are not preserved; CX, BP, and ES are preserved +; +; + +READ_SECTOR PROC NEAR + PUBLIC READ_SECTOR + push BP ; preserve BP register + mov BP,3 ; BP is retry count, set to 3 + push ES ; preserve ES also + mov DL, byte ptr [di].DriveNum + mov BX, offset DiskSector ; Get ES:BX to point to buffer + push CS ; get the segment right + pop ES ; now ES:BX is correct + +RD_RET: + ; set command to read (AH=2) and + mov AX, 0201h ; number of sectors to 1 (AL=1) + int 13h ; call rom-bios disk routines + + jnc OKRET2 ; if no carry then no error - done +Rd_rty: + call Again ; reset disk and decrement BP + jz Err_RD_RET + test word ptr ds:[di].flags,fNon_Removable + JNZ RD_RET +;;Rev 3.30 Modification ----------------------------------------- + push ds ; For retry, set head settle + push ax ; time to 0Fh. + lds si,cs:DPT + mov al, ds:[si].disk_head_sttl + mov cs:[save_head_sttl],al + mov byte ptr ds:[si].disk_head_sttl, NormSettle + pop ax + pop ds + ; SET CMD TO READ (AH=2) AND + MOV AX, 0201h ; NUM OF SECTORS TO 1 (AL=1) + INT 13h ; CALL ROM-BIOS DISK ROUTINES + push ds + push ax + lds si,cs:DPT + mov al, cs:[save_head_sttl] + mov byte ptr ds:[si].disk_head_sttl, al + pop ax + pop ds + jnc OKRET2 + jmp Rd_rty +ERR_RD_RET: + MOV DL,-1 ; MAKE SURE WE ASK ROM IF MEDIA CHANGED + STC ; RETURN ERROR +;;End of Modification ----------------------------------------- + + ; Update information pertaining to last drive + ; accessed, time of access, last track accessed + ; in that drive. +OKRET2: + ; set up for head settle logic in DISK + mov CS:[STEP_DRV],DL ; save last drive accessed + mov CS:[TIM_DRV],DL ; save the values + mov byte ptr [di].track,CH ; + pushf ; save the flags + call SET_TIM + popf ; restore flags + pop ES ; restore registers + pop BP + ret + +READ_SECTOR ENDP + + + +;------------------------------------------------------------------------ +; : +; Disk Removable Routine : +; : +; This routine determines if a particular logical drive has : +; removable media. : +; : +; Input : +; AL contains the logical drive number which the check is being : +; done. : +;------------------------------------------------------------------------ + +DSK$REM PROC NEAR ;ARR 2.41 + PUBLIC DSK$REM + Message fTestDisk,<"Disk Removable "> ; print debug messages + MNUM fTestDisk,AX + Message fTestDisk, + ; AL is logical unit number + call SetDrive ; get BDS for this drive + test word ptr [di].flags,fNon_Removable + jnz NON_REM + jmp EXIT + +NON_REM: ; if non removable set busy bit + jmp BUS$EXIT + +DSK$REM ENDP + + + +; +; SetDrive scans through the data structure of BDSs and returns a +; pointer to the BDS that belongs to the drive specified in AL. +; Carry is set if no BDS has a logical drive number which matches the +; value in AL. +; Input: +; AL contains the logical drive number +; Output: +; DS:DI points to correct BDS if Carry is clear. +; +; All register execpt DS and DI are preserved +; + + Public SetDrive +SETDRIVE PROC NEAR + message ftestdisk,<"SetDrive",cr,lf> ; print debug messages + push bx + push cs + pop ds + ; assume first BDS is in this segment + ASSUME DS:CODE + mov di,word ptr Start_BDS +Scan_Loop: +;;Rev 3.30 Modification ----------------------------------------- + CMP BYTE PTR CS:[PHYS_DRV],1 ; DOES AL HAVE PHYS DRV? + JB USE_LOGICAL_DRV + CMP BYTE PTR [DI].DRIVENUM,AL + JE SETDRV + JMP SHORT GET_NXT_BDS +USE_LOGICAL_DRV: + CMP BYTE PTR [DI].DRIVELET,AL + JE SETDRV +GET_NXT_BDS: + MOV BX,WORD PTR [DI].LINK+2 ; GO TO NEXT BDS + MOV DI,WORD PTR [DI].LINK + mov ds,bx + ASSUME DS:NOTHING +;;End of Modification ----------------------------------------- + + cmp di,-1 ; at end of list? + jnz Scan_Loop ; no, keep looking + stc ; yes, indicate error set carry +SetDrv: + pop bx ; restore bx + ret ; return + +SETDRIVE ENDP + + + +;------------------------------------------------------------------------ +; : +; DISK I/O ROUTINES : +; : +; On entry the register contain the following values: : +; : +; AH - Media Descriptor byte : +; AL - logical drive number : +; CX - count of sectors to be read or written : +; DX - start sector : +; DI - offset of destination buffer : +; : +;------------------------------------------------------------------------ + + +;------------------------------------------------------------------------ +; : +; Disk Write with Verify : +; : +; Input : +; See about header for register contents on entry. : +; : +;------------------------------------------------------------------------ + + +DSK$WRITV PROC NEAR + PUBLIC DSK$WRITV + Message fTestDisk,<"Disk Write with verify "> + MNUM fTestDisk,AX + Message fTestDisk,<" "> + MNUM fTestDisk,DX + Message fTestDisk,<" for "> + MNUM fTestDisk,CX + Message fTestDisk, + MOV CS:[WRTVERIFY],103H + JMP SHORT DSK$CL + +;------------------------------------------------------------------------ +; : +; Disk Write : +; : +; Input : +; See about header for register contents on entry. : +; : +;------------------------------------------------------------------------ + +DSK$WRIT: + PUBLIC DSK$WRIT + Message fTestDisk,<"Disk Write "> + MNUM fTestDisk,AX + Message fTestDisk,<" "> + MNUM fTestDisk,DX + Message fTestDisk,<" for "> + MNUM fTestDisk,CX + Message fTestDisk, + MOV CS:[WRTVERIFY],ROMWrite + +DSK$CL: + CALL DISKIO +DSK$IO: + JC DSKBad + JMP EXIT +DSKBad: + JMP ERR$CNT + +DSK$WRITV ENDP + + +;------------------------------------------------------------------------ +; : +; Disk Read : +; : +; Input : +; See about header for register contents on entry. : +; : +;------------------------------------------------------------------------ + +DSK$READ PROC NEAR + PUBLIC DSK$READ + Message fTestDisk,<"Disk Read "> + MNUM fTestDisk,AX + Message fTestDisk,<" "> + MNUM fTestDisk,DX + Message fTestDisk,<" for "> + MNUM fTestDisk,CX + Message fTestDisk, + CALL DISKRD + JMP DSK$IO +DSK$READ ENDP +; +; Miscellaneous odd jump routines. Moved out of mainline for speed. +; + + +; +; CheckSingle determines if the drive specified is a virtual drive (more +; than one logical drive associated with one physical drive). If this +; is the case we need to prompt the user to place the correct disk in +; the drive. +; +; Input: +; DS:DI pints to the BDS for the drive being checked. +; +; If there is a error the carry flag is set on return +; +; All registers are preserved. +; + +CHECKSINGLE PROC NEAR + PUBLIC CHECKSINGLE + push AX ; save affected registers + push BX + mov BX,word ptr ds:[di].flags + TEST BL,FNON_REMOVABLE OR FI_OWN_PHYSICAL ;Can't change disk + jnz SingleRet ; on hard drive so return + ; is there a drive sharing this + TEST BL,FI_AM_MULT ; physical drive? + jz SingleRet ; if not, then return + + ; At this point there is more than one + ; logical drive mapped to this physical drive. + ; But the drive being accessed is not the + ; owner of the physical drive. What needs to + ; be done is find the current owner BDS and + ; turn off the owner flag and then make current + ; BDS the owner of the drive. Then prompt the + ; user to change disks. + mov al,ds:[di].DriveNum ; get physical drive number + push ds ; preserve pointer to current BDS + push di + push cs + + pop ds ; Point to start of BDS linked list + ASSUME DS:CODE + + mov di,offset Start_BDS + +Scan_List: + mov bx,word ptr [di].link+2 ; go to next BDS + mov di,word ptr [di].link + mov ds,bx + ASSUME DS:NOTHING + + cmp di,-1 ; end of list? + jz single_err_ret ; if so there must be an error + ; same physical drive? + cmp byte ptr [di].DriveNum,al + jnz Scan_List ; no, keep looking + +Check_Own: ; yes, check to see if owner + mov bx,word ptr [di].flags + test bl,fI_Own_Physical + jz Scan_List ; not owner, keep looking + xor bl,fI_Own_Physical ; yes owner reset ownership flag + mov word ptr ds:[di].flags,bx + pop di ; Restore pointer to current BDS + pop ds + xor bx,bx + or bl,fI_Own_Physical ; establish current BDS as owner + or word ptr [di].flags,bx + + + ; + ; We examine the fSetOwner flag. If it is + ; set, then we are using the code in + ; CheckSingle to just set the owner of + ; a drive. We must not issue the prompt + ; in this case. + ; + + cmp byte ptr cs:[fSetOwner],1 + jz SingleRet + ; + ; To support "backward" compatibility with + ; IBM's "single drive status byte" we now + ; check to see if we are in a single drive + ; system and the Application has "cleverly" + ; diddled the SDSB (Single Drive Status Byte) + ; + + cmp cs:[single],2 ; single drive system? + jne short Ignore_SDSB ; no, jump down + + SaveReg ; yes... + mov al,ds:[di].DriveLet ; IF (Curr_drv == Req_drv) + mov ah,al + xor di,di + mov ds,di + xchg al,ds:byte ptr LSTDRV ; THEN swap(Curr_drv,Req_drv) + cmp ah,al ; ELSE + RestoreReg ; swap(Curr_drv,Req_drv) + je SingleRet ; Issue Swap_dsk_msg + +Ignore_SDSB: + call SWPDSK ; ask user for correct disk + +SingleRet: + pop BX ; restore registers + pop ax + ret ; return + +Single_Err_Ret: + stc ; set carry flage to indicate error + pop di ; restore current BDS + pop ds + jmp short SingleRet + + +; +; BadDrive is called when sector specified is greater than last +; sector on disk. +; or when BDS is not found for drive +; + +BadDrive: + mov AL,8 ; error code 'sector not found' + stc ; indicate error +IORET: ret ; return + + + +BogusSettle: + MOV AL,NormSettle ; someone has diddled the settle + JMP GotSlowSettle + +CHECKSINGLE ENDP + + + + +;------------------------------------------------------------ +; +; DISK I/O HANDLER +; +; On entry: +; AL = Drive Number (0-6) +; AH = media Descriptor +; CX = sector count +; DX = first sector +; DS = CS +; ES:DI = transfer address +; [RFLAG] = operation (2 for read, 3 for write) +; [VERIFY] = 1 for verity after write +; +; On exit: +; if successful carry flag = 0 +; else CF=1 and AL contains error code +; + + + Public DISKRD +DISKRD PROC NEAR + mov CS:[RFLAG],ROMRead ; set command to read + +DISKIO: + mov BX,DI ; ES:BX is transfer address + Call SetDrive ; map logical and physical + jc BadDrive ; carry means BDS not found + mov al,BYTE PTR DS:[DI].Mediad + mov cs:MedByt,al ; Preserve media byte for drive for use + ; in determining media change. + jcxz IORET + mov cs:[SPSAV],SP ; save the sp value +; +; Ensure that we are trying to access valid sectors on the drive +; + mov SI,DX ; start with first sector + add SI,CX ; add in sector count + add DX,WORD PTR [DI].HIDSEC ; add in the hidden sectors + cmp SI,WORD PTR [DI].DRVLIM ; compare against drive maximum + ja BADDRIVE ; if greater than max, error + mov cs:[SECCNT],CX ; save sector count +;;Rev 3.30 Modification ----------------------------------------- +; SET UP POINTER TO DISK BASE TABLE IN [DPT]. WE CANNOT ASSUME THAT IOSETUP +; WILL DO IT BECAUSE WE WILL SKIP THE SET UP STUFF WITH HARD DISKS. + PUSH DS + XOR AX,AX + MOV DS,AX + LDS SI,DWORD PTR DS:[DSKADR]; CURRENT DISK PARM TABLE + MOV WORD PTR CS:DPT,SI + MOV WORD PTR CS:DPT+2,DS + POP DS +;;End of Modification ----------------------------------------- +; +; For hard drives do not do media check or set DPT. +; + test word ptr [di].flags,fNon_Removable + jnz Skip_Setup + CALL CHECKSINGLE +; +; Check to see if we have previously noted a change line. The routine +; returns if everything is OK. Otherwise, it pops off the stack and returns +; the proper error code. +; +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| + Public DiskIO_Patch ;| +DiskIO_PATCH: ;| + CALL CheckLatchIO ;| +;----------------------------------------| +; +; Set up tables and variables for I/O + call IOSetUp +; +; Now the settle values are correct for the following code +; +Skip_Setup: + mov AX,DX ; setup locical sector for divide + xor DX,DX + div word ptr [DI].SECLIM ; divide by sectors per track + inc DL + mov cs:[CURSEC],DL ; save current sector + mov CX,word ptr [DI].HDLIM ; get number of heads + xor DX,DX ; divide tracks by heads per cylinder + div CX + mov cs:[CURHD],DL ; save current head + mov cs:[CURTRK],AX ; save current track +; +; We are now set up for the I/O. Normally, we consider the DMA boundary +; violations here. Not true. We perform the operation as if everything is +; symmetric; let the DISK INT handler worry about the DMA violations. +; + mov AX, cs:[SECCNT] + call BLOCK + call DONE + ret + +DISKRD ENDP + + + +; +; IOSetUp: +; +; IOSetUp does the following functions: +; * Set the drive-last-accessed flag (for diskette only). No need to +; update these flags for hard disks becuase we know a hard disk will +; not be removed. +; * Set the proper last sector number in the Disk Parameter Table (DPT) +; * Set the proper motor start up time in DPT +; * Set the proper head settle time in the DPT +; +; Input: +; DS:DI -> current BDS. +; Output: +; AX,CX,SI are destroyed. +; + public IOSetUp +IOSETUP PROC NEAR + MOV AL,[DI].DRIVENUM + MOV CS:[TIM_DRV],AL ; SAVE DRIVE LETTER +; +; determine proper head settle values +; + mov CX,DS + LDS SI,DWORD PTR CS:[DPT] ; GET POINTER TO DISK BASE TABLE + MOV AL,CS:[EOT] + mov [SI].DISK_EOT,AL ; bump for us + mov AL,[si].DISK_Motor_Strt ; preserve old motor start time + mov cs:MotorStartup,AL +; +; For 3.5" drives, both external as well as on the K09, we need to set the +; Motor Start Time to 4. This checking for every I/O is going to affect +; performance across the board, but is necessary!! +; + push es + mov es,cx ; ES:DI -> to current BDS + cmp byte ptr es:[di].FormFactor,ffsmall + jnz Motor_Start_OK + mov AL,4 + xchg AL,[si].DISK_MOTOR_STRT +Motor_Start_OK: + pop ES +; +; DS:SI now points to disk parameter table. Get current settle and set fast +; settle +; + + XOR AL,AL + INC AL ; IBM WANTS FAST SETTLE = 1 - RS + xchg AL,[SI].DISK_Head_Sttl ; get settle and set up for fast + mov cs:SettleCurrent,AL + MOV AL,NORMSETTLE ; SOMEONE HAS DIDDLED THE SETTLE +GotSlowSettle: + mov DS,CX + mov cs:SettleSlow,AL + ret + + + + +; +; Set time of last access, and reset default values in the DPT. +; +DONE: + test word ptr [di].Flags,fNon_Removable + jnz RETZ ; Do not set for non-removable Media + call SET_TIM ; set time of last access for drive +; +; Restore head settle and EOT values +; +DiddleBack: + push ax ; preserve AX + mov DX,DS ; save DS in DX + mov AL,cs:SettleCurrent ; get value in registers + mov AH,cs:MotorStartup + lds SI,cs:DPT ; get pointer to DPT + mov [SI].Disk_EOT,9 ; save values in DPT + mov [SI].Disk_Head_Sttl,AL + mov [si].Disk_Sector_Siz,2 + mov [si].Disk_Motor_Strt,AH + mov DS,DX ; restore DS + pop ax ; restore AX +RETZ: + ret + + + + + +; +; Block reads or writes the number of sectors specified in AX +; handling track boundaries. For example, on an 8 sector per track +; disk there might be a request to read 6 sectors starting at the 5th +; sector. Block breaks this request into a read of sectors 5-8 on +; the first track and a read of sectors 1-2 on the next track. Disk is +; called to do the actual read. +; +; Inputs: +; AX - number of sectors to be read +; DS:DI points to BDS for disk drive +; cs:CurSec - sector on track where read should start +; cs:CurTrk - track where read should start +; cs:CurHd - head for read +; ES:BX - transfer address +; AX, CX, and BL are not preserved +; + +BLOCK: + or AX,AX ; see if any sectors to read + jz RETZ ; if not, return +;;Rev 3.30 Modification ----------------------------------------- +; Fixed disk will not be restricted to the trk-by-trk basis. + test word ptr [di].Flags, fNon_Removable + jz BLOCK_FLOPPY + call DISK + xor ax,ax + RET +BLOCK_FLOPPY: +;;End of Modification ----------------------------------------- +; +; READ AT MOST 1 TRACK WORTH. PERFORM MINIMIZATION AT SECTOR / TRACK +; + mov CL,byte ptr [DI].SecLim ; get sectors per track + inc CL + sub CL,cs:CurSec ; set CX to number of sector after current + xor CH,CH ; sector on the current track + cmp AX,CX ; is all of request on current track? + jae GotMin ; no, jump down + mov CX,AX ; yes, set number of sector on this track to AX +GotMin: + ; now + ; AX is the requested number of sectors to read + ; CX is the number that we can do on this track + push AX + push CX + mov AX,CX ; AL is number of sectors to read + call Disk + pop CX + pop AX + + ; CX is the number of sectors just transferred + sub AX,CX ; reduce sectors-remaining by last I/O + shl CL,1 + add BH,CL ; adjust transfer address + jmp Block ; jump to do any remaining sectors + +IOSETUP ENDP + + + + + +; +; DISK: +; Disk is called to read or write one or more sectors on a track. +; Retries are make if an error occurs. +; +; Input: +; AL - number of sector to be read/written (they must all be on one track) +; DS:DI points to BDS for the drive +; ES:BX is transfer address (must not cross 64k physical boundry) +; [RFLAG] is 2 for read and 3 for write +; [VERIFY] is 0 for normal, 1 for verify after write +; [CurTrk] is track (cylinder) to be read/written. +; [CurHd] is head to be used in operation. +; [CurSec] is sector to start read on. +; +; The following are overwritten: BP, +; Output: +; [SECCNT] is decrement by the number of sectors read or written + + + public disk +DISK PROC NEAR + mov BP,MAXERR ; set up retry count + MOV AH,CS:RFLAG ;GET READ/WRITE INDICATOR + +RETRY: + ; AX is overwritten in int 13 call, so + ; to do a retry we need to save the + ; value by pushing on the stack + push AX + ; the next five lines of code put the + ; sector number in bit 5-0 of CL and the + ; cylinder number in CH and bits 7-6 of + ; CL. The register must be set up in this + ; way for the bios. + mov DX,cs:[CURTRK] ;Load current cylinder +;;Rev 3.30 Modification ----------------------------------------- + test word ptr [di].FLAGS, fNon_Removable ;Fixed disk + jz DISK_NOT_MINI ;no, skip this. + cmp [di].IsMini, 1 ;Is this a mini disk? + jnz DISK_NOT_MINI ;No. continue to next. + add dx, [di].Hidden_Trks ;else add hidden trks. +DISK_NOT_MINI: +;;End of Modification ----------------------------------------- + ror DH,1 ; get high two bits of cylinder in correct place + ror DH,1 + + or DH,cs:[CURSEC] ; get sector value + mov CX,DX ; put cylinder/sector values in correct register + ; get head value + xchg CH,CL ; put bytes in correct place + mov DH,byte ptr cs:[CurHD] + ; get drive number + mov DL,byte ptr [DI].DriveNum + + CMP BYTE PTR [DI].FORMFACTOR,FFHARDFILE + JZ DO_FAST ; HARD FILES USE FAST SPEED +; +; The registers are now all set up for call on rom-bios. +; The next dozen or so line determines whether we call Do_Fast or Do_Norm +; for the actual I/O read. Do_Fast calls FastSpeed for the actual I/O. +; Do_Norm calls NormSpeed. NormSpeed changes the value for the head settle +; time in the disk parameter table to a larger value and then calls FastSpeed +; to do the I/O. So Do_Fast just has a shorter head settle time. +; + CMP CS:[STEP_DRV],-1 + jz Do_Writej + + cmp AH,ROMRead ; For read... + je Do_Fast ; ... alway use fast + + cmp AH, ROMVerify ; For verify... + je Do_Fast ; ... alway use fast + +Do_Writej: + jmp DO_Write ; Jump down for write... + + +DO_Fast: + CALL FastSpeed ; do I/O carry set if error +TestErr: + jc DSKERR ; error -- get out +; SET DRIVE AND TRACK OF LAST ACCESS + mov cs:[STEP_DRV],DL ; save the last drive accessed + mov byte ptr [di].track,CH ; save in BDS + +NO_SET: + cmp CS:WRTVERIFY,103H ; Check for write and verify + jz DoVerify ; yes -- go do verify +NOVERIFY: + pop AX ; pop command and num sec. from stack + and CL,03FH ; Eliminate cylinder bits from sector + xor AH,AH + sub cs:[SECCNT],AX ; Reduce count of sectors to go + add CL,AL ; Next sector + mov cs:[CURSEC],CL + cmp CL,BYTE PTR [DI].SECLIM ; See if sector/track limit reached + jbe Disk_Ret ; yes, return +NextTrack: + mov cs:[CURSEC],1 ; Start with first sector of next track + mov DH,CS:[CURHD] + inc DH ; go to next head + cmp DH,BYTE PTR [DI].HDLIM ; at head limit? + jb NOXOR ; no, jump down + xor DH,DH ; at head limit, reset to head zero ... + inc cs:[CURTRK] ; and go to next head +NOXOR: + mov cs:[CURHD],DH ; save new head number +Disk_Ret: + clc ; successful return so clear error flag + ret ; all done +DISK ENDP +; +; The request is for write. Determine if we are talking about the same +; track and drive. If so, use the fast speed. +; +DO_WRITE PROC NEAR + cmp DL,cs:[STEP_DRV] ; same drive? + jnz DO_Norm ; no, do normal speed + cmp CH,byte ptr [di].track ; same track on drive + jz DO_Fast ; yes, do fast speed +DO_Norm: + call NormSpeed ; use larger head settle time + jmp SHORT TestErr ; test for error + +DO_WRITE ENDP + + +; +; we have a verify request also. Get state info and go verify +; + +DOVERIFY PROC NEAR + pop AX ; get number of sectors from stack + push AX ; in non-detructive fashion + MOV AH,ROMVERIFY ; REQUEST VERIFY + CALL FastSpeed ; MZ 2.21 change settle mode + JNC NoVerify +DOVERIFY ENDP + +; +; Need to special case the change-line error AH=06h. If we get this, we +; need to return it. +; +;----------------------------------------| +; Warning: Do not change the following. ;| +; It gets patched in msinit ;| + Public DSKERR ;| +DSKERR PROC NEAR ;| + CALL CheckIO ;| +;---------------------------------------;| + + Call AGAIN ; reset the disk and decrement retry cnt + jz HARDERR ; if z flag set, did all retries-give up + cmp AH,80H ; timeout? + jz HARDERR ; yes, jump to hard error +DSKERR1: + pop AX ; Restore sector count + jmp RETRY ; and try again + +HARDERR: + PUBLIC HARDERR + CALL MapError + +HARDERR2: ; for routines that call MapError themselves + PUBLIC HARDERR2 + mov cs:[Tim_Drv],-1 ;Force a media check through ROM + mov CX,cs:SECCNT ;Get count of sectors to go + mov SP,cs:[SPSAV] ;Recover entry stack pointer +; +; Since we are performing a non-local goto, restore the disk parameters +; +MedByt_OK: + call DiddleBack + ret ;and return + +DSKERR ENDP + + +; +; change settle value from SettleCurrent to whatever is appropriate +; +NORMSPEED PROC NEAR + push DS ; save two registers + push AX + mov AL,cs:SettleSlow ; change value in current disk parm tbl + lds SI,cs:DPT ; current disk parm table + mov [SI].Disk_Head_Sttl,AL + pop AX ; restore command and sector count + pop DS + call FastSpeed ; do I/0 + push DS ; restore the value in disk parm table + lds SI,cs:DPT + mov [SI].Disk_Head_Sttl,1 ; 1 is fast settle + pop DS + ret + +NORMSPEED ENDP + + +FASTSPEED PROC NEAR +; +; If the drive has been marked as too big (i.e. starting sector of the +; partition is > 16 bits, then ALWAYS return drive not ready. +; + TEST BYTE PTR [DI].FatSiz,fTOOBIG + + + IF TEST + JZ Ready ; if debugging use jmp rather + JMP NotReady ; than local jnz +Ready: + else + JNZ NotReady + endif + + Message fTestINIT,<"<"> ; print debug messages + MNUM fTestINIT,AX + Message fTestINIT,<","> + MNUM fTestINIT,ES + Message fTestINIT,<":"> + MNUM fTestINIT + Message fTestINIT,<","> + MNUM fTestINIT,CX + Message fTestINIT,<","> + MNUM fTestINIT,DX + Message fTestINIT,<">"> + + int 13h ; call rom-bios disk routines + +Death: + ret +NotReady: + stc ; set carry to indicate error + mov AH,80h ; put error code in AH + jmp Death ; jump to ret + +FASTSPEED ENDP + + +; +; Map error returned by ROM into corresponding code to be returned to +; DOS in AL. +; +MAPERROR PROC NEAR + PUBLIC MAPERROR + push CX ; save cx + push CS + pop ES ; make ES the local segment + mov AL,AH ; move error code into AL + mov cs:[LSTERR],AL ; terminate list with error code + mov CX,NUMERR ; number of possible error conditions + mov DI,OFFSET ERRIN ; point to error conditions + repne SCASB + mov AL,cs:[DI + NUMERR - 1] ; get translation + pop cx ; restore cx + stc ; flag error condition + ret +MAPERROR ENDP + +; +; Set the time of last access for this drive. This is done only for removable +; media. +; + public SET_TIM +SET_TIM PROC NEAR + push ax + xor AH, AH ; set command to get time + int 1Ah ; call rom-bios timer function + or AL,AL ; is there 24 hour rollover? + jz NOROLL3 ; no, skip down + inc cs:[DayCnt] ; yes, then increment DayCnt +NOROLL3: +; We have the new time. If we see that the time has passed, then we reset +; the threshold counter... + cmp DX,word ptr [di].TIM_LO ; Did any time pass? + jnz SetAccess ; yes, update access time + cmp CX,word ptr [di].TIM_HI ; now look at the high bits + jz Done_Set ; if equal then no time passed +SetAccess: ; we get here if some time has passed + ; zero AccessCount to show time passage + mov byte ptr cs:[AccessCount],0 + MOV WORD PTR DS:[DI].TIM_LO,DX ; save low time bits + MOV WORD PTR DS:[DI].TIM_HI,CX ; save high time bit +Done_Set: + clc ; indicate no error + pop ax ; restore AX register + ret + +SET_TIM ENDP + ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING + +; +; This is the true DISK INT handler. We parse the request to see if there is +; a DMA violation. If so, depending on the function, we: +; READ/WRITE Break the request into three pieces and move the middle one +; into our internal buffer. +; FORMAT Copy the format table into the buffer +; VERIFY Point the transfer address into the buffer +; +; This is the biggest bogosity of all. The IBM controller does NOT handle +; operations that cross physical 64K boundaries. In these cases, we copy +; the offending sector into the buffer below and do the I/O from there. +; + +INT13FRAME STRUC +oldbp dw ? +oldax dw ? +oldbx dw ? +oldcx dw ? +olddx dw ? +olddd dd ? +oldf dw ? +INT13FRAME ENDS + +;;Rev 3.30 Modification ----------------------------------------- +;To handle the INT 13h, AH = 8 Problem. +;Save Registers here. +Save_AX DW ? +Save_BX DW ? +Save_CX DW ? +Save_DX DW ? +Save_DI DW ? +Save_SI DW ? +Save_BP DW ? +Save_DS DW ? +Save_ES DW ? +Prev_DX DW ? +Save_Flag DW ? +;;End of Modification ----------------------------------------- + + +; +; Block13: +; +; Entry conditions: +; AH = function +; AL = number of sectors +; ES:BX = DMA address +; CX = packed track and sector +; DX = head and drive +; Output conditions: +; NO DMA violation. +; + Public Block13 +Block13 PROC FAR +; +; Let the opperation proceed. If there is a DMA violation, then we do things. +; + mov cs:PrevOper,AX ; save request + pushf ; preserve the flags + cmp AH,ROMFormat ; format request? + jnz Not_Format ; no, skip down + +; Set changed by format bit for all logical drives using this physical drive +;---------------------------------------------------------| +; Warning: Do Not Change the following. | +; It gets patched in at INIT time | + Public Changed_Patch +Changed_Patch: + mov word ptr cs:[FlagBits],fChanged_By_Format+fChanged + call Set_Changed_DL ; Indicate that media changed by format +; | +;---------------------------------------------------------| + +Not_Format: +;;Rev 3.30 Modification ----------------------------------------- + cmp ah, 8 ; Read Driver Parm ? + je Bus_Problem + cmp ah, 15h + je Bus_Problem + CALL ORIG13 ; SIMULATE INT 13 + JC GOTERR13_br ; ERROR? + RET 2 ; NO, RETURN AND CLEAR FLAGS + +GOTERR13_br: jmp Goterr13 + +;Some machines have a problem with Int 13h function=8 +;This function does not reset the common buses after the execution. +;To solve this problem, when we detect AH=8h, then we will save the result +;and will issue AH=1 (Read Status) call to reset the buses. + +Bus_Problem: + mov cs:Prev_DX, DX ;save orignal drive number + call Orig13 ;Do "Read drive parm" + + mov cs:Save_AX, AX ;Save registers,flag + mov cs:Save_BX, BX + mov cs:Save_CX, CX + mov cs:Save_DX, DX + mov cs:Save_DI, DI + mov cs:Save_SI, SI + mov cs:Save_BP, BP + mov cs:Save_DS, DS + mov cs:Save_ES, ES + pushf + pop cs:Save_Flag + + mov dx, cs:Prev_DX ;restore orignal drive + pushf + mov ah, 1 ;Read Status. + call Orig13 ;Reset the bus as a side effect + + mov AX, cs:Save_AX ;restore registers,flag + mov BX, cs:Save_BX + mov CX, cs:Save_CX + mov DX, cs:Save_DX + mov DI, cs:Save_DI + mov SI, cs:Save_SI + mov BP, cs:Save_BP + mov DS, cs:Save_DS + mov ES, cs:Save_ES + push cs:Save_Flag + popf + jc GotErr13 ;AH=8 had been an error? + ret 2 +; +; Some kind of error occurred. See if it is DMA violation +; +GotErr13: + pushf + cmp AH, 09h ; is error DMA error code? + JNZ CHECK_ECC + JMP GOTDMAERR +CHECK_ECC: + CMP AH,11H + JZ OK11 + POPF + RET 2 +; +; We have an error status 11h. This indicates an ECC-corrected error. Note +; that this indicates that the data is PROBABLY correct but not CERTAINLY +; correct. The ROMs on PC-1s and PC_XTs have a 'bug' in that if an ECC error +; occurs for a multi-sector read, only the sectors up to the one where the +; error occurred are read in. We have no way of knowing how many were read in +; this case, so we redo the operation, reading one sector at a time. If we +; get an ECC error on reading one sector, we ignore the error because the +; sector has been read in. +; + PUBLIC OK11 +OK11: +; popf ; restore flags +;;Rev 3.30 Modification ----------------------------------------- +; Here, it is better reset the system. So, we are going to +; call Orig13 again + mov ah, 0 + call Orig13 ;reset. Don't care about result +;;End of Modification ----------------------------------------- + + mov ax,cs:[PrevOper] ; Retrieve request +; +; This will provide a termination point. +; + cmp AL,1 ; If request for one sector, assume OK + jnz ECC_Err_Handle ; more than one sector -- jump down + xor AH,AH ; clear carry too! + ret 2 + + Public ECC_Err_Handle +ECC_Err_Handle: + SAVEREG + mov cs:[Number_Of_Sec],AL +Loop_ECC: + mov AX,CS:[PrevOper] ; set command to previos command + mov AL,1 ; but request only one sector +; +; we do reads one sector at a time. this ensures that we will eventually +; finish the request since ecc errors on 1 sector do read in that sector. +; +; we need some "intelligence" in the ecc handler to handle reads +; that attempt to read more sectors than are available on a particular +; track. +; we call check_wrap to set up the sector #, head # and cylinder # for +; this request. +; at this point, all registers are set up for the call to orig13, except +; that there maybe a starting sector number that is bigger than the number +; of sectors on a track. +; + + CALL Check_Wrap ; see if wrapping around cylinder + + pushf ; save flags + call ORIG13 ; call original rom-bios code +;;Rev 3.30 Modification ------------------------------------------------------ + JNC OK11_OP + CMP AH,11H ; ONLY ALLOW ECC ERRORS + JNZ OK11_EXIT_err ; Other error? + mov ah, 0 ; ECC error. Reset it again. + pushf + call Orig13 +OK11_Op: + dec cs:[Number_of_Sec] ; adjust number of sectors for one read + jz OK11_Exit ; all done? + inc CL ; advance sector number + inc BH ; add 200H to address + inc BH + jmp short Loop_ECC ; and around for reading another sector + +OK11_EXIT_err: + stc ; Set carry bit again. +;;End of Modification ------------------------------------------------------ + +OK11_Exit: + RESTOREREG + Ret 2 + + + +; +; we truly have a DMA violation. Restore register AX and retry the +; operation as best we can. +; +GotDMAErr: + pop AX ; clean up stack + mov AX,cs:PrevOper ; restore command + sti ; restore interrupts + cmp AH,ROMRead ; determine the command + jb IntDone + cmp AH,ROMVerify + jz IntVerify + cmp AH,ROMFormat + jz IntFormat + ja IntDone +; +; We are doing a read/write call. Check for DMA problems +; + SaveReg ; save register we overwrite + push BP + mov BP,SP + mov DX,ES ; Check for 64k boundary error + + shl DX,1 + shl DX,1 + shl DX,1 + shl DX,1 ; Segment converted to absolute address + + add DX,BX ; Combine with offset + add DX,511 ; simulate a transfer +; +; If carry is set, then we are within 512 bytes of the end of the segment. +; We skip the first transfer and perform the remaining buffering and transfer +; + JNC NO_SKIP_FIRST + mov DH,byte ptr [bp.olddx+1] ; set correct head number + jmp Buffer + +NO_SKIP_FIRST: +; +; DX is the physical 16 bits of start of transfer. Compute remaining +; sectors in segment. +; + shr DH,1 ; DH = number of sectors before address + mov AH,128 ; AH = max number of sectors in segment + sub AH,DH +; +; AH is now the number of sectors that we can successfully write in this +; segment. If this number is above or equal to the requested number, then we +; continue the operation as normal. Otherwise, we break it into pieces. +; + cmp AH,AL ; can we fit it in? + jb DoBlock ; no, perform blocking. +; +; Yes, the request fits. Let it happen +; + MOV DH,BYTE PTR [BP.OLDDX+1] ; SET UP HEAD NUMBER + call DoInt + jmp Bad13 +; +; Verify the given sectors. Place the buffer pointer into our space. +; +IntVerify: + SaveReg + push CS + pop ES +DoSimple: + mov BX,OFFSET DiskSector + pushf + call Orig13 + RestoreReg + ret 2 + +; +; Format operation. Copy the parameter table into memory +; +IntFormat: + SaveReg + SaveReg + push ES + push CS + pop ES + pop DS + mov SI,BX + mov DI,OFFSET DiskSector + call Move + RestoreReg + jmp DoSimple +; +; Inline continuation of operation +; +IntDone: + jmp Orig13 +; +; We can't fit the request into the entire block. Perform the operation on +; the first block. +; +; +; DoBlock is modified to correctly handle multi-sector disk I/O. +; Old DoBlock had added the number of sectors I/Oed (Ah in Old DoBlock) after +; the DoInt call to CL. Observing only the lower 6 bits of CL(=max. 64) can +; represent a starting sector, if AH was big, then CL would be clobbered. +; By the way, we still are going to use CL for this purpose since Checkwrap +; routine will use it as an input. To prevent CL from being clobbered, a +; safe number of sectors should be calculated like "63 - # of sectors/track". +; DoBlock will handle the first block of requested sectors within the +; boundary of this safe value. + +;Try to get the # of sectors/track from BDS via Rom drive number. +;For any mini disks installed, here we have to pray that they have the +;same # of sector/track as the main DOS partition disk drive. + +DoBlock: +;;Rev 3.30 Modification ------------------------------------------------------ + Message ftestDisk,<"!!!DMA DoBlock!!!"> + + mov dx, word ptr [bp.olddx] ;set head # + push di + push ds + push ax ;AH=# of sectors before DMA err + ;AL - User requeseted # of sectors + mov byte ptr CS:[phys_drv],1 + mov al, dl + call SetDrive ;get BDS pointer for this DISK. + pop ax + mov byte ptr CS:[phys_drv],0 + test word ptr [DI].Flags, fNon_Removable ;don't have to worry + jnz DoBlockHard ;about floppies. They are track by + ;track operatiions + mov al, ah ;set al = ah for floppies + jmp short DoBlockCont +DoBlockHard: + push cx + xor cx, cx + mov cx, [DI].SecLim ;# of sectors/track + mov ch, 63 + sub ch, cl + mov al, ch + xchg ah, al ;now ah - safe # of sectors + ;al - # of sectors before DMA err + pop cx +DoBlockCont: + pop ds + pop di +DoBlockContinue: + Message ftestDisk,<"%%DMA DoBlock Loop%%"> + cmp ah, al ;if safe_# >= #_of_sectors_to_go_before DMA, + jae DoBlocklast ;then #_of_sectors_to_go as it is for DoInt. + push ax ;save AH, AL + mov al, ah ;Otherwise, set al to ah to operate. + jmp short DoBlockDoInt ;DoInt will set AH to a proper function in [BP.Oldax] +DoBlocklast: + mov ah, al + push ax ;save AH +DoBlockDoInt: ;let AH=AL=# of sectors this shot + CALL DoInt + JC BAD13 ;something happened, bye! + pop ax + SUB BYTE PTR [BP.oldax], AH ;decrement by the successful operation + ADD CL,AH ;advance sector number. Safety gauranteed. + ADD BH,AH ;advance DMA address + ADD BH,AH ;twice for 512 byte sectors. + cmp ah, al ;check the previous value + je Buffer ;if #_of_sectors_to_go < safe_#, then we are done already. + sub al, ah ;otherwise, #_sector_to_go = #_of_sector_to_go - safe_# + call Check_Wrap ;get new CX, DH for the next operation. + jmp short DoBlockContinue ;handles next sectors left. +;;End of Modification ------------------------------------------------------ +; +Buffer: + push BX + mov AH,BYTE PTR [BP.oldax+1] + cmp AH,ROMWrite + jnz DoRead +; +; Copy the offending sector into local buffer +; + SaveReg + push CS ; exchange segment registers + push ES + pop DS + pop ES + mov DI,OFFSET DiskSector ; where to move + push DI ; save it + mov SI,BX ; source + call Move + pop BX ; new transfer address + RestoreReg + mov AL,1 + mov DL,byte ptr [BP.olddx] ; set drive number + call Check_Wrap ; check for head or cylinder wrap + +; +; AH is function +; AL is 1 for single sector transfer +; ES:BX is local transfer addres +; CX is track/sector number +; DX is head/drive number +; SI,DI unchanged +; + CALL DoInt + RestoreReg + jc Bad13 ; go clean up + jmp SHORT DoTail +; +; Reading a sector. Do INT first, then move things around +; +DoRead: + SaveReg + push CS + pop ES + mov BX,OFFSET DiskSector + mov AL,1 + mov DL,byte ptr [BP.olddx] ; set drive number + call Check_Wrap ; check for head or cylinder wrap + +; +; AH = function +; AL = 1 for single sector +; ES:BX points to local buffer +; CX, DX are track/sector, head/drive +; + CALL DoInt + RestoreReg + jc Bad13 ; error => clean up + SaveReg + push CS + pop DS + mov DI,BX + mov SI,OFFSET DiskSector + call Move + RestoreReg +; +; Note the fact that we've done 1 more sector +; +DoTail: + pop BX ; retrieve new DMA area + add BH,2 ; advance over sector + inc CX + mov AL,BYTE PTR [BP.oldAX] + clc + dec AL + jz Bad13 ; no more I/O + mov DL,byte ptr [BP.olddx] ; set drive number + call Check_Wrap ; check for head or cylinder wrap + call DoInt +; +; We are done. AX has the final code; we throw away what we got before +; +Bad13: + mov SP,BP + RestoreReg + ret 2 +Block13 ENDP + + + + + PAGE + + include msioctl.inc + + PAGE +; +; Check_Wrap is a routine that adjusts the starting sector, starting head +; and starting cylinder for an Int 13 request that requests I/O of a lot +; of sectors. It only does this for fixed disks. It is used in the sections +; of code that handle ECC errors and DMA errors. It is necessary, because +; ordinarily the ROM would take care of wraps around heads and cylinders, +; but we break down a request when we get an ECC or DMA error into several +; I/O of one or more sectors. In this case, we may already be beyond the +; number of sectors on a track on the medium, and the request would fail. +; +; Input conditions: +; ALL registers set up for an Int 13 request. +; +; Output: +; - contains starting head number for request +; - contains starting sector and cylinder numbers +; (The above may or may not have been changed, and are 0-based) +; All other registers preserved. +; + public check_wrap +Check_Wrap: + Message ftestDisk,<"Entering Check_Wrap...",cr,lf> + SaveReg + mov byte ptr cs:[Phys_drv],1;Use phys. drive in AL to get BDS + mov al,dl ; put drive number in AL for get BDS + call SetDrive ; Get pointer to BDS for drive. + mov byte ptr cs:[phys_drv],0; Restore flag to use Logical Drive + jc No_wrap ; Do nothing if wrong phys. drive + + test word ptr [di].Flags,fNon_Removable + jz No_wrap ; No wrapping for removable media + MOV BX,[DI].SECLIM + MOV AX,CX + AND AX,003FH ; EXTRACT SECTOR NUMBER + cmp ax,bx ; If Wrap + jbe No_wrap + + div bl ; AH=new sector#, AL = # of head wraps + +; We need to be careful here. If the new sector number == 0, then we are +; on the last sector on that track + or ah,ah + jnz Not_on_Bound + + mov ah,bl ; set sector = SECLIM if on Bndry + dec al ; and decrement Num. head wraps + +Not_on_Bound: + and CL,0C0H ; zero out sector # + + or CL,ah ; OR in new sector # + xor ah,ah ; AX = # of head wraps + inc ax + add al,DH ; add in starting head # + adc ah,0 ; catch any carry + CMP AX,[DI].HDLIM ; are we going to wrap around a head? + jbe No_Wrap_Head ; Do not lose new head number!! + + push DX ; preserve drive number and head number + xor dx,dx + mov bx,[DI].HDLIM + div bx ; DX=new head #, AX=# of cylinder wraps +; Careful here! If new head # is 0, then we are on the last head. + or dx,dx + jnz No_Head_Bound + + mov dx,bx ; On boundary. Set to HDLIM +; If we had some cylinder wraps, we need to reduce them by one!! + or ax,ax + jz No_Head_Bound + + dec ax ; Reduce number of cylinder wraps +No_Head_Bound: + mov bh,dl ; bh has new head number + POP DX ; restore drive number and head number + + dec bh ; get it 0-based + mov DH,bh ; set up new head number in DH + + mov bh,CL + and bh,3FH ; preserve sector number + mov bl,6 + xchg cl,bl + shr bl,cl ; get ms cylinder bits to ls end + + ADD CH,AL ; ADD IN CYLINDER WRAP + adc bl,ah ; add in high byte + shl bl,cl ; move up to ms end + xchg bl,cl ; restore cylinder bits into CL + or CL,bh ; OR in sector number + +No_Wrap: + clc ; reset carry + RestoreReg + RET + +No_Wrap_Head: + mov DH,al ; Do not lose new head number + dec DH ; get it 0-based + jmp short No_Wrap + +; +; INT_2F_13: +; This code is chained into the INT_2F interrupt during bios +; initialization. It allows the user to change the ORIG13 int_13 vector + +; INT_2F_13: +; This code is chained into the INT_2F interrupt during bios +; initialization. It allows the user to change the ORIG13 int_13 vector +; after booting. This allows testing and implementation of custom int_13 +; handlers, without giving up MS-DOS error recovery +; +; Entry Conditions +; AH == RESET_Int_13 (13h) +; DS:DX == Address of New INT_13 Handler +; ES:BX == Address of New INT_13 vector used by WARM BOOT +; (INT 19) +; +; Exit Conditions +; Orig13 == Address of new Int_13 Handler +; DS:DX == Old ORIG13 value +; ES:BX == Old OLD13 value + + ASSUME CS:CODE,DS:Nothing,ES:nothing,SS:NOTHING + + Public INT_2F_13 +INT_2F_13 Proc Far + + cmp AH,13h ; IF (interrupt_value != Reset_Int_13) + je Chg_Orig13 + jmp CS:[Next2f_13] ; THEN Continue on Int_2F chain + +Chg_Orig13: ; ELSE + push word ptr cs:[Orig13] ; Save Old value of OLD13 and + push word ptr cs:[Orig13 + 2]; ORIG13 so that we can + + Push word ptr cs:[OLD13] ; Return them to caller + Push word ptr cs:[OLD13 + 2] + + mov Word Ptr CS:[Orig13],DX ; Orig13 := Addr. Of New INT_13 + ; Vector + mov Word Ptr CS:[Orig13+2],DS + + mov Word Ptr CS:[Old13],BX ; Old13 := Addr. Of New + ; Boot_13 vector + mov Word Ptr CS:[Old13+2],ES + + pop ES ; ES:BX := Old OLD13 vector + pop BX + + pop DS ; DS:DX := Old ORIG13 vector + pop DX + + iret ; END else + +Int_2F_13 ENDP + + + + + + +Move Proc Near + push CX + mov CX,512/2 + cld + rep MOVSW + pop CX + ret +Move Endp + + + + +DoINT proc NEAR + mov DL,byte ptr [BP.olddx] + xor AH,AH + or AL,AL + jz DoIntDone + mov AH,BYTE PTR [BP.oldax+1] + push [BP.oldf] + call Orig13 + pushf + pop [BP.oldf] +DoIntDone: + ret +DoInt endp + +CODE ENDS + END diff --git a/UPDSRC/BIOS/MSINIT.ASM b/UPDSRC/BIOS/MSINIT.ASM new file mode 100644 index 0000000..cef2022 --- /dev/null +++ b/UPDSRC/BIOS/MSINIT.ASM @@ -0,0 +1,2228 @@ + +; modification history +; +; 3.21 sp added pushf-popf fix around NoParms to fix bug + +;;Rev 3.30 Modification ----------------------------------------------- + test = 0 + include msgroup.inc ;define code segment + include dskprm.inc + include msequ.inc + include msmacro.inc + include msextrn.inc + include biostruc.inc + include cmosequ.inc + + EXTRN OLD13:DWORD + +; THE FOLLOWING LABEL DEFINES THE END OF THE AT ROM PATCH. THIS IS USED +; AT CONFIGURATION TIME. +; Warning!!! This code will be dynamically relocated by MSINIT. + + PUBLIC ENDATROM ;NOT REFERENCES EXTERNALLY, BUT + ; JUST TO CAUSE ENTRY IN LINK MAP +ENDATROM LABEL BYTE + +;CMOS Clock setting support routines used by MSCLOCK. +;Warning!!! This code will be dynamically relocated by MSINIT. + + EXTRN base_century:byte + EXTRN base_year:byte + EXTRN month_tab:byte + + public Daycnt_to_day ;for real time clock support +Daycnt_to_day proc near ;for real time clock support +;Entry: [DAYCNT] = number of days since 1-1-80 +;Return: CH=centry in BCD, CL=year in BCD, DH=month in BCD, DL=day in BCD + + push [daycnt] ;save daycnt + cmp daycnt, (365*20+(20/4)) ;# days from 1-1-1980 to 1-1-2000 + jae century20 + mov base_century, 19 + mov base_year, 80 + jmp years +century20: ;20th century + mov base_century, 20 + mov base_year, 0 + sub daycnt, (365*20+(20/4)) ;adjust daycnt +years: + xor dx, dx + mov ax, daycnt + mov bx, (366+365*3) ;# of days in a Leap year block + div bx ;AX = # of leap block, DX=daycnt + mov daycnt, dx ;save daycnt left +; or ah, ah ;ax should be less than 256 +; jz OK1 +; jmp Erroroccur +;OK1: + mov bl,4 + mul bl ;AX=# of years. Less than 100 + add base_year, al ;So, ah = 0. Adjust year + inc daycnt ;set daycnt to 1 base + cmp daycnt, 366 ;daycnt=remainder of leap year bk + jbe Leapyear ;within 366+355+355+355 days. + inc base_year ;if daycnt <= 366, then leap year + sub daycnt, 366 ;else daycnt--, base_year++; + ;And next three years are normal + mov cx, 3 +Regularyear: + cmp daycnt, 365 ;for(i=1; i>3 or daycnt <=365;i++) + jbe YearDone ;{if (daycnt > 365) + inc base_year ; { daycnt -= 365 + sub daycnt, 365 ; } + loop regularyear ;} +; jmp Erroroccur ;cannot come to here +Leapyear: + mov byte ptr month_tab+1,29 ;leap year. change month table. +Yeardone: + xor bx,bx + xor dx,dx + mov ax, daycnt + mov si, offset month_tab + mov cx, 12 +Months: + inc bl ; + mov dl, byte ptr ds:[si] ;cmp daycnt for each month til fit + cmp ax, dx ;dh=0. + jbe Month_done + inc si ;next month + sub ax, dx ;adjust daycnt + loop Months +; jmp Erroroccur +Month_done: + mov byte ptr month_tab+1, 28 ;restore month table value + mov dl, bl + mov dh, base_year + mov cl, base_century ;al=day,dl=month,dh=year,cl=cntry + call word ptr BinToBCD ;To save 15 bytes, Bin_To_BCD proc + ;was rel from Daycnt_to_Day proc. +; call Bin_to_bcd ;convert "day" to bcd + xchg dl, al ;dl = bcd day, al = month + call word ptr BinToBCD +; call Bin_to_bcd + xchg dh, al ;dh = bcd month, al = year + call word ptr BinToBCD +; call Bin_to_bcd + xchg cl, al ;cl = bcd year, al = century + call word ptr BinToBCD +; call Bin_to_bcd + mov ch, al ;ch = bcd century + pop [daycnt] ;restore original value + ret +Daycnt_to_day endp + + public EndDaycntToDay +EndDaycntToDay label byte + + public Bin_to_bcd +Bin_to_bcd proc near ; real time clock sup +;Convert a binary input in AL (less than 63h or 99 decimal) +;into a bcd value in AL. AH destroyed. + push cx + xor ah, ah + mov cl, 10 + div cl ;al=high digit bcd, ah=low digit bcd + mov cl, 4 + shl al, cl ;mov the high digit to high nibble + or al, ah + pop cx + ret +Bin_to_bcd endp + + Public EndCMOSClockset ;End of routines for CMOS clock +EndCMOSClockset label byte +; + + EXTRN INT6C_RET_ADDR:DWORD ; RETURN ADDRESS FROM INT 6C + EXTRN BIN_DATE_TIME:BYTE + EXTRN MONTH_TABLE:WORD + EXTRN DAYCNT2:WORD + EXTRN FEB29:BYTE + EXTRN TimeToTicks:Word ;indirect intra-segment call add + + EVENB +; +; THE K09 REQUIRES ROUTINES FOR READING THE CLOCK BECAUSE OF THE SUSPEND/ +; RESUME FACILITY. THE SYSTEM CLOCK NEEDS TO BE RESET AFTER RESUME. +; + ASSUME ES:NOTHING + +; THE FOLLOWING ROUTINE IS EXECUTED AT RESUME TIME WHEN THE SYSTEM +; POWERED ON AFTER SUSPENSION. IT READS THE REAL TIME CLOCK AND +; RESETS THE SYSTEM TIME AND DATE, AND THEN IRETS. +; Warning!!! This code will be dynamically relocated by MSINIT. +INT6C PROC FAR + PUSH CS + POP DS + + ASSUME DS:CODE + + POP WORD PTR INT6C_RET_ADDR ; POP OFF RETURN ADDRESS + POP WORD PTR INT6C_RET_ADDR+2 + POPF + CALL READ_REAL_DATE ; GET THE DATE FROM THE CLOCK + CLI + MOV DS:DAYCNT,SI ; UPDATE DOS COPY OF DATE + STI + CALL READ_REAL_TIME ; GET THE TIME FROM THE RTC + CLI + MOV AH, 01h ; COMMAND TO SET THE TIME + INT 1Ah ; CALL ROM-BIOS TIME ROUTINE + STI + JMP INT6C_RET_ADDR ; LONG JUMP + +INT6C ENDP + + + INCLUDE READCLOCK.INC + INCLUDE CLOCKSUB.INC + + PUBLIC ENDK09 ;NOT REFERENCES EXTERNALLY, BUT + ; JUST TO CAUSE ENTRY IN LINK MAP +ENDK09 LABEL BYTE + ASSUME DS:NOTHING,ES:NOTHING +;;End of Modification ----------------------------------------------- + +;------------------------------------------------------------------------ +; : +; System initiailzation : +; : +; The entry conditions are established by the bootstrap : +; loader and are considered unknown. The following jobs : +; will be performed by this module: : +; : +; 1. All device initialization is performed : +; 2. A local stack is set up and DS:SI are set : +; to point to an initialization table. Then : +; an inter-segment call is made to the first : +; byte of the dos : +; 3. Once the dos returns from this call the ds : +; register has been set up to point to the start : +; of free memory. The initialization will then : +; load the command program into this area : +; beginning at 100 hex and transfer control to : +; this program. : +; : +;------------------------------------------------------------------------ + +; DRVFAT must be the first location of freeable space! + EVENB +DRVFAT DW 0000 ; Drive and FAT ID of DOS +BIOS$ DW 0000 ; First sector of data +DOSCNT DW 0000 ; How many sectors to read +fBigFAT DB 0 ; Flags for drive +FatLen DW ? ; number of sectors in FAT. +FatLoc DW ? ; seg addr of fat sector + +;;Rev 3.30 Modification ----------------------------------------------- +; THE FOLLOWING TWO BYTES ARE USED TO SAVE INFO RETURNED BY INT 13, AH=8 +; CALL TO DETERMINE DRIVE PARAMETERS. +NUM_HEADS DB 2 ; NUMBER OF HEADS RETURNED BY ROM +SEC_TRK DB 9 ; SEC/TRK RETURNED BY ROM +NUM_CYLN DB 40 ; NUMBER OF CYLINDERS RET BY ROM + + public Model_Byte +MODEL_BYTE DB 0FFH ; MODEL BYTE. SET UP AT INIT TIME. + ; FF - PC-1, EXPANSION, OLD PC-2 + ; FE - NEWER PC-2 (64/256K PLANAR) + ; FD - + ; FC - + public Secondary_Model_Byte +Secondary_Model_Byte db 0 +;;End of Modification ----------------------------------------------- + +BOOTBIAS = 200H + EVENB +DiskTable DW 512, 0100h, 64, 0 + DW 2048, 0201h, 112, 0 + DW 8192, 0402h, 256, 0 + DW 32680, 0803h, 512, 0 + DW 65535, 1004h, 1024, 0 + +DiskTable2 DW 32680, 0803h, 512, 0 + DW 65535, 0402h, 512, fBIG + +;;Rev 3.30 Modification ----------------------------------------------- +;************************************************************************* +;Variables for Mini disk initialization +;************************************************************************* +End_Of_BDSM dw ? ;offset value of the ending add + ;of BDSM table. Needed to figure + ;the Final_DOS_Location. +numh db 0 ;number of hard files +mininum db 0 ;logical drive num for mini disk +num_mini_dsk db 0 ;# of mini disk installed +Rom_Minidsk_num db 80h ;physical mini disk number +Mini_HDLIM dw 0 +Mini_SECLIM dw 0 +Mini_BPB_ptr dw 0 ;temporary variable used to save + ;Mini Disk BPB pt add in DskDrvs. +;;End of Modification ----------------------------------------------- + +Bios_Date DB '01/10/84',0 + +; +; The following are the recommended BPBs for the media that we know of so +; far. + +; 48 tpi diskettes + EVENB +BPB48T DW 512 + DB 2 + DW 1 + DB 2 + DW 112 + DW 2*9*40 + DB 0FDH + DW 2 + DW 9 + DW 2 + DD 0 ;hidden sectors - sp + DD 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved + +; 96tpi diskettes + EVENB +BPB96T DW 512 + DB 1 + DW 1 + DB 2 + DW 224 + DW 2*15*80 + DB 0f9H + DW 7 + DW 15 + DW 2 + DD 0 ;hidden sectors - sp + DD 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved + +BPBSIZ = $-BPB96T + +; 3 1/2 inch diskette BPB + EVENB +BPB35 DW 512 + DB 2 + DW 1 ; Double sided with 9 sec/trk + DB 2 + DW 70h + DW 2*9*80 + DB 0f9H + DW 3 + DW 9 + DW 2 + DD 0 ;hidden sectors - sp + DD 0 ;big total sectors - sp + DB 6 DUP(?) ;reserved + + + EVENB +BPBTable dw BPB48T ; 48tpi drives + dw BPB96T ; 96tpi drives + dw BPB35 ; 3.5" drives + ;dw BPB48T ; Not used - 8" drives + ;dw BPB48T ; Not Used - 8" drives + ;dw BPB48T ; Not Used - hard files + ;dw BPB48T ; Not Used - tape drives + ;dw BPB48T ; Not Used - Other + +PatchTable LABEL BYTE + DW 10,media_patch + DW 3,getbp1_patch + DW 3,SET_PATCH + DW 3,DiskIO_Patch + DW 3,DSKErr + DW 10,Changed_Patch + DW 3,INIT_PATCH + DW 0 + + ASSUME DS:NOTHING,ES:NOTHING + +; +; Entry from boot sector. The register contents are: +; DL = INT 13 drive number we booted from +; CH = media byte +; BX = First data sector on disk (0-based) +; +Public INIT +INIT PROC NEAR + MESSAGE FTESTINIT,<"MSBIO",CR,LF> ;3.30 + CLI + XOR AX,AX + MOV DS,AX +; +; Preserve original int 13 vector +; We need to save INT13 in two places in case we are running on an AT. +; On ATs we install the IBM supplied ROM_BIOS patch DISK.OBJ which hooks +; INT13 ahead of ORIG13. Since INT19 must unhook INT13 to point to the +; ROM INT13 routine, we must have that ROM address also stored away. +; + MOV AX,DS:[13h*4] + MOV WORD PTR Old13,AX + MOV WORD PTR Orig13,AX + MOV AX,DS:[13h*4+2] + MOV WORD PTR Old13+2,AX + MOV WORD PTR Orig13+2,AX +; +; Set up INT 13 for new action +; + MOV WORD PTR DS:[13h*4],OFFSET Block13 + MOV DS:[13h*4+2],CS +; +; Preserve original int 19 vector +; + MOV AX,DS:[19h*4] + MOV WORD PTR Orig19,AX + MOV AX,DS:[19h*4+2] + MOV WORD PTR Orig19+2,AX +; +; Set up INT 19 for new action +; + MOV WORD PTR DS:[19h*4],OFFSET int19 + MOV DS:[19h*4+2],CS + STI + + + int 11h ; rom-bios equipment determination + ROL AL,1 ;PUT BITS 6 & 7 INTO BITS 0 & 1 + ROL AL,1 + AND AX,3 ;ONLY LOOK AT BITS 0 & 1 + JNZ NOTSINGLE ;ZERO MEANS SINGLE DRIVE SYSTEM + INC AX ;PRETEND IT'S A TWO DRIVE SYSTEM + INC CS:SINGLE ;REMEMBER THIS +NOTSINGLE: + INC AX ;AX HAS NUMBER OF DRIVES, 2-4 + ;IS ALSO 0 INDEXED BOOT DRIVE IF WE + ; BOOTED OFF HARD FILE + mov CL, AL ; save number of diskette drives in CL + test DL, 80h ; booted from hard disk ? + jnz GotHrd ; yes, jump down + xor AX, AX ; no - indicate boot from drive A +GotHrd: + + ; At this point the registers contain these values: + ; AX = 0-based drive we booted from + ; BX = the logical number of the first data sector on the disk + ; CL = number of floppies including logical one + ; CH = media byte + ; + + Message fTestINIT,<"Init",CR,LF> + +; +; set up local stack +; + xor DX,DX + cli ; turn interrupts off while manupulating stack + mov SS,DX ; set stack segment register + mov SP,700h ; set stack pointer + sti ; turn interrupts on +ASSUME SS:NOTHING + + ; preserve some of the values in registers + + push CX ; save number of floppies and media byte + mov BIOS$,BX ; save first data sector + mov AH,CH ; FAT ID to AH too + push AX ; save boot drive number, and media byte +;;Rev 3.30 Modification ----------------------------------------------- +; Let Model_byte, Secondary_Model_Byte be set here!!! + mov ah,0c0h ; return system environment + int 15h ; call ROM-Bios routine + jc No_Rom_System_Conf ; just use Model_Byte + cmp ah, 0 ; double check + jne No_Rom_System_Conf + mov al, ES:[BX.bios_SD_modelbyte] ;get the model byte + mov [Model_Byte], al + mov al, ES:[BX.bios_SD_scnd_modelbyte] ;secondary model byte + mov [Secondary_Model_Byte], al + jmp short Turn_Timer_On +No_Rom_System_Conf: + MOV SI,0FFFFH ;MJB001 + MOV ES,SI ;MJB001 + MOV AL,ES:[0EH] ; GET MODEL BYTE ARR 2.41 + MOV MODEL_BYTE,AL ; SAVE MODEL BYTE ARR 2.41 +;;End of Modification ----------------------------------------------- +Turn_Timer_On: + mov AL,EOI + out AKPORT,AL ; turn on the timer + + Message fTestINIT,<"COM devices",CR,LF> + +;;Rev 3.30 Modification ----------------------------------------------- + mov si,offset COM4DEV + call AUX_INIT + mov si,offset COM3DEV + call AUX_INIT +;;End of Modification ----------------------------------------------- + mov SI,OFFSET COM2DEV + call AUX_INIT ;INIT COM2 + mov SI,OFFSET COM1DEV + call AUX_INIT ;INIT COM1 + + Message fTestINIT,<"LPT devices",CR,LF> + mov SI,OFFSET LPT3DEV + call PRINT_INIT ;INIT LPT3 + mov SI,OFFSET LPT2DEV + call PRINT_INIT ;INIT LPT2 + mov SI,OFFSET LPT1DEV + call PRINT_INIT ;INIT LPT1 + + xor DX,DX + mov DS,DX ;TO INITIALIZE PRINT SCREEN VECTOR + mov ES,DX + + xor AX,AX + mov DI,INITSPOT + stosw ;INIT four bytes to 0 + stosw + + mov AX,CS ;FETCH SEGMENT + + mov DS:WORD PTR BRKADR,OFFSET CBREAK ;BREAK ENTRY POINT + mov DS:BRKADR+2,AX ;VECTOR FOR BREAK + + mov DS:WORD PTR CHROUT*4,OFFSET WORD PTR OUTCHR + mov DS:WORD PTR CHROUT*4+2,AX + + Message fTestINIT,<"Interrupt vectors",CR,LF> + mov DI,4 + mov BX,OFFSET INTRET ;WILL INITIALIZE REST OF INTERRUPTS + xchg AX,BX + stosw ;Location 4 + xchg AX,BX + stosw ;INT 1 ;Location 6 + add DI,4 + xchg AX,BX + stosw ;Location 12 + xchg AX,BX + stosw ;INT 3 ;Location 14 + xchg AX,BX + stosw ;Location 16 + xchg AX,BX + stosw ;INT 4 ;Location 18 + + mov DS:WORD PTR 500H,DX ;SET PRINT SCREEN & BREAK =0 + mov DS:WORD PTR LSTDRV,DX ;clean out last drive spec + + Message fTestINIT,<"Disk parameter table",CR,LF> + + EXTRN MotorStartup:byte + EXTRN SettleCurrent:byte + + mov SI,WORD PTR DS:DSKADR ; ARR 2.41 + mov DS,WORD PTR DS:DSKADR+2 ; DS:SI -> current table ARR 2.41 + + mov DI,SEC9 ; ES:DI -> New Table ARR 2.41 + mov CX,SIZE DISK_PARMS ; ARR 2.41 + rep MOVSB ; Copy Table ARR 2.41 + push ES ; ARR 2.41 + pop DS ; DS = 0 ARR 2.41 + + mov WORD PTR DS:DSKADR,SEC9 ; ARR 2.41 + mov WORD PTR DS:DSKADR+2,DS ; Point disk parm vector to new table + ; ARR 2.41 + + +;----------------------------------------------- +; +; THE FOLLOWING DEPEND ON THE TYPE OF MACHINE. +; + CMP MODEL_BYTE,0FDH ; IS THIS AN OLD ROM? ARR 2.41 + JB NO_DIDDLE ; NO ARR 2.41 + MOV WORD PTR DS:(SEC9 + DISK_HEAD_STTL),0200H+NORMSETTLE + ; SET HEAD SETTLE AND MOTOR START + ; ON PC-1 PC-2 PC-XT HAL0 ARR 2.41 + MOV DS:(SEC9 + DISK_SPECIFY_1),0DFH + ; SET 1ST SPECIFY BYTE + ; ON PC-1 PC-2 PC-XT HAL0 ARR 2.41 +NO_DIDDLE: ; ARR 2.41 + +;--------------------------------------------------------------bug330a08 +; sp - fix from IBM +; + mov al,byte ptr ds:(sec9+disk_motor_strt) + mov cs:MotorStartup,al + + mov al,byte ptr ds:(sec9+disk_head_sttl) + mov cs:SettleCurrent,al + +;--------------------------------------------------------------bug330a08 + + int 12h ; call rom-bios for memory size + mov CL, 6 ; get ready for shift + shl AX, CL ; change from K to 16 byte blocks + pop CX ; restore CX + mov DRVFAT, CX + push AX + mov dx,ds:(7C00h + 16h) ; number of sectors/fat from boot sec + xor dh,dh + mov FatLen,DX +; +; Convert sector count to paragraph count:512 bytes / sec / 16 bytes / para +; = 32 para /sector +; +;;Rev 3.30 Modification ----------------------------------------------- + SHL DX,1 + SHL DX,1 + SHL DX,1 + SHL DX,1 + SHL DX,1 +;;End of Modification ----------------------------------------------- + SUB AX,dx ; room for FAT + MOV FatLoc,AX ; location to read fat + POP AX + + MOV DX,SYSINITSEG + MOV DS,DX + + ASSUME DS:SYSINITSEG + + MOV WORD PTR DEVICE_LIST,OFFSET CONHeader + MOV WORD PTR DEVICE_LIST+2,CS + +; Allocation of buffers has moved to SYSINIT - Aug 19/85 BAS + +;DEF_BUFF: + + MOV MEMORY_SIZE,AX + INC CL + MOV DEFAULT_DRIVE,CL ;SAVE DEFAULT DRIVE SPEC + +;DOSSEG = ((((OFFSET END$)-(OFFSET START$))+15)/16)+BIOSEG+SYSIZE + +; BAS DEBUG +;MOV CURRENT_DOS_LOCATION,((((OFFSET END$)-(OFFSET START$))+15)/16)+SYSIZE + MOV AX, OFFSET END$ + SUB AX, OFFSET START$ + ADD AX, 15 + RCR AX, 1 ; DIVIDE BY 16 + SHR AX, 1 + SHR AX, 1 + SHR AX, 1 + ADD AX, SYSIZE + ADD AX, CODE + MOV Current_DOS_Location, AX +; BAS DEBUG +; ADD Current_DOS_Location,CODE + +; +; IMPORTANT: Some old IBM hardware generates spurious INT F's due to bogus +; printer cards. We initialize this value to point to an IRET ONLY IF +; +; 1) The original segment points to storage inside valid RAM. +; +; 2) The original segment is 0F000:xxxx +; +; Theses are capricious requests from our OEM for reasons behind them, read +; the DCR's for the IBM DOS 3.2 project. +; + push ax + +ASSUME ES:SYSINITSEG, DS:NOTHING + mov ax,SYSINITSEG + mov es,ax + xor ax,ax + mov ds,ax + + mov ax,word ptr ds:(0fH*4+2) ; segment for Int 15 + + cmp ax,es:MEMORY_SIZE ; Condition 1 + jna ResetIntF + + cmp ax, 0F000h ; Condition 2 + jne KeepIntF + +ResetIntF: + mov word ptr ds:[0FH*4],offset INTRET + mov word ptr ds:[0FH*4+2],cs + +KeepIntF: + pop ax +; +; END IMPORTANT +; + +;************************************************************** +; WILL INITIALIZE THE NUMBER OF DRIVES +; AFTER THE EQUIPMENT CALL (INT 11H) BITS 6&7 WILL TELL +; THE INDICATIONS ARE AS FOLLOWS: +; +; BITS 7 6 DRIVES +; 0 0 1 +; 0 1 2 +; 1 0 3 +; 1 1 4 +;************************************************************** + PUSH CS + POP DS + PUSH CS + POP ES + + ASSUME DS:CODE,ES:CODE + + call CMOS_Clock_Read ;Before doing anything if CMOS clock, + ;then set the system time accordingly. + ;Also, reset the cmos clock rate. + + Message fTestINIT,<"Disk devices",CR,LF> + + XOR SI,SI + MOV WORD PTR [SI],OFFSET HARDDRV ;set up pointer to hdrive + + POP AX ;number of floppies and FAT ID + XOR AH,AH ; Chuck FAT ID byte + MOV HARDNUM,AL ;Remember which drive is hard disk + MOV DRVMAX,AL ;And set initial number of drives + SHL AX,1 ;Two bytes per address + MOV DI,OFFSET DSKDRVS + ADD DI,AX ;Point to hardfile location + MOV SI,OFFSET HDSKTAB + MOVSW ;Two addresses to move + MOVSW + MESSAGE FTESTINIT,<"BEFORE INT 13",CR,LF> + mov DL, 80h ; tell rom bios to look at hard drives + mov AH, 8h ; set command to get drive parameter + int 13h ; call ROM-BIOS to get number of drives + jc ENDDRV ; old, rom therefore no hard disks + mov HNUM, DL ; save number of hard drives in HNUM + +ENDDRV: + Message fTestINIT,<"Setting up BDSs",CR,LF> + +; +; Scan the list of drives to determine their type. We have three flavors of +; diskette drives: +; +; 48tpi drives We do nothing special for them +; 96tpi drives Mark the fact that they have changeline support. +; 3 1/4 drives Mark changeline support and small. +; +; The following code uses registers for certain values: +; DL - Physical Drive +; DS:DI - points to current BDS +; CX - Flag bits for BDS +; DH - Form Factor for the drive (1 - 48tpi, 2 - 96tpi, 3 - 3.5" medium) +; + XOR DL,DL ; start out with drive 0. + push cs + pop ds + ASSUME DS:CODE + MOV EOT,9 + mov di,offset Start_BDS +loop_drive: + cmp dl,drvmax + jb got_more + jmp Done_Drives +got_more: + xor cx,cx ; zero all flags + mov di,word ptr [di].link ; get next BDS + mov dh,ff48tpi ; Set Form Factor to 48 tpi + MOV NUM_CYLN,40 ; 40 TRACKS PER SIDE + + PUSH DS + PUSH DI + PUSH DX + PUSH CX + PUSH ES + + MOV AH, 8h ;GET DRIVE PARAMETERS + INT 13h ;CALL ROM-BIOS + JNC PARMSFROMROM + JMP NOPARMSFROMROM ; GOT AN OLD ROM +PARMSFROMROM: +;If CMOS is bad, it gives ES,AX,BX,CX,DH,DI=0. CY=0. +;In this case, we are going to put bogus informations to BDS table. +;We are going to set CH=39,CL=9,DH=1 to avoid divide overflow when +;they are calculated at the later time. This is just for the Diagnostic +;Diskette which need IO.SYS,MSDOS to boot up before it sets CMOS. +;This should only happen with drive B. + +;;Rev 3.30 Modification ----------------------------------------------- + CMP CH,0 ; if ch=0, then cl,dh=0 too. + JNE PFR_OK + MOV CH,39 ; ROM gave wrong info. + MOV CL,9 ; Let's default to 360K. + MOV DH,1 +PFR_OK: + INC DH ; MAKE NUMBER OF HEADS 1-BASED + INC CH ; MAKE NUMBER OF CYLINDERS 1-BASED + MOV NUM_HEADS,DH ; SAVE PARMS RETURNED BY ROM + AND CL,00111111B ; EXTRACT SECTORS/TRACK + MOV SEC_TRK,CL + MOV NUM_CYLN,CH ; ASSUME LESS THAN 256 CYLINDERS!! +; MAKE SURE THAT EOT CONTAINS THE MAX NUM OF SEC/TRK IN SYSTEM OF FLOPPIES + CMP CL,EOT ; MAY SET CARRY + JBE EOT_OK + MOV EOT,CL +EOT_OK: + POP ES + POP CX + POP DX + POP DI + POP DS + +; +; Check for presence of changeline +; + mov AH, 15h ; set command to get DASD type + int 13h ; call ROM-BIOS + JC CHANGELINE_DONE + CMP AH,02 ; CHECK FOR PRESENCE OF CHANGELINE + JNE CHANGELINE_DONE +;;End of Modification ----------------------------------------------- +; +; We have a drive with change line support. +; + Message fTestINIT,<"96tpi devices",CR,LF> + + or CL,fChangeLine ; signal type + mov fHave96,1 ; Remember that we have 96tpi disks +; ;3.30 +; WE NOW TRY TO SET UP THE FORM FACTOR FOR THE TYPES OF MEDIA THAT WE KNOW;3.30 +; AND CAN RECOGNISE. FOR THE REST, WE SET THE FORM FACTOR AS "OTHER". ;3.30 +; ;3.30 +CHANGELINE_DONE: ;3.30 +; 40 CYLINDERS AND 9 OR LESS SEC/TRK, TREAT AS 48 TPI MEDIUM. ;3.30 + CMP NUM_CYLN,40 ;3.30 + JNZ TRY_80 ;3.30 + CMP SEC_TRK,9 ;3.30 + JBE GOT_FF ;3.30 +GOTOTHER: ;3.30 + MOV DH,FFOTHER ; WE HAVE A "STRANGE" MEDIUM ;3.30 + JMP SHORT GOT_FF ;3.30 + ;3.30 +; ;3.30 +; 80 CYLINDERS AND 9 SECTORS/TRACK => 720 KB DEVICE ;3.30 +; 80 CYLINDERS AND 15 SEC/TRK => 96 TPI MEDIUM ;3.30 +; ;3.30 +TRY_80: ;3.30 + CMP NUM_CYLN,80 ;3.30 + JNZ GOTOTHER ;3.30 + CMP SEC_TRK,15 ;3.30 + JZ GOT96 ;3.30 + CMP SEC_TRK,9 ;3.30 + JNZ GOTOTHER ;3.30 + MOV DH,FFSMALL ;3.30 + JMP SHORT GOT_FF ;3.30 + ;3.30 +GOT96: ;3.30 + MOV DH,FF96TPI ;3.30 + ;3.30 +GOT_FF: ;3.30 + JMP SHORT NEXTDRIVE ;3.30 + ;3.30 +; AN OLD ROM, SO WE EITHER HAVE A 48TPI OR 96TPI DRIVE. IF THE DRIVE ;3.30 +; HAS CHANGELINE, WE ASSUME IT IS A 96TPI, OTHERWISE IT IS A 48TPI. ;3.30 + ;3.30 +NOPARMSFROMROM: ;3.30 + POP ES ;3.30 + POP CX ;3.30 + POP DX ;3.30 + POP DI ;3.30 + POP DS ;3.30 + ;3.30 + MOV AH, 15h ; SET COMMAND TO GET DASD TYPE ;3.30 + INT 13h ; CALL ROM-BIOS ;3.30 + JC NEXTDRIVE ;3.30 + CMP AH,2 ; IS THERE CHANGELINE? ;3.30 + JNZ NEXTDRIVE ;3.30 + OR CL,FCHANGELINE ;3.30 + MOV FHAVE96,1 ; REMEMBER WE HAVE 96TPI DRIVES ;3.30 + MOV NUM_CYLN,80 ;3.30 + MOV DH,FF96TPI ;3.30 + MOV AL,15 ; SET EOT IF NECESSARY ;3.30 + CMP AL, EOT ;3.30 + JBE EOT_OK2 ;3.30 + MOV EOT,AL ;3.30 +EOT_OK2: ;3.30 + +NextDrive: + or cl,fI_Own_Physical ; set this true for all drives + mov bh,dl ;save Int13 drive number +; +; We need to do special things if we have a single drive system and are setting +; up a logical drive. It needs to have the same Int13 drive number as its +; counterpart, but the next drive letter. Also reset ownership flag. +; We detect the presence of this situation by examining the flag SINGLE for the +; value 2. +; + cmp single,2 + jnz Not_Special + dec bh ; Int13 drive number same for logical drive + xor cl,fI_Own_Physical ; reset ownership flag for logical drive +Not_Special: +; The values that we put in for RHdlim and RSeclim will only remain if the +; form factor is of type "ffOther". + xor ax,ax ; fill BDS for drive + mov al,num_heads + mov word ptr [di].RHdlim,ax + mov al,sec_trk + mov word ptr [di].RSeclim,ax + mov word ptr [di].flags,cx + mov byte ptr [di].FormFactor,dh + mov byte ptr [di].DriveLet,dl + mov byte ptr [di].DriveNum,bh + MOV BL,BYTE PTR NUM_CYLN ;3.30 + mov byte ptr [di].cCyln,bl ; only the l.s. byte is set here + cmp single,1 ; Special case for single drive system + jnz No_Single + message fTestINIT,<"Single Drive System",CR,LF> + ; Don't forget we have + mov single,2 ; single drive system + or cx,fI_Am_Mult ; set that this is one of + ; several drives + or word ptr [di].flags,cx ; save flags + mov di,word ptr [di].link ; move to next BDS in list + inc dl ; add a number + jmp short NextDrive ; Use same info for BDS as previous + + + +No_Single: + inc dl + jmp loop_drive + +Done_Drives: + mov ax,-1 ; Signify end of list by + mov word ptr [di].link,ax ; setting pointer to -1 +; +; Set up all the hard drives in the system +; +DoHard: + MNUM fTestINIT+fTestHARD,AX + Message fTestINIT+fTestHARD,<" Hard disk(s) to initialize",CR,LF> + Message fTestINIT+fTestHARD,<"Hard disk 1",CR,LF> + + CMP HNUM,0 ; IF (No_Hard_files) + JLE STATIC_CONFIGURE ; THEN EXIT TO CONFIGURE ;3.30 + mov DL, 80h ; set first hard file number + mov di,offset BDSH ; Set up first hard file. + mov bl,HARDNUM + call SETHARD + jnc HardFile1_OK + + dec HNUM ; First hard file is bad. + cmp HNUM,0 ; IF (Second_Hard_File) + jg Second_Hard ; THEN Set up second hard file + JMP SHORT STATIC_CONFIGURE ;3.30 + +HardFile1_OK: + call Install_BDS ; install BDS into linked list + cmp HNUM,2 ; IF (Only_one_hardfile) + jb SetIt ; THEN SetIt "in place" + + mov bl,HARDNUM + inc BL ; next drive letter + mov di,offset BDSX + +Second_Hard: ; SETUP Second Hard FILE + + Message fTestINIT+fTestHARD,<"Hard disk 2",CR,LF> + mov DL, 81h ; set second hard file number + call SETHARD + jnc HardFile2_OK + dec HNUM + jmp short SetIt + +HardFile2_OK: + Call Install_BDS + +SETIT: + mov al,HNUM + or al,al + JZ STATIC_CONFIGURE ;3.30 + add al,HARDNUM + mov DRVMAX,al + +; End of physical drive initialization. ;3.30 +; *** Do not change the position of the following statement. +; *** DoMini routine will use [DRVMAX] value for the start of the logical ;3.30 +; *** drive number of Mini disk(s). ;3.30 + ;3.30 + call DoMini ;For setting up mini disks, if found -;3.30 + +; End of drive initialization. + +;9/24/86 We now decide, based on the configurations available so far,;3.30 +;what code or data we need to keep as a stay resident code. The following;3.30 +;table shows the configurations under consideration. They are listed in ;3.30 +;the order of their current position memory. ;3.30 +;Configuration will be done in two ways: ;3.30 +;First, we are going to set "Static configuration". Static configuration ;3.30 +;will consider from basic configuration to ENDOF96TPI configuration. ;3.30 +;The result of static configuration will be the address the Dynamic ;3.30 +;configuration will use to start with. ;3.30 +;Secondly, "Dynamic cofiguration" will be performed. Dynamic configuration;3.30 +;involves possible relocation of CODE/DATA. Dynamic configuration routine ;3.30 +;will take care of BDSM tables and AT ROM Fix module thru K09 suspend/res ;3.30 +;code individually. After these operation, FINAL_DOS_LOCATION will be set.;3.30 +;This will be the place SYSINIT routine will relocate MSDOS module. ;3.30 +; ;3.30 +; 1. BASIC CONFIGURATION FOR MSBIO (EndFloppy, EndSwap) ;3.30 +; 2. ENDONEHARD ;3.30 +; 3. ENDTWOHARD ;3.30 +; 4. END96TPI ;a system that supports "Change Line Error" ;3.30 +; 5. End of BDSM ;BDSM tables for mini disks. ;3.30 +; 6. ENDATROM ;Some of AT ROM fix module. ;3.30 +; 7. ENDCMOSCLOCKSET;Supporting program for CMOS clock write. ;3.30 +; 8. ENDK09 ;K09 CMOS Clock module to handle SUSPEND/RESUME ;3.30 +; ;3.30 +;9/24/86. ;3.30 + ;3.30 +; *** For mini disk configuration. 4/7/86 ;3.30 +; *** END_OF_BDSM will contain the ending address(off) of BDSM table for ;3.30 +; *** mini disks which is located right after the label END96TPI. ;3.30 +; *** The variable NUM_MINI_DSK will indicate the existance. 4/7/86 ;3.30 + ;3.30 + ;3.30 +STATIC_CONFIGURE: ;3.30 + ;3.30 + ;3.30 + PUSH AX ;3.30 + mov ax, offset END96TPI ;let's start with the biggest one.;3.30 + cmp fHave96, 0 ;Is change line support there? ;3.30 + jnz Config96 ;Yes. ;3.30 + ;3.30 + mov ax, offset ENDTWOHARD ;3.30 + cmp HNUM, 1 ;1 hard file? ;3.30 + jbe No_Two_HRD ;3.30 + jmp ConfigTwoHard ;3.30 +No_Two_HRD: ;3.30 + mov ax, offset ENDONEHARD ;3.30 + jnz Basic_Floppy ;3.30 + jmp ConfigOneHard ;3.30 +Basic_Floppy: ;3.30 + mov ax, offset ENDFLOPPY ;3.30 + jmp Dynamic_Configure ;static configuration is done! ;3.30 + +; +; Keep the 96tpi code +; +Config96: +; +; Save old INT 13 vector +; + PUSH AX + PUSH DS + XOR AX,AX + MOV DS,AX + ASSUME DS:NOTHING ;3.30 + MOV AX,DS:[4 * 13h] + MOV WORD PTR CS:Real13,AX + MOV AX,DS:[4 * 13h+2] + MOV WORD PTR CS:Real13+2,AX +; +; Insert new vector +; + MOV WORD PTR DS:[4 * 13h],OFFSET INT13 + MOV DS:[4 * 13h + 2],CS + POP DS + ASSUME DS:CODE ;3.30 + POP AX +; +; Keep two hard disk BPBs +; +ConfigTwoHard: +; +; Keep one hard disk BPB +; +ConfigOneHard: +; +; Adjust the number of drives to include the hard disks. +; + PUSH AX + MOV AL,HardNum + ADD AL,HNum + add al, num_mini_dsk ;4/7/86 for mini disks installed ;3.30 + ;if not installed, then num_mini_dsk = 0. ;3.30 + MOV DrvMax,AL + POP AX + +DYNAMIC_CONFIGURE: ;3.30 + call Get_Para_Offset ;For dynamic allocation, we are ;3.30 + ;going to use offset address that ;3.30 + ;is in paragraph boundary. ;3.30 + push cs ;3.30 + pop es ;es -> code ;3.30 + assume es:code ;3.30 + cld ;clear direction ;3.30 + ;3.30 + cmp [num_mini_dsk], 0 ;Mini disk(s) installed ? ;3.30 + jz CheckATROM ;No. ;3.30 + mov ax, End_Of_BDSM ;set the new ending address ;3.30 + call Get_Para_Offset ;3.30 +CheckATROM: ;3.30 + cmp Model_Byte, 0FCh ;AT ? ;3.30 + jnz CheckCMOSClock ;3.30 + cmp HNUM, 0 ;No hard file? ;3.30 + jz CheckCMOSClock ;3.30 + mov si, 0F000h ;3.30 + mov es, si ;ES -> BIOS segment ;3.30 + assume es:nothing ;3.30 + mov si, offset BIOS_DATE ;3.30 + mov di, 0FFF5H ;ROM BIOS string is at F000:FFF5 ;3.30 +Cmpbyte: ;Only patch ROM for bios 01/10/84 ;3.30 + cmpsb ;3.30 + jnz CheckCMOSClock ;3.30 + cmp byte ptr [si-1],0 ;3.30 + jnz Cmpbyte ;3.30 + ;3.30 +SetRomCode: ;Now we have to install ROM fix ;3.30 + ;AX is the address to move. ;3.30 + push cs ;3.30 + pop es ;set ES to CODE seg ;3.30 + assume es:code ;3.30 + mov word ptr ORIG13, ax ;3.30 + mov word ptr ORIG13+2, cs ;set new ROM bios int 13 vector ;3.30 + mov cx, offset ENDATROM ;3.30 + mov si, offset IBM_DISK_IO ;3.30 + sub cx, si ;size of AT ROM FIX module ;3.30 + mov di, ax ;destination ;3.30 + rep movsb ;relocate it ;3.30 + mov ax, di ;new ending address ;3.30 + call Get_Para_Offset ;in AX ;3.30 + ;3.30 +CheckCMOSClock: ;3.30 + push cs ;3.30 + pop es ;set ES to CODE seg ;3.30 + assume es:code ;3.30 + cmp HaveCMOSClock, 1 ;CMOS Clock exists? ;3.30 + jne CheckK09 ;3.30 + mov DaycntToDay, ax ;set the address for MSCLOCK ;3.30 + mov cx, offset EndDaycntToDay ;3.30 + mov si, offset Daycnt_To_Day ;3.30 + sub cx, si ;size of CMOS clock sup routine ;3.30 + mov di, ax ;3.30 + rep movsb ;3.30 + mov ax, di ;3.30 + call Get_Para_Offset ;3.30 + mov BinToBCD, ax ;set the address for MSCLOCK ;3.30 + mov cx, offset EndCMOSClockSet ;3.30 + mov si, offset Bin_To_BCD ;3.30 + sub cx, si ;3.30 + mov di, ax ;3.30 + rep movsb ;3.30 + mov ax, di ;3.30 + call Get_Para_Offset ;3.30 + ;3.30 +CheckK09: ;3.30 + push ax ;save ax ;3.30* + mov ax,4100h ;Q: is it a K09 ;3.30* + mov bl,0 ; ;3.30* + int 15h ; ;3.30* + pop ax ;3.30 + jc CONFIGDONE ;3.30 + ;3.30 + mov si, offset INT6C ;3.30 + mov cx, offset ENDK09 ;3.30 + sub cx, si ;size of K09 routine ;3.30 + mov di, ax ;3.30 + push di ;save destination ;3.30 + rep movsb ;3.30 + mov ax, di ; ;3.30 + call Get_Para_Offset ;AX = new ending address ;3.30 + pop di ;3.30 + ;3.30 + push ax ;3.30 + push ds ;3.30 + mov fHaveK09, 1 ;remember we have a K09 type ;3.30 + xor ax,ax ;3.30 + mov ds, ax ;3.30 + assume ds:nothing ;3.30 + ;3.30 + mov word ptr ds:[4 * 6Ch], di ;new INT 6Ch handler ;3.30 + mov ds:[4 * 6Ch +2], cs ;3.30 + ;3.30 + pop ds ;3.30 + assume ds:code ;3.30 + pop ax ;restore the ending address ;3.30 + +; +; Set up config stuff for SYSINIT +; +ConfigDone: + MOV DX,SYSINITSEG + MOV DS,DX + ASSUME DS:SYSINITSEG + SUB AX,OFFSET START$ ;3.30 + ADD AX,15 + RCR AX,1 + SHR AX, 1 + SHR AX, 1 + SHR AX, 1 + MOV FINAL_DOS_LOCATION, AX + POP AX + +GOINIT: + ADD Final_DOS_Location,CODE + Message fTestINIT,<"Final DOS location is "> + MNUM fTestINIT,Final_DOS_Location + Message fTestINIT, + PUSH CS + POP DS + + ASSUME DS:CODE,ES:NOTHING + + CMP BYTE PTR fHave96,0 + JNZ ReadDos + call purge_96tpi ;mjb001 eliminate calls to 96tpi hoohah + +ReadDos: + Message fTestINIT,<"Load FAT",CR,LF> + mov ax,DRVFAT ; Get drive and FAT ID + call SetDrive ; Get BDS for drive + call GetBP ; Ensure valid BPB is present + call GETFAT ; Read in the FAT sector + xor DI,DI + mov AL,ES:[DI] ; Get fat id byte + mov BYTE PTR DRVFAT+1,AL ; Save FAT byte + mov AX,DRVFAT + Message fTestINIT,<"FATID read "> + mnum ftestinit,ax + message ftestinit, + call SETDRIVE ; Get Correct BDS for this drive + mov BL,[DI].FatSiz ; get size of fat on media + mov fBigFat,BL + mov CL,[DI].SecPerClus ; get sectors/cluster + mov AX,[DI].HIDSEC ; get number of hidden sectors + sub BIOS$,AX ; subtract hidden sector offset + xor CH,CH ; CX = sectors/cluster +; +; THE BOOT PROGRAM HAS LEFT THE DIRECTORY AT 0:500 +; + PUSH DS + XOR DI,DI + MOV DS,DI ; ES:DI POINTS TO LOAD LOCATION + MOV BX,DS:WORD PTR [53AH] ; clus=*53A; + POP DS ; + Message fTestINIT,<"Load DOS",CR,LF> +; BAS DEBUG +;LOADIT: MOV AX,((((OFFSET END$)-(OFFSET START$))+15)/16)+SYSIZE +LOADIT: + MOV AX, OFFSET END$ ;3.30 + SUB AX, OFFSET START$ ;3.30 + ADD AX, 15 + RCR AX, 1 ; DIVIDE BY 16 + SHR AX, 1 + SHR AX, 1 + SHR AX, 1 + ADD AX, SYSIZE + + ADD AX,CODE + + MOV ES,AX ; + CALL GETCLUS ; clus = GetClus (clus); + +IsEof: + TEST fBigFat,fBIG ; if (fBigFAT) + JNZ EOFBig + Message fTestINIT, + CMP BX,0FF7h ; return (clus > 0ff7h); + JMP SHORT ISEOFX ;3.30 +EOFBig: + Message fTestINIT, + CMP BX,0FFF7h ; else +ISEOFX: ;3.30 + JB LOADIT ; } WHILE (!ISEOF (CLUS)); ;3.30 + ;3.30 + CALL SETDRVPARMS ;3.30 + ;3.30 + MESSAGE FTESTINIT,<"SYSINIT",CR,LF> ;3.30 + ZWAIT ;3.30 + MESSAGE FTESTINIT,<"ON TO SYSINIT...",CR,LF> ;3.30 + JMP SYSINIT ;3.30 + ;3.30 +INIT ENDP ;3.30 + ;3.30 +;**************************** ;3.30 + ;3.30 +Get_Para_Offset proc near ;3.30 +;in: AX - offset value ;3.30 +;out: AX - offset value adjusted for the next paragraph boundary. ;3.30 + add ax, 15 ;make a paragraph ;3.30 + rcr ax, 1 ;3.30 + shr ax, 1 ;3.30 + shr ax, 1 ;3.30 + shr ax, 1 ;3.30 + shl ax, 1 ;now, make it back to offset value ;3.30 + shl ax, 1 ;3.30 + shl ax, 1 ;3.30 + shl ax, 1 ;3.30 + ret ;3.30 +Get_Para_Offset endp ;3.30 + +; +; READ A FAT SECTOR INTO fat location +; +GETFAT PROC NEAR ;3.30 + XOR DI,DI ; offset + MOV DX,1 ; relative sector (1st sector of fat) + MOV CX,FatLen ; read entire fat. + MOV AX,FatLoc ; + MOV ES,AX ; location to read + MOV AX,DRVFAT ; AH FAT ID byte, AL drive + JMP DISKRD +GETFAT ENDP ;3.30 + + +; +; READ A BOOT RECORD INTO 7C0:BootBias +; GetBoot reads the boot record into 7C0:BootBias +; On Entry: +; DL contains ROM drive number (80 or 81) +; On Exit: +; if carry set error +; if carry clear: +; ES:BX piont to boot sector +; AX and CX are not preserved +; BX and ES are used to return values +; +GETBOOT PROC NEAR + mov AX, 07C0h ; prepare to load ES + mov ES, AX ; load ES segment register + mov BX, BootBias ; load BX, ES:BX is where sector goes + mov AX, 0201h ; command to read & num sec. to 1 + xor DH, DH ; head number zero + mov CX, 0001h ; cylinder zero and sector one + int 13h ; call rom bios + jc ERRET + cmp WORD PTR ES:[BootBias+1FEH],0AA55H ; DAVE LITTON MAGIC BYTE? + jz Norm_Ret + message ftesthard,<"Signature AA55 not found",cr,lf> +ERRET: + message ftesthard,<"Error in Getboot",cr,lf> + STC +Norm_Ret: + RET +GETBOOT ENDP ;3.30 +; +; SetHard - generate BPB for a variable sized hard file. IBM has a +; partitioned hard file; we must read physical sector 0 to determine where +; our own logical sectors start. We also read in our boot sector to +; determine version number +; +; Inputs: DL is ROM drive number (80 OR 81) +; DS:DI points to BDS +; Outputs: Carry clear -> BPB is filled in +; Carry set -> BPB is left uninitialized due to error +; + +SETHARD PROC NEAR ;3.30 + push di + push bx + push ds + mov byte ptr [di].DriveLet,bl + mov byte ptr [di].DriveNum,dl + xor ax,ax + or al,fNon_Removable + or word ptr [di].flags,ax + mov byte ptr [di].FormFactor,ffHardFile + MOV fBigFat,0 ; Assume 12 bit FAT + PUSH DX + + mov AH, 8 ; set command to get drive parameters + int 13h ; call rom-bios disk routine + + ; DH is number of heads-1 + ; DL is number of hard disks attached + ; Low 6 bits of CL is sectors/track + ; High 2 bits of CL with CH are max # of cylinders + INC DH ; get number of heads + MOV BYTE PTR [DI].HDLIM,DH + POP DX + JC SETRET ; carry here means no hard disk + AND CL,3FH ; extract number of sectors/track + MOV BYTE PTR [DI].SECLIM,CL + CALL GETBOOT ; if (getBoot ()) + JC SETRET ; return -1; + MOV BX,1C2H+BootBias ; p = &boot[0x1C2]; +SET1: + CMP BYTE PTR ES:[BX],1 ; while (p->PartitionType != 1 && + JZ SET2 + CMP Byte Ptr ES:[BX],4 ; p->PartitionType != 4) { + JZ Set2 + ADD BX,16 ; p += sizeof Partition; + CMP BX,202H+BootBias ; if (p == &boot[0x202h]) + JNZ SET1 ; return -1; +SETRET: + STC ; } + jmp Ret_Hard + +SET2: + PUSH DX + MOV AX,WORD PTR ES:[BX+4] + MOV DX,WORD PTR ES:[BX+6] + +;Decrement the sector count by 1 to make it zero based. Exactly 64k ;3.30 +;sectors should be allowed ;3.30 +; ;3.30 + SUB AX,1 ; PTM 901 12/12/86 MT ;3.30 + SBB DX,0 ; PTM 901 12/12/86 MT ;3.30 + + ADD AX,WORD PTR ES:[BX+8] + ADC DX,WORD PTR ES:[BX+10] + JZ OKDrive + Message fTestHard,<"Partition invalid",CR,LF> + OR fBigFat,fTOOBIG +OKDrive: + POP DX + MOV AX,WORD PTR ES:[BX+4] + MOV [DI].HIDSEC,AX ; BPB->HidSecCt = p->PartitionBegin; + MOV AX,WORD PTR ES:[BX+8] + CMP AX,64 ; if (p->PartitionLength < 64) + JB SETRET ; return -1; + + MOV WORD PTR [DI].DRVLIM,AX ; BPB->MaxSec = p->PartitionLength; + PUSH AX + + PUSH DX + MOV AX,[DI].HidSec ; boot sector number + XOR DX,DX + MOV BH,DH + MOV BL,byte ptr [DI].SecLim + DIV BX + MOV CL,DL ; CL is sector number + INC CL ; sectors are 1 based + CWD + MOV BL,byte ptr [DI].HdLim + DIV BX ; DL is head, AX is cylinder +; +; DL is head. +; AX is cylinder +; CL is sector number +; TOS is drive +; + +;*** For Mini Disks *** 4/7/86 ;3.30 + cmp word ptr [di].IsMini, 1 ;check for mini disk - 4/7/86 ;3.30 + jnz OKnotMini ;not mini disk. - 4/7/86 ;3.30 + add ax, [di].hidden_trks ;set phy track num - 4/7/86 ;3.30 +OKnotMini: ; 4/7/86 ;3.30 +;*** End of added logic for mini disk ;3.30 + + ROR AH,1 ; move high two bits of cyl to high + ROR AH,1 ; two bits of upper byte + AND AH,0C0h ; turn off remainder of bits + OR CL,AH ; move two bits to correct spot + MOV CH,AL ; CH is Cylinder +; +; CL is sector + 2 high bits of cylinder +; CH is low 8 bits of cylinder +; DL is head +; TOS is drive +; + POP AX ; AL is drive + MOV DH,DL ; DH is head + MOV DL,AL ; DL is drive +; +; CL is sector + 2 high bits of cylinder +; CH is low 8 bits of cylinder +; DH is head +; DL is drive +; + xor BX, BX ; clear BX -- ES:BX points to buffer + mov ax, 0201h ; set command to read one sector + int 13h ; call rom-bios to read sector + pop AX + +; +; ES:[0] points to the boot sector. In theory, (ha ha) the BPB in this thing +; is correct. We can, therefore, pull out all the relevant statistics on the +; media if we recognize the version number. +; + CMP WORD PTR ES:[3], "B" SHL 8 + "I" + JNZ Unknownj + CMP WORD PTR ES:[5], " " SHL 8 + "M" + JNZ Unknownj + CMP WORD PTR ES:[8], "." SHL 8 + "2" + JNZ Try5 + CMP BYTE PTR ES:[10], "0" + JNZ Try5 + Message fTestHard,<"Version 2.0 media",CR,LF> + JMP SHORT CopyBPB +unknownj: + jmp unknown +Try5: + CMP WORD PTR ES:[8],"." SHL 8 + "3" + JNZ Unknownj + cmp byte ptr es:[10],"1" ;do not trust 3.0 boot record. 4/15/86;3.30 + jb unknownj ;if version >= 3.1, then O.K. 4/15/86 ;3.30 + Message ftestHard,<"VERSION 3.1 OR ABOVE MEDIA",CR,LF> + +CopyBPB: +; We have a valid Boot sector. Use the BPB in it to build the +; BPB in BIOS. It is assumed that ONLY SecPerClus, cDIR, and +; cSecFat need to be set (all other values in already). fBigFat +; is also set. + MOV AX,WORD PTR ES:[11+DRVLIM-BytePerSec] ; Total sectors + MNUM fTestHard,AX + Message fTestHard,<" Sec "> + DEC AX ; Subtract # reserved (always 1) + MOV DX,WORD PTR ES:[11+cSecFAT-BytePerSec] ; Sectors for 1 fat + MNUM fTestHard,DX + Message fTestHard,<" Sec/Fat "> + MOV [DI+cSecFAT],DX ; Set in BIOS BPB + SHL DX,1 ; Always 2 FATs + SUB AX,DX ; Sub # FAT sectors + MOV DX,WORD PTR ES:[11+cDIR-BytePerSec] ; # root entries + MOV [DI+cDIR],DX ; Set in BIOS BPB + MNUM fTestHard,DX + Message fTestHard,<" directory entries "> + MOV CL,4 + SHR DX,CL ; Div by 16 ents/sector + SUB AX,DX ; Sub # dir sectors + ; AX now contains the # of data sectors. + MOV CL,BYTE PTR ES:[11+SecPerClus-BytePerSec] ; Sectors per cluster + MOV [DI.SecPerClus],CL ; Set in BIOS BPB + XOR DX,DX + MOV CH,DH + MNUM fTestHard,CX + Message fTestHard,<" SecPerClus",CR,LF> + DIV CX + ; AX now contains the # clusters. + CMP AX,4096-10 ; is this 16-bit fat? + JB GoodRetj ; No + OR fBigFat,fBIG ; 16 bit FAT +GoodRetj: + JMP GoodRet + +Unknown: + Message fTestHard,<"Unknown hard media. Assuming 3.0.",CR,LF> + MOV SI,OFFSET DiskTable2 +Scan: + CMP AX,[SI] + JBE GotParm + ADD SI,4 * 2 + JMP Scan +GotParm: + MOV CL,BYTE PTR [SI+6] + OR fBigFat,CL + MOV CX,[SI+2] + MOV DX,[SI+4] +; +; AX = number of sectors on disk drive +; DX = number of dir entries, +; CH = number of sectors per cluster +; CL = log base 2 of ch +; +; NOW CALCULATE SIZE OF FAT TABLE +; + MNUM fTestHard,AX + Message fTestHard,<" sectors "> + MNUM fTestHard,DX + Message fTestHard,<" directory entries "> + MNUM fTestHard,CX + Message fTestHard,<" SecPerClus|ClusShift"> + MOV WORD PTR cDir[DI],DX ;SAVE NUMBER OF DIR ENTRIES + MOV BYTE PTR SecPerClus[DI],CH ;SAVE SECTORS PER CLUSTER + TEST fBigFAT,fBIG ; if (fBigFat) + JNZ DoBig ; goto DoBig; + Message fTestHard,<" Small fat",CR,LF> + XOR BX,BX + MOV BL,CH + DEC BX + ADD BX,AX + SHR BX,CL ; BX = 1+(BPB->MaxSec+SecPerClus-1)/ + INC BX ; SecPerClus + AND BL,11111110B ; BX &= ~1; (=number of clusters) + MOV SI,BX + SHR BX,1 + ADD BX,SI + ADD BX,511 ; BX += 511 + BX/2 + SHR BH,1 ; BH >>= 1; (=BX/512) + MOV BYTE PTR [DI].cSecFat,BH ;SAVE NUMBER OF FAT SECTORS + JMP SHORT GOODRET ;3.30 +DoBig: + Message fTestHard,<" Big fat",CR,LF> + MOV CL,4 ; 16 (2^4) directory entries per sector + SHR DX,CL ; cSecDir = cDir / 16; + SUB AX,DX ; AX -= cSecDir; AX -= cSecReserved; + DEC AX ; ax = t - r - d + MOV BL,2 + MOV BH,SecPerClus[DI] ; bx = 256 * secperclus + 2 + XOR DX,DX + ADD AX,BX ; ax = t-r-d+256*spc+2 + ADC DX,0 + SUB AX,1 ; ax = t-r-d+256*spc+1 + SBB DX,0 + DIV BX ; cSecFat = ceil((total-dir-res)/ + ; (256*secperclus+2)); + MOV WORD PTR [DI].cSecFat,AX ; number of fat sectors +GoodRet: + MOV BL,fBigFat + MOV [DI].FatSiz,BL ; set size of fat on media + CLC +Ret_Hard: + pop ds + pop bx + pop di + RET +SETHARD ENDP ;3.30 + + +; +; SetDrvParms sets up the recommended BPB in each BDS in the system based on +; the form factor. It is assumed that the BPBs for the various form factors +; are present in the BPBTable. For hard files, the Recommended BPB is the same +; as the BPB on the drive. +; No attempt is made to preserve registers since we are going to jump to +; SYSINIT straight after this routine. +; +SETDRVPARMS PROC NEAR ;3.30 + message ftestinit,<"Setting Drive Parameters",cr,lf> + xor bx,bx + les di,dword ptr cs:[Start_BDS] ; get first BDS in list +Next_BDS: + cmp di,-1 + jnz Do_SetP +Done_SetParms: + RET +Do_SetP: + push es + push di ; preserve pointer to BDS + mov bl,es:[di].FormFactor + cmp bl,ffHardFile + jnz NotHardFF + mov ax,es:[di].DrvLim + push ax + mov ax,word ptr es:[di].hdlim + mul word ptr es:[di].seclim + mov cx,ax ; cx has # sectors per cylinder + pop ax + xor dx,dx ; set up for div + div cx ; div #sec by sec/cyl to get # cyl + or dx,dx + jz No_Cyl_Rnd ; came out even + inc ax ; round up +No_Cyl_Rnd: + mov es:[di].cCyln,ax + message ftestinit,<"Ccyln "> + MNUM ftestinit,AX + message ftestinit, + push es + pop ds + lea si,[di].BytePerSec ; ds:si -> BPB for hard file + jmp short Set_RecBPB +NotHardFF: + push cs + pop ds + cmp bl,ffOther ; Special case "other" type of medium + JNZ NOT_PROCESS_OTHER ;3.30 +Process_Other: + xor dx,dx + mov ax,[di].cCyln + mov bx,[di].RHdlim + mul bx + mov bx,[di].RSeclim + mul bx + mov [di].RDrvlim,ax ; Have the total number of sectors + dec ax + +; New logic to get the sectors/fat area. ;3.30 + ;Fat entry assumed to be 1.5 bytes;3.30 + mov bx, 3 ;3.30 + mul bx ;3.30 + mov bx,2 ;3.30 + div bx ;3.30 + xor dx, dx ;3.30 + mov bx, 512 ;3.30 + div bx ;3.30 + inc ax ;3.30 + +No_Round_Up: + mov [di].RcSecFat,ax + jmp short Go_To_Next_BDS + +NOT_PROCESS_OTHER: ;3.30 + shl bx,1 ; bx is word index into table of BPBs + mov si,offset BPBTable + mov si,word ptr [si+bx] ; get address of BPB +Set_RecBPB: + lea di,[di].RBytePerSec ; es:di -> RecBPB + mov cx,BPBSIZ + REP MOVSB ; MOVE BPBSIZ BYTES ;3.30 +Go_To_Next_BDS: + pop di + pop es ; restore pointer to BDS + mov bx,word ptr es:[di].link+2 + mov di,word ptr es:[di].link + mov es,bx + jmp Next_BDS +SETDRVPARMS ENDP ;3.30 + + +; +; READ CLUSTER SPECIFIED IN BX +; CX = SECTORS PER CLUSTER +; DI = LOAD LOCATION +; +GETCLUS PROC NEAR ;3.30 + PUSH CX + PUSH DI + MOV DOSCNT,CX ;SAVE NUMBER OF SECTORS TO READ + MOV AX,BX + DEC AX + DEC AX + MUL CX ;CONVERT TO LOGICAL SECTOR + ADD AX,BIOS$ ;ADD IN FIRST DATA SECTOR + MOV DX,AX ;DX = FIRST SECTOR TO READ + +GETCL1: + MNUM fTestINIT + Message fTestINIT,<" => "> + ;SI = BX, BX = NEXT ALLOCATION UNIT +; +; GET THE FAT ENTRY AT BX, WHEN FINISHED SI=ENTRY BX +; +UNPACK: + PUSH DS + PUSH BX + MOV SI,FatLoc + TEST fBigFat,fBIG ; if (!fBigFat) { + JNZ Unpack16 + MOV DS,SI + MOV SI,BX + SHR SI,1 + MOV BX,[SI+BX] ; p = fat[clus+clus/2]; + JNC HAVCLUS ; if (clus&1) + SHR BX,1 ; p >>= 4; + SHR BX,1 + SHR BX,1 + SHR BX,1 +HAVCLUS: + AND BX,0FFFH ; oldclus=clus; clus = p & 0xFFF; + JMP SHORT UNPACKX ;3.30 +Unpack16: ; else { + MOV DS,SI + SHL BX,1 ; oldclus = clus; + MOV BX,[BX] ; clus = fat[2*clus]; +UNPACKX: ;3.30 + POP SI ; return; + POP DS + ; } + MNUM fTestINIT + Message fTestINIT,<" "> + SUB SI,BX + CMP SI,-1 ;one apart? + JNZ GETCL2 + ADD DOSCNT,CX + JMP GETCL1 + +GETCL2: + PUSH BX + MOV AX,DRVFAT ;GET DRIVE AND FAT SPEC + MOV CX,DOSCNT + CALL DISKRD ;READ THE CLUSTERS + POP BX + POP DI + MOV AX,DOSCNT ;GET NUMBER OF SECTORS READ + XCHG AH,AL ;MULTIPLY BY 256 + SHL AX,1 ;TIMES 2 EQUAL 512 + ADD DI,AX ;UPDATE LOAD LOCATION + POP CX ;RESTORE SECTORS/CLUSTER + RET +GETCLUS ENDP ; RETURN; ;3.30 + +; +; SI POINTS TO DEVICE HEADER +; +; 4/22/86 - print_init, aux_init is modified to eliminate the ;3.30 +; self-modifying code. ;3.30 + ;3.30 +PRINT_INIT: ;3.30 + call Get_device_number ;3.30 + mov ah,1 ;initalize printer port ;3.30 + int 17h ;call ROM-Bios routine ;3.30 + ret ;3.30 + ;3.30 +AUX_INIT: ;3.30 + call Get_device_number ;3.30 + mov al,RSINIT ;2400,N,1,8 (MSEQU.INC) ;3.30* + mov ah,0 ;initalize AUX port ;3.30* + int 14h ;call ROM-Bios routine ;3.30* + ret ;3.30 + ;3.30 +GET_DEVICE_NUMBER: ;3.30 +;SI -> device header ;3.30 + MOV AL,CS:[SI+13] ;GET DEVICE NUMBER FROM THE NAME ;3.30 + SUB AL,"1" ;3.30 + CBW ;3.30 + MOV DX,AX ;3.30 + RET ;3.30 + +; +; purge_96tpi NOP's calls to 96tpi support. +; +PURGE_96TPI PROC NEAR ;MJB001 ;3.30 + PUSH DS + PUSH ES + + push cs ;mjb001 + pop es ;mjb001 + push cs ;mjb001 + pop ds ;mjb001 + ASSUME DS:CODE,ES:CODE ;3.30 + MOV SI,OFFSET PatchTable +PatchLoop: + LODSW + MOV CX,AX + JCXZ PatchDone + LODSW + MOV DI,AX + MOV AL,90h + REP STOSB + JMP PatchLoop + +PatchDone: + mov di,offset TABLE_PATCH ; ARR 2.42 + MOV AX,OFFSET EXIT + STOSW + STOSW + + POP ES + POP DS + ret ;mjb001 +PURGE_96TPI ENDP ;3.30 + +;Mini disk initialization routine. Called right after DoHard - 4/7/86;3.30 +; DoMini **************************************************************** ;3.30 +; **CS=DS=ES=code ;3.30 +; **DoMini will search for every extended partition in the system, and ;3.30 +; initialize it. ;3.30 +; **BDSM stands for BDS table for Mini disk and located right after the ;3.30 +; label End96Tpi. End_Of_BDSM will have the offset value of the ending ;3.30 +; address of BDSM table. ;3.30 +; **BDSM is the same as usual BDS except that TIM_LO, TIM_HI entries are ;3.30 +; overlapped and used to id mini disk and the number of Hidden_trks. ;3.30 +; Right now, they are called as IsMini, Hidden_Trks respectively. ;3.30 +; **DoMini will use the same routine in SETHARD routine after label SET1 ;3.30 +; to save coding. ;3.30 +; **DRVMAX determined in DoHard routine will be used for the next ;3.30 +; available logical mini disk drive number. ;3.30 +; ;3.30 +; Input: DRVMAX, DSKDRVS ;3.30 +; ;3.30 +; Output: MiniDisk installed. BDSM table established and installed to BDS.;3.30 +; num_mini_dsk - number of mini disks installed in the system. ;3.30 +; End_Of_BDSM - ending offset address of BDSM. ;3.30 +; ;3.30 +; ;3.30 +; Called modules: ;3.30 +; GetBoot, WRMSG, int 13h (AH=8, Rom) ;3.30 +; FIND_MINI_PARTITION (new), Install_BDSM (new), ;3.30 +; SetMini (new, it will use SET1 routine) ;3.30 +; Variables used: End_Of_BDSM, numh, mininum, num_mini_dsk, ;3.30 +; Rom_Minidsk_num, Mini_HDLIM, Mini_SECLIM ;3.30 +; BDSMs, BDSM_type (struc), Start_BDS ;3.30 +;************************************************************************ ;3.30 +; ;3.30 + ;3.30 +DoMini: ;3.30 + Message fTestHard,<"Start of DoMini...",cr,lf> ;3.30 + ;3.30 + push ax ;Do I need to do this? ;3.30 + ;3.30 + mov di, offset BDSMs ;from now on, DI points to BDSM ;3.30 + mov dl, 80h ;look at first hard drive ;3.30* + mov ah, 8h ;get drive parameters ;3.30* + int 13h ;call ROM-Bios ;3.30* + cmp dl, 0 ;3.30 + jz DoMiniRet ;no hard file? Then exit. ;3.30 + mov numh, dl ;save the number of hard files. ;3.30 + xor ax,ax ;3.30 + mov al, drvmax ;3.30 + mov mininum, al ;this will be logical drive letter;3.30 + ;for mini disk to start with. ;3.30 + ;3.30 + shl ax, 1 ;ax=number of devices. word bndry ;3.30 + push bx ;3.30 + mov bx, offset DSKDRVS ;3.30 + add bx, ax ;3.30 + mov Mini_BPB_ptr, BX ;Mini_BPB_ptr points to first avlb;3.30 + ;spot in DskDrvs for Mini disk ;3.30 + ;which points to BPB area of BDSM.;3.30 + pop bx ;3.30 + ;3.30 + mov Rom_Minidsk_num, 80h ;3.30 +DoMiniBegin: ;3.30 + inc dh ;Get # of heads (conv to 1 based) ;3.30 + xor ax, ax ;3.30 + mov al, dh ;3.30 + mov Mini_HDLIM, ax ;save it. ;3.30 + xor ax, ax ;3.30 + and cl, 3fh ;Get # of sectors/track ;3.30 + mov al, cl ;3.30 + mov Mini_SECLIM, ax ;and save it. ;3.30 + ;3.30 + mov dl, Rom_Minidsk_num ;drive number