diff --git a/README.md b/README.md
index b4bc405..9281069 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,11 @@
-# MS-DOS v1.25 and v2.0 Source Code
+# MS-DOS v1.25, v2.0, v4.0 Source Code
-This repo contains the original source-code and compiled binaries for MS-DOS v1.25 and MS-DOS v2.0.
+This repo contains the original source-code and compiled binaries for MS-DOS v1.25 and MS-DOS v2.0, plus the source-code for MS-DOS v4.00 jointly developed by IBM and
+Microsoft.
-These are the same files [originally shared at the Computer History Museum on March 25th, 2014]( http://www.computerhistory.org/atchm/microsoft-ms-dos-early-source-code/) and are being (re)published in this repo to make them easier to find, reference-to in external writing and works, and to allow exploration and experimentation for those interested in early PC Operating Systems.
+The MS-DOS v1.25 and v2.0 files [were originally shared at the Computer History Museum on March 25th, 2014]( http://www.computerhistory.org/atchm/microsoft-ms-dos-early-source-code/) and are being (re)published in this repo to make them easier to find, reference-to in external writing and works, and to allow exploration and experimentation for those interested in early PC Operating Systems.
# License
diff --git a/v4.0-ozzie/Multitasking DOS BETA - 286 Compatability.pdf b/v4.0-ozzie/Multitasking DOS BETA - 286 Compatability.pdf
new file mode 100644
index 0000000..e56cb3d
Binary files /dev/null and b/v4.0-ozzie/Multitasking DOS BETA - 286 Compatability.pdf differ
diff --git a/v4.0-ozzie/Multitasking DOS BETA - Command Guide.pdf b/v4.0-ozzie/Multitasking DOS BETA - Command Guide.pdf
new file mode 100644
index 0000000..6df8d3d
Binary files /dev/null and b/v4.0-ozzie/Multitasking DOS BETA - Command Guide.pdf differ
diff --git a/v4.0-ozzie/Multitasking DOS BETA - Device Drivers.pdf b/v4.0-ozzie/Multitasking DOS BETA - Device Drivers.pdf
new file mode 100644
index 0000000..7054542
Binary files /dev/null and b/v4.0-ozzie/Multitasking DOS BETA - Device Drivers.pdf differ
diff --git a/v4.0-ozzie/Multitasking DOS BETA - Dynamic Linking.pdf b/v4.0-ozzie/Multitasking DOS BETA - Dynamic Linking.pdf
new file mode 100644
index 0000000..d40f2c5
Binary files /dev/null and b/v4.0-ozzie/Multitasking DOS BETA - Dynamic Linking.pdf differ
diff --git a/v4.0-ozzie/Multitasking DOS BETA - Intro.pdf b/v4.0-ozzie/Multitasking DOS BETA - Intro.pdf
new file mode 100644
index 0000000..abc1ee9
Binary files /dev/null and b/v4.0-ozzie/Multitasking DOS BETA - Intro.pdf differ
diff --git a/v4.0-ozzie/Multitasking DOS BETA - Memory Management.pdf b/v4.0-ozzie/Multitasking DOS BETA - Memory Management.pdf
new file mode 100644
index 0000000..c9f9a07
Binary files /dev/null and b/v4.0-ozzie/Multitasking DOS BETA - Memory Management.pdf differ
diff --git a/v4.0-ozzie/Multitasking DOS BETA - Overview.pdf b/v4.0-ozzie/Multitasking DOS BETA - Overview.pdf
new file mode 100644
index 0000000..ce6f077
Binary files /dev/null and b/v4.0-ozzie/Multitasking DOS BETA - Overview.pdf differ
diff --git a/v4.0-ozzie/Multitasking DOS BETA - Release Notes.pdf b/v4.0-ozzie/Multitasking DOS BETA - Release Notes.pdf
new file mode 100644
index 0000000..8a632f3
Binary files /dev/null and b/v4.0-ozzie/Multitasking DOS BETA - Release Notes.pdf differ
diff --git a/v4.0-ozzie/Multitasking DOS BETA - Session Manager.pdf b/v4.0-ozzie/Multitasking DOS BETA - Session Manager.pdf
new file mode 100644
index 0000000..5c02646
Binary files /dev/null and b/v4.0-ozzie/Multitasking DOS BETA - Session Manager.pdf differ
diff --git a/v4.0-ozzie/Multitasking DOS BETA - System Calls.pdf b/v4.0-ozzie/Multitasking DOS BETA - System Calls.pdf
new file mode 100644
index 0000000..e09f284
Binary files /dev/null and b/v4.0-ozzie/Multitasking DOS BETA - System Calls.pdf differ
diff --git a/v4.0-ozzie/Multitasking DOS BETA - Welcome Beta Site Letter.pdf b/v4.0-ozzie/Multitasking DOS BETA - Welcome Beta Site Letter.pdf
new file mode 100644
index 0000000..80cbbdb
Binary files /dev/null and b/v4.0-ozzie/Multitasking DOS BETA - Welcome Beta Site Letter.pdf differ
diff --git a/v4.0-ozzie/Multitasking DOS BETA - Welcome OEMs Letter.pdf b/v4.0-ozzie/Multitasking DOS BETA - Welcome OEMs Letter.pdf
new file mode 100644
index 0000000..a19def0
Binary files /dev/null and b/v4.0-ozzie/Multitasking DOS BETA - Welcome OEMs Letter.pdf differ
diff --git a/v4.0-ozzie/bin/DISK1/AUTOEXEC.BAT b/v4.0-ozzie/bin/DISK1/AUTOEXEC.BAT
new file mode 100644
index 0000000..7842e98
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK1/AUTOEXEC.BAT
@@ -0,0 +1,5 @@
+date
+time
+prompt $p$g
+path a:\bin;a:\
+
\ No newline at end of file
diff --git a/v4.0-ozzie/bin/DISK1/BIN/ARENA.EXE b/v4.0-ozzie/bin/DISK1/BIN/ARENA.EXE
new file mode 100644
index 0000000..0bf52f1
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/BIN/ARENA.EXE differ
diff --git a/v4.0-ozzie/bin/DISK1/BIN/BBSET.EXE b/v4.0-ozzie/bin/DISK1/BIN/BBSET.EXE
new file mode 100644
index 0000000..1414161
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/BIN/BBSET.EXE differ
diff --git a/v4.0-ozzie/bin/DISK1/BIN/CHKDSK.EXE b/v4.0-ozzie/bin/DISK1/BIN/CHKDSK.EXE
new file mode 100644
index 0000000..3a6dded
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/BIN/CHKDSK.EXE differ
diff --git a/v4.0-ozzie/bin/DISK1/BIN/COUNTDOW.EXE b/v4.0-ozzie/bin/DISK1/BIN/COUNTDOW.EXE
new file mode 100644
index 0000000..148ce1c
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/BIN/COUNTDOW.EXE differ
diff --git a/v4.0-ozzie/bin/DISK1/BIN/DEMO1.BAT b/v4.0-ozzie/bin/DISK1/BIN/DEMO1.BAT
new file mode 100644
index 0000000..c4f8563
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK1/BIN/DEMO1.BAT
@@ -0,0 +1,3 @@
+cd bin
+pound 290 a:bbset.exe a:sm.exe
+
\ No newline at end of file
diff --git a/v4.0-ozzie/bin/DISK1/BIN/DEMO2.BAT b/v4.0-ozzie/bin/DISK1/BIN/DEMO2.BAT
new file mode 100644
index 0000000..49fe3d6
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK1/BIN/DEMO2.BAT
@@ -0,0 +1,4 @@
+c:
+cd \bin
+pound 800 bbset.exe sm.exe
+
\ No newline at end of file
diff --git a/v4.0-ozzie/bin/DISK1/BIN/DEMO3.BAT b/v4.0-ozzie/bin/DISK1/BIN/DEMO3.BAT
new file mode 100644
index 0000000..eb99c7b
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK1/BIN/DEMO3.BAT
@@ -0,0 +1,7 @@
+c:
+cd \bin
+cd a:\bin
+detach pound 800 bbset.exe sm.exe
+detach pound 290 a:bbset.exe a:sm.exe
+basica a:prime
+
\ No newline at end of file
diff --git a/v4.0-ozzie/bin/DISK1/BIN/DETACH.EXE b/v4.0-ozzie/bin/DISK1/BIN/DETACH.EXE
new file mode 100644
index 0000000..dc75d46
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/BIN/DETACH.EXE differ
diff --git a/v4.0-ozzie/bin/DISK1/BIN/HE_DAEM.EXE b/v4.0-ozzie/bin/DISK1/BIN/HE_DAEM.EXE
new file mode 100644
index 0000000..3cf823b
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/BIN/HE_DAEM.EXE differ
diff --git a/v4.0-ozzie/bin/DISK1/BIN/KILL.EXE b/v4.0-ozzie/bin/DISK1/BIN/KILL.EXE
new file mode 100644
index 0000000..ef240b6
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/BIN/KILL.EXE differ
diff --git a/v4.0-ozzie/bin/DISK1/BIN/POUND.EXE b/v4.0-ozzie/bin/DISK1/BIN/POUND.EXE
new file mode 100644
index 0000000..1ed27f1
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/BIN/POUND.EXE differ
diff --git a/v4.0-ozzie/bin/DISK1/BIN/PRIME.BAS b/v4.0-ozzie/bin/DISK1/BIN/PRIME.BAS
new file mode 100644
index 0000000..a088c0c
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/BIN/PRIME.BAS differ
diff --git a/v4.0-ozzie/bin/DISK1/BIN/SLEEP.EXE b/v4.0-ozzie/bin/DISK1/BIN/SLEEP.EXE
new file mode 100644
index 0000000..fdeaa14
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/BIN/SLEEP.EXE differ
diff --git a/v4.0-ozzie/bin/DISK1/BIN/SM.EXE b/v4.0-ozzie/bin/DISK1/BIN/SM.EXE
new file mode 100644
index 0000000..15da78c
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/BIN/SM.EXE differ
diff --git a/v4.0-ozzie/bin/DISK1/BIN/TEXT.EXE b/v4.0-ozzie/bin/DISK1/BIN/TEXT.EXE
new file mode 100644
index 0000000..edcc27f
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/BIN/TEXT.EXE differ
diff --git a/v4.0-ozzie/bin/DISK1/COMMAND.COM b/v4.0-ozzie/bin/DISK1/COMMAND.COM
new file mode 100644
index 0000000..3546cbd
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/COMMAND.COM differ
diff --git a/v4.0-ozzie/bin/DISK1/COMMANDS.DOC b/v4.0-ozzie/bin/DISK1/COMMANDS.DOC
new file mode 100644
index 0000000..0fcfed7
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK1/COMMANDS.DOC
@@ -0,0 +1,199 @@
+
+
+
+
+
+
+ Multi-Tasking MS-DOS
+ Beta Test Release 1.00
+
+ Command Guide
+
+
+ ARENA.EXE - Prints out arena assignments
+
+ arena
+
+ The system's memory arena is printed out. The
+ number listed under the owner field is the PID of
+ the process which owns the memory.
+
+
+ BBSET.EXE - Set and report on behavior bits
+
+ bbset [-o] [ {+|-}bitname ... ] fname ...
+
+ BBSET sets or clears behavior bits in an .EXE file
+ header. Multi-Tasking MS-DOS uses the behavior
+ bits to determine the level of special
+ compatibility support needed to run the
+ application.
+
+ BBSET will set (if +bitname) or clear (if -
+ bitname) the named behavior bit(s) from the
+ specified files. If the -o switch is specified,
+ BBSET writes a report on the current setting of
+ all the defined behavior bits to stdout after
+ making the requested changes.
+
+ For a list of behavior bits that BBSET knows
+ about, type BBSET without any arguments.
+
+
+ COUNTDOW.EXE - Count down a CPU loop
+
+ countdown number
+
+ Its argument is a number; it counts the number
+ down to 0, at about a 1hz rate. It prints out
+ the countdown. Another CPU loop program like
+ TEXT, but this one terminates when the count
+ reaches 0
+
+
+ DETACH.EXE - Detaches a child process
+
+ detach command [argument ...]
+
+ The command given is run as a background process.
+ Detach prints out the Command Subgroup ID (CSID)
+ which may be used as an argument to KILL to
+ terminate the process.
+
+
+
+
+
+
+
+
+
+ Multi-Tasking MS-DOS Command Guide - Page: 2
+
+ HE_DAEM.EXE - Hard error catcher
+
+ detach he_daem
+
+ Intercepts hard errors, reports them and requests
+ user action. This should always be run in the
+ background for now. Put the above command line in
+ your AUTOEXEC.BAT file if you're not going to use
+ the Session Manager (SM).
+
+
+ KILL.EXE - send a signal to a process
+
+ kill [-nn] [sig=nn] [disp=mm] pid ...
+
+ Sends signal nn with disposition mm to processes
+ mentioned in pid. Defaults to SIGTERM and process
+ tree disposition.
+
+
+ POUND.EXE - Exercise disk I/O system
+
+ pound [t]count filea fileb
+
+ Pound reads sequencially through filea and fileb,
+ reading 512 bytes at a time alternating between
+ the files on each read. When the end of file is
+ read the following read for that file begins at
+ the beginning of the file. If a count is
+ specified without the preceeding "t" then pound
+ reads 512 bytes, count number of times from each
+ file before the program terminates. If "t"
+ preceeds the count value then the files are read
+ for count number of seconds before the program
+ terminates.
+
+
+ SLEEP.EXE - Sleep for a while
+
+ sleep sec[.millisec]
+
+ Sleep will execute a sleep system call for the
+ number of seconds and milliseconds specified.
+ This might be useful in batch files to pause for
+ an interval as opposed to waiting for a user
+ response.
+
+
+ SM.EXE - Session manager
+
+ sm
+
+ Manages multiple processes running on different
+ screens. Uses initialization file SM.INI. This
+
+
+
+
+
+
+
+
+
+
+ Multi-Tasking MS-DOS Command Guide - Page: 3
+
+ program includes the hard error catcher, so don't
+ run HE_DAEM if you're going to use this. See the
+ file SM.DOC for more information.
+
+
+ TEXT.EXE - Loop and print text
+
+ text argument
+
+ CPU loops and prints its argument every 2 CPU
+ seconds or so
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/v4.0-ozzie/bin/DISK1/CONFIG.SYS b/v4.0-ozzie/bin/DISK1/CONFIG.SYS
new file mode 100644
index 0000000..3d6d514
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK1/CONFIG.SYS
@@ -0,0 +1,3 @@
+buffers = 40
+files = 20
+break=on
diff --git a/v4.0-ozzie/bin/DISK1/DOS33/FDISK.COM b/v4.0-ozzie/bin/DISK1/DOS33/FDISK.COM
new file mode 100644
index 0000000..b4e3af1
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/DOS33/FDISK.COM differ
diff --git a/v4.0-ozzie/bin/DISK1/DOS33/FORMAT.COM b/v4.0-ozzie/bin/DISK1/DOS33/FORMAT.COM
new file mode 100644
index 0000000..306fc49
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/DOS33/FORMAT.COM differ
diff --git a/v4.0-ozzie/bin/DISK1/DOS33/SYS.COM b/v4.0-ozzie/bin/DISK1/DOS33/SYS.COM
new file mode 100644
index 0000000..d26e982
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/DOS33/SYS.COM differ
diff --git a/v4.0-ozzie/bin/DISK1/IBMBIO.COM b/v4.0-ozzie/bin/DISK1/IBMBIO.COM
new file mode 100644
index 0000000..280a2ef
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/IBMBIO.COM differ
diff --git a/v4.0-ozzie/bin/DISK1/IBMDOS.COM b/v4.0-ozzie/bin/DISK1/IBMDOS.COM
new file mode 100644
index 0000000..a859665
Binary files /dev/null and b/v4.0-ozzie/bin/DISK1/IBMDOS.COM differ
diff --git a/v4.0-ozzie/bin/DISK1/README b/v4.0-ozzie/bin/DISK1/README
new file mode 100644
index 0000000..4163d4f
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK1/README
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+ Multi-Taking MS-DOS
+ Beta Test Release 1.00
+
+ Release Notes
+
+
+ Enclosed you will find Microsoft's first beta release
+ of Multi-tasking MS-DOS. This version is based upon MS-DOS
+ Version 2 sources, we will be reimplementing the multi-
+ tasking enhancements on top of Version 3 sources shortly.
+
+ Although we have distributed a bootable disk for the
+ IBM PC, this package can be adapted to any MS-DOS machine.
+ Those manufacturers who are designing IBM compatible ROMs,
+ would be wise to keep multi-tasking in mind. Specifically,
+ this IBM PC implementation has had to hook out the entire
+ disk (both floppy and hard disk) ROM code because after he
+ IBM code set's up the DMA transfer it simply loops in ROM
+ waiting for the interrupt to occur (routine WAIT_INT).
+
+ Problems you may wish to avoid within future ROMs are:
+ 1) loading ES with the physical video RAM location
+ (label M3)
+ 2) Looping in ROM on Cntrl-NumLock (label K40)
+ 3) No way to add special detecting special key
+ strokes which a jump out into RAM after reading
+ the keystroke at KB_INT would avoid
+ 4) Not being able to hook the loading of DS to point
+ to DATA (EQU 40H) in numerous routines.
+ Other than these deficiencies the ROM code developed should
+ be very usable.
+
+ By implementing the above suggestions, the size of your
+ BIOS can be reduced since it will not be necessary to
+ duplicate functionality in RAM.
+
+ More detailed specifications of the device driver
+ formats will be forth coming. For the time being you will
+ have to make use of the sample source code for the IBM PC.
+ If you have further questions please contact Microsoft OEM
+ customer support through Technical Assist Requests (TAR).
+
+
+ * * * WARNING * * * WARNING * * * WARNING * * *
+
+ Each copy of this software distribution has been
+ individually serialized to facilitate tracing of
+ unauthorized duplication.
+
+ * * * WARNING * * * WARNING * * * WARNING * * *
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/v4.0-ozzie/bin/DISK1/SM.DOC b/v4.0-ozzie/bin/DISK1/SM.DOC
new file mode 100644
index 0000000..ebbe220
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK1/SM.DOC
@@ -0,0 +1,199 @@
+
+
+
+
+
+
+ Multi-Tasking MS-DOS
+ Beta Test Release 1.00
+
+ Session Manager
+ User's Guide
+
+
+ Introduction
+
+ The Session Manager(SM) for Multi-Tasking MS-DOS
+ allows you to run up to six programs at one time and switch
+ between them with a couple of keystrokes. Each program's
+ screen is preserved so that it can be restored when you
+ switch back to it. SM also contains the system-wide, Int24
+ Handler.
+
+
+ Initialization
+
+ The first thing SM does when it is started is look for
+ any program initialization information you may have. SM
+ looks for the initialization information in a file named
+ SM.INI in the current directory. Although recommended, no
+ initialization information is needed.
+
+ There are two types of initialization lines:
+ 1) define [program args]
+
+ 2) start
+
+ "program key" - a printable ascii character, a control
+ character (^A thru ^^), or a function key (F1
+ - F10).
+ "working directory" - a well formed path; i.e., begins
+ with drive letter (d:\).
+
+ Each define line will associate a key with a program.
+ If there is more than one define line using the same key,
+ only the information in the last one is used.
+
+ A start line is optional. If one exists, the program
+ associated with the key on the start line is run as soon as
+ SM finishes initializing. If more than one start line is
+ given, the last one is used.
+
+ This is what a sample initialization file might look like:
+
+ define f1 a:\command.com c:\bin\src
+ define ^z z.exe foo.c a:\foo\bar
+ start f1
+
+
+ Running the Session Manager
+
+ To run Session Manager, just type SM. It does not
+ require any arguments. If there was a start line in the
+
+
+
+
+
+
+
+
+ Session Manager User's Guide - Page: 2
+
+ initialization file, the program associated with the start
+ key will be run. Otherwise, the SM screen will be displayed
+ and you will be prompted for input.
+
+ The SM screen contains a chart that describes each
+ defined program's key, status, arguments, and working
+ directory. There are 3 types of program status:
+
+ 1) New - the program has never been run.
+ 2) Active - the program has been started.
+ 3) Dead - the program has terminated.
+
+ The input choices at this point are to either type a
+ program key or hit the button to enter command mode.
+ If you hit a program key, the screen associated with that
+ program will be displayed and the program will
+ start/continue executing. If this is the first time the
+ program has been run, a chdir to the program's working
+ directory is made before it is started. If SM cannot start
+ the program you desired, the SM screen will reappear.
+
+ If the program you chose to run has died, its screen
+ will still be displayed so that you can check its output.
+ That is all you can do while in a dead programs screen
+ except switch back to SM.
+
+ To switch back to SM, hit Alt-F10. Alt-F10 is
+ currently the program key for SM and will be recognized no
+ matter what other programs are running. This is the only
+ program key that works this way. All of the others will
+ only be recognized if SM is running and the SM screen is
+ being displayed.
+
+ Whenever any of SM's children die, their status is
+ changed to dead. You will see the status change the next
+ time the SM screen is displayed. If the program using the
+ current screen dies, you will go back into SM.
+
+
+ Command Mode
+
+ When you enter SM's command mode the prompt "SM command or
+ HELP>" is displayed. The valid SM commands are:
+
+ 1) INIT
+ Initialize the program associated with key so that
+ it can be run again. The program's status is
+ changed to "New" and its screen memory is freed.
+ If the program is active, it is killed before it
+ is initialized.
+
+ 2) DEFINE [program args]
+
+ Define and run a new program using the supplied
+ information. If the key was previously defined,
+ redefine it.
+
+
+
+
+
+
+
+
+ Session Manager User's Guide - Page: 3
+
+ 3) RUN
+ Run the program associated with key.
+
+ 4) RESTART
+ Restart the program associated with key. This
+ like issuing an INIT and a RUN command.
+
+ 5) KILL
+ Kill the program associated with key. Its status
+ is changed to dead.
+
+ 6) HELP
+ Display a help screen.
+
+ 7) EXIT
+ Kill all of SM's children and exit SM.
+
+ In all of the above commands, "key" is the printable
+ ascii representation of a programs key. If a command fails,
+ you will either be asked to enter a new command or placed in
+ SM's top level.
+
+
+ Session Manager's Int24 Handler
+
+ Whenever an Int24 occurs, SM's Int24 handler is called.
+ No matter what program is using the screen and no matter
+ which program caused the error, SM's Int24 screen is always
+ displayed. This screen will contain information on the type
+ of Int24 that happened, and the name and pid of the program
+ that caused the error. You will then be prompted for one of
+ the valid actions for this type of error. After the action
+ typed in has been taken, you are returned to the screen you
+ were using before the Int24.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/v4.0-ozzie/bin/DISK1/SM.INI b/v4.0-ozzie/bin/DISK1/SM.INI
new file mode 100644
index 0000000..bf7dfc8
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK1/SM.INI
@@ -0,0 +1,2 @@
+define F7 a:\command.com a:\
+define F8 a:\command.com c:\
diff --git a/v4.0-ozzie/bin/DISK2/BIOS/ANSI.INC b/v4.0-ozzie/bin/DISK2/BIOS/ANSI.INC
new file mode 100644
index 0000000..37e661b
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK2/BIOS/ANSI.INC
@@ -0,0 +1,573 @@
+; Termcap description of capabilities:
+
+;ibmans4:mtcon:IBM PC with V4.0 ANSI driver:\
+; :al=\E[L:am:bs:ce=\E[K:cl=\E[2J\E[H:cm=\E[%;%H:co#80:\
+; :dl=\E[M:do=\E[B:ho=\E[H:li#24:mi:nd=\E[C:\
+; :ms:pt:se=\E[m:so=\E[1;36m:up=\E[A:\
+; :kb=^h:ku=\E[A:kd=\E[B:kl=\E[D:kr=\E[C:kh=\E[H:kn#8:\
+; :k1=\ES:k2=\ET:k3=\EU:k4=\EV:k5=\EW:\
+; :k6=\EP:k7=\EQ:k8=\ER:
+
+CMDTABL DB 'A'
+ DW CUU ;CUrsor Up
+ DB 'B'
+ DW CUD ;CUrsor Down
+ DB 'C'
+ DW CUF ;CUrsor Forward
+ DB 'D'
+ DW CUB ;CUrsor Back
+ DB 'H'
+ DW CUP ;CUrsor Position
+ DB 'J'
+ DW ED ;Erase in Display
+ DB 'K'
+ DW EL ;Erase in Line
+ DB 'L'
+ DW IL ;Insert Line
+ DB 'M'
+ DW xDL ;Delete Line
+;; DB 'R'
+;; DW CPR ;Cursor Postion Report
+ DB 'f'
+ DW HVP ;Horizontal and Vertical Position
+ DB 'h'
+ DW SM ;Set Mode
+ DB 'l'
+ DW RM ;Reset Mode
+ DB 'm'
+ DW SGR ;Select Graphics Rendition
+;; DB 'n'
+;; DW DSR ;Device Status Report
+ DB 's'
+ DW SCP ;Save Cursor Position
+ DB 'u'
+ DW RCP ;Restore Cursor Position
+ DB 00
+
+; Graphic Rendition modes: parameter, mask, set
+GRMODE DB 00,00000000B,00000111B ; all off
+ DB 01,11111111B,00001000B ; bold (increased intensity)
+ DB 04,11111000B,00000001B ; underscore
+ DB 05,11111111B,10000000B ; blink
+ DB 07,11111000B,01110000B ; reverse video
+ DB 08,10001000B,00000000B ; concealed
+ DB 30,11111000B,00000000B ; foreground colors ...
+ DB 31,11111000B,00000100B
+ DB 32,11111000B,00000010B
+ DB 33,11111000B,00000110B
+ DB 34,11111000B,00000001B
+ DB 35,11111000B,00000101B
+ DB 36,11111000B,00000011B
+ DB 37,11111000B,00000111B
+ DB 40,10001111B,00000000B ; background colors ...
+ DB 41,10001111B,01000000B
+ DB 42,10001111B,00100000B
+ DB 43,10001111B,01100000B
+ DB 44,10001111B,00010000B
+ DB 45,10001111B,01010000B
+ DB 46,10001111B,00110000B
+ DB 47,10001111B,01110000B
+ DB 0FFH
+
+; Set/Reset Modes: indexed by (SelChar-'<'*8) + (PARAM0 AND 7)
+SRMODE DW 0,0,0,0,0,0,0,0 ; SelChar '<'
+ DW 1,1,1,1,1,1,1,WRAP ; SelChar '='
+ DW 0,EnaL25,0,0,0,0,0,0 ; SelChar '>'
+ DW 0,0,0,0,0,0,0,WRAP ; SelChar '?'
+
+PAGE
+; The following are duplicates of the same variables from the ROM
+;
+;* WARNING - the following two variables are accessed as a word
+MODE DB 3
+MAXCOL DB 79
+IF LINE25 ; special treatment of line 25?
+maxrow equ 24
+ELSE
+maxrow equ 25
+ENDIF
+;* WARNING - the following two variables are accessed as a word
+COL DB 0 ; current column
+ROW DB 0 ; current row
+
+
+AnsiState LABEL BYTE ; the following must be saved on a screen swap
+WRAP DB 1 ; 0 = NO WRAP, 1 = WRAP
+EnaL25 DB 0 ; 0 = 25th line disabled, 1 = enabled
+STATE DW S1
+SAVCR DW 0 ; saved cursor position
+;* WARNING - the following two variables are accessed as a word
+SelChar DB 0 ; <,=,> or ? private use indicators
+PRMCNT LABEL BYTE ; number of parameters for command
+PRMCNTW DW 0
+NUMPARAM equ 5 ; max. number of parameters
+PARAM DB NUMPARAM DUP (?) ; buffer for command parameters
+;* WARNING - the following two variables are accessed as a word
+attrw LABEL WORD
+ATTR DB 00000111B ;CHARACTER ATTRIBUTE
+BPAGE DB 0 ;BASE PAGE
+
+AnsiSize equ ($-AnsiState)
+
+IF (AnsiSize GT TermSize)
+ .RADIX 0 ; ERROR - Terminal state not big enough
+ENDIF
+
+;-------------------------------------------------------------
+;
+; CHROUT - WRITE OUT CHAR IN AL USING CURRENT ATTRIBUTE
+;
+base dw 0b800h
+screen_seg dw 00000h
+
+chrout: cmp al,13 ; carriage return?
+ ja outchr
+ jnz trylf
+ mov [col],0
+;; jmp short setit
+ jmp setit
+
+trylf: cmp al,10 ; line feed?
+ jz lf
+ cmp al,7 ; bell?
+ jnz trytab
+torom:
+ mov bx,[attrw]
+ and bl,7
+ mov ah,14
+ int 10h
+ret5: ret
+
+trytab:
+ cmp al,9 ; tab?
+ jnz tryback
+ mov al,[col]
+ add al,8
+ mov ah,al
+ and ah,7
+ sub al,ah
+ cmp al,[maxcol]
+ jb tunder
+ mov al,[maxcol]
+tunder:
+ mov [col],al
+ jmp short setit
+
+tryback:
+ cmp al,8 ; backspace?
+ jnz outchr
+ cmp [col],0
+ jz ret5
+ dec [col]
+ jmp short setit
+
+outchr:
+ mov bx,[attrw]
+ mov cx,1
+ mov ah,9
+ int 10h
+ inc [col]
+ mov al,[col]
+ cmp al,[maxcol]
+ jbe setit
+ cmp [wrap],1
+ jz outchr1
+ dec [col]
+ ret
+outchr1:
+ mov [col],0
+lf: cmp [row],(maxrow-1)
+ ja setit ; on line 25, don't move
+ jz lf1 ; on 24th line, scroll
+ inc [row]
+ jmp short setit
+lf1: call scroll
+
+setit: mov dx,word ptr col
+ mov bh,[bpage]
+ mov ah,2
+ int 10h
+ ret
+
+scroll: mov al,mode
+ cmp al,2
+ jz myscroll
+ cmp al,3
+ jz myscroll
+IF LINE25
+ xor cx,cx ; from 0,0
+ mov dh,(maxrow-1) ; to maxrow-1,maxcol
+ mov dl,maxcol
+ mov bh,attr
+ mov ax,0601h ; scroll up one line
+ int 10h
+ ret
+ELSE
+ mov al,10
+ jmp torom
+ENDIF
+myscroll:
+ mov bh,[attr]
+ mov bl,' '
+ mov bp,80
+ mov ax,[base]
+ add ax,[screen_seg]
+ mov es,ax
+ mov ds,ax
+ xor di,di
+ mov si,160
+ mov cx,(maxrow-1)*80
+ cld
+
+; This code will never get executed since we get here when
+; mode = 2 or 3 only.
+;; cmp cs:[base],0b800h
+;; jz colorcard
+
+;; rep movsw
+;; mov ax,bx
+;; mov cx,bp
+;; rep stosw
+;; jmp short sret
+
+;;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
+sret: push cs
+ pop ds
+ ret
+
+
+CharOut: PUSH AX ; Main entry point
+ PUSH BX
+ PUSH CX
+ PUSH DX
+ PUSH SI
+ PUSH DI
+ PUSH ES
+ PUSH BP
+
+ MOV [base],0B800H
+ XCHG AX,SI ; SAVE CHARACTER TO STUFF
+ MOV AX,40H ; POINT TO ROS BIOS
+ MOV DS,AX
+ MOV AX,DS:[49H] ; AL=MODE, AH=MAX COL
+ DEC AH ; ANSI NEEDS 0-79 OR 0-39
+ MOV WORD PTR CS:[MODE],AX ; SAVE MODE AND MAX COL
+ CMP AL,7
+ JNZ NOT_BW
+ MOV WORD PTR CS:[base],0B000H
+NOT_BW: MOV AL,DS:[62H] ; GET ACTIVE PAGE
+ MOV CS:[BPAGE],AL
+ CBW
+ ADD AX,AX
+ MOV BX,AX
+ MOV AX,DS:[BX+50H] ; AL=COL, AH=ROW
+ MOV WORD PTR CS:[COL],AX ; SAVE ROW AND COLUMN
+ MOV AX,DS:[4EH] ; GET START OF SCREEN SEG
+ MOV CL,4
+ SHR AX,CL ; CONVERT TO A SEGMENT
+ PUSH CS
+ POP DS
+ MOV [screen_seg],AX
+ XCHG AX,SI ; GET BACK CHARACTER IN AL
+
+ CALL VIDEO
+ POP BP
+ POP ES
+ POP DI
+ POP SI
+ POP DX
+ POP CX
+ POP BX
+ POP AX
+ RET
+
+
+;----------------------------------------------------------
+;
+; OUTPUT SINGLE CHAR IN AL TO VIDEO DEVICE
+;
+VIDEO: MOV SI,OFFSET STATE
+ JMP [SI]
+
+S2: CMP AL,'['
+ JZ S22
+ JMP S1
+S22: MOV WORD PTR [SI],OFFSET S30
+ XOR BX,BX
+ MOV WORD PTR SelChar,BX
+ MOV WORD PTR PARAM,BX
+ JMP SHORT S3B
+
+S30: CMP AL,'?' ; experimental use selector (SM/RM)?
+ JA S7
+ mov SelChar,al
+ MOV WORD PTR [SI],OFFSET S3
+ cmp al,'<'
+ jae S3B
+
+S3: CMP AL,';'
+ JNZ S3C
+S3A: INC PRMCNT
+S3B: CALL GETPTR
+ XOR AX,AX
+ MOV WORD PTR [BX],AX ;DEFAULT VALUE IS ZERO
+ RET
+
+S3C: CMP AL,'0'
+ JB S3D
+ CMP AL,'9'
+ JA S7
+ CALL GETPTR
+ SUB AL,'0'
+ XCHG AL,BYTE PTR [BX]
+ MOV AH,10
+ MUL AH ;*10
+ ADD BYTE PTR [BX],AL ;MOVE IN DIGIT
+ RET
+
+S3D:
+;; CMP AL,'"' ;BEGIN QUOTED STRING
+;; JZ S3E
+;; CMP AL,"'"
+ JNZ S7
+;;S3E: MOV WORD PTR [SI],OFFSET S4
+;; MOV [INQ],AL
+S3RET: RET
+
+;
+; ENTER QUOTED STRINGS
+;
+
+;;S4: CMP AL,[INQ] ;CHECK FOR STRING TERMINATOR
+;; JNZ S4A
+;; DEC PRMCNT ;TERMINATE STRING
+;; MOV WORD PTR [SI],OFFSET S3
+;; RET
+
+;;S4A: CALL GETPTR
+;; MOV BYTE PTR [BX],AL
+;; MOV WORD PTR [SI],OFFSET S4
+;; JMP S3A
+;
+; LOOK FOR ANSI COMMAND SPECIFIED IN AL
+;
+
+S7: MOV BX,OFFSET CMDTABL-3
+;
+S7A: ADD BX,3
+ CMP BYTE PTR [BX],0
+ JZ S1B
+ CMP BYTE PTR [BX],AL
+ JNZ S7A
+;
+S7B: MOV AX,WORD PTR [BX+1] ;AX = JUMP ADDRESS
+ MOV BX,OFFSET PARAM
+ MOV DL,BYTE PTR [BX]
+ XOR DH,DH ;DX = FIRST PARAMETER
+ MOV CX,DX
+ OR CX,CX
+ JNZ S7C
+ INC CX ; if DX=0, CX=1 else CX = DX
+S7C: JMP AX ;AL = COMMAND
+
+S1: CMP AL,1Bh ;ESCAPE SEQUENCE?
+ JNZ S1B
+ MOV WORD PTR [SI],OFFSET S2
+ RET
+
+S1B: CALL CHROUT
+S1A: MOV WORD PTR [STATE],OFFSET S1
+ RET
+
+MOVCUR: CMP BYTE PTR [BX],AH
+ JZ SETCUR
+ ADD BYTE PTR [BX],AL
+ LOOP MOVCUR
+SETCUR: MOV DX,WORD PTR COL
+ XOR BX,BX
+ MOV AH,2
+ int 10h ; call ROM
+ JMP S1A
+
+HVP:
+CUP:
+IF LINE25
+ CMP CL,(maxrow+1)
+ jb cup3 ; new row is 24 or less
+ JA SETCUR ; error - 26 or greater
+ cmp EnaL25,0 ; else 25, is it allowed?
+ jz SETCUR
+cup3:
+ELSE
+ CMP CL,maxrow
+ JA SETCUR
+ENDIF
+ MOV AL,MAXCOL
+ MOV CH,BYTE PTR [BX+1]
+ OR CH,CH
+ JZ CUP1
+ DEC CH
+CUP1: CMP AL,CH
+ JA CUP2
+ MOV CH,AL
+CUP2: XCHG CL,CH
+ DEC CH
+ MOV WORD PTR COL,CX
+ 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,(maxrow-1)*256+1
+IF LINE25
+ cmp ah,[row] ; at bottom of screen?
+ ja SETCUR
+ENDIF
+ JMP CUU1
+
+SCP: MOV AX,WORD PTR COL
+ MOV SAVCR,AX
+ JMP SETCUR
+
+RCP: MOV AX,SAVCR
+IF LINE25
+ cmp ch,maxrow
+ jb rcp1
+ cmp EnaL25,0
+ jz rcp2
+ENDIF
+rcp1: MOV WORD PTR COL,AX
+rcp2: JMP SETCUR
+
+SGR: XOR CX,CX
+ XCHG CL,PRMCNT
+ CALL GETPTR
+ INC CX
+SGR1: MOV AL,BYTE PTR [BX]
+ PUSH BX
+ MOV BX,OFFSET GRMODE
+SGR2: MOV AH,BYTE PTR [BX]
+ ADD BX,3
+ CMP AH,0FFH
+ JZ SGR3
+ CMP AH,AL
+ JNZ SGR2
+ MOV AX,WORD PTR [BX-2]
+ AND ATTR,AL
+ OR ATTR,AH
+SGR3: POP BX
+ INC BX
+ LOOP SGR1
+ JMP SETCUR
+
+ED:
+IF LINE25
+ cmp row,maxrow ; on 25th line?
+ je EL ; yes, treat like Erase in Line
+ENDIF
+ xor cx,cx
+ mov dl,maxcol
+ mov dh,(maxrow-1)
+ cmp param,1 ; which subcommand?
+ ja el2 ; all
+ jb ed1
+ mov dh,row ; to beginning
+ dec dh
+ jle EL
+ jmp short ed2
+ed1: mov ch,row ; to end
+ inc ch
+ cmp ch,dh
+ jae EL
+ed2: mov bh,attr
+ MOV AX,0600H
+ int 10h ; call ROM
+
+EL: MOV CX,WORD PTR COL
+ MOV dx,cx
+ mov al,param
+ inc al ; 0,1,2 => 1,2,3
+ test al,1 ; to end?
+ je el1
+ mov dl,maxcol
+el1: test al,2 ; to beginning?
+ je el2
+ mov cl,0
+el2: mov bh,attr
+ mov ax,0600H
+ int 10h
+S1A_j: jmp S1A
+
+IL: mov ah,7 ; scroll down
+ jmp short dl1
+
+xDL: mov ah,6 ; scroll up
+dl1: mov al,cl ; number of lines
+ mov ch,row
+ xor cl,cl
+ mov dh,(maxrow-1)
+ mov dl,maxcol
+ mov bh,attr
+ int 10h
+ jmp S1A_j
+
+RM: XOR CL,CL
+ JMP SHORT SM1
+
+SM: MOV CL,1
+SM1: mov bl,SelChar ; get selection character
+ sub bl,'<' ; adjust
+ jb S1A_j ; less than '<'
+ cmp bl,4
+ jae S1A_j ; greater than '?'
+ xor bh,bh
+ shl bx,1
+ shl bx,1
+ shl bx,1
+ MOV AL,DL
+ CMP AL,7
+ JA S1A_j
+ or bl,al
+ shl bx,1
+ mov bx,SRMODE[bx] ; get function indicator
+ cmp bx,1 ; no or special function?
+ jb S1A_j
+ jz SM2 ; sets screen mode
+ MOV [bx],CL
+ JMP S1A_j
+
+SM2: MOV AH,0
+ int 10h ; call ROM
+ JMP S1A_j
+
+; GetPtr - get a pointer to the current parameter
+GETPTR: MOV BX,PRMCNTW
+ CMP BX,NUMPARAM
+ JB GET1
+ DEC PRMCNT
+ JMP GETPTR
+GET1: ADD BX,OFFSET PARAM
+ RET
diff --git a/v4.0-ozzie/bin/DISK2/BIOS/BIOSOBJ.MAK b/v4.0-ozzie/bin/DISK2/BIOS/BIOSOBJ.MAK
new file mode 100644
index 0000000..e69d153
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK2/BIOS/BIOSOBJ.MAK
@@ -0,0 +1,20 @@
+ibmbio.obj: ibmbio.asm defdbug.inc bugcode.inc
+ masm ibmbio;
+
+ibmmtcon.obj: ibmmtcon.asm ansi.inc defdbug.inc
+ masm ibmmtcon;
+
+ibmdsk.obj: ibmdsk.asm defdbug.inc
+ masm ibmdsk;
+
+sysini.obj: sysini.asm dossym.inc devsym.inc syscalls.inc
+ masm sysini;
+
+sysimes.obj: sysimes.asm
+ masm sysimes;
+
+ibmbio.exe: ibmbio.obj ibmmtcon.obj ibmdsk.obj sysini.obj sysimes.obj
+ link ibmbio ibmmtcon ibmdsk sysini sysimes,ibmbio,ibmbio/map;
+
+ibmbio.com: ibmbio.exe
+ exe2bin ibmbio ibmbio.com
diff --git a/v4.0-ozzie/bin/DISK2/BIOS/BOOTPACH.EXE b/v4.0-ozzie/bin/DISK2/BIOS/BOOTPACH.EXE
new file mode 100644
index 0000000..378331e
Binary files /dev/null and b/v4.0-ozzie/bin/DISK2/BIOS/BOOTPACH.EXE differ
diff --git a/v4.0-ozzie/bin/DISK2/BIOS/BUGCODE.INC b/v4.0-ozzie/bin/DISK2/BIOS/BUGCODE.INC
new file mode 100644
index 0000000..4a87725
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK2/BIOS/BUGCODE.INC
@@ -0,0 +1,553 @@
+;*** Bugcode.inc - Debug code for including into sysini.asm and ibmbio.asm
+;
+; Can't link in via buglib due to memory and relocation games played
+; by these modules. Each gets a private, local-only copy of these
+; modules.
+
+
+IFDEF DEBUGFLG
+
+
+;** DPRINTF _ Debug Printf
+;
+; Dprintf is a kernel debug print formatting package. It is intended
+; to produce conviently formatted output.
+;
+; Dprintf is called, indirectly, by a macro:
+;
+; DEBUG n,m,"string",
+;
+; string = format string
+; a1 = first argument
+; an = last argument
+;
+; The format string is an ASCIZ string which can contain 2 types of
+; specifications: data-format specifications and literal characters.
+; Data format specifications always begin with a '$' character; all
+; characters not part of a data format specification are treated as
+; literal characters.
+;
+; Literal characters
+; - any character not part of a format specification. Special
+; non-printing characters are:
+; \n - CRLF
+; \t - tab
+; \b - bell
+; \\ - \
+; \$ - $
+;
+; Format Specifications
+;
+; A format specification takes the form:
+; $ [@]
+;
+; where =
+;
+; x - print argument as a hex word
+; d - print argument as decimal word
+; c - print argument as ascii character
+; b - print argument as hex byte
+; For each of the above formats, the supplied argument
+; is a 16-bit word - the value to be printed. The optional @
+; (described below) allows a segmented address to be supplied,
+; instead.
+;
+; s[nn] - print argument as asciz string; if optional decimal
+; argument follows the format character this specifys
+; a maximum string length. Non printing characters are
+; printed in the form \nnn where "nnn" is the octal byte
+; value.
+; Note that this format character cannot be directly
+; followed by a digit unless that digit is to be taken
+; as the start of a length argument.
+;
+; Bnn - print argument as hex bytes. The required following
+; decimal argument is the number of bytes to print.
+;
+; Both of these formats take a long address as their argument.
+; The '@' character is thus invalid for these formats.
+;
+; WARNINGS
+; As befitting a debug routine, DPRINTF does not have a whole lot
+; of "failsafe" code in it. Supplying screwed up formats can
+; muck things up. Specifically:
+; The @ argument must NOT be specified with the 's' or 'B'
+; format
+; A string/byte-length argument of 0 is taken as 65536
+; The string "%% BAD FMT %%" appears in the output when
+; 1) an illegal format specifier is given, or
+; 2) the B format is given a 0 or missing length
+;
+; ENTRY (sp+n ) = address of format string (offset from return cs value)
+; (sp+n-2) = first argument word
+; (sp+n-4) = second argument word
+; .
+; (sp+4 ) = last argument word
+; (sp+2 ) = seg of return address
+; (sp ) = offset of return address
+; (bp) = offset of format string on the stack
+; EXIT none
+; USES flags
+
+ PUBLIC DPRINTF
+DPRINTF PROC near
+
+ push ds
+ push es
+ push bp
+ push di
+ push si
+ push dx
+ push cx
+ push bx
+ push ax ; save registers
+ cld
+
+ mov si,[bp] ; get address of format string
+ sub bp,2
+ mov bx,sp
+ mov ds,ss:20[bx] ; (ds:si) = address of format string
+ push cs
+ pop ds
+
+; Scan format string for next character
+;
+; (ds:si) = address of format string
+; (ss:bp) = address of next argument
+
+dpf1: lodsb ; (al) = format string byte
+ and al,al
+ je dpf3 ; all done
+ cmp al,'$'
+ je dpf4 ; is data escape
+ cmp al,'\'
+ jnz dpf2 ; got the character
+
+; it's an "\" escape code - crack the argument character
+
+ lodsb
+ and al,al
+ je dpf3 ; all done, ignore hanging \
+ xchg ah,al
+ mov al,0Ch
+ cmp ah,'n'
+ jne dpf1$5 ; not \n
+ mov al,0dH
+ call putchar
+ mov al,0aH
+ jmp SHORT dpf2 ; print LF
+
+dpf1$5: cmp ah,'t'
+ mov al,9
+ je dpf2 ; is \t
+ cmp ah,'b'
+ mov al,7
+ je dpf2 ; is \b
+ xchg ah,al
+dpf2: call putchar
+ jmp dpf1
+
+; have the end of the format string - exit
+
+dpf3: pop ax
+ pop bx
+ pop cx
+ pop dx
+ pop si
+ pop di
+ pop bp
+ pop es
+ pop ds
+ ret
+
+
+;* Have a '$' character - is data format escape
+;
+; Get address of data into es:di
+;
+; (bp) = address of data value
+
+dpf4: mov di,bp
+ push ss
+ pop es ; (es:di) = address of data value
+ sub bp,2 ; point to next argument
+ lodsb ; (al) = format specifier
+ cmp al,'@'
+ jne dpf5 ; not an indirect flag
+ les di,[bp]
+ sub bp,2 ; have an extra 2 for @
+ lodsb
+dpf5: cmp al,'x'
+ jne dpfd1 ; not 'x'
+
+; is 'x' format - print hex word
+
+ mov ax,es:[di]
+ call THW ; type hex word
+ jmp dpf1
+
+dpfd1: cmp al,'d'
+ jnz dpfc1 ; not 'd'
+
+; is 'd' format - print decimal word
+
+ mov ax,es:[di]
+ call TDW ; type decimal word
+ jmp dpf1
+
+dpfc1: cmp al,'c'
+ jne dpfb1
+
+; is 'c' format - print character
+
+ mov al,es:[di]
+ call putchar
+ jmp dpf1
+
+dpfb1: cmp al,'b'
+ jne dpfs1
+
+; is 'b' format - print hex byte
+
+ mov al,es:[di]
+ call THB ; type hex byte
+ jmp dpf1
+
+dpfs1: cmp al,'s'
+ jne dpfbb1
+
+; is 's' format - print ASCIZ string. First, check for
+; optional decimal limit
+
+ public SSB
+SSB: sub cx,cx ; set 65536 limit
+ les di,[bp] ; (es:DI) = fwa of string
+ sub bp,2 ; argument to 's' was two words
+ mov al,[si]
+ cmp al,'0'
+ jb dpfs2 ; not decimal
+ cmp al,'9'
+ ja dpfs2 ; not decimal
+ call atod ; (ax) = decimal value, (ds:si) updated
+ xchg cx,ax
+
+; print asciz string at es:di, max of (cx) characters
+; (cx) = 0 means max of 65536
+;
+; Other sections of code in dpf jump here to print strings
+
+dpfs2: mov al,es:[di]
+ inc di
+ and al,al
+ je dpfs3
+ call putchar
+ loop dpfs2 ; continue if not at limit
+dpfs3: jmp dpf1
+
+dpfbb1: cmp al,'B'
+ je dpfbb2 ; is 'B' format
+
+; error in format code - print message
+
+dpferr: push cs
+ pop es
+ mov di,OFFSET dpfa ; (es:di) = error message
+ sub cx,cx
+ jmp dpfs2
+
+dpfa: DB '%% BAD FMT %%',0
+
+; have B format
+
+dpfbb2: call atod ; (ax) = length specifier
+ jc dpferr ; number not there - error
+ xchg cx,ax
+ jcxz dpferr ; number is 0 - error
+ les di,[bp] ; (es:DI) = fwa of string
+ sub bp,2 ; argument to 's' was two words
+dpfbb3: mov al,es:[di]
+ call THB ; type hex byte
+ mov al,' '
+ call putchar ; space em out
+ inc di
+ loop dpfbb3 ; do em all
+ jmp dpf1
+
+DPRINTF ENDP
+
+
+;** THB - Type Hex Byte
+;
+; THB types a hex byte (via "putchar")
+;
+; ENTRY (AL) = byte
+; EXIT none
+; USES ax, flags
+
+THBA DB '0123456789abcdef'
+
+ PUBLIC THB
+THB PROC near
+
+ push ax
+ shr al,1
+ shr al,1
+ shr al,1
+ shr al,1
+ and ax,0fH
+ xchg bx,ax
+ mov bl,CS:THBA[bx]
+ xchg ax,bx
+ call putchar ; put first character
+ pop ax
+ and ax,0fH
+ xchg bx,ax
+ mov bl,CS:THBA[bx]
+ xchg ax,bx
+ call putchar
+ ret
+
+THB ENDP
+
+
+
+
+;** THW - Type Hex Word
+;
+; THW types a word in hex (via "putchar")
+;
+; ENTRY (AX) = word
+; EXIT none
+; USES AX, flags
+
+ PUBLIC THW
+THW PROC near
+
+ push ax
+ xchg ah,al
+ call THB
+ pop ax
+ call THB
+ ret
+
+THW ENDP
+
+
+
+;** TDW - Type Decimal Word
+;
+; TDW types (via "putchar") the unsigned decimal representation
+; of a 16-bit unsigned integer. Only significant digits are
+; printed; if the number is 0 a "0" is printed.
+;
+; ENTRY (AX) = number
+; EXIT none
+; USES AX, flags
+
+ PUBLIC TDW
+TDW PROC near
+
+ push cx ; preserve registers
+ push dx
+ mov cx,10
+ call tdw$ ; recurse cracking digits
+ pop dx
+ pop cx
+ ret
+
+TDW ENDP
+
+
+;* tdw$ - crack number recursively
+;
+; tdw$ cracks the least significant decimal digit. If there
+; are no higher-significant digits, print and return.
+; else, recurse for higher digits
+;
+; (AX) = value
+; (CX) = 10
+
+tdw$ PROC NEAR
+
+ sub dx,dx
+ div cx ; (ax) = quotient, (dx) = remainder
+ and ax,ax
+ jz tdw$1 ; this is highest-order, do it
+ push dx
+ call tdw$
+ pop dx
+tdw$1: xchg ax,dx
+ add al,'0'
+ call putchar
+ ret
+
+TDW$ ENDP
+
+
+
+;** ATOD - Convert ASCII string to decimal number
+;
+; ATOD is called to convert an ascii string of digits to a
+; decimal number. Digits are converted until we run out of them.
+;
+; ENTRY (DS:SI) = address of first digit
+; EXIT 'C' clear if OK
+; (AX) = value
+; (SI) updated to first non-digit
+; 'C' set if error - no digits, or result >65535
+; (DS:SI) points to error character
+; USES AX, SI, FLAGS
+
+ PUBLIC ATOD
+ATOD PROC near
+
+ push dx
+ push cx ; save registers
+ mov al,[si]
+ sub al,'0'
+ jc atod9 ; error - no digits
+ cmp al,10
+ cmc
+ jc atod9 ; error - no digits
+ sub ax,ax ; clear accumulator
+ mov cx,10 ; base 10
+
+; crack next digit
+;
+; (AX) = number accumulated so near
+; (CX) = 10
+; (DS:SI) = next character
+
+atod1: xchg dx,ax ; keep accum in dx for a while
+ lodsb ; (al) = character
+ sub al,'0'
+ jc atod7 ; not digit - all done
+ cmp al,9
+ ja atod7 ; not digit - all done
+ sub ah,ah ; (ax) = digit value (0 - 9)
+ push ax
+ xchg ax,dx
+ mul cx ; (ax) = 10*accum
+ pop dx ; (dx) = digit to add
+ jo atod8 ; overflow
+ add ax,dx
+ jmp atod1 ; go back for more
+
+; Done with number, all OK
+;
+; (dx) = number
+; (ds:si) = address+1 of first unused character
+
+atod7: clc
+
+; Done with number, error
+; 'C' set
+
+atod8: dec si ; backup over non-decimal (or error) char
+atod9: pop cx
+ xchg ax,dx ; (ax) = number iff no error
+ pop dx ; restore registers
+ ret ; exit
+
+ATOD ENDP
+
+;** putchar - put a character on the console
+;
+; ENTRY (al) = character
+; EXIT none
+; USES ax,flags
+
+
+UR_DAT = 02f8H ; COM1 = 03f8H, COM2 = 02f8H
+UR_IEN = UR_DAT+1 ; Interrupt enable
+UR_IER = UR_DAT+2 ; interrupt ID
+UR_LCR = UR_DAT+3 ; line control registers
+UR_MCR = UR_DAT+4 ; modem control register
+UR_LSR = UR_DAT+5 ; line status register
+UR_MSR = UR_DAT+6 ; modem status regiser
+UR_DLL = UR_DAT ; divisor latch least sig
+UR_DLM = UR_DAT+1 ; divisor latch most sig
+
+iflag DB 0 ; != 0 when initialized 8250
+
+;* inchr - input character
+;
+; EXIT 'z' set if no character
+; 'z' clear if char
+; (al) = char
+
+inchr: mov dx,UR_LSR
+ in al,dx
+ and al,1
+ jz inchr1
+ mov dx,UR_DAT
+ in al,dx
+ and al,07fh
+inchr1: ret
+
+
+ PUBLIC putchar
+putchar PROC NEAR
+ pushf
+ cli
+ push dx
+ push cx
+ push bx
+ push ax ; (al) = character
+ test iflag,255
+ jnz putc1 ; is initialized
+ inc iflag
+
+; program the usart
+
+ mov dx,UR_LCR
+ mov al,80h
+ out dx,al ; command it
+ sub al,al
+ mov dx,UR_DLM
+ out dx,al
+ mov dx,UR_DLL
+ mov al,12 ; 9600 baud = 12, 19.2 Kbaud = 6
+ out dx,al
+ mov al,3
+ mov dx,UR_LCR
+ out dx,al ; command normal mode
+
+; see if CTL-Q or CTL-S
+
+putc1: pushf
+ cli
+ call inchr
+ jz putc3 ; no characters incomming
+ cmp al,19 ; ctl-S?
+ jnz putc3 ; no, ignore
+
+; have ctl-s. wait till we see ctl-Q
+
+putc2: call inchr
+ jz putc2
+ cmp al,17
+ jnz putc2
+
+putc3: popf
+ mov dx,UR_LSR
+putc4: in al,dx
+ test al,020h
+ jz putc4
+
+; ready. crank it out!
+
+ mov dx,UR_DAT
+
+ pop ax
+ out dx,al
+
+ pop bx
+ pop cx
+ pop dx
+ popf
+ ret
+
+putchar ENDP
+
+ENDIF
diff --git a/v4.0-ozzie/bin/DISK2/BIOS/DEFDBUG.INC b/v4.0-ozzie/bin/DISK2/BIOS/DEFDBUG.INC
new file mode 100644
index 0000000..590e376
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK2/BIOS/DEFDBUG.INC
@@ -0,0 +1,122 @@
+;** DEFDBUG.ASM - Debugging Macro Definitions
+;
+;
+; DEBUG n,m,,
+;
+;
+
+.sall
+
+DEBUG MACRO N,M,string,args
+ local b,c
+ IFDEF DEBUGFLG
+ pushf
+ DEBUGTST N,M
+ jz b
+ push ax
+ push bp
+ call c ;; push address of string
+ DB '&string',0
+c: mov bp,sp
+; IFNB
+ IRP Y,
+ IFIDN ,
+ push 4[bp]
+ ELSE
+ IFIDN ,
+ push 4[bp]
+ ELSE
+ IFIDN ,
+ push 2[bp]
+ ELSE
+ IFIDN ,
+ push 2[bp]
+ ELSE
+ mov ax,Y
+ push ax
+ ENDIF
+ ENDIF
+ ENDIF
+ ENDIF
+ ENDM
+; ENDIF
+ call DPRINTF
+ mov sp,bp
+ pop ax ;; discard format string offset
+ pop bp
+ pop ax
+b: popf
+ ENDIF
+ENDM
+
+
+
+
+;** ERRNZ - generate assembly error if arg != 0
+;
+
+ERRNZ MACRO EXPR
+ IF1
+ IFE expr
+ ELSE
+ RADIX 0 ; CONDITION NOT MET - ERROR
+ ENDIF
+ ENDIF
+ ENDM
+
+
+;** DBBEG - Start debugging range
+;
+
+DBBEG MACRO N,M
+ LOCAL lab
+ IFDEF DEBUGFLG
+ pushf
+ DEBUGTST N,M
+ jnz lab ;; am to do it
+ DBJMP %DBCNT
+lab:
+ ENDM
+
+
+
+DBJMP MACRO N
+ jmp DBLAB&N
+ ENDM
+
+
+;** DEBUGTST - Test Debug Flags
+;
+; DEBUGTST n,m
+;
+; Where N and M are bit masks.
+;
+; If one or more of the bits in N is set in the high byte
+; of BUGBITS, and one or more of the bits in M is set in
+; the low byte of BUGBITS then clear the Z flag.
+;
+; In other words:
+;
+; If both masks show a "hit" clear 'Z' else set 'Z'
+;
+; USES FLAGS
+
+DEBUGTST MACRO N,M
+ LOCAL A
+ test BYTE PTR BUGBITS,n
+ jz A
+ test BYTE PTR BUGBITS+1,m
+A:
+ ENDM
+
+DBEND MACRO
+ DBLAB %DBCNT
+DBCNT = DBCNT+1
+ popf
+ ENDM
+
+DBLAB MACRO N
+DBLAB&N:
+ ENDM
+
+ DBCNT = 1
diff --git a/v4.0-ozzie/bin/DISK2/BIOS/IBMBIO.ASM b/v4.0-ozzie/bin/DISK2/BIOS/IBMBIO.ASM
new file mode 100644
index 0000000..318b1b0
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK2/BIOS/IBMBIO.ASM
@@ -0,0 +1,2214 @@
+TITLE IBMBIO IBM BIOS FOR MS-DOS 4.0
+
+; Modified for 3.0, July '83, Marc McDonald
+;
+; arw 02/01/84
+; split disk driver into separate file
+; arw 05/01/84
+; split out console driver
+
+;::::::::::::::::::::::::::::::::::::::::::::::
+;
+; IBM ADDRESSES FOR I/O
+;
+;::::::::::::::::::::::::::::::::::::::::::::::
+
+ PAGE ,132
+;DEBUGFLG = 1 ; don't enable debug printfs
+CONSFLAG = 0 ; =1 to include console driver here
+
+.xlist
+ INCLUDE DEFDBUG.INC
+.list
+
+ BIOSEG=70H ;0070 SEGMENT FOR THE BIOS
+ SYSIZE=100H ;Number of paragraphs in sysinit module
+ RSINIT=0A3H ;RS232 INITIALIZATION
+ ;9600 BAUD:NO PARITY:1 STOP:8 BIT WORD
+ LF=10 ;LINE FEED
+ CR=13 ;CARRIAGE RETURN
+ BACKSP=8 ;BACKSPACE
+ BRKADR=6CH ;006C BREAK VECTOR ADDRESS
+ DSKADR=1EH*4 ;ADDRESS OF PTR TO DISK PARAMETERS
+ SEC9=522H ;ADDRESS OF DISK PARAMETERS
+ AKPORT=20H
+ EOI=20H
+
+
+;** Timer and Clock Definitions
+
+SCHEDCOUNT EQU 50 ; # msec/scheduler tick
+MOTORCOUNT EQU 55 ; # msec/ROM BIOS tick
+
+ EXTRN CURRENT_DOS_LOCATION:WORD
+ EXTRN FINAL_DOS_LOCATION:WORD
+ EXTRN DEVICE_LIST:DWORD
+ EXTRN MEMORY_SIZE:WORD
+ EXTRN DEFAULT_DRIVE:BYTE
+ EXTRN SYSINIT:FAR
+
+BiosSeg GROUP Code,BiosInit
+Code SEGMENT BYTE PUBLIC 'CODE'
+
+ ASSUME CS:BiosSeg,DS:NOTHING,ES:NOTHING
+
+START$:
+ JMP INIT
+
+ DB 20 DUP (0) ; IBM WANTS SOME ZEROED AREA
+
+SUBTTL Jump tables for devices
+;--------------------------------------------------------------
+;
+; COMMAND JUMP TABLES
+;
+; BEWARE - These tables overlap somewhat! -c.p.
+;
+IF CONSFLAG
+CONTBL:
+ DW SetAddr
+ DW StatusComplete
+ DW StatusComplete
+ DW CMDERR
+ DW CON$READ
+ DW CON$RDND
+ DW StatusComplete
+ DW CON$FLSH
+ DW CON$WRIT
+ DW CON$WRIT
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ENDIF ;CONSFLAG
+
+AUXTBL:
+ DW StatusComplete
+ DW StatusComplete
+ DW StatusComplete
+ DW CMDERR
+ DW AUX$READ
+ DW AUX$RDND
+ DW StatusComplete
+ DW AUX$FLSH
+ DW AUX$WRIT
+ DW AUX$WRIT
+ DW AUX$WRST
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+
+TIMTBL:
+ DW StatusComplete
+ DW StatusComplete
+ DW StatusComplete
+ DW CMDERR
+ DW TIM$READ
+ DW StatusDevReady
+ DW StatusComplete
+ DW StatusComplete
+ DW TIM$WRIT
+ DW TIM$WRIT
+
+PRNTBL:
+ DW StatusComplete
+ DW StatusComplete
+ DW StatusComplete
+ DW CMDERR
+ DW StatusNoXfer ; Printer doesn't read
+ DW StatusDevReady
+ DW StatusComplete
+ DW StatusComplete
+ DW PRN$WRIT
+ DW PRN$WRIT
+ DW PRN$STAT
+ DW StatusComplete
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+ DW CMDERR
+
+SUBTTL Device entry points
+;---------------------------------------------------
+;
+; 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
+Dfun = DWORD PTR 14 ; Passed addr of dos function
+COUNT = 18 ;COUNT OF BLOCKS OR CHARACTERS
+START = 20 ;FIRST BLOCK TO TRANSFER
+
+AUXNUM DB 0 ;WHICH AUX DEVICE WAS REQUESTED
+
+; Dos routine to do functions for device drivers
+ PUBLIC DosFunction
+DosFunction DD 0 ; Device help function entry point
+ScrnIOok dd 0 ; (char *) true if in current screen locus
+
+TIM_DRV DB -1 ; TIME WHEN LAST DISK I/O PERFORMED
+TIM_REM DW 0 ; scheduler tics left until media presumed
+ ; changed
+
+;** Debugging control:
+;
+; Group Level Controls
+; 01 General BIOS, bootstrapping and initialization
+; 01 Device initialization
+; 02 MS-DOS bootstrapping
+; 04 Driver error conditions
+; 10 Command dispatch
+; 04 Diskette driver
+; 01 Initialization
+; 02 System entrys
+; 04 Details of read/write processing
+; 08 Hard disk driver
+; 01 Initialization
+; 02 System entrys
+; 10 Console display driver
+
+
+ PUBLIC BUGBITS
+BUGBITS DB 000H ; group bits
+ DB 0ffH ; level bits
+
+Strategy PROC FAR
+ RET
+Strategy ENDP
+
+IF CONSFLAG
+CON$IN:
+ PUSH SI
+ MOV SI,OFFSET CONTBL
+ JMP SHORT Interrupt
+ENDIF ;CONSFLAG
+
+AUX0$IN:
+ PUSH SI
+ PUSH AX
+ XOR AL,AL
+ JMP SHORT AUXENT
+
+AUX1$IN:
+ PUSH SI
+ PUSH AX
+ MOV AL,1
+AUXENT:
+ MOV SI,OFFSET AUXTBL
+ JMP SHORT entry1
+
+PRN0$IN:
+ PUSH SI
+ PUSH AX
+ XOR AL,AL
+ JMP SHORT PRNENT
+
+PRN1$IN:
+ PUSH SI
+ PUSH AX
+ MOV AL,1
+ JMP SHORT PRNENT
+
+PRN2$IN:
+ PUSH SI
+ PUSH AX
+ MOV AL,2
+PRNENT:
+ MOV SI,OFFSET PRNTBL
+ JMP SHORT entry1
+
+TIM$IN:
+ PUSH SI
+ MOV SI,OFFSET TIMTBL
+
+
+COMMENT *
+ Interrupt is the main part of the interrupt device entry point( a
+misnomer, actually is the execute function entry ) for all devices.
+The various devices set up the dispatch table address and unit choice
+and then jump to Interrupt which then dispatches to the appropriate
+device routine.
+
+Entry parameters:
+ SI Address of device dispatch table
+ AL Unit # for Aux/Prn( stored in AuxNum )
+ ES:BX Device request packet address
+
+Exit parameters: ( to device routine )
+ AL Unit code from packet
+ AH Media descriptor from packet
+ CX Count from packet
+ DX Start sector from packet
+ ES:DI Buffer address from packet
+ DS:BX Packet address
+ SS TaskArea segment( from dos call )
+ *
+
+ PUBLIC Interrupt
+Interrupt PROC FAR
+ PUSH AX
+entry1:
+ PUSH CX
+ PUSH DX
+ PUSH DI
+ PUSH BP
+ PUSH DS
+ PUSH ES
+ PUSH BX
+ debug 1,10H,< INTERRUPT cmdtbl $x >,
+ MOV CS:[AUXNUM],AL ; Save unit choice of AUX/PRN
+ MOV AX,ES
+ MOV DS,AX ; DS:BX also points to packet
+
+ MOV AL,DS:[BX].Cmd ; Get device command
+ XOR AH,AH
+ ADD SI,AX
+ ADD SI,AX ; Get Address of routine
+ CMP AL,18 ; Too high a command number?
+ JA CmdErr ; Yes, error
+ MOV AL,DS:[BX].UNIT ;AL = Unit code
+ MOV AH,DS:[BX].MEDIA ;AH = Media descriptor
+ MOV CX,DS:[BX].COUNT ;CX = Count
+ MOV DX,DS:[BX].START ;DX = Start sector
+ LES DI,DS:[BX].TRANS ; ES:DI = buffer addr
+ debug 1,10H,,
+ JMP WORD PTR CS:[SI] ; Do request
+Interrupt ENDP
+
+SUBTTL Routines used by device routines
+COMMENT *
+ All routines on this page are various exits for device functions.
+They each return different information in the request packet for the
+dos. The routines are as follows:
+
+ StatusDevReady
+ The busy and done bits are set in the packet. This
+ means that the device has input to be read or can
+ do output without any waiting.
+
+ StatusPartialXfer
+ The device was unable to do the I/O for the requested
+ number of bytes/blocks. CX contains the number that are
+ left to do. Fall into StatusError to set error has
+ happened.
+
+ StatusError
+ Set the error and done bits in the status.
+
+ StatusNoXfer
+ The device couldn't do the read or write, set the
+ number of bytes transferred to 0, but don't set the
+ error bit.
+
+ StatusComplete
+ The device actually completed the request and every-
+ thing was just fine, so just set the done bit in the
+ request status.
+
+ StatusWait
+ The device driver is for 3.0 and saw that it would
+ have to wait in a loop to do the request, so instead
+ it will not set the done bit which tells the dos to
+ put the task into the I/O wait queue.
+
+Entry parameters: ( for all of the above routines )
+ DS:BX Address of device request packet
+ CX Count of bytes/blocks left to transfer if applicable
+ AL Error code if applicable
+
+Exit parameters:
+ ES:BX Pointer to packet
+ AX Destroyed
+ SI Destroyed
+ All other registers preserved
+ *
+
+ PUBLIC StatusDevReady
+StatusDevReady PROC NEAR ; Device has data or can send
+ MOV AH,00000011B ; Done + busy
+ JMP SHORT SetStatus
+StatusDevReady ENDP
+
+ PUBLIC CmdErr
+CmdErr PROC NEAR ; Bad device command number
+ debug 1,4,< CMDERR - $b $x\n>,
+ MOV AL,3 ; Unknown command error
+CmdErr ENDP
+
+StatusPartialXfer PROC NEAR
+ SUB [BX].COUNT,CX ;# of successful I/O's
+StatusPartialXfer ENDP
+
+ PUBLIC StatusError
+StatusError PROC NEAR
+ MOV AH,10000001B ; Error + done
+ JMP SHORT SetStatus
+StatusError ENDP
+
+StatusNoXfer PROC NEAR
+ XOR AX,AX
+ MOV [BX].COUNT,AX ; No chars read
+StatusNoXfer ENDP
+
+ PUBLIC StatusComplete
+StatusComplete PROC NEAR
+ MOV AH,00000001B ; Done
+ PUBLIC SetStatus
+SetStatus:
+ POP BX
+ POP ES
+ MOV ES:WORD PTR [BX].STATUS,AX ;MARK OPERATION COMPLETE
+ POP DS
+ POP BP
+ POP DI
+ POP DX
+ POP CX
+ POP AX
+ POP SI
+XXX PROC FAR
+ RET ;RESTORE REGS AND RETURN
+XXX ENDP
+StatusComplete ENDP
+
+StatusWait PROC NEAR
+ MOV AH,0 ; Don't set done bit
+ MOV [BX].Count,CX ; Set number completed
+ MOV WORD PTR [BX].Trans,DI ; Set new offset
+ JMP SetStatus
+StatusWait ENDP
+
+IF CONSFLAG
+; Set the address of the dos function routine for drivers
+SetAddr PROC NEAR
+ MOV AX,WORD PTR [BX].Dfun
+ MOV WORD PTR DosFunction,AX
+ MOV AX,WORD PTR [BX+2].Dfun
+ MOV WORD PTR (DosFunction+2),AX
+ mov ax,0
+ mov cx,1
+ mov dx,16
+ call DosFunction
+ mov word ptr ScrnIOok,ax
+ mov word ptr ScrnIOok+2,dx
+ JMP StatusComplete
+SetAddr ENDP
+
+
+;-------------------------------------------------------------
+;
+; CHROUT - WRITE OUT CHAR IN AL USING CURRENT ATTRIBUTE
+;
+; CALLED VIA INT 29H
+;
+CHROUT = 29H
+
+OUTCHR: STI
+ PUSH AX
+ MOV BX,7
+ MOV AH,14 ;WRITE CHARACTER
+ INT 10H ;SEND THE CHARACTER
+ POP AX
+ IRET
+ENDIF ;CONSFLAG
+
+;----------------------------------------------
+;
+; SET DX TO AUXNUM
+;
+GETDX: MOV DL,[AUXNUM]
+ XOR DH,DH
+ RET
+
+SUBTTL Console driver
+COMMENT *
+ This is the console( CON ) device driver. The input side is assigned
+to the keyboard and the output to the video screen. The output code
+remains more or less the same as in 2.0. The input side, however, is
+changed for 4.0 to enter an I/O wait rather than loop waiting for a
+character.
+ *
+
+IF CONSFLAG
+CONDEV LABEL WORD ;HEADER FOR DEVICE "CON"
+ DW AUXDEV,BIOSEG
+ DW 1000000000010011B ;CON IN AND CON OUT + SPECIAL
+ DW STRATEGY
+ DW CON$IN
+ DB 'CON '
+ELSE
+ EXTRN CONDEV:NEAR
+ PUBLIC AUXDEV
+ENDIF ;CONSFLAG
+
+IF CONSFLAG
+Key2ndPart DB 0 ; Leftover byte of 2 key codes
+
+RomData SEGMENT AT 40H
+ ORG 1AH
+Bufferhead DW ?
+BufferTail DW ?
+KeyBuffer LABEL WORD
+KeyBufLen equ 32 ; length of KeyBuffer
+RomData ENDS
+
+; BREAK interrupt routine
+; ROM interrupt handler resets buffer pointers to beginning of buffer
+; and places a 0000h dummy character into the buffer.
+
+Break PROC NEAR
+ mov Key2ndPart,3 ; Force next char to be ^C( stop )
+ IRET
+Break ENDP
+
+SUBTTL Console read and subroutines
+ PAGE
+
+COMMENT *
+ The console read dispatch tries to read the selected number of
+characters from the keyboard. If at any point there is no key in
+the queue, it returns to the dos to allow another process to run
+until a key is depressed.
+
+Entry parameters:
+ ES:DI Pointer to buffer in which to store characters
+ CX Number of characters to read
+ DS:BX Pointer to device request packet
+
+Exit parameters:
+ CX Number of characters left to read
+ DS:BX Pointer to device request packet
+ *
+
+Con$Read PROC NEAR
+ JCXZ StatusComplete
+CON$LOOP:
+ PUSH CX ;SAVE COUNT
+ CALL ChrIn ;GET CHAR IN AL
+ POP CX
+ STOSB ;STORE CHAR AT ES:DI
+ LOOP CON$LOOP
+ JMP StatusComplete
+Con$Read ENDP
+
+COMMENT *
+ ChrIn attempts to read a character from the keyboard queue that
+is maintained by the ROM BIOS. If the queue is not empty, the code
+is returned. Otherwise, the packet is added to the list of keyboard
+reads and carry is set to cause the driver routine to return to the
+dos with the done bit not set which results in an I/O wait.
+
+Entry parameters:
+ DS:BX Pointer to device request packet
+
+Exit parameters:
+ AL Character from keyboard if present
+*
+
+ChrIn PROC NEAR
+ConReadLoop:
+ XOR AX,AX
+ XCHG AL,Key2ndPart ; GET CHARACTER & ZERO Key2ndPart
+ OR AL,AL
+ JNZ KeyRet
+ MOV AH,0
+ INT 16H ; Get the char
+ OR AX,AX ;Check for non-key after BREAK
+ JZ ConReadLoop
+ CMP AX,7200H ;Check for CTRL-PRTSC
+ JNZ ALT15
+ MOV AL,16
+ALT15:
+ OR AL,AL ; 2 byte keycode?
+ JNZ KeyRet ; No, have whole code
+ MOV Key2ndPart,AH ; Yes, store scan code for next read
+KeyRet: RET
+ChrIn ENDP
+
+
+COMMENT *
+ The non-destructive keyboard read routine returns the next char
+in the queue if there is one.
+
+Entry parameters:
+ DS:BX Pointer to device request packet
+
+Exit parameters:
+ DS:BX Pointer to device request packet
+ *
+Con$RdNd PROC NEAR
+ MOV AL,[Key2ndPart]
+ OR AL,AL
+ JNZ RDexit
+ mov ah,1
+ int 16h
+ JZ CONBUS
+ OR AX,AX
+ JNZ NOTBRK ;CHECK FOR NULL AFTER BREAK
+ MOV AH,0
+ INT 16H ;READ THE NULL
+ JMP CON$RDND ;AND GET A REAL STATUS
+NOTBRK: CMP AX,7200H ;CHECK FOR CTRL-PRTSC
+ JNZ RDexit
+ MOV AL,16
+RDexit:
+ MOV [BX].MEDIA,AL
+EXVEC: JMP StatusComplete
+CONBUS: JMP StatusDevReady
+Con$RdNd ENDP
+
+;--------------------------------------------------------------
+;
+; KEYBOARD FLUSH ROUTINE
+;
+Con$Flsh PROC NEAR
+ MOV [Key2ndPart],0 ;Clear out holding buffer
+
+ CALL Flush ; Flush the keyboard
+ JMP EXVEC
+Con$Flsh ENDP
+
+
+Flush PROC NEAR
+ PUSH DS
+ MOV AX,RomData
+ MOV DS,AX
+ ASSUME DS:RomData
+
+ CLI ; ** Disable interrupts
+ MOV AX,offset RomData:KeyBuffer ; Start of Rom buffer
+ MOV BufferHead,AX
+ MOV BufferTail,AX ; Empty the queue
+ STI ; ** enable interrupts
+ POP DS
+ ASSUME DS:NOTHING
+
+ RET
+Flush ENDP
+
+SUBTTL Console output( video ) routines
+ PAGE
+
+;----------------------------------------------------------
+;
+; CONSOLE WRITE ROUTINE
+;
+CON$WRIT:
+ JCXZ EXVEC
+CON$LP: MOV AL,ES:[DI] ;GET CHAR
+ INC DI
+ PUSH CX
+ PUSH DI
+ INT CHROUT ;OUTPUT CHAR
+ POP DI
+ POP CX
+ LOOP CON$LP ;REPEAT UNTIL ALL THROUGH
+ JMP EXVEC
+
+SUBTTL Keyboard interrupt routine
+PAGE
+; Replacement for ROM keyboard interrupt, tacks on the front.
+; OldKeyInterrupt is set to original contents of INT 09H.
+; The input character is passed to the O.S. console input filter
+; to determine if any special action should be taken. The filter
+; return value indicates if the character should be saved in the
+; type ahead buffer or if it should be discarded. A keyboard
+; semaphore exists to indicate if a process is waiting for input.
+; If the keboard semaphore is set all of the processes sleeping on
+; it are woken up.
+
+OldKeyInterrupt DD ?
+KeySem db 0 ; non-zero if someone waiting on input
+
+KeyboardInterrupt PROC FAR
+ INT 32H ; Save regs
+ MOV AX,RomData
+ MOV DS,AX
+ ASSUME DS:RomData
+
+ PUSHF ; Save flags to simulate INT
+ CALL CS:OldKeyInterrupt ; Now do ROM code
+; Now tell scheduler keyboard had char
+ cli ; interrupts off!
+ mov bx,BufferTail ; Get tail of queue
+ cmp bx,BufferHead ; Anything in keyboard queue?
+ JE NoKey ; No, don't requeue then
+ dec bx
+ dec bx
+ cmp bx,offset RomData:KeyBuffer
+ jae kbi1 ; no rap around in buffer
+ mov bx,offset RomData:KeyBuffer+KeyBufLen
+kbi1:
+ mov ax,[bx] ; get last queued char.
+ mov dx,5 ; ConsInputFilter subfunction
+ call DosFunction
+ jnz kbi2 ; key should remain in buffer
+ mov BufferTail,bx ; discard key from buffer
+ jmp SHORT NoKey
+kbi2:
+ cli
+ CMP KeySem,0 ; Outstanding request?
+ JE NoKey ; No, may not be inited either
+ push ax
+ push bx
+ push cx
+ push dx
+ mov ax,cs
+ mov bx,OFFSET KeySem
+ mov cs:byte ptr [bx],0 ; reset keyboard semaphore
+ mov dx,10 ;; ProcRun
+ call [DosFunction] ; awaken anyone waiting on input
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+NoKey:
+ IRET
+KeyBoardInterrupt ENDP
+
+;-------------------------------------------------------------
+; Keyboard INT 16 intercept routine to allow console input to sleep.
+; Only console input function 1 is intercepted, all other functions
+; are allowed to go directly to the ROM BIOS. For the function 1
+; the input status is checked, if a character is ready the function
+; is allowed to go to the ROM BIOS. Otherwise the keyboard semaphore
+; is set and the process is put to sleep on the address of the
+; semaphore. When a key is typed the keyboard interrupt routine
+; will wakeup any processes sleeping on this semaphore.
+;
+; WARNING: The following routines can be entered recursively
+; due to the fact that the ROM BIOS routines called
+; reenable interrupts. It's not usually a problem
+; since interrupts will generally be processed faster
+; than anyone can type.
+
+OldKbdHandler dd ?
+
+;-------------------------------------------------------------
+
+KeyBoardHandler proc far
+ or ah,ah
+ je DoLocalRead
+ cmp ah,1
+ je DoLocalStat
+OldKBint:
+ jmp [OldKbdHandler]
+
+DoLocalStat:
+ push bx
+ push ds
+ lds bx,ScrnIOok
+ test byte ptr [bx],0FFh
+ pop ds
+ pop bx
+ jnz OldKBint
+ xor ax,ax
+ ret 2
+
+DoLocalRead:
+ push ax
+ push bx
+ push cx
+ push dx
+DoLocalRd1:
+ push ds
+ lds bx,ScrnIOok
+ mov ax,ds
+ test byte ptr [bx],0FFh
+ pop ds
+ jnz DoLocalRd2
+ xor cx,cx
+ mov dx,9 ;; ProcBlock
+ call [DosFunction] ; sleep until a char is typed
+ jmp DoLocalRd1
+
+DoLocalRd2:
+ mov ah,1 ; get console status
+ pushf ; simulate INT to old handler
+ cli
+ call [OldKbdHandler]
+ cli ; subfunction 1 unconditionally sets IF
+ jnz LocalRead ; go read character
+ mov ax,cs
+ mov bx,OFFSET KeySem
+ mov cs:byte ptr [bx],0FFh ; set keyboard semaphore
+ xor cx,cx
+ mov dx,9 ;; ProcBlock
+ call [DosFunction] ; sleep until a char is typed
+ jmp DoLocalRd1
+
+LocalRead:
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ jmp [OldKbdHandler] ; read the character and return
+
+KeyBoardHandler endp
+
+ENDIF ;CONSFLAG
+
+SUBTTL Aux driver
+;------------------------------------------------------
+;
+; A U X - AUXILARY DEVICE DRIVER
+;
+AUXDEV LABEL WORD ;HEADER FOR DEVICE "AUX"
+ DW PRNDEV,BIOSEG
+ DW 1000000000000000B
+ DW STRATEGY
+ DW AUX0$IN
+ DB 'AUX '
+
+ PUBLIC COM1DEV
+COM1DEV LABEL WORD
+ DW LPT1DEV,BIOSEG
+ DW 1000000000000000B
+ DW STRATEGY
+ DW AUX0$IN
+ DB 'COM1 '
+
+COM2DEV LABEL WORD
+ DW -1,BIOSEG
+ DW 1000000000000000B
+ DW STRATEGY
+ DW AUX1$IN
+ DB 'COM2 '
+
+AUXBUF DB 0,0
+;-------------------------------------------------------
+;
+; READ FROM AUXILARY DEVICE
+;
+AUX$READ:
+ JCXZ EXVEC2
+ CALL GETBX
+ XOR AX,AX
+ XCHG AL,[BX] ;Get character and zero buffer
+ OR AL,AL
+ JNZ AUX2
+AUX1: CALL AUXIN
+AUX2: STOSB ;STORE CHARACTER
+ LOOP AUX1
+EXVEC2: JMP StatusComplete
+
+AUXIN: MOV AH,2 ;INDICATES A READ
+ CALL AUXOP ;READ THE AUXILIARY PORT
+ TEST AH,0EH ;Check framing, parity, overrun
+ JZ AROK
+ POP AX ;Clean up the stack
+ MOV AL,0BH ;READ ERROR
+ JMP StatusPartialXfer
+AROK: RET
+;--------------------------------------------------------
+;
+; AUX NON-DESTRUCTIVE READ, NO WAITING
+;
+AUX$RDND:
+ CALL GETBX
+ MOV AL,[BX] ;GET KEY AND ZERO BUFFER
+ OR AL,AL
+ JNZ AUXRDX ;KEY IN BUFFER?
+ CALL AUXSTAT
+ TEST AH,00000001B ;TEST DATA READY
+ JZ AUXBUS
+ TEST AL,00100000B ;TEST DATA SET READY
+ JZ AUXBUS
+ CALL AUXIN
+ CALL GETBX
+ MOV [BX],AL ;GET AND SAVE KEY
+AUXRDX: JMP StatusComplete
+AUXBUS: JMP StatusDevReady
+;----------------------------------------------------------
+;
+; AUX OUTPUT STATUS
+;
+AUX$WRST:
+ CALL AUXSTAT
+ TEST AL,00100000B ;TEST DATA SET READY
+ JZ AUXBUS
+ TEST AH,00100000B ;TEST CLEAR TO SEND
+ JZ AUXBUS
+ JMP EXVEC2
+
+AUXSTAT:
+ MOV AH,3
+AUXOP: CALL GETDX
+ INT 14H
+ RET
+;---------------------------------------------------------
+;
+; FLUSH AUX INPUT BUFFER
+;
+AUX$FLSH:
+ CALL GETBX
+ MOV BYTE PTR [BX],0
+ JMP EXVEC2
+;---------------------------------------------------------
+;
+; WRITE TO AUXILARY DEVICE
+;
+AUX$WRIT:
+ JCXZ EXVEC2
+AUX$LOOP:
+ MOV AL,ES:[DI] ;GET CHAR
+ INC DI ;POINT TO NEXT ONE
+ MOV AH,1 ;INDICATES A WRITE
+ CALL AUXOP ;SEND CHARACTER OVER AUX PORT
+ TEST AH,80H ;CHECK FOR ERROR
+ JZ AWOK
+ MOV AL,10 ;INDICATE WRITE FAULT
+ JMP StatusPartialXfer
+AWOK: LOOP AUX$LOOP
+ JMP EXVEC2
+
+GETBX: CALL GETDX
+ MOV BX,DX
+ ADD BX,OFFSET AUXBUF
+ RET
+SUBTTL Printer driver
+;-------------------------------------------------------------
+;
+; P R N - PRINTER DEVICE
+;
+PRNDEV LABEL WORD ;HEADER FOR DEVICE "PRN"
+ DW TIMDEV,BIOSEG
+ DW 1000000000000000B
+ DW STRATEGY
+ DW PRN0$IN
+ DB 'PRN '
+
+LPT1DEV LABEL WORD
+ DW LPT2DEV,BIOSEG
+ DW 1000000000000000B
+ DW STRATEGY
+ DW PRN0$IN
+ DB 'LPT1 '
+
+LPT2DEV LABEL WORD
+ DW LPT3DEV,BIOSEG
+ DW 1000000000000000B
+ DW STRATEGY
+ DW PRN1$IN
+ DB 'LPT2 '
+
+LPT3DEV LABEL WORD
+ DW COM2DEV,BIOSEG
+ DW 1000000000000000B
+ DW STRATEGY
+ DW PRN2$IN
+ DB 'LPT3 '
+
+ERRFLG DB 0
+
+;----------------------------------------------------------
+;
+; WRITE TO PRINTER DEVICE
+;
+PRN$WRIT:
+ JCXZ EXVEC3
+PRN$LOOP:
+ MOV AL,ES:[DI] ;GET CHAR INTO AL
+ INC DI ;POINT TO NEXT CHAR
+ MOV [ERRFLG],0 ;INITIALIZE RETRY FLAG
+
+PRETRY: XOR AH,AH ;AH=0
+ CALL PRNOP ;TO INDICATE PRINT CHAR IN AL
+
+ERRCHK: JZ PROK
+ XOR [ERRFLG],1 ;DO 1 AUTOMATIC RETRY
+ JNZ PRETRY
+PMESSG: JMP StatusPartialXfer ;RETURN WITH THE ERROR
+
+PROK: LOOP PRN$LOOP
+EXVEC3: JMP StatusComplete
+;--------------------------------------------------------
+;
+; PRINTER STATUS ROUTINE
+;
+PRN$STAT:
+ CALL PRNSTAT ;DEVICE IN DX
+ JNZ PMESSG
+ TEST AH,10000000B
+ JNZ EXVEC3
+ JMP StatusDevReady
+
+PRNSTAT:
+ MOV AH,2
+PRNOP: CALL GETDX
+ INT 17H
+
+ MOV AL,2
+ TEST AH,0001B ;TEST FOR NOT READY
+ JNZ PRNOP2
+
+ MOV AL,10 ;WRITE FAULT CODE
+ TEST AH,1000B ;TEST FOR I/O ERROR
+ JZ PRNOP2
+
+ TEST AH,00100000B ;OUT-OF-PAPER?
+ JZ PRNOP1
+ MOV AL,9 ;OUT OF PAPER CODE
+PRNOP1: OR AL,AL ;SET NZ FLAG
+PRNOP2: RET
+
+SUBTTL Timer (clock) driver
+ PAGE
+
+;** Time Functions
+;
+; Uses clock with 1000 ticks per second. User sees only
+; time in hours, minutes, seconds, and 1/100 second, in registers
+; CH, CL, DH, DL respectively. (Each is a binary number.)
+; Modified for 4.0. The ROM bios timer routines are completely
+; replaced with code on this page. This provides a better time base
+; for the scheduler.
+
+
+ EXTRN Floppydevice:NEAR
+TIMDEV LABEL WORD
+ DW Floppydevice,BIOSEG
+ DW 1000000000001000B
+ DW STRATEGY
+ DW TIM$IN
+ DB 'CLOCK$ '
+
+DAYCNT DW 0
+
+;--------------------------------------------------------------------
+;
+; Settime sets the current time
+;
+; On entry ES:[DI] has the current time:
+;
+; number of days since 1-1-80 (WORD)
+; minutes (0-59) (BYTE)
+; hours (0-23) (BYTE)
+; hundredths of seconds (0-99) (BYTE)
+; seconds (0-59) (BYTE)
+;
+; Each number has been checked for the correct range.
+
+TIM$WRIT:
+ PUSH BX
+ MOV AX,ES:[DI]
+ MOV DAYCNT,AX
+ MOV CX,ES:[DI+2]
+ MOV AL,60
+ MUL CH ;Hours to minutes
+ MOV CH,0
+ ADD AX,CX ;Total minutes
+ MOV CX,60000 ;60*1000
+ MUL CX ;Convert to milliseconds
+ MOV SI,AX
+ MOV BX,DX ; Save hours, min in Msecs in BX:SI
+ MOV AL,ES:[DI+5] ; Get # seconds
+ MOV CX,100
+ MUL CL ; Get seconds in 1/100s
+ MOV CL,ES:[DI+4] ; Hundredths of second
+ ADD AX,CX ; Now have seconds and 1/100ths
+ MOV CL,10
+ MUL CX ; Get DX:AX = milliseconds
+ ADD AX,SI
+ MOV CS:TickLow,AX
+ ADC BX,0
+ MOV CS:TickHigh,BX ; Set time in milliseconds
+ POP BX
+ JMP StatusComplete
+
+
+;***************************************
+;
+; Gettime reads date and time
+; and returns the following information:
+;
+; ES:[DI] =count of days since 1-1-80
+; ES:[DI+2]=minutes
+; ES:[DI+3]=hours
+; ES:[DI+4]=hundredths of seconds
+; ES:[DI+5]=seconds
+;
+;***************************************
+ PUBLIC TIM$READ
+TIM$READ:
+ PUSH BX
+ MOV AX,DayCnt
+ STOSW ; return day
+ MOV DX,CS:TickHigh
+ MOV AX,CS:TickLow ; Get current time
+ MOV CX,60000 ; # milliseconds in a minute
+ DIV CX ; Get AX= minutes, DX = seconds&msecs
+ MOV BX,DX ; Save seconds and fraction
+ XOR DX,DX
+ MOV CX,60 ; # minutes/hour
+ DIV CX ; Get AX= hour, DX= minute
+ xchg ax,dx
+ STOSB ; Return minutes
+ xchg ax,dx
+ STOSB ; Return hours
+ MOV AX,BX
+ XOR DX,DX
+ MOV CX,1000
+ DIV CX ; Get AX= seconds, DX= milliseconds
+ xchg ax,bx ; (bx) = seconds
+ MOV AX,DX
+ XOR DX,DX
+ MOV CX,10
+ DIV CX ; Get hundredths of second
+ STOSB ; Return hundredths of second
+ xchg ax,bx
+ STOSB ; Return second
+ POP BX
+ JMP StatusComplete
+
+SUBTTL Clock interrupt and replacement for ROM code
+PAGE
+
+COMMENT *
+ The clock code in the ROM is replaced with the following code which
+provides the clock interface to the scheduler and a 1 ms time base. The
+1AH interrupt is simulated to return the approximate time for those
+routines which still call 1AH. The time period for motor start up is
+preserved since that code has not yet been rewritten.
+ *
+
+RomData SEGMENT AT 040H
+ ORG 03FH
+Motor_Status DB 1 DUP(?)
+Motor_Count DB 1 DUP(?)
+RomData ENDS
+
+TickLow DW ? ; Low part of time in Msec
+TickHigh DW ? ; High part of time in msec
+MotorFlag DB 0 ; There is an active motor
+MotorTick DB MOTORCOUNT ; # ticks until 1/18.2 secs
+SchedTick DB SCHEDCOUNT ; Scheduler countdown
+
+; Interrupt 8H - timer interrupt
+
+ ASSUME DS:NOTHING
+TimerInterrupt PROC FAR
+ PUSH AX
+ INC TickLow
+ JNZ NoOverflow
+ INC TickHigh
+NoOverFlow:
+ CMP TickHigh,1318 ; Close to 24 hours?
+ JNZ NotDay ; No
+ CMP TickLow,23552 ; Reach 24 hours?
+ JNZ NotDay ; No
+; Have reached a day, bump day count
+ INC DayCnt
+ XOR AX,AX
+ MOV TickHigh,AX
+ MOV TickLow,AX ; Reset time of day
+NotDay:
+;; DEC MotorTick ; Time to decrement motor?
+;; JNZ CheckSched ; No
+;; MOV MotorTick,MOTORCOUNT ; Reset 1/18 sec worth of msecs
+;; PUSH DS
+;; MOV AX,RomData
+;; MOV DS,AX
+;; ASSUME DS:RomData
+
+;; TEST MotorFlag,0FFH ; Active motor timer?
+;; JZ CheckMotor ; No, see if new one
+;; DEC Motor_Count
+;; JNZ CheckMotor ; Not time to shut down
+;; AND Motor_Status,0F0H ; Turn off motor running bits
+;; MOV AL,0CH
+;; PUSH DX
+;; MOV DX,03F2H
+;; OUT DX,AL ; Turn off the motors
+;; POP DX
+;; MOV MotorFlag,0 ; No motor timeout running
+;; POP DS
+;; JMP CheckSched ; Go see if time to sched
+
+;;CheckMotor:
+;; MOV AL,Motor_Count
+;; POP DS
+;; JNZ CheckSched ; Motor already active
+;; OR AL,AL ; Need to start countdown?
+;; JZ CheckSched ; No
+;; MOV MotorFlag,0FFH ; Yes, set flag
+;; MOV MotorTick,MOTORCOUNT ; 1/18.2 sec later
+
+; The scheduler is called every 10ms, rather than every 1 ms to see if
+; it should switch tasks.
+CheckSched:
+; First reset the timer so will interrupt again
+ MOV AL,36H
+ OUT 43H,AL
+ MOV AL,169
+ OUT 40H,AL
+ MOV AL,4
+ OUT 40H,AL ; Set 1 msec delay
+ MOV AL,20H
+ OUT 20H,AL ; Tell 8259 interrupt done
+; Now see if should call scheduler
+ DEC SchedTick ; Time to call scheduler?
+ JNZ NoSched ; No, all done
+ MOV SchedTick,SCHEDCOUNT ; Reset countdown
+csch1: POP AX ; Stack is now clean
+ INT 32H ; Save all regs
+ CMP WORD PTR (DosFunction+2),0 ; Dos installed?
+ JE NoSchedActive ; Not yet, don't call sched
+ sub dx,dx ; (dx) = 0 = tic subfunction
+ mov ax,SCHEDCOUNT ; 10 milliseconds per tic
+ CALL DosFunction ; Do the tick
+ EXTRN FloppyTimer:FAR
+ CALL FloppyTimer ; timer service for floppy disk also
+NoSchedActive:
+ IRET ; All done
+
+NoSched:
+ POP AX
+INTRET: IRET ; All done
+TimerInterrupt ENDP
+
+; INT 1AH - Get/Set time based in 55msec tick
+
+TimeOfDay PROC FAR
+ OR AH,AH ; Function 0: Read time?
+ JZ ReadOld ; Yes
+ DEC AH ; Function 1: Write time?
+ JZ WriteOld ; Yes
+ IRET ; No, bad function code
+
+; Read old( 1/18.2 second tick ) time
+ReadOld:
+ MOV AX,TickHigh
+ xor dx,dx
+ MOV CX,MOTORCOUNT ; # milliseconds in 1/18.2 secs
+ DIV CX ; Get value in old ticks
+ push ax
+ MOV AX,TickLow
+ div cx
+ pop cx ; get high order count
+ XOR AL,AL ; Never have oveflow
+ IRET ; Return the time
+
+; Set time using old resolution
+WriteOld:
+ MOV AX,DX
+ push bx
+ MOV BX,MOTORCOUNT ; Conversion factor
+ MUL BX
+ MOV TickLow,AX ; Set low part of time
+ mov ax,cx
+ mov cx,dx
+ MUL BX
+ pop bx
+ ADD AX,CX ; Combine high parts
+ MOV TickHigh,AX ; Set time
+ IRET ; Return with new time set
+TimeOfDay ENDP
+
+;++++
+memsizmsg db 13,10,'Error - Interrupt 12',13,10,0
+memsizint dd 0
+
+memsizhandler proc far
+ push ax
+ push bx
+ push si
+ push ds
+ push cs
+ pop ds
+ mov SI,offset CS:memsizmsg
+ call WRMSG
+ pop ds
+ pop si
+ pop bx
+ pop ax
+ jmp memsizint
+memsizhandler endp
+;++++
+
+;----------------------------------------------
+; WRITE OUT MESSAGE POINTED TO BY [SI]
+;
+WRMSG: LODSB ;GET THE NEXT CHARACTER OF THE MESSAGE
+ AND AL,7FH ;SEE IF END OF MESSAGE
+ JZ WRMRET
+ MOV BX,7
+ MOV AH,14 ;WRITE CHARACTER
+ INT 10H ;SEND THE CHARACTER
+ JMP SHORT WRMSG
+WRMRET: RET
+
+.xlist
+ INCLUDE BUGCODE.INC
+.list
+
+Code ENDS
+
+SUBTTL Diskette driver -- now used only for bootup
+;-----------------------------------------------------------------
+;
+; DISK INTERFACE ROUTINES
+;
+BiosInit SEGMENT PARA PUBLIC 'CODE'
+
+DRVMAX DB 4
+
+ ASSUME CS:BiosSeg
+
+MAXERR = 5
+LSTDRV = 504H
+
+WRTVERIFY LABEL WORD
+RFLAG DB 2 ;2 for read, 3 for write
+VERIFY DB 0 ;1 if verify after write
+SINGLE DB 0 ;1 if single drive system
+SWPFLG DB 0 ;1 if BIOS swapped out
+SECCNT DW 0
+HARDNUM DB 99 ;logical drive number of first hardfile
+
+RESSEC = 3
+DRVLIM = 8 ;Number of sectors on device
+SECLIM = 13 ;MAXIMUM SECTOR
+HDLIM = 15 ;MAXIMUM HEAD
+HIDSEC = 17 ;NUMBER OF HIDDEN SECTORS
+
+;WARNING - preserve order of drive and curhd! -c.p.
+
+DRIVE DB 0 ;PHYSICAL DRIVE CODE
+CURHD DB 0 ;CURRENT HEAD
+CURSEC DB 0 ;CURRENT SECTOR
+CURTRK DW 0 ;CURRENT TRACK
+
+
+ERRIN: ;DISK ERRORS RETURNED FROM THE IBM ROM
+ DB 80H ;NO RESPONSE
+ DB 40H ;Seek failure
+ DB 10H ;BAD CRC
+ DB 8 ;DMA OVERRUN
+ DB 4 ;SECTOR NOT FOUND
+ DB 3 ;WRITE ATTEMPT TO WRITE-PROTECT DISK
+LSTERR DB 0 ;ALL OTHER ERRORS
+
+
+ERROUT: ;RETURNED ERROR CODES CORRESPONDING TO ABOVE
+ DB 2 ;NO RESPONSE
+ DB 6 ;SEEK FAILURE
+ DB 4 ;BAD CRC
+ DB 4 ;DMA OVERRUN
+ DB 8 ;SECTOR NOT FOUND
+ DB 0 ;WRITE ATTEMPT ON WRITE-PROTECT DISK
+ DB 12 ;GENERAL ERROR
+
+NUMERR= ERROUT-ERRIN
+;---------------------------------------------------------------------
+SPSAV DW 0 ;SAVE THE STACK POINTER
+;
+
+GETBP: 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 DI,OFFSET CS:HDRIVE
+ CMP AL,[HARDNUM]
+ JZ GETRET
+ JB GETBP1
+ MOV DI,OFFSET CS:DRIVEX
+ JMP SHORT GETRET
+
+GETBP1: 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
+ MOV DI,OFFSET CS:FDRIVE
+ TEST AH,00000010B ;TEST FOR 8 OR 9 SECTOR
+ 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 NUMBER OF DIRECTORY ENTRIES
+ INC DH ;INC SEC/ALL UNIT
+ INC DL ;INC HEAD LIMIT
+HAS1: MOV CS:[DI].2,DH
+ MOV CS:[DI].6,BH
+ MOV CS:[DI].8,CX
+ MOV CS:[DI].10,AH
+ MOV CS:[DI].11,AL
+ MOV CS:[DI].13,BL
+ MOV CS:[DI].15,DL
+GETRET: POP BX
+RET88: POP DX
+ POP CX
+ POP AX
+ RET
+
+;*********************************************************************
+; "FDRIVE" IS A FLOPPY DISK, VARIOUS PARAMETERS ARE PATCHED
+; BY GETBP TO REFLECT THE TYPE OF MEDIA INSERTED
+FDRIVE:
+ 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 11111100B ;Media descriptor
+ DW 2 ;Number of FAT sectors
+ DW 9 ;Sector limit
+ DW 1 ;Head limit
+ DW 0 ;Hidden sector count
+
+;------------------------------------------------------------
+;
+; DISK I/O HANDLER
+;
+; AL = DRIVE NUMBER (0-3)
+; AH = MEDIA DESCRIPTOR
+; CX = SECTOR COUNT
+; DX = FIRST SECTOR
+; ES:DI = TRANSFER ADDRESS
+; [RFLAG]=OPERATION (2=READ, 3=WRITE)
+; [VERIFY]=1 FOR VERIFY AFTER WRITE
+;
+; IF SUCCESSFUL CARRY FLAG = 0
+; ELSE CF=1 AND AL CONTAINS ERROR CODE
+;
+DISKRD:
+ debug 1,4,,
+ MOV [RFLAG],2
+DISKIO:
+ CLC
+ JCXZ IORET
+ MOV [TIM_DRV],AL ;SAVE DRIVE LETTER
+
+ MOV [SPSAV],SP ;SAVE SP
+ XCHG BX,DI ;ES:BX = TRANSFER ADDRESS
+ CALL GETBP ;CS:DI = PTR TO B.P.B
+ MOV SI,DX
+ ADD SI,CX
+ ADD DX,CS:[DI].HIDSEC ;ADD IN THE HIDDEN SECTORS
+ CMP SI,CS:[DI].DRVLIM ;COMPARE AGAINST DRIVE MAX
+ JBE INRANGE
+ MOV AL,8
+STCRET: STC
+IORET: RET
+
+INRANGE:CMP AL,[HARDNUM]
+ JB NOTHARD
+ MOV AL,CS:[HARDDRV] ;SET DRIVE NUMBER OF HARDFILE
+ JZ RDWR
+ INC AL
+ JMP SHORT RDWR
+
+NOTHARD:CMP [SINGLE],1 ;SINGLE FLOPPY INSTALLED?
+ JNZ RDWR
+ CALL SWPDSK ;ASK USER FOR CORRECT DISK
+RDWR:
+ MOV [DRIVE],AL
+ MOV [SECCNT],CX ;SAVE SECTOR COUNT
+ XCHG AX,DX ;SETUP LOGICAL SECTOR FOR DIVIDE
+ XOR DX,DX
+ DIV WORD PTR CS:[DI].SECLIM ;DIVIDE BY SEC PER TRACK
+ INC DL
+ MOV [CURSEC],DL ;SAVE CURRENT SECTOR
+ MOV CX,CS:[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
+
+ debug 1,4,< Drv $b Hd $b Trk $x Sec $b\n>,<,,CURTRK,>
+ MOV AX,[SECCNT]
+ MOV SI,ES ;Check for 64k boundary error
+ SHL SI,1
+ SHL SI,1
+ SHL SI,1
+ SHL SI,1 ;Segment converted to absolute address
+ ADD SI,BX ;Combine with offset
+ ADD SI,511 ;Add sector size and see if overflow
+ JC BUFIO ;Must handle special if so
+
+ XCHG BX,SI
+ SHR BH,1
+ MOV AH,128 ;Max. sectors in 64K
+ SUB AH,BH ;Number of sectors left in this 64K
+ XCHG BX,SI
+
+ CMP AH,AL ;Does it exceed total request?
+ JBE FIRBLK
+ MOV AH,AL ;If so, limit transfer to the request
+FIRBLK:
+;At this point, AL=total number of sectors to be read, AH=number
+; of sectors that can be read before 64K boundary error. AH<=AL.
+; ES:BX points to load area, DS:DI points to B.P.B
+
+ PUSH AX
+ MOV AL,AH ;No. of sectors to read at once (<>0)
+ CALL BLOCK ;Transfer portion before boundary
+ POP AX
+ SUB AL,AH
+ JZ DONE
+BUFIO:
+ PUSH AX
+ PUSH ES
+ PUSH BX ;SAVE CURRENT TRANSFER ADDRESS
+ CALL SWAP ;SWAP BUFFER WITH BIOS CODE
+
+ ADD BH,2 ;POINT TO TEMP BUFFER
+ CALL DISK1 ;Perform disk operation
+
+ POP BX ;RECALL TRANSFER ADDRESS
+ POP ES
+ POP AX
+ CALL SWAP ;SWAP BACK
+
+ DEC AL ;Dec sectors to read by 1
+ ADD BH,2 ;Add 200H to transfer address
+ CALL BLOCK ;Read the remaining sectors
+DONE:
+ debug 1,4,< DISKIO DONE\n>
+ CLC ;No error
+ RET ;From subroutine DISKIO
+
+; Swap 512 bytes of BIOS with transfer address
+
+SWAP: PUSH DI
+ PUSH BX
+ PUSH AX
+ MOV DI,BX ;ES:DI POINTS TO USER BUFFER
+ ADD BH,2
+ MOV SI,BX ;ES:SI POINTS TO TEMP BUFFER
+ CLD
+ debug 1,4,< SWAP $x:$x <==> $x:$x\n>,
+ MOV CX,256 ;256 WORDS TO SWAP
+SWAP1: MOV BX,WORD PTR ES:[DI] ;GET USER WORD
+ MOV AX,WORD PTR ES:[SI] ;GET SCRATCH WORD
+ MOV WORD PTR ES:[SI],BX ;PUT SCRATCH WORD
+ STOSW ;PUT BIOS WORD
+ INC SI
+ INC SI
+ LOOP SWAP1
+ XOR [SWPFLG],1 ;TOGGLE SWAPPED FLAG
+ POP AX
+ POP BX
+ POP DI
+RETZ: RET
+
+;Read the number of sectors specified in AL, handling track boundaries
+
+BLOCK: OR AL,AL ;See if any sectors to read
+ JZ RETZ
+
+ MOV AH,CS:[DI].SECLIM ;Sectors per track
+ INC AH
+ SUB AH,[CURSEC] ;Number of sectors left on this track
+ CMP AH,AL ;Compare with no. of sectors needed
+ JBE DOIO
+ MOV AH,AL ;Limit to only those requested
+DOIO:
+ PUSH AX
+ MOV AL,AH ;Put count where ROM needs it
+ CALL DISK ;Call ROM and trap errors
+ POP AX
+ SUB AL,AH ;Reduce request by amount just done
+ SHL AH,1 ;AH * 2^8 = no. of bytes
+ ADD BH,AH ;Bump address pointer
+ JMP BLOCK
+
+;Perform disk I/O with retries
+; AL = number of sectors (1-8, all on one track)
+; ES:BX = Transfer address (must not cross a 64K physical boundary)
+; [RFLAG] = 2 if read, 3 if write
+; [VERIFY] = 0 for normal, 1 for verify after write
+
+DISK1: MOV AL,1 ;Only one sector for buffered I/O
+
+DISK: MOV SI,MAXERR
+ MOV AH,RFLAG ;Get read/write indicator
+
+RETRY: PUSH AX
+
+CALLROM:MOV DX,[CURTRK] ;Load current cylinder
+ MOV CL,6 ;move high bits of cyl to sec
+ SHL DH,CL
+ OR DH,[CURSEC]
+ MOV CX,DX
+ XCHG CH,CL ;CL = sector, CH = cylinder
+ MOV DX,WORD PTR [DRIVE] ;Load physical drive number
+ ;and current head number
+;; debug 1,4,< CALLROM $x $x $x $x $x\n>,
+ INT 13H ;Request disk read/write
+ JC DSKERR
+ POP AX ;Restore sector count
+ PUSH AX
+ CMP WRTVERIFY,103H ;Check for write and verify
+ JNZ NOVERIFY
+ MOV AH,4 ;Request verify
+ INT 13H
+ JC DSKERR
+NOVERIFY:
+;; debug 1,4,< back from ROM\n>,<>
+ POP AX
+ AND CL,03FH ;Eliminate cylinder bits from sector
+ XOR AH,AH
+ SUB [SECCNT],AX ;Reduce count of sectors to go
+ ADD CL,AL ;Next sector
+ MOV [CURSEC],CL
+ CMP CL,CS:[DI].SECLIM ; Reached limit?
+ JBE RET1
+
+ MOV [CURSEC],1 ;Start with first sector of next track
+ MOV DH,[CURHD]
+ INC DH
+ CMP DH,CS:[DI].HDLIM
+ JB NOXOR
+ XOR DH,DH
+ INC [CURTRK] ;NEXT TRACK
+NOXOR: MOV [CURHD],DH
+
+RET1: RET
+
+DSKERR:
+ debug 1,4,< DSKERR $x >,
+ PUSH AX ;Save error code
+ MOV AH,0 ;Ask for disk reset
+ INT 13H
+ POP AX ;Restore error code
+ DEC SI ;decrement retry count
+ JZ HARDERR
+ CMP AH,80H ;Timeout?
+ JZ HARDERR ;***
+DSKERR1:POP AX ;Restore sector count
+ JMP RETRY
+
+HARDERR:
+ CMP [SWPFLG],0 ;If BIOS swapped out
+ JZ HARD1
+ POP BX ;Get disk1 return address
+ POP BX ;Get low part of transfer address
+ POP ES ;Get high part of transfer address
+ CALL SWAP ;swap it back in
+HARD1: PUSH CS
+ POP ES ;Make ES the local segment
+ MOV AL,AH ;Put error code in AL
+ MOV [LSTERR],AL ;Terminate list with error code
+ MOV CX,NUMERR ;Number of possible error conditions
+ MOV DI,OFFSET CS:ERRIN ;Point to error conditions
+ REPNE SCASB
+ MOV AL,es:NUMERR-1[DI] ;Get translation
+ MOV CX,SECCNT ;Get count of sectors to go
+ MOV SP,[SPSAV] ;Recover entry stack pointer
+ STC ;Flag error condition
+ RET ;and return
+
+INITAB DW FDRIVE
+ DW FDRIVE
+ DW FDRIVE
+ DW FDRIVE
+INITABH DW HDRIVE
+ DW DRIVEX
+
+RomData SEGMENT AT 040H
+ ORG 03EH
+Seek_Status DB 1 DUP(?)
+RomData ENDS
+
+
+;-------------------------------------------------
+;
+; ASK TO SWAP THE DISK IN DRIVE A:
+;
+SWPDSK: PUSH DS
+ XOR SI,SI ;Select segment 0
+ MOV DS,SI
+ MOV AH,AL ;Make copy of drive number
+ XCHG AH,DS:LSTDRV ;Xchange with last drive used
+ CMP AL,AH ;See if same as last drive
+ JZ RDWR0
+;Using a different drive in a one drive system so request the user change disks
+ ADD AL,"A" ;Add "A" to convert to drive letter
+ MOV CS:DRVLET,AL
+ push cs
+ pop ds
+ MOV SI,OFFSET CS:SNGMSG
+ PUSH BX
+ CALL WRMSG ;Print disk change message
+ XOR AH,AH
+ INT 16H ;Wait for a keyboard character
+ POP BX
+RDWR0:
+ POP DS
+ XOR AL,AL ;Always use drive 0
+ RET
+
+
+SNGMSG DB CR,LF,"Insert diskette for drive "
+DRVLET DB "A: and strike",CR,LF,"any key when ready",CR,LF,LF,0
+HNUM DB 0 ;NUMBER OF HARDFILES
+
+
+;** End of Permanently Resident BIOS
+
+
+HARDDRV DB 80H ;Physical drive number of first hardfile
+;**********************************************************************
+; "HDRIVE" IS A HARD DISK WITH 512 BYTE SECTORS
+;*********************************************************************
+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
+;**********************************************************************
+; "DRIVEX " IS AN EXTRA TYPE OF DRIVE USUALLY RESERVED FOR AN
+; ADDITIONAL HARD FILE
+;*********************************************************************
+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
+
+SUBTTL Bios initialization
+;*********************************************************
+; SYSTEM INITIALIZATION
+;
+; 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 DW 0000 ;DRIVE AND FAT ID OF DOS
+BIOS$ DW 0000 ;FIRST SECTOR OF DATA
+DOSCNT DW 0000 ;HOW MANY SECTORS TO READ
+
+BootBufr EQU 17C0H ; High memory scratch area
+
+ ASSUME DS:NOTHING,ES:NOTHING
+
+INIT: mov dx,1000h
+ MOV SS,DX
+ MOV SP,7C00h ;LOCAL STACK 1000:7C00
+ STI
+ PUSH CX ;Save number of floppies
+ MOV [BIOS$],BX
+ PUSH AX ;Save Drive info
+ MOV AL,EOI
+ OUT AKPORT,AL ;TURN ON THE TIMER
+
+ 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
+
+ MOV SI,OFFSET COM2DEV
+ CALL AUX_INIT ;INIT COM2
+ MOV SI,OFFSET COM1DEV
+ CALL AUX_INIT ;INIT COM1
+;* Can't do any DEBUG prints till now
+ debug 1,1,,<>
+ XOR DX,DX
+ MOV DS,DX ;TO INITIALIZE PRINT SCREEN VECTOR
+ MOV ES,DX
+
+ MOV AX,CS ;FETCH SEGMENT
+
+IF CONSFLAG
+ MOV WORD PTR DS:BRKADR,OFFSET BREAK
+ MOV DS:BRKADR+2,AX ;VECTOR FOR BREAK
+ MOV WORD PTR DS:(CHROUT*4),OFFSET OUTCHR
+ MOV DS:(CHROUT*4+2),AX
+ENDIF
+ MOV WORD PTR DS:DSKADR,SEC9 ;DISK PARAMETERS
+ MOV DS:DSKADR+2,ES
+
+ MOV DI,4
+ MOV BX,OFFSET INTRET ; Rest just return
+ 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
+; Set up some vectors for scheduler and change rom interrupts
+;
+ CLI ; Disable, changing int vectors
+ ADD DI,3*4 ; Move up to INT 8
+ MOV CX,OFFSET TimerInterrupt
+ XCHG AX,CX
+ STOSW
+ XCHG AX,CX
+ STOSW ; Set new INT 8: Timer
+IF CONSFLAG
+ MOV CX,DS:[DI] ; Save old addr to hook to
+ MOV WORD PTR OldKeyInterrupt,CX
+ MOV CX,DS:2[DI]
+ MOV WORD PTR (OldKeyInterrupt+2),CX
+ MOV CX,OFFSET KeyboardInterrupt
+ XCHG AX,CX
+ STOSW
+ XCHG AX,CX
+ STOSW ; Set new keyboard interrupt
+ELSE
+ ADD DI,4
+ENDIF
+ XCHG AX,BX
+ STOSW
+ XCHG AX,BX ; INT 0A unused
+ STOSW
+ XCHG AX,BX
+ STOSW
+ XCHG AX,BX ; INT 0B unused
+ STOSW
+ add di,4*6 ; skip 0C - 11
+ MOV CX,DS:[DI] ; Save INT 12 addr to hook to
+ MOV WORD PTR memsizint,CX
+ MOV CX,DS:2[DI]
+ MOV WORD PTR (memsizint+2),CX
+ mov cx,offset memsizhandler
+ xchg ax,cx
+ stosw
+ xchg ax,cx
+ stosw
+ add di,4*2 ; skip 13 - 14
+ STI
+; End of new 3.0 vectors
+ XCHG AX,BX
+ STOSW ;INT 15 ;Location 60
+ XCHG AX,BX
+ STOSW ;Location 62
+IF CONSFLAG
+ MOV CX,DS:[DI] ; Save INT 16 addr to hook to
+ MOV WORD PTR OldKbdHandler,CX
+ MOV CX,DS:2[DI]
+ MOV WORD PTR (OldKbdHandler+2),CX
+ MOV CX,OFFSET KeyboardHandler
+ XCHG AX,CX
+ STOSW
+ XCHG AX,CX ; Set new keyboard Handler
+ STOSW
+; Set new get/set time vector, time base changed
+ ADD DI,4*3 ; skip 17 - 19
+ELSE
+ ADD DI,4*4 ; skip 16 - 19
+ENDIF ;CONSFLAG
+ MOV CX,OFFSET TimeOfDay
+ XCHG AX,CX
+ STOSW ; setup 1A to TimeofDay
+ XCHG AX,CX
+ STOSW
+ ADD DI,4*23 ; skip 1B - 31
+ XCHG AX,BX
+ STOSW ; no-op INT 32 until Sched:SchedInit
+ XCHG AX,BX
+ STOSW
+ debug 1,1,,<>
+
+ MOV DS:WORD PTR 500H,DX ;SET PRINT SCREEN & BREAK =0
+ MOV DS:WORD PTR LSTDRV,DX ;clean out last drive spec
+
+ MOV DI,SEC9 ;location of drive table
+ MOV AX,02DFH ;Stuff the disk speedup/9 sector
+ STOSW ;code
+ MOV AX,0225H
+ STOSW
+ MOV AX,2A09H
+ STOSW
+ MOV AX,50FFH
+ STOSW
+ MOV AX,00F6H
+ STOSW
+ MOV AL,2
+ STOSB
+
+ pushf ;simulate int 12h
+ call memsizint ;Get memory size--1K blocks in AX
+ MOV CL,6
+ SHL AX,CL ;Convert to 16-byte blocks(segment no.)
+ POP CX ;Recall drive info
+ MOV [DRVFAT],CX ;SAVE DRIVE TO LOAD DOS
+
+ MOV DX,SEG SYSINIT
+ MOV DS,DX
+
+ ASSUME DS:SEG SYSINIT
+
+ MOV MEMORY_SIZE,AX
+ INC CL
+ MOV DEFAULT_DRIVE,CL ;SAVE DEFAULT DRIVE SPEC
+
+ add dx,SYSIZE
+ MOV CURRENT_DOS_LOCATION,dx ; load address of DOS
+
+ MOV FINAL_DOS_LOCATION,SEG BiosInit
+ debug 1,2,,
+ MOV WORD PTR DEVICE_LIST,OFFSET CONDEV ;DS:SI = ptr to device list
+ MOV AX,CS
+ MOV WORD PTR DEVICE_LIST+2,AX
+;**************************************************************
+; 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
+ PUSH CS
+ POP DS
+ POP ES
+
+ ASSUME DS:BiosSeg,ES:BiosSeg
+
+ INT 11H ;GET EQUIPMENT STATUS
+ AND AL,11000000B ;MASK DRIVE BITS
+ JNZ NOTSNGL ;Zero means single drive system
+ INC [SINGLE] ;REMEMBER THIS
+NOTSNGL:
+ POP AX ;BOOT specifies number of floppies
+ MOV [HARDNUM],AL ;Remember which drive is hard disk
+ MOV [DRVMAX],AL ;And set initial number of drives
+ MOV AH,8
+ MOV DL,80H
+ INT 13H ;Request number of hardfiles attached
+ JC ENDDRV ;Carry indicates old rom, so no hardfile
+ MOV [HNUM],DL
+ENDDRV:
+ MOV DL,80H
+ MOV DI,OFFSET CS:HDRIVE
+ CMP [HNUM],0
+ JLE ITSOK1
+ CALL SETHRD ;SET UP FIRST HARDFILE
+
+ MOV DL,81H ;SET UP FOR NEXT CALL
+ MOV DI,OFFSET CS:DRIVEX
+ JC NOTOK
+ CMP [HNUM],2
+ JZ SETIT
+ JMP SHORT ITSOK
+
+NOTOK: MOV [HARDDRV],DL
+ MOV DI,OFFSET CS:HDRIVE
+ DEC [HNUM]
+ CMP [HNUM],0
+ JZ ITSOK1
+SETIT: CALL SETHRD ;SET UP SECOND HARDFILE
+ JNC ITSOK
+ DEC [HNUM]
+
+; End of drive initialization
+
+ITSOK: MOV AL,[HNUM]
+ OR AL,AL
+ JZ ITSOK1
+ ADD AL,[HARDNUM]
+ MOV [DRVMAX],AL
+ MOV AL,[HNUM]
+ JMP SHORT ITSOK2 ;GO SET DESTINATION SEGMENT
+
+ITSOK1: CMP BYTE PTR [SINGLE],1
+ JMP SHORT GOINIT
+
+ ASSUME DS:BiosSeg
+
+ITSOK2:
+ DEC AL
+
+GOINIT:
+ debug 1,1,,<,drvfat>
+ PUSH CS
+ POP DS
+
+ ASSUME DS:BiosSeg,ES:NOTHING
+
+ 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
+ debug 1,2,< FAT ID: $b ds:$x\n>,
+ MOV AX,[DRVFAT]
+ CALL GETBP ;GET DISK POINTER
+ MOV CL,[DI+2] ;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
+ PUSH DS
+ XOR DI,DI
+ MOV DS,DI
+;
+; THE BOOT PROGRAM HAS LEFT THE DIRECTORY AT 0:500
+;
+ MOV BX,DS:WORD PTR 53AH ;GET FIRST CLUSTER OF DOS
+ POP DS ;BX = FIRST CLUSTER OF DOS
+LOADIT: MOV AX,SEG SYSINIT
+ add ax,SYSIZE
+ MOV ES,AX ;ES:DI POINTS TO LOAD LOCATION
+ CALL GETCLUS ;READ IN A CLUSTER
+ CMP BX,0FFFH
+ JNZ LOADIT ;END OF FILE?
+
+ EXTRN Disk_Init:NEAR
+ call Disk_Init ; do some device driver initialization
+ debug 1,2,,<>
+ JMP SYSINIT
+
+SUBTTL Routines for reading in MSDOS
+
+;
+; READ A FAT SECTOR INTO 17C0:0
+;
+GETFAT: debug 1,2,,<>
+ XOR DI,DI
+ MOV CX,1
+ MOV DX,CX
+ MOV AX,BootBufr
+ MOV ES,AX
+ MOV AL,BYTE PTR DRVFAT
+ MOV AH,0FCH
+ JMP DISKRD
+;
+; READ A BOOT RECORD INTO 17C0:0
+;
+GETBOOT:debug 1,2,,<>
+ MOV CX,1
+ MOV AX,0201H
+ MOV BX,BootBufr
+ MOV ES,BX
+ XOR BX,BX
+ MOV DH,BH
+ INT 13H
+ JC SETRET
+ CMP WORD PTR ES:[1FEH],0AA55H
+ JNZ SETRET
+ RET
+;
+; SETUP VARIABLE SIZED HARDFILE
+; ON ENTRY DL=DRIVE NUMBER (80 OR 81)
+; DI=PTR TO B.P.B
+;
+SETHRD: PUSH DX
+ MOV AH,8 ;GET DRIVE PARAMETERS
+ INT 13H
+ INC DH
+ MOV [DI].HDLIM,DH
+ POP DX
+ JC SETRET
+ AND CL,3FH
+ MOV [DI].SECLIM,CL
+ CALL GETBOOT ;GET THE BOOT RECORD
+ JC SETRET
+ MOV BX,1C2H
+SET1: CMP BYTE PTR ES:[BX],1
+ JZ SET2
+ ADD BX,16
+ CMP BX,202H
+ JNZ SET1
+SETRET: STC ;NOT FOUND SO USE DEFAULTS
+ RET
+
+SET2: MOV AX,ES:[BX+4]
+ MOV DS:[DI].HIDSEC,AX ;SET HIDDEN SECTOR COUNT
+ MOV AX,ES:[BX+8]
+ CMP AX,64 ;HAS TO BE AT LEAST 32K
+ JB SETRET
+ MOV DS:[DI].8,AX ;SAVE LOGICAL SECTOR COUNT
+ MOV CX,0100H ;SET CLUS SIZE AND SHIFT COUNT
+ MOV DX,64 ;SET NUMBER OF DIR ENTRIES
+ CMP AX,512
+ JBE SET3
+
+ ADD CH,CH
+ INC CL
+ MOV DX,112
+ CMP AX,2048
+ JBE SET3
+
+ ADD CH,CH
+ INC CL
+ MOV DX,256
+ CMP AX,8192
+ JBE SET3
+
+ ADD CH,CH
+ INC CL
+ ADD DX,DX
+ CMP AX,32680 ;NOT 32768! MAX NUMBER OF CLUSTERS=4085
+ JBE SET3
+
+ ADD CH,CH
+ INC CL
+ ADD DX,DX
+SET3:
+;
+; DX=NUMBER OF DIR ENTRIES, CH=NUMBER OF SECTORS PER CLUSTER
+; CL=LOG BASE 2 OF CH
+;
+; NOW CALCULATE SIZE OF FAT TABLE
+;
+ MOV [DI].6,DX ;SAVE NUMBER OF DIR ENTRIES
+ MOV [DI].2,CH ;SAVE SECTORS PER CLUSTER
+ XOR BX,BX
+ MOV BL,CH
+ DEC BX
+ ADD BX,AX
+ SHR BX,CL ;DIVIDE BY SECTORS/CLUSTER
+ INC BX
+ AND BL,11111110B ;MAKE SURE COUNT IS EVEN
+ MOV SI,BX
+ SHR BX,1
+ ADD BX,SI ;MULTIPY BY 1.5
+ ADD BX,511
+ SHR BH,1
+ MOV [DI].11,BH ;SAVE NUMBER OF FAT SECTORS
+ CLC
+ RET
+;
+; READ CLUSTER SPECIFIED IN BX
+; CX = SECTORS PER CLUSTER
+; DI = LOAD LOCATION
+;
+GETCLUS:debug 1,2,,
+ 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: CALL UNPACK ;SI = BX, BX = NEXT ALLOCATION UNIT
+ 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
+;
+; GET THE FAT ENTRY AT BX, WHEN FINISHED SI=ENTRY BX
+;
+UNPACK: PUSH DS
+ PUSH BX
+ MOV SI,BootBufr
+ MOV DS,SI
+ MOV SI,BX
+ SHR SI,1
+ MOV BX,[SI+BX]
+ JNC HAVCLUS
+ SHR BX,1
+ SHR BX,1
+ SHR BX,1
+ SHR BX,1
+HAVCLUS:AND BX,0FFFH
+ POP SI
+ POP DS
+ RET
+;
+; SI POINTS TO DEVICE HEADER
+;
+PRINT_INIT:
+ MOV BH,1
+ MOV DL,17H
+ JMP SHORT DEV_INIT
+AUX_INIT:
+ MOV BX,RSINIT
+ MOV DL,14H
+DEV_INIT:
+ MOV CS:[INTNUM],DL
+ MOV AL,CS:[SI+13] ;GET DEVICE NUMBER FROM THE NAME
+ SUB AL,"1"
+ CBW
+ MOV DX,AX
+ MOV AX,BX ;SET THE CALL
+ DB 0CDH ;INT 17H
+INTNUM DB 17H
+ RET
+
+END$:
+
+BiosInit ENDS
+ END
diff --git a/v4.0-ozzie/bin/DISK2/BIOS/IBMBIO.OBJ b/v4.0-ozzie/bin/DISK2/BIOS/IBMBIO.OBJ
new file mode 100644
index 0000000..28d0720
Binary files /dev/null and b/v4.0-ozzie/bin/DISK2/BIOS/IBMBIO.OBJ differ
diff --git a/v4.0-ozzie/bin/DISK2/BIOS/IBMDSK.ASM b/v4.0-ozzie/bin/DISK2/BIOS/IBMDSK.ASM
new file mode 100644
index 0000000..47869d0
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK2/BIOS/IBMDSK.ASM
@@ -0,0 +1,2551 @@
+TITLE DISK - MS-DOS 4.0 disk drivers for IBM
+NAME DISK
+
+ PAGE ,132
+
+;DEBUGFLG=1
+
+.xlist
+ INCLUDE DEFDBUG.INC
+.list
+
+; Constants
+
+ErrLim= 5 ; Number of retries on error
+
+; Floppy delay constants
+
+DelayLoad= 35 ; 35 milliseconds to load head
+
+; Constants for floppy disk controller
+
+Rate99= 000H ; Step rate 96tpi disk in 96tpi drive
+Rate49= 001H ; Step rate 48tpi disk in 96tpi drive
+Rate44= 002H ; Step rate 48tpi disk in 48tpi drive
+
+; Commands to floppy disk controller
+
+FD_CRESET= 007H ; Recalibrate drive
+FD_CSENSE= 008H ; Sense interrupt status
+FD_CSEEK= 00FH ; Seek to another track
+FD_CREAD= 046H ; MFM read, skip deleted data
+FD_CWRITE= 045H ; MFM write, skip deleted data
+FD_CSPEC= 003H ; Special - step rate, head load/unload
+
+; Status codes
+
+FD_SDIO= 01000000B ; Transfer direction (0 -> controller)
+FD_SRQM= 10000000B ; Controller ready for next data
+
+; Hard disk controller commands
+HD_CSENS= 03H ; request sense block
+HD_CREAD= 08H ; read
+HD_CWRITE= 0AH ; write
+
+HDcontrolbyte= 05H ; step rate = 70 us.
+
+; I/O ports
+
+FD_PSEL= 03F2H ; Controls drive select and motors
+FD_PDAT= 03F5H ; Data transfer to/from controller
+FD_PSTAT= 03F4H ; Controller status
+FD_PCMD= 03F7H ; Controller command register
+
+HD_PDAT= 0320H ; read/write data
+HD_PSTAT= 0321H ; controller status
+HD_PSEL= 0322H ; controller select
+HD_PMSK= 0323H ; DMA and interrupt mask bits
+
+PDMA= 0 ; Base of ports for DMA control
+PDMAX= 7FH ; Address extension regs for DMA
+ ;NOTE base address suitable for ch. 2 & 3 only
+FD_DMA= 2 ; floppy disk DMA channel
+HD_DMA= 3 ; hard disk DMA channel
+
+DMA_READ= 44H ; DMA read command
+DMA_WRITE= 48H ; DMA write command
+
+; Misc
+
+DORmask= 00CH ; Not reset, enable DMA & interrupt
+
+
+
+SUBTTL Data for performing requests
+PAGE +
+
+;* Dos Request Packet structure
+
+DosPacket STRUC
+ RqCmdLen DB 0 ; Length of this command
+ RqUnit DB 0 ; Unit in this driver
+ RqCmd DB 0 ; Command to do
+ RqStatus DW 0 ; Status of request
+ DD 0
+ DD 0 ; Not used
+ RqMedia DB 0 ; Media descriptor
+ RqAddr DW 0 ; Offset of data
+ DW 0 ; Segment of data
+ RqCount DW 0 ; Number of sectors
+ RqFirst DW 0 ; First sector to do
+DosPacket ENDS
+
+; The disk drivers work as a state machine performing the various actions
+; that make up disk I/O.
+
+; Driver states
+; The following states are common to both drivers
+Start= 0 ; Starting I/O
+Calc= 1 ; Calculate position on disk
+Done= 7 ; I/O is done
+Idle= 8 ; Drive is inactive
+Error= 9 ; Have an error
+; The following states are used by the floppy driver only
+Select= 2 ; Select drive, start motor, seek
+Recal= 3 ; Drive was just recalibrated
+Seek= 4 ; Seek just finished
+Settle= 5 ; Head has settled
+RdWri= 6 ; Read/write is done
+; The following states are used by the fixed driver only
+Verify= 6 ; Start verify portion of write
+
+
+DeviceStruc STRUC
+ State DW Idle ; Current drive state
+ Current DW -1 ; Current active drive
+ ErrCnt DB 0 ; # of errors in doing request
+ Flags DB 0 ; Various bit flags, see below
+ DOR DB 0 ; Copy of select/motor reg
+; Following values are set by Setup from the request packet and are
+; updated after each transfer is completed.
+ Unit DB 0 ; Unit
+ First DW 0 ; 1st sector of request
+ RealAddr DD 0 ; Real addr of data when Addr is
+ ; scratch buffer.
+ Count DW 0 ; Number of sectors to xfer
+; Following values are set by MapSector.
+ Cyl DW 0 ; Cylinder
+ Sector DB 0 ; Sector - zero based
+ Head DB 0 ; Head
+ NumSectors DW 0 ; Number of sectors to do
+ NumBytes DW 0 ; Number of bytes
+ Addr DD 0 ; Pointer to data buffer
+; Device dependent data
+ ST0 DB 0 ; floppy controller ST0
+ ST1 DB 0 ; floppy controller ST1
+ ST2 DB 0 ; floppy controller ST2
+ CHRN DB 0,0,0,0 ; other floppy status returns
+DeviceStruc ENDS
+ DCB EQU ST0 ; Fixed disk Device Control Block
+
+; Bits in Flags
+
+ Factive= 1 ; Actively working on something
+ F2step= 2 ; Must double step when seeking
+ Fwrite= 4 ; This is a write, not a read
+ Fverify= 8 ; This is a verify, not a rd/wr
+ Fwrap1= 010H ; We are currently using ScratchBuffer
+ Fwrap2= 020H ; We have used ScratchBuffer in this req
+
+BiosSeg GROUP Code,BiosInit
+
+Code SEGMENT BYTE PUBLIC 'CODE'
+ ASSUME CS:BiosSeg
+
+IFDEF DEBUGFLG
+ EXTRN BUGBITS:BYTE,DPRINTF:NEAR
+ENDIF
+
+SUBTTL Device data
+PAGE +
+
+Floppy DeviceStruc <>
+Fixed DeviceStruc <>
+
+;* Per drive information, including BPBs
+
+DriveStruc STRUC
+ BPBsecsiz DW 512 ; Physical sector size
+ BPBsecpau DB 1 ; Sectors/Allocation unit
+ BPBressec DW 1 ; Reserved sectors for DOS
+ BPBnfat DB 2 ; # of allocation tables
+ BPBndir DW 64 ; # of directory entries
+ BPBnsec DW 9*40 ; Number of sectors
+ BPBmediab DB 0FCH ; Media descriptor
+ BPBnfatsec DW 2 ; # of FAT sectors
+ BPBtrksiz DW 9 ; # of sectors/track
+ BPBnhead DW 1 ; # of heads
+ BPBhidsec DW 0 ; Hidden sector count
+ Timer DB 0 ; Countdown for motor off
+ DrvFlag DB 1 ; Per-drive flags, see below
+ TPI DB 0 ; Drive TPI= Not present, 48, 96
+ CurCyl DW -1 ; Current cylinder
+DriveStruc ENDS
+
+; DrvFlag values
+Frestor= 1 ; restore needed
+Fmotoron= 2 ; motor is on
+
+DriveA DriveStruc <> ; floppy drive 0
+DriveB DriveStruc <> ; floppy drive 1 or 0
+DriveC DriveStruc <> ; hard drive 0 or floppy drive 2
+DriveD DriveStruc <> ; hard drive 1 or floppy drive 3
+
+FDinfo DW DriveA
+ DW DriveB
+HDinfo DW DriveC
+ DW DriveD
+
+
+; Structure of parameter block for floppy pointed to by 0:4*1E
+
+FloppyParameter STRUC
+ Spec1 DB 0 ; 0 1st byte for specify cmd
+ Spec2 DB 0 ; 1 2nd byte for specify cmd
+ DelayOff DB 0 ; 2 # of Ticks(1/18.2) until
+ ; motor shut off
+ SectorSize DB 0 ; 3 Sector size(128,256,512,1024)
+ ; = (O,1,2,3 are put here)
+ CylSize DB 0 ; 4 Number of sectors/cylinder
+ DataGap DB 0 ; 5 Gap length of read/write
+ ValueDTL DB 0 ; 6 Data length (ignored)
+ FormatGap DB 0 ; 7 Gap for format operation
+ FormatFill DB 0 ; 8 Fill char for format
+ DelaySettle DB 0 ; 9 Head settle time in msec
+ DelayMotor DB 0 ; 10 Motor start time in 1/8 sec
+FloppyParameter ENDS
+
+
+ScratchBuffer DB 512 DUP(?) ; Scratch buffer for when DMA fails
+ ; Hope we don't handle >512 sector
+ ; size
+
+;* Miscellaneous data
+
+Single DB 0 ; non-zero if 1 floppy disk system
+ ; in this case, NumFloppy will be 2
+
+SUBTTL Data for interface to 4.0
+PAGE +
+
+ EXTRN DosFunction:DWORD ; Addr of DOS function routine
+
+; Dos helper functions used by disk driver
+
+ PullRequest = 2 ; Pull a request from the queue
+ PushRequest = 4 ; Add a request to the queue
+ BlockProcess = 9 ; Block process until I/O done
+ ContinueProcess = 10 ; I/O done, continue process
+
+int_savregs= 32H ; interrupt routine which saves all regs
+
+
+SwapSem1 DB 0 ; non-zero if waiting to swap disks
+SwapSem2 DB 0 ; non-zero if waiting to prompt for swap
+ScratchBufSem DB 0 ; semaphore controlling ScratchBuffer
+
+SEM_WANT= 2
+SEM_BUSY= 1
+
+SemWait Macro wchan
+local l1,l2
+ pushf
+l1: cli
+ test wchan,SEM_BUSY ;;semaphore busy?
+ jz l2 ;;no
+ or wchan,SEM_WANT ;;say we want it
+ mov ax,cs
+ mov bx,OFFSET wchan
+ xor cx,cx
+ mov dx,BlockProcess
+ call [DosFunction] ;;wait till semaphore released
+ jmp l1
+l2: or wchan,SEM_BUSY ;;claim semaphore
+ popf
+ endm
+
+SemSig Macro wchan
+local l
+ test wchan,SEM_WANT ;;anyone waiting on semaphore?
+ jz l
+ mov ax,cs
+ mov bx,OFFSET wchan
+ mov dx,ContinueProcess
+ call [DosFunction]
+l: and wchan,NOT (SEM_WANT+SEM_BUSY)
+ endm
+
+
+FloppyQueue DD 0 ; List of requests for floppy
+FixedQueue DD 0 ; List of requests for fixed disk
+
+; Device driver headers
+
+ PUBLIC FloppyDevice
+FloppyDevice LABEL WORD
+ DD FixedDevice ; Next device is hard disk
+ DW 100000B ; This is 4.0 driver
+ DW JustReturn ; Strategy does nothing
+ DW FloppyRequest ; Interrupt does the work
+NumFloppy DB 4 ; Handle 4 floppys maximum
+ DB 0 ; can be addressed as word also
+
+ EXTRN Com1Dev:NEAR
+
+FixedDevice LABEL WORD
+ DD Com1Dev ; Next device is comm port 1
+ DW 100000B ; This is 4.0 driver
+ DW JustReturn ; Strategy does nothing
+ DW FixedRequest ; Interrupt does work (misnomer)
+NumFixed DB 0 ; Handle 2 hard disks maximum
+
+
+; Utility routines which reside in the BIOS main module
+
+ EXTRN Interrupt:NEAR ; BIOS interrupt routine(misnomer)
+ EXTRN CmdErr:NEAR
+ EXTRN StatusDevReady:NEAR
+ EXTRN StatusComplete:NEAR
+ EXTRN StatusError:NEAR
+ EXTRN SetStatus:NEAR
+
+JustReturn PROC FAR
+ RET
+JustReturn ENDP
+
+FloppyRequest PROC FAR
+ debug 4,2,,>
+ PUSH SI
+ LEA SI,FloppyFunction ; 4.0 function routines
+ JMP Interrupt ; Let BIOS figure out what to do
+FloppyRequest ENDP
+
+; Dispatch table for actions of the floppy requested by 4.0
+
+FloppyFunction LABEL WORD
+ DW FloppyInit ; 0 Initialize
+ DW FloppyCheck ; 1 Check media
+ DW FloppyBuild ; 2 Build BPB
+ DW CmdErr ; 3 IOCTL input
+ DW FloppyRead ; 4 Read
+ DW StatusDevReady ; 5 Non-destructive read
+ DW StatusComplete ; 6 Input status
+ DW StatusComplete ; 7 Input flush
+ DW FloppyWrite ; 8 Write
+ DW FloppyWriteV ; 9 Write with verify
+ DW CmdErr ; 10 Output status
+ DW CmdErr ; 11 Output flush
+ DW CmdErr ; 12 IOCTL output
+ DW CmdErr ; 13 Device open
+ DW CmdErr ; 14 Device close
+ DW CmdErr ; 15 Removable media
+ DW CmdErr ; 16 Generic IOCTL request
+
+FixedRequest PROC FAR
+ debug 8,2,,>
+ PUSH SI
+ LEA SI,FixedFunction ; 4.0 function routines
+ JMP Interrupt ; Let BIOS figure out what to do
+FixedRequest ENDP
+
+; Dispatch table for actions of the hard disk requested by 4.0
+
+FixedFunction LABEL WORD
+ DW FixedInit ; 0 Initialize
+ DW FixedCheck ; 1 Check media
+ DW FixedBuild ; 2 Build BPB
+ DW CmdErr ; 3 IOCTL input
+ DW FixedRead ; 4 Read
+ DW StatusDevReady ; 5 Non-destructive read
+ DW StatusComplete ; 6 Input status
+ DW StatusComplete ; 7 Input flush
+ DW FixedWrite ; 8 Write
+ DW FixedWriteV ; 9 Write with verify
+ DW CmdErr ; 10 Output status
+ DW CmdErr ; 11 Output flush
+ DW CmdErr ; 12 IOCTL output
+ DW CmdErr ; 13 Device open
+ DW CmdErr ; 14 Device close
+ DW CmdErr ; 15 Removable media
+ DW CmdErr ; 16 Generic IOCTL request
+
+
+SUBTTL Data for routines that make direct Int 13 requests
+PAGE +
+
+
+RealInt13Vec dw 0 ; Used to make Int 13 requests
+ dw 0
+OldIntDVec dw 0 ; Must be reset when Int 13's on hard
+ dw 0 ; disk.
+OldIntEVec dw 0 ; Must be reset when Int 13's on floppy
+ dw 0 ; disk.
+SemDiskIO db 0 ; Semaphore controlling disk io
+SemInt13 db 0 ; Semaphore controlling Int 13's
+
+
+SUBTTL 4.0 device driver routines (system entry points)
+PAGE +
+
+BiosInit SEGMENT PARA PUBLIC 'CODE'
+ ASSUME CS:BiosSeg
+
+ PUBLIC Disk_Init
+Disk_Init PROC
+;**************************************************************
+; This routine performs device dependent initialization
+; during the BIOS initialization. Not to be confused
+; with the device initialization entry points which are
+; called later on and perform different functions.
+;
+; AFTER THE EQUIPMENT CALL (INT 11H) BITS 6&7 WILL TELL
+; THE NUMBER OF FLOPPY DISKS IN THE SYSTEM.
+; THE INDICATIONS ARE AS FOLLOWS:
+;
+; BITS 7 6 DRIVES
+; 0 0 1
+; 0 1 2
+; 1 0 3
+; 1 1 4
+;**************************************************************
+
+ debug 12,1,,<>
+ PUSH CS
+ POP DS
+
+ ASSUME DS:BiosSeg
+ INT 11H ;GET EQUIPMENT STATUS
+ rol al,1 ; rotate around to low order bits
+ rol al,1
+ AND AL,11B ;MASK DRIVE BITS
+ JNZ NOTSNGL ;Zero means single drive system
+ INC [SINGLE] ;REMEMBER THIS
+ inc al ; make it look like two-drive system
+NOTSNGL:
+ inc al
+ MOV [NumFloppy],AL ;Remember how many drives
+ MOV AH,8
+ MOV DL,80H
+ INT 13H ;Request number of hardfiles attached
+ JC ENDDRV ;Carry indicates old rom, so no hardfile
+ MOV [NumFixed],DL
+ test dl,dl ; any specified?
+ jz ENDDRV ; no
+ cmp NumFloppy,2 ; too many floppies?
+ jbe ENDDRV
+ mov NumFloppy,2 ; limit to two floppies max.
+ENDDRV:
+
+;* Initialize the hard disk BPBs
+
+ MOV DL,80H
+ MOV DI,OFFSET DriveC
+ CMP [NumFixed],0
+ JLE ITSOK
+ CALL SETHRD ;SET UP FIRST HARDFILE
+
+ MOV DL,81H ;SET UP FOR NEXT CALL
+ MOV DI,OFFSET DriveD
+ JC NOTOK
+ CMP [NumFixed],2
+ JZ SETIT
+ JMP SHORT ITSOK
+NOTOK:
+ MOV DI,OFFSET DriveC
+ DEC [NumFixed]
+ CMP [NumFixed],0
+ JZ ITSOK
+SETIT: CALL SETHRD ;SET UP SECOND HARDFILE
+ JNC ITSOK
+ DEC [NumFixed]
+ITSOK:
+ cmp [NumFixed],0 ; any hard disks found?
+ jnz itsok2 ; yes
+ mov ax,[FixedDevice] ; no, patch device chain to skip fixed disk
+ mov [FloppyDevice],ax
+itsok2:
+ push es ; Install Int 13 handler and save the
+ xor ax,ax ; old value of the interrupt vector.
+ mov es,ax
+ mov ax,es:[4*13h]
+ mov [RealInt13Vec],ax
+ mov ax,OFFSET Int13Handler
+ mov es:[4*13H],ax
+ mov ax,es:[4*13h+2]
+ mov [RealInt13Vec+2],ax
+ mov es:[4*13H+2],cs
+ mov ax,es:[4*0dh] ; Save original Int D vector
+ mov [OldIntDVec],ax
+ mov ax,es:[4*0dh+2]
+ mov [OldIntDVec+2],ax
+ mov ax,es:[4*0eh] ; Save original Int E vector
+ mov [OldIntEVec],ax
+ mov ax,es:[4*0eh+2]
+ mov [OldIntEVec+2],ax
+ pop es
+ ret
+Disk_Init ENDP
+
+;
+; READ A BOOT RECORD INTO Scratch buffer
+;
+GETBOOT:
+ MOV CX,1
+ MOV AX,0201H
+ push CS
+ pop es
+ mov BX,OFFSET ScratchBuffer
+ xor DH,DH
+ INT 13H
+ JC SETRET
+ CMP WORD PTR ES:[BX+1FEH],0AA55H
+ JNZ SETRET
+ RET
+;
+; SETUP VARIABLE SIZED HARDFILE
+; ON ENTRY DL=DRIVE NUMBER (80 OR 81)
+; DI=PTR TO B.P.B
+;
+SETHRD: PUSH DX
+ MOV AH,8 ;GET DRIVE PARAMETERS
+ INT 13H
+ INC DH
+ MOV BYTE PTR [DI].BPBnhead,DH
+ POP DX
+ JC SETRET
+ AND CL,3FH
+ MOV BYTE PTR [DI].BPBtrksiz,CL
+ CALL GETBOOT ;GET THE BOOT RECORD
+ JC SETRET
+ add BX,1C2H
+ mov cx,4
+SET1: CMP BYTE PTR ES:[BX],1
+ JZ SET2
+ ADD BX,16
+ loop SET1
+SETRET: STC ;NOT FOUND SO USE DEFAULTS
+ debug 8,3,,
+ RET
+
+SET2: MOV AX,ES:[BX+4]
+ MOV DS:[DI].BPBhidsec,AX ;SET HIDDEN SECTOR COUNT
+ MOV AX,ES:[BX+8]
+ CMP AX,64 ;HAS TO BE AT LEAST 32K
+ JB SETRET
+ MOV DS:[DI].BPBnsec,AX ;SAVE LOGICAL SECTOR COUNT
+ MOV CX,0100H ;SET CLUS SIZE AND SHIFT COUNT
+ MOV DX,64 ;SET NUMBER OF DIR ENTRIES
+ CMP AX,512
+ JBE SET3
+
+ ADD CH,CH
+ INC CL
+ MOV DX,112
+ CMP AX,2048
+ JBE SET3
+
+ ADD CH,CH
+ INC CL
+ MOV DX,256
+ CMP AX,8192
+ JBE SET3
+
+ ADD CH,CH
+ INC CL
+ ADD DX,DX
+ CMP AX,32680 ;NOT 32768! MAX NUMBER OF CLUSTERS=4085
+ JBE SET3
+
+ ADD CH,CH
+ INC CL
+ ADD DX,DX
+SET3:
+;
+; DX=NUMBER OF DIR ENTRIES, CH=NUMBER OF SECTORS PER CLUSTER
+; CL=LOG BASE 2 OF CH
+;
+; NOW CALCULATE SIZE OF FAT TABLE
+;
+ MOV [DI].BPBndir,DX ;SAVE NUMBER OF DIR ENTRIES
+ MOV [DI].BPBsecpau,CH ;SAVE SECTORS PER CLUSTER
+ XOR BX,BX
+ MOV BL,CH
+ DEC BX
+ ADD BX,AX
+ SHR BX,CL ;DIVIDE BY SECTORS/CLUSTER
+ INC BX
+ AND BL,11111110B ;MAKE SURE COUNT IS EVEN
+ MOV SI,BX
+ SHR BX,1
+ ADD BX,SI ;MULTIPY BY 1.5
+ ADD BX,511
+ SHR BH,1
+ MOV BYTE PTR [DI].BPBnfatsec,BH ;SAVE NUMBER OF FAT SECTORS
+ MOV [DI].BPBmediab,0F8H ; set media byte
+ CLC
+ RET
+BiosInit ENDS
+
+ ASSUME CS:BiosSeg,DS:NOTHING,ES:NOTHING
+
+FloppyInit PROC
+ debug 4,3,,<>
+ push ds ; install floppy interrupt routine
+ xor ax,ax
+ mov ds,ax
+ mov ax,OFFSET FloppyInterrupt
+ mov ds:[4*0eH],ax
+ mov ds:[4*0eH+2],cs
+ pop ds
+ call Rst765
+ mov ah,[NumFloppy]
+ mov di,OFFSET FDinfo
+DBBEG 4,3
+ jmp SHORT iniret
+DBEND
+ jmp bpbret
+ELSE
+ jmp SHORT bpbret
+ENDIF
+FloppyInit ENDP
+
+FixedInit PROC
+ debug 8,3,,<>
+ push ds ; install fixed disk interrupt routine
+ xor ax,ax
+ mov ds,ax
+ mov ax,OFFSET FixedInterrupt
+ mov ds:[4*0dH],ax
+ mov ds:[4*0dH+2],cs
+ pop ds
+ in al,21H ; unmask fixed disk interrupts
+ and al,0DFH
+ out 21H,al
+ mov dx,HD_PMSK ; set interrupt and DMA mask bits
+ mov al,3
+ out dx,al
+ mov ah,[NumFixed]
+ mov di,OFFSET HDinfo
+DBBEG 8,3
+iniret: debug 12,3,< - Num=$x BPB table=$x:$x\n>,
+DBEND
+ENDIF
+ jmp SHORT bpbret
+FixedInit ENDP
+
+FloppyBuild PROC
+ mov ah,byte ptr es:[di]
+ call FDGetBPB
+bpbret: mov [bx.RqMedia],ah
+ mov [bx.RqCount],di
+ mov [bx.RqCount+2],CS
+ jmp StatusComplete
+FloppyBuild ENDP
+
+FixedBuild PROC
+ mov ah,byte ptr es:[di]
+ call HDGetBPB
+ jmp SHORT bpbret
+FixedBuild ENDP
+
+;*** FloppyCheck - check to see if the disk may have been changed.
+;
+; ENTRY AL = unit #
+; AH = media byte
+; EXIT Return value in request header set to one of:
+; 1 Media may have been changed
+; 0 Media not changed
+; -1 Media was probably changed
+;
+
+FloppyCheck PROC
+ MOV DL,1 ; Assume not changed
+ cmp AH,0f8H ; Is disk removable?
+ JE FloppyCheckDone ; No, can't be changed then
+ cmp Single,0 ; single drive system?
+ je flchk1 ; no, check drive state
+ cmp Floppy.Unit,al ; unit = current drive?
+ je flchk1 ; yes, check drive state
+ mov DL,-1 ; say media changed for sure
+ jmp FloppyCheckDone
+flchk1: MOV CX,AX
+ XOR CH,CH
+ MOV SI,CX
+ ADD SI,SI
+ MOV SI,FDinfo[SI] ; Get pointer to drive info
+ TEST CS:[SI].DrvFlag,Fmotoron ; Is motor on?
+ JNZ FloppyCheckDone ; Yes, media not changed then
+ XOR DL,DL ; No, might have been changed
+FloppyCheckDone:
+ MOV BYTE PTR DS:[BX].RqAddr,DL
+ JMP StatusComplete ; Return whether media changed
+FloppyCheck ENDP
+
+
+FixedCheck PROC
+ MOV DL,1
+ JMP FloppyCheckDone
+FixedCheck ENDP
+;*** FloppyRead, FloppyWrite, FloppyWriteV - Basic I/O entry points
+;
+; FloppyRead, FloppyWrite and FloppyWriteV are the basic I/O
+; routines used by the DOS. They really do not do much except
+; queue the request and start the device if it is idle.
+; For single drive floppy systems, they also handle the
+; switching of disks when I/O changes from A to B or vice-versa.
+;
+; ENTRY DS:BX Packet address
+; ES:DI Transfer address
+; AL Unit #
+; AH Media Byte
+; CX # of sectors
+; DX Starting sector
+;
+; EXIT DS:BX Packet Addr
+; CX # of sectors left to do
+;
+; USES SI
+
+FloppyRead LABEL NEAR
+FloppyWrite LABEL NEAR
+FloppyWriteV PROC
+ debug 4,2,,
+ call BlockIfLocked
+ push di
+ call FDGetBPB ; cs:di => BPB
+ mov si,dx
+ add si,cx ; compute last sector + 1
+ cmp si,cs:[di.BPBnsec]
+ mov si,di
+ pop di
+ jbe flrw1
+ mov al,8 ; ERROR - Sector not found
+ jmp StatusError
+
+flrw1: OR CX,CX ; Anything to do?
+ JNZ flrw2 ; Yes
+ JMP StatusComplete ; No, all done now
+flrw2:
+ CMP Single,0 ; Is this a single drive system?
+ JE flrw3 ; No, don't check for drive change
+ CALL FloppyChange ; See if should change disks
+flrw3:
+ call CheckWrap
+ push ds
+ pop es ; ES:BX = Request addr
+ push cs
+ pop ds
+ LEA SI,FloppyQueue ; DS:SI = ptr to head of queue
+ MOV DX,PushRequest
+ CALL DosFunction ; Add request to list
+ push es
+ pop ds ; Back to DS:BX is request
+ pushf
+ cli ; interrupts off while testing state
+ TEST Floppy.Flags,Factive ; Is driver active?
+ JNE FloppyActive ; Yes, driver will get to it
+ PUSH DS
+ PUSH BX ; Save some regs
+ OR Floppy.Flags,Factive
+ MOV Floppy.State,Start ; Want to start I/O
+ CALL FloppyExecute ; Start up the driver
+ POP BX
+ POP DS ; Restore regs
+flrw4: test DS:[BX].RqStatus,0100H ; IO completed?
+ JNZ FloppyIOdone ; yes
+
+FloppyActive:
+ MOV AX,DS ; AX:BX = request
+ xor cx,cx
+ push bx
+ MOV DX,BlockProcess
+ CALL DosFunction ; Block until I/O is done
+ pop bx
+ jmp flrw4 ; test completion status again
+FloppyIOdone:
+ popf
+ MOV AX,DS:[BX].RqStatus ; Need AX = status
+ MOV CX,DS:[BX].RqCount ; Need CX = count left to do
+ debug 4,2,,
+ JMP SetStatus ; Return to DOS with results
+FloppyWriteV ENDP
+
+
+FixedRead LABEL NEAR
+FixedWrite LABEL NEAR
+FixedWriteV PROC
+ debug 8,2,,
+ call BlockIfLocked
+ push di
+ call HDGetBPB ; cs:di => BPB
+ mov si,dx
+ add si,cx ; compute last sector + 1
+ cmp si,cs:[di.BPBnsec]
+ mov si,di
+ pop di
+ jbe fxrw1
+ mov al,8 ; ERROR - Sector not found
+ jmp StatusError
+
+fxrw1: OR CX,CX ; Anything to do?
+ JNZ fxrw2 ; Yes
+ JMP StatusComplete ; No, all done now
+fxrw2:
+ call CheckWrap
+ push ds
+ pop es ; ES:BX = Request addr
+ push cs
+ pop ds
+ LEA SI,FixedQueue ; DS:SI = ptr to head of queue
+ MOV DX,PushRequest
+ CALL DosFunction ; Add request to list
+ push es
+ pop ds ; Back to DS:BX is request
+ pushf
+ cli ; interrupts off while testing state
+ TEST Fixed.Flags,Factive ; Is driver active?
+ JNE FixedActive ; Yes, driver will get to it
+ PUSH DS
+ PUSH BX ; Save some regs
+ OR Fixed.Flags,Factive
+ MOV Fixed.State,Start ; Want to start I/O
+ CALL FixedExecute ; Start up the driver
+ POP BX
+ POP DS ; Restore regs
+fxrw4: test DS:[BX].RqStatus,0100H ; IO completed?
+ JNZ FixedIOdone ; yes
+
+FixedActive:
+ MOV AX,DS ; AX:BX = request
+ xor cx,cx
+ push bx
+ MOV DX,BlockProcess
+ CALL DosFunction ; Block until I/O is done
+ pop bx
+ jmp fxrw4 ; test completion status again
+FixedIOdone:
+ popf
+ MOV AX,DS:[BX].RqStatus ; Need AX = status
+ MOV CX,DS:[BX].RqCount ; Need CX = count left to do
+ debug 8,2,,
+ JMP SetStatus ; Return to DOS with results
+FixedWriteV ENDP
+
+;*** CheckWrap - check whether a request crosses a 64Kb boundary
+;
+; CheckWrap will check whether the request given in DS:BX
+; crosses a 64Kb boundary. A portion of such requests must
+; be done using ScratchBuffer for a single sector transfer.
+; This routine ensures that only one such request is put into
+; either of the request queues at any time.
+;
+; ENTRY DS:BX Request header
+; ES:DI Transfer address
+; CS:SI Pointer to BPB
+; CX Sector count
+; EXIT When it's safe to proceed.
+; USES AX,BP
+
+CheckWrap PROC
+ push dx
+ push cx
+ mov ax,cx
+ mul cs:[si.BPBsecsiz]
+ mov dx,es ; compute offset
+ mov cl,4
+ shl dx,cl
+ add dx,di
+ clc ; now see if offset+nbytes overflows
+ add dx,ax
+ jnc chkw8
+ debug 12,10h,,
+ push bx
+ SemWait ScratchBufSem ; wait for ScratchBuffer to be available
+ pop bx
+
+chkw8: pop cx
+ pop dx
+ ret
+CheckWrap ENDP
+
+
+;*** FloppyChange - check whether floppy disk must be changed
+;
+; FloppyChange is called on a single drive system to simulate a
+; two drive system. The current request for I/O is checked against
+; what the driver considers to be the current drive. If they are
+; the same, FloppyChange just returns. Otherwise, SwapSem2 is set
+; and the current process is blocked on SwapSem2. Any process that
+; attempts I/O while SwapSem2 is set is blocked on SwapSem1. When
+; SwapSem2 is cleared, these processes are continued. When the
+; driver becomes idle and SwapSem2 is set, the Idle state continues
+; the blocked process. This process then puts out the message about
+; switching disks and waits for a user reply. When it is given,
+; FloppyChange clears SwapSem1 and causes the I/O to be started.
+;
+; ENTRY DS:BX Pointer to I/O request
+;
+; USES AX,DX
+;
+
+
+FloppyChange PROC
+ push cx
+ pushf
+ push bx
+ SemWait SwapSem1 ; Currently waiting to switch disk?
+ pop bx
+
+flcha1: and SwapSem1,NOT SEM_BUSY ; reset BUSY for now
+ MOV AL,DS:[BX].RqUnit ; Get desired unit
+ CMP AL,Floppy.Unit ; Switching A and B drive?
+ JE flcha7 ; No, keep using this drive
+ CLI ; ** Disable interrupts
+ OR SwapSem1,SEM_BUSY ; Flag waiting to switch
+ test Floppy.Flags,Factive ; Is driver idle?
+ JE flcha2 ; Yes, don't need to wait
+ push bx
+ SemWait SwapSem2
+ pop bx
+ jmp flcha1
+flcha2:
+ popf ; restore interrupt state
+ pushf
+ ADD AL,"A" ; Convert to drive letter
+ MOV CS:DriveLetter,AL ; Set the letter
+ PUSH DS
+ PUSH SI
+ push bx
+ push cs
+ pop ds
+ LEA SI,SwitchMsg
+flcha4:
+ LODSB
+ OR AL,AL ; End of message?
+ JZ flcha5 ; Yes
+ INT 29H ; No, output char
+ JMP flcha4 ; Put out whole msg
+
+flcha5:
+ mov ah,1 ; Flush keyboard input
+ int 16H
+ jz flcha5
+ XOR AH,AH
+ INT 16H ; Wait for a char
+ pop bx
+ POP SI
+ POP DS
+flcha7:
+ push bx
+ SemSig SwapSem1 ; Allow blocked processes to continue
+ pop bx
+flcha8:
+ popf
+ pop cx
+ RET
+
+FloppyChange ENDP
+
+
+SwitchMsg LABEL WORD
+ DB 13,10,"Insert diskette for drive "
+DriveLetter LABEL BYTE
+ DB "A: and strike",13,10,"any key when ready",13,10,10,0
+
+
+Int13Handler Proc Far
+ push dx ; Save regs used in local processing
+ push cx
+ push bx
+ push ax
+ pushf
+LockCheck:
+ cli ; If any Int 13 request is already
+ cmp SemInt13,0 ; pending, block this process until
+ jz NotLocked ; the previous one finishes.
+ mov ax,cs
+ mov bx,offset SemInt13
+ xor cx,cx
+ mov dx,BlockProcess
+ call DosFunction
+ jmp LockCheck
+NotLocked:
+ mov SemInt13,1 ; Lock out other disk requests
+ popf
+ pushf
+BusyCheck:
+ cli
+ cmp SemDiskIO,0 ; If the disks are busy, block this
+ jz DiskFree ; process till they free up.
+ mov ax,cs
+ mov bx,offset SemDiskIO
+ xor cx,cx
+ mov dx,BlockProcess
+ call DosFunction
+ jmp BusyCheck
+DiskFree:
+ popf
+ sti
+ pop ax ; Restore regs for call
+ pop bx
+ pop cx
+ pop dx
+ push dx
+ push cx
+ push bx
+ pushf
+ call dword ptr [RealInt13Vec]
+ mov SemInt13,0
+ push ax
+ pushf
+ mov ax,cs ; Unblock anything that is waiting
+ mov bx,offset SemInt13
+ mov dx,ContinueProcess
+ call DosFunction
+ popf ; Restore user regs
+ pop ax
+ pop bx
+ pop cx
+ pop dx
+ ret 2
+Int13Handler endp
+
+
+SUBTTL Fixed disk startup routine
+PAGE +
+
+; FixedExecute processes a disk request after it has been set up. When the
+; disk is inactive (State = Idle), it is called to start the device. For all
+; subsequent events, it is called on the disk interrupt which signaled the
+; completion of that subfunction. Some states do not involve waiting for an
+; interrupt to occur. This routine runs entirely off the 'Fixed' data structure
+
+FixedDispatch LABEL WORD
+ DW FxExStart
+ DW FxExCalc
+ DW FxExError ;; BUGBUG really error in state machine
+ DW FxExError ;; BUGBUG really error in state machine
+ DW FxExError ;; BUGBUG really error in state machine
+ DW FxExError ;; BUGBUG really error in state machine
+ DW FxExVerify
+ DW FxExDone
+ DW FxExIdle
+ DW FxExError
+
+FixedExecute PROC
+ push cs ; CS -> DS
+ pop ds
+ ASSUME DS:BiosSeg
+ MOV BX,Fixed.State ; Get current state
+ debug 8,4,,
+ ADD BX,BX
+ JMP FixedDispatch[BX] ; Dispatch to correct routine
+
+
+;* Fixed state Start
+;
+; Do setup calculations to figure out sector, start
+; up motor, advance to Calc state.
+;
+; Entered on initially picking up a new request to do and on error retries.
+; If error retries start here, then multiple sector requests will always start
+; at the beginning rather than at the point of the error! Why?
+
+FxExStart:
+ mov si,OFFSET Fixed ; SI = pointer to per-device info.
+ les bx,FixedQueue ; ES:BX = pointer to current request
+ mov al,es:[bx].RqUnit
+ call HDGetBPB ; DI = drive parameters
+ CALL Setup ; Do setup calculations
+ MOV Fixed.State,Calc ; Advance to next state
+ JMP FixedExecute ; Now return to do Calc code
+
+
+
+;* Fixed state Calc
+;
+; Calculate cylinder, head and sector, wait for motor
+; start or head load, advance to Select state.
+;
+; Entered after Start state and also on further sectors of a multiple sector
+; request.
+
+FxExCalc:
+ mov si,OFFSET Fixed ; SI = pointer to per-device info.
+ les bx,FixedQueue ; ES:BX = pointer to current request
+ mov al,es:[bx].RqUnit
+ call HDGetBPB ; DI = drive parameters
+ CALL MapSector ; Get head, cylinder and sector
+ test Fixed.Flags,Fwrite
+ jnz fxxc1
+ mov al,DMA_read
+ mov Fixed.DCB,HD_CREAD
+ jmp SHORT fxxc2
+fxxc1: mov al,DMA_write
+ mov Fixed.DCB,HD_CWRITE
+fxxc2: mov ah,HD_DMA
+ call DMAsetup ; set up DMA transfer
+ mov al,Fixed.Unit
+ mov cl,5
+ shl ax,cl
+ or al,Fixed.Head
+ mov Fixed.DCB+1,al ; set head/unit
+ mov ax,Fixed.cyl
+ mov Fixed.DCB+3,al ; set low cylinder
+ shr ax,1
+ shr ax,1
+ and al,0C0H
+ or al,Fixed.Sector
+ mov Fixed.DCB+2,al ; set high cylinder/sector
+ mov al,BYTE PTR Fixed.Numsectors
+ mov Fixed.DCB+4,al ; set sector count
+ mov Fixed.DCB+5,HDcontrolbyte ;BUGBUG - what do we want here?
+ mov al,3
+ call HDCommand
+ mov al,Done ; assume next state is Done
+ test Fixed.Flags,Fverify
+ jz fxxc3
+ mov al,Verify
+fxxc3: mov BYTE PTR Fixed.State,al ; set next state
+ ret
+
+
+;* Fixed state Verify
+;
+; Have executed a write function, must now verify.
+; BUGBUG For now just go to done state.
+
+FxExVerify:
+ mov Fixed.State,Done
+ jmp FixedExecute
+
+
+
+;* Fixed state Done
+;
+; If whole request is now complete, mark the request
+; as done and then start the next one if there is one. If the request is not
+; yet done, adjust values to show the amount of the request done and then go
+; back to the Calc state to do next part.
+
+FxExDone:
+ MOV AL,Fixed.Flags
+ AND AL,Fwrite+Fwrap1 ; Only interested in these bits
+ CMP AL,Fwrap1 ; Just read into scratch?
+ JNE fxxd1 ; No
+ PUSH DS
+ PUSH ES
+ MOV CX,Fixed.NumBytes ; CS = # bytes to write from scr
+ LES DI,Fixed.RealAddr ; ES:DI = real buffer
+ LDS SI,Fixed.Addr ; DS:SI = scratch buffer
+ CLD
+ REP MOVSB ; Copy into real buffer
+ POP ES
+ POP DS
+fxxd1:
+ MOV AX,Fixed.NumSectors ; AX = # of sectors we did
+ SUB Fixed.Count,AX ; Adjust count to number left
+ JZ fxxd3 ; Request is done, tell DOS
+ ADD Fixed.First,AX ; Advance sector number
+ MOV AX,Fixed.NumBytes ; Number of bytes handled
+ ADD WORD PTR Fixed.RealAddr,AX ; Advance data address
+ MOV Fixed.State,Calc ; Go to Calc state
+fxexj4: JMP FixedExecute
+
+fxxd3:
+ mov DI,OFFSET Fixed
+ mov SI,OFFSET FixedQueue ; DS:SI = head of queue
+ call DoneRequest
+ JMP fxexj4
+
+
+;* Fixed state Idle
+;
+; Nothing hapenning, become inactive.
+
+FxExIdle:
+ and Fixed.Flags,NOT Factive
+ RET
+
+
+;* Fixed state Error
+;
+; Entered when a non-recoverable error is detected.
+; A sense block has been requested and put into the
+; DCB.
+
+FxExError:
+ MOV Fixed.State,Done ; Request is done
+; Set error bits in request packet
+ MOV AL,Fixed.DCB ; Get status byte
+ mov bl,al ; isolate error type as word address
+ and bx,0030h
+ mov cl,3
+ shr bx,cl
+ mov bx,HDErrType[BX] ; index into error table by type
+ and ax,0Fh ; get error code
+ cmp al,ds:[bx] ; outside range of table?
+ jae fxxe1
+ add bx,ax
+ mov ah,ds:[bx+1] ; translate error code
+ jmp SHORT fxxe2
+fxxe1:
+ mov ah,12
+fxxe2: dbbeg 8,4
+ mov di,OFFSET Fixed.DCB
+ debug 8,4,,<<[di]>,<[di+1]>,<[di+2]>,<[di+3]>,ax>
+ dbend
+ endif
+ PUSH ES
+ LES DI,FixedQueue ; Get ptr to request
+ MOV AL,ah
+ MOV AH,10000001B
+ MOV ES:[DI].RqStatus,AX ; Set error and code
+ POP ES
+ JMP fxxd3 ; Advance to Done state
+FixedExecute ENDP
+
+;* Traslation of controller error codes to DOS error codes
+
+HDErrType DW HDErrTyp0
+ DW HDErrTyp1
+ DW HDErrTyp2
+ DW HDErrTyp3
+
+HDErrTyp0 DB 9, 12, 2, 6,10, 2,12, 6,12, 6
+HDErrTyp1 DB 10, 4, 4, 8,12, 8, 6,12,12, 4, 6
+HDErrTyp2 DB 2, 3, 8
+HDErrTyp3 DB 3, 4, 4, 4
+
+ ASSUME CS:BiosSeg,DS:NOTHING,ES:NOTHING
+
+FixedInterrupt PROC FAR
+ debug 8,8,,<>
+ cmp word [SemDiskIO],0001h
+ jnz fxinot13
+ cmp SemInt13,0 ; If a direct Int13 request is being
+ jz fxinot13 ; made call the ROM floppy interrupt
+ cmp SemDiskIO,0 ; routine to handle it.
+ jnz fxinot13
+ int int_savregs
+;; in al,21H ; Mask fixed disk interrupts
+;; or al,20h
+;; out 21H,al
+ pushf
+ call dword ptr [OldIntDVec]
+ in al,21H ; Unmask fixed disk interrupts
+ and al,0DFH
+ out 21H,al
+ mov dx,HD_PMSK ; set interrupt and DMA mask bits
+ mov al,3
+ out dx,al
+ iret
+fxinot13:
+ TEST Fixed.Flags,Factive ; device active?
+ JZ fxinret ; no, go away
+ INT int_savregs ; save registers
+ mov dx,HD_PDAT
+ in al,dx ; get status reg.
+;; mov ah,al
+;; mov dx,HD_PMSK
+;; xor al,al
+;; out dx,al ; turn off intr. and DMA.
+;; test ah,02h ; error bit set?
+ test al,02h ; error bit set?
+ jz fxin4 ; no
+;* error occurred. see if retry, else get error code.
+ push cs
+ pop ds
+ ASSUME ds:BiosSeg
+ CMP Fixed.ErrCnt,ErrLim ; Reach error limit?
+ JAE fxin0 ; Yes, request fails
+ INC Fixed.ErrCnt ; We are doing another try
+ MOV Fixed.State,Start ; Restart the request
+ JMP fxin4
+fxin0: mov Fixed.DCB,HD_CSENS ; send sense command
+ xor al,al ; reset intr. & DMA masks
+ call HDCommand
+ push cs
+ pop es
+ mov di,OFFSET Fixed.DCB
+ mov cx,5
+fxin1: call HDWaitReq ; get the sense block back
+ mov dx,HD_PDAT
+ in al,dx
+ stosb
+ loop fxin1
+ mov Fixed.State,Error
+
+ ASSUME ds:NOTHING
+fxin4: CALL FixedExecute
+fxinret: push ax
+ MOV AL,20H ; send EOI to 8259
+ OUT 20H,AL
+ pop ax
+ IRET
+FixedInterrupt ENDP
+
+SUBTTL Floppy disk startup routine
+PAGE +
+
+; FloppyExecute processes a disk request after it has been set up.
+; When the disk is inactive (State = Idle), it is called to start
+; the device. For all subsequent events, it is called on the disk
+; interrupt which signaled the completion of that subfunction.
+; Some states do not involve waiting for an interrupt to occur.
+; This routine runs entirely off the 'Floppy' data structure
+
+FloppyDispatch LABEL WORD
+ DW FlExStart
+ DW FlExCalc
+ DW FlExSelect
+ DW FlExRecal
+ DW FlExSeek
+ DW FlExSettle
+ DW FlExRdWri
+ DW FlExDone
+ DW FlExIdle
+ DW FlExError
+
+FloppyExecute PROC
+ push cs ; CS -> DS
+ pop ds
+ ASSUME DS:BiosSeg
+ MOV BX,Floppy.State ; Get current state
+ debug 4,4,,
+ ADD BX,BX
+ JMP FloppyDispatch[BX] ; Dispatch to correct routine
+
+
+;* Floppy state Start
+;
+; Do setup calculations to figure out sector, start
+; up motor, advance to Calc state.
+;
+; Entered on initially picking up a new request to do and on error retries.
+; If error retries start here, then multiple sector requests will always start
+; at the beginning rather than at the point of the error! Why?
+
+FlExStart:
+ mov si,OFFSET Floppy ; SI = pointer to per-device info.
+ les bx,FloppyQueue ; ES:BX = pointer to current request
+ mov al,es:[bx].RqUnit
+ mov ah,es:[bx].RqMedia
+ call FDGetBPB ; DI = drive parameters
+ CALL Setup ; Do setup calculations
+ MOV DX,FD_PCMD
+ MOV AL,Rate44
+ OUT DX,AL ; Set step rate
+ MOV Floppy.State,Calc ; Advance to next state
+flexj1: JMP FloppyExecute ; Now return to do Calc code
+
+
+
+;* Floppy state Calc
+;
+; Calculate cylinder, head and sector, wait for motor
+; start or head load, advance to Select state.
+;
+; Entered after Start state and also on further sectors of a multiple sector
+; request.
+
+FlExCalc:
+ mov si,OFFSET Floppy ; SI = pointer to per-device info.
+ les bx,FloppyQueue ; ES:BX = pointer to current request
+ mov al,es:[bx].RqUnit
+ mov ah,es:[bx].RqMedia
+ call FDGetBPB ; DI = drive parameters
+ CALL MapSector ; Get head, cylinder and sector
+ MOV Floppy.State,Select ; Will advance to Select state
+ CALL Sel765 ; Select the drive and maybe wait
+ JNC FloppyExecute ; Did select with no waiting
+ RET ; Have set a timer, get out
+
+
+
+;* Floppy state Select
+;
+; Recalibrate the drive if needed. If Seek is
+; needed, start it and advance to Seek state. Otherwise advance to Settle
+; state.
+
+FlExSelect:
+ call GetDrivePtr
+ OR [BX].DrvFlag,Fmotoron ; we've been selected, so motor is on
+ TEST [BX].DrvFlag,Frestor ; Is a restore needed?
+ JE NoRestore ; No
+ call SetTimer2 ; set a sanity/motor stop timer
+ MOV Floppy.State,Recal ; Next state will be recalibrate
+ CALL Rcl765 ; Start the recalibrate
+ RET ; Done until floppy interrupt arrives
+
+NoRestore: ; Start the seek if any
+ CALL Seek765 ; Start the seek to cylinder
+ JNC SeekOK ; Already on correct cylinder
+ MOV Floppy.State,Seek ; Next state is Seek
+ call GetDrivePtr
+ call SetTimer2 ; set sanity timer
+ RET ; Done until interrupt on seek done
+
+
+
+;* Floppy state Recal
+;
+; If error, set state is Error. Else, load drive
+; specs into controller and advance to Select state.
+
+FlExRecal:
+ CALL Sense765
+ OR AX,AX ; Error in recal?
+ JNZ SeekErr ; Yes
+RecalOK:
+ CALL Spec765 ; Load drive specs
+ MOV Floppy.State,Select ; Back to select state now
+flexj2: JMP flexj1
+
+
+
+;* Floppy state Seek
+;
+; If error, advance to Error state. Otherwise, wait
+; for head to settle and advance to Settle state.
+
+FlExSeek:
+ CALL Sense765 ; Get status of seek
+ OR AX,AX ; Any error?
+ JZ SeekOK ; No
+SeekErr:
+ CALL GetDrivePtr
+ OR [BX].DrvFlag,Frestor ; flag restore needed
+ MOV Floppy.State,Error ; Yes, next state is Error
+ or Floppy.ST1,8 ; indicate seek error in an unused bit
+ JMP flexj2
+
+SeekOK:
+ MOV Floppy.State,Settle ; Next state is Settle
+ MOV AL,DelaySettle
+ CALL GetFloppyParam ; Get the settle time in Msecs
+ xor ah,ah
+ CALL SetTimer1 ; Set the timer
+ JNC flexj2
+ RET
+
+
+
+;* Floppy state Settle
+;
+; Start the read/write request and advance to the RdWri state.
+
+FlExSettle:
+ MOV Floppy.State,RdWri ; Advance to read/write state
+ CALL RdWr765 ; Start the I/O
+ call GetDrivePtr
+ call SetTimer2 ; set sanity timer
+ RET ; Done until floppy interrupt
+
+
+
+;* Floppy state RdWri
+;
+; If error, next state is Error. Otherwise next state is Done.
+
+FlExRdWri:
+ CALL Fini765 ; Get status of I/O
+ OR AX,AX ; Any error?
+ JZ RdWriOK ; No
+ MOV Floppy.State,Error ; Yes, go to error state
+ JMP flexj2
+
+RdWriOK:
+ MOV Floppy.State,Done ; I/O is done
+flexj3: JMP flexj2
+
+
+
+;* Floppy state Done
+;
+; If whole request is now complete, mark the request
+; as done and then start the next one if there is one. If the request is not
+; yet done, adjust values to show the amount of the request done and then go
+; back to the Calc state to do next part.
+
+FlExDone:
+ MOV AL,Floppy.Flags
+ AND AL,Fwrite+Fverify+Fwrap1 ; Only interested in these bits
+ CMP AL,Fwrap1 ; Just read into scratch?
+ JNE DoneNotWrap ; No
+ PUSH DS
+ PUSH ES
+ MOV CX,Floppy.NumBytes ; CS = # bytes to write from scr
+ LES DI,Floppy.RealAddr ; ES:DI = real buffer
+ LDS SI,Floppy.Addr ; DS:SI = scratch buffer
+ CLD
+ REP MOVSB ; Copy into real buffer
+ POP ES
+ POP DS
+DoneNotWrap:
+ AND AL,Fwrite+Fverify ; Just want to see these bits
+ CMP AL,Fwrite+Fverify ; Just do write part of write+verify?
+ JNE DoneNotWritePart ; No
+ AND Floppy.Flags,NOT Fwrite ; Yes, do verify next
+ mov Floppy.State,Settle ; don't need to calc or seek
+ jmp flexj3
+
+DoneNotWritePart:
+ CMP AL,Fverify ; Just do verify part of write+verify?
+ JNE DoneNotVerify ; No
+ OR Floppy.Flags,Fwrite ; Yes, flip write back up for next
+DoneNotVerify:
+ MOV AX,Floppy.NumSectors ; AX = # of sectors we did
+ SUB Floppy.Count,AX ; Adjust count to number left
+ JZ flxd3 ; Request is done, tell DOS
+ ADD Floppy.First,AX ; Advance sector number
+ MOV AX,Floppy.NumBytes ; Number of bytes handled
+ ADD WORD PTR Floppy.RealAddr,AX ; Advance data address
+ MOV Floppy.State,Calc ; Go to Calc state
+flexj4: JMP flexj3
+
+flxd3:
+ mov di,OFFSET Floppy
+ mov SI,OFFSET FloppyQueue ; DS:SI = head of floppy queue
+ call DoneRequest
+ JMP flexj4
+
+
+;* Floppy state Idle
+;
+; Nothing hapenning except possible motor off timeout.
+
+FlExIdle:
+ call GetDrivePtr
+ CALL SetTimer2 ; Set the motor timer
+ and Floppy.Flags,NOT Factive
+ SemSig SwapSem2 ; someone waiting to switch drive?
+ RET
+
+
+;* Floppy state Error
+;
+; If error count not exceeded, restore the drive and start
+; the request over again. Otherwise set error in the packet and
+; advance to the Done state.
+
+FlExError:
+ CALL Rst765 ; Reset the controller
+ CMP Floppy.ErrCnt,ErrLim ; Reach error limit?
+ JAE FloppyFails ; Yes, request fails
+ INC Floppy.ErrCnt ; We are doing another try
+ MOV Floppy.State,Start ; Restart the request
+ JMP flexj4 ; Back to state machine loop
+
+FloppyFails:
+ call GetDrivePtr
+ OR CS:[BX].DrvFlag,Frestor ; Set drive needs a restore
+ MOV Floppy.State,Done ; Request is done
+; Set error bits in request packet
+ MOV AX, WORD PTR Floppy.ST0 ; Get ST0, ST1
+ mov BL,2 ; Drive not ready?
+ test AL,0cH
+ jne ErrorFound
+ MOV BL,6 ; Bad seek?
+ TEST AH,8
+ JNE ErrorFound
+ MOV BL,4 ; CRC error?
+ TEST AH,30H
+ JNE ErrorFound
+ MOV BL,8 ; Sector not found?
+ TEST AH,85H
+ JNE ErrorFound
+ MOV BL,0 ; Write protect?
+ TEST AH,2
+ JNE ErrorFound
+ MOV BL,12 ; Catch-all error
+ErrorFound:
+ debug 4,4,,
+ PUSH ES
+ LES DI,FloppyQueue ; Get ptr to request
+ MOV AL,BL
+ MOV AH,10000001B
+ MOV ES:[DI].RqStatus,AX ; Set error and code
+ POP ES
+ JMP flxd3 ; Advance to Done state (via shortcut)
+
+FloppyExecute ENDP
+
+
+ ASSUME CS:BiosSeg,DS:NOTHING,ES:NOTHING
+
+FloppyInterrupt PROC FAR
+ debug 4,8,,<>
+ cmp SemInt13,0 ; If a direct Int13 request is being
+ jz flinot13 ; made call the ROM floppy interrupt
+ cmp SemDiskIO,0 ; routine to handle it.
+ jnz flinot13
+ int int_savregs
+ pushf
+ call dword ptr [OldIntEVec]
+ iret
+flinot13:
+ TEST Floppy.Flags,Factive ; device active?
+ JZ flinret ; no, go away
+ INT int_savregs ; save registers
+ CALL FloppyExecute
+flinret: push ax
+ MOV AL,20H ; send EOI to 8259
+ OUT 20H,AL
+ pop ax
+ IRET
+FloppyInterrupt ENDP
+
+SUBTTL Timing routines for floppy disk
+PAGE +
+
+;* Data for timers
+TimerActive DB 0 ; bit flags for active timers
+TimerConv DB 50 ; conversion factor for ms => ticks
+Timer1 DB 0 ; One-shot time till restart intr. rtn.
+Timer2 DB 0 ; Repetitive 1 Hz timer
+Timer2count = 20 ; Reload value for timer2
+
+MOFFDELAY= 2 ; turn off motor after 2 sec. inactivity
+
+;*** SetTimer1 - Arm timer 1
+;
+; SetTimer1 will arm the Timer1. Input parameter
+; values in milliseconds will be converted to timer
+; ticks.
+;
+; ENTRY AX = delay value in milliseconds
+; EXIT AL = timer ticks
+; CF set if timer armed
+; CF clear if zero count passed
+; USES AX
+
+SetTimer1 PROC
+ TEST AX,AX ; zero count?
+ JNZ sett10 ; no
+ CLC
+ RET
+
+sett10: DIV TimerConv
+ TEST AH,AH ; remainder?
+ JZ sett11
+ INC AL ; yes, round up
+sett11: MOV Timer1,AL
+ OR TimerActive,1
+ debug 4,8,,
+ STC
+ RET
+SetTimer1 ENDP
+
+;*** SetTimer2 - Arm timer 2
+;
+; SetTimer2 will set a motor off timeout for the
+; drive whose parameter block is pointed to by
+; CS:BX
+;
+; ENTRY CS:BX = pointer to per drive info.
+; EXIT
+; USES NONE
+
+SetTimer2 PROC
+ TEST TimerActive,2
+ JNZ sett21
+ MOV Timer2,Timer2Count
+ OR TimerActive,2
+sett21: MOV CS:[BX].Timer,MOFFDELAY
+ debug 4,8,,<>
+ RET
+SetTimer2 ENDP
+
+
+
+; FloppyTimer is called every scheduler tick to perform
+; time related services for the floppy driver. There are
+; two services performed; rescheduling of interrupt time
+; service after a head load or motor startup delay, and
+; a motor turn off service when a drive is not active.
+;
+; It's assumed that all registers have been saved by the
+; caller.
+
+ ASSUME CS:BiosSeg,DS:NOTHING,ES:NOTHING
+
+ PUBLIC FloppyTimer
+FloppyTimer PROC FAR
+ TEST TimerActive,0ffH ; any timers active?
+ JNZ fltim1 ; yes
+ RET ; no, return quickly
+fltim1: TEST TimerActive,1 ; Timer1 active?
+ JZ fltim3 ; no
+ DEC Timer1 ; Timer1 expired?
+ JNZ fltim3 ; no
+;* Perform Timer1 service
+ debug 4,8,,<>
+ AND TimerActive,NOT 1
+ CALL FloppyExecute ; push the states around a while
+ RET ; don't do Timer2 service this time.
+
+fltim3: TEST TimerActive,2 ; Timer2 active?
+ JZ fltim4 ; no
+ DEC Timer2 ; 1 Hz clock time?
+ JZ fltim5 ; no
+fltim4: JMP fltim9
+fltim5:
+ debug 4,8,,<>
+ MOV BL,Timer2count ; reload the counter
+ MOV Timer2,BL
+
+;* Perform Timer2 service
+ XOR CH,CH ; No active timeouts seen
+ XOR DI,DI ; Start with drive A
+TimeOutLoop:
+ MOV BX,DI
+ ADD BX,BX
+ MOV BX,FDinfo[BX] ; Get ptr to drive info
+ TEST CS:[BX].DrvFlag,Fmotoron ; motor on?
+ JZ fltim8 ; no
+ CMP CS:[BX].Timer,0 ; Is timer active for drive?
+ JZ fltim8 ; No
+ DEC CS:[BX].Timer ; Yes, another tick has passed
+ JNZ fltim7
+ cmp di,Floppy.Current ; Current drive?
+ jnz fltim6 ; no
+ test Floppy.Flags,Factive ; device active?
+ jz fltim6 ; no, go ahead
+ mov Floppy.State,Error
+ mov Floppy.ErrCnt,ErrLim ; don't retry this one
+ mov Floppy.ST0,048H ; set not ready error
+ call FloppyExecute ; oops, sanity timeout
+ jmp fltim9
+fltim6:
+ AND CS:[BX].DrvFlag,NOT Fmotoron ; stop drive motor
+ MOV AX,DI
+ MOV CL,AL
+ ADD CL,4
+ MOV AL,1
+ SHL AL,CL ; Get bit mask for motor on
+ TEST Floppy.DOR,AL ; Is motor already off?
+ JE fltim8 ; Yes, go on to next drive
+ NOT AL ; Get all bits except this motor
+ AND Floppy.DOR,AL ; Clear this motor on
+ MOV DX,FD_PSEL
+ MOV AL,Floppy.DOR
+ OUT DX,AL ; Turn off motor
+;; cmp di,Floppy.Current ; Current drive?
+;; jnz fltim8 ; no
+;; test Floppy.Flags,Factive ; device active
+;; jz fltim8 ; no, go on to next drive
+;; call DumpRegs ; oops, sanity timeout
+
+fltim7: INC CH ; Flag still active
+fltim8: INC DI ; Advance to next drive
+ CMP DI,WORD PTR NumFloppy ; Any more to check?
+ JNE TimeOutLoop ; Yes, do them
+ OR CH,CH ; Need to keep timer active?
+ JNZ fltim9 ; Yes
+ AND TimerActive,NOT 2 ; No, clear timeout is active
+fltim9: RET
+
+FloppyTimer ENDP
+
+
+IFDEF DEBUGFLG
+DumpRegs PROC
+ push cs
+ pop ds
+ debug 4,0fh,,<>
+ mov di,OFFSET Floppy
+ debug 4,0fh,,<[di],[di.2],[di.4],[di.6],[di.8],[di.10],[di.12],[di.14]>
+ debug 4,0fh,< $x $x $x $x $x $x $x $x\n>,<[di.10h],[di.12h],[di.14h],[di.16h],[di.18h],[di.1ah],[di.1ch],[di.1eh]>
+ call GetDrivePtr
+ debug 4,0fh,,<[bx],[bx.2],[bx.4],[bx.6],[bx.8],[bx.10],[bx.12],[bx.14]>
+ debug 4,0fh,< $x $x $x $x\n>,<[bx.16],[bx.18],[bx.20],[bx.22]>
+ debug 4,0fh,< IMR IRR ISR 8259 status\n>,<>
+ mov al,0ah
+ out 20h,al
+ in al,20h
+ mov bl,al
+
+ mov al,0bh
+ out 20h,al
+ in al,20h
+ mov cl,al
+ in al,21h
+ debug 4,0fh,< $b $b $b\n>,
+ debug 4,0fh,<765 status, data\n>,<>
+ mov dx,FD_PSTAT
+ in al,dx
+ mov bl,al
+ mov dx,FD_PDAT
+ in al,dx
+ debug 4,0fh,< $b $b\n>,
+ sti
+dmpr0: jmp dmpr0
+DumpRegs ENDP
+ENDIF ;DEUBGFLAG
+
+SUBTTL Routines shared between Floppy and Hard disk drivers
+PAGE +
+
+;*** Setup - Set request parameters into local structure.
+;
+; Setup sets the Unit, First, Addr, Count and Flags fields in the
+; device structure which are used to drive the I/O. The following
+; flags are affected:
+; Fwrite This is a write request, not a read
+; Fverify This is a write with verify (verify when write
+; is cleared).
+; Other fields are copied from the DOS request packet.
+;
+; ENTRY SI Pointer to device variables
+; ES:BX Current request
+; AL Unit number
+; DI BPB for drive
+; DS CS
+;
+; EXIT The following variables are set
+; [SI].Unit
+; [SI].First The hidden sectors are added
+; [SI].RealAddr
+; [SI].Count
+; [SI].Flags
+
+ ASSUME CS:BiosSeg,DS:BiosSeg
+
+Setup PROC
+ MOV AX,ES:[BX].RqCount
+ MOV [SI].Count,AX ; Set number of sectors to do
+ MOV AX,ES:[BX].RqAddr
+ MOV WORD PTR [SI].RealAddr,AX
+ MOV AX,ES:[BX].RqAddr+2
+ MOV WORD PTR [SI].RealAddr+2,AX ; Copy data address
+ MOV AL,ES:[BX].RqUnit ; Get unit number
+ MOV [SI].Unit,AL ; Set drive needed
+ MOV AX,ES:[BX].RqFirst ; Get the starting sector number
+ ADD AX,[DI].BPBhidsec ; Add # of hidden sectors
+ MOV [SI].First,AX ; Set 1st sector of I/O
+ and [SI].Flags,Factive+F2step ; mask excess flags
+ CMP ES:[BX].RqCmd,4 ; Is this a read?
+ JE SetupDone ; Yes, all done
+ OR [SI].Flags,Fwrite ; No, flag this is a read
+ CMP ES:[BX].RqCmd,9 ; Write with verify?
+ JNE SetupDone ; No, just write
+ OR [SI].Flags,Fverify ; Yes, set to verify too
+SetupDone:
+ RET
+Setup ENDP
+
+
+;*** MapSector - compute head, sector, cylinder
+;
+; MapSector takes the fields set up by Setup and figures out the
+; head, cylinder and sector involved. If the request involves
+; multiple sectors, it figures out how many can be done at once
+; based on the number of sectors left on the track and that the
+; target address' offset does not wrap around 64k (the DMA on the
+; PC uses a 20 bit address, but the high 4 bits do not change when
+; the low 16 cycle back to 0). If the request wraps around 64k, it
+; is split into 2 or 3 pieces which are all data before wrap, after
+; wrap and the wrap itself. The wrap itself is transferred via a temp
+; buffer (ScratchBuffer).
+;
+; ENTRY SI Pointer to device variables
+; ES:BX Current request
+; AL Unit number
+; DI BPB for drive
+; DS CS
+; EXIT The following variables are set
+; [SI].Flags
+; [SI].Head
+; [SI].Cyl
+; [SI].Sector
+; [SI].NumSectors
+; [SI].NumBytes
+; [SI].Addr
+; USES AX,CX,DX,DI
+;
+
+MapSector PROC
+ PUSH ES
+ les CX,[SI].RealAddr
+ MOV WORD PTR [SI].Addr,CX ; copy RealAddr to Addr
+ MOV WORD PTR [SI].Addr+2,ES
+ AND [SI].Flags,NOT Fwrap1 ; Clear buffer wrap flag
+
+; Calculate the head, cylinder and sector of the start of the request
+; from [SI].First
+ POP ES
+ MOV AX,[SI].First
+ XOR DX,DX
+ DIV [DI].BPBtrksiz ; Divide by sectors/track
+;; INC DL
+ MOV [SI].Sector,DL ; Set sector to start at
+ XOR DX,DX
+ DIV [DI].BPBnhead ; Divide by number of heads
+ MOV [SI].Head,DL ; Set head number
+ MOV [SI].Cyl,AX ; Set cylinder number
+ debug 8,4,,>
+;
+; Now see how many sectors of request can be done. The floppy
+; controller will not advance tracks, but will allow reading or
+; writing the remaining sectors on the track.
+;
+ MOV AX,[DI].BPBtrksiz
+ SUB AL,[SI].Sector ; AL = # of sectors left on
+ ; track after desired.
+ XOR AH,AH
+;; inc ax
+ CMP AX,[SI].Count ; Is whole request on this cyl?
+ JB maps2 ; No, can only do what is left
+ MOV AX,[SI].Count ; Yes, use the actual # wanted
+maps2:
+ MOV [SI].Numsectors,AX ; Set number to do this time
+;
+; Now have to normalize offset (add in paragraph) and then see if adding
+; [SI].Numsectors causes overflow. If it does, DMA will trash memory, so
+; decrement Numsectors and loop.
+;
+ MOV AX,WORD PTR([SI].Addr+2)
+ MOV CL,4
+ SHL AX,CL ; Convert para to offset
+ ADD AX,WORD PTR [SI].Addr ; Add in offset
+ MOV CX,AX ; Save offset of buffer
+maps4:
+ MOV AX,[DI].BPBsecsiz
+ MUL [SI].NumSectors ; Get # bytes in transfer
+ MOV [SI].NumBytes,AX ; Set # bytes involved
+ ADD AX,CX ; Get final offset
+ JAE maps6 ; No overflow, DMA will be ok
+ OR [SI].Flags,Fwrap2 ; Flag we will be using scratch
+ DEC [SI].NumSectors ; Overflow, try using one less
+ JNZ maps4
+;
+; If we got here, no sectors can be transferred before the 64K
+; boundary. One sector must be transferred through a scratch buffer.
+;
+ debug 12,10h,,
+ INC [SI].NumSectors ; Doing 1 sector of I/O
+ OR [SI].Flags,Fwrap1 ; Flag we are using scratch
+ MOV AX,CS
+ MOV DI,OFFSET ScratchBuffer
+ MOV WORD PTR([SI].Addr),DI
+ MOV WORD PTR([SI].Addr+2),AX ; Change buffer to scratch
+ TEST [SI].Flags,Fwrite ; Doing a write?
+ JE maps6 ; No, All done
+ PUSH ES
+ PUSH DS
+ PUSH SI
+ MOV ES,AX ; ES:DI = scratch buffer
+ mov cx,[SI].NumBytes
+ LDS SI,[SI].RealAddr ; DS:SI = Data buffer
+ CLD
+REP MOVSB ; Copy the write buffer
+ POP SI
+ POP DS
+ POP ES
+maps6:
+ RET
+MapSector ENDP
+
+
+
+
+;*** DMAsetup - Set the DMA channel up to do the I/O
+;
+; ENTRY AL = DMA mode
+; AH = DMA channel number (2 or 3 only)
+; SI = pointer to device parameters
+; USES AX,CX,DX
+;
+
+DMAsetup PROC
+ PUSH AX
+ XCHG AH,AL
+ OR AL,4
+ OUT PDMA+10,AL ; set channel's mask bit
+ OUT PDMA+12,AL ; clear byte pointer F/F
+ pop ax
+ push ax ; restore AH, AL
+ OR AL,AH ; add channel number to command
+ OUT PDMA+11,AL ; Set DMA mode
+ MOV DX,PDMA
+ ROL AH,1
+ ADD DL,AH
+ MOV AX,WORD PTR [SI].Addr+2 ; Get segment of addr
+ MOV CL,4
+ ROL AX,CL ; Convert para to bytes
+ MOV CH,AL ; CH = 4 bits ROLed around
+ AND AL,0F0H ; Lose high bits rotated around
+ ADD AX,WORD PTR [SI].Addr ; Add in offset value
+ ADC CH,0 ; Add in any carry
+ OUT DX,AL ; Output low byte of address
+ MOV AL,AH
+ OUT DX,AL ; Output high byte of address
+ inc dx ; address `word' count register
+ MOV AX,[SI].NumBytes ; # bytes in request
+ dec ax
+ OUT DX,AL
+ MOV AL,AH
+ OUT DX,AL ; Tell DMA how many bytes
+ pop ax ; get back channel number
+ mov dl,PDMAX
+ add dl,ah
+ MOV AL,CH
+ AND AL,0FH ; Only 4 bits are good
+ OUT DX,AL ; Output highest 4 bits of address
+ MOV AL,AH ; Channel to start
+ OUT PDMA+10,AL ; Clear channel's mask bit
+ RET
+DMAsetup ENDP
+
+;*** DoneRequest - Mark a request complete, setup to start next one
+;
+; DoneRequest does common processing needed when a request
+; has been completed. It will reset the device state,
+; dequeue the request, mark it complete, restart the
+; process and restart any process waiting on ScratchBuffer
+; if this request had reserved it.
+;
+; ENTRY SI Pointer to head of queue
+; DI Pointer to device information
+; EXIT ES:BX Next request
+; USES AX,BX,DX,BP,ES
+
+
+DoneRequest PROC
+ push cs
+ pop ds
+ ASSUME ds:BiosSeg
+ MOV [DI].ErrCnt,0 ; Reset error count
+ MOV [DI].State,Idle ; Assume will be idle
+ MOV DX,PullRequest
+ CALL DosFunction ; Pull the current request out
+ JZ dnrq2 ; Nothing really completed
+ MOV AX,[DI].Count ; Get I/O left to do
+ SUB ES:[BX].RqCount,AX ; Adjust requested count by residual
+ OR ES:[BX].RqStatus,0100h ; set done bit
+ MOV AX,ES ; AX:BX = Request completed
+ MOV DX,ContinueProcess
+ CALL DosFunction ; Make process run again
+ CMP WORD PTR [SI]+2,0 ; Is there another request to do?
+ JZ dnrq2 ; No, let device shut down
+ MOV [DI].State,Start ; Yes, start up next request
+dnrq2:
+ test [DI].Flags,Fwrap2 ; had this request used ScratchBuffer?
+ jz dnrq4 ; no
+ SemSig ScratchBufSem ; let anyone waiting proceed
+ and [DI].Flags,NOT Fwrap2
+dnrq4: ; If both the fixed and floppy drivers
+ push bx ; are idle, reset the busy flag and
+ cmp Floppy.State,Idle ; continue any processes that were
+ jne dnrq5 ; waiting for it.
+ cmp Fixed.State,Idle
+ jne dnrq5
+ mov SemDiskIO,0
+ mov ax,ds
+ mov bx,offset SemDiskIO
+ mov dx,ContinueProcess
+ call DosFunction
+dnrq5:
+ pop bx
+ ret
+DoneRequest ENDP
+
+
+; FDGetBPB returns a pointer to the floppy disk BPB for the
+; selected media byte. The BPB contains various drive parameters
+; such as physical disk dimensions and the size of FATs and the
+; root directory.
+;
+; Input: AH = Media byte
+; AL = Drive number
+; Destroys: None
+; Output: CS:DI = Pointer to BPB
+
+ ASSUME DS:NOTHING,ES:NOTHING
+
+FDGetBPB PROC
+
+ PUSH AX
+ PUSH BX
+ PUSH CX
+ PUSH DX ; Save regs
+ MOV CL,AH ; Copy media value
+ AND CL,0F8H ; Look at just top 5 bits
+ CMP CL,0F8H ; Valid media byte?
+ JE BPBGood ; Yes
+ MOV AH,0FEH ; No, make it 8 sector 1 sided
+BPBgood:
+ MOV BL,AL ; Get pointer to per drive info.
+ XOR BH,BH
+ ADD BX,BX
+ MOV DI,CS:FDinfo[BX]
+ CMP AH,CS:[DI].BPBmediab ; already set?
+ JE BPBdone ; yes, don't bother rebuilding
+ MOV AL,1 ; Assume will have 1 FAT sector
+ MOV BX,64*256+8 ; Assume # dir = 64, 8 sector
+ MOV CX,40*8 ; Assume 320 sectors/disk
+ MOV DX,1*256+1 ; Assume 1 head, 1 sector/allocate
+ TEST AH,2 ; Is drive 8 or 9 sector?
+ JNZ BPBKnowSectors ; It's 8, we assumed right
+ INC AL ; 9 sector, incr # of FAT sectors
+ INC BL ; Set we have 9 sectors/cylinder
+ ADD CX,40 ; Increase size to 360 sectors
+BPBKnowSectors:
+ TEST AH,1 ; Is disk double sided?
+ JE BPBKnowHeads ; No, we guessed right
+ ADD CX,CX ; Double size of disk
+ MOV BH,112 ; Increase # of directory entries
+ INC DH ; Set 2 sectors/allocation unit
+ INC DL ; Set 2 heads
+BPBKnowHeads:
+ MOV CS:[DI].BPBsecpau,DH ; Set sectors/allocation unit
+ MOV BYTE PTR CS:[DI].BPBndir,BH ; Set # of directory entries
+ MOV CS:[DI].BPBnsec,CX ; Set size of disk in sectors
+ MOV CS:[DI].BPBmediab,AH ; Set media byte
+ MOV BYTE PTR CS:[DI].BPBnfatsec,AL ; Set number of FAT sectors
+ MOV BYTE PTR CS:[DI].BPBtrksiz,BL ; Set sectors/track
+ MOV BYTE PTR CS:[DI].BPBnhead,DL ; Set # of heads
+BPBdone:
+ POP DX
+ POP CX
+ POP BX
+ POP AX
+ RET
+FDGetBPB ENDP
+
+
+; HDGetBPB returns a pointer to the hard disk BPB for the
+; selected unit. The BPB contains various drive parameters
+; such as physical disk dimensions and the size of FATs and the
+; root directory.
+;
+; Input: AL = Drive number
+; Destroys: None
+; Output: CS:DI = Pointer to BPB
+
+ ASSUME DS:NOTHING,ES:NOTHING
+
+HDGetBPB PROC
+ PUSH BX
+ MOV BL,AL ; Get pointer to per drive info.
+ XOR BH,BH
+ ADD BX,BX
+ MOV DI,CS:HDinfo[BX]
+ POP BX
+ RET
+HDGetBPB ENDP
+
+
+ ASSUME DS:NOTHING,ES:NOTHING
+
+BlockIfLocked Proc Near ; Block the current process if it has
+ pushf ; been locked out by an Int 13 request.
+bifl1: cli ; Otherwise, set the busy flag to block
+ cmp SemInt13,0 ; out Int 13 requests.
+ jz bifl2
+ push dx
+ push cx
+ push bx
+ push ax
+ mov ax,cs
+ mov bx,offset SemInt13
+ xor cx,cx
+ mov dx,BlockProcess
+ call DosFunction
+ pop ax
+ pop bx
+ pop cx
+ pop dx
+ jmp bifl1
+bifl2:
+ mov SemDiskIO,1
+ popf
+ ret
+BlockIfLocked endp
+
+SUBTTL Routines that interface to hard disk controller
+PAGE +
+
+;*** HDCommand - send a command to the hard disk controller
+;
+; HDCommand will send the previously set up command block
+; to the hard disk controller.
+;
+; ENTRY AL = value to be put in interrupt/DMA mask
+; EXIT AL = status port value
+; USES AX,CX,DX,SI
+
+HDCommand PROC
+ mov dx,HD_PSEL ; point to select port
+ out dx,al
+;; mov cx,10 ;BUGBUG - timing prob. w/ expansion box?
+;;hdcom0: loop hdcom0 ;BUGBUG - timing prob. w/ expansion box?
+ inc dx ; point to mask port
+ out dx,al
+ mov dx,HD_PSTAT
+hdcom1: in al,dx ; get status
+ and al,0FH
+ cmp al,0DH ; test for busy, command/data, request
+ jnz hdcom1
+ mov si,OFFSET Fixed.DCB
+ mov cx,6
+ cld
+ dec dx ; point to data port
+hdcom2: lodsb
+ out dx,al
+ loop hdcom2
+ inc dx
+;; mov cx,10 ;BUGBUG - timing prob. w/ expansion box?
+;;hdcom3: loop hdcom3 ;BUGBUG - timing prob. w/ expansion box?
+ in al,dx
+ ret
+HDCommand ENDP
+
+;*** HDWaitReq - wait for request bit in status register
+;
+; HDWaitReq will pause until the request bit in the hard disk
+; status register is set.
+;
+; ENTRY
+; EXIT AL = status byte
+; USES AX,DX
+
+HDWaitReq PROC
+ mov dx,HD_PSTAT
+ in al,dx
+ test al,01h ; request bit?
+ jz HDWaitReq
+ ret
+HDWaitReq ENDP
+SUBTTL Routines that interface to floppy disk controller
+PAGE +
+
+;*** GetDrivePtr - compute ptr to per drive info.
+;
+; GetDrivePtr returns a pointer to the per-drive information
+; for the current drive. Should not be called before the
+; current drive is set up by Sel765 in state CALC.
+;
+; EXIT BX = pointer to per drive table
+; USES BX
+
+GetDrivePtr PROC
+ mov bx,cs:Floppy.Current
+ add bx,bx
+ mov bx,cs:FDinfo[bx]
+ ret
+GetDrivePtr ENDP
+
+
+; GetFloppyParam is called to get a disk parameter from the parameter
+; block set up by the BIOS. This block allows disk parameters to be changed
+; from the standard.
+;
+; Input: AL = parameter desired (see FloppyParam structure)
+; Destroys: AX
+; Output: AL = parameter byte desired
+
+GetFloppyParam PROC
+ PUSH DS
+ PUSH BX
+ XOR AH,AH
+ MOV BX,AX
+ XOR AX,AX
+ MOV DS,AX ; Point to INT area
+ LDS AX,DWORD PTR DS:(4*1EH) ; Get pointer to param block
+ ADD BX,AX ; Add in block offset
+ MOV AL,[BX]
+ POP BX
+ POP DS
+ RET
+GetFloppyParam ENDP
+
+
+
+; Recalibrate the current drive. Clear Restore flag, set cylinder to
+; unknown and issue command to controller.
+;
+; Destroys: AX,BX,DX
+;
+
+Rcl765 PROC
+ AND CS:[BX].DrvFlag,NOT Frestor ; Have restored drive
+ MOV CS:[BX].CurCyl,-1 ; Flag don't know where we are
+ MOV AL,FD_CRESET
+ CALL Put765 ; Put out reset command
+ MOV AX,Floppy.Current ; Get current drive
+ CALL Put765 ; Tell controller which drive
+ RET
+Rcl765 ENDP
+
+
+; Reset the controller.
+;
+; Destroys: AX,CX,DX
+;
+
+Rst765 PROC
+ MOV AL,CS:Floppy.DOR
+ AND AL,NOT(DORmask)
+ MOV DX,FD_PSEL
+ OUT DX,AL
+ MOV CX,10000
+RstDelayLoop:
+ loop RstDelayLoop
+ OR AL,DORmask
+ MOV CS:Floppy.DOR,AL ; Update value
+ OUT DX,AL
+ RET
+Rst765 ENDP
+
+
+; Load the drive specs into the controller.
+;
+; Destroys: AX,DX
+;
+
+Spec765 PROC
+ MOV AL,FD_CSPEC
+ CALL Put765
+ MOV AL,Spec1
+ CALL GetFloppyParam
+ CALL Put765
+ MOV AL,Spec2
+ CALL GetFloppyParam
+ CALL Put765
+ RET
+Spec765 ENDP
+
+
+; Get the interrupt status from the controller and into AX
+;
+; Destroys: AX,CX,DX
+;
+
+Sense765 PROC
+ MOV AL,FD_CSENSE ; Get status
+ CALL Put765
+ CALL Get765 ; Read ST0
+ PUSH AX ; Save status
+ CALL Get765 ; Read PCN (present cylinder number)
+ POP AX ; Restore status
+ MOV CL,6
+ SHR AL,CL ; Shift bits down
+ AND AX,3 ; Leave only error bits
+ RET
+Sense765 ENDP
+
+
+; Select the current drive. Return carry set if must wait until drive is
+; ready. FloppyExecute will be called again when the drive is ready. The
+; code must wait either for a motor start or head load delay, otherwise it
+; returns with carry clear.
+;
+; Destroys: AX,BX,CX,DX
+;
+
+Sel765 PROC
+ MOV DX,FD_PSEL ; set DX = Digital Output Register
+ MOV CL,Floppy.Unit ; Get unit we want to use
+ XOR CH,CH ; CX = wanted unit
+ CMP Single,0 ; Single drive system?
+ JE Sel765Double ; No, Unit is accurate
+ MOV CL,CH ; Yes, there is only drive 0
+Sel765Double:
+ CMP CX,Floppy.Current ; Wanted same as current?
+ MOV Floppy.Current,CX ; Set new current unit
+ JNE SelectUnit ; No, must select new drive
+ ADD CL,4
+ MOV AL,1
+ SHL AL,CL ; AL = Bit for drive's motor on
+ TEST AL,Floppy.DOR ; Is the drive's motor still on?
+ JE SelectUnit ; No, must turn it back on
+ MOV AL,Floppy.DOR
+ OUT DX,AL ; ? For some reason output value again
+ CLC ; Clear carry, don't have to wait
+ RET
+
+SelectUnit:
+ MOV AL,NOT(3) ; Drive select is low 2 bits
+ AND AL,Floppy.DOR ; Lose old select bits
+ OR AL,DORmask
+ MOV CL,BYTE PTR Floppy.Current ; get unit number
+ OR AL,CL ; Put in new select bits
+ MOV Floppy.DOR,AL ; Save new bits
+ ADD CL,4
+ MOV AL,1
+ SHL AL,CL ; Get bit for motor is on
+ TEST AL,Floppy.DOR ; Is drive's motor on?
+ JE SelectStartMotor ; No, must start motor
+ MOV AL,Floppy.DOR
+ OUT DX,AL ; Load the head
+ MOV AX,DelayLoad ; Load head delay
+ CALL SetTimer1
+ RET
+
+SelectStartMotor:
+ OR Floppy.DOR,AL ; Add in motor start bit
+ MOV AL,Floppy.DOR
+ OUT DX,AL ; Start the motor
+ MOV AL,DelayMotor
+ CALL GetFloppyParam ; Get the proper delay time in 1/8 sec
+ mov cl,125
+ mul cl ; convert to milliseconds
+ CALL SetTimer1 ; Set timer for motor startup
+ RET
+Sel765 ENDP
+
+
+; Seek to the correct cylinder. Set carry if have to wait for operation
+; to complete (we are not on right cylinder).
+;
+; Destroys: AX,BX,DX
+;
+
+Seek765 PROC
+ MOV AX,Floppy.Cyl ; Get cylinder wanted
+ CMP AX,CS:[BX].CurCyl ; Already on cylinder?
+ JE SeekDone ; Yes, return with carry clear
+ MOV CS:[BX].CurCyl,AX ; Set the new current cylinder
+ MOV AL,FD_CSEEK
+ CALL Put765 ; Seek command
+ MOV AL,Floppy.Head ; Get head desired
+ SHL AL,1
+ SHL AL,1 ; Move head # 2 bits left
+ ADD AL,BYTE PTR Floppy.Current ; Low 2 bits are unit (hhuu)
+ CALL Put765 ; Put out drive and head select
+ MOV AX,Floppy.Cyl
+ TEST Floppy.Flags,F2step ; Need to double step?
+ JE SeekNoDouble ; No
+ ADD AX,AX ; Yes, double cylinder number
+SeekNoDouble:
+ CALL Put765 ; Give controller the cylinder
+ STC ; Set carry, must wait for seek intr.
+SeekDone:
+ RET
+Seek765 ENDP
+
+
+
+; Start the Read/write. Set up the DMA channel and give a read or write
+; command to the controller depending on flag.
+;
+; Destroys: AX,CX,DX
+;
+
+RdWr765 PROC
+ mov ah,FD_DMA
+ mov si,OFFSET Floppy
+ TEST Floppy.Flags,Fwrite ; Is this a write?
+ JNE WriteSetup ; Yes
+ MOV AL,DMA_READ ; No, read
+ CALL DMAsetup ; Set up the DMA
+ MOV AL,FD_CREAD ; Want to read
+ JMP SHORT RdWrLoc ; Now put out rest of command
+
+WriteSetup:
+ MOV AL,DMA_WRITE
+ CALL DMAsetup ; Set DMA up for write
+ MOV AL,FD_CWRITE ; Want to write
+RdWrLoc:
+ CALL Put765 ; Put out command
+ MOV AL,Floppy.Head
+ ADD AL,AL
+ ADD AL,AL ; Form HHxx Binary
+ ADD AL,BYTE PTR Floppy.Current ; Form HHUU
+ CALL Put765 ; Output unit and head
+ MOV AX,Floppy.Cyl
+ CALL Put765 ; Output cylinder
+ MOV AL,Floppy.Head
+ CALL Put765 ; Output head again?
+ MOV AL,Floppy.Sector
+ inc al
+ CALL Put765 ; Output sector
+ MOV AL,SectorSize
+ CALL GetFloppyParam ; Get sector size code
+ CALL Put765 ; Tell controller sector size
+ MOV AL,CylSize
+ CALL GetFloppyParam ; Get number of sectors/cylinder
+ CALL Put765 ; Tell controller
+ MOV AL,DataGap ; Gap length for read/write
+ CALL GetFloppyParam
+ CALL Put765 ; Tell controller gap length
+ MOV AL,ValueDTL
+ CALL GetFloppyParam ; Get value for DTL
+ CALL Put765 ; Since bytes/sector#0, this is a
+ ; meaningless value, but controller
+ ; wants to see something
+ RET
+RdWr765 ENDP
+
+
+
+; Fini765 gets the completion status.
+;
+; Destroys: AX,CX,DX
+; Returns: AL
+;
+
+Fini765 PROC
+ push es
+ push di
+ push cs
+ pop es
+ mov di,OFFSET Floppy.ST0
+ MOV CX,7
+fini1: CALL Get765
+ stosb
+ loop fini1
+ mov al,Floppy.ST0
+ mov cl,6
+ SHR AL,CL
+ AND AX,3 ; Mask down to value to return
+ pop di
+ pop es
+ RET
+Fini765 ENDP
+
+
+
+; Put765 writes a command to the controller.
+;
+; Input: AL = value
+; Destroys: AX,DX
+;
+
+Put765 PROC
+ PUSH AX ; Save the value to write
+PutWaitLoop:
+ MOV DX,FD_PSTAT
+ IN AL,DX ; Get status
+ AND AL,FD_SDIO+FD_SRQM
+ CMP AL,FD_SRQM ; Controller ready for data?
+ JNE PutWaitLoop ; No, keep waiting
+ POP AX ; Get value back
+ MOV DX,FD_PDAT
+ OUT DX,AL ; Put out value
+ RET
+Put765 ENDP
+
+
+; Get765 gets a value back from the controller into AL.
+;
+; Destroys: AX,DX
+; Returns: AL
+;
+
+Get765 PROC
+ MOV DX,FD_PSTAT
+ IN AL,DX ; Get status
+ AND AL,FD_SDIO+FD_SRQM
+ CMP AL,FD_SDIO+FD_SRQM ; Controller data available?
+ JNE Get765 ; No, wait for it
+ MOV DX,FD_PDAT
+ IN AL,DX ; Get value from controller
+ ret
+Get765 ENDP
+
+Code ENDS
+ END
diff --git a/v4.0-ozzie/bin/DISK2/BIOS/IBMDSK.OBJ b/v4.0-ozzie/bin/DISK2/BIOS/IBMDSK.OBJ
new file mode 100644
index 0000000..daf953a
Binary files /dev/null and b/v4.0-ozzie/bin/DISK2/BIOS/IBMDSK.OBJ differ
diff --git a/v4.0-ozzie/bin/DISK2/BIOS/IBMMTCON.ASM b/v4.0-ozzie/bin/DISK2/BIOS/IBMMTCON.ASM
new file mode 100644
index 0000000..6cfefbe
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK2/BIOS/IBMMTCON.ASM
@@ -0,0 +1,1424 @@
+ TITLE MTCON - Console device driver for MT-MSDOS
+ page ,132
+
+
+;; TODO -
+;; split CON and KBD
+;; interruptible waits and unwinding
+;; per screen keyboard buffers
+
+;------------------------------------------------------------------------
+; Revision History
+;
+; V1.00 04/10/84 M.A.Ulloa
+; First Implementation: Only one segment used and only
+; one screen in the color card (alpha mode).
+;
+; V1.01 04/15/84 M.A.Ulloa
+; Re-enabled the blocking of writing from processes not
+; with the current screen.
+;
+; V1.02 04/16/84 M.A.Ulloa
+; Increased to 8 the num of screens. Added the screen
+; blanking when reading and writing the screen data
+; (see BLANK switch). Added screen # for writes.
+;
+; V1.03 04/17/84 M.A.Ulloa
+; Corrected problem with flush.
+;
+; V1.05 04/30/84 A.R.Whitney
+; Added conditional compilation to allow linking with
+; resident BIOS.
+;
+; V1.06 05/08/84 A.R.Whitney
+; Added ANSI escape sequences. Conditional on ANSI.
+;
+; V1.07 05/15/84 A.R.Whitney
+; Fixed compatibility problems with Eagle PC Turbo.
+; Fixed BLANK conditional code to allow saving graphics
+; mode screens.
+; Added enable/disable 25th line to Ansi.
+;
+; V1.08 05/22/84 A.R.Whitney
+; Fixed problem with scrolling in screen modes other
+; than 80x25. Bug due to 25th line stuff.
+;
+;------------------------------------------------------------------------
+
+;DEBUGFLG = 1
+
+.xlist
+ include DEFDBUG.INC
+.list
+
+FALSE EQU 0
+TRUE EQU NOT FALSE
+
+CVERS equ 01 ; update version number!!
+CREV equ 08
+
+BLANK equ TRUE ; blank screen during data r/w
+INBIOS equ TRUE ; link with BIOS
+ANSI equ TRUE ; include ANSI escape sequences
+ LINE25 equ TRUE ; special 25th line like VT52
+EAGLE equ TRUE ; Eagle PC ROM botches CRT_LEN
+
+
+subttl Screen Information Block Definition
+page
+
+;------------------------------------------------------------------------
+; Screen Information Block (SIB) Definition
+;
+; This structure contains all information necessary to
+; describe the state of the screen, plus pointers to buffers
+; which contain the actual screen content.
+;
+
+;------------------------------------------------------------------------
+MaxSEG equ 2 ; NOTE: assumption is made in the
+ ; code that all SIB's have same
+ ; number os SEGs
+SEGst struc
+SizeNeeded dw 0 ; needed size for seg, (0 = unused)
+MemFlag dw ? ; maintened by system (0 = in mem)
+MPointer dd ? ; vaild iff MemFlag == 0
+SEGst ends
+
+;------------------------------------------------------------------------
+MaxSIB equ 8 ; maximum number of Screens
+
+
+IF ANSI
+TermSize EQU 20 ; max. size of terminal emulation state
+ENDIF
+
+SIBst struc
+ctlS db 0 ; if the screen is NOT frozen = 0
+ ; NOTE: this field should be the
+ ; FIRST of each SIB !! (see ConWrit)
+OffsetVal dw 7 ; start of Seg Descriptors
+SegCnt dw MaxSeg ; max number of Segments
+SIBlen dw (SIZE SIBst) ; length of the SIB
+;--- Segments
+ db ((SIZE SEGst) * MaxSeg) dup (?)
+;--- PC video state info
+xCRT_MODE DB ?
+xCRT_COLS DW ?
+xCRT_LEN DW ?
+xCRT_START DW ?
+xCURSOR_POSN DW 8 DUP(?)
+xCURSOR_MODE DW ?
+xACTIVE_PAGE DB ?
+xADDR_6845 DW ?
+xCRT_MODE_SET DB ?
+xCRT_PALETTE DB ?
+xTERM_STATE DB TermSize DUP(?)
+SIBst ends
+
+
+subttl Request packet definitions
+page
+
+;------------------------------------------------------------------------
+; Request packet offset definitions
+;
+
+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
+
+
+subttl IBM-PC ROM Data area Locations
+page
+
+;------------------------------------------------------------------------
+; IBM-PC ROM Data area Locations
+;
+
+RomData SEGMENT AT 40H
+ ORG 1AH
+BufferHead DW ?
+BufferTail DW ?
+KeyBuffer DW 16 DUP (?)
+KeyBufLen equ ($-KeyBuffer) ; length of KeyBuffer
+
+ ORG 49H
+CRT_MODE DB ?
+CRT_COLS DW ?
+CRT_LEN DW ?
+CRT_START DW ?
+CURSOR_POSN DW 8 DUP(?)
+CURSOR_MODE DW ?
+ACTIVE_PAGE DB ?
+ADDR_6845 DW ?
+CRT_MODE_SET DB ?
+CRT_PALETTE DB ?
+
+CrtLen EQU ($-CRT_MODE) ; length of screen state area
+RomData ENDS
+
+MonoSc SEGMENT AT 0B000H
+;--- 4k of screen memory
+MonoSc ENDS
+
+ColorSc SEGMENT AT 0B800H
+;--- 16k of screen memory
+ColorSc ENDS
+
+BRKADR equ 006CH ; Break vector address
+
+
+subttl Device Header
+page
+
+
+BiosSeg group Code,BiosInit
+Code Segment byte public 'CODE'
+
+;------------------------------------------------------------------------
+; Device Header
+;
+
+assume cs:Code,ds:NOTHING,es:NOTHING,ss:NOTHING
+
+ PUBLIC CONDEV
+IF INBIOS
+ extrn AUXDEV:FAR
+CONDEV dd AUXDEV
+ELSE
+CONDEV dw 0FFFFh,0FFFFh
+ENDIF ;INBIOS
+;*** should ioctl bit be set for gen ioctl too?
+ dw 1100000000010011b ; console in and out
+ dw Strategy
+ dw Entry
+ db "CON "
+
+
+;------------------------------------------------------------------------
+; Command dispatch table
+;
+
+ComTbl:
+;--- 2.0
+ dw OFFSET BiosSeg:$ConInit ; Initialization function
+ dw StatusComplete ; Media Check
+ dw StatusComplete ; Build BPB
+ dw CmdErr ; IOCTL Input
+ dw $ConRead ; Input (Read)
+ dw $ConRdnd ; Non-Destructive read, no wait
+ dw StatusComplete ; Input Status
+ dw $ConFlsh ; Input Flush
+ dw $ConWrit ; Output (Write)
+ dw $ConWrit ; Output with verify
+ dw StatusComplete ; Output Status
+ dw StatusComplete ; Output Flush
+ dw StatusComplete ; IOCTL Output
+;--- 3.0
+ dw StatusComplete ; Device Open
+ dw StatusComplete ; Device Close
+ dw StatusComplete ; Removable Media
+;--- 4.0
+ dw $GenIOCTL ; Generic IOCTL
+ dw $ConStop ; Pause Device
+ dw $ConStart ; Continue Device
+
+ComTblEnd:
+
+CTSIZE equ (ComTblEnd - ComTbl)/2 ; number of table entries
+
+
+subttl Device Data Area
+page
+
+;------------------------------------------------------------------------
+; Device Data Area
+;
+
+SaveFlg db 0 ; Screen being saved flag, (true = 1)
+IF INBIOS
+ EXTRN DosFunction:DWORD
+ELSE
+DosFunction dd ? ; pointer to dos "helper" functions
+ENDIF ;INBIOS
+AltAH db 0 ; Side buffer for input
+CurrSc dw 0 ; Current screen number
+CurrSIB dw SIB ; offset to the current SIB
+SIB SIBst MaxSIB dup (<>) ; allocate room for SIB's
+
+IF EAGLE
+ScreenLen db 08h ; table of (high byte of) regen. buffer
+ db 08h ; len. Indexed by screen mode.
+ db 10h ; 80x25 text modes
+ db 10h
+ db 40h ; graphics modes
+ db 40h
+ db 40h
+ db 10h ; monochrome
+ENDIF
+
+
+IFDEF DEBUGFLG
+IF INBIOS
+ EXTRN BUGBITS:BYTE,DPRINTF:NEAR
+ELSE
+BUGBITS db 0ffh,0ffh
+ENDIF
+ENDIF
+
+subttl Device Entry Points
+page
+
+;------------------------------------------------------------------------
+; 2.0 Interrupt Routine (Not Used)
+;
+
+EntryP proc far
+Entry: ret
+EntryP endp
+
+
+;------------------------------------------------------------------------
+; 2.0 Strategy Routine, main entry point
+;
+; entry
+; ES:BX points to Request packet
+;
+
+StratP proc far
+
+Strategy:
+IF INBIOS
+ extrn Interrupt:NEAR
+
+ push si
+ mov si,OFFSET CS:ComTbl
+ jmp Interrupt
+ELSE
+ push ax ; save all
+ push cx
+ push dx
+ push si
+ push di
+ push bp
+ push ds
+
+ push es ; DS = ES
+ pop ds
+
+ push es
+ push bx
+ mov al, byte ptr ds:[bx].CMD
+ cmp al,CTSIZE ; Command within range?
+ jae CmdErr ; no must be an error
+ mov cx, word ptr ds:[bx].COUNT
+ les di, dword ptr ds:[bx].TRANS
+ xor ah,ah
+ mov si, offset ComTbl
+ add si,ax
+ add si,ax
+
+ jmp word ptr cs:[si] ; dispatch
+ENDIF ;INBIOS
+
+StratP endp
+
+
+subttl Exit Routines
+page
+
+;------------------------------------------------------------------------
+; Exit Routines, Common to all device functions
+;
+
+IF INBIOS
+ extrn StatusComplete:NEAR,StatusError:NEAR,StatusDevReady:NEAR
+ extrn CmdErr:NEAR
+ELSE
+
+assume ds:NOTHING,es:NOTHING
+
+StatusDevReady:
+ mov ah,00000011b ; device busy
+ jmp short errEx
+
+CmdErr:
+ mov al,3 ; Unknown command Error
+StatusError:
+ mov ah,10000001b
+ jmp short errEx
+
+ExitP proc far
+StatusComplete: mov ah,00000001b
+errEx: pop bx
+ pop es
+
+ mov word ptr es:[bx].STATUS,ax ; put status out
+
+ pop ds
+ pop bp
+ pop di
+ pop si
+ pop dx
+ pop cx
+ pop ax
+ ret
+ExitP endp
+
+ENDIF ;INBIOS
+
+
+subttl Break - Break interrupt routine
+page
+
+;------------------------------------------------------------------------
+; Break interrupt routine
+;
+
+assume ds:NOTHING,es:NOTHING
+
+Break PROC NEAR
+ int 32H ; save registers
+ cli ; ints should be off, make sure!
+ mov ax,RomData
+ mov ds,ax
+ assume ds:RomData
+ mov ax,offset RomData:KeyBuffer
+ mov [BufferHead],ax
+ mov [BufferTail],ax
+ assume ds:NOTHING
+ mov ax,3 ; send char to system
+ mov dx,5 ; ConsInputFilter subfunction
+ call [DosFunction]
+ jz brk1 ; key was eaten by system
+ mov [AltAH],al ; force a ^C
+brk1:
+ iret
+Break ENDP
+
+SUBTTL Keyboard interrupt routine
+PAGE
+; Replacement for ROM keyboard interrupt, tacks on the front.
+; OldKeyInterrupt is set to original contents of INT 09H.
+; The input character is passed to the O.S. console input filter
+; to determine if any special action should be taken. The filter
+; return value indicates if the character should be saved in the
+; type ahead buffer or if it should be discarded. A keyboard
+; semaphore exists to indicate if a process is waiting for input.
+; If the keboard semaphore is set all of the processes sleeping on
+; it are woken up.
+
+OldKeyInterrupt DD ?
+KeySem db 0 ; non-zero if someone waiting on input
+
+KeyboardInterrupt PROC FAR
+ INT 32H ; Save regs
+ MOV AX,RomData
+ MOV DS,AX
+ ASSUME DS:RomData
+
+ PUSHF ; Save flags to simulate INT
+ CALL CS:OldKeyInterrupt ; Now do ROM code
+; Now tell DOS keyboard had char
+ cli ; interrupts off!
+ mov bx,BufferTail ; Get tail of queue
+ cmp bx,BufferHead ; Anything in keyboard queue?
+ JE NoKey ; No, don't requeue then
+ dec bx
+ dec bx
+ cmp bx,offset RomData:KeyBuffer
+ jae kbi1 ; no wrap around in buffer
+ mov bx,offset RomData:KeyBuffer+(KeyBufLen-2)
+kbi1:
+ mov ax,[bx] ; get last queued char.
+ mov dx,5 ; ConsInputFilter subfunction
+ call [DosFunction]
+ jnz kbi2 ; key should remain in buffer
+ mov BufferTail,bx ; discard key from buffer
+ jmp SHORT NoKey
+kbi2:
+ cli
+ CMP KeySem,0 ; Outstanding request?
+ JE NoKey ; No, may not be inited either
+ push ax
+ push bx
+ push cx
+ push dx
+ mov ax,cs
+ mov bx,OFFSET KeySem
+ mov cs:byte ptr [bx],0 ; reset keyboard semaphore
+ mov dx,10 ;; ProcRun
+ call [DosFunction] ; awaken anyone waiting on input
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+NoKey:
+ IRET
+KeyBoardInterrupt ENDP
+
+;-------------------------------------------------------------
+; Keyboard INT 16 intercept routine to allow console input to sleep.
+; Only console input function 1 is intercepted, all other functions
+; are allowed to go directly to the ROM BIOS. For the function 1
+; the input status is checked, if a character is ready the function
+; is allowed to go to the ROM BIOS. Otherwise the keyboard semaphore
+; is set and the process is put to sleep on the address of the
+; semaphore. When a key is typed the keyboard interrupt routine
+; will wakeup any processes sleeping on this semaphore.
+;
+; WARNING: The following routines can be entered recursively
+; due to the fact that the ROM BIOS routines called
+; reenable interrupts. It's not usually a problem
+; since interrupts will generally be processed faster
+; than anyone can type.
+
+OldKbdHandler dd ?
+ScrnIoOk dd ?
+
+;-------------------------------------------------------------
+
+KeyBoardHandler proc far
+ or ah,ah
+ je DoLocalRead
+ cmp ah,1
+ je DoLocalStat
+OldKBint:
+ jmp [OldKbdHandler]
+
+DoLocalStat:
+ push bx
+ push ds
+ lds bx,ScrnIoOk
+ test byte ptr [bx],0FFh
+ pop ds
+ pop bx
+ jnz OldKBint
+ xor ax,ax
+ ret 2
+DoInt16 LABEL FAR ; entry for ChrIn
+DoLocalRead:
+ push ax
+ push bx
+ push cx
+ push dx
+DoLocalRd1:
+ push ds
+ lds bx,ScrnIoOk
+ mov ax,ds
+ test byte ptr [bx],0FFh
+ pop ds
+ jnz DoLocalRd2
+ xor cx,cx
+ mov dx,9 ;; ProcBlock
+ call [DosFunction] ; sleep until a screen switch
+ jmp DoLocalRd1
+
+DoLocalRd2:
+ mov ah,1 ; get console status
+ pushf ; simulate INT to old handler
+ cli
+ call [OldKbdHandler]
+ cli ; subfunction 1 unconditionally sets IF
+ jnz LocalRead ; go read character
+ mov ax,cs
+ mov bx,OFFSET KeySem
+ mov cs:byte ptr [bx],0FFh ; set keyboard semaphore
+ xor cx,cx
+ mov dx,9 ;; ProcBlock
+ call [DosFunction] ; sleep until a char is typed
+ jmp DoLocalRd1
+
+LocalRead:
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ jmp [OldKbdHandler] ; read the character and return
+
+KeyBoardHandler endp
+
+
+subttl $ConRead - Console Input (Read)
+page
+
+;------------------------------------------------------------------------
+; Console Input (Read)
+;
+; entry:
+; DS:BX = pointer to Request packet
+; ES:DI = Transfer address
+; CX = Count
+;
+
+assume ds:NOTHING,es:NOTHING
+
+$ConRead:
+ and cx,cx
+ jnz jgl2
+ jmp CRExit
+; jcxz CRExit ; no chars to read BUGBUG restore
+jgl2: cld ; make sure!
+ mov dx,word ptr ds:[bx].START ; get screen number
+ cmp dx,(MaxSIB-1) ; valid number?
+ jbe ConRLoop ; yes, do input
+ mov al,0BH ; no, READ FAULT ERROR
+ jmp StatusError
+ConRLoop:
+ DEBUG 10h,1,,
+ cmp dx,[CurrSc]
+ je sjp0
+ call GetSIBAdr ; get pointer to the SIB
+ DEBUG 10h,1,,<>
+ call DoPBlock ; block the process
+ jmp short ConRLoop ; test flag again
+sjp0:
+ call ChrIn
+ stosb
+; loop ConRLoop
+ loop jgl3
+CRExit: jmp StatusComplete
+
+jgl3: jmp ConRLoop
+
+subttl ChrIn - Read a single character In
+page
+
+;------------------------------------------------------------------------
+; Read a single character In
+;
+; exit:
+; Character in AL
+;
+; modifies: AX
+;
+
+assume ds:NOTHING,es:NOTHING
+
+ChrIn:
+ DEBUG 10h,1,,<>
+ xor ax,ax
+ xchg al,[AltAH] ; Get Character & zero AltAH
+ or al,al ; A char available?
+ jnz KeyRet
+;
+;--- NOTE: The blocking on read is done at int 16h level
+; in IBMBIO. No need to block here.
+;
+ DEBUG 10h,1,< con.do.16 >,<>
+ mov ah,0 ; no, do a read call
+ pushf
+ call DoInt16
+;; int 16h
+ DEBUG 10h,1,< con.got.$x >,
+ or ax,ax ; check for non-key after BREAK
+ jnz jgl1
+ jmp chrin
+
+jgl1: cmp ax,7200h ; CTRL-PRTSC ?
+ jnz sja0
+ mov al,10h ; yes, make it a ctrl-P
+sja0: or al,al ; special case?
+ jnz KeyRet
+ mov [AltAH],ah
+KeyRet:
+ ret
+
+
+subttl $ConRdnd - Console non-destructive Input, no wait
+page
+
+;------------------------------------------------------------------------
+; Console non-destructive Input, no wait
+;
+; entry:
+; DS:BX = pointer to Request packet
+;
+
+assume ds:NOTHING,es:NOTHING
+
+$ConRdnd:
+ mov dx,word ptr ds:[bx].START ; get screen number
+ cmp dx,(MaxSIB-1) ; valid number?
+ jbe sjq0 ; yes, do input
+ mov al,0BH ; no, READ FAULT ERROR
+ jmp StatusError
+sjq0:
+ DEBUG 10h,1,,
+ cmp dx,[CurrSc]
+IFDEF DEBUGFLG
+ je sjq1
+ jmp ConBus
+ELSE
+ jne ConBus ; not current screen, no char avail
+ENDIF
+; call GetSIBAdr ; get pointer to the SIB
+; call DoPBlock ; block the process
+; jmp short sjq0 ; test flag again
+sjq1:
+ mov al,[AltAH] ; char avail already?
+ or al,al
+ jnz rdExit
+ DEBUG 10h,1,< NRD:do.16 >,<>
+ mov ah,1 ; no, get status
+ int 16h
+ jz ConBus
+ DEBUG 10h,1,< NRD:nonbus $x >,
+ or ax,ax
+ jnz NotBk ; Check for null after break
+ mov ah,0 ; flush the null
+ int 16h
+ jmp $ConRdnd ; try again
+; jmp short $ConRdnd ; try again BUGBUG
+NotBk:
+ cmp ax,7200h ; CTRL-PRTSC ?
+ jnz rdExit
+ mov al,10h ; yes, make it a ctrl-P
+rdExit:
+ mov byte ptr ds:[bx].MEDIA,al ; save character
+DoExit: jmp StatusComplete
+
+ConBus: DEBUG 10h,1,< ConBus - >,<>
+ jmp StatusDevReady
+
+
+subttl $ConFlsh - Console Flush Input
+page
+
+;------------------------------------------------------------------------
+; Console Flush Input
+;
+; entry:
+; DS:BX = pointer to Request packet
+;
+
+assume ds:NOTHING,es:NOTHING
+
+$ConFlsh:
+ mov dx,word ptr ds:[bx].START ; get screen number
+ cmp dx,(MaxSIB-1) ; valid number?
+ jbe sjr0 ; yes, do flush
+ mov al,0BH ; no, READ FAULT ERROR
+ jmp StatusError
+sjr0:
+ cmp dx,[CurrSc]
+ je sjr1
+ call GetSIBAdr ; get pointer to the SIB
+ call DoPBlock ; block the process
+ jmp short sjr0 ; test flag again
+sjr1:
+ mov [AltAH],0 ; clear side bufer
+ push ds
+ mov ax,RomData
+ mov ds,ax
+ assume ds:RomData
+ cli ; Disable interrupts
+ mov ax,offset RomData:KeyBuffer ; Start of Rom buffer
+ mov [BufferHead],ax
+ mov [BufferTail],ax ; Empty the queue
+ sti
+ pop ds
+ assume ds:NOTHING
+ jmp StatusComplete
+
+
+subttl $ConWrit - Console Output (Write)
+page
+
+;------------------------------------------------------------------------
+; Console Output (Write)
+;
+; entry:
+; DS:BX = pointer to Request packet
+; ES:DI = Transfer address
+; CX = Count
+;
+
+assume ds:NOTHING,es:NOTHING
+
+$ConWrit:
+ jcxz CWExit
+ mov dx, word ptr ds:[bx].START ; get screen number
+ cmp dx,(MaxSIB-1) ; valid screen number?
+ jbe sjb0
+ mov al,0AH ; no, write fault error
+ jmp StatusError
+sjb0: push cs
+ pop ds
+ assume ds:Code
+ mov bx,[CurrSIB]
+
+ConWLoop:
+ cmp dx,[CurrSc] ; Is it to the current screen?
+ je sjb2 ; yes, do not block
+ call GetSIBAdr ; get pointer to the SIB
+sjb1: call DoPBlock ; block the process
+ jmp short ConWLoop ; test ALL flags again
+sjb2:
+ cmp [bx].ctlS,0 ; is the screen frozen?
+ je sjb3
+ mov ax,bx ; AX = [CurrSIB] = [CurrSIB].ctlS !!!!
+ jmp short sjb1 ; yes, block the process
+sjb3:
+ cmp [SaveFlg],0 ; are we in the middle of a save?
+ je sjb4 ; no, do write
+ mov ax,offset SaveFlg
+ jmp short sjb1 ; yes, block...
+sjb4:
+ mov al,es:[di] ; get a character
+ inc di
+ call CharOut
+ loop ConWLoop
+CWExit: jmp StatusComplete
+
+
+subttl CharOut - Output a character to the screen
+page
+
+;------------------------------------------------------------------------
+; Output a character to the screen
+;
+; entry:
+; AL = Character to write
+;
+; preserves:
+; BX, CX, DX, DI, DS & ES
+;
+
+assume ds:NOTHING,es:NOTHING
+
+IF ANSI
+ include ansi.inc
+ELSE
+CharOut:
+ push bx
+ push di
+ mov bx,7
+ mov ah,14
+ int 10h ; Write Character
+ pop di
+ pop bx
+ ret
+ENDIF
+
+
+subttl $GenIOCTL - Generic IOCTL
+page
+
+;------------------------------------------------------------------------
+; Generic IOCTL
+;
+; entry:
+; DS:BX = pointer to Request packet
+;
+
+;--- Offsets into the request packet
+;*** Check offset are correct
+FunCode = 14 ; Function Code
+FunCat = 13 ; Function Category
+;***
+RegSI = 15 ; Contents of SI
+RegDI = 17 ; Contents of DI
+DatBuf = 19 ; Pointer to data buffer
+
+;--- Code & Category definitions
+IOC_SC = 03h ;--- Screen Control
+IOSC_LS = 41h ; Locate SIB
+IOSC_SS = 42h ; save segment
+IOSC_RS = 43h ; restore segment
+IOSC_EI = 44h ; re-enable i/o
+IOSC_IS = 45h ; initialize screen
+
+assume ds:NOTHING,es:NOTHING
+
+$GenIOCTL:
+ cmp byte ptr ds:[bx].FunCode,IOC_SC
+ jne GI_BadCode ; function not suported
+ mov si,word ptr ds:[bx].RegSI
+ mov al,byte ptr ds:[bx].FunCat
+ cmp al,IOSC_LS
+ jne sjc0
+ jmp short do_IOSC_LS
+sjc0: cmp al,IOSC_SS
+ jne sjc1
+ jmp short do_IOSC_SS
+sjc1: cmp al,IOSC_RS
+ jne sjc2
+ jmp do_IOSC_RS
+sjc2: cmp al,IOSC_EI
+ jne sjc3
+ jmp do_IOSC_EI
+sjc3: cmp al,IOSC_IS
+ jne GI_BadCode
+ jmp do_IOSC_IS
+
+GI_BadCode:
+ jmp CmdErr ; error exit: Command error
+
+
+subttl do_IOSC_LS - Locate SIB
+page
+
+;------------------------------------------------------------------------
+; Locate SIB
+;
+; entry:
+; SI = SIB Number
+; DS:BX = pointer to Request packet
+;
+
+assume ds:NOTHING,es:NOTHING
+
+do_IOSC_LS:
+ cmp si,(MaxSIB-1) ; index within range?
+ ja BadNum
+ push bx
+ push ds
+ push cs
+ pop ds
+ assume ds:Code
+ cmp si,[CurrSc] ; is it the current screen?
+ je CurrLS
+ mov [CurrSc],si ; no, just switch curr screens
+ mov dx,si ; index
+ call GetSIBAdr ; get pointer to SIB
+ mov [CurrSIB],ax ; save pointer to curr SIB
+ jmp short retLS
+
+CurrLS:
+ mov [SaveFlg],1 ; Signal we are Saving the screen
+
+;*** Only one segment for now
+
+ mov ax,0
+ call GetSegAdr ; on return BX points to segment
+ mov ax,RomData
+ mov es,ax
+ assume es:RomData
+IF EAGLE
+ mov al,es:[CRT_MODE]
+ xor ah,ah
+ mov si,ax
+ mov ah,ScreenLen[si]
+ xor al,al
+ELSE
+ mov ax,es:[CRT_LEN]
+ assume es:NOTHING ; not true, but just to be safe
+ENDIF
+ mov [bx].SizeNeeded,ax ; save size of segment
+ mov ax,dx ; pointer to current SIB
+retLS:
+ pop ds
+ pop bx
+ assume ds:NOTHING
+ mov word ptr ds:[bx].DatBuf,ax ; offset
+ mov word ptr ds:[bx].DatBuf+2,cs ; segment
+ mov word ptr ds:[bx].RegSI,0 ; operation ok
+ jmp StatusComplete
+
+BadNum:
+ mov word ptr ds:[bx].RegSI,1 ; bad SIB number error
+ jmp StatusComplete
+
+
+subttl do_IOSC_SS - Save Segment
+page
+
+;------------------------------------------------------------------------
+; Save Segment
+;
+; entry:
+; SI = Segment Index (into the Current SIB)
+; DS:BX = pointer to Request packet
+;
+
+assume ds:NOTHING,es:NOTHING
+
+do_IOSC_SS:
+ cmp si,(MaxSeg-1) ; within range?
+BadNumJ1:
+ ja BadNum ; no, somebody screwed up...
+ push bx
+ push ds
+ cmp si,0 ; first segment save?
+ jne nfSS ; no, just save screen data
+;--- save screen state data
+ push si ; save index
+ mov ax,RomData
+ mov ds,ax ; DS = ROM data area
+ assume ds:RomData
+ mov si,offset RomData:CRT_MODE
+ mov cx,CrtLen ; length of screen state data
+ push cs
+ pop es
+ assume es:Code
+ mov di,[CurrSIB]
+ lea di,[di].xCRT_MODE
+ cld
+ rep movsb ; copy ROM info to SIB area
+IF ANSI
+ push cs
+ pop ds
+ assume ds:Code
+ mov si,offset AnsiState ; point to ANSI state info
+ mov cx,AnsiSize
+ rep movsb ; save ANSI state info in SIB
+ENDIF
+ pop si ; restore segment index
+;--- save a segment of screen data
+nfSS:
+ push cs
+ pop ds
+ assume ds:Code
+ mov ax,si
+ call GetSegAdr ; get adress of segment and curr SIB ptr
+ mov cx,[bx].SizeNeeded ; CX = Ammount to transfer
+ shr cx,1 ; words!
+ les di,[bx].MPointer ; ES:DI = Screen save area
+ assume es:NOTHING
+
+;*** For now we are using only one segment
+
+ mov si,dx ; SI points to the current SIB
+ mov bx,ColorSc ; assume color card
+ cmp [si].xCRT_MODE,7 ; is this a BW monitor?
+ jne do_save
+ mov bx,MonoSc
+do_save:
+IF BLANK
+ mov dx,[si].xADDR_6845 ; point to mode register
+ add dx,4
+ mov al,[si].xCRT_MODE_SET ; and get value
+ and al,NOT 8
+ out dx,al ; turn off video
+ENDIF
+ mov ds,bx ; DS points to apropiate screen area
+ assume ds:NOTHING
+ mov si,0
+ cld
+ rep movsw ; copy the screen
+IF BLANK
+ or al,8
+ out dx,al ; turn on video
+ENDIF
+ pop ds
+ pop bx
+ mov word ptr ds:[bx].RegSI,0 ; operation ok
+ jmp StatusComplete
+
+
+subttl do_IOSC_RS - Restore Segment
+page
+
+;------------------------------------------------------------------------
+; Restore Segment
+;
+; entry:
+; SI = Segment Index (into the Current SIB)
+; DS:BX = pointer to Request packet
+;
+
+assume ds:NOTHING,es:NOTHING
+
+do_IOSC_RS:
+ cmp si,(MaxSeg-1) ; within range?
+ ja BadNumJ1 ; no, somebody screwed up...
+ push bx
+ push ds
+ push cs
+ pop ds
+ assume ds:Code
+ cmp si,0 ; first segment save?
+ jne nfRS ; no, just restore screen data
+;--- restore screen state data
+ push si ; save index
+ mov si,[CurrSIB]
+ push si
+ lea si,[si].xCRT_MODE
+ mov ax,RomData
+ mov es,ax ; ES = ROM data area
+ assume es:RomData
+ mov cx,CrtLen ; length of screen state data
+ mov di,offset RomData:CRT_MODE
+ cld
+ rep movsb ; copy ROM info from SIB area
+IF ANSI
+ push es
+ push cs
+ pop es
+ assume es:Code
+ mov di,offset AnsiState ; point to ANSI state info
+ mov cx,AnsiSize
+ rep movsb ; restore ANSI state info from SIB
+ pop es
+ assume es:RomData
+ENDIF
+
+;--- Setup new screen state
+ pop si
+ mov al,[si].xCRT_MODE
+ cmp al,7 ; is this the BW monitor?
+ jne sjd0
+ mov al,2 ; this is the "real" mode
+sjd0:
+ mov ah,0
+ int 10h ; set new mode
+ mov cx,[si].xCURSOR_MODE
+ mov ah,1
+ int 10h ; set cursor type
+ mov dx,[si].xCURSOR_POSN
+ mov bh,[si].xACTIVE_PAGE
+ mov ah,2
+ int 10h ; set cursor position
+ mov al,[si].xACTIVE_PAGE
+ mov ah,5
+ int 10h ; set page #
+ mov dx,[si].xADDR_6845
+ add dx,5
+ mov al,[si].xCRT_PALETTE
+ out dx,al ; set color port
+ mov es:CRT_PALETTE,al
+ pop si ; restore segment index
+;--- restore a segment of screen data
+nfRS:
+ mov ax,si
+ call GetSegAdr ; get adress of segment
+ mov cx,[bx].SizeNeeded ; CX = Ammount to transfer
+ shr cx,1 ; words!
+ lds si,[bx].MPointer ; DS:SI = Screen save area
+ assume ds:NOTHING
+
+;*** For now we are using only one segment
+
+ mov di,dx ; DI points to the current SIB
+ mov bx,ColorSc ; assume color card
+ cmp cs:[di].xCRT_MODE,7 ; is this a BW monitor?
+ jne do_rest
+ mov bx,MonoSc
+do_rest:
+IF BLANK
+ mov dx,cs:[di].xADDR_6845 ; point to mode register
+ add dx,4
+ mov al,cs:[di].xCRT_MODE_SET ; and get value
+ and al,NOT 8
+ out dx,al ; turn off video
+ENDIF
+ mov es,bx ; ES points to apropiate screen area
+ assume es:NOTHING
+ mov di,0
+ cld
+ rep movsw ; copy the screen
+IF BLANK
+ or al,8
+ out dx,al ; turn on video
+ENDIF
+
+ pop ds
+ assume ds:NOTHING
+ pop bx
+ mov word ptr ds:[bx].RegSI,0 ; operation ok
+ jmp StatusComplete
+
+BadNumJ:
+ jmp BadNum
+
+
+subttl do_IOSC_EI - Re-enable i/o
+page
+
+;------------------------------------------------------------------------
+; Re-enable i/o
+;
+; entry:
+; DS:BX = pointer to Request packet
+;
+
+assume ds:NOTHING,es:NOTHING
+
+do_IOSC_EI:
+ mov [SaveFlg],0 ; Signal we are done Saving the screen
+ mov ax,offset Code:SaveFlg
+ call DoPRun ; ProcRun
+ mov ax,[CurrSIB] ; pointer to current SIB
+ call DoPRun ; ProcRun any output blocked because
+ ; screen was not current
+ jmp StatusComplete
+
+
+subttl do_IOSC_IS - Initialize Screen
+page
+
+;------------------------------------------------------------------------
+; Initialize Screen
+;
+; entry:
+; SI = SIB Number
+; DS:BX = pointer to Request packet
+;
+
+assume ds:NOTHING,es:NOTHING
+
+do_IOSC_IS:
+ cmp si,(MaxSIB-1) ; index within range?
+ ja BadNumJ
+ push ds
+ push cs
+ pop ds
+ assume ds:Code
+ mov [CurrSc],si ; switch curr screens
+ mov dx,si ; index
+ call GetSIBAdr ; get pointer to SIB
+ mov [CurrSIB],ax ; save pointer to curr SIB
+ mov si,ax
+ mov [si].ctlS,0 ; screen not frozen
+;--- set screen mode to pc mode 3 (80x25 BW)
+ mov ax,0003 ; Set mode 3
+ int 10h
+ pop ds
+ assume ds:NOTHING
+ mov word ptr ds:[bx].RegSI,0 ; operation ok
+ jmp StatusComplete
+
+
+subttl $ConStop - Stop (freeze) console output
+page
+
+;------------------------------------------------------------------------
+; Stop (freeze) console output
+;
+
+assume ds:NOTHING,es:NOTHING
+
+$ConStop:
+ mov bx,[CurrSIB] ; pointer to current SIB
+ mov cs:[bx].ctlS,01 ; set the freeze flag
+ jmp StatusComplete
+
+
+subttl $ConStart - Start (continue) console output
+page
+
+;------------------------------------------------------------------------
+; Start (continue) console output
+;
+
+assume ds:NOTHING,es:NOTHING
+
+$ConStart:
+ mov bx,[CurrSIB] ; pointer to current SIB
+ cmp cs:[bx].ctlS,0 ; is it already going?
+ je csRet ; yes, no need to re-enable
+ mov cs:[bx].ctlS,0 ; reset the freeze flag
+ lea ax,[bx].ctlS ; get address of current ctlS
+ call DoPRun ; do ProcRun
+csRet: jmp StatusComplete
+
+
+subttl DoPBlock - Block the current process
+page
+
+;------------------------------------------------------------------------
+; Block the current process
+;
+; entry:
+; CS:AX = address to block on
+;
+; modifies: AX, FLAGS
+;
+
+assume ds:NOTHING,es:NOTHING
+
+DoPBlock:
+ push bx
+ push cx
+ push dx
+ mov bx,ax
+ mov ax,cs ; AX:BX = event identifier
+ xor cx,cx ; No timeout
+;; mov dx,0109h ;;BUGBUG - should be interruptible wait; will
+ ;; give InternalError (SchedFind - not on Q)
+ mov dx,0009h ; PROCBLOC function
+ cli ; No races!
+ call [DosFunction]
+ pop dx ; on return ints are back on
+ pop cx
+ pop bx
+ ret
+
+
+subttl DoPRun - Restart a process
+page
+
+;------------------------------------------------------------------------
+; Restart a process
+;
+; entry:
+; CS:AX = address to signal on (same as blocked on)
+;
+; modifies: AX, FLAGS
+;
+
+assume ds:NOTHING,es:NOTHING
+
+DoPRun:
+ push bx
+ push cx
+ push dx
+ mov bx,ax
+ mov ax,cs
+ mov dx,10 ; PROCRUN function
+ call [DosFunction]
+ pop dx
+ pop cx
+ pop bx
+ ret
+
+
+subttl GetSIBAdr - Return SIB address
+page
+
+;------------------------------------------------------------------------
+; Returns the adress of the specified SIB
+;
+; entry:
+; DX = index to the SIB
+;
+; exit:
+; AX = pointer to the SIB
+;
+; preserves: ALL
+;
+
+assume ds:Code,es:NOTHING
+
+GetSIBAdr:
+ push dx ; save screen #
+ mov ax,dx ; index
+ mov dx,(SIZE SIBst)
+ mul dx ; multiply by size of SIB entry
+ pop dx ; restore screen #
+ add ax,offset SIB ; AX = pointer to SIB for the write
+ ret
+
+
+subttl GetSegAdr - Return segment address
+page
+
+;------------------------------------------------------------------------
+; Returns the adress of a segment in the current SIB
+;
+; entry:
+; AX = index to the segment
+;
+; exit:
+; BX = pointer to the segment
+; DX = pointer to the Current SIB
+;
+
+assume ds:Code,es:NOTHING
+
+GetSegAdr:
+ mov dx,(SIZE SEGst)
+ mul dx ; multiply by size of SEG entry
+ mov bx,[CurrSIB] ; pointer to SIB
+ mov dx,bx ; save for exit
+ mov bx,[bx].OffsetVal ; pointer to start of SEGs in SIB
+ add bx,ax ; BX = pointer to SEG from start of SIB
+ add bx,dx ; BX = absolute pointer to SEG to use
+ ret
+
+ifdef DEBUGFLG
+if NOT INBIOS
+ INCLUDE BUGCODE.INC
+endif
+endif
+
+
+subttl $ConInit - Initialization Routine
+page
+
+;------------------------------------------------------------------------
+; Initialization Routine
+;
+;entry:
+; DS:BX = pointer to Request packet
+; ES:DI = Dos Functions entry point address
+;
+
+assume ds:NOTHING,es:NOTHING
+
+$ConInit:
+IF NOT INBIOS
+ push ds ; print greeting
+ push cs
+ pop ds
+ mov dx,offset Intro
+ MOV ah,9
+ int 21h
+ pop ds
+ mov word ptr ds:[bx].TRANS, offset $ConInit
+ mov word ptr ds:[bx].TRANS+2,cs
+ENDIF
+ mov cs:Word Ptr DosFunction,di ; Save pointer to service routines
+ mov cs:Word Ptr DosFunction+2,es
+
+ mov ax,0
+ mov cx,1
+ mov dx,16
+ call [DosFunction] ; get DOS variable ScrnIoOk
+ mov word ptr ScrnIoOk,ax
+ mov word ptr ScrnIoOk+2,dx
+
+;* Initialize interrupt vectors.
+;;BUGBUG - we should be using Get/Set_Interrupt_Vector calls
+
+ xor ax,ax ; initialize break interrupt handler
+ mov es,ax ; points to page 0
+ mov ax,cs
+ mov word ptr es:BRKADR,offset Break
+ mov word ptr es:BRKADR+2,ax ; Vector for Break
+
+ MOV DI,9*4 ; INT 9 - Keyboard interrupt vector
+ MOV CX,es:[DI] ; Save old addr to hook to
+ MOV WORD PTR OldKeyInterrupt,CX
+ MOV CX,es:2[DI]
+ MOV WORD PTR (OldKeyInterrupt+2),CX
+ MOV CX,OFFSET KeyboardInterrupt
+ XCHG AX,CX
+ STOSW
+ XCHG AX,CX
+ STOSW ; Set new keyboard interrupt
+
+ mov di,16h*4 ; INT 16 - keyboard input
+ MOV CX,es:[DI] ; Save INT 16 addr to hook to
+ MOV WORD PTR OldKbdHandler,CX
+ MOV CX,es:2[DI]
+ MOV WORD PTR (OldKbdHandler+2),CX
+ MOV CX,OFFSET KeyboardHandler
+ XCHG AX,CX
+ STOSW
+ XCHG AX,CX ; Set new keyboard Handler
+ STOSW
+ jmp StatusComplete
+
+
+IF INBIOS
+Code ends
+
+BiosInit segment para public 'CODE'
+ENDIF
+
+Intro db "--- Installing MTCON Device Driver V"
+ db CVERS+"0",".",CREV/10+"0"
+ db (CREV-CREV/10*10)+"0"," ---"
+ db 13,10,"$"
+
+BiosInit ends
+
+ END
diff --git a/v4.0-ozzie/bin/DISK2/BIOS/IBMMTCON.OBJ b/v4.0-ozzie/bin/DISK2/BIOS/IBMMTCON.OBJ
new file mode 100644
index 0000000..ed4dc74
Binary files /dev/null and b/v4.0-ozzie/bin/DISK2/BIOS/IBMMTCON.OBJ differ
diff --git a/v4.0-ozzie/bin/DISK2/BIOS/READ_ME b/v4.0-ozzie/bin/DISK2/BIOS/READ_ME
new file mode 100644
index 0000000..03623a4
--- /dev/null
+++ b/v4.0-ozzie/bin/DISK2/BIOS/READ_ME
@@ -0,0 +1,25 @@
+29 May 1984
+
+The object files given here are sufficient to create the BIOS
+for the IBM system. Some sources are given as examples for
+OEM supplied device drivers. These sources do not necessarily
+implement all the features described in the device driver
+documentation. They have evolved in parallel with the
+documentation, so some features described in the documentation
+may not yet be present in the drivers. Below is a summary of
+the files supplied:
+
+ read_me This file.
+ ibmbio.asm Main body of the BIOS.
+ ibmdsk.asm Floppy and Hard disk drivers.
+ ibmmtcon.asm Multi-screen console driver.
+ ansi.inc ANSI X3.64 terminal emulation.
+ bugcode.inc Module which implements debugging
+ prints. The routine PUTC must be
+ modified for other devices. See
+ also the file DEFDBUG.INC.
+ sys*.obj The SYSINIT program. No source supplied.
+ biosobj.mak Contains instructions for building the
+ IBM BIOS.
+ bootpach.exe Modifies a V2.0 boot sector (on A:) for
+ the IBM to accomodate the larger BIOS.
diff --git a/v4.0-ozzie/bin/DISK2/BIOS/SYSIMES.OBJ b/v4.0-ozzie/bin/DISK2/BIOS/SYSIMES.OBJ
new file mode 100644
index 0000000..4439f35
Binary files /dev/null and b/v4.0-ozzie/bin/DISK2/BIOS/SYSIMES.OBJ differ
diff --git a/v4.0-ozzie/bin/DISK2/BIOS/SYSINI.OBJ b/v4.0-ozzie/bin/DISK2/BIOS/SYSINI.OBJ
new file mode 100644
index 0000000..0fc06ba
Binary files /dev/null and b/v4.0-ozzie/bin/DISK2/BIOS/SYSINI.OBJ differ
diff --git a/v4.0-ozzie/bin/DRDOS1.IMD b/v4.0-ozzie/bin/DRDOS1.IMD
new file mode 100644
index 0000000..0a7a84f
Binary files /dev/null and b/v4.0-ozzie/bin/DRDOS1.IMD differ
diff --git a/v4.0-ozzie/bin/DRDOS1_IMD.img b/v4.0-ozzie/bin/DRDOS1_IMD.img
new file mode 100644
index 0000000..d6d7165
Binary files /dev/null and b/v4.0-ozzie/bin/DRDOS1_IMD.img differ
diff --git a/v4.0-ozzie/bin/DRDOS2.IMD b/v4.0-ozzie/bin/DRDOS2.IMD
new file mode 100644
index 0000000..972058b
Binary files /dev/null and b/v4.0-ozzie/bin/DRDOS2.IMD differ
diff --git a/v4.0-ozzie/bin/DRDOS2_IMD.img b/v4.0-ozzie/bin/DRDOS2_IMD.img
new file mode 100644
index 0000000..64d8395
Binary files /dev/null and b/v4.0-ozzie/bin/DRDOS2_IMD.img differ
diff --git a/v4.0/LICENSE b/v4.0/LICENSE
new file mode 100644
index 0000000..b13d100
--- /dev/null
+++ b/v4.0/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) IBM and Microsoft Corporation.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE
diff --git a/v4.0/src/BIOS/BIOSTRUC.INC b/v4.0/src/BIOS/BIOSTRUC.INC
new file mode 100644
index 0000000..f131e11
--- /dev/null
+++ b/v4.0/src/BIOS/BIOSTRUC.INC
@@ -0,0 +1,103 @@
+%OUT BIOSTRUC.INC...
+; SCCSID = @(#)BIOSTRUC.INC 1.0 86/09/30
+; 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, 6Mhz PC/AT,
+; 6Mhz PC/AT running coprocessor(?),
+; PS/2 Model 50, 50 z
+; 0FAh = PS/2 Model 25, 30
+; 0F9h = PC Convertible
+; 0F8h = PS/2 Model 80
+; 0F7h = Nova
+; 0E0 thru 0EFh = reserved
+;
+; DB xx secondary model byte
+; 000h = PC1
+; 000h = PC/XT, Portable
+; 000h = PC/JR
+; 000h = PC/AT
+; 001h = 6Mhz PC/AT
+; 003h = 6Mhz PC/AT running coprocessor(?)
+; 004h = PS/2 Model 50, 50z
+; 001h = PS/2 Model 25
+; 000h = PC Convertible
+; 000h = PS/2 Model 80
+; 000h = Nova
+;
+; 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(INT15h)
+; 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
+;
+;Model Byte
+MDL_PC1 EQU 0FFH
+MDL_XT EQU 0FEH
+MDL_JR EQU 0FDH
+MDL_AT EQU 0FCH
+MDL_CONVERT EQU 0F9H
+
+mdl_ps2_30 equ 0fah
+mdl_ps2_80 equ 0f8h
diff --git a/v4.0/src/BIOS/CLOCKSUB.INC b/v4.0/src/BIOS/CLOCKSUB.INC
new file mode 100644
index 0000000..65b6698
--- /dev/null
+++ b/v4.0/src/BIOS/CLOCKSUB.INC
@@ -0,0 +1,78 @@
+;
+; date_verify loosely checks bcd date values to be in range in bin_date_time
+;
+date_verify: ;
+assume ds:code,es:nothing
+ 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:
+assume ds:code,es:nothing
+ 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: ;
+assume ds:code,es:nothing
+ 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/v4.0/src/BIOS/CMOSEQU.INC b/v4.0/src/BIOS/CMOSEQU.INC
new file mode 100644
index 0000000..b52b259
--- /dev/null
+++ b/v4.0/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/v4.0/src/BIOS/DEFEMS.INC b/v4.0/src/BIOS/DEFEMS.INC
new file mode 100644
index 0000000..a1786d0
--- /dev/null
+++ b/v4.0/src/BIOS/DEFEMS.INC
@@ -0,0 +1,33 @@
+;J.K. This is a temporary version of EMS function definitions needed for
+;IBMBIO SYSINIT.
+
+EMS_INT equ 67h ;interrupt vector designated for EMS.
+
+EMS_STATUS equ 40h ;status of memery manager
+EQ_PAGES equ 42h ;get number of unallocated & total pages
+E_GET_HANDLE equ 43h ;allocate pages
+EMAP_L_TO_P equ 44h ;Map logical to physical page
+EMAP_STATE equ 4Fh ;Mapping status
+ GET_MAP_STATE equ 00h
+ GET_MAP_SIZE equ 02h
+ SET_MAP_STATE equ 01h
+EDE_ALLOCATE equ 45h ;deallocate pages
+EMS_VERSION equ 46h ;Get EMM version number
+GET_PAGE_FRAME equ 58h ;Get page frame address
+ GET_PAGEFRAME_TAB equ 00H
+ GET_NUM_PAGEFRAME equ 01H
+EMS_HANDLE_NAME equ 53h
+ SET_HANDLE_NAME equ 01h
+
+IBM_PAGE_ID equ 255 ;Physical page id that will be used by
+ ;IBMBIO and IBMDOS for buffer manipulation.
+
+;MAX_NUM_PAGEFRAME equ 12 ;maximum number of page frames IBMBIO can
+ ;handle
+
+MAX_NUM_PAGEFRAME equ 64 ;maximum number of page frames MSBIO can
+ ;handle
+
+EMSVERSION equ 40h ;4.0
+
+
\ No newline at end of file
diff --git a/v4.0/src/BIOS/DEVMARK.INC b/v4.0/src/BIOS/DEVMARK.INC
new file mode 100644
index 0000000..1b919f7
--- /dev/null
+++ b/v4.0/src/BIOS/DEVMARK.INC
@@ -0,0 +1,23 @@
+;Structure, Equtes for DEVMARK for MEM command.
+
+DEVMARK struc
+DEVMARK_ID db 0
+DEVMARK_SEG dw 0
+DEVMARK_SIZE dw 0
+DEVMARK_DUM db 3 dup (?)
+DEVMARK_FILENAME db 8 dup (' ')
+DEVMARK ends
+
+DEVMARK_STK equ 'S'
+DEVMARK_DEVICE equ 'D'
+DEVMARK_IFS equ 'I'
+DEVMARK_BUF equ 'B'
+DEVMARK_CDS equ 'L' ;lastdrive
+DEVMARK_FILES equ 'F'
+DEVMARK_FCBS equ 'X'
+DEVMARK_INST equ 'T' ;used for SYSINIT BASE for INSTALL= command.
+DEVMARK_EMS_STUB equ 'E'
+
+SETBRKDONE equ 00000001b
+FOR_DEVMARK equ 00000010b
+NOT_FOR_DEVMARK equ 11111101b
diff --git a/v4.0/src/BIOS/JUMPMAC.INC b/v4.0/src/BIOS/JUMPMAC.INC
new file mode 100644
index 0000000..e631e2e
--- /dev/null
+++ b/v4.0/src/BIOS/JUMPMAC.INC
@@ -0,0 +1,31 @@
+ ;;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/v4.0/src/BIOS/LOCSCR b/v4.0/src/BIOS/LOCSCR
new file mode 100644
index 0000000..2bbd69c
--- /dev/null
+++ b/v4.0/src/BIOS/LOCSCR
@@ -0,0 +1 @@
+70
diff --git a/v4.0/src/BIOS/MAKEFILE b/v4.0/src/BIOS/MAKEFILE
new file mode 100644
index 0000000..66a281f
--- /dev/null
+++ b/v4.0/src/BIOS/MAKEFILE
@@ -0,0 +1,167 @@
+#************************** makefile for bios ***************************
+
+dest =io
+msg =..\messages
+dos =..\dos
+inc =..\inc
+hinc =..\h
+
+#
+####################### dependencies begin here. #########################
+#
+
+all: $(dest).sys
+
+msbio.cl1: msbio.skl \
+ $(msg)\$(COUNTRY).msg
+
+msload.obj: msload.asm \
+ makefile \
+ msbio.cl1 \
+ $(inc)\bootform.inc \
+ $(inc)\versiona.inc \
+ msload.inc
+
+msload.com: msload.obj
+ link msload.obj,msload,,;
+ exe2bin msload.exe msload.com
+
+msbio1.obj: msbio1.asm \
+ makefile \
+ msbdata.inc \
+ msgroup.inc \
+ jumpmac.inc \
+ pushpop.inc \
+ $(inc)\devsym.inc \
+ msdskpr.inc \
+ msmacro.inc
+
+mscon.obj: mscon.asm \
+ makefile \
+ msgroup.inc \
+ jumpmac.inc \
+ msmacro.inc
+
+msaux.obj: msaux.asm \
+ makefile \
+ msgroup.inc \
+ jumpmac.inc \
+ msmacro.inc
+
+mslpt.obj: mslpt.asm \
+ makefile \
+ msgroup.inc \
+ msequ.inc \
+ $(inc)\msbds.inc \
+ msmacro.inc \
+ $(inc)\devsym.inc \
+ $(inc)\ioctl.inc $(inc)\bpb.inc
+
+msclock.obj: msclock.asm \
+ makefile \
+ msgroup.inc \
+ msmacro.inc
+
+msdisk.obj: msdisk.asm \
+ makefile \
+ msgroup.inc \
+ msequ.inc \
+ $(inc)\msbds.inc \
+ pushpop.inc \
+ msmacro.inc \
+ $(inc)\devsym.inc \
+ msdskpr.inc \
+ msioctl.inc $(inc)\ioctl.inc $(inc)\bpb.inc
+
+msinit.obj: msinit.asm \
+ makefile \
+ msgroup.inc \
+ msdskpr.inc \
+ msequ.inc $(inc)\msbds.inc \
+ $(inc)\cputype.inc \
+ msmacro.inc \
+ readcloc.inc \
+ clocksub.inc \
+ msextrn.inc
+
+
+sysinit1.obj: sysinit1.asm \
+ makefile \
+ msstack.inc \
+ msbio.cl4 \
+ msbio.cl5 \
+ stkinit.inc \
+ devmark.inc \
+ $(inc)\smifssym.inc \
+ $(inc)\devsym.inc \
+ $(inc)\ioctl.inc \
+ $(inc)\cputype.inc \
+ $(inc)\smdossym.inc $(inc)\dosmac.inc $(inc)\bpb.inc $(inc)\buffer.inc \
+ $(inc)\sysvar.inc $(inc)\vector.inc $(inc)\dirent.inc \
+ $(inc)\dpb.inc $(inc)\curdir.inc \
+ $(inc)\pdb.inc $(inc)\exe.inc $(inc)\sf.inc $(inc)\arena.inc \
+ $(inc)\intnat.inc $(inc)\mi.inc \
+ $(inc)\syscall.inc
+
+
+sysconf.obj: sysconf.asm \
+ makefile \
+ psoption.inc \
+ devmark.inc \
+ $(inc)\psdata.inc \
+ $(inc)\parse.asm \
+ $(inc)\smifssym.inc \
+ $(inc)\devsym.inc \
+ $(inc)\ioctl.inc \
+ $(inc)\smdossym.inc $(inc)\dosmac.inc $(inc)\bpb.inc $(inc)\buffer.inc \
+ $(inc)\sysvar.inc $(inc)\vector.inc $(inc)\dirent.inc \
+ $(inc)\dpb.inc $(inc)\curdir.inc \
+ $(inc)\pdb.inc $(inc)\exe.inc $(inc)\sf.inc $(inc)\arena.inc \
+ $(inc)\intnat.inc $(inc)\mi.inc \
+ $(inc)\syscall.inc
+
+sysinit2.obj: sysinit2.asm \
+ makefile \
+ devmark.inc \
+ $(inc)\copyrigh.inc \
+ $(inc)\smifssym.inc \
+ $(inc)\devsym.inc \
+ $(inc)\ioctl.inc \
+ $(inc)\smdossym.inc $(inc)\dosmac.inc $(inc)\bpb.inc $(inc)\buffer.inc \
+ $(inc)\sysvar.inc $(inc)\vector.inc $(inc)\dirent.inc \
+ $(inc)\dpb.inc $(inc)\curdir.inc \
+ $(inc)\pdb.inc $(inc)\exe.inc $(inc)\sf.inc $(inc)\arena.inc \
+ $(inc)\intnat.inc $(inc)\mi.inc \
+ $(inc)\syscall.inc
+
+sysimes.obj: sysimes.asm \
+ makefile \
+ msmacro.inc \
+ msbio.cl3 \
+ msequ.inc $(inc)\msbds.inc
+
+msbio2.obj: msbio2.asm \
+ makefile \
+ msgroup.inc \
+ msequ.inc \
+ $(inc)\msbds.inc \
+ $(inc)\devsym.inc \
+ pushpop.inc \
+ msmacro.inc \
+ msbio.cl2 \
+ ms96tpi.inc msvolid.inc
+
+mshard.obj: mshard.asm $(inc)\postequ.inc $(inc)\dseg.inc
+
+$(dest).sys: msbio.cl1 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 \
+ msload.com \
+ makefile
+ link @msbio.lnk
+ exe2bin msbio.exe msbio.bin
+ MNUM FTESTDISK,AX
+ MESSAGE FTESTDISK,
+; AL IS LOGICAL DRIVE
+ CALL SETDRIVE ;GET BDS FOR DRIVE
+ INC WORD PTR DS:[DI].OPCNT
+ JMP EXIT ;ARR 2.41
+
+DSK$CLOSE: ;ARR 2.41
+ PUBLIC DSK$CLOSE
+
+ MESSAGE FTESTDISK,<"DISK CLOSE ">
+ 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 ARR 2.41
+ DEC WORD PTR DS:[DI].OPCNT
+EXITJX:
+ JMP EXIT
+
+; 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 ">
+ 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.
+;
+ 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
+;SB33001****************************************************************
+ mov DL, DS:[DI.drivenum] ;SB ; set logical drive number ;3.30*
+ mov AH, 16h ;SB ; get changeline status ;3.30*
+ int 13h ;SB ; call rom diskette routine ;3.30*
+;SB33001****************************************************************
+ POP DX
+ POP AX
+ JC MEDIADOVOLID
+ MOV SI,1 ; 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
+;
+; 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
+;
+; 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.
+;J.K. 9/16/86 For DOS 3.3, this will work only for the drive that has
+;J.K. 9/16/86 changeline.
+ 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
+;J.K. 9/16/86
+; call HasChange ;change line supported?
+; jz CheckRet ;No. Just return
+ 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
+ POP SI ; POP OFF RETURN ADDRESS
+ RET
+
+;
+; 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:
+;J.K. Now with the extended BOOT record, the logic should be enhanced.
+;If it is the extended BOOT record, then we check the volume serial
+;number instead of volume id. If it is different, then set SI to -1.
+;If it is same, then SI= 1 (No change).
+;If it is not the extended BOOT record, then just follows the old
+;logic. DOS 4.00 will check if the # of FAT in the boot record BPB
+;is not 0. If it is 0 then it must be Non_FAT based system and
+;should have already covered by extended boot structure checking.
+;So, we will return "I don't know" by setting SI to 0.
+;This routine assume the newest valid boot record is in CS:[DISKSECTOR].
+;(This will be gauranteed by a successful GETBP call right before this
+;routine.)
+ MESSAGE FTEST96,<"CHECK VID",CR,LF>
+;SB34MS96TPI001*********************************************************
+;SB check the EXT_Boot_Sig variable for the Extended boot signature
+;SB if it is set then go to do the extended ID check otherwise continue
+;SB with code below
+;SB 2 LOCS
+
+ cmp cs:[Ext_Boot_Sig],Ext_Boot_Signature
+ jz Do_Ext_Check_Id
+;SB34MS96TPI001*********************************************************
+ call HasChange ;AN000;
+ jz CheckRet ;AN000;
+
+ xor si,si ;AN000; assume I don't know.
+ cmp byte ptr cs:[SECPERCLUSINSECTOR]+3,0 ;AN000; Don't read vol id from
+ je CHECKFATRET ;AN000; the directory if not FAT system
+ CALL READ_VOLUME_ID
+ JC CHECKFATRET
+ CALL CHECK_VOLUME_ID
+ OR SI,SI
+ JNZ CHANGED_DRV
+ MESSAGE FTEST96,<"VID NOT CHANGED",CR,LF>
+
+VID_NO_Changed:
+ CALL RESETCHANGED
+ clc ;AN000;
+CHECKFATRET:
+ RET
+CHANGED_DRV:
+ MOV CS:[TIM_DRV],-1 ; ENSURE THAT WE ASK ROM FOR MEDIA
+ RET ; CHECK NEXT TIME ROUND
+ ;
+ ; extended ID check
+ ;
+Do_Ext_Check_ID: ;AN000;
+ push ax ;AN000;
+;SB34MS96TPI002**************************************************************
+;SB The code to check extended ID is basically a check to see if the
+;Sb volume serial number is still the same. The volume serial number
+;SB previously read is in cs:[Boot_Serial_H] and cs:[Boot_Serial_L]
+;SB high and low words respectively. DS:DI points to the BDS of the
+;SB drive under consideration. The BDS has fields containing the
+;SB high and low words of the volume serial number of the media in the
+;SB drive. Compare these fields to the fields mentioned above. If these
+;SB fields do not match the media has changed and so we should jump
+;SB to the code starting at Ext_Changed else return "I don't know" status
+;SB in the register used for the changeline status and continue executing
+;SB the code given below. For temporary storage use the register which
+;SB has been saved and restored around this block.
+;SB 7 LOCS
+;SB BDS fields in inc\msbds.inc
+
+ mov ax,cs:[Boot_Serial_L]
+ cmp ax,word ptr ds:[di+VOL_SERIAL]
+ jnz Ext_Changed
+ mov ax,cs:[Boot_Serial_H]
+ cmp ax,word ptr ds:[di+VOL_SERIAL+2]
+ jnz Ext_Changed
+ xor si,si ; don't know
+
+;SB34MS96TPI002**************************************************************
+ pop ax ;AN000;
+; jmp CheckFatRet ;AN000;
+ jmp VID_NO_Changed ;AN001;Reset the flag
+Ext_Changed: ;AN000; Serial number is different!
+ pop ax ;AN000;
+ mov si, -1 ;AN000; disk changed!
+ clc ;AN000; clear carry. Only SI is meaningful here.
+ jmp Changed_Drv ;AN000;
+
+;
+; AT I/O TIME, WE DETECTED THE ERROR. NOW WE NEED TO DETERMINE WHETHER THE
+; MEDIA WAS TRULY CHANGED OR NOT. WE RETURN NORMALLY IF MEDIA CHANGE UNKNOWN.
+; AND WE POP OFF THE CALL AND JMP TO HARDERR IF WE SEE AN ERROR.
+;
+ PUBLIC CHECKIO
+CHECKIO:
+ CMP AH,06
+ JNZ CHECKFATRET
+ 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:
+; POP SI ; POP OFF RETURN
+ 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
+ STC
+ RET
+
+;
+; MUNGE THE TIME OF LAST SUCCESSFUL ACCESS FOR TWEEKED DRIVES
+;
+; DON'T NEED ANY MORE
+; TWEEKCHECK:
+; PUSH AX
+; MOV AX,WORD PTR DS:[DI].FLAGS
+; TEST AL,FCHANGED_BY_FORMAT
+; JZ TWEEKDONE
+; MOV CS:[TIM_DRV],-1
+; TWEEKDONE:
+; POP AX
+; RET
+
+;
+; DRIVE IS THE LOGICAL DRIVE TO USE
+;
+; FORMAT_MEDIA_CHECK: ;ARR 2.42
+; PUSH AX
+; MOV AX,WORD PTR DS:[DI].FLAGS
+; TEST AL,FCHANGED_BY_FORMAT
+; JZ RETF1 ; MEDIA NOT CHANGED VIA FORMAT
+; AND AL,NOT FCHANGED_BY_FORMAT
+; MOV WORD PTR [DI].FLAGS,AX ; RESET CHANGED_BY_FORMAT BIT
+; MOV SI,-1 ; MEDIA CHANGED VIA FORMAT
+; RETF1:
+; POP AX
+; RET
+
+;
+; 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: ; ARR 2.42
+ PUBLIC MEDIA_SET_VID
+
+ CALL INIT_VID_LOOP ; SETS ES:DI -> VID
+ 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
+;
+; 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 ; RETURN TO TAIL OF GETBP
+
+DOFLOPPY:
+ RET
+
+ PATHSTART 001,TPI96
+
+;
+; CERTAIN BOGUS 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
+
+ PUBLIC INT13
+INT13 PROC FAR
+ POP WORD PTR OLDINT
+ POP WORD PTR OLDINT+2
+ POP DMY
+ MESSAGE FTEST13,<"*">
+ PUSHF
+ 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 ">
+ MNUM FTEST13,AX
+ MESSAGE FTEST13,
+ PUSHF ; SAVE STATE
+ CMP AH,06H ; DID I SEE A CHANGE EVENT?
+ JZ GOTERR ; YES
+B: POPF ; NO, SOME OTHER ERROR, IGNORE IT
+ 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
+
+ MESSAGE FTEST96,<"SET CHANGED",CR,LF>
+ 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 ">
+ MNUM FTEST13
+ MESSAGE FTEST13,
+ 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
+
+ public ResetChanged
+RESETCHANGED:
+ MESSAGE FTEST13,<"RESETCHANGED ">
+ MNUM FTEST13
+ MESSAGE FTEST13,
+ 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
+HASCHANGE:
+ MESSAGE FTEST13,<"HASCHANGE ">
+ MNUM FTEST13
+ MESSAGE FTEST13,
+ TEST WORD PTR [DI].FLAGS,FCHANGELINE
+ RET
+
+ ASSUME DS:CODE
+
+ INCLUDE MSVOLID.INC
+
+ PUBLIC END96TPI
+END96TPI LABEL BYTE
diff --git a/v4.0/src/BIOS/MSAUX.ASM b/v4.0/src/BIOS/MSAUX.ASM
new file mode 100644
index 0000000..4d5a95e
--- /dev/null
+++ b/v4.0/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 ---------------------------
+ itest=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/v4.0/src/BIOS/MSBDATA.INC b/v4.0/src/BIOS/MSBDATA.INC
new file mode 100644
index 0000000..d0be320
--- /dev/null
+++ b/v4.0/src/BIOS/MSBDATA.INC
@@ -0,0 +1,722 @@
+;==============================================================================
+;REVISION HISTORY:
+;AN000 - New for DOS Version 3.4 - J.K.
+;AC000 - Changed for DOS Version 3.4 - J.K.
+;ANxxx - PTR, DCRs
+;==============================================================================
+;AN001 - d9 Double word MOV instruction for 80386 based machine. 7/1/87 J.K.
+;AN002 - d25 Change DASD ERP to that recommended by Storage Systems. 7/29/87 J.K.
+;AN003; d304 Boot record structure change for OS2 11/9/87 J.K.
+;==============================================================================
+ EXTRN INIT:NEAR
+
+ PUBLIC START$
+START$:
+ JMP INIT ;START$ PATCH BY INIT TO POINT TO
+ ;HDRIVE BPB
+; PUBLIC FORMAT_PATCH
+;FORMAT_PATCH: ;ARR 2.42
+; JMP FMTSET ;MJB001 DISPATCH FOR CALL FROM FORMAT UTILITY
+
+
+ PATHSTART 001,BIO
+
+; DB 20 DUP (0) ;IBM WANTS SOME ZEROED AREA (DELETED)
+
+
+;HEADER DB "Ver 2.45"
+;--------------------------------------------------------------
+;
+; COMMAND JUMP TABLES
+;
+; BEWARE - THESE TABLES OVERLAP SOMEWHAT! -C.P.
+;
+ ODD
+DSKTBL LABEL BYTE
+ DB 24 ; THIS IS THE SIZE OF THE TABLE YUK!!!!
+ DW DSK$INIT
+ DW MEDIA$CHK
+ DW GET$BPB
+ DW CMDERR ;RS
+ DW DSK$READ
+ DW BUS$EXIT
+ DW EXIT
+ DW EXIT
+ DW DSK$WRIT
+ DW DSK$WRITV
+ DW EXIT ;ARR 2.41
+ DW EXIT ;ARR 2.41
+ DW CMDERR ;RS
+
+ PUBLIC TABLE_PATCH
+TABLE_PATCH LABEL WORD ;ARR 2.42
+ DW DSK$OPEN ;ARR 2.41
+ DW DSK$CLOSE ;ARR 2.41
+ DW DSK$REM ;ARR 2.41
+ DW EXIT
+ DW EXIT
+ DW EXIT
+ DW GENERIC$IOCTL ; KGS 3.20
+ DW EXIT
+ DW EXIT
+ DW EXIT
+ DW IOCTL$GETOWN ; RS 3.20
+ DW IOCTL$SETOWN ; RE 3.20
+
+ 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 ;ARR 2.41
+
+; DW CMDERR ;J.K. 4/29/86 for CON$GENIOCTL support
+; DW CMDERR ;J.K. 4/29/86
+; DW CMDERR ;J.K. 4/29/86
+; DW CMDERR ;J.K. 4/29/86
+; DW CMDERR ;J.K. 4/29/86
+; DW CMDERR ;J.K. 4/29/86
+; DW CMDERR ;J.K. 4/29/86
+; DW CMDERR ;J.K. 4/29/86
+; DW CON$GENIOCTL ;J.K. 4/29/86
+
+ 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
+
+ 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
+
+ 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 ;ARR 2.41
+ DW EXIT ;ARR 2.41
+ DW EXIT ;ARR 2.41
+ DW EXIT ;ARR 2.41
+ DW PRN$TILBUSY
+ DW EXIT ;RS 3.20
+ DW EXIT ;RS 3.20
+ DW PRN$GENIOCTL ;RS 3.20
+ DW EXIT ;RS 3.20
+ DW EXIT ;RS 3.20
+ DW EXIT ;RS 3.20
+ DW CMDERR ;RS 3.20
+ DW CMDERR ;RS 3.20
+
+ EVENB
+ PUBLIC OLD13 ;(MOVED HERE FROM IBMBIO2)
+OLD13 label DWORD
+ db '5986' ;J.K. 11/7/86 Secrete Code for DOS 3.30 IBMBIO.
+ PUBLIC ORIG13
+ORIG13 label DWORD
+ db '21',0,0 ;J.K. 11/8/86 This is my employee serial # !!!
+
+ EVENB
+ PUBLIC PTRSAV
+PTRSAV DD 0
+ 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
+PREVOPER DW ? ; HOLDS INT 13 REQUEST (I.E. REGISTER AX).
+NUMBER_OF_SEC DB ? ; HOLDS NUMBER OF SECTORS TO READ ON AN ECC ERROR
+
+ 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
+
+ EVENB
+; WARNING!!! THESE ARE ADDRESSED TOGETHER IN GETDX
+AUXNUM DB 0 ;WHICH AUX DEVICE WAS REQUESTED
+ DB 0
+
+ EVENB
+ PUBLIC CONHEADER
+CONHEADER LABEL WORD ;HEADER FOR DEVICE "CON"
+ DD AUXDEV2
+ DW 1000000000010011B ;CON IN AND CON OUT + SPECIAL
+ DW STRATEGY
+ DW CON$IN
+ DB 'CON '
+
+ EVENB
+ PUBLIC AUXDEV2
+AUXDEV2 LABEL WORD ;HEADER FOR DEVICE "AUX"
+ DD PRNDEV2
+ DW 1000000000000000B
+ DW STRATEGY
+ DW AUX0$IN
+ DB 'AUX '
+
+ EVENB
+ PUBLIC PRNDEV2
+PRNDEV2 LABEL WORD ;HEADER FOR DEVICE "PRN"
+ DD TIMDEV
+ DW CHARDEV + OUTTILBUSY + DEV320
+ DW STRATEGY
+ DW PRN0$IN
+ DB 'PRN '
+
+ EVENB
+ PUBLIC TIMDEV
+TIMDEV LABEL WORD
+ DD DSKDEV
+ DW 1000000000001000B
+ DW STRATEGY
+ DW TIM$IN
+ DB 'CLOCK$ '
+
+ EVENB
+ PUBLIC DSKDEV
+DSKDEV LABEL WORD
+ DD COM1DEV
+ DW 0000100001000010B ;J.K.I1. 32 bit sector calculation
+ DW STRATEGY
+ DW DSK$IN
+DRVMAX DB 4
+ PUBLIC DRVMAX
+
+ PUBLIC STEP_DRV
+STEP_DRV DB -2 ; ARR 2.20 LAST DRIVE ACCESSED
+
+ PUBLIC PHYS_DRV
+PHYS_DRV DB 0 ; USED BY SETDRIVE FOR GETTING BDS FOR
+ ; LOGICAL DRIVE, OR PHYSICAL DRIVE.
+ 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' ;J.K. 11/7/86 Secrete code for DOS 3.30 IBMBIO.
+
+ EVENB
+ PUBLIC COM1DEV
+COM1DEV LABEL WORD
+ DD LPT1DEV
+ DW 1000000000000000B
+ DW STRATEGY
+ DW AUX0$IN
+ DB 'COM1 '
+
+ EVENB
+ PUBLIC LPT1DEV
+LPT1DEV LABEL WORD
+ DD LPT2DEV
+ DW CHARDEV + OUTTILBUSY + DEV320
+ DW STRATEGY
+ DW PRN1$IN
+ DB 'LPT1 '
+
+ EVENB
+ PUBLIC LPT2DEV
+LPT2DEV LABEL WORD
+ DD LPT3DEV
+ DW CHARDEV + OUTTILBUSY + DEV320
+ DW STRATEGY
+ DW PRN2$IN
+ DB 'LPT2 '
+
+ EVENB
+ PUBLIC LPT3DEV
+LPT3DEV LABEL WORD
+ DD COM2DEV
+ DW CHARDEV + OUTTILBUSY + DEV320
+ DW STRATEGY
+ DW PRN3$IN
+ DB 'LPT3 '
+
+ EVENB
+ PUBLIC COM2DEV
+COM2DEV LABEL WORD
+ DD COM3DEV
+ DW 1000000000000000B
+ DW STRATEGY
+ DW AUX1$IN
+ DB 'COM2 '
+
+ EVENB
+ PUBLIC COM3DEV
+COM3DEV LABEL WORD ;EDK
+ DD COM4DEV
+ DW 1000000000000000B
+ DW STRATEGY
+ DW AUX2$IN
+ DB 'COM3 '
+
+ EVENB
+ PUBLIC COM4DEV
+COM4DEV LABEL WORD ;EDK
+ DW -1,CODE
+ DW 1000000000000000B
+ DW STRATEGY
+ DW AUX3$IN
+ DB 'COM4 '
+
+; HARD-WIRE THE LINK TO THE NEXT INT2F HANDLER.
+ EVENB
+ PUBLIC NEXT2F_13
+NEXT2F_13 LABEL WORD
+ EXTRN INT2F_DISK:FAR ;IBMBIO2
+ DD INT2F_DISK
+
+ EVENB
+ PUBLIC START_BDS
+START_BDS LABEL WORD
+ DD BDS1 ;START OF BDS LINKED LIST.
+ PUBLIC ACCESSCOUNT
+ACCESSCOUNT DB 0 ; NUMBER OF TIMES MEDIA CHECK CALLED
+ PUBLIC TIM_DRV
+TIM_DRV DB -1 ; TIME WHEN LAST DISK I/O PERFORMED
+ PUBLIC FLAGBITS
+FLAGBITS DW 0 ; BITS TO SET IN FLAG FIELD WHEN DOING
+ ; A SET_CHANGED_DL
+ PUBLIC MEDBYT
+MEDBYT DB ?
+
+ 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
+ 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
+
+ EVENB
+ PUBLIC DPT
+DPT DD ?
+
+;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 0cch ;AN002; Write Fault error
+ 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 CODES CORRESPONDING TO ABOVE
+ PUBLIC ERROUT
+ERROUT LABEL BYTE
+ db 10 ;AN002; Write Fault error
+ 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
+
+;-------------------------------------------------------------
+
+; READ IN BOOT SECTOR HERE, READ DONE IN READBOOT.
+; ALSO READ SECTOR FOR DMA CHECK FOR HARD DISK.
+
+;J.K. The buffer for a disk sector is going to be at a double word boundary
+; for 80386 machine.
+
+ IF ($-CODE) Mod 4 ;AN001;
+ Org ($-CODE)+4-(($-CODE) Mod 4) ;AN001;
+ ENDIF ;AN001;
+
+ 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 ?
+ public NumberOfFats
+NumberOfFats DB ?
+ DW ?
+ DW ?
+ PUBLIC MEDIABYTE
+MediaByte DB ?
+ DW ?
+ DW ?
+ DW ?
+ DW ?
+ DW ? ;AN000; Extended Hidden sector (high)
+ DW ? ;AN000; Extended Total sector (low)
+ DW ? ;AN000; Extended Total sector (high)
+ db ? ;AN003; PHYDRV in boot record.
+ db ? ;AN003; CURRENT HEAD in boot record.
+ public Ext_Boot_Sig
+Ext_Boot_Sig DB ? ;AN000; Extended Boot record sig. (=90h)
+ public Boot_Serial_L
+Boot_Serial_L DW ? ;AN000; Boot volume serial number (Low)
+ public Boot_Serial_H
+Boot_Serial_H DW ? ;AN000; Boot volume serial number (High)
+ public Boot_Volume_Label
+Boot_Volume_Label DB 11 dup (' ') ;AN000; Volume label
+ public Boot_System_ID
+Boot_System_ID DB 8 dup (' ') ;AN000; File system Id.
+ DB 512-($-DISKSECTOR) DUP (?)
+
+;*********************************************************************
+; "BDS" CONTAINS INFORMATION FOR EACH DRIVE IN THE SYSTEM.
+; VARIOUS VALUES ARE PATCHED WHENEVER ACTIONS ARE PERFORMED.
+; SECTORS/ALLOC. UNIT IN BPB INITIALLY SET TO -1 TO SIGNIFY THAT
+; THE BPB HAS NOT BEEN FILLED. LINK ALSO SET TO -1 TO SIGNIFY END
+; OF LIST. # OF CYLINDERS IN MAXPARMS INITIALIZED TO -1 TO INDICATE
+; THAT THE PARAMETERS HAVE NOT BEEN SET.
+;
+ EVENB
+BDS1 LABEL WORD
+ DD BDS2 ;LINK TO NEXT STRUCTURE
+ DB 0 ;INT 13 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 (low word)
+ dw 0 ;J.K. Hidden sector (high)
+ dw 0 ;J.K. Number sectors (low)
+ dw 0 ;J.K. Number sectors (high)
+ DB 0 ; TRUE => LARGE FATS
+OPCNT1 DW 0 ;OPEN REF. COUNT
+
+ DB 3 ;FORM FACTOR
+FLAGS1 DW 0020H ;VARIOUS FLAGS
+; DB 9 DUP (0) ;RESERVED FOR FUTURE USE
+ DW 40 ; NUMBER OF CYLINDERS
+; RECOMMENDED BPB FOR DRIVE.
+RECBPB1 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(low)
+ dw 0 ;J.K. Hidden sector count (high)
+ dw 0 ;J.K. Number sectors (low)
+ dw 0 ;J.K. Number sectors (high)
+ DB 6 DUP (?)
+TRACK1 DB -1 ;LAST TRACK ACCESSED ON THIS DRIVE
+TIM_LO1 DW -1 ;KEEP THESE TWO CONTIGUOUS (?)
+TIM_HI1 DW -1
+VOLID1 DB "NO NAME ",0 ;VOLUME ID FOR THIS DISK
+VOLSER1 dd 0 ;Current volume serial number from Boot record
+SYSID1 db "FAT12 ",0 ;Current file system id from Boot record
+
+ 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 (low word)
+ dw 0 ;J.K. Hidden sector (high)
+ dw 0 ;J.K. Number sectors (low)
+ dw 0 ;J.K. Number sectors (high)
+ DB 0 ; TRUE => LARGE FATS
+OPCNT2 DW 0 ;OPEN REF. COUNT
+ DB 3 ;FORM FACTOR
+FLAGS2 DW 0020H ;VARIOUS FLAGS
+; DB 9 DUP (0) ;RESERVED FOR FUTURE USE
+ DW 40 ; NUMBER OF CYLINDERS
+; RECOMMENDED BPB FOR DRIVE.
+RECBPB2 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(low)
+ dw 0 ;J.K. Hidden sector count (high)
+ dw 0 ;J.K. Number sectors (low)
+ dw 0 ;J.K. Number sectors (high)
+ DB 6 DUP (?)
+TRACK2 DB -1 ;LAST TRACK ACCESSED ON THIS DRIVE
+TIM_LO2 DW -1 ;KEEP THESE TWO CONTIGUOUS (?)
+TIM_HI2 DW -1
+VOLID2 DB "NO NAME ",0 ;VOLUME ID FOR THIS DISK
+VOLSER2 dd 0 ;Current volume serial number from Boot record
+SYSID2 db "FAT12 ",0 ;Current file system id from Boot record
+
+ 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 (low word)
+ dw 0 ;J.K. Hidden sector (high)
+ dw 0 ;J.K. Number sectors (low)
+ dw 0 ;J.K. Number sectors (high)
+ DB 0 ; TRUE => LARGE FATS
+OPCNT3 DW 0 ;OPEN REF. COUNT
+ DB 3 ;FORM FACTOR
+FLAGS3 DW 0020H ;VARIOUS FLAGS
+; DB 9 DUP (0) ;RESERVED FOR FUTURE USE
+ DW 40 ; NUMBER OF CYLINDERS
+; RECOMMENDED BPB FOR DRIVE.
+RECBPB3 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(low)
+ dw 0 ;J.K. Hidden sector count (high)
+ dw 0 ;J.K. Number sectors (low)
+ dw 0 ;J.K. Number sectors (high)
+ DB 6 DUP (?)
+TRACK3 DB -1 ;LAST TRACK ACCESSED ON THIS DRIVE
+TIM_LO3 DW -1 ;KEEP THESE TWO CONTIGUOUS (?)
+TIM_HI3 DW -1
+VOLID3 DB "NO NAME ",0 ;VOLUME ID FOR THIS DISK
+VOLSER3 dd 0 ;Current volume serial number from Boot record
+SYSID3 db "FAT12 ",0 ;Current file system id from Boot record
+
+ 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 (low word)
+ dw 0 ;J.K. Hidden sector (high)
+ dw 0 ;J.K. Number sectors (low)
+ dw 0 ;J.K. Number sectors (high)
+ DB 0 ; TRUE => LARGE FATS
+OPCNT4 DW 0 ;OPEN REF. COUNT
+ DB 3 ;FORM FACTOR
+FLAGS4 DW 0020H ;VARIOUS FLAGS
+; DB 9 DUP (0) ;RESERVED FOR FUTURE USE
+ DW 40 ; NUMBER OF CYLINDERS
+; RECOMMENDED BPB FOR DRIVE.
+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(low)
+ dw 0 ;J.K. Hidden sector count (high)
+ dw 0 ;J.K. Number sectors (low)
+ dw 0 ;J.K. Number sectors (high)
+ DB 6 DUP (?)
+TRACK4 DB -1 ;LAST TRACK ACCESSED ON THIS DRIVE
+TIM_LO4 DW -1 ;KEEP THESE TWO CONTIGUOUS (?)
+TIM_HI4 DW -1
+VOLID4 DB "NO NAME ",0 ;VOLUME ID FOR THIS DISK
+VOLSER4 dd 0 ;Current volume serial number from Boot record
+SYSID4 db "FAT12 ",0 ;Current file system id from Boot record
+
+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>
+
+;-----------------------------------------------
+;
+; C O N - CONSOLE DEVICE DRIVER
+;
+ PUBLIC ALTAH
+ALTAH DB 0 ;SPECIAL KEY HANDLING
+ public KEYRD_Func
+KEYRD_Func DB 0 ;AN000; Default is conventional keyboard read
+ public KEYSTS_Func
+KEYSTS_Func DB 1 ;AN000; Defualt if conventional keyboard status check.
+
+; PUBLIC SAV_SC_INFO ;J.K. 4/29/86 FOR CON$GENIOCTL
+; PUBLIC SAV_SC_MODE
+; PUBLIC SAV_SC_COLORS
+; PUBLIC SAV_SC_WIDTH
+; PUBLIC SAV_SC_LENGTH
+;SAV_SC_INFO LABEL BYTE
+;SAV_SC_MODE DB 0
+;SAV_SC_COLORS DW 0
+;SAV_SC_WIDTH DW 0
+;SAV_SC_LENGTH DW 0 ;J.K. 4/29/86 FOR CON$GENIOCTL
+
+;-------------------------------------------------------------
+;
+; P R N - PRINTER DEVICE
+;
+ PUBLIC PRINTDEV
+PRINTDEV DB 0 ; INDEX INTO ABOVE ARRAY
+
+; 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.
+
+ EVENB
+ PUBLIC WAIT_COUNT
+WAIT_COUNT DW 4 DUP (50H) ; ARRAY OF RETRY COUNTS FOR PRINTER
+
+ EVENB
+ PUBLIC DAYCNT
+DAYCNT DW 0
+
+
+ IF iTEST ;Testing Mode for IBMBIO.
+ PUBLIC NUMBUF
+NUMBUF DB 5 DUP (?)
+ PUBLIC DIGITS
+DIGITS DB "0123456789ABCDEF"
+ PUBLIC FTESTBITS
+;FTESTBITS DW FTESTDISK+FTESTINIT
+FTESTBITS DW fTestDISK
+;ftestbits dw ftestclock
+ ENDIF
+
+ PATHEND 001,BIO
+
\ No newline at end of file
diff --git a/v4.0/src/BIOS/MSBIO.LNK b/v4.0/src/BIOS/MSBIO.LNK
new file mode 100644
index 0000000..d1a15bd
--- /dev/null
+++ b/v4.0/src/BIOS/MSBIO.LNK
@@ -0,0 +1,14 @@
+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/v4.0/src/BIOS/MSBIO.SKL b/v4.0/src/BIOS/MSBIO.SKL
new file mode 100644
index 0000000..9c890df
--- /dev/null
+++ b/v4.0/src/BIOS/MSBIO.SKL
@@ -0,0 +1,139 @@
+;==============================================================================
+;REVISION HISTORY:
+;AN000 - New for DOS Version 4.0 - J.K.
+;AC000 - Changed for DOS Version 4.0 - J.K.
+;AN00x - PTM number for DOS Version 4.0 - J.K.
+;==============================================================================
+;==============================================================================
+;AN001 D246, P976 Show "Bad command or parameters - ..." msg 9/22/87 J.K.
+;AN002 D274 Take "file" out from "Incorrect order..." msg 10/07/87 J.K.
+;AN003 D486 Share installation for large media 02/24/88 J.K.
+;==============================================================================
+;===================
+:class 1
+;===================
+; MESSAGES FOR THE IBM BOOT SECTOR. NUL Terminated.
+; This is used by IBMBOOT and IBMLOAD program and it stays in IBMBOOT directory.
+
+;For IBMLOAD program
+;SYSMSG DB 13,10,"Non-System disk or disk error",13,10
+; DB "Replace and strike any key when ready",13,10,0
+:use 001 BOOT SYSMSG
+
+;===================
+:class 2
+;===================
+; SCCSID = @(#)biomes.asm 1.2 85/07/25
+; SINGLE DRIVE MESSAGE FOR IBMBIO.COM. 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
+
+
+:def 20 SNGMSG DB 13,10,"Insert diskette for drive "
+:def 21 DRVLET DB "A: and strike",13,10,"any key when ready",13,10,10,0
+
+; PATHEND 001,BIOMS
+
+;==================
+:class 3
+;==================
+
+; PRINTED when there is a bad command in CONFIG.SYS. '$' TERMINATED, note
+; that this message includes crlfm!
+;PATHSTART 001,SYSMES
+
+:def 03 BADOPM DB 13,10,"Unrecognized command in CONFIG.SYS"
+
+;BADSIZ_POST LABEL BYTE
+;BADLD_POST LABEL BYTE
+
+:def 04 CRLFM DB 13,10,'$'
+
+:def 22 BadParm db 13,10,"Bad command or parameters - $" ;AN001;
+
+;PRINTED when installed device specifies too large a sector size.'$' terminated.
+; FORM: device name
+:def 05 BADSIZ_PRE DB 13,10,"Sector size too large in file $"
+
+;PRINTED when installed device cannot be found. '$' terminated.
+; FORM: device name
+:def 06 BADLD_PRE DB 13,10,"Bad or missing $"
+
+;PRINTED when command interpreter is not found. NUL terminated.
+; FORM:
+:def 07 BADCOM DB "Command Interpreter",0
+
+;PRINTED when country code, code page combination was not found in country.sys file. '$' terminated.
+; FORM:
+:def 08 BADCOUNTRY DB 13,10,"Invalid country code or code page",13,10,"$"
+
+;PRINTED when code page id is missing or wrong syntax. - J.K.
+; FORM:
+:def 09 BADCOUNTRYCOM DB 13,10,"Error in COUNTRY command",13,10,"$"
+
+;PRINTED when the memory left is not sufficient to handle COUTRY.SYS file
+; FORM:
+:def 10 INSUFMEMORY DB 13,10, "Insufficient memory for COUNTRY.SYS file",13,10,"$"
+
+; PRINTED when there is insufficient memory. '$' TERMINATED, note
+; that this message includes crlfm!
+:def 11 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'
+:def 12 BADBLOCK DB 13,10,"Too many Block Devices",13,10,"$"
+
+; PRINTED when the attempt is made to install a stack with invalid
+; combinations of # of stacks, stack size. - J.K. 5/23/86
+:def 13 BADSTACK DB 13,10,"Invalid STACK parameters",13,10,"$"
+
+;AN000; - PRINTED when encountering a command that is not "install=" after
+; we had a "Install=" command. - J.K.I1.
+; Translation::: Please leave the last blank space at the end of the line
+; as it is.
+:def 14 BADORDER DB 13,10,"Incorrect order in CONFIG.SYS line ","$"
+
+;AN000; - PRINTED when the command failed.
+; Translation::: Please leave the last blank space at the end of the line
+; as it is.
+:def 15 ERRORCMD DB "Error in CONFIG.SYS line ","$"
+
+;AN003; - PRINTED when SHARE.EXE is not loaded and has a large media > 32 MB.
+:def 23 SHAREWARNMSG db "WARNING! SHARE should be loaded for large media",13,10,"$"
+
+;==================
+:class 4
+;==================
+;IBMBIO SYSINIT
+;Message for SYSINIT_BASE program.
+:def 16 Mem_alloc_err db 13,10,"Memory allocation error","$"
+
+
+;==================
+:class 5
+;==================
+; %OUT STKMES.INC...
+; SCCSID = @(#)stkmes.inc 1.0 86/10/21
+
+; PUBLIC FATAL_MSG
+:def 17 FATAL_MSG DB 0DH,0AH,7,0DH,0AH
+ DB "Internal stack overflow",0DH,0AH
+ DB "System halted",0DH,0AH,"$"
+;
+:END
+
diff --git a/v4.0/src/BIOS/MSBIO1.ASM b/v4.0/src/BIOS/MSBIO1.ASM
new file mode 100644
index 0000000..36dac91
--- /dev/null
+++ b/v4.0/src/BIOS/MSBIO1.ASM
@@ -0,0 +1,645 @@
+
+ PAGE ,132 ;
+ TITLE MSBIO1.asm - BIOS
+;==============================================================================
+;REVISION HISTORY:
+;AN000 - New for DOS Version 4.00 - J.K.
+;AC000 - Changed for DOS Version 4.00 - J.K.
+;AN00x - PTM number for DOS Version 4.00 - J.K.
+;==============================================================================
+COMMENT *
+THE LINK STEP IS PERFORMED BY USING THE FOLLOWING "NEW.ARF" FILE:
+msbio1+
+msSTACK+
+MsCON+
+msAUX+
+msLPT+
+msCLOCK+
+msdISK+
+msBIO2+
+C:\BIO2\OLDOBJ\disk+
+C:\BIO2\OLDOBJ\msinit+
+C:\BIO2\OLDOBJ\sysinit1+
+C:\BIO2\OLDOBJ\sysinit2+
+C:\BIO2\OLDOBJ\sysimes,msbio,/M;
+
+THE FOLLOWING IS A BATCH FILE THAT CAN BE USED TO CREATE THE IBMBIO.COM
+WHERE "LOCSCR" IS A FILE THAT JUST HAS THE NUMBER, 70:
+
+link @NEW.ARF
+exe2bin ibmbio ibmbio.com 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 ;J.K. - 4/9/86
+ 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
+;SB33002*******************************************************
+ MOV AH, 0Eh ;SET COMMAND TO WRITE A CHAR ;SB;3.30*
+ MOV BX, 7 ;SET FOREGROUND COLOR ;SB;3.30*
+ INT 10h ;CALL ROM-BIOS ;SB;3.30*
+;SB33002*******************************************************
+ POP BX
+ POP BP
+ POP DI
+ POP SI
+ POP AX
+ RET
+Outchar endp
+
+ ENDIF
+ INCLUDE MSMACRO.INC
+
+;---------------------------------------------------
+;
+; 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
+EXTRA = 22 ;USUALLY A POINTER TO VOL ID FOR ERROR 15
+START_L = 26 ;AN000; Extended start sector (Low)
+START_H = 28 ;AN000; Extended start sector (High)
+
+ PUBLIC STRATEGY
+STRATEGY PROC FAR
+ MOV WORD PTR CS:[PTRSAV],BX
+ MOV WORD PTR CS:[PTRSAV+2],ES
+ RET
+STRATEGY ENDP
+
+ 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 ;J.K. 4/15/86
+AUX1$IN ENDP
+
+;SB33102****************************************************************
+;SB Add code to handle two more COM Ports
+;boban
+
+ 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
+
+;SB33102****************************************************************
+
+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 INTO ARRAY OF RETRY COUNTS
+ 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
+
+ENTRY:
+ PUSH AX
+ENTRY1:
+ PUSH CX
+ 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
+
+;SB34MSB100*********************************************************************
+;SB
+;SB The disk device driver can now handle 32 bit start sector number.
+;SB So we should check to see if a 32 bit sector number has been specified
+;SB and if so get it. Whether a 32 bit sector has been specified or not
+;SB the disk driver expects a 32 bit sector number with the high word
+;SB in cs:Start_Sec_H and the low word in dx.
+;SB
+;SB Algorithm:
+;SB 1. Check to see if the request is for the disk driver by
+;SB checking to see if SI points to DSKTBL.
+;SB
+;SB 2. If request not for the disk nothing special needs to be done.
+;SB
+;SB 3. If request for the disk then check to see if a 32 bit
+;SB sector number has been specified by seeing whether the
+;SB the conventional sector number specified is -1. If so
+;SB we need to pick the 32 bit sector number from the new
+;SB fields in the request packet. See the request header
+;SB struc for the fields you need. If the conventional
+;SB sector field is not -1 then a 16 bit sector number
+;SB has been specified and we just need to initalise the
+;SB high word in cs:Start_Sec_H to 0
+;SB
+;SB NOTE: START_L and START_H are the offsets withing the IO_REQUEST packet
+;SB which contain the low and hi words of the 32 bit start sector if
+;SB it has been used.
+;SB
+;SB NOTE:Remember not to destroy the registers which have been set up before
+
+ CMP SI,OFFSET DSKTBL
+ JNZ DSK_REQ_CONT ; Not Disk Req
+ CMP DX,-1
+ JNZ DSK_REQ_16
+ MOV DX,DS:[BX].START_H ; 32 bits DSK REQ
+ MOV CS:START_SEC_H,DX ; CS:Start_sec_H = Packet.Start_H
+ MOV DX,DS:[BX].START_L ; DX = Packet.Start_L
+ JMP SHORT DSK_REQ_CONT
+DSK_REQ_16:
+ MOV CS:START_SEC_H,0
+DSK_REQ_CONT:
+
+;SB34MSB100*********************************************************************
+
+ XCHG DI,AX
+ MOV AL,BYTE PTR DS:[BX].CMD
+ CMP AL,CS:[SI] ;ARR 2.41
+ JA CMDERR
+
+ CBW ; NOTE THAT AL <= 15 MEANS OK
+ SHL AX,1
+
+ ADD SI,AX
+ XCHG AX,DI
+
+ LES DI,DWORD PTR DS:[BX].TRANS
+
+ PUSH CS
+ POP DS
+
+ ASSUME DS:CODE
+
+ CLD
+ JMP WORD PTR [SI+1] ;GO DO COMMAND
+DSK$IN ENDP
+ PAGE
+;=====================================================
+;=
+;= SUBROUTINES SHARED BY MULTIPLE DEVICES
+;=
+;=====================================================
+;----------------------------------------------------------
+;
+; EXIT - ALL ROUTINES RETURN THROUGH THIS PATH
+;
+ PUBLIC BUS$EXIT
+BUS$EXIT PROC FAR
+ ASSUME DS:NOTHING
+ MOV AH,00000011B
+ 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 RETURN
+ JMP SHORT ERR1
+BUS$EXIT ENDP
+
+EXITP PROC FAR
+ ASSUME DS:CODE ; WE ARE NOT SURE THIS IS CORRECT 3/18/86
+EXIT$ZER:
+ LDS BX,[PTRSAV]
+ ASSUME DS:NOTHING
+ XOR AX,AX
+ MOV WORD PTR [BX].COUNT,AX ;INDICATE NO CHARS 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
+ POP ES
+ POP DS
+ POP BP
+ POP DI
+ POP DX
+ POP CX
+ POP AX
+ POP SI
+ RET ;RESTORE REGS AND RETURN
+EXITP ENDP
+
+;-------------------------------------------------------------
+;
+; CHROUT - WRITE OUT CHAR IN AL USING CURRENT ATTRIBUTE
+;
+; CALLED VIA INT 29H
+;
+ PUBLIC CHROUT
+CHROUT = 29H
+
+ PUBLIC OUTCHR
+OUTCHR PROC FAR
+ PUSH AX
+ PUSH SI
+ PUSH DI
+ PUSH BP
+;SB33002a*******************************************************
+ push bx ; ;SB ;3.30
+ mov AH, 0Eh ; set command to write a character;SB;3.30
+ mov BX, 7 ; set foreground color ;SB ;3.30
+ int 10h ; call rom-bios ;SB ;3.30
+ pop bx ; ;SB ;3.30
+;SB33002a*******************************************************
+ POP BP
+ POP DI
+ POP SI
+ POP AX
+ IRET
+OUTCHR ENDP
+;----------------------------------------------
+;
+; SET DX TO AUXNUM
+;
+ PUBLIC GETDX
+GETDX PROC NEAR
+ MOV DX,WORD PTR CS:[AUXNUM]
+ RET
+GETDX ENDP
+ PAGE
+;************************************************** ARR 2.15
+
+;-----------------------------------------------
+;
+; TIMER INTERRUPT HANDLER
+;
+;TIMER_LOW DW 0
+;TIMER_HIGH DW 0
+;
+;TIMER:
+; STI
+; PUSH AX
+; PUSH CX
+; PUSH DX
+; PUSH DS
+; PUSH CS
+; POP DS
+; XOR AX,AX
+; INT 1AH ; GET ROM TIME AND ZAP ROLL OVER
+; MOV [TIMER_HIGH],CX
+; MOV [TIMER_LOW],DX
+; OR AL,AL
+; JZ T5
+; INC WORD PTR [DAYCNT] ; ONE DAY GONE BY
+;T5:
+; POP DS
+; POP DX
+; POP CX
+; POP AX
+; IRET
+;************************************************** ARR 2.15
+CODE ENDS
+ END
diff --git a/v4.0/src/BIOS/MSBIO2.ASM b/v4.0/src/BIOS/MSBIO2.ASM
new file mode 100644
index 0000000..50b25bc
--- /dev/null
+++ b/v4.0/src/BIOS/MSBIO2.ASM
@@ -0,0 +1,572 @@
+ PAGE ,132 ;
+ TITLE MSBIO2 - BIOS
+
+ %OUT ...MSBIO2.ASM
+
+;==============================================================================
+;REVISION HISTORY:
+;AN000 - New for DOS Version 4.00 - J.K.
+;AC000 - Changed for DOS Version 4.00 - J.K.
+;AN00x - PTM number for DOS Version 4.00 - J.K.
+;==============================================================================
+;AN001; - P1820 New Message SKL file 10/20/87 J.K.
+;AN002; - P5045 New INT 2fh for Get BDS table vector for EMS 06/06/88 J.K.
+;==============================================================================
+
+ROMSEGMENT EQU 0F000H
+MODELBYTE EQU DS:BYTE PTR [0FFFEH]
+MODELPCJR EQU 0FDH
+
+ itest=0
+
+ 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 READ_SECTOR:NEAR
+ EXTRN INT_2F_13:FAR
+
+ EXTRN OLD13:DWORD
+
+;DATA
+ EXTRN PTRSAV:DWORD ;IBMBIO1
+ 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
+ extrn Ext_Boot_Sig:byte ;AN000; ibmbdata
+ extrn SecPerClusInSector:byte ;AN000; ibmbdata
+ extrn Boot_Serial_L:word ;AN000; ibmbdata
+ extrn Boot_Serial_H:word ;AN000; ibmbdata
+
+ PATHSTART 005,DISK
+ EVENB
+ public Model_Byte
+MODEL_BYTE DB 0FFH ; MODEL BYTE. SET UP AT INIT TIME.
+ ; FF - PC1
+ ; FE - XT (64/256K PLANAR)
+ ; FD - PC-JR
+ ; FC - PC/AT
+ public Secondary_Model_Byte
+Secondary_Model_Byte db 0
+
+ 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 hardware int. vectors 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 *** J.K. 4/7/86
+;* Don't change this position. Should be addressible from DskDrvs *** J.K. 4/7/86
+MINI_DISK_BPB_PTRS DB 40 dup (?) ;J.K. 4/7/86 - memory reserved for Mini disk.
+
+ EVENB
+ PUBLIC INT_2F_NEXT
+INT_2F_NEXT DD ?
+
+RET_ADDR DD ?
+
+ PATHEND 005,DISK
+; = = = = = = = = = = = = = = = = = = = =
+
+; INT19
+;
+; WE "HOOK" THE INT 19 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_19.
+; CURRENTLY THE ONLY VECTORS THAT NEED TO BE UNHOOKED ARE INT_19, INT_13,
+; AND THE HARDWARE INTERRUPTS.
+;
+ PUBLIC INT19
+INT19 PROC FAR
+ XOR AX,AX
+ MOV DS,AX
+ assume ds:nothing
+ assume es:nothing
+
+ LES DI,OLD13
+ MOV DS:[13H*4],DI
+ MOV DS:[13H*4+2],ES
+
+ CMP BYTE PTR INT19SEM, 0
+ JNZ INT19VECS
+ JMP DOINT19
+
+; ON THE PCJR, DON'T REPLACE ANY VECTORS
+; MODEL BYTE DEFINITIONS FROM IBMSTACK.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:
+ 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
+;SB33103******************************************************************
+
+ mov ax,es ;
+ cmp ax,-1 ;OPT 0ffffh is unlikely segment
+ je skip_int&AA ;OPT no need to check selector too
+ cmp di,-1 ;OPT 0ffffh is unlikely offset
+ je skip_int&AA
+
+;SB33103******************************************************************
+ MOV DS:[AA&H*4],DI
+ MOV DS:[AA&H*4+2],ES
+skip_int&AA:
+ ENDM
+
+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 IBMDISK. 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 IBMBIO) MUCH EASIER,
+; SINCE WE ONLY NEED TO MAKE CHANGES IN ONE PLACE (MOST OF THE TIME).
+;
+; 06/03/88 J.K. When AL=3, return DS:DI -> Start of BDS table.
+; (EMS device driver hooks INT 13h to handle 16KB DMA overrun
+; problem. BDS table is going to be used to get head/sector
+; informations without calling Generic IOCTL Get Device Parm call.)
+;
+; AL CONTAINS THE INT2F FUNCTION:
+; 0 - CHECK FOR INSTALLED HANDLER - RESERVED
+; 1 - INSTALL THE BDS INTO THE LINKED LIST
+; 2 - DOS REQUEST
+; 3 - Get BDS vector ;06/03/88 J.K.
+; Return BDS table starting pointer in DS:DI
+
+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
+ cmp al, 3 ;AN002; Get BDS vector?
+ je DO_Get_BDS_Vector ;AN002;
+ MOV WORD PTR CS:[PTRSAV],BX ;othrwise DOS function.
+ MOV WORD PTR CS:[PTRSAV+2],ES
+ JMP DSK$IN
+
+DO_Get_BDS_Vector: ;AN002; AL=3
+ push cs ;AN002;
+ pop ds ;AN002;
+ mov di, Start_BDS ;AN002;
+ IRET ;AN002;
+
+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
+
+;
+; THE FOLLOWING TWO LINES ARE NOT NEEDED ANYMORE BECAUSE THE LINK HAS BEEN
+; HARD-WIRED INTO THE CODE AT NEXT2F_13. - RAJEN.
+;------------------------------------------------------------------------------
+; MOV WORD PTR CS:[NEXT2F_13],OFFSET INT2F_DISK ; PRESERVE INT2F_DISK POINTER
+; MOV WORD PTR CS:[NEXT2F_13+2],CS
+;------------------------------------------------------------------------------
+
+ 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:
+;
+ PUBLIC SWPDSK
+SWPDSK PROC NEAR
+ MOV AL,BYTE PTR DS:[DI].DRIVELET ; GET THE DRIVE LETTER
+;USING A DIFFERENT DRIVE IN A ONE DRIVE SYSTEM SO REQUEST THE USER CHANGE DISKS
+ 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
+;SB33003***************************************************************
+ xor AH, AH ; set command to read character;SB
+ int 16h ; call rom-bios ;SB
+;SB33003***************************************************************
+ POP BX
+ POP DS ; RESTORE SEGMENT REGISTER
+WRMRET:
+ RET
+SWPDSK ENDP
+
+;----------------------------------------------
+;
+; WRITE OUT MESSAGE POINTED TO BY [SI]
+;
+ PUBLIC WRMSG
+WRMSG PROC NEAR
+ LODSB ;GET THE NEXT CHARACTER OF THE MESSAGE
+ OR AL,AL ;SEE IF END OF MESSAGE
+ JZ WRMRET
+; INT CHROUT
+ PUSHF
+ PUSH CS
+ CALL OUTCHR
+ JMP SHORT WRMSG
+WRMSG ENDP
+
+; INCLUDE BIOMES.INC
+ include MSBIO.CL2
+
+;
+; 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.
+;
+
+;J.K. 10/1/86 *******************************************************
+;Variables for Dynamic Relocatable modules
+;These should be stay resident.
+
+ public INT6C_RET_ADDR
+INT6C_RET_ADDR DD ? ; return address from INT 6C for P12 machine
+
+ 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 DECEMBER
+DAYCNT2 DW 0000 ;MJB002 TEMP FOR COUNT OF DAYS SINCE 1-1-80
+FEB29 DB 0 ;MJB002 FEBRUARY 29 IN A LEAP YEAR FLAG
+ PATHEND 001,CLK
+
+;********************************************************************
+;
+
+ 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 HARDFILES
+ 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 80 ;INT 13 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(low)
+ dw 00 ;AN000; Hidden Sector (high)
+ dw 00 ;AN000; Number of Sectors (low)
+ dw 00 ;AN000; Number of Sectors (high)
+ DB 0 ; TRUE => BIGFAT
+OPCNTH DW 0 ;OPEN REF. COUNT
+ DB 3 ;FORM FACTOR
+FLAGSH DW 0020H ;VARIOUS FLAGS
+; DB 9 DUP (0) ;RESERVED FOR FUTURE USE
+ 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
+VOLIDH DB "NO NAME ",0 ;AN000; VOLUME ID FOR THIS DISK
+VolSerH dd 0 ;AN000; Current volume serial number from Boot record
+SysIDH db "FAT12 " ,0 ;AN000; Current file system id from Boot record
+
+;
+; 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 81 ;INT 13 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 (low)
+ dw 00 ;AN000; Hidden Sector (high)
+ dw 00 ;AN000; Number of Sectors (low)
+ dw 00 ;AN000; Number of Sectors (high)
+ DB 0 ; TRUE => BIGFAT
+OPCNTD DW 0 ;OPEN REF. COUNT
+ DB 3 ;FORM FACTOR
+FLAGSD DW 0020H ;VARIOUS FLAGS
+; DB 9 DUP (0) ;RESERVED FOR FUTURE USE
+ 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
+VOLIDD DB "NO NAME ",0 ;AN000; VOLUME ID FOR THIS DISK
+VolSerD dd 0 ;AN000; Current volume serial number from Boot record
+SysIDD db "FAT12 " ,0 ;AN000; Current file system id from Boot record
+
+;
+; END OF SECTION FOR TWO HARD DISKS
+ PUBLIC ENDTWOHARD
+ENDTWOHARD LABEL BYTE
+
+ PATHEND 004,BIO
+
+ PUBLIC TWOHARD
+TWOHARD LABEL BYTE
+ PAGE
+ INCLUDE MS96TPI.INC
+
+;*********************************************************************
+;Memory allocation for BDSM table. - J.K. 2/21/86
+;*********************************************************************
+ PUBLIC BDSMs
+BDSMs BDSM_type Max_mini_dsk_num dup (<>) ;currently max. 23
+
+;** End_of_BDSM defined in IBMINIT.ASM will be used to set the appropriate
+;** ending address of BDSM table.
+
+;
+;;3.3 BUG FIX -SP ------------------------------
+;;Migrated into 4.00 -MRW
+;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/v4.0/src/BIOS/MSCLOCK.ASM b/v4.0/src/BIOS/MSCLOCK.ASM
new file mode 100644
index 0000000..5d66d03
--- /dev/null
+++ b/v4.0/src/BIOS/MSCLOCK.ASM
@@ -0,0 +1,296 @@
+ TITLE MSCLOCK - DOS 3.3
+;----------------------------------------------------------------
+; :
+; CLOCK DEVICE DRIVER :
+; :
+; :
+; This file contains the Clock Device Driver. :
+; :
+; The routines in this files are: :
+; :
+; routine function :
+; ------- -------- :
+; TIM$WRIT Set the current time :
+; TIM$READ Read the current time :
+; Time_To_Ticks Convert time to corresponding :
+; number of clock ticks :
+; :
+; The clock ticks at the rate of: :
+; :
+; 1193180/65536 ticks/second (about 18.2 ticks per second):
+; See each routine for information on the use. :
+; :
+;----------------------------------------------------------------
+
+
+ itest=0
+ INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT
+ INCLUDE MSMACRO.INC
+
+ EXTRN EXIT:NEAR
+;
+; DAYCNT is the number of days since 1-1-80.
+; Each time the clock is read it is necessary to check if another day has
+; passed. The ROM only returns the day rollover once so if it is missed
+; the time will be off by a day.
+;
+ EXTRN DAYCNT:WORD ;MSDATA
+
+;;Rev 3.30 Modification ------------------------------------------------
+; variables for real time clock setting
+ public HaveCMOSClock
+HaveCMOSClock db 0 ;set by MSINIT.
+ public base_century
+base_century db 19
+ public base_year
+base_year db 80
+ public month_tab
+month_tab db 31,28,31,30,31,30,31,31,30,31,30,31
+
+; The following are indirect intra-segment call addresses. The
+;procedures are defined in MSINIT for relocation. MSINIT will set these
+;address when the relocation is done.
+ public BinToBCD
+BinToBCD dw 0 ;should point to Bin_To_BCD proc in MSINIT
+ public DaycntToDay
+DaycntToDay dw 0 ;should point to Daycnt_to_day in MSINIT
+
+;********************************************************************
+; Indirect call address of TIME_TO_TICKS procedure.
+;This will be used by the relocatable portable suspend/resume code.
+
+ public TimeToTicks
+TimeToTicks dw Time_To_Ticks
+
+;;End of Modification ------------------------------------------------
+
+;--------------------------------------------------------------------
+;
+; Settime sets the current time
+;
+; On entry ES:[DI] has the current time:
+;
+; number of days since 1-1-80 (WORD)
+; minutes (0-59) (BYTE)
+; hours (0-23) (BYTE)
+; hundredths of seconds (0-99) (BYTE)
+; seconds (0-59) (BYTE)
+;
+; Each number has been checked for the correct range.
+;
+ PUBLIC TIM$WRIT
+TIM$WRIT PROC NEAR
+ ASSUME DS:CODE
+ mov AX,WORD PTR ES:[DI]
+ push AX ;DAYCNT. We need to set this at the very
+ ; end to avoid tick windows.
+;;Rev 3.30 Modification
+ cmp HaveCMOSClock, 0
+ je No_CMOS_1
+ mov al,es:[di+3] ;get binary hours
+ call BinToBCD ;convert to BCD
+ mov ch,al ;CH = BCD hours
+ mov al,es:[di+2] ;get binary minutes
+ call BinToBCD ;convert to BCD
+ mov cl,al ;CL = BCD minutes
+ mov al,es:[di+5] ;get binary seconds
+ call BinToBCD ;convert to BCD
+ mov dh,al ;DH = BCD seconds
+ mov dl,0 ;DL = 0 (ST) or 1 (DST)
+ cli ;turn off timer
+ mov ah,03h ;set RTC time
+ int 1Ah ;call rom bios clock routine
+ sti
+
+;;End of Modification
+No_CMOS_1:
+ mov CX,WORD PTR ES:[DI+2]
+ mov DX,WORD PTR ES:[DI+4]
+;;Rev 3.30 Modification
+ call time_to_ticks ; convert time to ticks
+ ;CX:DX now has time in ticks
+ cli ; Turn off timer
+ mov AH, 1 ; command is set time in clock
+ int 1Ah ; call rom-bios clock routines
+ pop [DAYCNT]
+ sti
+;CMOS clock -------------------------------------
+ cmp HaveCMOSClock, 0
+ je No_CMOS_2
+ call DaycntToDay ; convert to BCD format
+ cli ; Turn off timer
+ mov AH,05h ; set RTC date
+ int 1Ah ; call rom-bios clock routines
+ sti
+;------------------------------------------------
+
+No_CMOS_2:
+ jmp EXIT
+TIM$WRIT ENDP
+;;End of Modification
+
+
+
+;
+; convert time to ticks
+; input : time in CX and DX
+; ticks returned in CX:DX
+;
+public time_to_ticks
+TIME_TO_TICKS PROC NEAR
+
+ ; first convert from Hour,min,sec,hund. to
+ ; total number of 100th of seconds
+ mov AL,60
+ mul CH ;Hours to minutes
+ mov CH,0
+ add AX,CX ;Total minutes
+ mov CX,6000 ;60*100
+ mov BX,DX ;Get out of the way of the multiply
+ mul CX ;Convert to 1/100 sec
+ mov CX,AX
+ mov AL,100
+ mul BH ;Convert seconds to 1/100 sec
+ add CX,AX ;Combine seconds with hours and min.
+ adc DX,0 ;Ripple carry
+ mov BH,0
+ add CX,BX ;Combine 1/100 sec
+ adc DX,0
+
+;;Rev 3.30 Modification
+;DX:CX IS TIME IN 1/100 SEC
+ XCHG AX,DX
+ XCHG AX,CX ;NOW TIME IS IN CX:AX
+ MOV BX,59659
+ MUL BX ;MULTIPLY LOW HALF
+ XCHG DX,CX
+ XCHG AX,DX ;CX->AX, AX->DX, DX->CX
+ MUL BX ;MULTIPLY HIGH HALF
+ ADD AX,CX ;COMBINE OVERLAPPING PRODUCTS
+ ADC DX,0
+ XCHG AX,DX ;AX:DX=TIME*59659
+ MOV BX,5
+ DIV BL ;DIVIDE HIGH HALF BY 5
+ MOV CL,AL
+ MOV CH,0
+ MOV AL,AH ;REMAINDER OF DIVIDE-BY-5
+ CBW
+ XCHG AX,DX ;USE IT TO EXTEND LOW HALF
+ DIV BX ;DIVDE LOW HALF BY 5
+ MOV DX,AX
+ ; CX:DX is now number of ticks in time
+ ret
+TIME_TO_TICKS ENDP
+;;End of Modification
+
+
+;
+; Gettime reads date and time
+; and returns the following information:
+;
+; ES:[DI] =count of days since 1-1-80
+; ES:[DI+2]=hours
+; ES:[DI+3]=minutes
+; ES:[DI+4]=seconds
+; ES:[DI+5]=hundredths of seconds
+;
+ PUBLIC TIM$READ
+TIM$READ PROC NEAR
+ ; read the clock
+ xor AH, AH ; set command to read clock
+ int 1Ah ; call rom-bios to get time
+
+ or al,al ; check for a new day
+ jz noroll1 ; if al=0 then don't reset day count
+ INC [DAYCNT] ; CATCH ROLLOVE
+noroll1:
+ MOV SI,[DAYCNT]
+
+;
+; we now need to convert the time in tick to the time in 100th of
+; seconds. The relation between tick and seconds is:
+;
+; 65536 seconds
+; ----------------
+; 1,193,180 tick
+;
+; To get to 100th of second we need to multiply by 100. The equation is:
+;
+; Ticks from clock * 65536 * 100
+; --------------------------------- = time in 100th of seconds
+; 1,193,180
+;
+; Fortunately this fromula simplifies to:
+;
+; Ticks from clock * 5 * 65,536
+; --------------------------------- = time in 100th of seconds
+; 59,659
+;
+; The calculation is done by first multipling tick by 5. Next we divide by
+; 59,659. In this division we multiply by 65,536 by shifting the dividend
+; my 16 bits to the left.
+;
+; start with ticks in CX:DX
+; multiply by 5
+ MOV AX,CX
+ MOV BX,DX
+ SHL DX,1
+ RCL CX,1 ;TIMES 2
+ SHL DX,1
+ RCL CX,1 ;TIMES 4
+ ADD DX,BX
+ ADC AX,CX ;TIMES 5
+ XCHG AX,DX
+
+
+; now have ticks * 5 in DX:AX
+; we now need to multiply by 65,536 and divide by 59659 d.
+
+ mov CX,59659 ; get divisor
+ div CX
+ ; DX now has remainder
+ ; AX has high word of final quotient
+ mov BX,AX ; put high work if safe place
+ xor AX,AX ; this is the multiply by 65536
+ div CX ; BX:AX now has time in 100th of seconds
+
+;
+;Rounding based on the remainder may be added here
+;The result in BX:AX is time in 1/100 second.
+ mov DX,BX
+ mov CX,200 ;Extract 1/100's
+;Division by 200 is necessary to ensure no overflow--max result
+;is number of seconds in a day/2 = 43200.
+ div CX
+ cmp DL,100 ;Remainder over 100?
+ jb NOADJ
+ sub DL,100 ;Keep 1/100's less than 100
+NOADJ:
+ cmc ;If we subtracted 100, carry is now set
+ mov BL,DL ;Save 1/100's
+;To compensate for dividing by 200 instead of 100, we now multiply
+;by two, shifting a one in if the remainder had exceeded 100.
+ rcl AX,1
+ mov DL,0
+ rcl DX,1
+ mov CX,60 ;Divide out seconds
+ div CX
+ mov BH,DL ;Save the seconds
+ div CL ;Break into hours and minutes
+ xchg AL,AH
+
+;Time is now in AX:BX (hours, minutes, seconds, 1/100 sec)
+
+ push AX
+ MOV AX,SI ; DAYCNT
+ stosw
+ pop AX
+ stosw
+ mov AX,BX
+ stosw
+ jmp EXIT
+
+TIM$READ ENDP
+CODE ENDS
+ END
+
\ No newline at end of file
diff --git a/v4.0/src/BIOS/MSCON.ASM b/v4.0/src/BIOS/MSCON.ASM
new file mode 100644
index 0000000..68fcfff
--- /dev/null
+++ b/v4.0/src/BIOS/MSCON.ASM
@@ -0,0 +1,328 @@
+ PAGE ,132 ;
+ TITLE MSCON - BIOS
+ %OUT ...MSCON.ASM
+;==============================================================================
+;REVISION HISTORY:
+;AN000 - New for DOS Version 4.00 - J.K.
+;AC000 - Changed for DOS Version 4.00 - J.K.
+;AN00x - PTM number for DOS Version 4.00 - J.K.
+;==============================================================================
+
+ itest=0
+ INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT
+ INCLUDE JUMPMAC.INC
+ INCLUDE MSEQU.INC
+ INCLUDE MSMACRO.INC
+
+;*** DOS 3.3 will not support more than 25 rows
+; INCLUDE DEVSYM.INC ;J.K. 4/29/86 for CON$GENIOCTL support
+; INCLUDE IOCTL.INC ;J.K. 4/29/86 for CON$GENIOCTL support
+
+ EXTRN EXIT:NEAR ;MSBIO1
+ EXTRN BUS$EXIT:NEAR ;MSBIO1
+
+; EXTRN CMDERR:NEAR ;MSBIO1 J.K. 4/29/86
+
+;DATA
+ EXTRN PTRSAV:DWORD ;MSBIO1
+ EXTRN FHAVEK09:BYTE ;MSDISK
+ EXTRN ALTAH:BYTE ;MSBDATA
+ EXTRN KEYRD_Func:Byte ;MSBDATA
+ EXTRN KEYSTS_Func:Byte ;MSBDATA
+
+; EXTRN SAV_SC_INFO:BYTE ;MSBDATA J.K. 4/29/86
+; EXTRN SAV_SC_MODE:BYTE ;MSBDATA J.K. 4/29/86
+;------------------------------------------------------
+;
+; CONSOLE READ ROUTINE
+;
+ ASSUME DS:CODE ; THIS WAS SET BY THE CON DD ENTRY POINT
+ PUBLIC CON$READ
+CON$READ PROC NEAR
+ JCXZ CON$EXIT
+CON$LOOP:
+ CALL CHRIN ;GET CHAR IN AL
+ STOSB ;STORE CHAR AT ES:DI
+ LOOP CON$LOOP
+CON$EXIT:
+ JUMP EXIT
+CON$READ ENDP
+;---------------------------------------------------------
+;
+; INPUT SINGLE CHAR INTO AL
+;
+;J.K.5/12/87 We are going to issue extended keyboard function, if supported.
+;The returning value of the extended key stroke of the extended key board
+;function uses 0E0h in AL instead of 00 as in the conventional key board
+;function. This creates a conflict when the user entered real Greek Alpha
+;charater (= 0E0h) to distinguish the extended key stroke and the Greek Alpha.
+;This case will be handled in the following manner;
+; AH = 16h
+; INT 16h
+; If AL == 0, then extended code (in AH)
+; else If AL == 0E0h, then
+; IF AH <> 0, then extended code (in AH)
+; else Greek_Alpha character.
+;Also, for compatibility reason, if an extended code is detected, then we
+;are going to change the value in AL from 0E0h to 00h.
+
+
+CHRIN PROC NEAR
+;AN000;
+; XOR AX,AX
+ mov ah,KEYRD_Func ;AN000; Set by MSINIT. 0 or 10h
+ xor al,al ;AN000;
+ XCHG AL,ALTAH ;GET CHARACTER & ZERO ALTAH
+
+ OR AL,AL
+ JNZ KEYRET
+;SB34CON000**************************************************************
+;SB Keyboard I/O interrupt
+;SB AH already contains the keyboard read function number
+;SB 1 LOC
+
+ int 16h
+;SB34CON000**************************************************************
+ALT10:
+ OR AX,AX ;CHECK FOR NON-KEY AFTER BREAK
+ JZ CHRIN
+ CMP AX,7200H ;CHECK FOR CTRL-PRTSC
+ JNZ ALT_Ext_Chk ;AN000;
+ MOV AL,16
+ jmp KeyRet ;AN000;
+ALT_Ext_Chk:
+;SB34CON001**************************************************************
+;SB IF operation was extended function (i.e. KEYRD_Func != 0) THEN
+;SB IF character read was 0E0h THEN
+;SB IF extended byte was zero (i.e. AH == 0) THEN
+;SB goto keyret
+;SB ELSE
+;SB set AL to zero
+;SB goto ALT_SAVE
+;SB ENDIF
+;SB ENDIF
+;SB ENDIF
+;SB 9 LOCS
+
+ cmp BYTE PTR KEYRD_Func,0
+ jz NOT_EXT
+ cmp al,0E0h
+ jnz NOT_EXT
+ or ah,ah
+ jz KEYRET
+ xor al,al
+ jmp short ALT_SAVE
+NOT_EXT:
+
+;SB34CON001**************************************************************
+ OR AL,AL ;SPECIAL CASE?
+ JNZ KEYRET
+ALT_SAVE:
+ MOV ALTAH,AH ;STORE SPECIAL KEY
+KEYRET:
+ RET
+CHRIN ENDP
+
+;--------------------------------------------------------------
+;
+; KEYBOARD NON DESTRUCTIVE READ, NO WAIT
+;
+; PC-CONVERTIBLE-TYPE MACHINE: 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 POINT
+ PUBLIC CON$RDND
+CON$RDND:
+ MOV AL,[ALTAH]
+ OR AL,AL
+ JZ RD1
+ JMP RDEXIT
+
+RD1:
+;SB34CON002**************************************************************
+;SB Keyboard I/O interrupt
+;SB Get keystroke status (KEYSTS_Func)
+;SB 2 LOCS
+
+ mov ah,KEYSTS_Func
+ int 16h
+;SB34CON002**************************************************************
+ JZ NOCHR
+ JMP GOTCHR
+NOCHR:
+ CMP FHAVEK09,0
+ JZ CONBUSJ
+ LDS BX,[PTRSAV]
+ ASSUME DS:NOTHING
+ TEST [BX].STATUS,0400H ; SYSTEM WAIT ENABLED?
+ JZ CONBUSJ
+
+;********************************
+; NEED TO WAIT FOR IBM RESPONSE TO REQUEST FOR CODE ON HOW TO USE THE SYSTEM
+; WAIT CALL.
+;********************************
+ MESSAGE FTESTCON,<"SYSTEM WAIT STAGE",CR,LF>
+ MOV AX,4100H ; WAIT ON AN EXTERNAL EVENT
+; MOV BX,0300H ; NO TIMEOUT
+; MOV DX,60H ; LOOK AT I/O PORT 60H
+ INT 15H ; CALL ROM FOR SYSTEM WAIT
+ MESSAGE FTESTCON,<"OUT OF WAIT. AX IS ">
+ MNUM FTESTCON,AX
+ MESSAGE FTESTCON,
+ JMP CONBUS
+
+ ASSUME DS:CODE
+GOTCHR:
+ OR AX,AX
+ JNZ NOTBRK ;CHECK FOR NULL AFTER BREAK
+;SB34CON004**************************************************************
+;SB Keyboard I/O interrupt
+;SB Keyboard read function (KEYRD_Func)
+;SB 2 LOCS
+
+ mov ah,KEYRD_Func
+ int 16h
+;SB34CON004**************************************************************
+ JUMP CON$RDND ;AND GET A REAL STATUS
+NOTBRK:
+ CMP AX,7200H ;CHECK FOR CTRL-PRTSC
+ JNZ RD_Ext_Chk ;AN000;
+ MOV AL,16
+ jmp RDEXIT ;AN000;
+RD_Ext_Chk: ;AN000;
+ cmp KEYRD_Func, 0 ;AN000; Extended Keyboard function?
+ jz RDEXIT ;AN000; No. Normal exit.
+ cmp al,0E0h ;AN000; Extended key value or Greek Alpha?
+ jne RDEXIT ;AN000;
+ cmp ah, 0 ;AN000; Scan code exist?
+ jz RDEXIT ;AN000; Yes. Greek Alpha char.
+ mov al, 0 ;AN000; No. Extended key stroke. Change it for compatibility
+ PUBLIC RDEXIT
+RDEXIT:
+ LDS BX,[PTRSAV]
+ ASSUME DS:NOTHING
+ MOV [BX].MEDIA,AL
+EXVEC:
+ JUMP EXIT
+
+CONBUS:
+ ASSUME DS:NOTHING
+ JUMP BUS$EXIT
+;--------------------------------------------------------------
+;
+; KEYBOARD FLUSH ROUTINE
+;
+ ASSUME DS:CODE ; THIS WAS SET BY THE CON DD ENTRY POINT
+ PUBLIC CON$FLSH
+CON$FLSH:
+ CALL FLUSH
+ JUMP EXIT
+
+ PUBLIC FLUSH
+FLUSH:
+ MOV [ALTAH],0 ;CLEAR OUT HOLDING BUFFER
+
+FLLOOP:
+;SB33012****************************************************************
+ ;SB ; Is there a char there?
+ mov AH, 1 ;SB ; command code for check status
+ int 16h ;SB ; call rom-bios keyboard routine
+;SB33012****************************************************************
+ JZ FLDONE
+;SB33013****************************************************************
+ xor AH, AH ;SB ; if zf is nof set, get character
+ int 16h ;SB ; call rom-bios to get character
+;SB33013****************************************************************
+ JMP FLLOOP
+FLDONE:
+
+ RET
+;----------------------------------------------------------
+;
+; CONSOLE WRITE ROUTINE
+;
+ ASSUME DS:CODE ; THIS WAS SET BY THE CON DD ENTRY POINT
+ PUBLIC CON$WRIT
+CON$WRIT:
+ JCXZ EXVEC
+CON$LP:
+ MOV AL,ES:[DI] ;GET CHAR
+ INC DI
+ INT CHROUT ;OUTPUT CHAR
+ 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
+
+;------------------------------------------------------------------------------
+;J.K. 4/29/86 - CONSOLE GENERIC IOCTL SUPPORT FOR DOS 3.3.
+;CON$GENIOCTL supports Get mode information, Set mode information functions.
+;It will only save the value from "Set mode information" and will return
+;the value through "Get mode information". It is supposed to be set by
+;the MODE.COM and other application program can retrieve information
+;through "Get mode information" call.
+;Initially, there is no valuable informaton until set by MODE command, so
+;any attemp to "Get mode information" at that points will fail. (unknown
+;command with carry set.)
+;At entry: CS = DS = code
+; CS:[PTRSAV] has seg, address of the Request Header saved in
+; in Strategy routine.
+;
+; PUBLIC CON$GENIOCTL
+; ASSUME DS:CODE
+;CON$GENIOCTL:
+; les di, CS:[PTRSAV] ;get the request header
+; cmp es:[di].MajorFunction, IOC_SC
+; je Major_SC_OK
+;SC_CMDERR:
+; stc
+; jmp cmderr ;carry is set, exit to cmderr
+;Major_SC_OK:
+; mov al, es:[di].MinorFunction ;save minor function
+; les di, es:[di].GenericIOCTL_Packet ;pointer of SC_MODE_INFO structure
+; mov cx, es:[di].SC_INFO_LENGTH ;save length
+; inc di
+; inc di ;ES:DI -> SC_MODE in Info. Packet
+; cmp cx, SC_INFO_PACKET_LENGTH ;currently 9.
+; jne SC_CMDERR ;cannot accept the different packet
+; cmp al, GET_SC_MODE ;minor function = 60h ?
+; jne SC_SET_MODE_FUNC ;no, check if it is "Set mode function"
+; cmp SAV_SC_MODE, 0 ;information set before?
+; je SC_CMDERR ;no, cannot get the info.
+;;SC_GET_MODE_FUNC: ;es:di -> SC_MODE in info. packet
+; ;cx - length
+; mov si, offset SAV_SC_INFO
+; rep movsb ;ds:si -> sav_sc_info, es:di -> sc_mode
+; jmp exit
+;
+;SC_SET_MODE_FUNC: ;es:di -> SC_MODE
+; cmp al, SET_SC_MODE ;minor function = 40h ?
+; jne SC_CMDERR
+; mov si, offset SAV_SC_INFO
+; xchg di, si
+; push es
+; push ds
+; pop es
+; pop ds
+; rep movsb ;ds:si -> sc_mode, es:di -> sav_sc_info
+; jmp exit
+;
+;J.K. 4/29/86 - End of CONSOLE GENERIC IOCTL SUPPORT FOR DOS 3.3.
+
+CODE ENDS
+ END
diff --git a/v4.0/src/BIOS/MSDISK.ASM b/v4.0/src/BIOS/MSDISK.ASM
new file mode 100644
index 0000000..f132e7f
--- /dev/null
+++ b/v4.0/src/BIOS/MSDISK.ASM
@@ -0,0 +1,2443 @@
+ PAGE ,132 ;
+ TITLE MSDISK - BIOS
+ %OUT ...MSDISK.ASM
+
+;==============================================================================
+;REVISION HISTORY:
+;AN000 - New for DOS Version 4.00 - J.K.
+;AC000 - Changed for DOS Version 4.00 - J.K.
+;AN00x - PTM number for DOS Version 4.00 - J.K.
+;==============================================================================
+;AN001; d24 Multi Track enable/disable command in CONFIG.SYS 6/27/87 J.K.
+;AN002; d9 Double word MOV instruction 7/1/87 J.K.
+;AN003: d25 Change DASD ERP to that recommended by Storage systems 7/28/87 J.K.
+;AN004; D113 Disable I/O access to unformatted media 9/03/87 J.K.
+;AN005; P985 Allow I/O access to unformatted media 9/14/87 J.K.
+;AN006; P1535 Disallow I/O access to unformatted media. 10/15/87 J.K.
+; (Give the user to control this - Generic IOCTL subfunction 64h/44h
+;AN007; p2828 Do not retry for multi-track format request 12/08/87 J.K.
+;AC008; p3197 Should reset change line after BPB set in BDS table 01/21/88 J.K.
+;AN009; p3349 Should retry at hard file timeout error 02/03/88 J.K.
+;AN010; p4696 ECC error handler should cover PC ATs for CMC disks 05/04/88 J.K.
+;AN011; p5034 Possible virgin hard file problem with direct INT 13 06/03/88 J.K.
+;AN012; P5049 Attempt to write at DISK BASE table in ROM BIOS 06/06/88 J.K.
+;AN013; P5055 Diskcopy fails (Regression of P5049) 06/09/88 J.K.
+;==============================================================================
+
+;for testing, set itest to 1. So as MSBIO1.ASM.
+ itest=0
+ EXTRN NUMERR:ABS ;MSDATA
+
+ INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT
+ INCLUDE MSEQU.INC
+ INCLUDE PUSHPOP.INC
+ INCLUDE MSMACRO.INC
+ INCLUDE DEVSYM.INC
+ INCLUDE MSDSKPR.INC
+ include biostruc.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
+ extrn ResetChanged:near ;AN000; MS96TPI
+
+;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 ;msbdata
+ extrn Secrete_Code:word ;msbdata J.K. 11/7/86 Secrete code for DOS 3.3 MSBIO
+ extrn Ext_Boot_Sig:byte ;AN000; msbdata
+ extrn Boot_Serial_L:word ;AN000; msbdata
+ extrn Boot_Serial_H:word ;AN000; msbdata
+ extrn Boot_Volume_Label:byte ;AN000; msbdata
+ extrn Boot_System_ID:byte ;AN000; msbdata
+ extrn Model_Byte:Byte ;MSBIO2
+ extrn Secondary_Model_Byte:Byte ;MSBIO2
+
+;-----------------------------------------------------------------
+;
+; DISK INTERFACE ROUTINES
+;
+; DEVICE ATTRIBUTE BITS:
+; BIT 6 - GET/SET MAP FOR LOGICAL DRIVES AND GENERIC IOCTL.
+;
+
+MAXERR = 5
+LSTDRV = 504H
+
+; SOME FLOPPIES DO NOT HAVE CHANGELINE. AS A RESULT, MEDIA-CHECK WOULD
+; NORMALLY RETURN I-DON'T-KNOW, THE DOS WOULD CONTINUALLY REREAD THE FAT, AND
+; DISCARD CACHED DATA. WE OPTIMIZE THIS BY IMPLEMENTING A LOGICAL DOOR-
+; LATCH: IT IS PHYSICALLY IMPOSSIBLE TO CHANGE A DISK IN UNDER 2 SECONDS. WE
+; RETAIN THE TIME OF THE LAST SUCCESSFUL DISK OPERATION AND COMPARE IT WITH
+; THE CURRENT TIME DURING MEDIA-CHECK. IF < 2 SECONDS AND AT LEAST 1 TIMER
+; TICK HAS PASSED, THE WE SAY NO CHANGE. IF > 2 SECONDS THEN WE SAY I-
+; DON'T-KNOW. FINALLY, SINCE WE CANNOT TRUST THE TIMER TO BE ALWAYS
+; AVAILABLE, WE RECORD THE NUMBER OF MEDIA CHECKS THAT HAVE OCCURRED WHEN NO
+; APPARENT TIME HAS ELAPSED. WHILE THIS NUMBER IS < A GIVEN THRESHOLD, WE SAY
+; NO CHANGE. WHEN IT EXCEEDS THAT THRESHOLD, WE SAY I-DON'T-KNOW AND RESET
+; THE COUNTER TO 0. WHEN WE STORE THE TIME OF LAST SUCCESSFUL ACCESS, IF WE
+; SEE THAT TIME HAS PASSED TOO, WE RESET THE COUNTER.
+;
+ACCESSMAX = 5
+;
+; DUE TO VARIOUS BOGOSITIES, WE NEED TO CONTINUALLY ADJUST WHAT THE HEAD
+; SETTLE TIME IS. THE FOLLOWING ALGORITHM IS USED:
+;
+; GET THE CURRENT HEAD SETTLE VALUE.
+; IF IT IS 0, THEN
+; SET SLOW = 15
+; ELSE
+; SET SLOW = VALUE
+; ...
+;*********************************************
+;************ OLD ALGORITHM ******************
+;* IF WE ARE SEEKING AND WRITING THEN
+;* USE SLOW
+;* ELSE
+;* USE FAST
+;*********************************************
+;*********** IBM'S REQUESTED LOGIC ***********
+; IF WE ARE SEEKING AND WRITING AND NOT ON AN AT THEN
+; USE SLOW
+; ELSE
+; USE FAST
+; ...
+; RESTORE CURRENT HEAD SETTLE VALUE
+;
+
+Set_ID_Flag db 0 ;AN000; If 1, GETBP routine will set the
+ ;Vol_Serial and FileSys_ID in BDS table
+ ;from the media Boot record, if it is > DOS 4.00
+ ;formatted one. Then Set_ID_flag will be set to 2
+ ;to signal that volume_label is set from the extended
+ ;boot record and do not set it from the root
+ ;directory as done in SET_VOLUME_ID routine.
+ ;For the old version, Vol_Serial
+ ;will be set to -1, and FileSys_ID will be set
+ ;to "FAT12 " if it is a floppy.
+
+ public Fat_12_ID
+Fat_12_ID DB "FAT12 ",0 ;AN000; Default System ID for floppy.
+ public Fat_16_ID
+Fat_16_ID DB "FAT16 ",0 ;AN000;
+ public Vol_No_Name
+Vol_No_Name db "NO NAME ",0 ;AN000;
+ public Temp_H
+Temp_H dw 0 ;AN000; Temporary for 32 bit calculation.
+
+ public Start_Sec_H
+Start_Sec_H dw 0 ;AN000; Starting sector number high word.
+ ;Used as an input to DISKIO subroutine.
+Saved_Word dw 0 ;AN000; Tempory saving place for a word.
+
+;---------------------------------------
+;J.K. 6/29/87 For Multi-track
+MULTRK_ON EQU 10000000B ;User spcified Mutitrack=on, or System turns
+ ; it on after handling CONFIG.SYS file as a
+ ; default value, if MulTrk_flag = MULTRK_OFF1.
+MULTRK_OFF1 EQU 00000000B ;initial value. No "Multitrack=" command entered.
+MULTRK_OFF2 EQU 00000001B ;User specified Multitrack=off.
+ public MulTrk_Flag
+MulTrk_Flag dw 0 ;AN001;
+;J.K. 6/29/87 End of Multi-track definition.
+;---------------------------------------------------------------------
+ public EC35_Flag
+EC35_Flag db 0 ; flags for electrically compatible 3.5 inch disk drives (mrw 4/88)
+;---------------------------------------------------------------------
+VRetry_Cnt dw 0 ;AN003;
+Soft_ECC_Cnt dw 0 ;AN003;
+;---------------------------------------------------------------------
+MultiTrk_Format_Flag db 0 ;AN007;Testing. If 1, then Multi track format request
+;---------------------------------------------------------------------
+;
+; IF ID IS F9, HAVE A 96TPI DISK ELSE
+; IF BIT 2 IS 0 THEN MEDIA IS NOT REMOVABLE AND COULD NOT HAVE CHANGED
+; OTHERWISE IF WITHIN 2 SECS OF LAST DISK OPERATION MEDIA COULD NOT
+; HAVE CHANGED, OTHERWISE DONT KNOW IF MEDIA HAS CHANGED
+;
+ PUBLIC MEDIA$CHK
+MEDIA$CHK PROC NEAR
+ MESSAGE FTESTDISK,<"DISK MEDIA CHECK ">
+ MNUM FTESTDISK,AX
+ MESSAGE FTESTDISK,
+ CALL SETDRIVE
+
+ cmp cs:Secrete_Code, 'jk' ;J.K.11/7/86 Secrete code for DOS 3.3 IBMBIO.
+ jne media$done ;J.K.11/7/86
+
+; 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
+ AND WORD PTR [DI].FLAGS,NOT FCHANGED_BY_FORMAT ; RESET FLAG
+; IF MEDIA HAS BEEN CHANGED BY FORMAT, WE MUST ASK 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
+;
+; WE NEED TO RETURN 'NOT CHANGED' IF WE HAVE A HARD FILE.
+;
+WEARENOTFAKINGIT:
+ TEST WORD PTR [DI].FLAGS,FNON_REMOVABLE
+ JNZ MEDIA$DONE
+WEHAVEAFLOPPY:
+ XOR SI,SI ; PRESUME "I DON'T KNOW"
+;
+; IF WE HAVE A FLOPPY WITH CHANGELINE SUPPORT, WE ASK THE ROM TO DETERMINE IF
+; MEDIA HAS CHANGED. WE DO NOT PERFORM THE 2 SECOND CHECK FOR 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 WE COME HERE, WE HAVE A FLOPPY WITH NO CHANGELINE SUPPORT
+ MOV SI,1 ; PRESUME NO CHANGE
+ MOV AL,CS:[TIM_DRV] ; LAST DRIVE ACCESSED
+ CMP AL,BYTE PTR [DI].DRIVENUM ;IS DRIVE OF LAST ACCESS THE SAME?
+ JNZ MEDIA$UNK ; NO, THEN "I DON'T KNOW"
+;
+; CHECK TO SEE IF THIS DRIVE HAS BEEN ACCESSED IN THE LAST 2 SECONDS.
+ CALL CHECK_TIME_OF_ACCESS ; SETS SI CORRECTLY
+ 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 PHYSICEL
+; 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.
+;SB33014*************************************************************
+ xor AH,AH ; set command to read time
+ int 1Ah ; call rom-bios clock routine
+;SB33014*************************************************************
+;
+; NOW THAT WE ARE READING THE TIME, WE MUST MAKE SURE THAT WE DO NOT LOSE A
+; DATE WRAP. THE ROM WILL RETURN THE VALUE ONLY ONCE, SO WE NEED TO NOTE THIS
+; FACT.
+;
+ SHR AL,1
+ ADC CS:[DAYCNT],0 ; ADD IT IN TO OUR REMEMBERED 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
+;
+; CX:DX IS THE ELAPSED TIME
+;
+ JNZ TIMECHECK_UNK ; CX <> 0 => > 1 HOUR
+ OR DX,DX ; TIME MUST PASS
+ JNZ TIMEPASSED ; YES, EXAMINE MAX VALUE
+;
+; NO NOTICEABLE TIME HAS PASSED. WE CANNOT TRUST THE COUNTER TO BE ALWAYS
+; AVAILABLE AS THERE ARE BOGUS PROGRAMS THAT GO AND REPROGRAM THE THING. WE
+; KEEP A COUNT OF THE NUMBER OF MEDIA CHECKS THAT WE'VE SEEN THAT DO NOT HAVE
+; ANY TIME PASSING. IF WE EXCEED A GIVE THRESHOLD, WE GIVE UP ON THE TIMER.
+;
+ INC BYTE PTR CS:ACCESSCOUNT
+ CMP BYTE PTR CS:ACCESSCOUNT,ACCESSMAX
+ JB TIMECHECK_RET ; IF COUNT IS LESS THAN THRESHOLD, OK
+ DEC BYTE PTR CS:ACCESSCOUNT ; DON'T LET THE COUNT WRAP
+ JMP SHORT TIMECHECK_UNK ; "I DON'T KNOW" IF MEDIA CHANGED
+;
+; 18.2 TICS PER SECOND.
+;
+TIMEPASSED:
+ CMP DX,18 * 2 ; MIN ELAPSED TIME?
+ JBE TIMECHECK_RET ; YES, 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
+;
+; BUILD A VALID BPB FOR THE DISK IN THE DRIVE.
+;
+ PUBLIC GET$BPB
+GET$BPB PROC NEAR
+ MESSAGE FTESTDISK,<"DISK BUILD BPB ">
+ MNUM FTESTDISK,AX
+ MESSAGE FTESTDISK,
+ MOV AH,BYTE PTR ES:[DI] ;GET FAT ID BYTE READ BY DOS
+ CALL SETDRIVE ; GET THE CORRECT BDS FOR THE DRIVE
+ TEST WORD PTR [DI].FLAGS,FNON_REMOVABLE
+ JNZ ALREADY_GOTBPB ; NO NEED TO BUILD FOR FIXED DISKS
+;J.K. Let's set the default value for VOLID,Vol_Serial,FileSys_ID in BDS table
+ call Clear_IDs ;AN000;
+ mov cs:[Set_ID_Flag],1 ;AN000; Indicate to set system id in BDS
+ CALL GETBP ;BUILD A BPB IF NECESSARY.
+ JC ERR$EXITJ2 ;AN000; If error, Set_ID_flag is set to 0 already.
+ cmp cs:[Set_ID_Flag],2 ;AN000; Already, volume_Label set from Boot record
+ mov cs:[Set_ID_Flag],0 ;AN000; to BDS table?
+ je Already_GotBPB ;AN000; Then do not set it again from Root directory.
+ ;AN000; Otherwise, conventional Boot record.
+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 ;|
+;----------------------------------------|
+ 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
+
+;J.K. Clear IDs in BDS table. Only applied for Floppies.
+;Input: DS:DI -> BDS table
+;Output: VOLID set to "NO NAME "
+; VOL_SERIAL set to 0.
+; FileSys_ID set to "FAT12 " or "FAT16 "
+; depending on the flag FATSIZE in BDS.
+;All registers saved.
+ public Clear_IDs
+Clear_IDs proc near ;AN000;
+ push ds ;AN000;
+ push di ;AN000;
+ push es ;AN000;
+ push si ;AN000;
+ push cx ;AN000;
+
+ push ds ;AN000;
+ pop es ;AN000; es -> bds
+ push cs ;AN000;
+ pop ds ;AN000; ds = cs
+
+ mov cx, 0 ;AN000; no serial number
+ mov word ptr es:[di.VOL_SERIAL],cx ;AN000;
+ mov word ptr es:[di.VOL_SERIAL]+2,cx ;AN000;
+
+ mov cx, BOOT_VOLUME_LABEL_SIZE ;AN000; =11
+ mov si, offset VOL_NO_NAME ;AN000;
+ push di ;AN000; save BDS pointer
+ add di, VOLID ;AN000; points to VOLID field
+ rep movsb ;AN000;
+ pop di ;AN000; restore BDS pointer
+ test es:[di.FATSIZ], FBIG ;AN000;
+ jnz CI_BigFat ;AN000; small fat
+ mov si, offset FAT_12_ID ;AN000;
+ jmp CI_Filesys ;AN000;
+CI_BigFat: ;AN000;
+ mov si, offset FAT_16_ID ;AN000; big fat
+CI_Filesys: ;AN000;
+ mov cx, BOOT_SYSTEM_ID_SIZE ;AN000; =8
+ add di, FILESYS_ID ;AN000; points to FILESYS_ID field
+ rep movsb ;AN000;
+
+ pop cx ;AN000;
+ pop si ;AN000;
+ pop es ;AN000;
+ pop di ;AN000;
+ pop ds ;AN000;
+ ret ;AN000;
+Clear_IDs endp ;AN000;
+
+
+; GETBP - RETURN BPB FROM THE DRIVE SPECIFIED BY THE BDS.
+; IF THE RETURN_FAKE_BPB FLAG IS SET, THEN IT DOES NOTHING.
+; NOTE THAT WE NEVER COME HERE FOR FIXED DISKS.
+; FOR ALL OTHER CASES,
+; - IT READS BOOT SECTOR TO PULL OUT THE BPB
+; - IF NO VALID BPB IS FOUND, IT THEN READS THE FAT SECTOR,
+; TO GET THE FAT ID BYTE TO BUILD THE BPB FROM THERE.
+;
+; INPUTS: DS:DI POINT 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.
+; If failed to recognize the Boot Record, then will set the
+; Set_ID_Flag to 0.
+; J.K. This routine will only work for a floppy diskette.
+; For a fixed disk, it will just return.
+
+ PUBLIC GETBP
+GETBP PROC NEAR
+; IF 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
+ JC GETBP_ERR_RET_brdg ; CARRY SET IF THERE WAS ERROR.
+ CMP BX,0 ; BX IS 0 IF BOOT SECTOR IS VALID.
+ JNZ DOFATBPB
+
+ CALL MOVBPB ; MOVE BPB INTO REGISTERS.
+ JMP HAS1
+
+Getbp_err_ret_brdg: jmp Getbp_err_ret
+;
+; WE HAVE A 1.X DISKETTE.
+; IN THIS CASE READ IN THE FAT ID BYTE AND FILL IN BPB FROM THERE.
+;
+DOFATBPB:
+ CALL READFAT ; PUTS MEDIA DESCRIPTOR BYTE IN AH
+ JC GETBP_ERR_RET_Brdg
+;----------------------------------------|
+; 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
+;J.K. DS points to segment of BDS. The following should be modified
+;J.K. to get spf,csec,spa,spt correctly. It had been wrong if DRIVER.SYS
+;J.K. is loaded since the BDS is inside the driver.sys.
+ MOV AL,es:[BX.SPF]
+ MOV CX,es:[BX.CSEC]
+ MOV DX,WORD PTR es:[BX.SPA]
+ MOV BX,WORD PTR es:[BX.SPT]
+ JMP SHORT HAS1
+; MUST BE A 5.25" FLOPPY IF WE COME HERE
+IS_FLOPPY:
+ MOV CL,AH ;SAVE MEDIA
+ AND CL,0F8H ;NORMALIZE
+ CMP CL,0F8H ;COMPARE 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 SECTOR
+ 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 NUMBER OF DIRECTORY ENTRIES
+ INC DH ;INC SEC/ALL UNIT
+ INC DL ;INC HEAD LIMIT
+
+HAS1:
+ PUBLIC 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
+;SB34DISK001*******************************************************************
+;SB the HIDSEC_H field and DRVLIM_L field and the
+;SB DRVLIM_H fields need to be set to 0 since this code here is for floppies
+;SB 3 LOCS
+
+ mov word ptr ds:[di].HIDSEC_H,0
+ mov word ptr ds:[di].HIDSEC_L,0
+ mov word ptr ds:[di].DRVLIM_H,0
+
+;SB34DISK001*******************************************************************
+GETRET:
+ POP BX
+ RESTOREREG
+
+ ASSUME ES:NOTHING
+
+GETRET_EXIT:
+ RET
+
+GETBP_ERR_RET:
+;J.K. Before doing anything else, set Set_ID_Flag to 0.
+ mov cs:Set_ID_Flag, 0 ;AN000;
+ 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 cs:Set_ID_Flag, 0 ;AN000;
+ 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
+
+;
+; 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 DH,0 ;HEAD 0
+ MOV CX,0001 ;CYLINDER 0, SECTOR 1
+ CALL READ_SECTOR
+ JC ERR_RET
+ XOR BX,BX ; ASSUME VALID BOOT SECTOR.
+
+;*******************************************************************************
+; 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 (69H) OR A
+; SHORT JUMP (EBH) FOLLOWED BY A NOP (90H), OR A SHORT JUMP (E9H).
+; 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.
+;J.K. 10/15/86 DCR00012. For DOS 3.3, this logic is modified a little bit.
+; We are not going to check Signature. Instead we are going to sanity
+; check the media byte in BPB regardless of the validity of signature.
+; This is to save the already developed commercial products that have
+; good jump instruction and signature but with the false BPB informations
+; that will crash the diskette drive operation. (For example, Symphony diskette).
+;******************************************************************************
+ 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
+
+
+;J.K. 10/15/86 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.
+;
+
+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 LOT OF THEM) 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
+; SECTOR THAT HAVE THE SEC/CLUS FIELD SET TO 2 INSTEAD OF 1, AS IS STANDARD
+; IN DOS. IN ORDER 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 ; INDICATE THAT BOOT SECTOR INVALID
+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
+
+; MOVES THE BPB READ FROM THE BOOT SECTOR INTO REGISTERS FOR USE BY
+; GETBP ROUTINE AT HAS1
+;J.K.-
+; If the Set_ID_Flag is 1, and if an extended Boot Record, then set Volume
+; Serial Number, Volume Label, File System ID in BDS according to
+; the BOOT reocrd. After that, this routine will set the Set_ID_Flag to 2
+; to signal that VOLUME Label is set already from the Extended BOOT record
+; (so, don't set it again by calling "SET_VOLUME_ID" routine which uses
+; the volume label in the root directory.
+
+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
+ RESTOREREG
+ cmp cs:[Set_ID_Flag], 1 ;AC008 called by GET$BPB?
+ jne MovBPB_Ret ;AC008
+ call Mov_Media_IDs ;AC008
+ jc MovBPB_Conv ;AC008 Conventional boot record?
+ mov cs:[Set_ID_Flag],2 ;AC008 signals that Volume ID is set.
+MovBPB_Conv: ;AC008
+ cmp cs:fHave96, 1 ;AC008
+ jne MovBPB_Ret ;AC008
+ call ResetChanged ;AC008 Reset Flags in BDS to NOT fCHANGED.
+MovBPB_Ret: ;AC008
+ clc ;AC008
+ ret ;AC008
+MOVBPB ENDP ;AC008
+
+
+;
+ public Mov_Media_IDs
+Mov_Media_IDs Proc near ;AN000;
+;copy the boot_serial number, Volume id, and Filesystem id from the
+;***Extended Boot record*** in cs:DiskSector to the BDS table pointed
+;by DS:DI.
+;In.) DS:DI -> BDS
+; CS:DiskSector = Valid extended boot record.
+;Out.) Vol_Serial, Volid and System_Id in BDS are set according to
+; the boot record information.
+; Carry flag set if not an extended BPB.
+; All registers saved except the flag.
+
+ cmp cs:[Ext_Boot_Sig], EXT_BOOT_SIGNATURE ;AN000; = 41
+ jne MMI_Not_Ext ;AN000;
+ push cx ;AN000;
+ mov cx, cs:[Boot_Serial_L] ;AN000;
+ mov word ptr ds:[di.VOL_SERIAL],cx ;AN000;
+ mov cx, cs:[Boot_Serial_H] ;AN000;
+ mov word ptr ds:[di.VOL_SERIAL+2],cx ;AN000;
+ push ds ;AN000; Save regs.
+ push di ;AN000;
+ push es ;AN000;
+ push si ;AN000;
+
+ push ds ;AN000; ds-> cs, es-> bds
+ pop es ;AN000;
+ push cs ;AN000;
+ pop ds ;AN000;
+
+ mov cx, BOOT_VOLUME_LABEL_SIZE ;AN000;
+ mov si, offset Boot_Volume_Label;AN000;
+ push di
+ add di, VOLID ;AN000;
+ rep movsb ;AN000;
+ pop di
+ mov cx, BOOT_SYSTEM_ID_SIZE ;AN000; =8
+ mov si, offset Boot_System_ID ;AN000;
+ add di, FILESYS_ID ;AN000;
+ rep movsb ;AN000;
+
+ pop si ;AN000;
+ pop es ;AN000;
+ pop di ;AN000;
+ pop ds ;AN000;
+ pop cx ;AN000;
+ clc ;AN000;
+MMI_Ret: ;AN000;
+ ret ;AN000;
+MMI_Not_Ext: ;AN000;
+ stc ;AN000;
+ ret ;AN000;
+Mov_Media_IDs endp ;AN000;
+
+
+; 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 ; CYLINDER 0, SECTOR 2
+ CALL READ_SECTOR ; CS:BX POINTS TO FAT SECTOR
+ JC BAD_FAT_RET
+ 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 A SINGLE SECTOR INTO THE TEMP BUFFER.
+; PERFORM THREE RETRIES IN CASE OF ERROR.
+; INPUTS: DRIVE HAS PHYSICAL DRIVE TO USE
+; CX HAS SECTOR AND CYLINDER
+; DH HAS HEAD
+; OUTPUTS: CARRY CLEAR
+; CS:BX POINT TO SECTOR
+; CARRY SET
+; AX HAS ROM ERROR CODE
+; REGISTERS ES AND BP ARE PRESERVED.
+
+READ_SECTOR PROC NEAR
+ PUBLIC READ_SECTOR
+
+ PUSH BP
+ MOV BP,3 ; MAKE 3 ATTEMPTS
+ PUSH ES
+;SB33015*****************************************************************
+ mov DL, byte ptr ds:[di].DriveNum ;SB;3.30*
+ mov BX, offset DiskSector ; Get ES:BX to point to buffer ;SB;3.30*
+ push CS ; get the segment right ;SB;3.30*
+ pop ES ; now ES:BX is correct ;SB;3.30*
+;SB33015*****************************************************************
+RD_RET:
+;SB33016*****************************************************************
+ mov AX, 0201h ; number of sectors to 1 (AL=1);SB;3.30*
+ int 13h ; call rom-bios disk routines ;SB;3.30*
+
+;SB33016*****************************************************************
+ JNC OKRET2
+Rd_rty:
+ CALL AGAIN ; RESET DISK, DECREMENT BP, PRESERVE AX
+ jz Err_RD_RET
+ test word ptr ds:[di].flags,fNon_Removable
+ JNZ RD_RET
+ cmp cs:[Media_Set_For_Format], 0 ;AN012;
+ jne Rd_Skip1_DPT ;AN012;
+ push ds ;J.K. 11/7/86 For retry, set the head settle time
+ push ax ;to 0Fh. PTM845.
+ 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
+Rd_Skip1_DPT: ;AN012;
+;SB33017*****************************************************************
+ ; SET CMD TO READ (AH=2) AND ;SB ;3.30
+ MOV AX, 0201h ; NUM OF SECTORS TO 1 (AL=1) ;SB ;3.30
+ INT 13h ; CALL ROM-BIOS DISK ROUTINES ;SB ;3.30
+;SB33017*****************************************************************
+ pushf ;AN012;
+ cmp cs:[Media_Set_For_Format], 0 ;AN012;
+ jne Rd_Skip2_DPT ;AN012;
+ 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
+Rd_Skip2_DPT: ;AN012;
+ popf ;AN012;
+ jnc OKRET2
+ jmp Rd_rty
+ERR_RD_RET:
+ MOV DL,-1 ; MAKE SURE WE ASK ROM IF MEDIA HAS CHANGED
+ STC ; RETURN ERROR
+; UPDATE INFORMATION PERTAINING TO LAST DRIVE ACCESSED, TIME OF ACCESS, LAST
+; TRACK ACCESSED IN THAT DRIVE.
+OKRET2:
+ MOV CS:[STEP_DRV],DL ; SET UP FOR HEAD SETTLE LOGIC IN DISK.
+ MOV CS:[TIM_DRV],DL ;SAVE DRIVE LAST ACCESSED
+ MOV BYTE PTR [DI].TRACK,CH ; SAVE LAST TRACK ACCESSED ON THIS DRIVE
+ PUSHF ; PRESERVE FLAGS IN CASE ERROR OCCURRED
+ CALL SET_TIM
+ POPF ; RESTORE FLAGS
+ POP ES
+ POP BP
+ RET
+READ_SECTOR ENDP
+
+;-----------------------------------------------------------
+;
+; DISK REMOVABLE ROUTINE ARR 2.41
+;
+
+DSK$REM PROC NEAR ;ARR 2.41
+ PUBLIC DSK$REM
+
+ MESSAGE FTESTDISK,<"DISK REMOVABLE ">
+ MNUM FTESTDISK,AX
+ MESSAGE FTESTDISK,
+; AL IS UNIT #
+ CALL SETDRIVE ; GET BDS FOR THIS DRIVE
+ TEST WORD PTR [DI].FLAGS,FNON_REMOVABLE
+ JNZ NON_REM
+ JMP EXIT
+
+NON_REM:
+ JMP BUS$EXIT ;ARR 2.41
+DSK$REM ENDP
+
+; SETDRIVE SCANS THROUGH THE DATA STRUCTURE OF BDSS, AND RETURNS A POINTER TO
+; THE ONE THAT BELONGS TO THE DRIVE SPECIFIED. CARRY IS SET IF NONE EXISTS FOR
+; THE DRIVE.
+; IF THE BYTE [PHYS_DRV] IS 0 THEN
+; ON ENTRY, AL CONTAINS THE LOGICAL DRIVE NUMBER.
+; ON EXIT, DS:DI POINTS TO CORRECT BDS FOR THE DRIVE IF CARRY CLEAR.
+
+; ELSE IF THE BYTE [PHYS_DRV] IS 1 THEN (ONLY USED FOR FIXED DISKS WHEN AN ECC
+; ERROR OCCURS)
+; ON ENTRY, DL CONTAINS THE PYHSICAL DRIVE NUMBER.
+; ON EXIT, DS:DI POINTS TO CORRECT BDS FOR THE DRIVE IF CARRY CLEAR.
+
+ PUBLIC SETDRIVE
+SETDRIVE PROC NEAR
+ MESSAGE FTESTDISK,<"SETDRIVE",CR,LF>
+ PUSH BX
+ PUSH CS
+ POP DS
+ ASSUME DS:CODE
+
+; ASSUME FIRST BDS IS IN THIS SEGMENT
+ MOV DI,WORD PTR START_BDS
+SCAN_LOOP:
+ CMP BYTE PTR CS:[PHYS_DRV],1 ; DOES AL HAVE PHYSICAL DRIVE?
+ 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
+
+ CMP DI,-1
+ JNZ SCAN_LOOP
+ STC
+SETDRV:
+ POP BX
+ RET
+SETDRIVE ENDP
+
+;-----------------------------------------------------------
+;
+; DISK I/O ROUTINES
+;
+
+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
+
+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
+
+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.
+
+
+; IF WE HAVE A SYSTEM WHERE WE HAVE VIRTUAL DRIVES, WE NEED TO PROMPT THE
+; USER TO PLACE THE CORRECT DISK IN THE DRIVE.
+
+CHECKSINGLE PROC NEAR
+ PUBLIC CHECKSINGLE
+
+ PUSH AX
+ PUSH BX
+ MOV BX,WORD PTR DS:[DI].FLAGS
+ ; IF HARD DRIVE, CANNOT CHANGE DISK.
+ ; IF CURRENT OWNER OF PHYSICAL DRIVE, NO NEED TO CHANGE DISKETTE.
+ TEST BL,FNON_REMOVABLE OR FI_OWN_PHYSICAL
+ JNZ SINGLERET
+ TEST BL,FI_AM_MULT ; IS THERE A DRIVE SHARING THIS
+ ; PHYSICAL DRIVE?
+ JZ SINGLERET
+; LOOK FOR THE PREVIOUS OWNER OF THIS PHYSICAL DRIVE AND RESET ITS OWNERSHIP
+; FLAG.
+ MOV AL,DS:[DI].DRIVENUM ; GET PHYSICAL DRIVE NUMBER
+ PUSH DS ; PRESERVE POINTER TO CURRENT BDS
+ PUSH DI
+ PUSH CS
+ POP DS
+ 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 ; MUST BE ERROR
+ CMP BYTE PTR [DI].DRIVENUM,AL
+ JNZ SCAN_LIST
+
+CHECK_OWN:
+ MOV BX,WORD PTR [DI].FLAGS
+ TEST BL,FI_OWN_PHYSICAL
+ JZ SCAN_LIST
+ XOR BL,FI_OWN_PHYSICAL ; 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
+ CMP CS:[SINGLE],2 ; IF (SINGLE_DRIVE_SYSTEM)
+ JNE SHORT IGNORE_SDSB
+
+ SAVEREG ; THEN
+ 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
+ POP AX
+ RET
+
+SINGLE_ERR_RET:
+ STC
+ POP DI ; RESTORE CURRENT BDS
+ POP DS
+ JMP SHORT SINGLERET
+
+BADDRIVE:
+ MOV AL,8 ;Sector not found
+ jmp short BadDrive_Ret ;AN004;AN005;AN006;
+UnformattedDrive: ;AN004;AN005;AN006;
+ mov al,7 ;AN004;Unknown media;AN005;AN006;
+BadDrive_Ret:
+ STC
+IORET: RET
+
+BOGUSSETTLE:
+ MOV AL,NORMSETTLE ; SOMEONE HAS DIDDLED THE SETTLE
+ JMP GOTSLOWSETTLE
+CHECKSINGLE ENDP
+;------------------------------------------------------------
+;
+; DISK I/O HANDLER
+;
+; AL = DRIVE NUMBER (0-6)
+; AH = MEDIA DESCRIPTOR
+; CX = SECTOR COUNT
+; DX = FIRST SECTOR (low)
+; [Start_Sec_H] = FIRST SECTOR (high) ;J.K. 32 bit calculation.
+; DS = CS
+; ES:DI = TRANSFER ADDRESS
+; [RFLAG]=OPERATION (2=READ, 3=WRITE)
+; [VERIFY]=1 FOR VERIFY AFTER WRITE
+;
+; IF SUCCESSFUL CARRY FLAG = 0
+; ELSE CF=1 AND AL CONTAINS ERROR CODE
+;
+ PUBLIC DISKRD
+DISKRD PROC NEAR
+ MOV CS:[RFLAG],ROMREAD
+
+DISKIO:
+ MOV BX,DI ; ES:BX = TRANSFER ADDRESS
+ CALL SETDRIVE ; MAP LOGICAL AND PHYSICAL
+ MOV AL,BYTE PTR DS:[DI].MEDIAD
+ MOV CS:MEDBYT,AL ; PRESERVE MEDIA BYTE FOR DRIVE FOR USE
+ ; IN DETERMINING MEDIA CHANGE.
+ JCXZ IORET
+;SB34DISK006******************************************************************
+;SB See if the Media is formatted or not by checking the flags field in
+;SB in the BDS. If it is unformatted we cannot allow I/O, so we should
+;SB go to the error exit at label UnformattedDrive. 2LOCS
+
+ test word ptr ds:[di].FLAGS, UNFORMATTED_MEDIA
+ jnz UnformattedDrive
+;SB34DISK006******************************************************************
+ mov cs:[SECCNT],CX ;save sector count
+ MOV CS:[SPSAV],SP ; SAVE SP
+
+; ENSURE THAT WE ARE TRYING TO ACCESS VALID SECTORS ON THE DRIVE
+;
+
+ mov ax,dx ;AN000; save DX to AX
+ xor si,si ;AN000;
+ add dx,cx ;AN000;
+ adc si,0 ;AN000;
+ cmp [di].DrvLim, 0 ;AN000; Is this drive > 32 bit sector ?
+ je Sanity32 ;AN000;
+ cmp si,0 ;AN000;
+ jne BADDRIVE ;AN000;
+ cmp dx, [di].DrvLim ;AN000;
+ ja BADDRIVE ;AN000;
+ jmp short SanityOK ;AN000;
+Sanity32: ;AN000;
+ add si, cs:[Start_Sec_H] ;AN000;
+ cmp si, [di].DrvLim_H ;AN000;
+ jb SanityOK ;AN000;
+ ja BADDRIVE ;AN000;
+ cmp dx, [di].DrvLim_L ;AN000;
+ ja BADDRIVE ;AN000;
+SanityOK: ;AN000;
+ mov dx,cs:[Start_Sec_H] ;AN000;
+ add ax,word ptr [di].HIDSEC_L ;AN000;
+ adc dx,word ptr [di].Hidsec_H ;AN000;
+;J.K. Now DX;AX have the physical first sector.
+;Since the following procedures is going to destroy AX, let's
+;save it temporarily to SAVED_WORD.
+ mov cs:[Saved_Word], ax ;AN000; Save the sector number (low)
+
+; MOV SI,DX
+; ADD SI,CX
+; ADD DX,WORD PTR [DI].HIDSEC ; ADD IN THE HIDDEN SECTORS
+; CMP SI,WORD PTR [DI].DRVLIM ; COMPARE AGAINST DRIVE MAX
+; JA BADDRIVE
+
+; 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
+ 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:
+;J.K. 32 bit sector calculation.
+; DX;[Saved_Word] = starting sector number.
+ mov ax,dx ;AN000;
+ xor dx,dx ;AN000;
+ DIV WORD PTR [DI].SECLIM ;DIVIDE BY SEC PER TRACK
+ mov cs:[Temp_H],ax ;AN000;
+ mov ax, cs:[Saved_Word] ;AN000; Restore the lower word
+ div word ptr [di].SecLim ;AN000;
+;Now, [Temp_H],AX = track #, DX = sector
+ INC DL ;Sector number is 1 based.
+ MOV CS:[CURSEC],DL ;SAVE CURRENT SECTOR
+ MOV CX,WORD PTR [DI].HDLIM ;GET NUMBER OF HEADS
+
+ push ax ;AN000;
+ XOR DX,DX ;DIVIDE TRACKS BY HEADS PER CYLINDER
+ mov ax, cs:[Temp_H] ;AN000;
+ DIV CX
+ mov cs:[Temp_H],ax ;AN000;
+ pop ax ;AN000;
+ div cx ;AN000;
+;Now, [Temp_H],AX = cyliner #, DX = head
+ cmp cs:[Temp_H],0 ;AN000;
+ ja BADDRIVE_brdg ;AN000;
+ cmp AX, 1024 ;AN000; 2**10 currently maxium for track #.
+ ja BADDRIVE_brdg ;AN000;
+ 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 INT 13 HANDLER WORRY ABOUT THE DMA VIOLATIONS.
+;
+ MOV AX, CS:[SECCNT]
+ CALL BLOCK
+ CALL DONE
+ RET
+DISKRD ENDP
+
+;
+BADDRIVE_Brdg:jmp Baddrive
+;
+
+; SET THE DRIVE-LAST-ACCESSED FLAG FOR DISKETTE ONLY. WE KNOW THAT THE HARD
+; DISK WILL NOT BE REMOVED.
+; DS:DI -> CURRENT BDS.
+; 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
+;
+ cmp cs:[Media_Set_For_Format], 0 ;AN012;
+ jne Skip_DPT_Setting ;AN012;
+ 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!! - RS
+;
+ 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 TO BE 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
+Skip_DPT_Setting: ;AN012;
+ 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:
+ pushf ;AN013;Save flag
+ cmp cs:[Media_Set_For_Format], 0 ;AN012;
+ jne NoDiddleBack ;AN012;
+ PUSH AX
+ MOV DX,DS
+ MOV AL,CS:SETTLECURRENT
+ MOV AH,CS:MOTORSTARTUP
+ LDS SI,CS:DPT
+; MOV [SI].DISK_EOT,9 ;J.K. 4/25/86. Should not change the EOT value
+ ;of diskbase to 9. This cause a problem
+ ;with 1.44M diskette in Polaris when the user
+ ;issue INT 13 with the default system
+ ;diskbase.
+ mov [si].DISK_EOT,9 ;J.K. 11/5/86. For compatibility reason, return
+ ;back to set it to 9 ( PTM826 ).
+ MOV [SI].DISK_HEAD_STTL,AL
+ MOV [SI].DISK_SECTOR_SIZ,2
+ MOV [SI].DISK_MOTOR_STRT,AH
+ MOV DS,DX
+ POP AX
+NoDiddleBack: ;AN013;
+ popf ;AN013;Restore flag
+RETZ:
+ RET
+
+;READ THE NUMBER OF SECTORS SPECIFIED IN AX, HANDLING TRACK BOUNDARIES
+;DS:DI -> BDS FOR THIS DRIVE
+BLOCK:
+ OR AX,AX ;SEE IF ANY SECTORS TO READ
+ JZ RETZ
+;Fixed disk will not be restricted to the track-by-track basis. -J.K.4/10/86
+ test word ptr [di].Flags, fNon_Removable ;J.K. Fixed disk?
+ jz BLOCK_FLOPPY ;J.K.
+;SB34DISK002*****************************************************************
+;SB Check to see if multi track operation is allowed. If not
+;SB we have to go to the block_floppy below to break up the operation.
+;SB 2 LOCS
+ test word ptr CS:MulTrk_Flag, MulTrk_ON
+ jz BLOCK_FLOPPY
+;SB34DISK002*****************************************************************
+ call DISK ;J.K.
+ xor ax,ax
+ RET ;J.K.
+BLOCK_FLOPPY: ;J.K.4/10/86
+;
+; READ AT MOST 1 TRACK WORTH. PERFORM MINIMIZATION AT SECTOR / TRACK
+;
+ MOV CL,BYTE PTR [DI].SECLIM
+ INC CL
+ SUB CL,CS:CURSEC ; LEEAC 3.20 ADD SEGMENT OVERRIDE
+ XOR CH,CH
+ CMP AX,CX
+ JAE GOTMIN
+ MOV CX,AX
+GOTMIN:
+;
+; 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
+IOSETUP ENDP
+
+DskErr_Brdg: jmp DskErr ;AN003;
+
+;
+;PERFORM DISK I/O WITH RETRIES
+; AL = NUMBER OF SECTORS (1-8, ALL ON ONE TRACK)
+; DI POINT TO DRIVE PARAMETERS
+; ES:BX = TRANSFER ADDRESS (MUST NOT CROSS A 64K PHYSICAL BOUNDARY)
+; [RFLAG] = 2 IF READ, 3 IF WRITE
+; [VERIFY] = 0 FOR NORMAL, 1 FOR VERIFY AFTER WRITE
+
+ PUBLIC DISK
+DISK PROC NEAR
+ MOV BP,MAXERR ; SET UP RETRY COUNT
+ mov cs:VRetry_Cnt, BP ;AN003;Verify op. retry cnt for Write-Verify.
+ mov cs:Soft_ECC_Cnt, BP ;AN003;Soft ECC error retry count.
+ MOV AH,CS:RFLAG ;GET READ/WRITE INDICATOR
+
+RETRY:
+ PUSH AX
+
+ MOV DX,CS:[CURTRK] ;LOAD CURRENT CYLINDER
+
+ test word ptr [di].FLAGS, fNon_Removable ;Fixed disk? - J.K. 4/7/86
+ jz DISK_NOT_MINI ;no, skip this. - J.K. 4/7/86
+ cmp [di].IsMini, 1 ;Is this a mini disk? - J.K. 4/7/86
+ jnz DISK_NOT_MINI ;No. continue to next.- J.K. 4/7/86
+ add dx, [di].Hidden_Trks ;else add hidden trks.- J.K. 4/7/86
+DISK_NOT_MINI: ;J.K. 4/7/86
+ ROR DH,1
+ ROR DH,1
+
+ OR DH,CS:[CURSEC]
+ MOV CX,DX
+ XCHG CH,CL ; CL = SECTOR, CH = CYLINDER
+ MOV DH,BYTE PTR CS:[CURHD] ; LOAD CURRENT HEAD NUMBER AND
+ MOV DL,BYTE PTR [DI].DRIVENUM ; PHYSICAL DRIVE NUMBER
+ CMP BYTE PTR [DI].FORMFACTOR,FFHARDFILE
+ JZ DO_FAST ; HARD FILES USE FAST SPEED
+; IF WE HAVE [STEP_DRV] SET TO -1, WE USE THE SLOW SETTLE TIME.
+; THIS HELPS WHEN WE HAVE JUST DONE A RESED DISK OPERATION AND THE HEAD HAS
+; BEEN MOVED TO ANOTHER CYLINDER - THE PROBLEM CROPS UP WITH 3.5" DRIVES.
+ CMP CS:[STEP_DRV],-1
+ JZ DO_WRITEJ
+ CMP AH,ROMREAD ; ARR 2.20
+ JE DO_FAST
+ CMP AH, ROMVERIFY
+ JE DO_FAST
+DO_WRITEJ:
+; READS ALWAYS FAST, UNLESS WE HAVE JUST DONE A DISK RESET OPERATION
+ JMP DO_WRITE ; ARR 2.20 READS ALWAYS FAST
+DO_FAST: ; ARR 2.20
+ CALL FASTSPEED ; MZ 2.21 CHANGE SETTLE MODE
+TESTERR: ; MZ 2.21
+ JC DSKERR_brdg
+; SET DRIVE AND TRACK OF LAST ACCESS
+ MOV CS:[STEP_DRV],DL ; ARR 2.20 SET DRIVE
+ MOV BYTE PTR [DI].TRACK,CH ; ARR 2.20 SAVE TRACK
+NO_SET:
+ CMP CS:WRTVERIFY,103H ; CHECK FOR WRITE AND VERIFY
+ JZ DOVERIFY
+NOVERIFY:
+ POP AX
+
+;SB34DISK003*****************************************************************
+;SB Check the flags word in the BDS to see if the drive is non removable
+;SB If not we needn't do anything special
+;SB If it is a hard disk then check to see if multi-track operation
+;SB is specified. If specified we don't have to calculate for the next
+;SB track since we are already done. So we can go to the exit of this
+;SB routine. 5 LOCS
+
+ test word ptr [di].FLAGS, fNON_REMOVABLE
+ jz ITS_REMOVABLE
+ test CS:MulTrk_Flag, MulTrk_ON
+ jnz DISK_RET
+ITS_REMOVABLE:
+;SB34DISK003*****************************************************************
+ 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
+NEXTTRACK:
+ MOV CS:[CURSEC],1 ; START WITH FIRST SECTOR OF NEXT TRACK
+ MOV DH,CS:[CURHD]
+ INC DH
+ CMP DH,BYTE PTR [DI].HDLIM
+ JB NOXOR
+ XOR DH,DH
+ INC CS:[CURTRK] ;NEXT TRACK
+NOXOR:
+ MOV CS:[CURHD],DH
+DISK_RET:
+ CLC ; LEEAC
+ RET
+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] ; ARR 2.20
+ JNZ DO_NORM ; WE HAVE CHANGED DRIVES
+
+ CMP CH,BYTE PTR [DI].TRACK ; ARR 2.20
+ JZ DO_FAST ; WE ARE STILL ON THE SAME TRACK
+
+DO_NORM:
+ CALL NORMSPEED
+ JMP SHORT TESTERR ; MZ 2.21 TEST FOR ERROR
+DO_WRITE ENDP
+;
+; WE HAVE A VERIFY REQUEST ALSO. GET STATE INFO AND GO VERIFY
+;
+
+DOVERIFY PROC NEAR
+ POP AX ; RESTORE SECTOR COUNT
+ PUSH AX
+ MOV AH,ROMVERIFY ; REQUEST VERIFY
+ CALL FASTSPEED ; MZ 2.21 CHANGE SETTLE MODE
+ JNC NOVERIFY
+
+;SB34DISK004**************************************************************
+;SB check the error returned in AH to see if it is a SOFT ECC error.
+;SB If it is not we needn't do anything special. If it is a SOFT
+;SB ECC error then decrement the SOFT_ECC_CNT error retry count. If
+;SB this retry count becomes 0 then we just ignore the error and go to
+;SB No_verify but if we can still try then we call the routine to reset
+;SB the disk and go to DSKerr1 to retry the operation. 6 LOCS
+
+ cmp ah,11h ;SOFT ECC error ?
+ jnz Not_SoftECC_Err
+ dec SOFT_ECC_CNT
+ jz NoVerify ;no more retry
+ call ResetDisk ;reset disk
+ jmp DskErr1 ;retry
+
+;SB34DISK004**************************************************************
+
+Not_SoftECC_Err: ;AN003;Other error.
+ call ResetDisk ;AN003;
+ dec VRetry_Cnt ;AN003;
+ jmp DskErr0 ;AN003;
+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 ;|
+;---------------------------------------;|
+
+ cmp cs:MultiTrk_Format_Flag, 1 ;AN007;Multi trk format request?
+ jne DoChkAgain ;AN007;
+ mov bp, 1 ;AN007;No more retry.
+ mov cs:MultiTrk_Format_Flag, 0 ;AN007;Clear the flag.
+DoChkAgain: ;AN007;
+ CALL AGAIN
+DskErr0: ;AN003;
+ JZ HARDERR
+ test word ptr [di].FLAGS, fNon_Removable ;AN009;
+ jnz Skip_TimeOut_Chk ;AN009;
+ CMP AH,80H ;TIMEOUT?
+ JZ HARDERR ;***
+Skip_TimeOut_Chk: ;AN009;
+ cmp ah, 0cch ;AN003;Write Fault error?
+ jz Write_Fault_Err ;AN003; Then, don't retry.
+ mov cs:Soft_ECC_Cnt, MAXERR ;AN003;Set Soft_ECC_Cnt back to MAXERR
+DSKERR1:
+ POP AX ;RESTORE SECTOR COUNT
+ JMP RETRY
+
+Write_Fault_Err: ;AN003;
+ mov bp, 1 ;AN003;Just retry only once for Write Fault error.
+ jmp DskErr1 ;AN003;
+
+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
+; NOTE THAT THIS ROUTINE IS NEVER CALLED FOR A FIXED DISK.
+;
+NORMSPEED PROC NEAR
+ cmp cs:[Media_Set_For_Format], 0 ;AN012;
+ jne FASTSPEED ;AN012;
+ PUSH DS
+ PUSH AX
+ MOV AL,CS:SETTLESLOW
+ LDS SI,CS:DPT ; CURRENT DISK PARM TABLE
+ MOV [SI].DISK_HEAD_STTL,AL
+ POP AX
+ POP DS
+ CALL FASTSPEED
+ PUSH DS
+ LDS SI,CS:DPT
+ MOV [SI].DISK_HEAD_STTL,1 ; 1 IS FAST SETTLE VALUE
+ 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 iTEST
+ JZ READY
+ JMP NOTREADY
+READY:
+ ELSE
+ JNZ NOTREADY
+ ENDIF
+
+ MESSAGE FTESTINIT,<"<">
+ 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
+DEATH:
+ RET
+NOTREADY:
+ STC
+ MOV AH,80H
+ JMP DEATH
+FASTSPEED ENDP
+
+; MAP ERROR RETURNED BY ROM IN AH 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 ;PUT ERROR CODE IN 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
+;SB33018******************************************************************
+ xor AH, AH ; set command to get time ;SB;3.30*
+ int 1Ah ; call rom-bios timer function ;SB;3.30*
+;SB33018******************************************************************
+ OR AL,AL
+ JZ NOROLL3
+ INC CS:[DAYCNT] ; CATCH ROLLOVER
+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
+ JNZ SETACCESS
+ CMP CX,WORD PTR [DI].TIM_HI
+ JZ DONE_SET
+SETACCESS:
+ MOV BYTE PTR CS:[ACCESSCOUNT],0
+ MOV WORD PTR [DI].TIM_LO,DX ;SAVE IT
+ MOV WORD PTR [DI].TIM_HI,CX
+DONE_SET:
+ CLC
+ POP AX
+ RET
+SET_TIM ENDP
+
+ ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING
+
+;
+; THIS IS THE TRUE INT 13 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
+
+;J.K. 1/30/87 To handle the ps2_30 machine 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 ?
+
+
+; 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
+ CMP AH,ROMFORMAT
+ JNZ NOT_FORMAT
+; 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:
+ test dl, 80h ; floppy or hard disk?
+ jnz not_floppy ; if hard, skip this nonsense
+ cmp cs:EC35_Flag, 0 ; any electrically compat. drives?
+ jz not_floppy ; no; proceed unhindered
+ SAVEREG
+ mov cl, dl ; turn drive number into bit map:
+ mov al, 1 ; assume drive 0
+ shl al, cl ; shift over correct number of times
+ test al, cs:EC35_Flag ; is THIS drive an electrically compatible 3.5 incher?
+ jz not_EC35 ; no; don't change anything
+ mov bl, dl ; which drive was it?
+ xor bh, bh ; need only one byte of index
+ push es ; need a segment register
+ mov ax, 40h ; the machine state byte is in the...
+ mov es, ax ; ...segment at 40h
+ mov byte ptr es:[90h+bx], 93H ; establish drive type as: (360k disk in 360k drive, no double-stepping, 250 kbs transfer rate)
+ pop es ; fix up register again
+not_EC35:
+ RESTOREREG
+not_floppy:
+ cmp cs:[model_byte], mdl_ps2_30 ; is this a ps2/30?
+ jne not_ps2_30 ; if not, just do normal call
+ cmp ah, 8 ;J.K. 1/30/87 Read Driver Parm ?
+ je ps2_30_Problem ;J.K. 1/30/87
+ cmp ah, 15h
+ je ps2_30_Problem
+not_ps2_30:
+ CALL ORIG13 ; SIMULATE INT 13
+ JC GOTERR13_br ; ERROR?
+ RET 2 ; NO, RETURN AND CLEAR FLAGS
+
+GOTERR13_br: jmp Goterr13
+
+;J.K.1/30/87 ps2_30 machine has some problem with AH=8h(Read Drive Parm), Int 13h.
+;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.
+
+ps2_30_Problem: ;J.K. 1/30/87; ps2_30 = PS2 Model 30.
+ 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 of this call.
+
+ 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 ;AN011; DMA error?
+ je Chk_ValidMedia_ERR13 ;AN011;
+ cmp ah, 11h ;AN011; ECC error?
+ je Chk_ValidMedia_ERR13 ;AN011;
+ jmp Skip_Ecc_Check ;AN011; Other error. Just return back.
+
+Chk_ValidMedia_ERR13: ;AN011;If SetDrive fails, then just
+ push ds ;AN011; return back to INT 13h caller,
+ push di ;AN011; without performing ECC, DMA
+ push ax ;AN011; error handling.
+ mov byte ptr cs:[Phys_Drv], 1 ;AN011;
+ mov al, dl ;AN011;
+ call SetDrive ;AN011;
+ mov byte ptr cs:[Phys_Drv], 0 ;AN011;
+ pop ax ;AN011;
+ pop di ;AN011;
+ pop ds ;AN011;
+ jc Skip_Ecc_Check ;AN011;
+
+; TEST OF BIT PATTERN 08H LET OTHER ERRORS BE PASSED AS DMA ERRORS - PTR 32D0519
+; TEST AH,08H ; DMA BIT
+ CMP AH, 09H ; DMA ERROR CODE
+ JNZ CHECK_ECC
+ JMP GOTDMAERR
+CHECK_ECC:
+;J.K. AN003; Soft ECC bug is only applied to PC1 and PC-XT. So, we will enforce
+;this ECC error handler for them. Also, since CMC hardfiles in PC AT also
+;generate a lot of unnecessary ECC errors, we will still cover PC ATs as
+;it is done in the earlier version of MSBIO.
+;During Format/Verify operation, we are going to consider any Soft Ecc as a
+;hard error.
+
+;SB34DISK005*****************************************************************
+;SB See if the machine we are operating on is a PC, XT or AT by checking
+;SB the model byte. The soft ECC bug is only on these machines and if
+;SB the machine we are operating on is not one of these three then we
+;SB needn't do anything special. If we are operating one these however
+;SB we check to see if the error occured during format by checking
+;SB media_set_for_format. If it did occur during format we cannot do
+;SB anything but if not during format then check to see if the error
+;SB returned in AH is the SOFT_ECC error and if so go to OK11 since
+;SB the error can be ignored. 6 LOCS
+
+ cmp cs:[Media_Set_For_Format], 1 ; formatting?
+ je Skip_Ecc_Check
+ cmp cs:[Model_Byte], 0FEh ; PC or XT?
+ jae Go_Chk_Ecc
+ cmp cs:[Model_Byte], 0FBh ; XT?
+ je Go_Chk_Ecc
+ cmp cs:[Model_Byte], 0FCh
+ jne Skip_Ecc_Check
+ cmp cs:[Secondary_Model_Byte], 2 ; AT?
+ ja Skip_Ecc_Check
+Go_Chk_Ecc: ; for PC, XT, AT
+ CMP AH,11H
+ JZ OK11
+Skip_Ecc_Check: ;AN003; Just return back to INT 13h caller.
+
+;SB34DISK005*****************************************************************
+
+ 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
+;J.K. 8/29/86 Here, it is better reset the system. So, we are going to
+;call Orig13 again
+
+ xor ah, ah
+ call Orig13 ;reset. Don't care about the result
+
+ 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
+ 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]
+ MOV AL,1 ; REQUEST FOR ONE SECTOR ONLY
+;
+; WE DO READS ONE SECTOR AT A TIME. THIS ENSURES THAT WE WILL EVENTUALLY
+; FINISH THE REQUEST SINCE ECC ERRORS ON ONE SECTOR DO READ IN THAT SECTOR.
+;
+; WE NEED TO PUT IN SOME "INTELLIGENCE" INTO 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 MAY BE A STARTING SECTOR NUMBER THAT IS BIGGER THAN THE NUMBER
+; OF SECTORS ON A TRACK.
+;
+ CALL CHECK_WRAP ; GET CORRECT PARAMETERS FOR INT 13
+ PUSHF
+ CALL ORIG13
+ JNC OK11_OP
+ CMP AH,11H ; ONLY ALLOW ECC ERRORS
+ JNZ OK11_EXIT_err ;J.K. 8/26/86 Other error?
+ mov ah, 0 ;J.K. ECC error. Reset the system again.
+ pushf
+ call Orig13
+ xor ax, ax ; clear the error code so that if this
+ ; was the last sector, no error code
+ ; will be returned for the corrected
+ ; read. (clear carry too.)
+OK11_OP:
+ DEC CS:[NUMBER_OF_SEC]
+ JZ OK11_EXIT ; ALL DONE?
+ INC CL ; ADVANCE SECTOR NUMBER
+ INC BH ; ADD 200H TO ADDRESS
+ INC BH
+ JMP SHORT LOOP_ECC
+OK11_EXIT_err:
+ stc ;J.K. 8/28/86 Set carry bit again.
+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
+ STI
+ CMP AH,ROMREAD ; SAVE USER FLAGS
+ 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
+ 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 UP HEAD NUMBER
+ JMP BUFFER ;J.K. 4/10/86
+; JMP SHORT BUFFER
+;
+; DX IS THE PHYSICAL 16 BITS OF START OF TRANSFER. COMPUTE REMAINING
+; SECTORS IN SEGMENT.
+;
+NO_SKIP_FIRST:
+ 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. -J.K. 4/10/86
+; 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. - J.K. 2/28/86
+
+DoBlock:
+;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.
+
+ Message ftestDisk,<"!!!DMA DoBlock!!!">
+
+ mov dx, word ptr [bp.olddx] ;set head #
+ push di
+ push ds
+ push ax ;AH - # of sectors before DMA boundary
+ ;AL - User requeseted # of sectors for I/O.
+ 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 operation.
+ 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 boundary
+ 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 for 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 modificaion of DoBlock - J.K. 2/28/86
+;The following is the original one.
+; PUSH AX
+; MOV AL,AH ; get max to operate on
+; MOV AH,BYTE PTR [BP.oldax+1]; get function
+; mov dh,byte ptr [BP.olddx+1] ; set up head number
+; 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
+; ADD BH,AH ; advance DMA address
+; ADD BH,AH ; twice for 512 byte sectors.
+
+;
+; THE NEXT REQUEST WILL WRAP THE 64K BOUNDARY. IF WE ARE WRITING, THEN COPY
+; THE OFFENDING SECTOR INTO OUR SPACE.
+;
+; ES:BX POINTS TO THE SECTOR
+; CX,DX CONTAIN THE CORRECT TRACK/SECTOR/HEAD/DRIVE INFO
+; [BP.OLDAX] HAS CORRECT FUNCTION CODE
+;
+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
+; SEE IF WE ARE WRAPPING AROUND A TRACK OR HEAD
+ MOV DL,BYTE PTR [BP.OLDDX] ; GET DRIVE NUMBER
+ CALL CHECK_WRAP ; SETS UP REGISTERS IF WRAP-AROUND
+;
+; 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
+; SEE IF OUR REQUEST WILL WRAP A TRACK OR HEAD BOUNDARY
+ MOV DL,BYTE PTR [BP.OLDDX] ; GET DRIVE NUMBER
+ CALL CHECK_WRAP ; SETS UP REGISTERS IF WRAP-AROUND
+;
+; 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
+; SEE IF WE WRAP AROUND A TRACK OR HEAD BOUNDARY WITH STARTING SECTOR
+; WE ALREADY HAVE THE CORRECT HEAD NUMBER TO PASS TO CHECK_WRAP
+ MOV DL,BYTE PTR [BP.OLDDX] ; GET DRIVE NUMBER
+ CALL CHECK_WRAP ; SETS UP REGISTERS IF WRAP-AROUND
+ 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:
+; DH - CONTAINS STARTING HEAD NUMBER FOR REQUEST
+; CX - 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 PHYSICAL DRIVE IN AL TO GET BDS
+ MOV AL,DL ; AL HAS PHYSICAL DRIVE NUMBER
+ 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 PHYSICAL 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 ; ARE WE GOING TO WRAP?
+ JBE NO_WRAP
+ DIV BL ; AH=NEW SECTOR #, AL=# OF HEAD WRAPS
+; WE NEED TO BE CAREFUL HERE. IF THE NEW SECTOR # IS 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 BOUNDARY
+ DEC AL ; ALSO DECREMENT # OF 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
+; 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
+ CLD
+ PUSH CX
+ MOV CX,512/2
+;J.K. Warning!!! Do not change the position of this label.
+; The following three bytes will be NOPed out by MSINIT if the system
+; does not support the DOUBLE WORD MOV instruction, i.e., (if
+; not 386 base machine.)
+;----------------------------------------------------------------------------
+ public DoubleWordMov
+DoubleWordMov: ;AN002;
+ shr cx, 1 ;AN002;Make it a double word.
+ db 66h ;AN002;Machine code for double word mov
+;----------------------------------------------------------------------------
+ REP MOVSW
+ POP CX
+ RET
+MOVE ENDP
+
+DOINT PROC NEAR
+ MOV DL,BYTE PTR [BP.OLDDX] ; GET PHYSICAL DRIVE NUMBER
+ XOR AH,AH
+ OR AL,AL
+ JZ DOINTDONE
+ MOV AH,BYTE PTR [BP.OLDAX+1] ; GET REQUEST CODE
+ PUSH [BP.OLDF]
+ CALL ORIG13
+ PUSHF
+ POP [BP.OLDF]
+DOINTDONE:
+ RET
+DOINT ENDP
+CODE ENDS
+ END
diff --git a/v4.0/src/BIOS/MSDSKPR.INC b/v4.0/src/BIOS/MSDSKPR.INC
new file mode 100644
index 0000000..6b24bff
--- /dev/null
+++ b/v4.0/src/BIOS/MSDSKPR.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/v4.0/src/BIOS/MSEQU.INC b/v4.0/src/BIOS/MSEQU.INC
new file mode 100644
index 0000000..d45577b
--- /dev/null
+++ b/v4.0/src/BIOS/MSEQU.INC
@@ -0,0 +1,76 @@
+%OUT MSEQU.INC...
+;==============================================================================
+
+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
+
+;AN000; Extended BPB structure.
+BPB_TYPE STRUC
+SECSIZE DW ?
+SECALL DB ?
+RESNUM DW ?
+FATNUM DB ?
+DIRNUM DW ?
+SECNUM DW ?
+FATID DB ?
+FATSIZE DW ?
+SLIM DW ?
+HLIM DW ?
+HIDDEN_L DW ?
+HIDDEN_H dw 0 ;J.K.
+SECNUM_L dw 0 ;J.K.
+SECNUM_H dw 0 ;J.K.
+BPB_TYPE ENDS
+
+;;;;;;;;;;;
+BOOT_SERIAL_SIZE equ 4 ;J.K.
+BOOT_VOLUME_LABEL_SIZE equ 11 ;J.K.
+BOOT_SYSTEM_ID_SIZE equ 8 ;J.K.
+EXT_BOOT_SIGNATURE equ 41 ;J.K.
+RSINIT=0A3H ;RS232 INITIALIZATION
+ ;9600 BAUD:NO PARITY:1 STOP:8 BIT WORD
+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 ; ARR 2.20 ADDRESS OF HEAD SETTLE TIME
+NORMSETTLE=15 ; ARR 2.20 NORMAL HEAD SETTLE
+SPEEDSETTLE=0 ; ARR 2.20 SPEED UP SETTLE TIME
+INITSPOT=534H ; ARR 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
+
+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.
+ERROR_UNKNOWN_MEDIA = 7 ; FOR USE IN BUILD BPB CALL
+
+PATHGEN = 1
diff --git a/v4.0/src/BIOS/MSEXTRN.INC b/v4.0/src/BIOS/MSEXTRN.INC
new file mode 100644
index 0000000..b72d879
--- /dev/null
+++ b/v4.0/src/BIOS/MSEXTRN.INC
@@ -0,0 +1,97 @@
+; SCCSID = @(#)IBMEXTRN.ASM 1.11 85/11/18
+;This is for IBMINIT module.
+;=======================================================
+;REVISION HISTORY:
+;AN000; - NEW Version 4.00. J.K.
+;AC000; - Modified Line 4.00. J.K.
+;ANxxx; - PTMyyy
+;==============================================================================
+;AN001; D486 SHARE installation for large media 2/23/88 J.K.
+;==============================================================================
+
+ EXTRN ORIG13:DWORD,ORIG19:DWORD
+ EXTRN COM2DEV:WORD,COM1DEV:WORD
+ EXTRN COM4DEV:WORD,COM3DEV:WORD
+ 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 -J.K. 4/7/86
+ EXTRN HaveCMOSClock:byte ;set by IBMINIT. Used by IBMCLOCK.ASM
+ EXTRN BinToBCD:word ;set by IBMINIT. Used by IBMCLOCK.ASM
+ EXTRN DaycntToDay:word ;set by IBMINIT. Used by IBMCLOCK.ASM
+ EXTRN OLD13:DWORD
+ extrn Temp_H:word ;J.K. For 32 bit calculation. IBMDISK
+ extrn Start_Sec_H:word ;J.K. IBMDISK.
+ extrn KEYRD_Func:byte ;J.K. For IBMCON. Defined in IBMBDATA.
+ extrn KEYSTS_Func:byte ;J.K. For IBMCON. Defined in IBMBDATA.
+ extrn DiskSector:byte ;J.K. IBMBDATA
+ extrn Bpb_In_Sector:word ;J.K. IBMBDATA
+ extrn SecPerCLusInSector:Byte ;J.K. IBMBDATA
+ extrn NumberOfFats:byte ;J.K. IBMBDATA
+ extrn MediaByte:byte ;J.K. IBMBDATA
+ extrn Ext_Boot_Sig:Byte ;J.K. IBMBDATA
+ extrn Boot_Serial_L:Word ;J.K. IBMBDATA
+ extrn Boot_Serial_H:Word ;J.K. IBMBDATA
+ extrn Boot_Volume_Label:Byte ;J.K. IBMBDATA
+ extrn Boot_System_ID:Byte ;J.K. IBMBDATA
+ extrn Fat_12_ID:Byte ;J.K. IBMDISK
+ extrn Fat_16_ID:Byte ;J.K. IBMDISK
+ extrn Vol_No_Name:Byte ;J.K. IBMDISK
+ extrn MotorStartup:Byte ;J.K. IBMBDATA
+ extrn DoubleWordMov:Byte ;J.K. IBMDISK
+ extrn Model_Byte:Byte ;J.K. IBMBIO2
+ extrn Secondary_Model_Byte:Byte ;J.K. IBMBIO2
+
+ IF iTEST
+ IFNDEF NUMBUF
+ EXTRN NUMBUF:BYTE,DIGITS:BYTE,FTESTBITS:WORD
+ ENDIF
+ 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
+ EXTRN OUTCHR:NEAR,WRMSG:NEAR,TIME_TO_TICKS:NEAR
+ EXTRN INT2F_DISK:NEAR,INSTALL_BDS:NEAR,SETDRIVE:NEAR
+ extrn Mov_Media_IDs:Near ;J.K.
+ extrn Clear_IDs:Near ;J.K.
+ IF iTEST
+ IFNDEF NUMBUF
+ EXTRN MSGNUM:NEAR,MSGOUT:NEAR,dumpbytes:near,hex_to_ascii:near
+ EXTRN outchar:near
+ ENDIF
+ 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
+ extrn Big_Media_Flag:Byte ;AN001;
+SYSINITSEG ENDS
+
+ ASSUME CS:CODE
+
+; 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/v4.0/src/BIOS/MSGROUP.INC b/v4.0/src/BIOS/MSGROUP.INC
new file mode 100644
index 0000000..ac6202d
--- /dev/null
+++ b/v4.0/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/v4.0/src/BIOS/MSHARD.ASM b/v4.0/src/BIOS/MSHARD.ASM
new file mode 100644
index 0000000..51c0dc8
--- /dev/null
+++ b/v4.0/src/BIOS/MSHARD.ASM
@@ -0,0 +1,427 @@
+;***
+; Title: Disk
+; C: (C) Copyright 1988 by Microsoft corp.
+; Date: 1/11/85
+;
+; There is a bug in some versions of IBM's AT ROM BIOS.
+; Interrupts 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:
+;; Old code - Carry cleared after set by logical or opearation
+;; POP AX
+;; MOV AH,DISK_STATUS1 ;On return AH has error code
+;; STC
+;; OR AH,AH
+;; JNZ ATD5 ;Carry set if error
+;; CLC
+;;---------------------------------------------------
+;; New Code - Let Logical or clear carry and then set carry if ah!=0
+;; And save a couple bytes while were at it.
+ POP AX
+ MOV AH,DISK_STATUS1 ;On return AH has error code
+ OR AH,AH
+ JZ ATD5 ;Carry set if error
+ STC
+
+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 WAITT ;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
+
+
+
+;*** WAITT - 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.
+;
+WAITT PROC NEAR
+ PUSH OFFSET ROMFRET
+ JMP ROMWAIT
+WAITT 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/v4.0/src/BIOS/MSINIT.ASM b/v4.0/src/BIOS/MSINIT.ASM
new file mode 100644
index 0000000..d00c8af
--- /dev/null
+++ b/v4.0/src/BIOS/MSINIT.ASM
@@ -0,0 +1,2819 @@
+ PAGE ,132 ;
+ %OUT ...MSINIT.ASM
+;=======================================================
+;REVISION HISTORY:
+;AN000; - NEW Version 4.00. J.K.
+;AC000; - Modified Line 4.00. J.K.
+;ANxxx; - PTMyyy
+;==============================================================================
+;AN001; P87 Set the value of MOTOR START TIME Variable 6/25/87 J.K.
+;AN002; P40 Boot from the system with no floppy diskette drives 6/26/87 J.K.
+;AN003; D9 Double Word MOV instruction for 386 based machine 7/1/87 J.K.
+;AN004; D64 Extend DOS 3.3 FAT tables to 64 K entries. 7/8/87 J.K.
+;AN005; D113 Disable I/O access to unformatted media 9/03/87 J.K.
+;AN006; p941 D113 does not implemented properly. 9/11/87 J.K.
+;AN007; p969 Should Honor OS2 boot record. 9/11/87 J.K.
+;AN008; p985 Allow I/O access to unformtted media 9/14/87 J.K.
+;AN009; p1535 Disallow I/O access to unformtted media 10/15/87 J.K.
+;AN010; p2349 Cover DOS 3.3 and below FDISK bug 11/10/87 J.K.
+;AN011; P2431 OS2 boot record version number is at offset 7 (not 8)11/12/87 J.K.
+;AN012; P2900 DOS 4.0 does not recognize 3.0 formatted media 12/18/87 J.K.
+;AN013; P3409 Extended keyboard not recognized 02/05/88 J.K.
+;AN014; D486 Share installation for big media 02/23/88 J.K.
+;AN015; P3929 Boot record buffer overlaps MSBIO code 03/18/88 J.K.
+;==============================================================================
+
+ itest = 0
+ INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT
+ INCLUDE MSDSKPR.INC
+ INCLUDE MSEQU.INC
+ INCLUDE MSMACRO.INC
+ INCLUDE MSEXTRN.INC
+ INCLUDE BIOSTRUC.INC
+ INCLUDE CMOSEQU.INC
+ include cputype.inc
+
+; THE FOLLOWING LABEL DEFINES THE END OF THE AT ROM PATCH. THIS IS USED AT
+; CONFIGURATION TIME.
+;J.K. 10/2/86 Waring!!! 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.
+;J.K. 10/2/86 Waring!!! This code will be dynamically relocated by MSINIT.
+
+ EXTRN base_century:byte
+ EXTRN base_year:byte
+ EXTRN month_tab:byte
+
+ public Daycnt_to_day ;J.K. 4/30/86 for real time clock support
+Daycnt_to_day proc near ;J.K. 4/30/86 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)) ;# of 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 years!
+ add base_year, al ;So, ah = 0. Adjust year accordingly.
+ inc daycnt ;set daycnt to 1 base
+ cmp daycnt, 366 ;the daycnt here is the remainder of the leap year block.
+ jbe Leapyear ;So, it should within 366+355+355+355 days.
+ inc base_year ;First if daycnt <= 366, then leap year
+ sub daycnt, 366 ;else daycnt--, base_year++;
+ ;And the next three years are regular years.
+ 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 the 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] ;compare daycnt for each month until fits
+ 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 ;now, al=day, dl=month,dh=year,cl=century
+ call word ptr BinToBCD ;Oh my!!! To save 15 bytes, Bin_To_BCD proc
+ ;was relocated seperately 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 ;J.K. 4/30/86 for real time clock support
+;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 for bcd, ah - low digit for 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 supporting routines for CMOS clock setting.
+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 address
+
+ EVENB
+;
+; THE K09 REQUIRES THE 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.
+
+;J.K. 10/2/86 Waring!!! 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
+;SB33019***************************************************************
+ MOV AH, 01h ; COMMAND TO SET THE TIME ;SB;3.30
+ INT 1Ah ; CALL ROM-BIOS TIME ROUTINE ;SB;3.30
+;SB33019***************************************************************
+ STI
+ JMP INT6C_RET_ADDR ; LONG JUMP
+
+INT6C ENDP
+
+
+ INCLUDE READCLOC.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
+
+;*********************************************************
+; SYSTEM INITIALIZATION
+;
+; 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.
+;
+;********************************************************
+
+;SYSIZE=200H ;NUMBER OF PARAGRAPHS IN SYSINIT MODULE
+sysize=500h ;AC000;
+
+; DRVFAT MUST BE THE FIRST LOCATION OF FREEABLE SPACE!
+ EVENB
+DRVFAT DW 0000 ;DRIVE AND FAT ID OF DOS
+BIOS$_L DW 0000 ;FIRST SECTOR OF DATA (Low word)
+bios$_H dw 0000 ;First sector of data (High word)
+DOSCNT DW 0000 ;HOW MANY SECTORS TO READ
+FBIGFAT DB 0 ; FLAGS FOR DRIVE
+;an004
+;FATLEN DW ? ; NUMBER OF SECTORS IN FAT.
+FATLOC DW ? ; SEG ADDR OF FAT SECTOR
+Init_BootSeg dw ? ;AN015; seg addr of buffer for reading boot record
+ROM_drv_num db 80h ;AN000; rom drv number
+;Boot_Sec_Per_Fat dw 0 ;AN000; Boot media sectors/FAT
+Md_SectorSize dw 512 ;AN004; Used by Get_Fat_Sector proc.
+Temp_Cluster dw 0 ;AN004; Used by Get_Fat_Sector proc.
+Last_Fat_SecNum dw -1 ;AN004; Used by Get_Fat_Sector proc.
+
+; THE FOLLOWING TWO BYTES ARE USED TO SAVE THE 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 RETURNED BY ROM
+
+FakeFloppyDrv db 0 ;AN002; If 1, then No diskette drives in the system.
+
+BOOTBIAS = 200H
+BOOT_ADDR = 7C00H
+EXT_BOOT_SIG_OFF = 11+size BPB_TYPE ;AN000; 3 byte jmp+8 byte OEM +extended bpb
+
+
+ EVENB
+DISKTABLE DW 512, 0100H, 64, 0
+ DW 2048, 0201H, 112, 0
+ DW 8192, 0402H, 256, 0
+ DW 32680, 0803H, 512, 0 ;Warning !!! Old values
+; DW 20740, 0803H, 512, 0 ;PTM P892 J.K. 12/3/86 DOS 3.3 will use this.
+ ;J.K.3/16/87 P54 Return back to old value for compatibility.!!!
+ DW 65535, 1004H, 1024, 0
+
+;DISKTABLE2 DW 32680, 0803H, 512, 0 ;Warning !!! Old values ;J.K.3/16/87 P54 Return to old value!!!
+;DISKTABLE2 DW 20740, 0803H, 512, 0 ;PTM p892 J.K. 12/3/86 DOS 3.3 will use this.
+; DW 65535, 0402H, 512, FBIG
+;AN000;
+;DISKTABLE2 dw 0, 32680, 0803h, 512, 0 ;table with the assumption of the
+; dw 2h, 0000h, 0402h, 512, FBIG ;total fat size <= 64KB.
+; dw 4h, 0000h, 0803h, 512, FBIG ;-This will cover upto 134 MB
+; dw 8h, 0000h, 1004h, 512, FBIG ;-This will cover upto 268 MB
+; dw 10h, 0000h, 2005h, 512, FBIG ;-This will cover upto 536 MB
+
+;AN004 Default DiskTable under the assumption of Total FAT size <= 128 KB, and
+; the maxium size of FAT entry = 16 Bit.
+DiskTable2 dw 0, 32680, 0803h, 512, 0 ;For compatibility.
+ dw 4h, 0000h, 0402h, 512, FBIG ;Covers upto 134 MB media.
+ dw 8h, 0000h, 0803h, 512, FBIG ; upto 268 MB
+ dw 10h, 0000h, 1004h, 512, FBIG ; upto 536 MB
+ dw 20h, 0000h, 2005h, 512, FBIG ; upto 1072 MB
+ dw 40h, 0000h, 4006h, 512, FBIG ; upto 2144 MB
+ dw 80h, 0000h, 8007h, 512, FBIG ; upto 4288 MB...
+
+;******************************************************************************
+;Variables for Mini disk initialization - J.K. 4/7/86
+;******************************************************************************
+End_Of_BDSM dw ? ;offset value of the ending address
+ ;of BDSM table. Needed to figure out
+ ;the Final_DOS_Location.
+numh db 0 ;number of hard files
+mininum db 0 ;logical drive number for mini disk(s)
+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 the
+ ;Mini Disk BPB pointer address in DskDrvs.
+;J.K. 4/7/86 End of Mini Disk Init Variables **********************************
+
+
+BIOS_DATE DB '01/10/84',0 ;This is used for checking AT ROM BIOS date.
+
+; 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
+ DW 0
+ dw 0 ;AN000; hidden sector High
+ dd 0 ;AN000; extended total sectors
+
+; 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
+ DW 0
+ dw 0 ;AN000; hidden sector High
+ dd 0 ;AN000; extended total sectors
+
+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
+ DW 0
+ dw 0 ;AN000; hidden sector High
+ dd 0 ;AN000; extended total sectors
+
+ 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.
+;J.K.
+; AX = first data sector (High)
+; DI = Sectors/FAT for the boot media.
+;
+ PUBLIC INIT
+INIT PROC NEAR
+ MESSAGE FTESTINIT,<"IBMBIO",CR,LF>
+ CLI
+ push ax
+ XOR AX,AX
+ MOV DS,AX
+ pop ax
+;J.K. MSLOAD will check the extended boot record and set AX, BX accordingly.
+
+;SB34INIT000*************************************************************
+;SB MSLOAD passes a 32 bit sector number hi word in ax and low in bx
+;SB Save this in cs:BIOS$_H and cs:BIOS$_L. This is for the start of
+;SB data sector of the BIOS.
+
+ mov cs:BIOS$_H,ax
+ mov cs:BIOS$_L,bx
+
+;SB34INIT000*************************************************************
+
+;J.K. With the following information from MSLOAD, we don't need the
+; Boot sector any more.-> This will solve the problem of 29 KB size
+; limitation of MSBIO.COM file.
+;J.K. AN004 - Don't need this information any more, since we are not going to
+; read the whole FAT into memory.
+; mov cs:Boot_Sec_Per_FAT, di ;sectors/FAT for boot media. ;AN000;
+
+;
+; 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 ;GET EQUIPMENT STATUS
+;J.K.6/24/87 We have to support a system that does not have any diskette
+;drives but only hardfiles. This system will IPL from the hardfile.
+;If the equipment flag bit 0 is 1, then the system has diskette drive(s).
+;Otherwise, the system only have hardfiles.
+;Important thing is that still, for compatibility reason, the drive letter
+;for the hardfile start from "C". So, we still need to allocate dummy BDS
+;drive A and driver B. In SYSINIT time, we are going to set CDS table entry
+;of DPB pointer for these drives to 0, so any user attempt to access this
+;drives will get "Invalid drive letter ..." message. We are going to
+;establish "FAKEFLOPPYDRV" flag. ***SYSINIT module should call INT 11h to check
+;if there are any diskette drivers in the system or not.!!!***
+
+;SB34INIT001**************************************************************
+;SB check the register returned by the equipment determination interrupt
+;SB we have to handle the case of no diskettes in the system by faking
+;SB two dummy drives.
+;SB if the register indicates that we do have floppy drives we don't need
+;SB to do anything special.
+;SB if the register indicates that we don't have any floppy drives then
+;SB what we need to do is set the FakeFloppyDrv variable, change the
+;SB register to say that we do have floppy drives and then go to execute
+;SB the code which starts at NOTSINGLE. This is because we can skip the
+;SB code given below which tries to find if there are one or two drives
+;SB since we already know about this. 6 LOCS
+
+ test ax,1
+ jnz DO_FLOPPY
+ mov cs:FakeFloppyDrv,1 ; fake floppy
+ mov ax,1 ; set to indicate 2 floppies
+ jmp short NOTSINGLE
+
+DO_FLOPPY:
+
+;SB34INIT001**************************************************************
+ ;
+ ; Determine if there are one or two diskette drives in system
+ ;
+ 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 ;CH IS FAT ID, CL # FLOPPIES
+ TEST DL,80H ;BOOT FROM FLOPPY ?
+ JNZ GOTHRD ;NO.
+ XOR AX,AX ;INDICATE BOOT FROM DRIVE A
+GOTHRD:
+;
+; AX = 0-BASED DRIVE WE BOOTED FROM
+; BIOS$_L, BIOS$_H set.
+; CL = NUMBER OF FLOPPIES INCLUDING FAKE ONE
+; CH = MEDIA BYTE
+;
+ MESSAGE FTESTINIT,<"INIT",CR,LF>
+ XOR DX,DX
+ CLI
+ MOV SS,DX
+ MOV SP,700H ;LOCAL STACK
+ STI
+ ASSUME SS:NOTHING
+
+ PUSH CX ;SAVE NUMBER OF FLOPPIES AND MEDIA BYTE
+ MOV AH,CH ;SAVE FAT ID TO AH
+ PUSH AX ;SAVE BOOT DRIVE NUMBER, AND MEDIA BYTE
+;J.K. Let Model_byte, Secondary_Model_Byte be set here!!!
+;SB33020******************************************************************
+ mov ah,0c0h ; return system environment ;SB;3.30
+ int 15h ; call ROM-Bios routine ;SB;3.30
+;SB33020******************************************************************
+ 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
+Turn_Timer_On:
+ MOV AL,EOI
+ OUT AKPORT,AL ;TURN ON THE TIMER
+
+; NOP out the double word MOV instruction in MSDISK, if
+; this is not a 386 machine...
+ Get_CPU_Type ; macro to determine cpu type
+ cmp ax, 2 ; is it a 386?
+ je Skip_Patch_DoubleWordMov; yes: skip the patch
+
+Patch_DoubleWordMov:
+ push es ;AN003;
+ push cs ;AN003;
+ pop es ;AN003;ES -> CS
+ mov di, offset DoubleWordMov ;AN003;
+ mov cx, 3 ;AN003; 3 bytes to NOP
+ mov al, 90h ;AN003;
+ rep stosb ;AN003;
+ pop es ;AN003;
+Skip_Patch_DoubleWordMov: ;AN003;
+ MESSAGE FTESTINIT,<"COM DEVICES",CR,LF>
+;SB33IN1*********************************************************
+
+ mov si,offset COM4DEV
+ call AUX_INIT
+ mov si,offset COM3DEV
+ call AUX_INIT
+;SB33IN1*********************************************************
+ 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
+
+;*********************************************** ARR 2.15
+; SINCE WE'RE FIRST IN SYSTEM, NO NEED TO CHAIN THIS.
+; CLI ; ARR 2.15 DON'T GET BLOWN
+; MOV DS:WORD PTR TIMADR,OFFSET TIMER ; ARR 2.15 TIMER ENTRY POINT
+; MOV DS:TIMADR+2,AX ; ARR 2.15 VECTOR FOR TIMER
+; STI
+;*********************************************** ARR 2.15
+
+; BAS DEBUG
+ 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
+;SB34INIT002******************************************************************
+;SB We need to initalise the cs:MotorStartup variable from the disk
+;SB parameter table at SEC9. The offsets in this table are defined in
+;SB the DISK_PARMS struc in MSDSKPRM.INC. 2 LOCS
+
+ mov al,ds:SEC9 + DISK_MOTOR_STRT
+ mov cs:MotorStartup,al
+;SB34INIT002******************************************************************
+ 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 ;GET MEMORY SIZE--1K BLOCKS IN AX
+ MOV CL,6
+ SHL AX,CL ;CONVERT TO 16-BYTE BLOCKS(SEGMENT NO.)
+ POP CX ; RETREIVE BOOT DRIVE NUMBER, AND FAT ID
+ MOV DRVFAT,CX ;SAVE DRIVE TO LOAD DOS, AND FAT ID
+
+ PUSH AX
+;J.K. Don't have to look at the boot addr.
+; MOV DX,DS:(7C00H + 16H) ; NUMBER OF SECTORS/FAT FROM BOOT SEC
+;an004
+; mov dx, cs:Boot_Sec_Per_FAT ;AC000;Do not use the bpb info from Boot record any more.
+; XOR DH,DH
+; MOV FATLEN,DX
+;
+; CONVERT SECTOR COUNT TO PARAGRAPH COUNT:512 BYTES / SEC / 16 BYTES / PARA
+; = 32 PARA /SECTOR
+;
+
+; SHL DX,1
+; SHL DX,1
+; SHL DX,1
+; SHL DX,1
+; SHL DX,1
+; SUB AX,DX ; ROOM FOR FAT
+ sub ax, 64 ;AN004; Room for FATLOC segment. (1 KB buffer)
+ MOV FATLOC,AX ; LOCATION TO READ FAT
+ sub ax, 64 ;Room for Boot Record buffer segment (1 KB)
+ mov Init_BootSeg, ax ;AN015;
+ 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
+
+ MOV MEMORY_SIZE,AX
+ INC CL
+ MOV DEFAULT_DRIVE,CL ;SAVE DEFAULT DRIVE SPEC
+
+;DOSSEG = (((END$ - START$)+15)/16)+BIOSEG+SYSIZE
+
+; BAS DEBUG
+;MOV CURRENT_DOS_LOCATION,(((END$ - 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 ; AX := SEGMENT FOR INT 15
+ MOV DS,AX
+ MOV AX,WORD PTR DS:(0FH*4+2)
+
+ 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
+
+;SB34INIT003****************************************************************
+;SB We will check if the system has IBM extended key board by
+;SB looking at a byte at 40:96. If bit 4 is set, then extended key board
+;SB is installed, and we are going to set KEYRD_Func to 10h, KEYSTS_Func to 11h
+;SB for the extended keyboard function. Use cx as the temporary register. 8 LOCS
+
+ xor cx,cx
+ mov ds,cx
+ assume ds:nothing
+ mov cl,ds:0496h ; get keyboard flag
+ test cl,00010000b
+ jz ORG_KEY ; orginal keyboard
+ mov byte ptr KEYRD_func,10h ; extended keyboard
+ mov byte ptr KEYSTS_func,11h ; change for extended keyboard functions
+ORG_KEY:
+
+;SB34INIT003****************************************************************
+
+;**************************************************************
+; 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 anythig else if CMOS clock exists,
+ ;then set the system time according to that.
+ ;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>
+;SB33021********************************************************************
+ mov DL, 80h ;SB ; tell rom bios to look at hard drives
+ mov AH, 8h ;SB ; set command to get drive parameter
+ int 13h ;SB ; call ROM-BIOS to get number of drives
+;SB33021********************************************************************
+ JC ENDDRV ;CARRY INDICATES OLD ROM, SO NO HARDFILE
+ MOV HNUM,DL
+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
+;J.K.6/24/87 Check if the system has no physical diskette drives.
+;J.K. If it is, then we don't have to set BDS tables. But since we
+;J.K. pretend that we have 2 floppies, we are going to reserve two
+;J.K. BDS tables for the fake drive A, and B. and set the end of link
+;J.K. pointer.
+
+;SB34INIT004*********************************************************
+;SB Check to see if we are faking floppy drives. If not we don't
+;SB do anything special. If we are faking floppy drives we need
+;SB to set aside two BDSs for the two fake floppy drives. We
+;SB don't need to initalise any fields though. So starting at START_BDS
+;SB use the link field in the BDS structure to go to the second BDS
+;SB in the list and initalise it's link field to -1 to set the end of
+;SB the list. Then jump to the routine at DoHard to allocate/initialise
+;SB the BDS for HardDrives.
+
+ cmp cs:FakeFloppyDrv,1
+ jnz LOOP_DRIVE ; system has floppy
+ mov di,word ptr [di].link ; di <- first BDS link
+ mov di,word ptr [di].link ; di <- second BDS link
+ mov word ptr [di].link,-1 ; set end of link
+ jmp DoHard ; allocate/initialise BDS for HardDrives
+;SB34INIT004*********************************************************
+
+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
+
+;SB33022********************************************************************
+ MOV AH, 8h ;GET DRIVE PARAMETERS ;SB;3.30
+ INT 13h ;CALL ROM-BIOS ;SB;3.30
+;SB33022********************************************************************
+ JNC PARMSFROMROM
+ JMP NOPARMSFROMROM ; GOT AN OLD ROM
+PARMSFROMROM:
+;J.K. 10/9/86 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 MSBIO,MSDOS to boot up before it sets CMOS.
+;This should only happen with drive B.
+
+ 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 NUMBER 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 CHANGELINE SUPPORT ON DRIVE
+;SB33023********************************************************************
+ mov AH, 15h ;SB ; set command to get DASD type
+ int 13h ;SB ; call ROM-BIOS
+;SB33023********************************************************************
+ JC CHANGELINE_DONE
+ CMP AH,02 ; CHECK FOR PRESENCE OF CHANGELINE
+ JNE CHANGELINE_DONE
+;
+; 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
+;
+; WE NOW TRY TO SET UP THE FORM FACTOR FOR THE TYPES OF MEDIA THAT WE KNOW
+; AND CAN RECOGNISE. FOR THE REST, WE SET THE FORM FACTOR AS "OTHER".
+;
+CHANGELINE_DONE:
+; 40 CYLINDERS AND 9 OR LESS SEC/TRK, TREAT AS 48 TPI MEDIUM.
+ CMP NUM_CYLN,40
+ JNZ TRY_80
+ CMP SEC_TRK,9
+ JBE GOT_FF
+GOTOTHER:
+ MOV DH,FFOTHER ; WE HAVE A "STRANGE" MEDIUM
+ JMP SHORT GOT_FF
+
+;
+; 80 CYLINDERS AND 9 SECTORS/TRACK => 720 KB DEVICE
+; 80 CYLINDERS AND 15 SEC/TRK => 96 TPI MEDIUM
+;
+TRY_80:
+ CMP NUM_CYLN,80
+ JNZ GOTOTHER
+ CMP SEC_TRK,15
+ JZ GOT96
+ CMP SEC_TRK,9
+ JNZ GOTOTHER
+ MOV DH,FFSMALL
+ JMP SHORT GOT_FF
+
+GOT96:
+ MOV DH,FF96TPI
+
+GOT_FF:
+ JMP SHORT NEXTDRIVE
+
+; WE HAVE AN OLD ROM, SO WE EITHER HAVE A 48TPI OR 96TPI DRIVE. IF THE DRIVE
+; HAS CHANGELINE, WE ASSUEM IT IS A 96TPI, OTHERWISE WE TREAT IT AS A 48TPI.
+
+NOPARMSFROMROM:
+ POP ES
+ POP CX
+ POP DX
+ POP DI
+ POP DS
+
+;SB33024****************************************************************
+ MOV AH, 15h ; SET COMMAND TO GET DASD TYPE ;SB;3.30
+ INT 13h ; CALL ROM-BIOS ;SB;3.30
+;SB33024****************************************************************
+ JC NEXTDRIVE
+ CMP AH,2 ; IS THERE CHANGELINE?
+ JNZ NEXTDRIVE
+ OR CL,FCHANGELINE
+ MOV FHAVE96,1 ; REMEMBER THAT WE HAVE 96TPI DRIVES
+ MOV NUM_CYLN,80
+ MOV DH,FF96TPI
+ MOV AL,15 ; SET EOT IF NECESSARY
+ CMP AL, EOT
+ JBE EOT_OK2
+ MOV EOT,AL
+EOT_OK2:
+
+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
+ 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
+ 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>
+ MOV SINGLE,2 ; DON'T LOSE INFO THAT WE HAVE SINGLE SYSTEM
+ OR CX,FI_AM_MULT
+ OR WORD PTR [DI].FLAGS,CX
+ MOV DI,WORD PTR [DI].LINK ; MOVE TO NEXT BDS IN LIST
+ INC DL
+ JMP SHORT NEXTDRIVE ; USE SAME INFO FOR BDS A PREVIOUS
+NO_SINGLE:
+ INC DL
+ JMP LOOP_DRIVE
+
+DONE_DRIVES:
+ MOV AX,-1 ; SET LINK TO NULL
+ MOV WORD PTR [DI].LINK,AX
+
+; 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
+
+ MOV DL,80H
+ MOV DI,OFFSET BDSH ; SET UP FIRST HARD FILE.
+ MOV BL,HARDNUM
+ CALL SETHARD
+ assume es:nothing
+ 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
+
+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 ; NEXT HARD FILE
+ CALL SETHARD
+ assume es:nothing
+ JNC HARDFILE2_OK
+ DEC HNUM
+ JMP SHORT SETIT
+
+HARDFILE2_OK:
+ CALL INSTALL_BDS
+
+SETIT:
+ MOV AL,HNUM
+ OR AL,AL
+ JZ STATIC_CONFIGURE
+ ADD AL,HARDNUM
+ MOV DRVMAX,AL
+
+; End of physical drive initialization.
+; *** Do not change the position of the following statement.-J.K.4/7/86
+; *** DoMini routine will use [DRVMAX] value for the start of the logical
+; *** drive number of Mini disk(s).
+
+ call DoMini ;For setting up mini disks, if found -J.K.
+
+ assume es:nothing
+; END OF DRIVE INITIALIZATION.
+
+;J.K. 9/24/86 We now decide, based on the configurations available so far, what
+;code or data we need to keep as a stay resident code. The following table
+;shows the configurations under consideration. They are listed in the order
+;of their current position memory.
+;Configuration will be done in two ways:
+;First, we are going to set "Static configuration". Static configuration will
+;consider from basic configuration to ENDOF96TPI configuration. The result
+;of static configuration will be the address the Dynamic configuration will
+;use to start with.
+;Secondly, "Dynamic cofiguration" will be performed. Dynamic configuration
+;involves possible relocation of CODE or DATA. Dynamic configuration routine
+;will take care of BDSM tables and AT ROM Fix module thru K09 suspend/resume
+;code individually. After these operation, FINAL_DOS_LOCATION will be set.
+;This will be the place SYSINIT routine will relocate MSDOS module for good.
+;
+; 1. BASIC CONFIGURATION FOR IBMBIO (EndFloppy, EndSwap)
+; 2. ENDONEHARD
+; 3. ENDTWOHARD
+; 4. END96TPI ;a system that supports "Change Line Error"
+; 5. End of BDSM ;BDSM tables for mini disks.
+; 6. ENDATROM ;Some of AT ROM fix module.
+; 7. ENDCMOSCLOCKSET;Supporting program for CMOS clock write.
+; 8. ENDK09 ;K09 CMOS Clock module to handle SUSPEND/RESUME operation.
+;
+;J.K. 9/24/86.
+
+; *** For mini disk configuration. -J.K. 4/7/86
+; *** END_OF_BDSM will contains the ending address(offset) of BDSM table for
+; *** mini disks which is located right after the label END96TPI.
+; *** The variable NUM_MINI_DSK will indicate the existance of the mini disk.-J.K. 4/7/86
+
+
+STATIC_CONFIGURE:
+
+
+ PUSH AX
+ mov ax, offset END96TPI ;let's start with the biggest one.
+ cmp fHave96, 0 ;Is change line support there?
+ jnz Config96 ;Yes.
+
+ mov ax, offset ENDTWOHARD
+ cmp HNUM, 1 ;1 hard file?
+ jbe No_Two_HRD
+ jmp ConfigTwoHard
+No_Two_HRD:
+ mov ax, offset ENDONEHARD
+ jnz Basic_Floppy
+ jmp ConfigOneHard
+Basic_Floppy:
+ mov ax, offset ENDFLOPPY
+ jmp Dynamic_Configure ;static configuration is done!
+
+;
+; KEEP THE 96TPI CODE
+;
+CONFIG96:
+;
+; SAVE OLD INT 13 VECTOR
+;
+ PUSH AX
+ PUSH DS
+ XOR AX,AX
+ MOV DS,AX
+ ASSUME DS:NOTHING
+
+ 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
+
+ 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 ;J.K. 4/7/86 for mini disks installed
+ ;if not installed, then num_mini_dsk = 0.
+ MOV DRVMAX,AL
+ POP AX ;now, static config is done.
+
+
+DYNAMIC_CONFIGURE:
+ call Get_Para_Offset ;For dynamic allocation, we are
+ ;going to use offset address that
+ ;is in paragraph boundary.
+ push cs
+ pop es ;es -> code
+ assume es:code
+ cld ;clear direction
+
+ cmp [num_mini_dsk], 0 ;Mini disk(s) installed ?
+ jz CheckATROM ;No.
+ mov ax, End_Of_BDSM ;set the new ending address
+ call Get_Para_Offset
+CheckATROM:
+ cmp Model_Byte, 0FCh ;AT ?
+ jnz CheckCMOSClock
+ cmp HNUM, 0 ;No hard file?
+ jz CheckCMOSClock
+
+ mov si, 0F000h
+ mov es, si ;ES -> BIOS segment
+ assume es:nothing ;
+ mov si, offset BIOS_DATE ;
+ mov di, 0FFF5H ;ROM BIOS string is at F000:FFF5
+Cmpbyte: ;Only patch ROM for bios dated 01/10/84
+ cmpsb ;
+ jnz CheckCMOSClock ;
+ cmp byte ptr [si-1],0 ;
+ jnz Cmpbyte ;
+SetRomCode: ;Now we have to install ROM fix
+ ;AX is the address to move.
+ push cs ;
+ pop es ;set ES to CODE seg
+ assume es:code
+
+ mov word ptr ORIG13, ax
+ mov word ptr ORIG13+2, cs ;set new ROM bios int 13 vector
+ mov cx, offset ENDATROM
+ mov si, offset IBM_DISK_IO
+ sub cx, si ;size of AT ROM FIX module
+ mov di, ax ;destination
+ rep movsb ;relocate it
+ mov ax, di ;new ending address
+ call Get_Para_Offset ;in AX
+
+CheckCMOSClock:
+ push cs
+ pop es ;set ES to CODE seg
+ assume es:code
+ cmp HaveCMOSClock, 1 ;CMOS Clock exists?
+ jne CheckK09
+ mov DaycntToDay, ax ;set the address for MSCLOCK
+ mov cx, offset EndDaycntToDay
+ mov si, offset Daycnt_To_Day
+ sub cx, si ;size of CMOS clock supporting routine
+ mov di, ax
+ rep movsb
+ mov ax, di
+ call Get_Para_Offset
+ mov BinToBCD, ax ;set the address for MSCLOCK
+ mov cx, offset EndCMOSClockSet
+ mov si, offset Bin_To_BCD
+ sub cx, si
+ mov di, ax
+ rep movsb
+ mov ax, di
+ call Get_Para_Offset
+
+CheckK09:
+;SB33025****************************************************************
+ push ax ;save ax ;SB ;3.30*
+ mov ax,4100h ;Q: is it a K09 ;SB ;3.30*
+ mov bl,0 ; ;SB ;3.30*
+ int 15h ; ;SB ;3.30*
+;SB33025****************************************************************
+ pop ax
+ jc CONFIGDONE
+
+ mov si, offset INT6C
+ mov cx, offset ENDK09
+ sub cx, si ;size of K09 routine
+ mov di, ax
+ push di ;save destination
+ rep movsb
+ mov ax, di ;
+ call Get_Para_Offset ;AX = new ending address
+ pop di
+
+ push ax
+ push ds
+ mov fHaveK09, 1 ;remember we have a K09 type
+ xor ax,ax
+ mov ds, ax
+ assume ds:nothing
+
+ mov word ptr ds:[4 * 6Ch], di ;new INT 6Ch handler
+ mov ds:[4 * 6Ch +2], cs
+
+ pop ds
+ assume ds:code
+ pop ax ;restore the ending address
+
+; SET UP CONFIG STUFF FOR SYSINIT
+
+CONFIGDONE: ;AX is final ending address of MSBIO.
+ MOV DX,SYSINITSEG
+ MOV DS,DX
+ ASSUME DS:SYSINITSEG
+
+ SUB AX,OFFSET START$
+ 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
+
+;AN004; J.K. Don't need this. We are not read the whole FAT at once.
+; 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 bx, [di].BYTEPERSEC
+ mov cs:Md_SectorSize, bx ;AN004;Used by Get_Fat_Sector proc.
+ MOV BL,[DI].FATSIZ ; GET SIZE OF FAT ON MEDIA
+ MOV FBIGFAT,BL
+ MOV CL,[DI].SECPERCLUS ;GET SECTORS/CLUSTER
+;J.K.32 bit calculation
+ MOV AX,[DI].HIDSEC_L ;GET NUMBER OF HIDDEN SECTORS (low)
+ SUB BIOS$_L,AX ;SUBTRACT HIDDEN SECTORS since we
+ ;need a logical sector number that will
+ ;be used by GETCLUS(diskrd procedure)
+;SB34INIT005******************************************************************
+;SB We have 32 bit sector number now though. SO the high word also needs
+;SB to be adjusted. Update BIOS$_H too. 2 LOCS
+
+ mov ax,[di].HIDSEC_H ;subtract upper 16 bits of sector num
+ sbb BIOS$_H,ax
+;SB34INIT005******************************************************************
+ 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,(((END$ - START$)+15)/16)+SYSIZE
+
+LOADIT:
+ 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 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
+EOFBIG:
+ MESSAGE FTESTINIT,
+ CMP BX,0FFF7H ; ELSE
+ISEOFX:
+ JB LOADIT ; } WHILE (!ISEOF (CLUS));
+
+ CALL SETDRVPARMS
+
+ MESSAGE FTESTINIT,<"SYSINIT",CR,LF>
+ ZWAIT
+ MESSAGE FTESTINIT,<"ON TO SYSINIT...",CR,LF>
+ JMP SYSINIT
+
+INIT ENDP
+
+;****************************
+
+Get_Para_Offset proc near
+;in: AX - offset value
+;out: AX - offset value adjusted for the next paragraph boundary.
+ add ax, 15 ;make a paragraph
+ rcr ax, 1
+ shr ax, 1
+ shr ax, 1
+ shr ax, 1
+ shl ax, 1 ;now, make it back to offset value
+ shl ax, 1
+ shl ax, 1
+ shl ax, 1
+ ret
+Get_Para_Offset endp
+
+;AN004; Don't need this procedure. Get_FAT_Sector replace this.
+; READ A FAT SECTOR INTO FAT LOCATION
+;GETFAT PROC NEAR
+; 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
+
+; READ A BOOT RECORD INTO 7C0:BOOTBIAS
+;AN015; Read a boot record into Init_BootSeg:BOOTBIAS
+
+GETBOOT PROC NEAR
+;SB33026****************************************************************
+ mov AX, cs:Init_BootSeg ; prepare to load ES
+ mov ES, AX ;SB ; load ES segment register
+ assume es:nothing
+ mov BX, BootBias ;SB ; load BX, ES:BX is where sector goes
+ mov AX, 0201h ;SB ; command to read & num sec. to 1
+ xor DH, DH ;SB ; head number zero
+ mov CX, 0001h ;SB ; cylinder zero and sector one
+ int 13h ;SB ; call rom bios
+;SB33026****************************************************************
+ JC ERRET
+
+ CMP WORD PTR ES:[BOOTBIAS+1FEH],0AA55H ; DAVE L**** 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
+
+; 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
+ assume ds:code,es:nothing
+ 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
+;SB33027***************************************************************
+ mov AH, 8 ;SB ; set command to get drive parameters
+ int 13h ;SB ; call rom-bios disk routine
+;SB33027***************************************************************
+; 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 ())
+ assume es:nothing
+ 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
+
+;SB34INIT006******************************************************************
+;SB we have a new partition type 6 now. add code to support this too.
+
+ cmp byte ptr es:[bx],6 ; P->PARTITIONTYPE !=6
+ jz set2
+;SB34INIT006******************************************************************
+
+ ADD BX,16 ; P += SIZEOF PARTITION;
+ CMP BX,202H+BOOTBIAS ; IF (P == &BOOT[0X202H])
+ JNZ SET1 ; RETURN -1;}
+
+SETRET:
+ STC ;AN000; Note: Partitiontype 6 means either
+ JMP RET_HARD ;1).the partition has not been formatted yet, or
+ ;2).(# of sectors before the partition +
+ ; # of sectors in this partition) > word boundary
+ ; i.e., needs 32 bit sector calculation, or
+ ;3).the partition is not a FAT file system.
+
+;J.K. Until we get the real logical boot record and get the bpb,
+;DRVLIM_H,DRVLIM_L will be used instead of DRVLIM for the convenience of
+;the computation.
+;At the end of this procedure, if a BPB information is gotten from
+;the valid boot record, then we are going to use those BPB information
+;without change.
+;Otherwise, if (hidden sectors + total sectors) <= a word, then
+;we will move DRVLIM_L to DRVLIM and zero out DRVLIM_L entry to make
+;it a conventional BPB format.
+
+SET2:
+; PUSH DX ;AN000;
+ mov cs:ROM_drv_num, dl ;AN000; save the ROM BIOS drive number we are handling now.
+
+ MOV AX,WORD PTR ES:[BX+4] ;Hidden sectors
+ MOV DX,WORD PTR ES:[BX+6]
+
+
+ ;Decrement the sector count by 1 to make it zero based. Exactly 64k
+ ;sectors should be allowed
+ ;
+ SUB AX,1 ; PTM 901 12/12/86 MT
+ SBB DX,0 ; PTM 901 12/12/86 MT
+
+ ADD AX,WORD PTR ES:[BX+8] ;Sectors in Partition
+ ADC DX,WORD PTR ES:[BX+10]
+; JZ OKDRIVE
+ jnc Okdrive ;AC000;
+ MESSAGE FTESTHARD,<"PARTITION INVALID",CR,LF>
+ OR FBIGFAT,FTOOBIG
+OKDRIVE:
+; POP DX
+ MOV AX,WORD PTR ES:[BX+4]
+
+ MOV [DI].HIDSEC_L,AX ; BPB->HIDSECCT = P->PARTITIONBEGIN;
+ mov ax,word ptr es:[bx+6] ;AN000;
+ mov [di].HIDSEC_H,ax ;AN000;
+
+ mov dx,word ptr es:[bx+10] ;AN000; # of sectors (High)
+ MOV AX,WORD PTR ES:[BX+8] ;# of sectors (Low)
+ mov word ptr [di].DRVLIM_H,dx ;AN000;
+ MOV WORD PTR [DI].DRVLIM_L,AX ; BPB->MAXSEC = P->PARTITIONLENGTH;
+ cmp dx,0 ;AN000;
+ ja OKDrive_Cont ;AN000;
+ CMP AX,64 ; IF (P->PARTITIONLENGTH < 64)
+ JB SETRET ; RETURN -1;
+
+OKDrive_Cont: ;AN000;
+ ; PUSH DX ;AC000;
+ mov dx,[di].HIDSEC_H ;AN000;
+ MOV AX,[DI].HIDSEC_L ; BOOT SECTOR NUMBER - For mini disk,;J.K.
+; XOR DX,DX ; this will be logical and equal to ;AC000;
+ xor bx,bx ;usUally equal to the # of sec/trk. ;J.K.
+; MOV BH,DH ;AC000;
+ MOV BL,BYTE PTR [DI].SECLIM
+ push ax ;AN000;
+ mov ax,dx ;AN000;
+ xor dx,dx ;AN000;
+ div bx ;AN000;
+ mov cs:[Temp_H],ax ;AN000;
+ pop ax ;AN000;
+ DIV BX ;(Sectors)DX;AX / (Seclim)BX =(Track) Temp_H;AX + (Sector)DX
+ MOV CL,DL ; CL IS SECTOR NUMBER;J.K.Assume sector number < 255.
+ INC CL ; SECTORS ARE 1 BASED
+; CWD ;AC000;
+
+ xor bx,bx ;AN000;
+ MOV BL,BYTE PTR [DI].HDLIM
+ push ax ;AN000;
+ xor dx,dx ;AN000;
+ mov ax, cs:[Temp_H] ;AN000;
+ div bx ;AN000;
+ mov cs:[Temp_H],ax ;AN000;
+ pop ax ;AN000;
+ DIV BX ; DL IS HEAD, AX IS CYLINDER
+ cmp cs:[Temp_H],0 ;AN000;
+ ja SetRet_brdg ;AN000; Exceeds the limit of Int 13h
+ cmp ax, 1024 ;AN000;
+ ja SetRet_brdg ;AN000; Exceeds the limit of Int 13h
+
+; DL IS HEAD.
+; AX IS CYLINDER
+; CL IS SECTOR NUMBER (assume less than 2**6 = 64 for INT 13h)
+
+;*** For Mini Disks *** J.K. 4/7/86
+ cmp word ptr [di].ISMINI, 1 ;check for mini disk -J.K. 4/7/86
+ jnz OKnotMini ;not mini disk. -J.K. 4/7/86
+ add ax, [di].HIDDEN_TRKS ;set the physical track number -J.K. 4/7/86
+OKnotMini: ;J.K. 4/7/86
+;*** End of added logic for mini disk
+ 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
+; ROM_drv_num IS DRIVE
+
+; POP AX ;AC000; AL IS DRIVE
+ MOV DH,DL ; DH IS HEAD
+; MOV DL,AL ;AC000; DL IS DRIVE
+ mov dl, cs:ROM_drv_num ;AN000; Set the drive number
+
+; CL IS SECTOR + 2 HIGH BITS OF CYLINDER
+; CH IS LOW 8 BITS OF CYLINDER
+; DH IS HEAD
+; DL IS DRIVE
+;J.K. For convenience, we are going to read the logical boot sector
+;into cs:DiskSector area.
+
+;SB34INIT009*************************************************************
+;SB Read in boot sector using BIOS disk interrupt. The buffer where it
+;SB is to be read in is cs:Disksector.
+;SB 5 LOCS
+
+ push cs
+ pop es
+ mov bx,offset DiskSector
+ mov ax,0201h ; read, one sector
+ int 13h
+
+;SB34INIT009*************************************************************
+
+; cs:Disksec contains THE BOOT SECTOR. IN THEORY, (HA HA) THE BPB IN THIS THING
+; IS CORRECT. WE CAN, THEREFORE, SUCK OUT ALL THE RELEVANT STATISTICS ON THE
+; MEDIA IF WE RECOGNIZE THE VERSION NUMBER.
+ mov bx, offset DiskSector ;AN000;
+; look for a signature for msdos...
+ cmp word ptr cs:[bx+3], "S" shl 8 + "M"
+ jnz notmssig
+ cmp word ptr cs:[bx+5], "O" shl 8 + "D"
+ jnz notmssig
+ cmp byte ptr cs:[bx+7], "S"
+ je sigfound
+; ...or perhaps pcdos...
+notmssig:
+ CMP WORD PTR cs:[bx+3], "B" SHL 8 + "I"
+ jnz notibmsig
+ CMP WORD PTR cs:[bx+5], " " SHL 8 + "M"
+ je sigfound
+;----------------------------------------------------------------------
+; check for Microsoft OS/2 signature also. 7/29/88. HKN
+notibmsig:
+ CMP WORD PTR cs:[bx+3], "S" SHL 8 + "O"
+ JNZ UNKNOWNJ
+ CMP WORD PTR cs:[bx+5], " " SHL 8 + "2"
+ JNZ UNKNOWNJ
+;-----------------------------------------------------------------------
+
+sigfound: ; signature was found, now check version
+ CMP WORD PTR cs:[bx+8], "." SHL 8 + "2"
+ JNZ TRY5
+ CMP BYTE PTR cs:[bx+10], "0"
+ JNZ TRY5
+ MESSAGE FTESTHARD,<"VERSION 2.0 MEDIA",CR,LF>
+ JMP SHORT COPYBPB
+
+SetRet_Brdg:
+ jmp SETRET
+
+UNKNOWNJ:
+ JMP UNKNOWN ;Unformatted or illegal media.
+UNKNOWN3_0_J: ;AN012;Legally formatted media,
+ jmp Unknown3_0 ;AN012; although, content might be bad.
+
+TRY5:
+ call Cover_Fdisk_Bug ;AN010;
+ CMP WORD PTR cs:[bx+8],"." SHL 8 + "3"
+ jb Unknown3_0_J ;AN012; Must be 2.1 boot record. Do not trust it, but still legal.
+ JNZ COPYBPB ;AN007; Honor OS2 boot record, or DOS 4.0 version
+ cmp byte ptr cs:[bx+10],"1" ;do not trust 3.0 boot record. But still legal J.K. 4/15/86
+ jb UnKnown3_0_J ;AN012; if version >= 3.1, then O.K.
+ 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.
+
+;If it is non FAT based system, then just copy the BPB from the BOOT sector
+;into the BPB in BDS table, and also set the Boot serial number, Volume id,
+;and System ID according to the Boot record.
+;For the non_FAT system, don't need to set the other value. So just
+;do GOODRET.- J.K.
+
+ cmp cs:[Ext_Boot_Sig], EXT_BOOT_SIGNATURE ;AN000;
+ jne COPYBPB_FAT ;AN000; Conventional Fat system
+ cmp cs:[NumberOfFats], 0 ;AN000; If (# of FAT <> 0) then
+ jne COPYBPB_FAT ;AN000; a Fat system.
+;J.K. Non Fat based media.
+ push di ;AN000; Sav Reg.
+ push ds ;AN000;
+
+ push ds ;AN000;
+ pop es ;AN000; now es:di -> bds
+ push cs ;AN000;
+ pop ds ;AN000; ds = cs
+
+ mov si, offset Bpb_In_Sector ;AN000; ds:si -> BPB in Boot
+ add di, BYTEPERSEC ;AN000; es:di -> BPB in BDS
+ mov cx, size BPB_TYPE ;AN000;
+ rep movsb ;AN000;
+
+ pop ds ;AN000; Restore Reg.
+ pop di ;AN000;
+ call Mov_Media_IDs ;AN000; Set Volume id, SystemId, Serial.
+ jmp GoodRet
+
+COPYBPB_FAT: ;AN000; Fat system
+ xor dx,dx ;AN000;
+ mov si, offset Bpb_In_Sector ;AN000; cs:bx -> bpb in boot
+ mov ax, cs:[si.SECNUM] ;AN000; total sectors
+ cmp ax,0 ;AN000; double word sector number?
+ jnz Fat_Big_Small ;AN000; No. Conventional BPB.
+ mov ax, word ptr cs:[si.SECNUM_L] ;AN000; Use double word
+ mov dx, word ptr es:[si.SECNUM_H] ;AN000;
+
+Fat_Big_Small: ;AN000; Determine Fat entry size.
+;At this moment DX;AX = Total sector number
+; DEC AX ; SUBTRACT # RESERVED (ALWAYS 1)
+ sub ax,1 ;AN000; Subtrack # reserved (always 1)
+ sbb dx,0 ;AN000;
+ mov bx, cs:[si.FATSIZE] ;AN000; BX = Sectors/Fat
+ mov [di.CSECFAT],bx ;AN000; Set in BDS BPB
+ shl bx,1 ;AN000; Always 2 FATS
+ sub ax,bx ;AN000; Sub # fat sectors
+ sbb dx,0 ;AN000;
+ mov bx, cs:[si.DIRNUM] ;AN000; # root entries
+ mov [di.cDIR],bx ;AN000; Set in BDS BPB
+
+ MOV CL,4
+ shr bx,cl ;AN000; Div by 16 ents/sector
+ sub ax,bx ;AN000; sub # dir sectors
+ sbb dx,0 ;AN000;
+ ;AN000; DX;AX now contains the # of data sectors
+ xor cx,cx ;AN000;
+ MOV CL, cs:[si.SECALL] ; 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>
+;J.K. 3/16/87 P54 Returning back to old logic for compatibility reason.
+;So, use the old logic again that once had been commented out!!!!!!!!!!!!
+;Old logic to determine FAT Entry Size J.K. 12/3/86
+ push ax ;AN000;
+ mov ax,dx ;AN000;
+ xor dx,dx ;AN000;
+ div cx ;AN000; cx = sectors per cluster
+ mov cs:[Temp_H],ax ;AN000;
+ pop ax ;AN000;
+ DIV CX ;AN000; [Temp_H];AX NOW CONTAINS THE # CLUSTERS.
+ cmp cs:[Temp_H],0 ;AN000;
+ ja TooBig_Ret ;AN000; Too big cluster number
+ CMP AX,4096-10 ; IS THIS 16-BIT FAT?
+ JB CopyMediaID ; NO, small FAT
+ OR FBIGFAT,FBIG ; 16 BIT FAT
+;End of Old logic
+CopyMediaID:
+ call Mov_Media_IDs ;AN000; Copy Filesys_ID, Volume label,
+ ;and Volume serial to BDS table, if extended
+ ;boot record.
+ JMP Massage_bpb ;AN000; Now final check for BPB info. and return.
+
+TooBig_Ret: ;AN000;
+ OR cs:FBIGFAT,FTOOBIG
+ JMP GOODRET ;AN000; Still drive letter is assigned
+ ;AN000; But useless. To big for
+ ;AN000; current PC DOS FAT file system
+UNKNOWN:
+; or [di].FLAGS, UNFORMATTED_MEDIA ;AN005; Set unformatted media flag.
+ ; preceeding line commented out 10/88 by MRW-- The boot signature
+ ; may not be recognizable, but we should TRY and read it anyway.
+ ;AN006;
+ ;AN008; For the time being, allow it.
+ ;AN009; Now implemented again
+Unknown3_0: ;AN012;Skip setting UNFORMATTED_MEDIA bit
+ MESSAGE FTESTHARD,<"UNKNOWN HARD MEDIA. ASSUMING 3.0.",CR,LF>
+ mov dx, [di.DRVLIM_H] ;AN000;
+ mov ax, [di.DRVLIM_L] ;AN000;
+ MOV SI,OFFSET DISKTABLE2
+SCAN:
+; CMP AX,[SI]
+; JBE GOTPARM
+; ADD SI,4 * 2
+
+ cmp dx, word ptr cs:[si] ;AN000;
+ jb GotParm ;AN000;
+ ja Scan_Next ;AN000;
+ cmp ax, word ptr cs:[si+2] ;AN000;
+ jbe GotParm ;AN000;
+Scan_Next: ;AN000;
+ add si, 5 * 2 ;AN000;
+ JMP SCAN ;AN000; Covers upto 512 MB media
+GOTPARM:
+; MOV CL,BYTE PTR [SI+6]
+ mov cl,byte ptr [si+8] ;AN000; Fat size for FBIGFAT flag
+ OR FBIGFAT,CL
+; MOV CX,[SI+2]
+; MOV DX,[SI+4]
+ mov cx, word ptr cs:[SI+4] ;AN000;
+ mov dx, word ptr cs:[SI+6] ;AN000;
+
+; 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
+
+;Now, CX = SecPerClus|Clusshift
+; [DI.CDIR] = number of directory entries.
+
+ mov dx, [di.DRVLIM_H] ;AN000;
+ mov ax, [di.DRVLIM_L] ;AN000;
+ 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>
+;J.K. We don't need to change "small fat" logic since it is gauranteed
+;that double word total sector will not use 12 bit fat (unless
+;it's sectors/cluster >= 16 which will never be in this case.)
+;So in this case we assume DX = 0 !!!.
+
+ XOR BX,BX
+ MOV BL,CH
+ DEC BX
+ ADD BX,AX ;AN000; DX=0
+ 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 Massage_BPB
+DOBIG:
+;J.K. For BIGFAT we do need to extend this logic to 32 bit sector calculation.
+ MESSAGE FTESTHARD,<" BIG FAT",CR,LF>
+ MOV CL,4 ; 16 (2^4) DIRECTORY ENTRIES PER SECTOR
+ push dx ;AN000; Save total sectors (high)
+ mov dx, CDIR[DI] ;AN000;
+ SHR DX,CL ; CSECDIR = CDIR / 16;
+ SUB AX,DX ; DX;AX -= CSECDIR; DX;AX -= CSECRESERVED;
+ pop dx ;AN000;
+ SBB dx,0 ;AN000;
+; DEC AX ; AX = T - R - D
+ SUB ax,1 ;AN000; DX;AX = T - R - D
+ SBB dx,0 ;AN000;
+ MOV BL,2
+ MOV BH,SECPERCLUS[DI] ; BX = 256 * SECPERCLUS + 2
+; XOR DX,DX
+;J.K. I don't understand why to add BX here!!!
+ 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
+;J.K. Assuming DX in the table will never be bigger than BX.
+ DIV BX ; CSECFAT = CEIL((TOTAL-DIR-RES)/
+ ; (256*SECPERCLUS+2));
+ MOV WORD PTR [DI].CSECFAT,AX ; NUMBER OF FAT SECTORS
+;J.K. Now, set the default FileSys_ID, Volume label, Serial number
+ MOV BL,FBIGFAT
+ MOV [DI].FATSIZ,BL ; SET SIZE OF FAT ON MEDIA
+ call Clear_IDs ;AN000;
+
+;J.K. At this point, in BPB of BDS table, DRVLIM_H,DRVLIM_L which were
+;set according to the partition information. We are going to
+;see if (hidden sectors + total sectors) > a word. If it is true,
+;then no change. Otherwise, DRVLIM_L will be moved to DRVLIM
+;and DRVLIM_L will be set to 0.
+;We don't do this for the bpb information from the boot record. We
+;are not going to change the BPB information from the boot record.
+Massage_bpb: ;AN000;
+ mov dx, [di.DRVLIM_H] ;AN000;
+ mov ax, [di.DRVLIM_L] ;AN000;
+ cmp dx,0 ;AN000; Double word total sector?
+ ja GOODRET ;AN000; don't have to change it.
+ cmp [di.HIDSEC_H], 0 ;AN000;
+ ja GOODRET ;AN000; don't have to change it.
+ add ax, [di.HIDSEC_L] ;AN000;
+ jc GOODRET ;AN000; bigger than a word boundary
+ mov ax, [di.DRVLIM_L] ;AN000;
+ mov [di.DRVLIM], ax ;AN000;
+ mov [di.DRVLIM_L], 0 ;AN000;
+GOODRET:
+ cmp [di].DRVLIM_H, 0 ;AN014; Big media?
+ jbe Not_BigMedia ;AN014; No.
+ push es ;AN014;
+ push ax ;AN014;
+ mov ax, SYSINITSEG ;AN014;
+ mov es, ax ;AN014;
+ mov es:Big_Media_Flag, 1 ;AN014; Set the flag in SYSINITSEG.
+ pop ax ;AN014;
+ pop es ;AN014;
+Not_BigMedia: ;AN014;
+ 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
+
+Cover_FDISK_Bug proc ;AN010;
+;FDISK of PC DOS 3.3 and below, OS2 1.0 has a bug. The maximum number of
+;sector that can be handled by PC DOS 3.3 ibmbio should be 0FFFFh.
+;Instead, sometimes FDISK use 10000h to calculate the maximum number.
+;So, we are going to check that if SECNUM + Hidden sector = 10000h
+;then subtrack 1 from SECNUM.
+ push ax ;AN010;
+ push dx ;AN010;
+ push si ;AN010;
+ cmp cs:[Ext_Boot_Sig], EXT_BOOT_SIGNATURE ;AN010;
+ je CFB_Retit ;AN010;if extended BPB, then >= PC DOS 4.00
+ cmp word ptr cs:[bx+7], "0" shl 8 + "1" ;AN011; OS2 1.0 ? = IBM 10.0
+ jne CFB_Chk_SECNUM ;AN010;
+ cmp byte ptr cs:[bx+10], "0" ;AN010;
+ jne CFB_Retit ;AN010;
+CFB_Chk_SECNUM: ;AN010;
+ mov si, offset BPB_In_Sector ;AN010;
+ cmp cs:[si.SECNUM], 0 ;AN010;Just to make sure.
+ je CFB_Retit ;AN010;
+ mov ax, cs:[si.SECNUM] ;AN010;
+ add ax, cs:[si.HIDDEN_L] ;AN010;
+ jnc CFB_Retit ;AN010;
+ xor ax, ax ;AN010;if carry set and AX=0?
+ jnz CFB_Retit ;AN010;
+ dec cs:[si.SECNUM] ;AN010; then decrease SECNUM by 1.
+ dec [di].DRVLIM_L ;AN010;
+CFB_Retit: ;AN010;
+ pop si ;AN010;
+ pop dx ;AN010;
+ pop ax ;AN010;
+ ret ;AN010;
+Cover_FDISK_Bug endp ;AN010;
+
+
+; 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
+ 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
+
+ xor dx,dx ;AN000;
+ MOV AX,ES:[DI].DRVLIM
+ cmp ax,0 ;AN000;
+ jne GET_cCYL ;AN000;
+ mov dx,es:[di].DRVLIM_H ;AN000; Use Double word sector number
+ MOV AX,ES:[DI].DRVLIM_L ;AN000;
+GET_cCYL:
+ push dx ;AN000;
+ PUSH AX
+ MOV AX,WORD PTR ES:[DI].HDLIM
+ MUL WORD PTR ES:[DI].SECLIM ;Assume Sectorsp per cyl. < 64K.
+ MOV CX,AX ; CX HAS # SECTORS PER CYLINDER
+ POP AX ;
+ pop dx ;AN000; Restore drvlim.
+ push ax ;AN000;
+ mov ax,dx ;AN000;
+ xor dx,dx ;AN000;
+ div cx ;AN000;
+ mov cs:[Temp_H],ax ;AN000; AX be 0 here.
+ pop ax ;AN000;
+ 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:
+;J.K. We don't use the extended BPB for a floppy.
+ PUSH CS
+ POP DS
+ assume ds:code
+;J.K.6/24/87
+
+;SB34INIT007******************************************************************
+;SB If Fake floppy drive variable is set then we don't have to handle this
+;SB BDS. We can just go and deal with the next BDS at label Go_To_Next_BDS.
+
+ cmp cs:FakeFloppyDrv,1
+ jz Go_To_Next_BDS
+;SB34INIT007******************************************************************
+
+ CMP BL,FFOTHER ; SPECIAL CASE "OTHER" TYPE OF MEDIUM
+ JNZ NOT_PROCESS_OTHER
+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
+
+;J.K. Old logic was...
+; MOV BX,515
+; DIV BX
+; OR DX,DX
+; JZ NO_ROUND_UP
+; INC AX ; ROUND UP NUMBER OF FAT SECTORS
+
+;J.K. New logic to get the sectors/fat area.
+ ;Fat entry is assumed to be 1.5 bytes!!!
+ mov bx, 3
+ mul bx
+ mov bx,2
+ div bx
+ xor dx, dx
+ mov bx, 512
+ div bx
+ inc ax
+
+NO_ROUND_UP:
+ MOV [DI].RCSECFAT,AX
+ JMP SHORT GO_TO_NEXT_BDS
+NOT_PROCESS_OTHER:
+ 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
+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
+
+; READ CLUSTER SPECIFIED IN BX
+; CX = SECTORS PER CLUSTER
+; DI = LOAD LOCATION
+;
+GETCLUS PROC NEAR
+ 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
+;J.K. Now DX;AX = matching logical sector number starting from the data sector.
+;SB34INIT008*************************************************************
+;SB Add the BIOS start sector to the sector number in DX:AX. The BIOS
+;SB start sector number is in BIOS$_H:BIOS$_L
+
+ add ax,cs:BIOS$_L
+ adc dx,cs:BIOS$_H
+;SB34INIT008*************************************************************
+;J.K. Now DX;AX = first logical sector to read
+; 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
+
+UNPACK:
+ PUSH DS
+ push ax ;AN004;Save First logical sector (Low)
+ PUSH BX
+ MOV SI,FATLOC
+ MOV DS,SI ;DS -> FATLOC segment
+ mov si, bx ;AN004;
+ TEST cs:FBIGFAT,FBIG ;16 bit fat?
+ JNZ UNPACK16
+; MOV SI,BX
+ SHR SI,1 ;12 bit fat. si=si/2
+ add si, bx ;AN004; si = clus + clus/2
+ call Get_Fat_Sector ;AN004; offset of FAT entry in BX
+ mov ax, [bx] ;AN004;Save it into AX
+ jne Even_Odd ;AN004;IF not a splitted FAT, check even-odd.
+ mov al, byte ptr [bx] ;AN004;Splitted FAT.
+ mov byte ptr cs:Temp_Cluster, al ;AN004;
+ inc si ;AN004;
+ call Get_Fat_Sector ;AN004;
+ mov al, byte ptr ds:[0] ;AN004;
+ mov byte ptr cs:Temp_Cluster+1, al ;AN004;
+ mov ax, cs:Temp_Cluster ;AN004;
+Even_Odd: ;AN004;
+ pop bx ;AN004;Restore old Fat entry value
+ push bx ;AN004;Save it right away.
+ shr bx, 1 ;AN004;Was it even or odd?
+ jnc HAVCLUS ;It was even.
+ SHR ax,1 ;Odd. Massage FAT value and keep
+ SHR ax,1 ;the highest 12 bits.
+ SHR ax,1
+ SHR ax,1
+HAVCLUS:
+ mov bx, ax ;AN004; Now BX = New FAT entry.
+ AND BX,0FFFH ;AN004; keep low 12 bits.
+ JMP SHORT UNPACKX
+UNPACK16: ;16 bit fat.
+ shl si, 1 ;Get the offset value.
+ call Get_Fat_Sector ;AN004;
+ mov bx, [bx] ;AN004; Now BX = New FAT entry.
+UNPACKX:
+ POP SI ;Retore Old BX value into SI
+ pop ax ;AN004;Restore logical sector (low)
+ POP DS
+
+ MNUM FTESTINIT
+ MESSAGE FTESTINIT,<" ">
+ SUB SI,BX
+ CMP SI,-1 ;ONE APART?
+ JNZ GETCL2
+ ADD DOSCNT,CX
+ JMP GETCL1
+
+GETCL2:
+ PUSH BX
+ push dx ;AN000; Sector to read (High)
+ push ax ;AN000; Sector to read (low)
+ MOV AX,DRVFAT ;GET DRIVE AND FAT SPEC
+ MOV CX,DOSCNT
+ pop dx ;AN000; Sector to read for DISKRD (Low)
+ pop cs:[Start_Sec_H] ;AN000; Sector to read for DISKRD (High)
+ 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;
+
+Get_FAT_Sector proc near ;AN004;
+;Function: FInd and read the corresponding FAT sector into DS:0
+;In). SI - offset value (starting from FAT entry 0) of FAT entry to find.
+; DS - FATLOC segment
+; cs:DRVFAT - Logical drive number, FAT id
+; cs:Md_SectorSize
+; cs:Last_Fat_SecNum - Last FAT sector number read in.
+;Out). Corresponding FAT sector read in.
+; BX = offset value from FATLOG segment.
+; Other registera saved.
+; Zero flag set if the FAT entry is splitted, i.e., wehn 12 bit FAT entry
+; starts at the last byte of the FAT sector. In this case, the caller
+; should save this byte, and read the next FAT sector to get the rest
+; of the FAT entry value. (This will only happen with the 12 bit fat.)
+
+ push ax ;AN004;
+ push cx ;AN004;
+ push dx ;AN004;
+ push di ;AN004;
+ push si ;AN004;
+ push es ;AN004;
+ push ds ;AN004;
+ xor dx, dx ;AN004;
+ mov ax, si ;AN004;
+ mov cx, cs:Md_SectorSize ;AN004; =512 bytes
+ div cx ;AN004; AX=sector number, dx = offset
+ inc ax ;AN004; Make AX to relative logical sector number
+ cmp ax, cs:Last_Fat_SecNum ;AN004; by adding Reserved sector number.
+ je GFS_Split_Chk ;AN004; Don't need to read it again.
+ mov cs:Last_Fat_SecNum, ax ;AN004; Update Last_Fat_SecNum
+ push dx ;AN004; save offset value.
+ mov cs:[Start_Sec_H],0 ;AN004; Prepare to read the FAT sector
+ mov dx, ax ;AN004; Start_Sec_H is always 0 for FAT sector.
+ mov cx, 1 ;AN004; 1 sector to read
+ mov ax, cs:DrvFAT ;AN004;
+ push ds ;AN004;
+ pop es ;AN004;
+ xor di, di ;AN004; es:di -> FatLoc segment:0
+ call DiskRD ;AN004; cross your finger.
+ pop dx ;AN004; restore offset value.
+ mov cx, cs:Md_SectorSize ;AN004;
+GFS_Split_Chk: ;AN004;
+ dec cx ;AN004;if offset points to the
+ cmp dx, cx ;AN004;last byte of this sector, then splitted entry.
+ mov bx, dx ;AN004;Set BX to DX
+ pop ds ;AN004;
+ pop es ;AN004;
+ pop si ;AN004;
+ pop di ;AN004;
+ pop dx ;AN004;
+ pop cx ;AN004;
+ pop ax ;AN004;
+ ret ;AN004;
+Get_FAT_Sector endp ;AN004;
+
+;
+; SI POINTS TO DEVICE HEADER
+; J.K. 4/22/86 - print_init, aux_init is modified to eliminate the self-modifying
+; J.K. code.
+
+PRINT_INIT:
+ call Get_device_number
+;SB33028*****************************************************************
+ mov ah,1 ;initalize printer port ;SB;3.30
+ int 17h ;call ROM-Bios routine ;SB;3.30
+;SB33028*****************************************************************
+ ret
+
+AUX_INIT:
+ call Get_device_number
+;SB33028*****************************************************************
+ mov al,RSINIT ;2400,N,1,8 (MSEQU.INC) ;SB ;3.30*
+ mov ah,0 ;initalize AUX port ;SB ;3.30*
+ int 14h ;call ROM-Bios routine ;SB ;3.30*
+;SB33028*****************************************************************
+ ret
+
+GET_DEVICE_NUMBER:
+;SI -> device header
+ MOV AL,CS:[SI+13] ;GET DEVICE NUMBER FROM THE NAME
+ SUB AL,"1"
+ CBW
+ MOV DX,AX
+ RET
+
+;
+; PURGE_96TPI NOP'S CALLS TO 96TPI SUPPORT.
+;
+PURGE_96TPI PROC NEAR ;MJB001
+ PUSH DS
+ PUSH ES
+
+ PUSH CS ;MJB001
+ POP ES ;MJB001
+ PUSH CS ;MJB001
+ POP DS ;MJB001
+ ASSUME DS:CODE,ES:CODE
+
+ MOV SI,OFFSET PATCHTABLE
+PATCHLOOP:
+ LODSW
+ MOV CX,AX
+ JCXZ PATCHDONE
+ LODSW
+ MOV DI,AX
+ MOV AL,90H
+ REP STOSB
+ JMP PATCHLOOP
+
+PATCHDONE:
+;**************NOT NEEDED ANY MORE***********************
+; MOV DI,OFFSET FORMAT_PATCH ; ARR 2.42
+; MOV AL,CS:INST_FAR_RET
+; STOSB
+;********************************************************
+ MOV DI,OFFSET TABLE_PATCH ; ARR 2.42
+ MOV AX,OFFSET EXIT
+ STOSW
+ STOSW
+
+ POP ES
+ POP DS
+ RET ;MJB001
+PURGE_96TPI ENDP
+
+;Mini disk initialization routine. Called right after DoHard - J.K. 4/7/86
+; DoMini **********************************************************************
+; **CS=DS=ES=code
+; **DoMini will search for every extended partition in the system, and
+; initialize it.
+; **BDSM stands for BDS table for Mini disk and located right after the label
+; End96Tpi. End_Of_BDSM will have the offset value of the ending
+; address of BDSM table.
+; **BDSM is the same as usual BDS structure except that TIM_LO, TIM_HI entries
+; are overlapped and used to identify mini disk and the number of Hidden_trks.
+; Right now, they are called as IsMini, Hidden_Trks respectively.
+; **DoMini will use the same routine in SETHARD routine after label SET1 to
+; save coding.
+; **DRVMAX determined in DoHard routine will be used for the next
+; available logical mini disk drive number.
+;
+; Input: DRVMAX, DSKDRVS
+;
+; Output: MiniDisk installed. BDSM table established and installed to BDS.
+; num_mini_dsk - the number of mini disks installed in the system.
+; End_Of_BDSM - ending offset address of BDSM.
+;
+;
+; Called modules:
+; GetBoot, WRMSG, int 13h (AH=8, Rom)
+; FIND_MINI_PARTITION (new), Install_BDSM (new),
+; SetMini (new, it will use SET1 routine)
+; Variables used: End_Of_BDSM, numh, mininum, num_mini_dsk,
+; Rom_Minidsk_num, Mini_HDLIM, Mini_SECLIM
+; BDSMs, BDSM_type (struc), Start_BDS
+;******************************************************************************
+;
+
+DoMini:
+ push cs
+ pop es
+ push cs
+ pop ds
+ assume ds:code,es:code
+ Message fTestHard,<"Start of DoMini...",cr,lf>
+
+ push ax ;Do I need to do this?
+
+ mov di, offset BDSMs ;from now on, DI points to BDSM
+;SB33028********************************************************************
+ mov dl, 80h ;look at first hard drive ;SB ;3.30*
+ mov ah, 8h ;get drive parameters ;SB ;3.30*
+ int 13h ;call ROM-Bios ;SB ;3.30*
+;SB33028********************************************************************
+ cmp dl, 0
+ jz DoMiniRet ;no hard file? Then exit.
+ mov numh, dl ;save the number of hard files.
+ xor ax,ax
+ mov al, drvmax
+ mov mininum, al ;this will be the logical drive letter
+ ;for mini disk to start with.
+
+ shl ax, 1 ;ax=number of devices. make it to word boundary
+ push bx
+ mov bx, offset DSKDRVS
+ add bx, ax
+ mov Mini_BPB_ptr, BX ;Mini_BPB_ptr points to the first available
+ ;spot in DskDrvs for Mini disk which
+ ;points to BPB area of BDSM.
+ pop bx
+
+ mov Rom_Minidsk_num, 80h
+DoMiniBegin:
+ inc dh ;Get # of heads (convert it to 1 based)
+ xor ax, ax
+ mov al, dh
+ mov Mini_HDLIM, ax ;save it.
+ xor ax, ax
+ and cl, 3fh ;Get # of sectors/track
+ mov al, cl
+ mov Mini_SECLIM, ax ;and save it.
+
+ mov dl, Rom_Minidsk_num ;drive number
+ call GETBOOT ;read master boot record into 7c0:BootBias
+ assume es:nothing
+ jc DoMiniNext
+ call FIND_MINI_PARTITION
+DoMiniNext:
+ dec numh
+ jz DoMiniRet
+ inc Rom_MiniDsk_Num ;Next hard file
+;SB33028********************************************************************
+ mov dl, Rom_MiniDsk_Num ;look at next hard drive ;SB ;3.30*
+ mov ah, 8h ;get drive parameters ;SB ;3.30*
+ int 13h ;call ROM-Bios ;SB ;3.30*
+;SB33028********************************************************************
+ jmp DoMiniBegin
+
+DoMiniRet:
+ pop ax
+ ret
+
+
+;Find_Mini_Partition tries to find every Extended partition on a disk.
+;At entry: DI -> BDSM entry
+; ES:BX -> 07c0:BootBias - Master Boot Record
+; Rom_MiniDsk_Num - ROM drive number
+; MiniNum - Logical drive number
+; Mini_HDLIM, Mini_SECLIM
+;
+;Called routine: SETMINI which uses SET1 (in SETHARD routine)
+;Variables & equates used from original BIOS - flags, fNon_Removable, fBigfat
+;
+;
+FIND_MINI_PARTITION:
+
+ add bx, 1C2h ;BX -> system id.
+
+FmpNext:
+ cmp byte ptr ES:[BX], 5 ; 5 = extended partition ID.
+ jz FmpGot
+ add bx, 16 ; for next entry
+ cmp bx, 202h+BootBias
+ jnz FmpNext
+ jmp FmpRet ;not found extended partition
+
+FmpGot: ;found my partition.
+ Message ftestHard,<"Found my partition...",cr,lf>
+ 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.
+ mov ax, Mini_HDLIM
+ mov [DI].HDLIM, ax
+ mov ax, Mini_SECLIM
+ mov [DI].SECLIM, ax
+ mov al, Rom_MiniDsk_Num
+ mov [DI].DRIVENUM, al ;set physical number
+ mov al, Mininum
+ mov [DI].DRIVELET, al ;set logical number
+
+ cmp word ptr es:[bx+10], 0 ;AN000;
+ ja FmpGot_Cont ;AN000;
+ cmp word ptr ES:[BX+8], 64 ;**With current BPB, only lower word
+ ; is meaningful.
+ jb FmpRet ;should be bigger than 64 sectors at least
+FmpGot_Cont: ;AN000;
+ sub bx, 4 ;let BX point to the start of the entry
+ mov dh, byte ptr ES:[BX+2]
+ and dh, 11000000b ;get higher bits of cyl
+ rol dh, 1
+ rol dh, 1
+ mov dl, byte ptr ES:[BX+3] ;cyl byte
+ mov [DI].HIDDEN_TRKS, dx ;set hidden trks
+;** Now, read the volume boot record into BootBias.
+;SB33029******************************************************************
+ mov cx,ES:[BX+2] ;cylinder,cylinder/sector ;SB ;3.30*
+ mov dh,ES:[BX+1] ;head ;SB ;3.30*
+ mov dl,Rom_MiniDsk_Num ;drive ;SB ;3.30*
+ mov bx,BOOTBIAS ;buffer offset ;SB ;3.30*
+ mov ax,0201h ;read,1 sector ;SB ;3.30*
+ int 13h ;call ROM-Bios routine ;SB ;3.30*
+;SB33029******************************************************************
+ jc FmpRet ;cannot continue.
+ mov bx, 1c2h+BOOTBIAS
+
+ push es ;;DCL/KWC 8/2/87 addressability to
+ ;; next minidisk
+
+ call SetMini ;install a mini disk. BX value saved.
+
+ pop es ;;DCL/KWC 8/2/87
+
+ jc FmpnextChain
+
+ call Install_BDSM ;install the BDSM into the BDS table
+; call Show_Installed_Mini ;show the installed message. 3/35/86 - Don't show messages. J.K.
+ inc mininum ;increase the logical drive number for next
+ inc num_mini_dsk ;increase the number of mini disk installed.
+
+ push bx ;now, set the DskDrvs pointer to BPB info.
+ mov bx, Mini_BPB_ptr
+ lea si, [di].BYTEPERSEC ;points to BPB of BDSM
+ mov [bx], si
+ inc Mini_BPB_ptr ;advance to the next address
+ inc Mini_BPB_ptr
+ pop bx
+
+ add DI, type BDSM_type ;adjust to the next BDSM table entry.
+ mov End_OF_BDSM, DI ;set the ending address of BDSM table to this.
+; Message fTestHard,<"Mini disk installed.",cr,lf>
+FmpnextChain: jmp FmpNext ;let's find out if we have any chained partition
+FmpRet:
+ ret
+
+SetMini:
+ push di
+ push bx
+ push ds
+ jmp SET1 ;will be returned to Find mini partition routine.
+ ;Some logic has been added to SET1 to
+ ;deal with Mini disks.
+
+;
+;Install BDSM installs a BDSM (pointed by DS:DI) into the end of the current
+;linked list of BDS.
+;Also, set the current BDSM pointer segment to DS.
+;At entry: DS:DI -> BDSM
+;
+Install_BDSM:
+assume ds:code,es:nothing
+ push ax
+ push si
+ push es
+
+ les si, dword ptr cs:Start_BDS ;start of the beginning of list
+I_BDSM_Next:
+ cmp word ptr es:[si], -1 ;end of the list?
+ jz I_BDSM_New
+ mov si, word ptr es:[si].LINK
+ mov ax, word ptr es:[si].LINK+2 ;next pointer
+ mov es, ax
+ jmp short I_BDSM_Next
+I_BDSM_New:
+ mov ax, ds
+ mov word ptr ds:[di].LINK+2, ax ;BDSM segment had not been initialized.
+ mov word ptr es:[si].LINK+2, ax
+ mov word ptr es:[si].LINK, di
+ mov word ptr ds:[di].LINK, -1 ;make sure it is a null ptr.
+
+I_BDSM_ret:
+ pop es
+ pop si
+ pop ax
+ ret
+
+;***The following code is not needed any more. Don't show any
+;***messages to be compatible with the behavior of IBMBIO.COM.
+;;Show the message "Mini disk installed ..."
+;;This routine uses WRMSG procedure which will call OUTCHR.
+;Show_Installed_Mini:
+; push ax
+; push bx
+; push ds
+;
+; mov al, Mininum ;logical drive number
+; add al, Drv_Letter_Base ;='A'
+; mov Mini_Drv_Let, al
+; mov si, offset Installed_Mini
+; call WRMSG
+;
+; pop ds
+; pop bx
+; pop ax
+; ret
+;**End of mini disk initialization** ;J.K. 4/7/86
+
+
+CMOS_Clock_Read proc near
+
+ assume ds:code,es:code
+; IN ORDER TO DETERMINE IF THERE IS A CLOCK PRESENT IN THE SYSTEM, THE FOLLOWING
+; NEEDS TO BE DONE.
+ PUSH AX
+ PUSH CX
+ PUSH DX
+ PUSH BP
+
+ XOR BP,BP
+LOOP_CLOCK:
+ XOR CX,CX
+ XOR DX,DX
+;SB33030********************************************************************
+ MOV AH,2 ;READ REAL TIME CLOCK ;SB ;3.30
+ INT 1Ah ;CALL ROM-BIOS ROUTINE ;SB ;3.30
+;SB33030********************************************************************
+ CMP CX,0
+ JNZ CLOCK_PRESENT
+
+ CMP DX,0
+ JNZ CLOCK_PRESENT
+
+ CMP BP,1 ; READ AGAIN AFTER A SLIGHT DELAY, IN CASE CLOCK
+ JZ NO_READDATE ; WAS AT ZERO SETTING.
+
+ INC BP ; ONLY PERFORM DELAY ONCE.
+ MOV CX,4000H
+DELAY:
+ LOOP DELAY
+ JMP LOOP_CLOCK
+
+CLOCK_PRESENT:
+ mov cs:HaveCMOSClock, 1 ;J.K. Set the flag for cmos clock
+
+ call CMOSCK ;J.K. Reset CMOS clock rate that may be
+ ;possibly destroyed by CP DOS and POST routine did not
+ ;restore that.
+
+ PUSH SI
+ MESSAGE FTESTINIT,<"CLOCK DEVICE",CR,LF>
+ CALL READ_REAL_DATE ;MJB002 READ REAL-TIME CLOCK FOR DATE
+
+ CLI ;MJB002
+ MOV DAYCNT,SI ;MJB002 SET SYSTEM DATE
+ STI ;MJB002
+ POP SI ;MJB002
+NO_READDATE:
+ POP BP
+ POP DX
+ POP CX
+ POP AX
+ RET
+
+CMOS_Clock_Read endp
+;
+;J.K. 10/28/86
+;J.K. THE FOLLOWING CODE IS WRITTEN BY JACK GULLEY IN ENGINEERING GROUP.
+;J.K. CP DOS IS CHANGING CMOS CLOCK RATE FOR ITS OWN PURPOSES AND IF THE
+;J.K. USE COLD BOOT THE SYSTEM TO USE PC DOS WHILE RUNNING CP DOS, THE CMOS
+;J.K. CLOCK RATE ARE STILL SLOW WHICH SLOW DOWN DISK OPERATIONS OF PC DOS
+;J.K. WHICH USES CMOS CLOCK. PC DOS IS PUT THIS CODE IN MSINIT TO FIX THIS
+;J.K. PROBLEM AT THE REQUEST OF CP DOS.
+;J.K. THE PROGRAM IS MODIFIED TO BE RUN ON MSINIT. Equates are defined in CMOSEQU.INC.
+;J.K. This program will be called by CMOS_Clock_Read procedure.
+;
+; The following code CMOSCK is used to insure that the CMOS has not
+; had its rate controls left in an invalid state on older AT's.
+;
+; It checks for an AT model byte "FC" with a submodel type of
+; 00, 01, 02, 03 or 06 and resets the periodic interrupt rate
+; bits incase POST has not done it. This initilization routine
+; is only needed once when DOS loads. It should be ran as soon
+; as possible to prevent slow diskette access.
+;
+; This code exposes one to DOS clearing CMOS setup done by a
+; resident program that hides and re-boots the system.
+;
+CMOSCK PROC NEAR ; CHECK AND RESET RTC RATE BITS
+ assume ds:nothing,es:nothing
+
+;Model byte and Submodel byte were already determined in MSINIT.
+ push ax
+ cmp cs:Model_byte, 0FCh ;check for PC-AT model byte
+ ; EXIT IF NOT "FC" FOR A PC-AT
+ JNE CMOSCK9 ; Exit if not an AT model
+
+ CMP cs:Secondary_Model_Byte,06H ; Is it 06 for the industral AT
+ JE CMOSCK4 ; Go reset CMOS periodic rate if 06
+ CMP cs:Secondary_Model_Byte,04H ; Is it 00, 01, 02, or 03
+ JNB CMOSCK9 ; EXIT if problem fixed by POST
+ ;J.K. Also,Secondary_model_byte = 0 when AH=0c0h, int 15h failed.
+CMOSCK4: ; RESET THE CMOS PERIODIC RATE
+ ; Model=FC submodel=00,01,02,03 or 06
+;SB33IN2***********************************************************************
+
+ mov al,CMOS_REG_A or NMI ;NMI disabled on return
+ mov ah,00100110b ;Set divider & rate selection
+ call CMOS_WRITE
+
+;SB33IN2***********************************************************************
+
+ ; CLEAR SET,PIE,AIE,UIE AND SQWE
+ 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
+
+;SB33IN3***********************************************************************
+
+CMOSCK9: ; EXIT ROUTINE
+ pop ax
+ RET ; RETurn to caller
+ ; Flags modifyied
+CMOSCK ENDP
+PAGE
+;--- CMOS_READ -----------------------------------------------------------------
+; READ BYTE FROM CMOS SYSTEM CLOCK CONFIGURATION TABLE :
+; :
+; INPUT: (AL)= CMOS TABLE ADDRESS TO BE READ :
+; BIT 7 = 0 FOR NMI ENABLED AND 1 FOR NMI DISABLED ON EXIT :
+; BITS 6-0 = ADDRESS OF TABLE LOCATION TO READ :
+; :
+; OUTPUT: (AL) VALUE AT LOCATION (AL) MOVED INTO (AL). IF BIT 7 OF (AL) WAS :
+; ON THEN NMI LEFT DISABLED. DURING THE CMOS READ BOTH NMI AND :
+; NORMAL INTERRUPTS ARE DISABLED TO PROTECT CMOS DATA INTEGRITY. :
+; THE CMOS ADDRESS REGISTER IS POINTED TO A DEFAULT VALUE AND :
+; THE INTERRUPT FLAG RESTORED TO THE ENTRY STATE ON RETURN. :
+; ONLY THE (AL) REGISTER AND THE NMI STATE IS CHANGED. :
+;-------------------------------------------------------------------------------
+
+CMOS_READ PROC NEAR ; READ LOCATION (AL) INTO (AL)
+ assume es:nothing,ds:nothing
+ PUSHF ; SAVE INTERRUPT ENABLE STATUS AND FLAGS
+;SB33IN4********************************************************************
+
+ 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
+
+;SB33IN4********************************************************************
+ PUSH CS ; *PLACE CODE SEGMENT IN STACK AND
+ CALL CMOS_POPF ; *HANDLE POPF FOR B- LEVEL 80286
+ RET ; RETURN WITH FLAGS RESTORED
+
+CMOS_READ ENDP
+
+CMOS_POPF PROC NEAR ; POPF FOR LEVEL B- PARTS
+ IRET ; RETURN FAR AND RESTORE FLAGS
+
+CMOS_POPF ENDP
+
+;--- CMOS_WRITE ----------------------------------------------------------------
+; WRITE BYTE TO CMOS SYSTEM CLOCK CONFIGURATION TABLE :
+; :
+; INPUT: (AL)= CMOS TABLE ADDRESS TO BE WRITTEN TO :
+; BIT 7 = 0 FOR NMI ENABLED AND 1 FOR NMI DISABLED ON EXIT :
+; BITS 6-0 = ADDRESS OF TABLE LOCATION TO WRITE :
+; (AH)= NEW VALUE TO BE PLACED IN THE ADDRESSED TABLE LOCATION :
+; :
+; OUTPUT: VALUE IN (AH) PLACED IN LOCATION (AL) WITH NMI LEFT DISABLED :
+; IF BIT 7 OF (AL) IS ON. DURING THE CMOS UPDATE BOTH NMI AND :
+; NORMAL INTERRUPTS ARE DISABLED TO PROTECT CMOS DATA INTEGRITY. :
+; THE CMOS ADDRESS REGISTER IS POINTED TO A DEFAULT VALUE AND :
+; THE INTERRUPT FLAG RESTORED TO THE ENTRY STATE ON RETURN. :
+; ONLY THE CMOS LOCATION AND THE NMI STATE IS CHANGED. :
+;-------------------------------------------------------------------------------
+
+CMOS_WRITE PROC NEAR ; WRITE (AH) TO LOCATION (AL)
+ assume es:nothing,ds:nothing
+ PUSHF ; SAVE INTERRUPT ENABLE STATUS AND FLAGS
+ PUSH AX ; SAVE WORK REGISTER VALUES
+
+ 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
+
+;SB33IN5********************************************************************
+ POP AX ; RESTORE WORK REGISTERS
+ PUSH CS ; *PLACE CODE SEGMENT IN STACK AND
+ CALL CMOS_POPF ; *HANDLE POPF FOR B- LEVEL 80286
+ RET
+
+CMOS_WRITE ENDP
+;
+
+
+END$:
+CODE ENDS
+ END
+
\ No newline at end of file
diff --git a/v4.0/src/BIOS/MSIOCTL.INC b/v4.0/src/BIOS/MSIOCTL.INC
new file mode 100644
index 0000000..9967605
--- /dev/null
+++ b/v4.0/src/BIOS/MSIOCTL.INC
@@ -0,0 +1,1362 @@
+ %OUT MSIOCTL.SIL...
+ INCLUDE IOCTL.INC
+; $SALUT $ioctl$
+
+;==============================================================================
+;REVISION HISTORY:
+;AN000 - New for DOS Version 4.00 - J.K.
+;AC000 - Changed for DOS Version 4.00 - J.K.
+;AN00x - PTM number for DOS Version 4.00 - J.K.
+;==============================================================================
+;AN001 - P58 Diskcopy format fails when error occurs during format op.6/26/87 J.K.
+;AN002; - d24 MultiTrack= command added. 6/29/87 J.K.
+;AN003; - p155 Format intermittant failre due to haed settle time 8/18/87 J.K.
+;AN004; D113 Disable I/O access to unformatted media 9/03/87 J.K.
+;AN005; P985 Allow I/O access to unformtted media 9/14/87 J.K.
+;AN006; D241 Provide support of Multi-track Format/Verify 9/23/87 J.K.
+;AN007; P1535 Unformatted hard file problem 10/15/87 J.K.
+;AN008; P2590 Change the recommended BPB info. after AFS format 11/20/87 J.K.
+;AN009; P2828 Do not retry for multi-track format request 12/08/87 J.K.
+;AN010; P2781 Changeline error behavior incompatibile with DOS 3.3. 1/06/88 J.K.
+;AN011; P3178 Set Media ID should update media info in BDS table. 1/21/88 J.K.
+;AN012; D490 IOCTL subfunction 63h,43h,64h,44h conflicts with OS2 2/26/88 J.K.
+;==============================================================================
+
+;J.K. 10/15/87
+;NOTE: GetAccessFlag/SetAccessFlag is unpublished function.
+; This function is intended to give the user to control the
+; BDS table FLAGS of UNFORMATTED_MEDIA bit.
+; GetAccessFlag will show the status -
+; A_DISKACCESS_CONTROL.DAC_ACCESS_FLAG = 0 DISK I/O not allowed
+; 1 DISK I/O allowed
+; SetAccessFlag will Set/Reset the UNFORMATTED_MEDIA bit in FLAGS -
+; A_DISKACCESS_CONTROL.DAC_ACCESS_FLAG = 0 Allow disk I/O
+; 1 Disallow disk I/O
+;------------------------------------------------------------------------------
+
+; GENERIC IOCTL DISPATCH TABLES
+;
+IOREADJUMPTABLE DB 7 ;AN012;maximum number (0 based)
+ DW OFFSET GETDEVICEPARAMETERS ;60h
+ DW OFFSET READTRACK ;61h
+ DW OFFSET VERIFYTRACK ;62h
+ dw Cmd_Err_Proc ;AN012;Overlapped with OS2 subfunction
+ dw Cmd_Err_Proc ;AN012;
+ dw Cmd_Err_Proc ;AN012;
+ dw GetMediaID ;AN000;AN012;66h
+ dw GetAccessFlag ;AN007;AN012;67h Unpublished function
+
+IOWRITEJUMPTABLE DB 7 ;AN012;
+ DW OFFSET SETDEVICEPARAMETERS ;40h
+ DW OFFSET WRITETRACK ;41h
+ DW OFFSET FORMATTRACK ;42h
+ dw Cmd_Err_Proc ;AN012;
+ dw Cmd_Err_Proc ;AN012;
+ dw Cmd_Err_Proc ;AN012;
+ dw SetMediaID ;AN000;AN012;46h
+ dw SetAccessFlag ;AN007;AN012;47h Unpublished function
+;
+; TRACKTABLE CONTAINS A 4-TUPLES (C,H,R,N) FOR EACH SECTOR IN A TRACK
+; C = CYLINDER NUMBER, H = HEAD NUMBER, R = SECTOR ID, N = BYTES PER SECTOR
+; N BYTES PER SECTOR
+; --- ----------------
+; 0 128
+; 1 256
+; 2 512
+; 3 1024
+;
+MAX_SECTORS_CURR_SUP EQU 63 ; CURRENT MAXIMUM SEC/TRK THAT
+ ; WE SUPPORT (Was 40 in DOS 3.2)
+SECTORSPERTRACK DW 36
+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 0,0,19,2
+ db 0,0,20,2
+ db 0,0,21,2
+ db 0,0,22,2
+ db 0,0,23,2
+ db 0,0,24,2
+ db 0,0,25,2
+ db 0,0,26,2
+ db 0,0,27,2
+ db 0,0,28,2
+ db 0,0,29,2
+ db 0,0,30,2
+ db 0,0,31,2
+ db 0,0,32,2
+ db 0,0,33,2
+ db 0,0,34,2
+ db 0,0,35,2
+ db 0,0,36,2
+ DB 4*MAX_SECTORS_CURR_SUP - ($ - TRACKTABLE) DUP (0)
+
+; 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
+Had_Format_Error db 0 ; 1 if the previous format operation
+ ; failed. - J.K. 7/8/86
+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.
+
+; TEMP DISK BASE TABLE. IT HOLDS THE THE CURRENT DPT WHICH IS THEN REPLACED BY
+; THE ONE PASSED BY "NEW ROMS" BEFORE WE PERFORM A FORMAT OPERATION. THE OLD
+; DPT IS RESTORED IN RESTOREOLDDPT. THE FIRST ENTRY (DISK_SPECIFY_1) IS -1 IF
+; THIS TABLE DOES NOT CONTAIN THE PREVIOUSLY SAVED DPT.
+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
+ and al, 9fH ;AN000; Try to check other than 6x, 4x.
+ 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
+Cmd_Err_Proc: ;AN012;
+ pop dx ;AN012;clear up stack
+ pop dx ;AN012;clear up stack
+ jmp IOCTL_FUNC_ERR ;AN012;Cmd error
+;
+; GETDEVICEPARAMETERS:
+;
+; INPUT: DS:DI POINTS TO BDS FOR DRIVE
+; ES:BX POINTS TO DEVICE PARAMETER PACKET
+;
+ PUBLIC GETDEVICEPARAMETERS
+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
+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)
+ AND CX, NOT (FNON_REMOVABLE OR FCHANGELINE OR GOOD_TRACKLAYOUT or UNFORMATTED_MEDIA) ;AN004;AN005;AN007;
+ 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 ;AN008; Comment out this instruction.
+
+INSTALLRECOMMENDEDBPB:
+ MOV CX, SIZE A_BPB
+ LEA DI, BYTE PTR [DI].RBYTEPERSEC
+ JMP SHORT COPYTHEBPB
+
+INSTALLFAKEBPB:
+ or word ptr ds:[di].flags, return_fake_bpb ;AN000; Problem
+ ;reported by WHS.
+ 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 ; RESTORE THE OLD DPT FROM TEMPDPT
+ 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
+ MOV DI, OFFSET TRACKTABLE
+ LEA SI, ES:[BX].DP_SECTORTABLE
+ PUSH ES
+ POP DS
+ PUSH CS
+ POP ES
+STORESECTORINFO:
+ INC DI ; SKIP OVER CYLINDER
+ INC DI ; SKIP OVER HEAD
+ LODSW ; GET SECTOR ID
+ PUSH AX ; SAVE IT
+ LODSW ; GET SECTOR SIZE
+ CALL SECTORSIZETOSECTORINDEX
+ POP DX ; GET SECTOR ID BACK
+ MOV AL, DL ; AH = SECTOR SIZE INDEX
+ ; AL = SECTOR ID
+ STOSW
+ LOOP STORESECTORINFO
+
+SECTORINFOSAVED:
+ CLC
+ RET
+
+TOOMANYSECTORSPERTRACK:
+ MOV AL, 0CH
+ STC
+ RET
+
+SETDEVICEPARAMETERS ENDP
+
+;
+; SET MEDIA TYPE FOR FORMAT
+; PERFORMS THE INT 13 WITH AH = 18H TO SEE IF THE MEDIUM DESCRIBED IN THE
+; BPB AREA IN THE BDS CAN BE HANDLED BY THE ROM.
+; ON INPUT, DS:DI -> CURRENT BDS.
+; THE STATUS OF THE OPERATION IS RETURNED IN AL
+; - 0 - IF THE SUPPORT IS AVAILABLE, AND THE COMBINATION IS VALID.
+; - 1 - NO ROM SUPPORT
+; - 2 - ILLEGAL COMBINATION
+; - 3 - No media present (ROM support exists but cannot determine now)
+; 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.
+;
+ PUBLIC SET_MEDIA_FOR_FORMAT
+SET_MEDIA_FOR_FORMAT PROC NEAR
+ SAVEREG
+ XOR AX,AX
+ cmp cs:[Had_Format_Error],1 ;Did we have a format error before?
+ jne No_Form_Err ;AN001;
+ call ResetDisk
+No_Form_Err: ;AN001;
+ CMP BYTE PTR CS:[MEDIA_SET_FOR_FORMAT],1
+ jnz Do_Set_Media_for_Format
+ jmp SET_MED_RET ; MEDIA ALREADY SET
+Do_Set_Media_for_Format:
+ SAVEREG
+ MOV DS,AX
+ LDS SI,DWORD PTR DS:[DSKADR] ; GET POINTER TO DISK BASE TABLE
+ MOV WORD PTR CS:[DPT],SI
+ MOV WORD PTR CS:[DPT+2],DS ; SAVE POINTER TO TABLE
+;SB34IOCTL000******************************************************************
+;SB Initialise the head settle time to 0fh. See the offsets given in
+;SB DSKPRM.INC. 1 LOC.
+
+ mov ds:[si].DISK_HEAD_STTL, 0Fh
+;SB34IOCTL000******************************************************************
+ RESTOREREG
+ mov cs:[New_Rom], 1 ;assume a new ROM.
+ XOR AL,AL
+;SB33031****************************************************************
+ mov cx,ds:[di.ccyln] ;get number of cylinders ;SB ;3.30*
+ dec cx ;cylinder must be zero based ;SB ;3.30*
+ and ch,03h ; blank out unnecessary bits
+ ror ch,1 ;put in int form ;SB ;3.30*
+ ror ch,1 ; ;SB ;3.30*
+ xchg ch,cl ; ;SB ;3.30*
+ or cl,byte ptr ds:[di.seclim] ;get number of sectors ;SB ;3.30*
+ mov dl,ds:[di.drivenum] ;get drive number ;SB ;3.30*
+ mov ah,18h ;set media for format ;SB ;3.30*
+ SAVEREG
+ int 13h ;call rom bios ;SB ;3.30*
+;SB33031****************************************************************
+ JC FORMAT_STAT_ERR
+; ES:DI POINTS TO A DISK BASE TABLE FOR THIS COMBINATION FOR THIS DRIVE.
+ XOR CX,CX
+ MOV DS,CX ; HAVE DS -> SEGMENT 0
+ LDS SI,DWORD PTR DS:[DSKADR] ; GET CURRENT DISK BASE TABLE
+ MOV WORD PTR CS:[TEMPDPT],SI
+ MOV WORD PTR CS:[TEMPDPT+2],DS ; SAVE IT
+ MOV WORD PTR DS:[DSKADR],DI
+ MOV WORD PTR DS:[DSKADR+2],ES ; REPLACE WITH ONE RETURNED BY ROM
+ MOV BYTE PTR CS:[MEDIA_SET_FOR_FORMAT],1
+Skip_Disk_Base_setting:
+ XOR AL,AL ; LEGAL COMBINATION + ROM SUPPORT CODE
+ mov cs:[Had_Format_Error],al ;reset the flag
+ JMP SHORT POP_STAT_RET
+
+FORMAT_STAT_ERR:
+ cmp ah, Dsk_illegal_combination ;J.K. illegal combination = 0ch
+ je Format_stat_illegal_comb
+ cmp ah, Dsk_Time_Out_Err ;J.K. = 80h
+ je Format_stat_Time_out
+ mov al, 1 ;Function not supported.
+ mov cs:[New_Rom], 0 ;So, it is an old rom.
+ jmp short Pop_stat_ret
+Format_stat_illegal_comb: ;J.K. Function supported, but
+ MOV AL,2 ;J.K. illegal sect/trk, trk combination.
+ jmp short Pop_stat_ret
+Format_stat_Time_out: ;J.K. Function supported, but
+ mov al, 3 ;J.K. media not present.
+POP_STAT_RET:
+ RESTOREREG
+SET_MED_RET:
+ RESTOREREG
+ RET
+
+SET_MEDIA_FOR_FORMAT 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 ;J.K. 7/8/86
+; CARRY CLEARED.
+;
+; FOR FORMAT TRACK:
+; CARRY SET IF ERROR
+;
+ PUBLIC FORMATTRACK
+FORMATTRACK PROC NEAR
+ TEST BYTE PTR ES:[BX].DP_SPECIALFUNCTIONS,STATUS_FOR_FORMAT
+ JZ DO_FORMAT_TRACK
+ CALL SET_MEDIA_FOR_FORMAT ; ALSO MOVES CURRENT DPT TO TEMPDPT
+STAT_RET:
+ MOV BYTE PTR ES:[BX].DP_SPECIALFUNCTIONS,AL
+ CLC
+ RET
+
+DO_FORMAT_TRACK:
+ CMP BYTE PTR DS:[DI].FORMFACTOR, DEV_HARDDISK
+ jne Do_Format_Diskette
+ jmp DoVerifyTrack
+Do_Format_Diskette:
+ SAVEREG
+;SB34IOCTL001*************************************************************
+;SB check the special functions word to see if DO_FAST_FORMAT has been
+;SB specified. If so it is an error and we need to finish this operation
+;SB by indicating the error value 1 in register ah and going to the
+;SB the code at DO_MAP_IT to map the error. This is because we cannot
+;SB allow multitrack format on floppies - 5 LOCS
+
+ test byte ptr es:[bx].FP_SPECIALFUNCTIONS,DO_FAST_FORMAT
+ jz NO_FAST_FORMAT
+ mov ah, 1
+ jmp DO_MAP_IT
+NO_FAST_FORMAT:
+;SB34IOCTL001*************************************************************
+ CALL SET_MEDIA_FOR_FORMAT ; ALSO MOVES CURRENT DPT TO TEMPDPT
+ CMP AL,1 ; DO WE HAVE ROM SUPPORT FOR sector/trk, # trks combination?
+ JZ Need_Set_DASD ;Old ROM.
+ cmp al,3 ;time out error?
+ jnz No_Set_DASD ;No, fine.(At this point, don't care about the illegal combination.)
+ jmp Format_Failed
+Need_Set_DASD:
+ CALL SETDASD ;AH=17h, INT 13h
+;
+; 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.).
+
+NO_SET_DASD:
+; 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
+
+ PUSH DI ; SAVE PTR TO BDS
+ MOV DI, OFFSET TRACKTABLE
+ PUSH CS
+ POP ES
+ MOV CX, CS:SECTORSPERTRACK
+STORECYLINDERHEAD:
+ STOSW
+ INC DI ; SKIP SECTOR ID
+ INC DI ; SKIP SECTOR SIZE
+ LOOP STORECYLINDERHEAD
+ POP DI ; RESTORE PTR TO BDS
+
+ MOV CX, MAXERR ; SET UP RETRY COUNT
+FORMATRETRY:
+ PUSH CX
+ MOV BX, OFFSET TRACKTABLE
+ PUSH CS
+ POP ES
+ MOV AX, CS:SECTORSPERTRACK
+ MOV AH, ROMFORMAT
+ CALL TO_ROM
+ POP CX
+ JNC FORMATOK
+ call resetdisk
+ mov cs:[Had_Format_Error],1
+ push ax
+ push cx
+ push dx
+ call Set_Media_For_Format
+ cmp al, 1
+ jnz While_Err
+ call SetDASD
+While_Err:
+ pop dx
+ pop cx
+ pop ax
+ LOOP FORMATRETRY
+;SB33106*******************************************************************
+Format_Failed:
+ mov cs:[Had_Format_Error], 1 ;set the format error flag.
+ cmp ah, Dsk_Change_Line_Err ;=06h. Convert change line
+ jne Do_Map_it ;error to Time Out error.
+ mov ah, Dsk_Time_Out_Err ;=80h
+;SB33106*******************************************************************
+Do_Map_it:
+ CALL MAPERROR
+ RESTOREREG
+ RET
+
+FORMATOK:
+ mov cs:[Had_Format_Error],0 ;reset the format error flag.
+ RESTOREREG
+
+DOVERIFYTRACK:
+ CALL VERIFYTRACK
+ RET
+
+FORMATTRACK ENDP
+
+VerifyTrack_Err: ;AN006;
+ mov ah, 1 ;AN006;
+ call MapError ;AN006;
+ ret ;AN006;
+
+;
+; VERIFYTRACK:
+;
+; INPUT: DS:DI POINTS TO BDS FOR DRIVE
+; ES:BX POINTS TO VERIFY PACKET
+;
+ PUBLIC VERIFYTRACK
+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
+ MOV CX, CS:SECTORSPERTRACK ;CL = sectors/track
+;SB34IOCTL005*************************************************************
+;SB
+;SB Check SPECIALFUNCTIONS to see if DO_FAST_FORMAT has been specified
+;SB If not we should go to the normal track verification routine. If
+;SB fast format has been specified we should get the number of tracks
+;SB to be verified and check it to see if it is > 255. If it is then
+;SB it is an error and we should go to VerifyTrack_Err. If not multiply
+;SB the number of tracks by the sectors per track to get the total
+;SB number of sectors to be verified. This should also be less than
+;SB equal to 255 otherwise we go to same error exit. If everything
+;SB is okay we initalise cx to the total sectors. use ax as a temporary
+;SB register. 9 LOCS
+
+ test byte ptr es:[bx].FP_SPECIALFUNCTIONS,DO_FAST_FORMAT
+ jz Norm_VerifyTrack
+ mov ax,es:[bx].FP_TRACKCOUNT ;ax <- tracks to be verify
+ cmp ax,0FFh
+ ja VerifyTrack_Err ;#tracks > 255
+ mul cl
+ cmp ax,0FFh ;#sectors > 255
+ ja VerifyTrack_Err
+ mov cx,ax ;#sectors to verify
+;SB34IOCTL005*************************************************************
+
+;Set the multi track request flag
+ test word ptr [di].Flags, fNON_REMOVABLE ;AN009;hard disk?
+ jz Norm_VerifyTrack ;AN009;
+ test cs:Multrk_Flag, MULTRK_ON ;AN009;MultiTrack operation = on?
+ jz Norm_VerifyTrack ;AN009;
+ mov cs:Multitrk_Format_Flag, 1 ;AN009; then set the flag
+Norm_VerifyTrack: ;AN006;
+ XOR AX, AX ;1st sector
+; USE 0:0 AS THE TRANSFER ADDRESS FOR VERIFY
+ XOR BX, BX
+ MOV ES, BX
+ CALL TRACKIO
+ mov cs:Multitrk_Format_Flag, 0 ;AN009;Reset the flag.
+ RET
+VERIFYTRACK ENDP
+
+;
+; READTRACK:
+;
+; INPUT: DS:DI POINTS TO BDS FOR DRIVE
+; ES:BX POINTS TO READ PACKET
+;
+ PUBLIC READTRACK
+READTRACK:
+ MOV CS:RFLAG, ROMREAD
+ JMP READWRITETRACK
+
+;
+; WRITETRACK:
+;
+; INPUT: DS:DI POINTS TO BDS FOR DRIVE
+; ES:BX POINTS TO WRITE PACKET
+;
+ PUBLIC WRITETRACK
+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
+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
+; SEE IF WE HAVE ALREADY SET THE DISK BASE TABLE
+ CMP BYTE PTR CS:[MEDIA_SET_FOR_FORMAT],1
+ JZ DPTALREADYSET
+;
+; SET UP TABLES AND VARIABLES FOR I/O
+;
+ 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
+ LODS BYTE PTR CS:[SI]
+ MOV CS:CURSEC, AL
+;*** For a Fixed disk multi-track disk I/O - J.K. 4/14/86
+;Assumptions: 1). In the input CX (# of sectors to go) to TRACKIO, only CL is
+;valid. 2). Sector size should be set to 512 bytes. 3). GOODTRACKLAYOUT.
+;
+ test word ptr [di].Flags, fNon_Removable ;Fixed disk? - J.K.
+ jz IOREMOVABLE ;no -J.K.
+ test cs:MulTrk_Flag, MULTRK_ON ;AN002; Allow multi-track operation?
+ jz IORemovable ;AN002; No, don't do that.
+ mov cs:[seccnt], dx ;# of sectors to I/O -J.K.
+ mov ax, dx ;J.K.
+ call disk ;J.K.
+ pop dx ;J.K.
+ pop cx ;J.K.
+ clc ;J.K.
+ ret ;J.K.
+IOREMOVABLE: ;J.K.
+; GET SECTOR SIZE INDEX FROM TRACK TABLE AND SAVE IT
+ LODS BYTE PTR CS:[SI]
+ PUSH AX
+; PATCH SECTOR SIZE IN DPT
+ PUSH SI
+ PUSH DS
+ LDS SI, CS:DPT
+ MOV BYTE PTR DS:[SI].DISK_SECTOR_SIZ,AL
+ MOV AL,CS:[EOT]
+ MOV [SI].DISK_EOT,AL ; SET UP THE MAX NUMBER OF SEC/TRACK
+ POP DS
+ MOV AL, DL
+DOTHEIO:
+ MOV CS:[SECCNT],AX ; SET UP THE COUNT OF SECTORS TO I/O
+ CALL DISK
+; ADVANCE BUFFER POINTER BY ADDING SECTOR SIZE
+ POP SI
+ POP AX
+ CALL SECTORSIZEINDEXTOSECTORSIZE
+ ADD BX, AX
+ POP DX
+ POP CX
+ LOOP IONEXTSECTOR
+ cmp byte ptr cs:[Media_Set_For_Format], 1 ;AN001;
+ je No_Need_Done ;AN001;
+ CALL DONE ; SET TIME OF LAST ACCESS, AND RESET
+No_Need_Done: ;AN001;
+ 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
+ CMP AH,2 ; EXAMINE UPPER BYTE ONLY
+ JA ONEK
+ MOV AL,AH ; VALUE IN AH IS THE INDEX!
+ RET
+ONEK:
+ MOV AL,3
+ RET
+SECTORSIZETOSECTORINDEX ENDP
+
+SECTORSIZEINDEXTOSECTORSIZE PROC NEAR
+ MOV CL, AL
+ MOV AX,128
+ SHL AX, CL
+ 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
+;
+ PUBLIC SETDASD
+SETDASD:
+; SEE IF WE HAVE PREVIOUSLY SET DASD TYPE
+;SB33114******************************************************************
+ cmp cs:[Had_Format_Error],1
+ je DoSetDasd
+;SB33114******************************************************************
+ TEST WORD PTR DS:[DI].FLAGS, SET_DASD_TRUE
+ JZ DASDHASBEENSET
+ AND WORD PTR DS:[DI].FLAGS, NOT SET_DASD_TRUE
+;SB33115******************************************************************
+DoSetDasd:
+ mov cs:[Had_Format_Error],0 ;reset it
+;SB33115******************************************************************
+ MOV CS:[GAP_PATCH],50H ; FORMAT GAP FOR 48TPI DISKS
+ MOV AL,4
+ CMP BYTE PTR DS:[DI].FORMFACTOR,DEV_3INCH720KB
+ JZ DO_SET
+ CMP BYTE PTR DS:[DI].FORMFACTOR, DEV_5INCH96TPI
+ JZ GOT_BIG
+ MOV AL,1 ; 160/320K IN A 160/320K DRIVE
+ JMP SHORT DO_SET
+GOT_BIG:
+ MOV AL,2 ; 160/320K IN A 1.2 MEG DRIVE
+ CMP CS:MEDIATYPE, 0
+ JNE DO_SET
+ MOV AL,3 ; 1.2MEG IN A 1.2MEG DRIVE
+ MOV CS:[GAP_PATCH],54H
+DO_SET:
+ push ds ;AN003;
+ push si ;AN003;
+;SB34IOCTL002****************************************************************
+;SB Get the disk parameter table address (dword address) from the location
+;SB 0:[DSKADR] and fix the head settle time in this to be 0fh. 4 LOCS
+
+ xor si, si
+ mov ds, si
+ lds si, dword ptr ds:[DSKADR]
+ mov ds:[si].DISK_HEAD_STTL, 0Fh
+;SB34IOCTL002****************************************************************
+ pop si ;AN003;
+ pop ds ;AN003;
+;SB33032******************************************************************
+ mov AH, 17h ; set command to Set DASD type;SB ;3.30*
+ mov DL, [di].DriveNum ; set drive number ;SB ;3.30*
+ int 13h ; call rom-bios ;SB ;3.30*
+;SB33032******************************************************************
+DASDHASBEENSET:
+ MOV AH,BYTE PTR [DI].SECLIM
+ MOV CS:[FORMT_EOT],AH
+ RET
+
+;
+; 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
+;
+AGAIN:
+ CALL RESETDISK
+
+;(deleted section here, as requested by D.L.)
+
+ DEC BP ; DECREMENT RETRY COUNT
+ RET
+
+
+; RESET THE DRIVE.
+; WE ALSO SET [STEP_DRV] TO -1 TO FORCE THE MAIN DISK ROUTINE TO USE THE
+; SLOW HEAD SETTLE TIME FOR THE NEXT OPERATION. THIS IS BECAUSE THE RESET
+; OPERATION MOVES THE HEAD TO CYLINDER 0, SO WE NEED TO DO A SEEK THE NEXT
+; TIME AROUND - THERE IS A PROBLEM WITH 3.5" DRIVES IN THAT THE HEAD DOES
+; NOT SETTLE DOWN IN TIME, EVEN FOR READ OPERATIONS!!
+;
+ PUBLIC RESETDISK
+RESETDISK:
+ SAVEREG
+;SB33033******************************************************************
+ xor AH, AH ; set command to reset disk ;SB ;3.30*
+ int 13h ; call the rom-bios ;SB ;3.30*
+;SB33033******************************************************************
+ MOV CS:[STEP_DRV],-1 ; ZAP UP THE SPEED
+ RESTOREREG
+ 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
+ TEST BYTE PTR CS:[NEW_ROM],1
+ JNZ GOT_VALID_DPT
+ PUSH AX
+ MOV DX,DS ; SAVE DS:DI-> BDS
+ XOR AX,AX
+ MOV DS,AX
+ LDS SI,DWORD PTR DS:[DSKADR] ; GET POINTER TO DISK BASE TABLE
+ MOV WORD PTR CS:[DPT],SI
+ MOV WORD PTR CS:[DPT+2],DS ; SAVE POINTER TO TABLE
+ MOV AL,CS:[FORMT_EOT]
+ MOV [SI].DISK_EOT,AL
+ MOV AL,CS:[GAP_PATCH]
+ MOV [SI].DISK_FORMT_GAP,AL ; IMPORTANT FOR FORMAT
+ MOV [SI].DISK_HEAD_STTL,15 ; ASSUME WE ARE DOING A SEEK OPERATION
+; SET UP MOTOR START CORRECTLY FOR 3.5" DRIVES.
+ PUSH ES
+ MOV ES,DX
+ CMP BYTE PTR ES:[DI].FORMFACTOR,FFSMALL ; IS IT A 3.5" DRIVE?
+ JNZ MOTORSTRTOK
+ MOV AL,4
+ XCHG AL,[SI].DISK_MOTOR_STRT
+MOTORSTRTOK:
+ POP ES
+;----------------------------------------------------------------------------
+; THE FOLLOWING TWO LINES ARE NO LONGER NECESSARY SINCE THEY ARE ONLY USEFUL
+; FOR A VERIFY OPERATION.
+; MOV AL,CS:[SECTOR_SIZ_IND]
+; MOV [SI].DISK_SECTOR_SIZ,AL ; IMPORTANT FOR VERIFY
+;----------------------------------------------------------------------------
+ MOV DS,DX ; RESTORE DS:DI-> BDS
+ POP AX
+GOT_VALID_DPT:
+;SB33034*******************************************************************
+ mov dx, cs:[trknum] ; set track number ;SB ;3.30*
+ mov ch,dl ; set low 8 bits in ch ;SB ;3.30*
+ mov DL, ds:[di].DriveNum ; set drive number ;SB ;3.30*
+ mov DH, CS:[HDNUM] ; set head number ;SB ;3.30*
+ int 13h ; call the rom-bios routines ;SB ;3.30*
+;SB33034*******************************************************************
+ 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 TO 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
+
+;******************************************************************************
+;AN000; Get Media ID
+;*******************************************************************************
+; *
+; Function: Get the volume label, the system id and the serial number from *
+; the media that has the extended boot record. *
+; For the conventional media, this routine will return "Unknown *
+; media type" error to DOS. *
+; *
+; Input : DS:DI -> BDS table for this drive. *
+; ES:BX -> Request packet (= A_Media_ID_INFO structure) *
+; *
+; Output: The request packet filled with the information, if not carry. *
+; If carry set, then AL contains the device driver error number *
+; that will be returned to DOS. *
+; Register DS,DX,AX,CX,DI,SI destroyed. *
+; Subroutines to be called: *
+; BOOT_IO:NEAR *
+; *
+; Logic: *
+; /*To recognize the extended boot record, this logic will actually */ *
+; /*access the boot sector even if it is a hard disk. */ *
+; /*NOTE:the valid extended bpb is recognized by looking at the mediabyte*
+; /*field of BPB and the extended Boot Signature. *
+; *
+; { *
+; Get logical drive number from BDS table; *
+; RFLAG = Read operation; *
+; BOOT_IO; /*Get the media boot record into the buffer*/ *
+; IF (no error) THEN *
+; IF (extended boot record) THEN *
+; { set Volume Label, Volume Serial number and System id *
+; of the Request packet to those of the boot record; *
+; }; *
+; ELSE /*Not an extended BPB */ *
+; { set Register AL to "Unknown media.." error code; *
+; set Carry bit; *
+; }; *
+; ELSE *
+; Exit; /*Already error code is set in the register AL*
+; *
+; Expected LOC: 40 (New) *
+;*******************************************************************************
+
+GetMediaID proc near ;AN000;
+ call Changeline_Chk ;AN010;
+ mov al, DS:[DI].DRIVELET ;AN000; logical drive number
+ mov cs:RFlag, ROMREAD ;AN000; read operation
+ call Boot_IO ;AN000; read boot sector into cs:DiskSector
+; $IF NC ;AN000;
+ JC $IOCTL$IF1
+ mov cl, cs:MediaByte ;AN000; Mediabyte in BPB
+ and cl, 0F0h ;AN000;
+ cmp cl, 0F0h ;AN000; Is it a valid BPB?
+; $IF E,AND ;AN000;
+ JNE $IOCTL$IF2
+ cmp cs:Ext_Boot_Sig, EXT_BOOT_SIGNATURE ;AN000; =90h
+; $IF E ;AN000; Extended Boot Record
+ JNE $IOCTL$IF2
+ push cs ;AN000;
+ pop ds ;AN000;
+ mov si, offset Boot_Serial_L ;AN000;
+ mov di, bx ;AN000;
+ add di, MI_SERIAL ;AN000;
+ mov cx, BOOT_SERIAL_SIZE+BOOT_VOLUME_LABEL_SIZE+BOOT_SYSTEM_ID_SIZE
+ rep movsb ;AN000;
+; $ELSE ;AN000;
+ JMP SHORT $IOCTL$EN2
+$IOCTL$IF2:
+ mov al, ERROR_UNKNOWN_MEDIA ;AN000; =7
+ stc ;AN000;
+; $ENDIF ;End Extended Boot Record check.
+$IOCTL$EN2:
+; $ENDIF ;Read boot sector failed. Hard error.
+$IOCTL$IF1:
+ ret ;AN000;
+GetMediaID endp
+
+;******************************************************************************
+;AN000; Set Media ID
+;*******************************************************************************
+; *
+; Function: Set the volume label, the system id and the serial number of *
+; the media that has the extended boot record. *
+; For the conventional media, this routine will return "Unknown *
+; media.." error to DOS. *
+; This routine will also set the corresponding informations in *
+; the BDS table. *
+; *
+; Input : DS:DI -> BDS table for this drive. *
+; ES:BX -> Request packet (= A_Media_ID_INFO structure) *
+; *
+; Output: The extended boot record in the media will be set according to *
+; the Request packet. *
+; If carry set, then AL contains the device driver error number *
+; that will be returned to DOS. *
+; *
+; Subroutines to be called: *
+; BOOT_IO:NEAR *
+; *
+; Logic: *
+; *
+; *
+; { *
+; Get Drive_Number from BDS; *
+; RFLAG = "Read operation"; *
+; BOOT_IO; *
+; IF (no error) THEN *
+; IF (extended boot record) THEN *
+; { set Volume Label, Volume Serial number and System id *
+; of the boot record to those of the Request packet; *
+; RFLAG = "Write operation"; *
+; Get Drive Number from BDS; *
+; BOOT_IO; /*Write it back*/ *
+; }; *
+; ELSE /*Not an extended BPB */ *
+; { set Register AL to "Unknown media.." error code; *
+; set Carry bit; *
+; Exit; /*Return back to caller */ *
+; }; *
+; ELSE *
+; Exit; /*Already error code is set */ *
+; *
+; Expected LOC: 45 (New) *
+;*******************************************************************************
+
+SetMediaID proc near
+ call Changeline_Chk ;AN010;
+ mov al, DS:[DI].DRIVELET ;AN000; logical drive number
+ mov dl, al ;AN000; save it for the time being.
+ mov cs:RFlag, ROMREAD ;AN000; read operation
+ push dx ;AN000; save drive number
+ call Boot_IO ;AN000; read boot sector into cs:DiskSector
+ pop dx ;AN000; restore drive number
+; $IF NC ;AN000;
+ JC $IOCTL$IF6
+ mov cl, cs:MediaByte ;AN000; Mediabyte in BPB
+ and cl, 0F0h ;AN000;
+ cmp cl, 0F0h ;AN000; Is it a valid BPB?
+; $IF E,AND ;AN000;
+ JNE $IOCTL$IF7
+ cmp cs:Ext_Boot_Sig, EXT_BOOT_SIGNATURE ;AN000; =41 (=29h)
+; $IF E ;AN000; Extended Boot Record
+ JNE $IOCTL$IF7
+ push ds ;AN011; save BDS pointer
+ push di ;AN011;
+ push es ;AN000;
+ pop ds ;AN000;Now DS-> Request packet
+ push cs ;AN000;
+ pop es ;AN000;Now ES -> Boot Record
+ mov di, offset Boot_Serial_L ;AN000;
+ mov si, bx ;AN000;
+ add si, MI_Serial ;AN000;
+ mov cx, BOOT_SERIAL_SIZE+BOOT_VOLUME_LABEL_SIZE+BOOT_SYSTEM_ID_SIZE
+ rep movsb ;AN000;
+ pop di ;AN011;Restore BDS pointer
+ pop ds ;AN011;
+ call Mov_Media_IDs ;AN011; Update the BDS media ID info.
+ mov al, dl ;AN000; set drive number for Boot_IO
+ mov cs:RFlag, ROMWRITE ;AN000;
+ call Boot_IO ;AN000; write it back.
+ mov cs:[TIM_DRV], -1 ;AN011; Make sure chk$media check the driver
+; $ELSE ;AN000;
+ JMP SHORT $IOCTL$EN7
+$IOCTL$IF7:
+ mov al, ERROR_UNKNOWN_MEDIA ;AN000; =7
+ stc ;AN000;
+; $ENDIF ;End Extended Boot Record check.
+$IOCTL$EN7:
+; $ENDIF ;Read boot sector failed. Hard error.
+$IOCTL$IF6:
+ ret ;AN000;
+SetMediaID endp
+
+;******************************************************************************
+;AN000; Boot_IO
+;*******************************************************************************
+; *
+; Function: Read/Write the boot record into Boot sector. *
+; *
+; Input : *
+; AL=logical drive number *
+; RFLAG = operation (read/write) *
+; *
+; Output: For read operation, the boot record of the drive specified in BDS *
+; be read into the DISKSECTOR buffer. *
+; For write operation, the DISKSECTOR buffer image will be written *
+; to the drive specified in BDS. *
+; If carry set, then AL contains the device driver error number *
+; that will be returned to DOS. *
+; AX,CX,DX register destroyed. *
+; If carry set, then AL will contain the error code from DISKIO. *
+; *
+; Subroutines to be called: *
+; DISKIO:NEAR *
+; *
+; Logic: *
+; *
+; { *
+; First_Sector = 0; /*logical sector 0 is the boot sector */ *
+; SectorCount = 1; /*read 1 sector only */ *
+; Buffer = DISKSECTOR; /*read it into the disksector buffer */ *
+; Call DISKIO (RFLAG, Drive_Number,First_Sector,SectorCount,Buffer); *
+; } *
+; Expected LOC: 6 (New) *
+;*******************************************************************************
+Boot_IO proc near ;AN000;
+ push ds ;AN000;
+ push es ;AN000;
+ push di ;AN000;
+ push bx ;AN000;
+;SB34IOCTL003**************************************************************
+;SB Call DISKIO to read/write the boot sector. The parameters which
+;SB need to be initialised for this subroutine out here are
+;SB - transfer address to cs:DiskSector
+;SB - low sector needs to be initalised to 0. This is a reg. param
+;SB - hi sector in cs:[Start_Sec_H] needs to be initialised to 0.
+;SB - number of sectors <-- 1
+;SB 7 LOCS
+
+ mov di, cs
+ mov ds, di
+ mov es, di
+ mov di, offset DiskSector ;es:di -> transfer address
+ xor dx, dx ;first sector (H) -> 0
+ mov [Start_Sec_H], dx ;start sector (H) -> 0
+ mov cx, 01 ;one sector
+ call DISKIO
+;SB34IOCTL003**************************************************************
+ pop bx ;AN000;
+ pop di ;AN000;
+ pop es ;AN000;
+ pop ds ;AN000;
+ ret ;AN000;
+Boot_IO endp ;AN000;
+
+;*******************************************************************************
+;AN010; Changeline_Chk
+;*******************************************************************************
+;When the user calls Get/Set media ID call before DOS establishes the media *
+;by calling "Media$Chk", the change line activity of the drive is going to be *
+;lost. This routine will check the change line activity and will save the *
+;history in the flags. *
+; *
+; Function: Check the change line error activity *
+; *
+; Input : DS:DI -> BDS table. *
+; *
+; Output: FLAG in BDS table will be updated if change line occurs. *
+; *
+; Subroutines to be called: *
+; SET_CHANGED_DL *
+; *
+;*******************************************************************************
+Changeline_Chk proc near ;AN010;
+ mov dl, byte ptr ds:[di].DRIVENUM ;AN010;
+ or dl, dl ;AN010;Fixed disk?
+ js Chln_Chk_Ret ;AN010;Yes, skip it.
+ cmp cs:[fHave96], 1 ;AN011;This ROM support change line?
+ jne Chln_Chk_Ret ;AN011;
+ call HasChange ;AN011;This drive support change line?
+ jz Chln_Chk_Ret ;AN011;do nothing
+;SB34IOCTL004*****************************************************************
+;SB Execute the ROM disk interrupt to check changeline activity. 2 LOCS
+
+ mov ah, 16h
+ int 13h
+;SB34IOCTL004*****************************************************************
+ jnc Chln_Chk_Ret ;AN010;no change line activity?
+ mov word ptr cs:[FLAGBITS], FCHANGED ;AN010;
+ call SET_CHANGED_DL ;AN010;Update FLAG in BDS for this physical drive
+Chln_Chk_Ret: ;AN010;
+ ret ;AN010;
+Changeline_Chk endp ;AN010;
+
+;******************************************************************************
+;AN007; GetAccessFlag
+;*******************************************************************************
+; *
+; Function: Get the status of UNFORMATTED_MEDIA bit of FLAGS in BDS table *
+; *
+; Input : *
+; es:bx -> A_DISKACCESS_CONTROL structure *
+; ds:di -> BDS table *
+; *
+; Output: A_DISKACCESS_CONTROL.DAC_ACCESS_FLAG = 0 if disk I/O not allowed. *
+; = 1 if disk I/O allowed. *
+;*******************************************************************************
+GetAccessFlag proc ;AN007;
+ test word ptr ds:[di].FLAGS, UNFORMATTED_MEDIA ;AN007;Is it unformtted media?
+ jz GAF_Allowed ;AN007;No, formatted media
+ mov es:[bx].DAC_ACCESS_FLAG, 0 ;AN007;
+ jmp short GAF_Done ;AN007;
+GAF_Allowed: ;AN007;
+ mov es:[bx].DAC_ACCESS_FLAG, 1 ;AN007;
+GAF_Done: ;AN007;
+ ret ;AN007;
+GetAccessFlag endp ;AN007;
+
+;******************************************************************************
+;AN007; SetAccessFlag
+;*******************************************************************************
+; *
+; Function: Set/Reset the UNFORMATTED_MEDIA bit of FLAGS in BDS table *
+; *
+; Input : *
+; es:bx -> A_DISKACCESS_CONTROL structure *
+; ds:di -> BDS table *
+; *
+; Output: UNFORMTTED_MEDIA bit modified according to the user request *
+;*******************************************************************************
+SetAccessFlag proc ;AN007;
+ cmp es:[bx].DAC_ACCESS_FLAG, 0 ;AN007;
+ jne SAF_Allow_Access ;AN007;
+ or word ptr ds:[di].FLAGS, UNFORMATTED_MEDIA ;AN007;
+ jmp short SAF_Done ;AN007;
+SAF_Allow_Access: ;AN007;
+ and word ptr ds:[di].FLAGS, not UNFORMATTED_MEDIA ;AN007;
+SAF_Done: ;AN007;
+ ret ;AN007;
+SetAccessFlag endp ;AN007;
+
+
\ No newline at end of file
diff --git a/v4.0/src/BIOS/MSLOAD.ASM b/v4.0/src/BIOS/MSLOAD.ASM
new file mode 100644
index 0000000..859a318
--- /dev/null
+++ b/v4.0/src/BIOS/MSLOAD.ASM
@@ -0,0 +1,1090 @@
+
+page ,132;
+title Non-Contiguous IBMBIO Loader (MSLOAD)
+;==============================================================================
+;REVISION HISTORY:
+;AN000 - New for DOS Version 4.00 - J.K.
+;AC000 - Changed for DOS Version 4.00 - J.K.
+;AN00x - PTMs for DOS Version 4.00 - J.K.
+;==============================================================================
+;AN001; - P1820 New Message SKL file 10/20/87 J.K.
+;AN002; - D381 For SYS.COM, put the version number 01/06/88 J.K.
+;==============================================================================
+;JK, 1987 -
+; For DOS 4.00, MSLOAD program has been changed to allow:
+; 1. 32 bit calculation,
+; 2. Reading a FAT sector when needed, instead of reading the whole FAT
+; sectors at once. This will make the Boot time faster, and eliminate
+; the memory size limitation problem,
+; 3. Solving the limitation of the file size (29 KB) of IBMBIO.COM,
+; 4. Adding the boot error message. Show the same boot error message
+; and do the same behavior when the read operation of IBMBIO.COM
+; failes as the MSBOOT program, since MSLOAD program is the
+; extention of MSBOOT program.
+;
+
+IF1
+ %OUT ASSEMBLING: Non-Contiguous IBMBIO Loader (MSLOAD)
+ %OUT
+
+ENDIF
+
+
+DSKADR = 1Eh * 4 ;ROM bios diskette table vector position
+
+bootseg segment at 0h
+
+
+ org 7C00h
+Boot_Sector label byte
+bootseg ends
+
+
+dosloadseg segment at 70h
+ org 00h
+IBMBIO_Address label byte
+
+dosloadseg ends
+
+
+cseg segment public para 'code'
+ assume cs:cseg,ds:nothing,es:nothing,ss:nothing
+
+include MSload.inc
+include Bootform.inc ;AN000; Extended bpb, boot record defintion.
+include versiona.inc ;AN001; Version number for SYS.COM
+
+sec9 equ 522h ;;** 8/3/87 DCL
+
+BIOOFF equ 700h
+;
+org 0h
+
+start:
+ jmp Save_Input_Values
+SYS_Version dw EXPECTED_VERSION ;AN001; From VERSIONA.INC file
+Mystacks dw 64 dup (0) ;AN000; local stack
+MyStack_ptr label word
+
+;local data
+Number_Of_Heads dw 0
+Size_Cluster dw 0
+Start_Sector_L dw 0
+Start_Sector_H dw 0 ;J.K.
+Temp_H dw 0 ;J.K. For 32 bit calculation
+Temp_Cluster dw 0 ;J.K. Temporary place for cluster number
+Last_Fat_SecNum dw -1 ;Fat sector number starting from the first fat entry.
+Sector_Count dw 0
+Number_Of_FAT_Sectors dw 0
+Hidden_Sectors_L dw 0
+Hidden_Sectors_H dw 0 ;J.K.
+Sector_Size dw 0
+Reserved_Sectors dw 0
+Last_Found_Cluster dw 0
+Next_BIO_Location dw 0
+First_Sector_L dw 0
+First_Sector_H dw 0 ;J.K.
+Drive_Lim_L dw 0 ;J.K. Max. number of sectors
+Drive_Lim_H dw 0 ;J.K.
+Sectors_Per_Track dw 0
+Drive_Number db 0
+FAT_Size db 0
+Media_Byte db 0
+EOF db 0
+Org_Rom_Disktable dd 0
+FAT_Segment dw 0
+Sectors_Per_Cluster db 0
+
+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 (low) on disk (0-based)
+; DS:SI = Original ROM BIOS DISKETTE Parameter table.
+;J.K. 6/2/87 If an extended Boot Record, then AX will be the First data sector
+;J.K. high word. Save AX and set First_Sector_H according to AX if it is an
+;J.K. extended boot record.
+; AX = First data sector (High) on disk ;
+; Output:
+;
+; BX = first data sector on disk
+;
+; Media_Byte = input CH
+; Drive_Number = input DL
+; First_Sector_L = input BX
+; First_Sector_H = input AX, if an extended Boot record.;J.K.
+; Drive_Lim_L = maximum sector number in this media ;J.K.
+; Drive_Lim_H = high word of the above
+; Hidden_Sectors_L = hidden secotrs
+; Hidden_Sectors_H
+; Reserved_Sectors = reserved sectors
+; Sectors_Per_Track = Sectors/track
+; Number_Of_Heads = heads/cylinder
+;
+; DS = 0
+; AX,DX,SI destroyed
+;
+; Calls: none
+;-----------------------------------------------------------------------
+;Function:
+; Save input information and BPB informations from the boot record.
+;
+;----------------------------------------------------------------------
+Save_Input_Values:
+
+
+ mov First_Sector_L,bx ;AC000;
+ mov media_Byte,ch
+ mov Drive_Number,dl
+ mov word ptr Org_Rom_Disktable, si
+ push ds
+ pop word ptr Org_Rom_Disktable+2
+ xor cx,cx ;Segment 0
+ mov ds,cx
+ assume ds:Bootseg
+
+ push es ;;** DCL 8/3/87
+ mov es,cx ;;** DCL 8/3/87
+ assume es:Bootseg ;;** DCL 8/3/87
+
+ 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,11 ; taken from ibmboot.asm ARR 2.41
+ CLD ;
+ 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
+ pop es ;;** DCL 8/3/87
+ assume es:nothing
+
+ mov cx,Boot_Sector.EXT_BOOT_BPB.EBPB_BYTESPERSECTOR ;AN000;
+ mov cs:Sector_Size, cx ;AN000;
+ mov cl,Boot_Sector.EXT_BOOT_BPB.EBPB_SECTORSPERCLUSTER ;AN000;
+ mov cs:Sectors_Per_Cluster, cl ;AN000;
+ mov cx,Boot_Sector.EXT_BOOT_BPB.EBPB_SECTORSPERTRACK ;Get Sectors per track
+ mov cs:Sectors_Per_Track,cx
+ mov cx,Boot_Sector.EXT_BOOT_BPB.EBPB_HEADS ;Get BPB heads per cylinder
+ mov cs:Number_Of_Heads,cx
+ mov cx,Boot_Sector.EXT_BOOT_BPB.EBPB_SECTORSPERFAT ;Get sectors per FAT
+ mov cs:Number_Of_FAT_Sectors,cx
+ mov cx,Boot_Sector.EXT_BOOT_BPB.EBPB_RESERVEDSECTORS ;Get Reserved Sectors
+ mov cs:Reserved_Sectors,cx
+ mov cx,word ptr Boot_Sector.EXT_BOOT_BPB.EBPB_HIDDENSECTOR ;Get hidden sectors
+ mov cs:Hidden_Sectors_L,cx
+ mov cx, Boot_Sector.EXT_BOOT_BPB.EBPB_TOTALSECTORS ;AN000;
+ mov cs:Drive_Lim_L, cx ;AN000;
+
+;J.K. First of all, check if it the boot record is an extended one.
+;J.K. This is just a safe guard in case some user just "copy" the 4.00 IBMBIO.COM
+;J.K. to a media with a conventional boot record.
+
+ cmp Boot_Sector.EXT_BOOT_SIG, EXT_BOOT_SIGNATURE ;AN000;
+ jne Relocate ;AN000;
+ mov cs:First_Sector_H, AX ;AN000; start data sector (high)
+ mov ax,word ptr Boot_Sector.EXT_BOOT_BPB.EBPB_HIDDENSECTOR+2 ;AN000;
+ mov cs:Hidden_Sectors_H,ax ;AN000;
+ cmp cx, 0 ;AN000; CX set already before (=Totalsectors)
+ jne Relocate ;AN000;
+ mov ax, word ptr Boot_Sector.EXT_BOOT_BPB.EBPB_BIGTOTALSECTORS ;AN000;
+ mov cs:Drive_Lim_L, ax ;AN000;
+ mov ax, word ptr Boot_Sector.EXT_BOOT_BPB.EBPB_BIGTOTALSECTORS+2 ;AN000;
+ mov cs:Drive_Lim_H, ax ;AN000;
+subttl Relocate
+page
+;
+;***********************************************************************
+; RELOCATE
+;***********************************************************************
+;
+; Notes:
+;
+; Relocate the loader code to top-of-memory.
+;
+; Input: none
+;
+; Output: Code and data relocated.
+; ax,cx,si,di destroyed
+;
+; Calls: none
+;-----------------------------------------------------------------------
+; Copy code from Start to Top of memory.
+;
+; The length to copy is Total_length
+;
+; Jump to relocated code
+;-----------------------------------------------------------------------
+;
+Relocate:
+ assume ds:nothing
+ cld ;AN000;
+ xor si,si ;AN000;
+ mov di,si ;AN000;
+;SB34LOAD000****************************************************************
+;SB Determine the number of paragraphs (16 byte blocks) of memory.
+;SB This involves invoking the memory size determination interrupt,
+;SB which returns the number of 1K blocks of memory, and then
+;SB converting this to the number of paragraphs.
+;SB Leave the number of paragraphs of memory in AX.
+
+ int 12h ;get system memory size in Kbytes
+ mov cl,6 ;
+ shl ax,cl ;memory size in paragraphs
+;SB34LOAD000****************************************************************
+ mov cl,4 ;AN000;
+ mov dx, cs:Sector_Size ;AN000;
+ shr dx,cl ;AN000;
+ inc dx ;AN000;
+ sub ax, dx ;AN000;
+ mov cs:Fat_Segment, ax ;AN000;This will be used for FAT sector
+ mov dx, offset total_length ;AN000;
+ shr dx, cl ;AN000;
+ inc dx ;AN000;
+ sub ax, dx ;AN000;
+ mov es, ax ;AN000;es:di -> place be relocated.
+ push cs ;AN000;
+ pop ds ;AN000;ds:si -> source
+ mov cx, offset total_length ;AN000;
+ rep movsb ;AN000;
+
+ push es ;AN000;
+ mov ax, offset Setup_stack ;AN000;
+ push ax ;AN000;massage stack for destination of cs:ip
+Dumbbb proc far ;AN000;
+ ret ;AN000;
+Dumbbb endp ;AN000;
+
+
+; 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 Start ;Source
+; mov di,offset Relocate_Start ;Target
+; mov cx,Relocate_Length ;Length
+; rep movsb ;Go do it
+; jmp far ptr Relocate_Start
+
+
+
+subttl Setup Stack
+page
+;***********************************************************************
+; Setup_Stack
+;***********************************************************************
+;
+; Input: none
+;
+; Output:
+;
+; SS:SP set
+; 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
+;----------------------------------------------------------------------
+
+Setup_Stack:
+ assume ds:nothing, es:nothing, ss:nothing
+; CLI ;Stop interrupts till stack ok
+ mov ax,cs
+ MOV SS,AX ;Set up the stack to the known area.
+ mov sp, offset MyStack_Ptr
+; MOV SP,7C00h - 50 ;Leave room for stack frame
+; MOV BP,7C00h - 50 ;Point BP as stack index pointer
+; STI
+
+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.EXT_BOOT_BPB.EBPB_BYTESPERSECTOR ;AC000;Get BPB bytes/sector
+ xor bx,bx
+ mov bl,Boot_Sector.EXT_BOOT_BPB.EBPB_SECTORSPERCLUSTER ;AC000;Get sectors/cluster
+ mul bx ;Bytes/cluster
+ mov cs: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:
+;
+; Output:
+;
+; cs:Fat_Size = FAT12_bit or FAT16_bit
+; All other registers destroyed
+;
+;----------------------------------------------------------------------
+Determine_FAT_Size:
+ mov cs:FAT_Size,FAT12_bit ;AN000;Assume 12 bit fat
+ mov dx, cs:Drive_Lim_H ;AN000;
+ mov ax, cs:Drive_Lim_L ;AN000;
+ sub ax, cs:Reserved_Sectors ;AN000;
+ sbb dx, 0 ;AN000;now, dx;ax = available total sectors
+ mov bx, cs:Number_Of_FAT_Sectors ;AN000;
+ shl bx, 1 ;AN000;2 FATs
+ sub ax, bx ;AN000;
+ sbb dx, 0 ;AN000;now, dx;ax = tatal sectors - fat sectors
+ mov bx, Boot_Sector.EXT_BOOT_BPB.EBPB_ROOTENTRIES ;AN000;
+ mov cl, 4 ;AN000;
+ shr bx, cl ;AN000;Sectors for dir entries = dir entries / Num_DIR_Sector
+ sub ax, bx ;AN000;
+ sbb dx, 0 ;AN000;
+ xor cx, cx ;AN000;
+ mov cl, Boot_Sector.EXT_BOOT_BPB.EBPB_SECTORSPERCLUSTER ;AN000;
+ push ax ;AN000;
+ mov ax, dx ;AN000;
+ xor dx, dx ;AN000;
+ div cx ;AN000;
+ mov cs:Temp_H, ax ;AN000;
+ pop ax ;AN000;
+;J.K. We assume that cx > dx.
+ div cx ;AN000;
+ cmp ax, 4096-10 ;AN000;
+; jb Determine_First_Cluster ;AN000;
+ jb Read_In_FirstClusters
+ mov cs:FAT_Size, FAT16_Bit ;AN000;16 bit fat
+
+; cmp cs:Media_Byte,0F8h ;Is it floppy
+; jne FAT_Size_Found ;Yep, all set
+; mov cs:Logical_Sector,0 ;Got hardfile, go get MBR
+; xor ax,ax
+; mov es,ax
+; mov di,offset Relocate_Start
+; mov cs: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 cs:FAT_Size,FAT12_bit ;Assume 12 bit fat
+; cmp byte ptr [si],1
+; je FAT_Size_Found
+; mov cs: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 Read_In_FirstClusters
+page
+;***********************************************************************
+; Read_In_FirstClusters
+;***********************************************************************
+;
+; Notes: Read the start of the clusters that covers at least IBMLOADSIZE
+; fully. For example, if sector/cluster = 2, and IBMLOADSIZE=3
+; then we are going to re-read the second cluster to fully cover
+; MSLOAD program in the cluster boundary.
+;
+; Input:
+; IBMLOADSIZE - Make sure this value is the same as the one in
+; MSBOOT program when you build the new version!!!!!
+;
+; Sectors_Per_Cluster
+; Size_Cluster
+; First_Sector_L
+; First_Sector_H
+;
+; Output: MSLOAD program is fully covered in a cluster boundary.
+; AX = # of clusters we read in so far.
+;
+; Calls: Disk_Read
+; Logic:
+; AX; DX = IBMLOADSIZE / # of sector in a cluster.
+; if DX = 0 then Ok. (MSLOAD is in a cluster boundary.)
+; else (Has to read (AX+1)th cluster to cover MSLOAD)
+; read (AX+1)th cluster into the address after the clusters we
+; read in so far.
+;-----------------------------------------------------------------------
+
+Read_In_FirstClusters:
+ mov ax, IBMLOADSIZE ;AN000;
+ div cs:Sectors_Per_Cluster ;AN000;
+ cmp ah, 0 ;AN000;
+ je Set_Next_Cluster_Number ;AN000;
+ xor ah, ah ;AN000;
+ push ax ;AN000;
+ mov cx, cs:First_Sector_L ;AN000;
+ mov cs:Start_Sector_L, cx ;AN000;
+ mov cx, cs:First_Sector_H ;AN000;
+ mov cs:Start_Sector_H, cx ;AN000;
+ mul cs:Sectors_Per_Cluster ;AN000; Now, AX=# of sectors
+ add cs:Start_Sector_L, ax ;AN000;
+ adc cs:Start_Sector_H, 0 ;AN000;
+ pop ax ;AN000;
+ push ax ;AN000;
+ mov di, BIOOFF ;AN000;
+ mul cs:Size_Cluster ;AN000;AX = # of bytes read in before this cluster
+ add di, ax ;AN000;
+ xor ax, ax ;AN000;
+ mov es, ax ;AN000;
+ mov al, cs:Sectors_Per_Cluster ;AN000;
+ mov cs:Sector_Count, ax ;AN000;
+ call Disk_Read ;AN000;
+ pop ax ;AN000;
+ inc ax ;AN000;# of clusters read in so far.
+
+subttl Set_Next_Cluster_Number
+page
+;***********************************************************************
+; Set_Next_Cluster_Number
+;***********************************************************************
+;
+; Notes: Set LAST_Found_Cluster for the next use.
+; Last_Found_Cluster is the cluster number we are in now.
+; Since cluster number is 0 based and there are 2 clusters int
+; the beginning of FAT table used by the system, we just add
+; 1 to set Last_Found_Cluster.
+;
+; Input:
+; AX = # of clusters read in so far.
+;
+; Output:
+;
+; cs:Last_Found_Cluster
+;
+; Calls: none
+;------------------------------------------------------------------
+Set_Next_Cluster_Number:
+ inc ax ;AN000; For Last_Found_Cluster
+ mov cs:Last_Found_Cluster,ax ;2 is the first data cluster number(0 based)
+
+subttl Read In FAT
+page
+;***********************************************************************
+; Read_In_FAT
+;***********************************************************************
+;
+; Notes:
+;
+; Reads in the entire FAT at 800:0. This gives the relocated portion
+; of this loader a maximum size of 768 bytes (8000 - 7D00).
+; With 64 KB memory system, this can support maximum size of FAT to
+; be 32 KB. We assumes that the system memory size be 128 KB, if
+; the system has a big media with the total fat size bigger than
+; 32 KB.
+;
+; Input: none
+;
+; Output:
+;
+; ES = 0
+; All sectors destroyed
+;
+; Calls: READ DISK
+;-----------------------------------------------------------------------
+; Get number of sectors in FAT
+;
+; Set ES:DI to 800:0
+;
+; Read in the sectors
+;
+;----------------------------------------------------------------------
+;Read_In_FAT:
+; mov ax,cs:Number_Of_FAT_Sectors ;Get sectors/FAT
+; mov cs:Sector_Count,ax ;Number of sectors to read
+; mov ax,cs:Hidden_Sectors_L ;Hidden+Reserved = start of FAT sector
+; mov dx,cs:Hidden_Sectors_H ;AN000;
+; add ax,cs:Reserved_Sectors
+; adc dx, 0
+; mov cs:Start_Sector_L,ax ;AC000;Save it, setup for disk read
+; mov cs:Start_Sector_H,dx ;AN000;
+; mov di, 800h ;AC000;
+; mov es, di ;AC000;
+; xor di, di ;AC000;
+; assume es:nothing
+; call Disk_Read
+;
+subttl Keep Loaded BIO
+page
+;***********************************************************************
+; KEEP LOADED BIO
+;***********************************************************************
+;
+; Notes:
+;
+; Determine how much of IBMBIO was loaded in when the loader was loaded
+; by the boot record (only the portion that is guaranteed to be contiguous)
+;
+; Input:
+;
+; cs:Last_Found_Cluster = number of clusters used for loader+2
+;
+; Output:
+; ES=70h
+; DI = Next offset to load IBMBIO code
+; AX,BX,CX,DX,SI destroyed
+;
+; cs:Next_BIO_Location = DI on output
+; cs:Last_Cluster = last cluster loaded
+;
+; Calls: none
+;-----------------------------------------------------------------------
+;Number of clusters loaded+2 is in cs:Last_Found_Cluster
+;
+;Multiply cluster * cluster size in bytes to get total loaded for MSLOAD
+;
+;Subtract TOTAL_LOADED - LOADBIO_SIZE to get loaded IBMBIO in last cluster
+;
+;Relocate this piece of IBMBIO down to 70:0
+;
+;----------------------------------------------------------------------
+Keep_Loaded_BIO:
+ push ds
+ mov ax,cs:Last_Found_Cluster ;Point to last cluster loaded
+ sub ax,1 ;Get number of clusters loaded
+ mul cs:Size_Cluster ;Get total bytes loaded by
+ ;This is always < 64k, so
+ ;lower 16 bits ok
+ sub ax,LoadBio_Size ;Get portion of IBMBIO loaded
+ mov cx,ax ;Save length to move
+ mov ax,70h ;Segment at 70h
+ mov ds,ax
+ mov es,ax
+ mov si,offset Total_Length ;Point at IBMBIO
+ mov di,0 ;Point at 70:0
+ rep movsb ;Relocate this code
+ mov cs: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:
+;
+; cs:Next_BIO_Location
+; cs:
+;
+;
+; Output:
+;
+;
+; Calls: Get_Next_FAT_Entry
+;-----------------------------------------------------------------------
+;
+;Set cs: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 cs:Sector_Count
+;
+; Call Check_For_EOF
+;
+; IF (NC returned)
+;
+;
+;----------------------------------------------------------------------
+Get_Contiguous_Cluster:
+ xor ah,ah
+ mov al,cs:Sectors_Per_Cluster ;Assume we will get one cluster
+ mov cs:Sector_Count,ax
+ push cs:Sector_Count
+ call Get_Next_Fat_Entry ;Go get it in AX
+ pop cs:Sector_Count
+ mov cs:Last_Found_Cluster,ax ;Update the last one found
+ cmp cs:EOF,END_OF_FILE
+ je GO_IBMBIO
+
+; je GOTO_IBMBIO
+;Got_Contig_Clusters:
+
+ xor dx,dx ;AN000;
+ sub ax,2 ;Zero base the cluster
+ xor ch,ch
+ mov cl,cs:Sectors_Per_Cluster ;Get sectors per cluster
+ mul cx ;Get how many
+ add ax,cs:First_Sector_L ;AC000;See where the data sector starts
+ adc dx,cs:First_Sector_H ;AN000;
+ mov cs:Start_Sector_L,ax ;AC000;Save it
+ mov cs:Start_Sector_H,dx ;AN000;
+ mov di,cs:Next_Bio_Location ;Get where to put code
+ push cs:Sector_Count ;Save how many sectors
+ mov ax,dosloadseg ;Get area to load code
+ mov es,ax
+ call Disk_Read
+ pop ax ;Get back total sectors read in
+; jc ##########
+ mul cs:Sector_Size ;AC000;Get number of bytes we loaded
+; mul Boot_Sector.ByteSec
+ add cs:Next_Bio_Location,ax ;Point to where to load next
+ jmp Get_Contiguous_Cluster
+
+subttl GOTO IBMBIO
+page
+;***********************************************************************
+; GOTO_IBMBIO
+;***********************************************************************
+;
+; Notes:
+;
+; Set up required registers for IBMBIO, then jump to it (70:0)
+;
+; Input: none
+;
+; cs:Media_Byte = media byte
+; cs:Drive_Number = INT 13 drive number we booted from
+; cs:First_Sector_L = First data sector on disk (Low) (0-based)
+; cs:First_Sector_H = First data sector on disk (High)
+;
+; Output:
+;
+; Required by MSINIT
+; DL = INT 13 drive number we booted from
+; CH = media byte
+; BX = First data sector on disk (0-based)
+; AX = First data sector on disk (High)
+; DI = Sectors/FAT for the boot media.
+;
+; Calls: none
+;-----------------------------------------------------------------------
+;
+; Set up registers for MSINIT then do Far Jmp
+;
+;----------------------------------------------------------------------
+GO_IBMBIO:
+ mov ch,cs:Media_Byte ;Restore regs required for MSINT
+ mov dl,cs:Drive_Number ;Physical Drive number we booted from.
+ mov bx,cs:First_Sector_L ;AC000;
+ mov ax,cs:First_Sector_H ;AN000; AX will be the First data sector (High)
+;J.K. Don't need this information any more.
+; mov di,cs:Number_Of_FAT_Sectors ;AN000
+ jmp far ptr IBMBIO_Address
+
+
+subttl Disk Read
+page
+;***********************************************************************
+; Disk_Read
+;***********************************************************************
+;
+; Notes:
+;
+; Read in the cs:Sector_Count number of sectors at ES:DI
+;
+;
+; Input: none
+;
+; DI = Offset of start of read
+; ES = Segment of read
+; cs:Sector_Count = number of sectors to read
+; cs:Start_sector_L = starting sector (Low)
+; cs:Start_sector_H = starting sector (High)
+; Following is BPB info that must be setup prior to call
+; cs:Number_Of_Heads
+; cs:Number_Of_Sectors
+; cs:Drive_Number
+; cs:Sectors_Per_Track
+;
+; Output:
+;
+; AX,BX,CX,DX,SI,DI destroyed
+;-----------------------------------------------------------------------
+; 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,cs:Start_Sector_L ;AC000; Get starting sector
+ mov dx, cs:Start_Sector_H ;AN000;
+; XOR DX,DX
+ push ax ;AN000;
+ mov ax, dx ;AN000;
+ xor dx, dx ;AN000;
+ DIV word ptr cs:Sectors_Per_Track
+ mov cs:Temp_H, ax ;AN000;
+ pop ax ;AN000;
+ div word ptr cs:Sectors_Per_Track ;AN000;[temp_h];AX = track, DX = sector number
+ MOV bx,cs:Sectors_Per_Track ;Get number of sectors we can read in
+ sub bx,dx ;this track
+ mov si,bx
+ cmp cs:Sector_Count,si ;Is possible sectors in track more
+ jae Got_Length ;than what we need to read?
+ mov si,cs: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
+ mov dx, cs:Temp_H ;AN000;now, dx;ax = track
+; XOR DX, DX
+ push ax ;AN000;
+ mov ax, dx ;AN000;
+ xor dx, dx ;AN000;
+ DIV word ptr cs:Number_Of_Heads ;Start cyl in ax,head in DL
+ mov cs:Temp_h, ax ;AN000;
+ pop ax ;AN000;
+ div word ptr cs:Number_of_Heads ;AN000;now [temp_h];AX = cyliner, dx = head
+;J.K. At this moment, we assume that Temp_h = 0, AX <= 1024, DX <= 255
+ MOV DH,DL
+;
+; Issue one read request. ES:BX have the transfer address, AL is the number
+; of sectors.
+;
+ MOV CL,6
+ SHL AH,CL ;Shift cyl high bits up
+ OR AH,BL ;Mix in with sector bits
+ MOV CH,AL ;Setup Cyl low
+ MOV CL,AH ;Setup Cyl/high - Sector
+ mov bx,di ;Get back offset
+ MOV DL,cs:Drive_Number ;Get drive
+ mov ax,si ;Get number of sectors to read (AL)
+
+ MOV AH,2 ;Read
+ push ax ;Save length of read
+ push di
+; Issue one read request. ES:BX have the transfer address, AL is the number
+; of sectors.
+ INT 13H
+ pop di
+ pop ax
+ pop cx ;Get retry count back
+ jnc Read_OK
+ mov bx,di ;Get offset
+ xor ah,ah
+ push cx
+ mov dl,cs:Drive_Number
+ push di
+ int 13h
+ pop di
+ pop cx
+; loop Try_Read ;AC000;
+ ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx error
+ dec cx ;AN000;
+ jz Read_Error ;AN000;
+ jmp Try_Read ;AN000;
+Read_Error: ;AN000;
+ jmp ErrorOut ;AN000;
+
+Read_OK:
+ xor ah,ah ;Mask out read command, just get # read
+ sub cs:Sector_Count,ax ;Bump number down
+ jz Read_Finished
+ add cs:Start_Sector_L,ax ;AC000;Where to start next time
+ adc cs:Start_Sector_H, 0 ;AN000;
+ xor bx,bx ;Get number sectors read
+ mov bl,al
+ mov ax,cs:Sector_Size ;Bytes per sector
+ mul bx ;Get total bytes read
+ add di,ax ;Add it to offset
+ jmp 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
+; IBMBIO. If the last cluster is (F)FF8 - (F)FFF, then the final cluster
+; of IBMBIO has been loaded, and control is passed to GOTO_IBMBIO
+; MSLOAD can handle maximum FAT area size of 64 KB.
+;
+; Input:
+;
+; cs:Last_Found_Cluster
+; cs:Fat_Size
+;
+; Output:
+;
+; cs:Last_Found_Cluster (updated)
+;
+; Calls: Get_Fat_Sector
+;-----------------------------------------------------------------------
+; Get Last_Found_Cluster
+;
+; IF (16 bit FAT)
+; {IF (Last_Found_Cluster = FFF8 - FFFF)
+; {JMP GOTO_IBMBIO}
+; ELSE
+; {Get offset by multiply cluster by 2}
+;
+; ELSE
+; {IF (Last_Found_Cluster = FF8 - FFF)
+; {JMP GOTO_IBMBIO}
+; 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}
+; }
+; }
+;
+;
+;----------------------------------------------------------------------
+Get_Next_FAT_Entry:
+
+ push es ;AN000;
+ mov ax, cs:FAT_Segment ;AN000;
+ mov es, ax ;AN000; es-> Fat area segment
+ assume es:nothing
+
+ mov cs:EOF,End_Of_File ;Assume last cluster
+ mov ax,cs:Last_Found_Cluster ;Get last cluster
+ cmp cs:Fat_Size,FAT12_bit
+ jne Got_16_Bit
+ mov si, ax ;AN000;
+ shr ax, 1 ;AN000;
+ add si, ax ;AN000; si = ax*1.5 = ax+ax/2
+ call Get_Fat_Sector ;AN000;
+ jne Ok_cluster ;AN000;
+ mov al, byte ptr es:[bx] ;AN000;
+ mov byte ptr cs:Temp_cluster, al ;AN000;
+ inc si ;AN000;
+ call Get_Fat_Sector ;AN000;read next FAT sector
+ mov al, byte ptr es:[0] ;AN000;
+ mov byte ptr cs:Temp_cluster+1, al ;AN000;
+ mov ax, cs:Temp_cluster ;AN000;
+ jmp short Even_Odd ;AN000;
+Ok_cluster: ;AN000;
+ mov ax, es:[bx] ;AN000;
+Even_Odd: ;AN000;
+
+; 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 cs: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 ;AN000;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
+ call Get_Fat_Sector ;AN000;
+ mov ax, es:[bx] ;AN000;
+; mov ax,[si]+8000h ;Get new cluster
+ cmp ax,0FFF8h
+ jae Got_Cluster_Done
+
+Not_Last_Cluster:
+ mov cs:EOF,not END_OF_FILE ;Assume last cluster
+
+Got_Cluster_Done:
+ pop es
+ ret
+
+
+Get_Fat_Sector proc near
+;Function: Find and read the corresponding FAT sector into ES:0
+;In). SI = offset value (starting from FAT entry 0) of FAT entry to find.
+; ES = FAT sector segment
+; cs:Sector_Size
+;Out). Corresponding FAT sector read in.
+; BX = offset value of the corresponding FAT entry in the FAT sector.
+; CX destroyed.
+; Zero flag set if the FAT entry is splitted, i.e. when 12 bit FAT entry
+; starts at the last byte of the FAT sector. In this case, the caller
+; should save this byte, and read the next FAT sector to get the rest
+; of the FAT entry value. (This will only happen with the 12 bit fat).
+
+ push ax ;AN000;
+ push si ;AN000;
+ push di ;AN000;
+ push dx ;AN000;
+ xor dx, dx ;AN000;
+ mov ax, si ;AN000;
+ mov cx, cs:Sector_Size ;AN000;
+ div cx ;AN000;ax = sector number, dx = offset
+ cmp ax, cs:Last_Fat_SecNum ;AN000;the same fat sector?
+ je GFS_Split_Chk ;AN000;don't need to read it again.
+ mov cs:Last_Fat_SecNum, ax ;AN000;
+ push dx ;AN000;
+ xor dx, dx ;AN000;
+ add ax, cs:Hidden_Sectors_L ;AN000;
+ adc dx, cs:Hidden_Sectors_H ;AN000;
+ add ax, cs:Reserved_Sectors ;AN000;
+ adc dx, 0 ;AN000;
+ mov cs:Start_Sector_L, ax ;AN000;
+ mov cs:Start_Sector_H, dx ;AN000;set up for Disk_Read
+ mov cs:Sector_Count, 1 ;AN000;1 sector
+ xor di, di ;AN000;
+ call Disk_Read ;AN000;
+ pop dx ;AN000;
+ mov cx, cs:Sector_Size ;AN000;
+GFS_Split_Chk: ;AN000;
+ dec cx ;AN000;now, cx= sector size - 1
+ cmp dx, cx ;AN000;if the last byte of the sector, then splitted entry.
+ mov bx, dx ;AN000;Set BX to DX
+ pop dx ;AN000;
+ pop di ;AN000;
+ pop si ;AN000;
+ pop ax ;AN000;
+ ret ;AN000;
+Get_Fat_Sector endp ;AN000;
+
+
+Errorout: ;AN000;
+ push cs ;AN000;
+ pop ds ;AN000;
+ mov si, offset Sysmsg ;AN000;
+ call write ;AN000;
+;SB34LOAD001****************************************************************
+;SB Wait for a keypress on the keyboard. Use the BIOS keyboard interrupt.
+;SB 2 LOCS
+
+ xor ah,ah
+ int 16h ;read keyboard
+;SB34LOAD001****************************************************************
+
+;SB34LOAD002****************************************************************
+;SB We have to restore the address of the original rom Disk parameter table
+;SB to the location at [0:DSKADR]. The address of this original table has been
+;SB saved previously in 0:Org_Rom_DiskTable and 0:Org_Rom_Disktable+2.
+;SB After this table address has been restored we can reboot by
+;SB invoking the bootstrap loader BIOS interrupt.
+
+ xor bx, bx
+ mov ds, bx
+ les bx, dword ptr ds:Org_Rom_DiskTable
+ mov si, DSKADR
+ mov word ptr ds:[si], bx ;restore offset
+ mov word ptr ds:[si+2], es ;restore segment
+ int 19h ;reboot
+;SB34LOAD002****************************************************************
+
+Write proc near ;show error messages
+;In) DS:SI -> ASCIIZ string.
+
+ lodsb ;AN000;
+ or al, al ;AN000;
+ jz Endwr ;AN000;
+;SB34LOAD003****************************************************************
+;SB Write the character in al to the screen.
+;SB Use Video service 'Write teletype to active page' (ROM_TELETYPE)
+;SB Use normal character attribute
+ mov ah, ROM_TELETYPE
+ mov bl, 7 ;"normal" attribute ?
+ int 10h ;video write
+;SB34LOAD003****************************************************************
+ jmp Write ;AN000;
+Endwr: ;AN000;
+ ret ;AN000;
+Write endp
+;
+
+;include MSbtmes.inc ;AN000;
+include MSbio.cl1 ;AN001;
+
+Relocate_Length equ $ - start
+Total_Length label byte
+LoadBIO_Size equ $ - Start
+
+cseg ends
+ end start
diff --git a/v4.0/src/BIOS/MSLOAD.INC b/v4.0/src/BIOS/MSLOAD.INC
new file mode 100644
index 0000000..1f8d73c
--- /dev/null
+++ b/v4.0/src/BIOS/MSLOAD.INC
@@ -0,0 +1,7 @@
+;MSLOAD.INC
+End_Of_File equ 0FFh
+FAT12_Bit equ 01h
+FAT16_Bit equ 04h
+ROM_TELETYPE equ 14 ;INT 10h, Teletype function
+
+NUM_DIR_PER_SECTOR equ 16 ; number of directory entries per sector
diff --git a/v4.0/src/BIOS/MSLPT.ASM b/v4.0/src/BIOS/MSLPT.ASM
new file mode 100644
index 0000000..ad858a0
--- /dev/null
+++ b/v4.0/src/BIOS/MSLPT.ASM
@@ -0,0 +1,270 @@
+ PAGE ,132 ;
+ TITLE MSLPT - BIOS
+ %OUT ...MSLPT.ASM
+
+;==============================================================================
+;REVISION HISTORY:
+;AN000 - New for DOS Version 4.00 - J.K.
+;AC000 - Changed for DOS Version 4.00 - J.K.
+;AN00x - PTM number for DOS Version 4.00 - J.K.
+;==============================================================================
+;AN001 - P156 KBMLPT device driver's retry logic. 8/18/87 J.K.
+;==============================================================================
+ itest=0
+ INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT
+ INCLUDE MSEQU.INC
+ INCLUDE MSMACRO.INC
+ INCLUDE DEVSYM.INC
+ INCLUDE IOCTL.INC
+
+ EXTRN BUS$EXIT:NEAR ;MSBIO1
+ EXTRN ERR$CNT:NEAR ;MSBIO1
+ EXTRN CMDERR:NEAR ;MSBIO1
+ EXTRN GETDX:NEAR ;MSBIO1
+ EXTRN EXIT:NEAR ;MSBIO1
+ EXTRN ERR$EXIT:NEAR ;MSBIO1
+;DATA
+ EXTRN PTRSAV:DWORD ;MSBIO1
+ EXTRN TIMDEV:WORD ;MSCLOCK
+ EXTRN LPT2DEV:WORD ;MSBIO2
+ EXTRN WAIT_COUNT:WORD ;MSDATA
+ EXTRN PRINTDEV:BYTE ;MSDATA
+; IBM ROM STATUS BITS (I DON'T TRUST THEM, NEITHER SHOULD YOU)
+
+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.
+
+
+; WARNING!!! THE IBM ROM DOES NOT RETURN JUST ONE BIT. IT RETURNS A
+; WHOLE SLEW OF BITS, ONLY ONE OF WHICH IS CORRECT.
+
+;----------------------------------------------------------
+;J.K. AN001; PRN$WRIT will retry only if error code is TIMEOUT.
+
+; WRITE TO PRINTER DEVICE
+
+; CX HAS COUNT OF BYTES
+; ES:DI POINT TO DESTINATION
+; AUXNUM HAS PRINTER NUMBER
+
+ PUBLIC PRN$WRIT
+PRN$WRIT PROC NEAR
+ ASSUME DS:CODE ; SET BY PRINTER DEVICE DRIVER ENTRY
+
+ jcxz Prn$Done ;No char to output
+Prn$Loop:
+ mov bx, 2 ;Initialize retry count
+Prn$Out:
+;SB34LPT000****************************************************************
+;SB Print the character at ES:[DI]
+;SB Call the function PrnOP to do this
+;SB The character to be printed goes in AL and the function code
+;SB for 'Output character' goes in AH
+;SB Check for error in printing.
+;SB If there is no error go to print the next character.
+;SB If there is an error indicated see if it is due to TIMEOUT. If the
+;SB error is not TIMEOUT then we can do nothing about it. Just go to
+;SB print the next character. If it is due to timeout we can execute
+;SB the code to retry the print which follows this piece of code
+;SB LOCS: 6
+
+ mov al,es:[di] ; assume AX disposible since enter
+ xor ah,ah ; via int 21h
+ call PrnOp ; print to printer
+ jz Prn$Con ; no error - continue
+ test ah,TIMEOUTSTATUS
+ jz Prn$Con ; NOT time out - continue
+
+;SB34LPT000****************************************************************
+ dec bx ;Retry until count is exhausted.
+ jnz Prn$Out ;Retry it.
+ jmp short Pmessg ;Return with error.
+ ;
+ ; next character
+ ;
+Prn$Con:
+ inc di ;point to next char and continue
+ loop Prn$Loop
+Prn$Done:
+ jmp Exit
+Pmessg:
+ jmp Err$Cnt
+PRN$WRIT endp
+
+; JCXZ EXVEC3 ; NO CHARS TO OUTPUT..
+;PRN$LOOP:
+; MOV BX,2 ; INITIALIZE RETRY FLAG
+;PRN$OUT:
+; MOV AL,ES:[DI] ; GET CHAR INTO AL
+; INC DI ; POINT TO NEXT CHAR
+; XOR AH,AH ; AH=0 => OUTPUT CHAR IN DL
+; CALL PRNOP ; TO INDICATE PRINT CHAR IN AL
+; JNZ PRRETRY
+; LOOP PRN$LOOP
+;EXVEC3:
+; JMP EXIT
+;PRRETRY:
+; DEC DI ; UNDO THE INC ABOVE...
+; DEC BX
+; JNZ PRN$OUT
+;PMESSG:
+; JMP ERR$CNT ;RETURN WITH THE ERROR
+;PRN$WRIT ENDP
+
+;--------------------------------------------------------
+
+; PRINTER STATUS ROUTINE
+
+ PUBLIC PRN$STAT
+PRN$STAT PROC NEAR
+ ASSUME DS:CODE ; SET BY PRINTER DEVICE DRIVER ENTRY
+
+ CALL PRNSTAT ;DEVICE IN DX
+ JNZ PMESSG ; OTHER ERRORS WERE FOUND
+;J.K. The next three lines are commented out, since it is a dead code.
+; MOV AL,9 ; AGAIN, ASSUME OUT OF PAPER...
+; TEST AH,NOPAPERSTATUS
+; JNZ PMESSG
+ TEST AH,NOTBUSYSTATUS
+ jnz Prn$Done ;No error. Exit
+ JMP BUS$EXIT
+PRN$STAT ENDP
+
+; TAKE THE APPROPRIATE PRINTER AND DO THE OPERATION. TRIAGE THE STATUS
+; RETURNED IN AH INTO SOME MEANINGFUL ERROR.
+
+PRNSTAT PROC NEAR
+;SB33037**********************************************************************
+ mov AH, 2 ; set command for get status ;SB ;3.30*
+PRNOP: ;SB ;3.30*
+ call GETDX ; determine which printer ;SB ;3.30*
+ int 17h ; call ROM-BIOS printer routine ;SB;3.30*
+
+;SB33037**********************************************************************
+
+; EXAMINE THE STATUS BITS TO SEE IF AN ERROR OCCURRED. UNFORTUNATELY, SEVERAL
+; OF THE BITS ARE SET SO WE HAVE TO PICK AND CHOOSE. WE MUST BE EXTREMELY
+; CAREFUL ABOUT BREAKING BASIC.
+
+ TEST AH,IOERRSTATUS ; I/O ERROR?
+ JZ CHECKNOTREADY ; NO, TRY NOT READY
+
+; AT THIS POINT, WE KNOW WE HAVE AN ERROR. THE CONVERSE IS NOT TRUE.
+
+ MOV AL,9 ; FIRST, ASSUME OUT OF PAPER
+ TEST AH,NOPAPERSTATUS ; OUT OF PAPER SET?
+ JNZ RET1 ; YES, ERROR IS SET
+ INC AL ; INDICATE I/O ERROR
+RET1:
+
+; WE HAVE TRIAGED NOW FOR OUT OF PAPER AND IO ERR (IGNORING TIME-OUT)
+
+ RET ; RETURN WITH ERROR
+
+; THE BITS SAID NO ERROR. UNFORTUNATELY, THERE MAY BE OTHER THINGS AT WORK
+; HERE.
+
+CHECKNOTREADY:
+ MOV AL,2 ; ASSUME NOT-READY
+ TEST AH,TIMEOUTSTATUS ; IS TIME-OUT SET?
+ ; IF NZ THEN ERROR, ELSE OK???
+PRNOP2:
+ RET
+PRNSTAT ENDP
+
+; 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
+PRN$TILBUSY PROC NEAR
+ ASSUME DS:CODE ; SET BY PRINTER DEVICE DRIVER ENTRY
+
+ PUSH DS
+ PUSH ES
+ POP DS ; NOW ES AND DS BOTH POINT TO SOURCE BUFFER
+ ASSUME DS:NOTHING
+
+ 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 ; ERROR
+ TEST AH,10000000B ; READY YET?
+ LOOPZ PRN$GETSTAT ; NO, GO FOR MORE
+ POP CX ; GET ORIGINAL COUNT
+ JZ PRN$BERR ; STILL NOT READY => DONE
+ LODSB
+ XOR AH,AH
+ CALL PRNOP
+ JNZ PRN$BERR ; ERROR
+ LOOP PRN$TILBLOOP ; GO FOR MORE
+PRN$B:
+ POP DS
+ LDS BX,CS:[PTRSAV]
+ ASSUME DS:NOTHING
+ SUB WORD PTR [BX].COUNT,CX ;# OF SUCCESSFUL I/O'S
+ JMP EXIT
+PRN$TILBUSY ENDP
+
+PRN$BPERR PROC NEAR
+ ASSUME DS:CODE
+ POP CX
+PRN$BERR:
+ POP DS
+ LDS BX,CS:[PTRSAV]
+ ASSUME DS:NOTHING
+
+ SUB WORD PTR [BX].COUNT,CX ;# OF SUCCESSFUL I/O'S
+ JMP ERR$EXIT
+PRN$BPERR ENDP
+;
+; 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
+PRN$GENIOCTL PROC NEAR
+ ASSUME DS:CODE ; SET BY PRINTER DEVICE DRIVER ENTRY
+
+ 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
+CODE ENDS
+ END
diff --git a/v4.0/src/BIOS/MSMACRO.INC b/v4.0/src/BIOS/MSMACRO.INC
new file mode 100644
index 0000000..efc034c
--- /dev/null
+++ b/v4.0/src/BIOS/MSMACRO.INC
@@ -0,0 +1,192 @@
+;
+; This file contains three macros used in debugging the system. If the
+; variable "itest" (in msbio.asm) is nonzero code is included in the
+; modules to print debugging messages. The level of debugging is controlled
+; by the value of the variable fTestBits in msbio.asm. Specific bits in
+; the variable determine which messages to print. The equ's below tell
+; which bits control which funcitons. For example the fifth bit
+; cooresponds to disk activity (see fTestDisk equ below).
+;
+; The macros in the file are:
+;
+; message Prints an ascii string on the screen.
+; Example usage:
+;
+; message fTestDisk, <"Start Disk Write", CR, LF>
+; message fTestINIT, <"Begin BDS initialization">
+;
+;
+; MNUM Print the value in a register or memory location on
+; the screen. Value is displayed in hex.
+; Usage:
+; MNUM bitpattern, valueLocation
+;
+; valueLocation is typically a regester:
+;
+; mnum fTestCom, AX
+; mnum fTestDisk, DX
+;
+; ValueLocation can also be a memory location:
+;
+; mnum fTestINIT, Final_Dos_Location
+;
+; If no valueLocation is given the macro defaults to
+; the BX register.
+;
+; ZWAIT Stops the program until any key is pressed.
+;
+;
+; The three macros preserve all register values. If "test" is zero
+; defined during assembly then the marco produce no code.
+;
+
+ IF iTEST ;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/v4.0/src/BIOS/MSSTACK.INC b/v4.0/src/BIOS/MSSTACK.INC
new file mode 100644
index 0000000..21a2095
--- /dev/null
+++ b/v4.0/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 PC Convertible / NMI handler
+;
+; On the PC Convertible, there is a situation where an NMI can be
+; caused by using the "OUT" instructions to certain ports. When this
+; occurs, the PC Convertible 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 PC Convertible, 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],mdl_convert ;check if convertible
+ 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], mdl_convert ;convertible? ;3.30
+ pop ds ;3.30
+ jne Skip_NMIS ;3.30
+ ;3.30
+ mov al,07h ; disable PC Convertible 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/v4.0/src/BIOS/MSVOLID.INC b/v4.0/src/BIOS/MSVOLID.INC
new file mode 100644
index 0000000..d1a9588
--- /dev/null
+++ b/v4.0/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/v4.0/src/BIOS/PSOPTION.INC b/v4.0/src/BIOS/PSOPTION.INC
new file mode 100644
index 0000000..d7f56d4
--- /dev/null
+++ b/v4.0/src/BIOS/PSOPTION.INC
@@ -0,0 +1,63 @@
+;*******************************************************************
+; Parser Options set for IBMBIO SYSCONF module
+;*******************************************************************
+;
+;**** Default assemble swiches definition **************************
+
+IFNDEF FarSW
+FarSW equ 0 ; Near call expected
+ENDIF
+
+IFNDEF DateSW
+DateSW equ 0 ; Check date format
+ENDIF
+
+IFNDEF TimeSW
+TimeSW equ 0 ; Check time format
+ENDIF
+
+IFNDEF FileSW
+FileSW equ 1 ; Check file specification
+ENDIF
+
+IFNDEF CAPSW
+CAPSW equ 0 ; Perform CAPS if specified
+ENDIF
+
+IFNDEF CmpxSW
+CmpxSW equ 0 ; Check complex list
+ENDIF
+
+IFNDEF NumSW
+NumSW equ 1 ; Check numeric value
+ENDIF
+
+IFNDEF KeySW
+KeySW equ 0 ; Support keywords
+ENDIF
+
+IFNDEF SwSW
+SwSW equ 1 ; Support switches
+ENDIF
+
+IFNDEF Val1SW
+Val1SW equ 1 ; Support value definition 1
+ENDIF
+
+IFNDEF Val2SW
+Val2SW equ 0 ; Support value definition 2
+ENDIF
+
+IFNDEF Val3SW
+Val3SW equ 1 ; Support value definition 3
+ENDIF
+
+IFNDEF DrvSW
+DrvSW equ 1 ; Support drive only format
+ENDIF
+
+IFNDEF QusSW
+QusSW equ 0 ; Support quoted string format
+ENDIF
+
+
\ No newline at end of file
diff --git a/v4.0/src/BIOS/PUSHPOP.INC b/v4.0/src/BIOS/PUSHPOP.INC
new file mode 100644
index 0000000..aaa76eb
--- /dev/null
+++ b/v4.0/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/v4.0/src/BIOS/READCLOC.INC b/v4.0/src/BIOS/READCLOC.INC
new file mode 100644
index 0000000..700f0aa
--- /dev/null
+++ b/v4.0/src/BIOS/READCLOC.INC
@@ -0,0 +1,165 @@
+; 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
+ assume ds:code,es:nothing
+ 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
+ assume ds:code,es:nothing
+ 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
+ assume ds:nothing,es:nothing
+ 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/v4.0/src/BIOS/STKINIT.INC b/v4.0/src/BIOS/STKINIT.INC
new file mode 100644
index 0000000..8298fb8
--- /dev/null
+++ b/v4.0/src/BIOS/STKINIT.INC
@@ -0,0 +1,271 @@
+;
+; 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.T; 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
+ assume ds:sysinitseg ; sunilp SB340
+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], mdl_convert ;convertible? ;3.30
+ pop ds ;3.30
+ jne Skip_disableNMIS ;3.30
+ ;3.30
+ MOV AL,07H ; DISABLE Convertible 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], mdl_convert ;PC convertible? ;3.30
+ pop ds ;3.30
+ jne Skip_EnableNMIS ;3.30
+ ;3.30
+ MOV AL,27H ; ENABLE Convertible 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/v4.0/src/BIOS/SYSCONF.ASM b/v4.0/src/BIOS/SYSCONF.ASM
new file mode 100644
index 0000000..7de3d30
--- /dev/null
+++ b/v4.0/src/BIOS/SYSCONF.ASM
@@ -0,0 +1,3392 @@
+ PAGE ,132 ;
+; SCCSID = @(#)sysconf.asm 0.0 86/10/20
+TITLE BIOS SYSTEM INITIALIZATION
+%OUT ...SYSCONF
+
+;==============================================================================
+;REVISION HISTORY:
+;AN000 - New for DOS Version 4.00 - J.K.
+;AC000 - Changed for DOS Version 4.00 - J.K.
+;AN00x - PTM number for DOS Version 4.00 - J.K.
+;==============================================================================
+;AN001; P132 Multiple character device installation problem. 06/27/87 J.K.
+;AN002; D24 MultiTrack= command added. 06/29/87 J.K.
+;AN003; D41 REM command in CONFIG.SYS. 07/6/87 J.K.
+;AN004; D184 Set DEVMARK for MEM command 08/25/87 J.K.
+;AN005; P568 CONFIG.SYS parsing error with FCBS=10,15 08/31/87 J.K.
+;AN006; P887 STACKS=0 does not show "ERROR in CONFIG.SYS..." 09/09/87 J.K.
+;AN007; D246, P976 Show "Bad command or parameters - ..." msg 09/22/87 J.K.
+;AN008; P1299 Set the second entry of DEVMARK for MEM command 09/25/87 J.K.
+;AN009; P1326 New Extended attribute 09/28/87 J.K.
+;AN010; P1820 New message SKL file 10/20/87 J.K.
+;AN011; P1970 AUTOTEST FCBS= command error msg inconsistent 10/23/87 J.K.
+;AN012; P2211 Setting the EA=7 for ANSI.SYS hangs the system 11/02/87 J.K.
+;AN013; P2342 REM not allowed after INSTALL command 11/09/87 J.K.
+;AN014; P2546 DEVICE= command still allowed after IFS= 11/17/87 J.K.
+;AN015; D358 New device driver INIT function package 12/03/87 J.K.
+;AN016; D285 Undo the extended error handling 12/17/87 J.K.
+;AN017; P3170 Do not call block device driver when drive # > 26 01/20/88 J.K.
+;AN018; P3111 Take out the order dependency of the INSTALL= 01/25/88 J.K.
+;AN019; D479 New option to disable extended INT 16h function call 02/12/88 J.K.
+;AN020; P3607 MEM does not give correct filename 02/24/88 J.K.
+;AN021; D493 Undo D358 & do not show error message for device driv 02/24/88 J.K.
+;AN022; P3807 Single buffer unprotected - System hangs 03/10/88 J.K.
+;AN023; P3797 An INSTALL cmd right after Bad cmd is not executed 03/10/88 J.K.
+;AN024; D503 Version change to 4.0 - IBMCACHE.SYS is an exception 03/15/88 J.K.
+;AN025; D474 Change BUFFERS= /E option to /X for expanded memory 03/16/88 J.K.
+;AN026; D506 Take out the order dependency of the IFS= 03/28/88 J.K.
+;AN027; P3957 Undo D503 - IBMCACHE.SYS version check problem 03/30/88 J.K.
+;AN028; P4086 Memory allocation error when loading share.exe 03/31/88 J.K.
+;AN029; D528 Install XMAEM.SYS first before everything else 04/29/88 J.K.
+;AN030; P4759 INT2f, INT 67h handlers for XMA 05/11/88 J.K.
+;AN031; P4889 Should check the validity of INT 67h call 05/17/88 G.A.
+;AN032; P4934 P4759 INT 2fh number should be changed to 1Bh 05/20/88 J.K.
+;AN033; P5002 EMS w/single page allocated now works 05/20/88 G.A.
+;AN034; P5128 EMS INT 2FH HANDLER BUG 06/24/88
+;==============================================================================
+
+TRUE EQU 0FFFFh
+FALSE EQU 0
+LF equ 10
+CR equ 13
+TAB equ 9
+SEMICOLON equ ';'
+
+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
+
+HAVE_INSTALL_CMD equ 00000001b ;AN018; CONFIG.SYS has INSTALL= commands
+HAS_INSTALLED equ 00000010b ;AN018; SYSINIT_BASE installed.
+
+IS_IFS equ 00000001b ;IFS command?
+NOT_IFS equ 11111110b
+;
+;AN016; Undo the extended attribute handling
+;;Extended attribute value
+;EA_UNSPECIFIED equ 0 ;AN009;
+;EA_DEVICE_DRIVER equ 6 ;AN009;
+;EA_IFS_DRIVER equ 7 ;AN009;
+
+DEFAULT_FILENUM = 8
+;
+ IF IBMJAPVER
+NOEXEC EQU TRUE
+ ELSE
+NOEXEC EQU FALSE
+ ENDIF
+
+DOSSIZE EQU 0A000H
+;dossize equ 0C000H ;J.K. for the debugging version of IBMDOS.
+
+.xlist
+; INCLUDE dossym.INC
+ include smdossym.inc ;J.K. Reduced version of DOSSYM.INC
+ INCLUDE devsym.INC
+ include ioctl.INC
+ include BIOSTRUC.INC
+ include smifssym.inc ;AN000; Reduced version of IFSSYM.INC.
+ include DEVMARK.inc ;AN004;
+ include version.inc
+.list
+
+ IF NOT IBMJAPVER
+ EXTRN RE_INIT:FAR
+ ENDIF
+
+;
+
+;J.K. 6/29/87 External variable defined in IBMBIO module for Multi-track
+MULTRK_ON EQU 10000000B ;User spcified Mutitrack=on, or System turns
+ ; it on after handling CONFIG.SYS file as a
+ ; default value, if MulTrk_flag = MULTRK_OFF1.
+MULTRK_OFF1 EQU 00000000B ;initial value. No "Multitrack=" command entered.
+MULTRK_OFF2 EQU 00000001B ;User specified Multitrack=off.
+
+CODE segment public 'code'
+ EXTRN MulTrk_flag:word ;AN002;
+ extrn KEYRD_Func:byte ;AN019;
+ extrn KEYSTS_Func:byte ;AN019;
+CODE ends
+;J.K. 6/29/87 End of Multi-track definition.
+
+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
+ EXTRN SYSSIZE:BYTE,BADCOUNTRY:BYTE,INSUFMEMORY:BYTE
+ EXTRN CONDEV:BYTE,AUXDEV:BYTE,PRNDEV:BYTE,COMMND:BYTE,CONFIG:BYTE
+ EXTRN Cntry_Drv:BYTE,Cntry_Root:BYTE,Cntry_Path:BYTE
+ EXTRN DeviceParameters:byte
+ EXTRN MEMORY_SIZE:word
+ EXTRN BUFFERS:word
+ EXTRN FILES:byte,NUM_CDS:byte
+ EXTRN DOSINFO:dword,ENTRY_POINT:dword
+ EXTRN FCBS:byte,KEEP:byte
+ EXTRN CONFBOT:word,ALLOCLIM:word,COMMAND_LINE:byte
+ EXTRN ZERO:byte,SEPCHR:byte
+ EXTRN COUNT:word,CHRPTR:word,CNTRYFILEHANDLE:word
+ EXTRN MEMLO:word,MEMHI:word,PRMBLK:word,LDOFF:word
+ EXTRN PACKET:byte,UNITCOUNT:byte,BREAK_ADDR:dword
+ EXTRN BPB_ADDR:dword,DRIVENUMBER:byte,SYSI_COUNTRY:dword
+ extrn Config_Size:word ;AN000;
+ extrn Install_Flag:word ;AN000;
+ extrn BadOrder:byte ;AN000;
+ extrn Errorcmd:byte ;AN000;
+ extrn LineCount:word ;AN000;
+ extrn ShowCount:byte ;AN000;
+ extrn Buffer_LineNum:word ;AN000;
+ extrn IFS_Flag:word ;AN000;
+ extrn IFS_RH:byte ;AN000;
+ extrn H_Buffers:word ;AN000;
+ extrn Buffer_Slash_X:byte ;AN000;AN025;
+ extrn Badparm:byte ;AN007;
+ extrn ConfigMsgFlag:Word ;AN015;
+ extrn Org_Count:Word ;AN018;
+ extrn Multi_Pass_Id:byte ;AN026;
+
+ EXTRN MEM_ERR:NEAR,SetDOSCountryInfo:NEAR
+ EXTRN PARAROUND:NEAR,TEMPCDS:NEAR
+ EXTRN Set_Country_Path:NEAR,Move_ASCIIZ:NEAR,DELIM:NEAR
+ EXTRN BADFIL:NEAR,ROUND:NEAR
+ extrn Do_Install_Exec:NEAR ;AN018;
+ extrn SetDevMark:NEAR ;AN030;
+
+;AN016; Undo the extended attribute handling
+; extrn Get_Ext_Attribute:near ;AN009;
+
+ 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
+ extrn stack_size:word
+ extrn stack_addr:dword
+
+ ENDIF
+
+ PUBLIC DOCONF
+ PUBLIC GETCHR
+ public Multi_Pass ;AN018;AN026;
+
+ public MultDeviceFlag
+MultDeviceFlag db 0 ;AN001;
+ public DevMark_Addr
+DevMark_Addr dw ? ;AN004;Segment address for DEVMARK.
+ public SetDevMarkFlag
+SetDevMarkFlag db 0 ;AN004;Flag used for DEVMARK
+
+EMS_Stub_Installed db 0 ;AN030;
+
+Badparm_Ptr label dword
+Badparm_Off dw 0 ;AN007;
+Badparm_Seg dw 0 ;AN007;
+
+XMAEM_file db 'XMAEM.SYS',0 ;AN029;
+
+;IBMCACHE_file db 'IBMCACHE.SYS',0;AN024;AN026;To cope with the IBMCACHE.SYS
+ ; problem of DOS version checking.
+
+;******************************************************************************
+;Take care of Config.sys file.
+;SYSTEM parser data and code.
+;******************************************************************************
+.xlist
+ include PSOPTION.INC ;Parsing options for SYSCONF.
+ include PARSE.ASM ;together with PSDATA.INC
+.list
+;Control block definitions for PARSER.
+;---------------------------------------------------
+; BUFFER = [n | n,m] {/E}
+
+Buf_Parms label byte ;AN000;
+ dw Buf_Parmsx ;AN000;
+ db 1 ;AN000; An extra delimeter list
+ db 1 ;AN000; length is 1
+ db SEMICOLON ;AN000;
+
+Buf_Parmsx label byte ;AN000;
+ db 1,2 ;AN000; Min 1, Max 2 positional
+ dw Buf_Pos1 ;AN000;
+ dw Buf_Pos2 ;AN000;
+ db 1 ;AN000; 1 switch
+ dw SW_X_Ctrl ;AN000;AN025; /X control
+ db 0 ;AN000; no keywords
+
+Buf_Pos1 label word ;AN000;
+ dw 8000h ;AN000; Numeric value
+ dw 0 ;AN000; no function
+ dw Result_Val ;AN000; Result value buffer
+ dw Buf_Range_1 ;AN000; value list
+ db 0 ;AN000; no switches/keywords
+
+Buf_Range_1 label byte ;AN000; value definition
+ db 1 ;AN000; range definition
+ db 1 ;AN000; 1 definition of range
+ db 1 ;AN000; item tag for this range
+ dd 1,10000 ;AN000; from 1 to 10000
+
+Buf_Pos2 label word ;AN000;
+ dw 8001h ;AN000; Numeric value, Optional
+ dw 0 ;AN000; no function
+ dw Result_Val ;AN000; Result value buffer
+ dw Buf_Range_2 ;AN000; value list
+ db 0 ;AN000; no switches/keywords
+
+Buf_Range_2 label byte ;AN000; value definition
+ db 1 ;AN000; range definition
+ db 1 ;AN000; 1 definition of range
+ db 1 ;AN000; item tag for this range
+ dd 0,8 ;AN000; from 0 to 8.
+
+SW_X_Ctrl label word ;AN000;AN025;
+ dw 0 ;AN000; no matching flag
+ dw 0 ;AN000; no function
+ dw Result_Val ;AN000; return value
+ dw NoVal ;AN000; no value definition
+ db 1 ;AN000; # of switches
+Switch_X label byte ;AN000;AN025;
+ db '/X',0 ;AN000;AN025;
+;local variables
+P_Buffers dw 0 ;AN000;
+P_H_Buffers dw 0 ;AN000;
+P_Buffer_Slash_X db 0 ;AN000;AN025;
+Buffer_Pre_Scan db 0 ;AN030;
+
+;Common definitions -------------
+NoVal db 0 ;AN000;
+
+Result_Val label byte ;AN000;
+ db ? ;AN000; type returned
+ db ? ;AN000; item tag returned
+ dw ? ;AN000; ES:offset of the switch defined
+RV_Byte label byte ;AN000;
+RV_Dword label dword ;AN000;
+ dd ? ;AN000; value if number, or seg:offset to string.
+;--------------------------------
+
+; BREAK = [ ON | OFF ]
+
+Brk_Parms label byte ;AN000;
+ dw Brk_Parmsx ;AN000;
+ db 1 ;AN000; An extra delimeter list
+ db 1 ;AN000; length is 1
+ db SEMICOLON ;AN000;
+
+Brk_Parmsx label byte ;AN000;
+ db 1,1 ;AN000; Min 1, Max 1 positional
+ dw Brk_Pos ;AN000;
+ db 0 ;AN000; no switches
+ db 0 ;AN000; no keywords
+
+Brk_Pos label word ;AN000;
+ dw 2000h ;AN000; Simple string
+ dw 0 ;AN000; No functions
+ dw Result_Val ;AN000;
+ dw On_Off_String ;AN000; ON,OFF string descriptions
+ db 0 ;AN000; no keyword/switch synonyms
+
+On_Off_String label byte ;AN000;
+ db 3 ;AN000; signals that there is a string choice
+ db 0 ;AN000; no range definition
+ db 0 ;AN000; no numeric values choice
+ db 2 ;AN000; 2 strings for choice
+ db 1 ;AN000; the 1st string tag
+ dw On_String ;AN000;
+ db 2 ;AN000; the 2nd string tag
+ dw Off_String ;AN000;
+
+On_String db "ON",0 ;AN000;
+Off_String db "OFF",0 ;AN000;
+;local variable
+P_Ctrl_Break db 0 ;AN000; local variable
+
+;--------------------------------
+
+; COUNTRY = n {m {path}}
+; or
+; COUNTRY = n,,path
+
+Cntry_Parms label byte ;AN000;
+ dw Cntry_Parmsx ;AN000;
+ db 1 ;AN000; An extra delimeter list
+ db 1 ;AN000; length is 1
+ db SEMICOLON ;AN000;
+
+Cntry_Parmsx label byte ;AN000;
+ db 1,3 ;AN000; Min 1, Max 3 positional
+ dw Cntry_Pos1 ;AN000;
+ dw Cntry_Pos2 ;AN000;
+ dw Cntry_Pos3 ;AN000;
+ db 0 ;AN000; no switches
+ db 0 ;AN000; no keywords
+
+Cntry_Pos1 label word ;AN000; control definition for positional 1
+ dw 8000h ;AN000; Numeric value
+ dw 0 ;AN000; no functions
+ dw Result_Val ;AN000;
+ dw Cntry_Codepage_Range ;AN000; country id code range description
+ db 0 ;AN000; no switch/keyword synonyms
+
+Cntry_Codepage_Range label byte ;AN000;
+ db 1 ;AN000; # of value definitions
+ db 1 ;AN000; # of ranges
+ db 1 ;AN000; Tag for this range
+ dd 1,999 ;AN000;
+
+Cntry_Pos2 label word ;AN000; control definition for positional 2
+ dw 8001h ;AN000; Numeric value, optional
+ dw 0 ;AN000; no functions
+ dw Result_Val ;AN000;
+ dw Cntry_Codepage_Range ;AN000; code page range descriptions.
+ db 0 ;AN000; no switch/keyword synonyms
+
+Cntry_Pos3 label word ;AN000; control definition for positional 3
+ dw 0201h ;AN000; File spec, optional
+ dw 0 ;AN000; No functions. Don't need to CAP.
+ dw Result_Val ;AN000;
+ dw NoVal ;AN000; no value list
+ db 0 ;AN000; no switch/keyword synonyms
+
+;Local variables
+P_Cntry_Code dw 0 ;AN000;
+P_Code_Page dw 0 ;AN000;
+
+;--------------------------------
+
+; FILES = n
+
+Files_Parms label byte ;AN000;
+ dw Files_Parmsx ;AN000;
+ db 1 ;AN000; An extra delimeter list
+ db 1 ;AN000; length is 1
+ db SEMICOLON ;AN000;
+
+Files_Parmsx label byte ;AN000;
+ db 1,1 ;AN000; Min 1, Max 1 positional
+ dw Files_Pos ;AN000;
+ db 0 ;AN000; no switches
+ db 0 ;AN000; no keywords
+
+Files_Pos label byte ;AN000;
+ dw 8000h ;AN000; Numeric value
+ dw 0 ;AN000; no functions
+ dw Result_Val ;AN000;
+ dw Files_Range ;AN000; Files range description
+ db 0 ;AN000; no switch/keyword synonyms
+
+Files_Range label byte ;AN000;
+ db 1 ;AN000; # of value definitions
+ db 1 ;AN000; # of ranges
+ db 1 ;AN000; Tag for this range
+ dd 8,255 ;AN000;
+;local variable
+P_Files db 0 ;AN000;
+
+;--------------------------------
+
+; FCBS = n,m
+
+FCBS_Parms label byte ;AN000;
+ dw FCBS_Parmsx ;AN000;
+ db 1 ;AN000; An extra delimeter list
+ db 1 ;AN000; length is 1
+ db SEMICOLON ;AN000;
+
+FCBS_Parmsx label byte ;AN000;
+ db 2,2 ;AN000; Min 2, Max 2 positional
+ dw FCBS_Pos_1 ;AN000;
+ dw FCBS_Pos_2 ;AN000;
+ db 0 ;AN000; no switches
+ db 0 ;AN000; no keywords
+
+FCBS_Pos_1 label byte ;AN000;
+ dw 8000h ;AN000; Numeric value
+ dw 0 ;AN000; no functions
+ dw Result_Val ;AN000;
+ dw FCBS_Range ;AN000; FCBS range descriptions
+ db 0 ;AN000; no switch/keyword synonyms
+
+FCBS_Range label byte ;AN000;
+ db 1 ;AN000; # of value definitions
+ db 1 ;AN000; # of ranges
+ db 1 ;AN000; Tag for this range
+ dd 1,255 ;AN000;
+
+FCBS_Pos_2 label byte ;AN000;
+ dw 8000h ;AN000; Numeric value
+ dw 0 ;AN000; no functions
+ dw Result_Val ;AN000;
+ dw FCBS_Keep_Range ;AN000; FCBS KEEP range descriptions
+ db 0 ;AN000; no switch/keyword synonyms
+
+FCBS_Keep_Range label byte ;AN000;
+ db 1 ;AN000; # of value definitions
+ db 1 ;AN000; # of ranges
+ db 1 ;AN000; Tag for this range
+ dd 0,255 ;AN000;
+
+;local variable
+P_Fcbs db 0 ;AN000;
+P_Keep db 0 ;AN000;
+;--------------------------------
+
+; LASTDRIVE = x
+
+LDRV_Parms label byte ;AN000;
+ dw LDRV_Parmsx ;AN000;
+ db 1 ;AN000; An extra delimeter list
+ db 1 ;AN000; length is 1
+ db SEMICOLON ;AN000;
+
+LDRV_Parmsx label byte ;AN000;
+ db 1,1 ;AN000; Min 1, Max 1 positional
+ dw LDRV_Pos ;AN000;
+ db 0 ;AN000; no switches
+ db 0 ;AN000; no keywords
+
+LDRV_Pos label byte ;AN000;
+ dw 0110h ;AN000; Drive only, Ignore colon.
+ dw 0010h ;AN000; Remove colon at end
+ dw Result_Val ;AN000;
+ dw NoVal ;AN000; No value list
+ db 0 ;AN000; no switch/keyword synonyms
+
+;local variable
+P_Ldrv db 0 ;AN000;
+;--------------------------------
+
+; STACKS = n,m
+
+STKS_Parms label byte ;AN000;
+ dw STKS_Parmsx ;AN000;
+ db 1 ;AN000; An extra delimeter list
+ db 1 ;AN000; length is 1
+ db SEMICOLON ;AN000;
+
+STKS_Parmsx label byte ;AN000;
+ db 2,2 ;AN000; Min 2, Max 2 positional
+ dw STKS_Pos_1 ;AN000;
+ dw STKS_Pos_2 ;AN000;
+ db 0 ;AN000; no switches
+ db 0 ;AN000; no keywords
+
+STKS_Pos_1 label byte ;AN000;
+ dw 8000h ;AN000; Numeric value
+ dw 0 ;AN000; no functions
+ dw Result_Val ;AN000;
+ dw STKS_Range ;AN000; number of stack range descriptions
+ db 0 ;AN000; no switch/keyword synonyms
+
+STKS_Range label byte ;AN000;
+ db 1 ;AN000; # of value definitions
+ db 1 ;AN000; # of ranges
+ db 1 ;AN000; Tag for this range
+ dd 0,64 ;AN000;
+
+STKS_Pos_2 label byte ;AN000;
+ dw 8000h ;AN000; Numeric value
+ dw 0 ;AN000; no functions
+ dw Result_Val ;AN000;
+ dw STK_SIZE_Range ;AN000; stack size range descriptions
+ db 0 ;AN000; no switch/keyword synonyms
+
+STK_SIZE_Range label byte ;AN000;
+ db 1 ;AN000; # of value definitions
+ db 1 ;AN000; # of ranges
+ db 1 ;AN000; Tag for this range
+ dd 0,512 ;AN000;
+;local variables
+P_Stack_Count dw 0 ;AN000;
+P_Stack_Size dw 0 ;AN000;
+
+;--------------------------------
+
+; MULTITRACK = [ ON | OFF ]
+
+MTrk_Parms label byte ;AN002;
+ dw MTrk_Parmsx ;AN002;
+ db 1 ;AN002; An extra delimeter list
+ db 1 ;AN002; length is 1
+ db SEMICOLON ;AN002;
+
+MTrk_Parmsx label byte ;AN002;
+ db 1,1 ;AN002; Min 1, Max 1 positional
+ dw MTrk_Pos ;AN002;
+ db 0 ;AN002; no switches
+ db 0 ;AN002; no keywords
+
+MTrk_Pos label word ;AN002;
+ dw 2000h ;AN002; Simple string
+ dw 0 ;AN002; No functions
+ dw Result_Val ;AN002;
+ dw On_Off_String ;AN002; ON,OFF string descriptions
+ db 0 ;AN002; no keyword/switch synonyms
+
+;local variables
+P_Mtrk db 0 ;AN002;
+;--------------------------------
+
+; CPSW = [ ON | OFF ]
+
+CPSW_Parms label byte ;AN002;
+ dw CPSW_Parmsx ;AN002;
+ db 1 ;AN002; An extra delimeter list
+ db 1 ;AN002; length is 1
+ db SEMICOLON ;AN002;
+
+CPSW_Parmsx label byte ;AN002;
+ db 1,1 ;AN002; Min 1, Max 1 positional
+ dw CPSW_Pos ;AN002;
+ db 0 ;AN002; no switches
+ db 0 ;AN002; no keywords
+
+CPSW_Pos label word ;AN002;
+ dw 2000h ;AN002; Simple string
+ dw 0 ;AN002; No functions
+ dw Result_Val ;AN002;
+ dw On_Off_String ;AN002; ON,OFF string descriptions
+ db 0 ;AN002; no keyword/switch synonyms
+
+;local variables
+P_CPSW db 0 ;AN002;
+
+;--------------------------------
+; SWITCHES=/K
+
+Swit_Parms label byte ;AN019;
+ dw Swit_Parmsx ;AN019;
+ db 1 ;AN019; An extra delimeter list
+ db 1 ;AN019; length is 1
+ db SEMICOLON ;AN019;
+
+Swit_Parmsx label byte ;AN019;
+ db 0,0 ;AN019; No positionals
+ db 1 ;AN019; 1 switch for now.
+ dw Swit_K_Ctrl ;AN019; /K control
+ db 0 ;AN019; no keywords
+
+Swit_K_Ctrl label word ;AN019;
+ dw 0 ;AN019; no matching flag
+ dw 0 ;AN019; no function
+ dw Result_Val ;AN019; return value
+ dw NoVal ;AN019; no value definition
+ db 1 ;AN019; # of switches
+Swit_K label byte ;AN019;
+ db '/K',0 ;AN019;
+;local variables
+P_Swit_K db 0 ;AN019;
+
+;******************************************************************************
+
+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 (sickness)
+ jc No_Config_sys ;AN028;
+ JMP NOPROB ;PROBLEM WITH OPEN
+No_Config_sys: ;AN028;
+ mov Multi_Pass_Id, 11 ;AN028; set it to unreasonable number
+ENDCONF:
+ return
+
+
+BADOP: MOV DX,OFFSET BADOPM ;WANT TO PRINT COMMAND ERROR "Unrecognized command..."
+ invoke PRINT
+ call Error_Line ;show "Error in CONFIG.SYS ..." .
+ JMP COFF
+
+Badop_p proc near ;AN000;
+;Same thing as BADOP, but will make sure to set DS register back to SYSINITSEG
+;and return back to the calller.
+ push cs
+ pop ds ;set ds to CONFIGSYS seg.
+ mov dx, offset badopm
+ invoke PRINT
+ call Error_Line
+ ret
+Badop_p endp
+
+Badparm_p proc near ;AN007;
+;Show "Bad command or parameters - xxxxxx"
+;In Badparm_seg, Badparm_off -> xxxxx
+;
+ cmp cs:Buffer_Pre_Scan, 1 ;AN030; Pre scanning Buffers ... /X?
+ je BadParmp_Ret ;AN030; then do not show any message.
+ push ds ;AN007;
+ push dx ;AN007;
+ push si ;AN007;
+
+ push cs ;AN007;
+ pop ds ;AN007;
+ mov dx, offset Badparm ;AN007;
+ invoke PRINT ;AN007;"Bad command or parameters - "
+ lds si, Badparm_ptr ;AN007;
+Badparm_Prt: ;AN007;print "xxxx" until CR.
+ mov dl, byte ptr [si] ;AN007;
+ mov ah,STD_CON_OUTPUT ;AN007;
+ int 21h ;AN007;
+ inc si ;AN007;
+ cmp dl, CR ;AN007;
+ jne Badparm_Prt ;AN007;
+ push cs ;AN007;
+ pop ds ;AN007;
+ mov dx, offset CRLFM ;AN007;
+ invoke PRINT ;AN007;
+ call Error_Line ;AN007;
+ pop si ;AN007;
+ pop dx ;AN007;
+ pop ds ;AN007;
+BadParmp_Ret: ;AN030;
+ ret ;AN007;
+Badparm_p endp
+
+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 dx, [ConfBot] ;AN022;Use current CONFBOT value
+ MOV AX,[COUNT]
+ mov [config_size], ax ;save the size of config.sys file.
+ call ParaRound
+ SUB DX,AX
+ SUB DX,11H ;ROOM FOR HEADER
+ MOV [CONFBOT],DX ; Config starts here. New CONBOT value.
+ 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,CR
+ STOSB ; CR
+ MOV AL,LF
+ 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
+
+Multi_Pass: ;AN018;AN026; called to execute IFS=, INSTALL= commands
+ push cs ;AN018;
+ pop ds ;AN018;
+ cmp Multi_Pass_id, 10 ;J.K.
+ jae Endconv ;J.K. Do nothing. Just return.
+ push Confbot ;AN018;
+ pop es ;AN018; ES -> Confbot
+ mov si, Org_Count ;AN018;
+ mov Count, si ;AN018; set Count
+ xor si,si ;AN018;
+ mov Chrptr, si ;AN018; reset Chrptr, LineCount
+ mov LineCount, si ;AN018;
+ call GetChr ;AN018;
+ jmp Conflp ;AN018;
+GETCOM:
+ invoke ORGANIZE ;ORGANIZE THE FILE
+ CALL GETCHR
+
+CONFLP: JC ENDCONV
+ call Reset_DOS_Version ;AN024;AN026; Still need to reset version even IBMDOS handles this through
+ ; function 4Bh call, since IBMDOS does not know when Load/Overlay call finishes.
+
+IF NOT BUFFERFLAG
+ call EMS_Stub_handler ;AN030;
+ENDIF
+
+ inc LineCount ;AN000; Increase LineCount.
+ mov Buffer_Pre_Scan, 0 ;AN030; Reset Buffer_Pre_Scan.
+ mov MultDeviceFlag,0 ;AN001; Reset MultDeviceFlag.
+ mov SetDevMarkFlag,0 ;AN004; Reset SetDevMarkFlag.
+ cmp al, LF ;AN000; LineFeed?
+ je Blank_Line ;AN000; then ignore this line.
+ MOV AH,AL
+ CALL GETCHR
+ jnc TryI ;AN000;
+ cmp Multi_Pass_ID, 2 ;AN026;
+ jae Endconv ;AN026;Do not show Badop again for multi_pass.
+ JMP BADOP
+
+COFF: PUSH CS
+ POP DS
+ invoke NEWLINE
+ JMP CONFLP
+Blank_Line: ;AN000;
+ call Getchr ;AN000;
+ jmp CONFLP ;AN000;
+
+COFF_P:
+ push cs
+ pop ds
+
+
+;J.K. 1/27/88 ;;;;;;;;;;;;;;;;;;
+;To handle INSTALL= commands, we are going to use multi-pass.
+;The first pass handles the other commands and only set Install_Flag when
+;it finds any INSTALL command. The second pass will only handle the
+;INSTALL= command.
+
+;------------------------------------------------------------------------------
+;INSTALL command
+;------------------------------------------------------------------------------
+TRYI:
+ cmp Multi_Pass_Id, 0 ;AN029; the initial pass for XMAEM.SYS
+ je Multi_Try_XMAEM ;AN029; and BUFFERS= ... /X pre scan.
+ cmp Multi_Pass_Id, 2 ;AN026; the second pass for IFS= ?
+ je Multi_Try_J ;AN026;
+ cmp Multi_Pass_Id, 3 ;AN026; the third pass for INSTALL= ?
+ je Multi_Try_I ;AN026;
+ cmp ah, 'I' ;AN018; INSTALL= command?
+ jne TryB ;AN018; the first pass is for normal operation.
+ or Install_Flag, HAVE_INSTALL_CMD ;AN018; Set the flag
+ jmp coff ;AN018; and handles the next command
+
+Multi_Try_XMAEM: ;AN029;
+ cmp ah, 'D' ;AN029; device= command?
+ jne Multi_Try_Buff ;AN029; no skip it.
+ call Chk_XMAEM ;AN029; is it for XMAEM.SYS?
+ jnz Multi_Pass_FIlter ;AN029; no skip it.
+ mov byte ptr es:[si-1], 0FFh ;AN029; mark this command as a Null command for the next pass.
+ jmp TryDJ ;AN029; execute this command.
+Multi_Try_Buff: ;AN030;
+ cmp ah, 'B' ;AN030; Buffers= command?
+ jne Multi_Pass_Filter ;AN030;
+ mov Buffer_Pre_Scan, 1 ;AN030; Set Buffer_Pre_Scan
+ jmp TryB ;AN030; TryB will set P_Buffer_Slash_X to non-zero value.
+
+Multi_Try_J: ;AN026;
+ cmp ah, 'J' ;AN026; IFS= command?
+ jne Multi_Pass_Filter ;AN026; No. Ignore this.
+ jmp GotJ ;AN026; Handles IFS= command.
+
+Multi_Try_I: ;AN026;
+ cmp ah, 'I' ;AN026; INSTALL= command?
+ jne Multi_Pass_Filter ;AN026; No. Ignore this.
+ call Do_Install_Exec ;Install it.
+ jmp Coff ;to handle next Install= command.
+
+Multi_Pass_Filter: ;AN023;AN026;
+ cmp ah, 'Y' ;AN023; Comment?
+ je Multi_Pass_Adjust ;AN023;
+ cmp ah, 'Z' ;AN023; Bad command?
+ je Multi_Pass_Adjust ;AN023;
+ cmp ah, '0' ;AN023; REM?
+ jne Multi_Pass_Coff ;AN023; ignore the rest of the commands.
+Multi_Pass_Adjust: ;AN023; These commands need to
+ dec Chrptr ;AN023; adjust chrptr, count
+ inc Count ;AN023; for NEWLINE proc.
+Multi_Pass_Coff: ;AN023;
+ jmp Coff ;AN018; To handle next INSTALL= commands.
+
+;------------------------------------------------------------------------------
+
+Sysinit_Parse proc
+;Set up registers for SysParse
+;In) ES:SI -> command line in CONFBOT
+; DI -> offset of the parse control defintion.
+;
+;Out) Calls SYSPARSE.
+; Carry will set if Parse error.
+; *** The caller should check the EOL condition by looking at AX
+; *** after each call.
+; *** If no parameters are found, then AX will contain a error code.
+; *** If the caller needs to look at the SYNOMYM@ of the result,
+; *** the caller should use CS:@ instead of ES:@.
+; CX register should be set to 0 at the first time the caller calls this
+; procedure.
+; AX - exit code
+; BL - TErminated delimeter code
+; CX - new positional ordinal
+; SI - set to pase scanned operand
+; DX - selected result buffer
+
+ push es ;save es,ds
+ push ds
+
+ push es
+ pop ds ;now DS:SI -> command line
+ push cs
+ pop es ;now ES:DI -> control definition
+
+ mov cs:Badparm_Seg,ds ;AN007;Save the pointer to the parm
+ mov cs:Badparm_Off,si ;AN007; we are about to parse for Badparm msg.
+ mov dx, 0
+ call SysParse
+ cmp ax, $P_NO_ERROR ;no error
+; $IF E,OR
+ JE $$LL1
+ cmp ax, $P_RC_EOL ;or the end of line?
+; $IF E
+ JNE $$IF1
+$$LL1:
+ clc
+; $ELSE
+ JMP SHORT $$EN1
+$$IF1:
+ stc
+; $ENDIF
+$$EN1:
+ pop ds
+ pop es ;restore es,ds
+ ret
+Sysinit_Parse endp
+
+;------------------------------------------------------------------------------
+; Buffer command
+;------------------------------------------------------------------------------
+;*******************************************************************************
+; *
+; Function: Parse the parameters of buffers= command. *
+; *
+; Input : *
+; ES:SI -> parameters in command line. *
+; Output: *
+; Buffers set *
+; Buffer_Slash_X flag set if /X option chosen. *
+; H_Buffers set if secondary buffer cache specified. *
+; *
+; Subroutines to be called: *
+; Sysinit_Parse *
+; Logic: *
+; { *
+; Set DI points to Buf_Parms; /*Parse control definition*/ *
+; Set DX,CX to 0; *
+; Reset Buffer_Slash_X; *
+; While (End of command line) *
+; { Sysinit_parse; *
+; if (no error) then *
+; if (Result_Val.$P_SYNONYM_ptr == Slash_E) then /*Not a switch *
+; Buffer_Slash_X = 1 *
+; else if (CX == 1) then /* first positional */ *
+; Buffers = Result_Val.$P_Picked_Val; *
+; else H_Buffers = Result_Val.$P_Picked_Val; *
+; else {Show Error message;Error Exit} *
+; }; *
+; If (Buffer_Slash_X is off & Buffers > 99) then Show_Error; *
+; }; *
+; *
+;*******************************************************************************
+;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
+
+TryB:
+ CMP AH,'B'
+ JNZ TryC
+ mov P_Buffer_Slash_X, 0 ;AN000;AN025;
+ mov di, offset Buf_Parms ;AN000;
+ xor cx, cx ;AN000;
+ mov dx, cx ;AN000;
+
+; $SEARCH ;AN000;
+$$DO4:
+ call Sysinit_Parse ;AN000;
+; $EXITIF C ;AN000; Parse Error,
+ JNC $$IF4
+ call Badparm_p ;AN007; and Show messages and end the search loop.
+; $ORELSE ;AN000;
+ JMP SHORT $$SR4
+$$IF4:
+ cmp ax, $P_RC_EOL ;AN000; End of Line?
+; $LEAVE E ;AN000; then jmp to $Endloop for semantic check.
+ JE $$EN4
+ cmp Result_Val.$P_SYNONYM_PTR, offset Switch_X ;AN000;AN025;
+; $IF E ;AN000;
+ JNE $$IF8
+ mov P_Buffer_Slash_X, 1 ;AN000;AN025; set the flag
+; $ELSE ;AN000;
+ JMP SHORT $$EN8
+$$IF8:
+ mov ax, word ptr Result_Val.$P_PICKED_VAL ;AN000;
+ cmp cx, 1 ;AN000;
+; $IF E ;AN000;
+ JNE $$IF10
+ mov P_Buffers, ax ;AN000;
+; $ELSE ;AN000;
+ JMP SHORT $$EN10
+$$IF10:
+ mov P_H_Buffers, ax ;AN000;
+; $ENDIF ;AN000;
+$$EN10:
+; $ENDIF ;AN000;
+$$EN8:
+; $ENDLOOP ;AN000;
+ JMP SHORT $$DO4
+$$EN4:
+ cmp P_Buffers, 99 ;AN000;
+; $IF A,AND ;AN000;
+ JNA $$IF15
+ cmp P_Buffer_Slash_X, 0 ;AN000;AN025;
+; $IF E ;AN000;
+ JNE $$IF15
+ call Badparm_p ;AN000;
+ mov P_H_Buffers, 0 ;AN000;
+; $ELSE ;AN000;
+ JMP SHORT $$EN15
+$$IF15:
+ mov ax, P_Buffers ;AN000; We don't have any problem.
+ mov Buffers, ax ;AN000; Now, let's set it really.
+ mov ax, P_H_Buffers ;AN000;
+ mov H_Buffers, ax ;AN000;
+ mov al, P_Buffer_Slash_X ;AN000;AN025;
+ mov Buffer_Slash_X, al ;AN000;AN025;
+ mov ax, LineCount ;AN000;
+ mov Buffer_LineNum, ax ;AN000; Save the line number for the future use.
+; $ENDIF ;AN000;
+$$EN15:
+; $ENDSRCH ;AN000;
+$$SR4:
+ jmp Coff
+
+;------------------------------------------------------------------------------
+; Break command
+;------------------------------------------------------------------------------
+;*******************************************************************************
+; *
+; Function: Parse the parameters of Break = command. *
+; *
+; Input : *
+; ES:SI -> parameters in command line. *
+; Output: *
+; Turn the Control-C check on or off. *
+; *
+; Subroutines to be called: *
+; Sysinit_Parse *
+; Logic: *
+; { *
+; Set DI to Brk_Parms; *
+; Set DX,CX to 0; *
+; While (End of command line) *
+; { Sysinit_Parse; *
+; if (no error) then *
+; if (Result_Val.$P_Item_Tag == 1) then /*ON */ *
+; Set P_Ctrl_Break, on; *
+; else /*OFF */ *
+; Set P_Ctrl_Break, off; *
+; else {Show message;Error_Exit}; *
+; }; *
+; If (no error) then *
+; DOS function call to set Ctrl_Break check according to *
+; }; *
+; *
+;********************************************************************************
+;TryC: CMP AH,'C'
+; JZ GOTC
+; JMP TRYDJ
+;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
+;
+TryC:
+ CMP AH,'C'
+ JNZ TRYM
+ mov di, offset Brk_Parms ;AN000;
+ xor cx,cx ;AN000;
+ mov dx,cx ;AN000;
+; $SEARCH ;AN000;
+$$DO19:
+ call Sysinit_Parse ;AN000;
+; $EXITIF C ;AN000; Parse error
+ JNC $$IF19
+ call Badparm_p ;AN007; Show message and end the serach loop.
+; $ORELSE ;AN000;
+ JMP SHORT $$SR19
+$$IF19:
+ cmp ax, $P_RC_EOL ;AN000; End of Line?
+; $LEAVE E ;AN000; then end the $ENDLOOP
+ JE $$EN19
+ cmp Result_Val.$P_ITEM_TAG, 1 ;AN000;
+; $IF E ;AN000;
+ JNE $$IF23
+ mov P_Ctrl_Break, 1 ;AN000; Turn it on
+; $ELSE ;AN000;
+ JMP SHORT $$EN23
+$$IF23:
+ mov P_Ctrl_Break, 0 ;AN000; Turn it off
+; $ENDIF ;AN000;
+$$EN23:
+; $ENDLOOP ;AN000; we actually set the ctrl break
+ JMP SHORT $$DO19
+$$EN19:
+ mov ah, SET_CTRL_C_TRAPPING ;AN000; if we don't have any parse error.
+ mov al, 1 ;AN000;
+ mov dl, P_Ctrl_Break ;AN000;
+ Int 21h ;AN000;
+; $ENDSRCH ;AN000;
+$$SR19:
+ jmp Coff
+
+;------------------------------------------------------------------------------
+; MultiTrack command
+;------------------------------------------------------------------------------
+;*******************************************************************************
+; *
+; Function: Parse the parameters of MultiTrack= command. *
+; *
+; Input : *
+; ES:SI -> parameters in command line. *
+; Output: *
+; Turn MulTrk_Flag on or off. *
+; *
+; Subroutines to be called: *
+; Sysinit_Parse *
+; Logic: *
+; { *
+; Set DI to Brk_Parms; *
+; Set DX,CX to 0; *
+; While (End of command line) *
+; { Sysinit_Parse; *
+; if (no error) then *
+; if (Result_Val.$P_Item_Tag == 1) then /*ON */ *
+; Set P_Mtrk, on; *
+; else /*OFF */ *
+; Set P_Mtrk, off; *
+; else {Show message;Error_Exit}; *
+; }; *
+; If (no error) then *
+; DOS function call to set MulTrk_Flag according to P_Mtrk. *
+; *
+; }; *
+; *
+;********************************************************************************
+TryM: ;AN002;
+ CMP AH,'M' ;AN002;
+ JNZ TRYW ;AN002;
+ mov di, offset Mtrk_Parms ;AN002;
+ xor cx,cx ;AN002;
+ mov dx,cx ;AN002;
+; $SEARCH ;AN002;
+$$DO28:
+ call Sysinit_Parse ;AN002;
+; $EXITIF C ;AN002; Parse error
+ JNC $$IF28
+ call Badparm_p ;AN007; Show message and end the serach loop.
+; $ORELSE ;AN002;
+ JMP SHORT $$SR28
+$$IF28:
+ cmp ax, $P_RC_EOL ;AN002; End of Line?
+; $LEAVE E ;AN002; then end the $ENDLOOP
+ JE $$EN28
+ cmp Result_Val.$P_ITEM_TAG, 1 ;AN002;
+; $IF E ;AN002;
+ JNE $$IF32
+ mov P_Mtrk, 1 ;AN002; Turn it on temporarily.
+; $ELSE ;AN002;
+ JMP SHORT $$EN32
+$$IF32:
+ mov P_Mtrk, 0 ;AN002; Turn it off temporarily.
+; $ENDIF ;AN002;
+$$EN32:
+; $ENDLOOP ;AN002; we actually set the MulTrk_Flag here.
+ JMP SHORT $$DO28
+$$EN28:
+ push ds ;AN002;
+ mov ax, Code ;AN002;
+ mov ds, ax ;AN002;
+ assume ds:Code
+ cmp P_Mtrk, 0 ;AN002;
+; $IF E ;AN002;
+ JNE $$IF36
+ mov MulTrk_Flag, MULTRK_OFF2 ;AN002; 0001h
+; $ELSE ;AN002;
+ JMP SHORT $$EN36
+$$IF36:
+ mov MulTrk_Flag, MULTRK_ON ;AN002; 8000h
+; $ENDIF ;AN002;
+$$EN36:
+ pop ds ;AN002;
+ assume ds:SYSINITSEG
+; $ENDSRCH ;AN002;
+$$SR28:
+ jmp Coff ;AN002;
+
+;------------------------------------------------------------------------------
+; CPSW command
+;------------------------------------------------------------------------------
+;*******************************************************************************
+; *
+; Function: Parse the parameters of CPSW= command. *
+; *
+; Input : *
+; ES:SI -> parameters in command line. *
+; Output: *
+; Turn CPSW on or off. *
+; *
+; Subroutines to be called: *
+; Sysinit_Parse *
+; Logic: *
+; { *
+; Set DI to CPSW_Parms; *
+; Set DX,CX to 0; *
+; While (End of command line) *
+; { Sysinit_Parse; *
+; if (no error) then *
+; if (Result_Val.$P_Item_Tag == 1) then /*ON */ *
+; Set P_CPSW, on; *
+; else /*OFF */ *
+; Set P_CPSW, off; *
+; else {Show message;Error_Exit}; *
+; }; *
+; If (no error) then *
+; DOS function call to set CPSW according to P_CPSW. *
+; }; *
+; *
+;********************************************************************************
+TryW: ;AN002;
+ CMP AH,'W' ;AN002;
+ JNZ TRYDJ ;AN002;
+ mov di, offset CPSW_Parms ;AN002;
+ xor cx,cx ;AN002;
+ mov dx,cx ;AN002;
+; $SEARCH ;AN002;
+$$DO40:
+ call Sysinit_Parse ;AN002;
+; $EXITIF C ;AN002; Parse error
+ JNC $$IF40
+ call Badparm_p ;AN007; Show message and end the serach loop.
+; $ORELSE ;AN002;
+ JMP SHORT $$SR40
+$$IF40:
+ cmp ax, $P_RC_EOL ;AN002; End of Line?
+; $LEAVE E ;AN002; then end the $ENDLOOP
+ JE $$EN40
+ cmp Result_Val.$P_ITEM_TAG, 1 ;AN002;
+; $IF E ;AN002;
+ JNE $$IF44
+ mov P_CPSW, 1 ;AN002; Turn it on temporarily.
+; $ELSE ;AN002;
+ JMP SHORT $$EN44
+$$IF44:
+ mov P_CPSW, 0 ;AN002; Turn it off temporarily.
+; $ENDIF ;AN002;
+$$EN44:
+; $ENDLOOP ;AN002; we actually set the MulTrk_Flag here.
+ JMP SHORT $$DO40
+$$EN40:
+ mov ah, SET_CTRL_C_TRAPPING ;AN000; The same function number as Ctrl_Break
+ mov al, 4 ;AN000; Set CPSW state function
+ mov dl, P_CPSW ;AN000; 0=off, 1=on
+ Int 21h ;AN000;
+; $ENDSRCH ;AN002;
+$$SR40:
+ jmp Coff ;AN002;
+
+;------------------------------------------------------------------------------
+; Device command
+;------------------------------------------------------------------------------
+TRYDJ:
+ and cs:IFS_Flag, NOT_IFS ;AN000; Reset the flag
+ CMP AH,'D'
+ JZ GOTDJ
+ CMP AH,'J'
+ jz GOTJ
+ JMP TRYQ
+GOTJ: ;AN000; IFS= command.
+ or cs:[IFS_Flag], IS_IFS ;AN000; set the flag.
+ cmp Multi_Pass_Id, 2 ;second pass?
+ je GOTDJ ;then proceed
+ jmp Coff ;else ignore this until the second pass.
+
+; jmp GOTDJ_Cont
+;GOTD:
+; test cs:[IFS_Flag], HAD_IFS ;AN000; Cannot have DEVICE= command after IFS= command.
+; jz GOTDJ_Cont ;AN000;
+; call Incorrect_Order ;AN000; Display "Incorrect order ..." msg.
+; jmp COFF ;AN000;
+
+GOTDJ:
+ MOV BX,CS ;DEVICE= or IFS= command.
+ MOV DS,BX
+
+ MOV WORD PTR [BPB_ADDR],SI
+ MOV WORD PTR [BPB_ADDR+2],ES
+
+;J.K. In case it is for IFS=, then set the parameter pointer.
+ mov word ptr [ifs_rh.IFSR_PARMS@], SI ;AN000; for IFS
+ mov word ptr [ifs_rh.IFSR_PARMS@+2], ES ;AN000;
+
+ CALL ROUND
+;J.K. Set up the DEVMARK entries here for MEM command.
+;J.K. Only the DEVMARK_ID and DEVMARK_FILENAME will be set.
+;J.K. DEVMARK_SIZE should be set after a successful process of this file.
+ call Set_DevMark ;AN004;
+ inc [MEMHI] ;AN004;Size of DEVMARK is a paragraph!!
+ ;Don't forget decrease MEMHI
+ ; with an unsuccessful process of this file!!.
+ 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
+;AN016; UNDO THE EXTENDED ATTRIBUTE HANDLING
+; call Get_Ext_Attribute ;AN009;
+; jc BadLdReset ;AN009;
+; test cs:[IFS_Flag], IS_IFS ;AN009;
+; jnz Chk_Ext_Attr_IFS ;AN009;
+; cmp al, EA_UNSPECIFIED ;AN009;Check the extended attr. for device driver
+; je Ext_Attr_Ok ;AN009; Allow 0 and EA_DEVICE_DRIVER
+; cmp al, EA_DEVICE_DRIVER ;AN009;
+; je Ext_Attr_Ok ;AN009;
+; stc ;AN012;BadLdReset depends on the carry bit.
+; jmp BadLdReset ;AN009;
+;Chk_Ext_Attr_IFS: ;AN009;
+; cmp al, EA_IFS_DRIVER ;AN009;
+; je Ext_Attr_Ok ;AN012;
+; stc ;AN012;
+; jmp BadLdReset ;AN012;
+;Ext_Attr_Ok: ;AN009;
+ 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:
+ test cs:[SetDevMarkFlag],SETBRKDONE ;AN004;If already Set_Break is done,
+ jnz Skip0_ResetMEMHI ;AN004; then do not
+ dec cs:[MEMHI] ;AN004;Adjust MEMHI by a paragrah of DEVMARK.
+Skip0_ResetMEMHI:
+ cmp byte ptr es:[si], CR ;file name is CR? (Somebody entered "device=" without filename)
+ jne BADBRK_1
+ jmp BADOP ;show "Unrecognized command in CONFIG.SYS"
+BADBRK_1:
+ invoke BADLOAD
+ JMP COFF
+
+GOODLD:
+;J.K. If it is IFS=, then we should set IFS_DOSCALL@ field in IFSHEADER.
+ test cs:[IFS_Flag], IS_IFS ;AN000;
+ jz Skip_IFSHEADER_Set ;AN000;
+ push es ;AN000;
+ push di ;AN000;
+ push ds ;AN000;
+ mov bx, word ptr cs:[ENTRY_POINT+2] ;AN000;
+ mov ds, bx ;AN000; DS:0 will be the header
+ les di, cs:[DosInfo] ;AN000;
+ mov bx, word ptr es:[di.SYSI_IFS_DOSCALL@] ;AN000;
+ mov word ptr ds:[IFS_DOSCALL@], bx ;AN000;
+ mov bx, word ptr es:[di.SYSI_IFS_DOSCALL@]+2 ;AN000;
+ mov word ptr ds:[IFS_DOSCALL@]+2, bx ;AN000;
+ pop ds ;AN000;
+ pop di ;AN000;
+ pop es ;AN000;
+Skip_IFSHEADER_Set: ;AN000;
+ SaveReg ;INITIALIZE THE DEVICE
+; call Chk_IBMCACHE ;AN024 IBMCACHE.SYS problem.;AN026;IBMDOS will handles this thru 4Bh call.
+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
+
+ test cs:[IFS_Flag], IS_IFS ;AN000;
+ jz Got_Device_Com ;AN000;
+ mov bx, IFS_CALL@ ;AN000; offset from the start of IFSHEADER
+ call CallIFS ;AN000;
+ jmp short End_Init_Call
+Got_Device_Com:
+ push ds ;AN017;
+ push si ;AN017;
+ lds si, cs:[ENTRY_POINT] ;AN017; Peeks the header attribute
+ test word ptr ds:[si.SDEVATT], DEVTYP ;AN017;Block device driver?
+ jnz Got_Device_Com_Cont ;AN017;No.
+ lds si, cs:[DOSINFO] ;AN017; DS:SI -> SYS_VAR
+ cmp ds:[si.SYSI_NUMIO], 26 ;AN017; No more than 26 drive number
+ jb Got_Device_Com_Cont ;AN017;
+ pop si ;AN017;
+ pop ds ;AN017;
+ pop si ;AN017;clear the stack
+ pop es ;AN017;
+ jmp BadNumBlock ;AN017;
+Got_Device_Com_Cont: ;AN017;
+ pop si ;AN017;
+ pop ds ;AN017;
+ MOV BX,SDEVSTRAT
+ invoke CALLDEV ; CallDev (SDevStrat);
+ MOV BX,SDEVINT
+ invoke CALLDEV ; CallDev (SDevInt);
+End_Init_Call:
+ RestoreReg
+ MOV BYTE PTR [SI],0 ; *p = 0;
+
+ PUSH CS
+ POP DS
+
+ test [IFS_Flag], IS_IFS ;AN000;
+ jz Was_Device_Com ;AN000;
+ cmp [ifs_rh.IFSR_RETCODE], 0 ;AN000; Was a success ?
+ jne Erase_Dev_do ;AN000;
+ pop si ;AN000; restore es:si to clean up the
+ pop es ;AN000; stack for Set_Break call.
+ mov ax, word ptr [Entry_Point+2] ;AN000; Get the loaded segment
+ add ax, word ptr [ifs_rh.IFSR_RESSIZE] ;AN000;
+ mov word ptr [Break_addr], 0 ;AN000;
+ mov word ptr [Break_addr+2], ax ;AN000;
+ or cs:[SetDevMarkFlag], FOR_DEVMARK ;AN004;
+ invoke Set_Break ;AN000; Will also check the memory size too.
+ push es ;AN000; Save it again, in case, for Erase_Dev_Do.
+ push si ;AN000;
+ jc Erase_Dev_do ;AN000;
+Link_IFS: ;AN000;
+ les di, cs:[dosinfo] ;AN000;
+ mov cx, word ptr es:[di.SYSI_IFS] ;AN000; save old pointer
+ mov dx, word ptr es:[di.SYSI_IFS+2] ;AN000;
+ lds si, cs:[Entry_Point] ;AN000;
+ mov word ptr es:[di.SYSI_IFS],si ;AN000;
+ mov word ptr es:[di.SYSI_IFS+2], ds ;AN000;
+ mov word ptr ds:[si], cx ;AN000; We don't permit multiple IFSs.
+ mov word ptr ds:[si+2], dx ;AN000;
+ pop si ;AN000; Restore es:si for the next command.
+ pop es ;AN000;
+; mov cs:[IFS_Flag], HAD_IFS ;AN014; Set the flag.
+ jmp COFF ;AN000;
+
+ERASE_DEV_do: ;AC000;; Modified to show message "Error in CONFIG.SYS..."
+ pop si
+ pop es
+ push cs
+ pop ds
+ test [SetDevMarkFlag],SETBRKDONE ;AN004;If already Set_Break is done,
+ jnz Skip1_ResetMEMHI ;AN004; then do not
+ dec [MEMHI] ;AN004;Adjust MEMHI by a paragrah of DEVMARK.
+Skip1_ResetMEMHI:
+ cmp ConfigMsgFlag, 0 ;AN015;
+ je No_Error_Line_Msg ;AN015;
+ call Error_Line ;AN021; No "Error in CONFIG.SYS" msg for device driver. DCR D493
+ mov ConfigMsgFlag, 0 ;AN015;AN021;Set the default value again.
+No_Error_Line_Msg: ;AN015;
+ JMP Coff
+
+Was_Device_Com: ;AN000;
+ 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
+ or cs:[SetDevMarkFlag],FOR_DEVMARK ;AN004;
+ invoke Set_Break ; Go ahead and alloc mem for device
+ jc Erase_Dev_do ;device driver's Init routien failed.
+ 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
+ jz Erase_Dev_do
+; JNZ PERDRV
+; MOV AX, -1
+; 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
+BadNumBlock: ;AN017;
+ PUSH CS
+ POP DS
+ MOV DX,OFFSET BADBLOCK
+ invoke PRINT
+ JMP ERASE_DEV_do
+
+OK_BLOCK:
+ or cs:[SetDevMarkFlag],FOR_DEVMARK ;AN004;
+ 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
+ or cs:[SetDevMarkFlag], FOR_DEVMARK ;AN004;Add DPB area for this unit
+ 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]
+ PUSH ES
+ LES DI,CS:[DOSINFO] ;ES:DI POINT TO DOS INFO
+ CMP AX,ES:[DI.SYSI_MAXSEC]
+ POP ES
+ ja Bad_BPB_Size_Sector
+ 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
+ inc cs:MultDeviceFlag ;AN001; Possibly multiple device driver.
+ JMP GOODLD ;OTHERWISE PRETEND WE LOADED IT IN
+COFFJ3: mov cs:MultDeviceFlag, 0 ;AN001; Reset the flag
+ JMP COFF
+
+Bad_BPB_Size_Sector:
+ POP SI
+ POP ES
+ MOV DX,OFFSET BADSIZ_PRE
+; MOV BX,OFFSET BADSIZ_POST
+ mov bx, offset CRLFM ;AN???;
+ invoke PRNERR
+ test [SetDevMarkFlag],SETBRKDONE ;AN004;If already Set_Break is done,
+ jnz Skip2_ResetMEMHI ;AN004; then do not
+ dec [MEMHI] ;AN004;Adjust MEMHI by a paragrah of DEVMARK.
+Skip2_ResetMEMHI:
+ JMP COFF
+
+
+;------------------------------------------------------------------------------
+; Country command
+; J.K. The syntax is:
+; COUNTRY=country id {,codepage {,path}}
+; COUNTRY=country id {,,path} :Default CODEPAGE ID in DOS
+;------------------------------------------------------------------------------
+TRYQ:
+ CMP AH,'Q'
+ JZ TRYQ_CONT
+ JMP TRYF
+TRYQ_CONT:
+
+; invoke GETNUM
+; JZ TryQBad ; 0 is never a valid code, or number is
+; ; bad
+; MOV BX,AX ; Country code in BX
+;
+; ;J.K. 5/26/86
+; MOV DX,0 ; assume no code page id
+;
+; invoke skip_delim ;skip the delimeters after the first num
+; jc TryQ_Def_File ;no more characters left? then use default file
+; cmp al, CR ;
+; je TryQ_Def_File
+; cmp al, LF
+; jne TRYQ_YES_EXTENDED
+; inc [COUNT] ;This is for NEWLINE routine in COFF.
+; dec [CHRPTR]
+;COFFJ41:
+; JMP TryQ_Def_File ;O.K. no code page, no path specified. Use default path.
+;
+;TRYQ_YES_EXTENDED:
+; cmp al, ',' ;was the second comma?
+; jne TryQ_GETNUM
+; invoke skip_delim ;Yes, skip ',' and other possible delim
+; jmp short TRYQ_PATH ;and No code page id entered.
+;TRYQ_GETNUM:
+; invoke GETNUM
+; jc TryQBadCOM ;"Country=xxx,path" will not be accepted.
+;; jc TRYQ_PATH ;Codepage is not specified. No code page.
+;; ;At this point, AL already contain the
+;; ;first char of the PATH.
+; jz TryQBad ;codepage=0 entered. Error
+; mov DX, AX ;save code page in DX
+; invoke skip_delim ;move CHRPTR to the path string
+; jc TryQ_Def_File ;no more char? then use default filename
+; cmp al, CR
+; je TryQ_Def_File
+; cmp al, LF
+; jne TryQ_PATH ;path entered.
+; inc [COUNT]
+; dec [CHRPTR]
+;TryQ_Def_File:
+; push dx ;save code page
+; mov cs:CNTRY_DRV, 0 ;flag that the default path has been used!!!
+; mov dx, offset CNTRY_ROOT ;the default path
+; jmp TRYQ_OPEN
+;
+;TryQBad: ;"Invalid country code or code page"
+; STC
+; MOV DX,OFFSET BADCOUNTRY
+; jmp TryQChkErr
+;
+;TryQBadCOM: ;Error in COUNTRY command
+; STC
+; MOV DX,OFFSET BADCOUNTRYCOM
+; jmp TryQChkErr
+;
+;TRYQ_PATH: ;DS - sysinitseg, ES - CONFBOT,
+; mov CX, [COUNT] ;AL - the first char of path
+; inc CX ;BX - country id, DX - codepage id, 0 = No code page
+; mov DI, SI
+;TRYQ_PATH_LOOP: ;find the end of path to put 0 after that.
+; mov AL, byte ptr ES:[DI]
+; call delim
+; jz TRYQ_PATH_END
+; cmp al, 13
+; jz TRYQ_PATH_END
+; inc DI
+; jmp short TRYQ_PATH_LOOP
+;TryQBad_Brg:jmp short TryQBad
+;TRYQ_PATH_END:
+; mov es:byte ptr [di], 0 ;make it a ASCIIZ string. (Organize did not handle this string)
+; push ds ;switch ds,es
+; push es
+; pop ds
+; pop es
+;
+; mov di, offset CNTRY_DRV ;move the user specified path to CNTRY_DRV
+; call Move_ASCIIZ
+;
+; push ds ;restore ds,es
+; push es
+; pop ds
+; pop es
+;
+;; call Set_Country_Path ;set CNTRY_DRV
+;
+; push dx ;save DX
+; mov dx, offset CNTRY_DRV ;Now DS:DX -> CNTRY_DRV
+
+ mov Cntry_Drv, 0 ;AN000; Reset the drive,path to default value.
+ mov P_Code_Page,0 ;AN000;
+ mov di, offset Cntry_Parms ;AN000;
+ xor cx,cx ;AN000;
+ mov dx,cx ;AN000;
+; $SEARCH ;AN000;
+$$DO49:
+ call Sysinit_Parse ;AN000;
+; $EXITIF C ;AN000; Parse error, check the error code and
+ JNC $$IF49
+ call Cntry_Error ;AN000; Show message and end the serach loop.
+ mov P_Cntry_Code, -1 ;AN000; Signals that parse error.
+; $ORELSE ;AN000;
+ JMP SHORT $$SR49
+$$IF49:
+ cmp ax, $P_RC_EOL ;AN000; End of Line?
+; $LEAVE E ;AN000; then end the $SEARCH LOOP
+ JE $$EN49
+ cmp Result_Val.$P_TYPE, $P_NUMBER ;AN000; Numeric?
+; $IF E ;AN000;
+ JNE $$IF53
+ mov ax, word ptr Result_Val.$P_PICKED_VAL ;AN000;
+ cmp cx, 1 ;AN000;
+; $IF E ;AN000;
+ JNE $$IF54
+ mov P_Cntry_Code, ax ;AN000;
+; $ELSE ;AN000;
+ JMP SHORT $$EN54
+$$IF54:
+ mov P_Code_Page, ax ;AN000;
+; $ENDIF ;AN000;
+$$EN54:
+; $ELSE ;AN000; Path entered.
+ JMP SHORT $$EN53
+$$IF53:
+ push ds ;AN000;
+ push es ;AN000;
+ push si ;AN000;
+ push di ;AN000;
+ push cs ;AN000;
+ pop es ;AN000;
+ lds si, RV_Dword ;AN000; Move the path to known place.
+ mov di, offset CNTRY_Drv ;AN000;
+ call Move_ASCIIZ ;AN000;
+ pop di ;AN000;
+ pop si ;AN000;
+ pop es ;AN000;
+ pop ds ;AN000;
+; $ENDIF ;AN000;
+$$EN53:
+; $ENDLOOP
+ JMP SHORT $$DO49
+$$EN49:
+; $ENDSRCH ;AN000;
+$$SR49:
+ cmp P_Cntry_Code, -1 ;AN000; Had a parse error?
+ jne TRYQ_OPEN ;AN000;
+ jmp Coff ;AN000;
+
+TryQBad: ;"Invalid country code or code page"
+ STC
+ MOV DX,OFFSET BADCOUNTRY
+ jmp TryQChkErr
+
+TRYQ_OPEN:
+ cmp CNTRY_Drv, 0 ;AC000;
+ je TRYQ_Def ;AC000;
+ mov dx, offset CNTRY_Drv ;AC000;
+ jmp TryQ_Openit ;AC000;
+TRYQ_Def: ;AC000;
+ mov dx, offset CNTRY_Root ;AC000;
+TryQ_Openit:
+ mov ax, 3d00h ;open a file
+ stc
+ int 21h
+ jc TryQFileBad ;open failure
+
+ mov cs:CntryFileHandle, ax ;save file handle
+ mov bx, ax
+ mov ax, cs:P_Cntry_Code ;AN000;
+ mov dx, cs:P_Code_Page ;AN000; Now, AX=country id, bx=filehandle
+; xchg ax, bx ;now, AX = country id, BX = file handle
+ mov cx, cs:[MEMHI]
+ add cx, 128 ;I need 2K buffer to handle COUNTRY.SYS
+ cmp cx, cs:[ALLOCLIM]
+ ja TryQMemory ;cannot allocate the buffer for country.sys
+
+ mov si, offset CNTRY_DRV ;DS:SI -> CNTRY_DRV
+ cmp byte ptr [si],0 ;default path?
+ jne TRYQ_Set_for_DOS
+ inc si
+ inc si ;DS:SI -> CNTRY_ROOT
+TRYQ_Set_for_DOS:
+ les di, cs:SYSI_Country ;ES:DI -> country info tab in DOS
+ push di ;save di
+ add di, ccPath_CountrySys
+ call MOVE_ASCIIZ ;Set the path to COUNTRY.SYS in DOS.
+ pop di ;ES:DI -> country info tab again.
+ mov cx, cs:[MEMHI]
+ mov ds, cx
+ xor si, si ;DS:SI -> 2K buffer to be used.
+ call SetDOSCountryInfo ;now do the job!!!
+ jnc TryQchkERR ;read error or could not find country,code page combination
+ cmp cx, -1 ;Could not find matching country_id,code page?
+ je TryQBad ;then "Invalid country code or code page"
+TryQFileBad:
+ push cs ;AN000;
+ pop es ;AN000;
+ cmp cs:CNTRY_DRV,0 ;Is the default file used?
+ je TryQDefBad
+; mov si, cs:[CONFBOT]
+; mov es, si
+; mov si, cs:[CHRPTR]
+; dec si ;ES:SI -> path in CONFBOT
+ mov si, offset CNTRY_Drv
+ jmp short TryQBADLOAD
+TryQDefBad: ;Default file has been used.
+; push cs
+; pop es
+ mov si, offset CNTRY_ROOT ;ES:SI -> \COUNTRY.SYS in SYSINIT_SEG
+TryQBADLOAD:
+ call BADLOAD ;DS will be restored to SYSINIT_SEG
+ mov cx, cs:[CONFBOT]
+ mov es, cx ;Restore ES -> CONFBOT.
+ jmp short CoffJ4
+TryQMemory:
+ MOV DX,OFFSET INSUFMEMORY
+TryQChkErr:
+ mov cx, cs:[CONFBOT]
+ mov es, cx ;restore ES -> CONFBOT seg
+ push cs
+ pop ds ;retore DS to SYSINIT_SEG
+ jnc CoffJ4 ;if no error, then exit
+ invoke PRINT ;else show error message
+ call Error_Line ;AN000;
+CoffJ4:
+ mov bx, CntryFileHandle
+ mov ah, 3eh
+ int 21h ;close a file. Don't care even if it fails.
+ JMP COFF
+
+Cntry_Error proc near
+;Function: Show "Invalid country code or code page" messages, or
+; "Error in COUNTRY command" depending on the error code
+; in AX returned by SYSPARSE;
+;In: AX - error code
+; DS - Sysinitseg
+; ES - CONFBOT
+;Out: Show message. DX destroyed.
+
+ cmp ax, $P_OUT_OF_RANGE
+; $IF E
+ JNE $$IF61
+ mov dx, offset BadCountry ;"Invalid country code or code page"
+; $ELSE
+ JMP SHORT $$EN61
+$$IF61:
+ mov dx, offset BadCountryCom ;"Error in CONTRY command"
+; $ENDIF
+$$EN61:
+ invoke Print
+ call Error_Line
+ ret
+Cntry_Error endp
+
+;------------------------------------------------------------------------------
+; Files command
+;------------------------------------------------------------------------------
+;*******************************************************************************
+; Function: Parse the parameters of FILES= command. *
+; *
+; Input : *
+; ES:SI -> parameters in command line. *
+; Output: *
+; Variable FILES set. *
+; *
+; Subroutines to be called: *
+; Sysinit_Parse *
+; Logic: *
+; { *
+; Set DI points to FILES_Parms; *
+; Set DX,CX to 0; *
+; While (End of command line) *
+; { Sysinit_parse; *
+; if (no error) then *
+; Files = Result_Val.$P_Picked_Val *
+; else *
+; Error Exit; *
+; }; *
+; }; *
+; *
+;*******************************************************************************
+TRYF:
+ CMP AH,'F'
+ JNZ TRYL
+
+; invoke GETNUM
+; CMP AX,5 ;j.k. change it to 8!!!!!!!!
+; 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
+
+ mov di, offset Files_Parms ;AN000;
+ xor cx, cx ;AN000;
+ mov dx, cx ;AN000;
+
+; $SEARCH ;AN000;
+$$DO64:
+ call Sysinit_Parse ;AN000;
+; $EXITIF C ;AN000; Parse Error,
+ JNC $$IF64
+ call Badparm_p ;AN007; and Show messages and end the search loop.
+; $ORELSE ;AN000;
+ JMP SHORT $$SR64
+$$IF64:
+ cmp ax, $P_RC_EOL ;AN000; End of Line?
+; $LEAVE E ;AN000; then end the $ENDLOOP
+ JE $$EN64
+ mov al, byte ptr Result_Val.$P_PICKED_VAL ;AN000;
+ mov P_Files, al ;AN000; Save it temporarily
+; $ENDLOOP ;AN000;
+ JMP SHORT $$DO64
+$$EN64:
+ mov al, P_Files ;AN000;
+ mov Files, al ;AN000; No error. Really set the value now.
+; $ENDSRCH ;AN000;
+$$SR64:
+ jmp Coff
+
+;------------------------------------------------------------------------------
+; LastDrive command
+;------------------------------------------------------------------------------
+;*******************************************************************************
+; Function: Parse the parameters of LASTDRIVE= command. *
+; *
+; Input : *
+; ES:SI -> parameters in command line. *
+; Output: *
+; Set the variable NUM_CDS. *
+; *
+; Subroutines to be called: *
+; Sysinit_Parse *
+; Logic: *
+; { *
+; Set DI points to LDRV_Parms; *
+; Set DX,CX to 0; *
+; While (End of command line) *
+; { Sysinit_Parse; *
+; if (no error) then *
+; Set NUM_CDS to the returned value; *
+; else /*Error exit*/ *
+; Error Exit; *
+; }; *
+; }; *
+; *
+;*******************************************************************************
+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
+
+ mov di, offset LDRV_Parms ;AN000;
+ xor cx, cx ;AN000;
+ mov dx, cx ;AN000;
+
+; $SEARCH ;AN000;
+$$DO70:
+ call Sysinit_Parse ;AN000;
+; $EXITIF C ;AN000; Parse Error,
+ JNC $$IF70
+ call Badparm_p ;AN007; and Show messages and end the search loop.
+; $ORELSE ;AN000;
+ JMP SHORT $$SR70
+$$IF70:
+ cmp ax, $P_RC_EOL ;AN000; End of Line?
+; $LEAVE E ;AN000; then end the $ENDLOOP
+ JE $$EN70
+ mov al, RV_Byte ;AN000; Pick up the drive number
+ mov P_Ldrv, al ;AN000; Save it temporarily
+; $ENDLOOP ;AN000;
+ JMP SHORT $$DO70
+$$EN70:
+ mov al, P_Ldrv ;AN000;
+; sub al, 'A' ;AN000; Convert it to drive number
+; inc al ;AN000; make it to be a number of drives.
+ mov Num_CDS, al ;AN000; No error. Really set the value now.
+; $ENDSRCH ;AN000;
+$$SR70:
+ jmp Coff
+
+
+;-------------------------------------------------------------------------------
+; Setting Drive Parameters
+;-------------------------------------------------------------------------------
+TRYP:
+ CMP AH,'P'
+ JNZ TRYK
+ invoke PARSELINE
+ JC TryPBad
+ invoke SETPARMS
+ INVOKE DIDDLEBACK
+ jc TryPBad
+ JMP COFF
+TryPBad:jmp Badop
+;-------------------------------------------------------------------------------
+; Setting Internal Stack Parameters
+; STACKS=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)
+; J.K. 5/5/86: STACKS=0,0 implies no stack installation.
+; Any combinations that are not within the specified limits will
+; result in "Unrecognized command" error.
+;-------------------------------------------------------------------------------
+;*******************************************************************************
+; *
+; Function: Parse the parameters of STACKS= command. *
+; The minimum value for "number of stacks" and "stack size" is *
+; 8 and 32 each. In the definition of SYSPARSE value list, they *
+; are set to 0. This is for accepting the exceptional case of *
+; STACKS=0,0 case (,which means do not install the stack.) *
+; So, after SYSPARSE is done, we have to check if the entered *
+; values (STACK_COUNT, STACK_SIZE) are within the actual range, *
+; (or if "0,0" pair has been entered.) *
+; Input : *
+; ES:SI -> parameters in command line. *
+; Output: *
+; Set the variables STACK_COUNT, STACK_SIZE. *
+; *
+; Subroutines to be called: *
+; Sysinit_Parse *
+; Logic: *
+; { *
+; Set DI points to STKS_Parms; *
+; Set DX,CX to 0; *
+; While (End of command line) *
+; { Sysinit_Parse; *
+; if (no error) then *
+; { if (CX == 1) then /* first positional = stack count */ *
+; P_Stack_Count = Result_Val.$P_Picked_Val; *
+; if (CX == 2) then /* second positional = stack size */ *
+; P_Stack_Size = Result_Val.$P_Picked_Val; *
+; } *
+; else /*Error exit*/ *
+; Error Exit; *
+; }; *
+; Here check P_STACK_COUNT,P_STACK_SIZE if it meets the condition; *
+; If O.K., then set Stack_Count, Stack_Size; *
+; else Error_Exit; *
+; }; *
+;*******************************************************************************
+TRYK:
+ CMP AH,'K'
+ JE Do_TryK
+ jmp TRYS
+
+ IF STACKSW
+
+; MOV SepChr,','
+; INVOKE GetNum ; Get number of stacks
+; MOV SepChr,0
+; cmp ax, 0 ;J.K. 5/5/86
+; je TRYK_0 ;J.K. Let's accept 0.
+; CMP AX, MinCount ; 8 <= Number of Stacks <= 64
+; JB TryKBad
+; CMP AX, MaxCount
+; JA TryKBad
+;TRYK_0:
+; MOV [STACK_COUNT], AX
+;
+; Skip delimiters after the first number.
+;
+; invoke Skip_delim ;J.K.
+; JC TryKBad
+;
+; INVOKE GetNum ; Get size of individual stack
+; JC TryKBad ; Number bad
+;
+; cmp ax, 0 ;J.K. 5/5/86
+; je TRYK_SIZE0 ;J.K. 5/5/86. Accept 0
+;
+; CMP AX, MinSize ; 32 <= Stack Size <= 512
+; JB TryKBad
+; CMP AX, MaxSize
+; JA TryKBad
+;TRYK_SIZE0:
+; MOV [STACK_SIZE], AX
+; cmp ax,0
+; je TRYK_BOTH0
+;TRYK_OK:
+; mov word ptr [stack_addr], -1 ;set the flag that the user entered stacks= command.
+; JMP COFF
+;TRYK_BOTH0:
+; cmp [STACK_COUNT],0 ;stack_size = 0. Stack_Count = 0 too?
+; je TRYK_OK ;yes. accepted.
+;TryKBad:
+; MOV DX, OFFSET BADSTACK ;J.K. 5/26/86 "Invalid stack parameter"
+; invoke PRINT
+; JMP COFF
+
+Do_TryK:
+ mov di, offset STKS_Parms ;AN000;
+ xor cx, cx ;AN000;
+ mov dx, cx ;AN000;
+
+; $SEARCH ;AN000;
+$$DO76:
+ call Sysinit_Parse ;AN000;
+; $EXITIF C ;AN000; Parse Error,
+ JNC $$IF76
+ mov dx, offset BadStack ;AN000; "Invalid stack parameter"
+ call Print ;AN000; and Show messages and end the search loop.
+ call Error_Line ;AN006;
+; $ORELSE ;AN000;
+ JMP SHORT $$SR76
+$$IF76:
+ cmp ax, $P_RC_EOL ;AN000; End of Line?
+; $LEAVE E ;AN000; then end the $ENDLOOP
+ JE $$EN76
+ mov ax, word ptr Result_Val.$P_PICKED_VAL ;AN000;
+ cmp cx, 1 ;AN000;
+; $IF E ;AN000;
+ JNE $$IF80
+ mov P_Stack_Count, ax ;AN000;
+; $ELSE ;AN000;
+ JMP SHORT $$EN80
+$$IF80:
+ mov P_Stack_Size, ax ;AN000;
+; $ENDIF ;AN000;
+$$EN80:
+; $ENDLOOP ;AN000;
+ JMP SHORT $$DO76
+$$EN76:
+ cmp P_Stack_Count, 0 ;AN000;
+; $IF NE ;AN000;
+ JE $$IF84
+ cmp P_Stack_Count, MINCOUNT ;AN000;
+; $IF B,OR ;AN000;
+ JB $$LL85
+ cmp P_Stack_Size, MINSIZE ;AN000;
+; $IF B ;AN000;
+ JNB $$IF85
+$$LL85:
+ mov P_Stack_Count, -1 ;AN000; Invalid
+; $ENDIF ;AN000;
+$$IF85:
+; $ELSE ;AN000;
+ JMP SHORT $$EN84
+$$IF84:
+ cmp P_Stack_Size, 0 ;AN000;
+; $IF NE ;AN000;
+ JE $$IF88
+ mov P_Stack_Count, -1 ;AN000; Invalid
+; $ENDIF ;AN000;
+$$IF88:
+; $ENDIF ;AN000;
+$$EN84:
+ cmp P_Stack_Count, -1 ;AN000; Invalid?
+; $IF E ;AN000;
+ JNE $$IF91
+ mov Stack_Count, DEFAULTCOUNT ;AN000;Reset to default value.
+ mov Stack_Size, DEFAULTSIZE ;AN000;
+ mov word ptr STACK_ADDR, 0 ;AN000;
+ mov dx, offset BadStack ;AN000;
+ call Print ;AN000;
+ call Error_Line ;AN006;
+; $ELSE ;AN000;
+ JMP SHORT $$EN91
+$$IF91:
+ mov ax, P_Stack_Count ;AN000;
+ mov Stack_Count, ax ;AN000;
+ mov ax, P_Stack_Size ;AN000;
+ mov Stack_Size, ax ;AN000;
+ mov word ptr Stack_Addr, -1 ;AN000;STACKS= been accepted.
+; $ENDIF ;AN000;
+$$EN91:
+; $ENDSRCH ;AN000;
+$$SR76:
+ jmp Coff
+ ENDIF
+;------------------------------------------------------------------------------
+; Switch command ;No longer supported.
+;------------------------------------------------------------------------------
+;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 ;No longer supported.
+;------------------------------------------------------------------------------
+;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,LF
+ JNZ CONV
+ CALL GETCHR
+CONV: JMP CONFLP
+
+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
+
+;------------------------------------------------------------------------------
+; FCBS Command
+;------------------------------------------------------------------------------
+;*******************************************************************************
+; Function: Parse the parameters of FCBS= command. *
+; *
+; Input : *
+; ES:SI -> parameters in command line. *
+; Output: *
+; Set the variables FCBS, KEEP. *
+; *
+; Subroutines to be called: *
+; Sysinit_Parse *
+; Logic: *
+; { *
+; Set DI points to FCBS_Parms; *
+; Set DX,CX to 0; *
+; While (End of command line) *
+; { SYSPARSE; *
+; if (no error) then *
+; { if (CX == 1) then /* first positional = FCBS */ *
+; FCBS = Result_Val.$P_Picked_Val; *
+; if (CX == 2) then /* second positional = KEEP */ *
+; KEEP = Result_Val.$P_Picked_Val; *
+; } *
+; else /*Error exit*/ *
+; Error Exit; *
+; }; *
+; }; *
+;*******************************************************************************
+TRYX:
+ CMP AH,'X'
+ JNZ TRYY
+; 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 first number including ","
+;
+; invoke Skip_delim ;J.K.
+; 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
+
+ mov di, offset FCBS_Parms ;AN000;
+ xor cx, cx ;AN000;
+ mov dx, cx ;AN000;
+
+; $SEARCH ;AN000;
+$$DO95:
+ call Sysinit_Parse ;AN000;
+; $EXITIF C ;AN000; Parse Error,
+ JNC $$IF95
+ call Badparm_p ;AN007; and Show messages and end the search loop.
+; $ORELSE ;AN000;
+ JMP SHORT $$SR95
+$$IF95:
+ cmp ax, $P_RC_EOL ;AN000; End of Line?
+; $LEAVE E ;AN000; then end the $ENDLOOP
+ JE $$EN95
+ mov al, byte ptr Result_Val.$P_PICKED_VAL ;AN000;
+ cmp cx, 1 ;AN000; The first positional?
+; $IF E ;AN000;
+ JNE $$IF99
+ mov P_Fcbs, al ;AN000;
+; $ELSE ;AN000;
+ JMP SHORT $$EN99
+$$IF99:
+ mov P_Keep, al ;AN000;
+; $ENDIF ;AN000;
+$$EN99:
+; $ENDLOOP ;AN000;
+ JMP SHORT $$DO95
+$$EN95:
+ mov al, P_Fcbs ;AN005;make sure P_Fcbs >= P_Keep
+ cmp al, P_Keep ;AN005;
+; $IF B ;AN005;
+ JNB $$IF103
+; call Badop_p ;AN005;
+ call Badparm_p ;AN011;show "Bad parameter -" msg.
+ mov P_Keep, 0 ;AN005;
+; $ELSE ;AN005;
+ JMP SHORT $$EN103
+$$IF103:
+ mov Fcbs, al ;AN000; No error. Really set the value now.
+ mov al, P_Keep ;AN000;
+ mov Keep, al ;AN000;
+; $ENDIF ;AN005;
+$$EN103:
+; $ENDSRCH ;AN000;
+$$SR95:
+ jmp Coff
+
+;------------------------------------------------------------------------------
+; Comment= Do nothing. Just decrese CHRPTR, and increase COUNT for correct
+; line number
+;------------------------------------------------------------------------------
+TRYY: ;AN000;
+ cmp ah, 'Y' ;AN000;
+ jne Try0 ;AN000;
+DoNothing:
+ dec CHRPTR ;AN000;
+ inc COUNT ;AN000;
+ jmp COFF ;AN000;
+
+;------------------------------------------------------------------------------
+; REM command
+;------------------------------------------------------------------------------
+Try0: ;AN003;do nothing with this line.
+ cmp ah, '0' ;AN003;
+ je DoNothing ;AN003;
+
+;------------------------------------------------------------------------------
+; SWITCHES command
+;------------------------------------------------------------------------------
+;*******************************************************************************
+; *
+; Function: Parse the option switches specified. *
+; Note - This command is intended for the future use also. When we need to *
+; to set system data flag, use this command. *
+; *
+; Input : *
+; ES:SI -> parameters in command line. *
+; Output: *
+; P_Swit_K set if /K option chosen. *
+; *
+; Subroutines to be called: *
+; Sysinit_Parse *
+; Logic: *
+; { *
+; Set DI points to Swit_Parms; /*Parse control definition*/ *
+; Set DX,CX to 0; *
+; While (End of command line) *
+; { Sysinit_parse; *
+; if (no error) then *
+; if (Result_Val.$P_SYNONYM_ptr == Swit_K) then *
+; P_Swit_K = 1 *
+; endif *
+; else {Show Error message;Error Exit} *
+; }; *
+; }; *
+; *
+;*******************************************************************************
+
+ cmp ah, '1' ;AN019;Switches= command entered?
+ jne Tryz ;AN019;
+
+ mov di, offset Swit_Parms ;AN019;
+ xor cx, cx ;AN019;
+ mov dx, cx ;AN019;
+
+; $SEARCH ;AN019;
+$$DO107:
+ call Sysinit_Parse ;AN019;
+; $EXITIF C ;AN019; Parse Error,
+ JNC $$IF107
+ call Badparm_p ;AN019; and Show messages and end the search loop.
+; $ORELSE ;AN019;
+ JMP SHORT $$SR107
+$$IF107:
+ cmp ax, $P_RC_EOL ;AN019; End of Line?
+; $LEAVE E ;AN019; then jmp to $Endloop for semantic check.
+ JE $$EN107
+ cmp Result_Val.$P_SYNONYM_PTR, offset Swit_K ;AN019;
+; $IF E ;AN019;
+ JNE $$IF111
+ mov P_Swit_K, 1 ;AN019; set the flag
+; $ENDIF ;AN019;
+$$IF111:
+; $ENDLOOP ;AN019;
+ JMP SHORT $$DO107
+$$EN107:
+ cmp P_Swit_K, 1 ;AN019;If /K entered,
+ push ds ;AN019;
+ mov ax, Code ;AN019;
+ mov ds, ax ;AN019;
+ assume ds:Code ;AN019;
+; $IF E ;AN019;
+ JNE $$IF114
+ mov KEYRD_Func, 0 ;AN019;Use the conventional keyboard functions
+ mov KEYSTS_Func, 1 ;AN019;
+; $ENDIF ;AN019;
+$$IF114:
+ pop ds ;AN019;
+ assume ds:SYSINITSEG ;AN019;
+; $ENDSRCH ;AN019;
+$$SR107:
+ jmp Coff ;AN019;
+
+;------------------------------------------------------------------------------
+; Bogus command
+;------------------------------------------------------------------------------
+TRYZ:
+ cmp ah, 0FFh ;AN029;
+ je TryFF ;AN029;
+ dec CHRPTR
+ inc COUNT
+ JMP BADOP
+
+;------------------------------------------------------------------------------
+; Null command
+;------------------------------------------------------------------------------
+TryFF: ;AN029;Skip this command.
+ jmp DoNothing ;AN029;
+
+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
+
+Incorrect_Order proc near ;AN000;
+;Show "Incorrect order in CONFIG.SYS ..." message.
+ mov dx, offset BADORDER ;AN000;
+ call print ;AN000;
+ call ShowLineNum ;AN000;
+ ret ;AN000;
+Incorrect_Order endp ;AN000;
+;
+ public Error_Line
+Error_Line proc near ;AN000;
+;Show "Error in CONFIG.SYS ..." message.
+ push cs ;AN000;
+ pop ds ;AN000;
+ mov dx, offset ErrorCmd ;AN000;
+ call print ;AN000;
+ call ShowLineNum ;AN000;
+ ret ;AN000;
+Error_Line endp ;AN000;
+;
+ShowLineNum proc near ;AN000;
+;J.K. Convert the binary LineCount to Decimal ASCII string in ShowCount
+;and Display Showcount at the current curser position.
+;In.) LineCount
+;
+;Out) the number is printed.
+ push es ;AN000;
+ push ds ;AN000;
+ push di ;AN000;
+
+ push cs ;AN000;
+ pop es ;AN000; es=cs
+ push cs ;AN000;
+ pop ds ;AN000;
+
+; mov ax, ' '
+; mov di, offset ShowCount ;clean it up.
+; stosw
+; stosw
+; stosb ;lenght of ShowCount is 5.
+; dec di ;let DI points to the least significant ASCII field.
+
+ mov di, offset ShowCount+4 ;AN000; DI -> the least significant decimal field.
+ mov cx, 10 ;AN000; decimal devide factor
+ mov ax, cs:LineCount ;AN000;
+SLN_Loop: ;AN000;
+ cmp ax, 10 ;AN000; < 10?
+ jb SLN_Last ;AN000;
+ xor dx,dx ;AN000;
+ div cx ;AN000;
+ or dl, 30h ;AN000; add "0" (= 30h) to make it an ascii.
+ mov [di],dl ;AN000;
+ dec di ;AN000;
+ jmp SLN_Loop ;AN000;
+SLN_Last: ;AN000;
+ or al, 30h ;AN000;
+ mov [di],al ;AN000;
+ mov dx, di ;AN000;
+ call print ;AN000; show it.
+ pop di ;AN000;
+ pop ds ;AN000;
+ pop es ;AN000;
+ ret ;AN000;
+ShowLineNum endp ;AN000;
+
+
+CallIFS proc near ;AN000;
+;*******************************************************************************
+; Function: Interface to IFS call. This procedure will call IFS_CALL@ *
+; *
+; Input : *
+; Entry_Point - Segment:Offset of loaded IFS. *
+; BX = IFS_CALL@ (offset of IFS_CALL@ from the IFS header) *
+; ES = Segment of IFS request header *
+; IFS_Packet - IFS Request packet *
+; *
+; Output: Nothing *
+;*******************************************************************************
+ push ax ;AN000;
+ mov ds, word ptr cs:[Entry_Point+2] ;AN000;
+ add bx, word ptr cs:[Entry_Point] ;AN000; DS:[BX] = Real IFS_CALL@ addr.
+ mov ax, ds:[bx] ;AN000; save it
+ push word ptr cs:[Entry_Point] ;AN000; save Entry point offset
+ mov word ptr cs:[Entry_Point], ax ;AN000; set for the call
+ mov bx, offset IFS_RH ;AN000; Now, ES:BX -> Request packet
+ call cs:[Entry_Point] ;AN000; Far call
+ pop word ptr cs:[Entry_Point] ;AN000; Restore Entry point offset
+ pop ax ;AN000;
+ ret ;AN000;
+CallIFS endp ;AN000;
+
+
+Set_DevMark proc near ;AN004;
+;*******************************************************************************
+; Function: Set a paragraph of informations infront of a Device file or *
+; an IFS file to be loaded for MEM command. *
+; The structure is: *
+; DEVMARK_ID byte "D" for device, "I" for IFS *
+; DEVMARK_SIZE size in para for the device loaded *
+; DEVMARK_FILENAME 11 bytes. Filename *
+; *
+; Input : *
+; [MEMHI] = address to set up DEVMARK. *
+; [MEMLO] = 0 *
+; ES:SI -> pointer to [drive][path]filename,0 *
+; [IFS_Flag] = IS_IFS bit set if IFS= command. *
+; *
+; Output: DEVMARK_ID, DEVMARK_FILENAME set *
+; cs:[DevMark_addr] set. *
+; AX, CX register destroyed. *
+;*******************************************************************************
+ push ds ;AN004;
+ push si ;AN004;
+ push es ;AN004;
+ push di ;AN004;
+
+ mov di, cs:[MEMHI] ;AN004;
+ mov ds, di ;AN004;
+ assume ds:nothing ;AN004;
+ mov [DevMark_Addr], di ;AN004; save the DEVMARK address for the future.
+ test [IFS_Flag], IS_IFS ;AN004;
+ jnz SDVMK_IFS ;AN004;
+ mov al, DEVMARK_DEVICE ;AN004; ='D'
+ jmp short SDVMK_ID ;AN004;
+SDVMK_IFS:
+ mov al, DEVMARK_IFS ;AN004; ='I'
+SDVMK_ID: ;AN004;
+ mov ds:[DEVMARK_ID], al ;AN004;
+ inc di ;AN008;
+ mov ds:[DEVMARK_SEG], di ;AN008;
+ xor al,al ;AN004;
+ push si ;AN004;
+ pop di ;AN004; now es:si = es:di = [path]filename,0
+ mov cx, 128 ;AN004; Maximum 128 char
+ repnz scasb ;AN004; find 0
+ dec di ;AN020; Now es:di-> 0
+SDVMK_Backward: ;AN004; find the pointer to the start of the filename.
+ mov al, byte ptr es:[di] ;AN004;;AN020;We do this by check es:di backward until
+ cmp al, '\' ;AN004;;AN020; DI = SI or DI -> '\' or DI -> ':'.
+ je SDVMK_GotFile ;AN004;;AN020;
+ cmp al, ':' ;AN004;
+ je SDVMK_GotFile ;AN004;
+ cmp di, si ;AN004;
+ je SDVMK_FilePtr ;AN004;
+ dec di ;AN004;
+ jmp SDVMK_BackWard ;AN004;
+SDVMK_GotFile: ;AN004;
+ inc di ;AN004;
+SDVMK_FilePtr: ;AN004; now es:di -> start of file name
+ push di ;AN004;
+ pop si ;AN004; save di to si.
+ push ds ;AN004; switch es, ds
+ push es ;AN004;
+ pop ds ;AN004;
+ pop es ;AN004; now, ds:si -> start of filename
+ mov di, DEVMARK_FILENAME ;AN004;
+ push di ;AN004;
+ mov al, ' ' ;AN004;
+ mov cx, 8 ;AN004;
+ rep stosb ;AN004; Clean up Memory.
+ pop di ;AN004;
+ mov cx, 8 ;AN004; Max 8 char. only
+SDVMK_Loop: ;AN004;
+ lodsb ;AN004;
+ cmp al, '.' ;AN004;
+ je SDVMK_Done ;AN004;
+ cmp al, 0 ;AN004;
+ je SDVMK_Done ;AN004;
+ stosb ;AN004;
+ loop SDVMK_Loop ;AN004;
+SDVMK_Done: ;AN004;
+ pop di ;AN004;
+ pop es ;AN004;
+ pop si ;AN004;
+ pop ds ;AN004;
+ ret ;AN004;
+Set_DevMark endp ;AN004;
+
+Chk_XMAEM proc near ;AN029;
+;Function: Check XMAEM.SYS file name.
+;In: ES:SI -> path, filename, 0
+;out: if XMAEM.SYS, then zero flag set.
+
+ push es ;AN029;
+ push si ;AN029;
+ push ds ;AN029;
+ push di ;AN029;
+ push cx ;AN029;
+ mov di, si ;AN029;save current starting pointer
+CX_Cmp: ;AN029;
+ cmp byte ptr es:[si], 0 ;AN029;
+ je CX_Endfile ;AN029;
+ inc si ;AN029;
+ jmp CX_Cmp ;AN029;
+CX_Endfile: ;AN029;
+ dec si ;AN029;
+ cmp byte ptr es:[si], '\' ;AN029;
+ je CX_Got_Tail ;AN029;
+ cmp byte ptr es:[si], ':' ;AN029;
+ je CX_Got_Tail ;AN029;
+ cmp di, si ;AN029;
+ je CX_Got_Tail0 ;AN029;
+ jmp CX_Endfile ;AN029;
+CX_Got_Tail: ;AN029;
+ inc si ;AN029;
+CX_Got_Tail0: ;AN029;
+ push cs ;AN029;
+ pop ds ;AN029;
+ push si ;AN029;
+ pop di ;AN029;now es:di -> filename,0
+ mov cx, 9 ;AN029;
+ mov si, offset XMAEM_File ;AN029;ds:si -> XMAEM.SYS,0
+ repe cmpsb ;AN029;
+CX_Ret: ;AN029;
+ pop cx ;AN029;
+ pop di ;AN029;
+ pop ds ;AN029;
+ pop si ;AN029;
+ pop es ;AN029;
+ ret ;AN029;
+Chk_XMAEM endp
+
+;Chk_IBMCACHE proc near ;AN024;AN026; Don't need this any more.
+ ; IBMDOS is going to handle this through 4Bh call.
+;Function: IBMCACHE.SYS does not handle a DOS version 4.0 or above.
+; So, this procedure will check if the device driver is IBMCACHE.SYS.
+; If it is, through new INT 2fh interface "Set/Restore DOS version"
+; AX=122Fh
+; DX= 0 ; reset
+; otherwise ; DH = minor version, DL = major version
+; INT 2fh
+;In: ES:SI -> path, filename, 0
+;out: if IBMCACHE.SYS, then DOS version changed to 4.00 temporarily.
+; Reset_Dos_Version proc will later reset it back to current DOS version 4.0.
+
+; push es ;AN024;
+; push si ;AN024;
+; push ds ;AN024;
+; push di ;AN024;
+; push cx ;AN024;
+; mov di, si ;AN024;save current starting pointer
+;CIC_Cmp: ;AN024;
+; cmp byte ptr es:[si], 0 ;AN024;
+; je CIC_Endfile ;AN024;
+; inc si ;AN024;
+; jmp CIC_Cmp ;AN024;
+;CIC_Endfile: ;AN024;
+; dec si ;AN024;
+; cmp byte ptr es:[si], '\' ;AN024;
+; je CIC_Got_Tail ;AN024;
+; cmp byte ptr es:[si], ':' ;AN024;
+; je CIC_Got_Tail ;AN024;
+; cmp di, si ;AN024;
+; je CIC_Got_Tail0 ;AN024;
+; jmp CIC_Endfile ;AN024;
+;CIC_Got_Tail: ;AN024;
+; inc si ;AN024;
+;CIC_Got_Tail0: ;AN024;
+; push cs ;AN024;
+; pop ds ;AN024;
+; push si ;AN024;
+; pop di ;AN024;now es:di -> filename,0
+; mov cx, 12 ;AN024;
+; mov si, offset IBMCACHE_File ;AN024;ds:si -> IBMCACHE.SYS,0
+; repe cmpsb ;AN024;
+; jnz CIC_ret ;AN024;
+; mov ax, 122Fh ;AN024;Change DOS version to
+; mov dx, 2803h ;AN024; DOS 3.4 temporarily.
+; int 2fh ;AN024;
+;CIC_Ret: ;AN024;
+; pop cx ;AN024;
+; pop di ;AN024;
+; pop ds ;AN024;
+; pop si ;AN024;
+; pop es ;AN024;
+; ret ;AN024;
+;Chk_IBMCACHE endp
+;
+
+Reset_DOS_Version proc near ;AN024;
+;Function: issue AX=122Fh, DX=0, INT 2fh to restore the DOS version.
+ push ax ;AN024;
+ push dx ;AN024;
+ mov ax, 122Fh ;AN024;
+ mov dx, 0 ;AN024;
+ int 2fh ;AN024;
+ pop dx ;AN024;
+ pop ax ;AN024;
+ ret ;AN024;
+Reset_DOS_Version endp
+
+
+;Int 2F EMS handler + Int 67h handler for EMS
+;=========================================================================
+; Int_2F_EMS - This routine provides support for VDISK,
+; FASTOPEN, and BUFFERS to determine the physical
+; EMS pages available for their usage.
+;
+; Inputs : AH - Function code (18h) to return available phys. page
+; DI - FEh (Signals to return useable page for VDISK & FASTOPEN)
+; FFh (Signals to return useable page for BUFFERS)
+;
+; AL = 0 is for installation check. - J.K.
+;
+; Outputs : ES - Segment value for physical page
+; DI - Physical Page number
+; AH - Non-zero (physical page not available)
+; Zero (valid physical page data returned)
+;
+; For installation check, AL = 0FFh for being present. - J.K.
+; For the other functions, AX = 0 for successful op.
+; AX = -1 for an error.
+;
+; Date : 5/5/88
+; Release : DOS 4.0
+;=========================================================================
+
+;Int_2F_Handler proc ;traps Int_2f and checks for EMS ;an000; dms;
+
+EMS_STUB_START label byte ;AN030;J.K.
+;Dummy DEVICE HEADER for other dummy ;AN031; Symphony assumes int 67h handler seg as a device driver!
+ DD -1 ;AN031;becomes pointer to next device header
+ DW 0C040H ;AN031;attribute (character device)
+ DW 0000 ;AN031;pointer to harzard area. System will hang.
+ DW 0000 ;AN031;pointer to harzard area. System will hang.
+ DB 'EMMXXXX0' ;AN031;device name
+
+INTV2F equ $-EMS_STUB_START ;AN030;J.K.pointer to old 2Fh handler ;an000; dms;
+IntV2FO DW ? ;AN030;;offset ;an000; dms;
+IntV2FS DW ? ;AN030;;segment ;an000; dms;
+
+OLDINT67_VECTOR equ $-EMS_STUB_START ;AN030;J.K.
+OldInt67 dd ? ;AN030;; save pointer to old INT 67 handler here
+
+IF BUFFERFLAG
+
+LOCKFLAG equ $-EMS_STUB_START
+LOCK_FLAG db ?
+
+ELSE
+
+EMSPAGE_CNT equ $-EMS_STUB_START ;AN030;J.K.
+EMSPageCount dw ? ;AN030;; save count of EMS mappable pages here
+
+EMSReservedArray_X label word ;AN030;;J.K. For initialization routine
+EMSRESERVEDARRAY equ $-EMS_STUB_START ;AN030;;J.K.
+ dw 0ffffh,0ffffh ;AN030;; array of reserved pages
+ dw 0ffffh,0ffffh ;AN030;; phys_page_segment, phys_page_number * 2 entries
+MappableArray_X label word ;AN030;;J.K. for initialization routine
+MAPPABLEARRAY equ $-EMS_STUB_START ;AN030;;J.K.
+ dw 64 dup (0,0) ;AN030;; table to get addresses from old INT 67 handler
+
+ENDIF
+ ; 64 entries * 2 words
+NEWEMS2F_OFF equ $-EMS_STUB_START;AN030;
+Int_2F_EMS: ;AN030;;J.K. Name changed.
+ cmp ah,1Bh ;AN030;;AN032;2Fh trap for Mappable Phys. Add. Array ;an000; dms;
+ je Int_2F_EMS_MINE ;AN030;;This one we want ;an000; dms;
+
+ jmp dword ptr cs:IntV2F ;AN030;;go to old interrupt handler ;an000; dms;
+
+Int_2F_EMS_MINE: ;AN030;
+ or al, al ;AN030;;J.K. Installation check?
+ jnz Int_2F_5800_Func ;AN030;;J.K.
+ mov al, 0FFh ;AN030;;J.K. Yes, I am here!
+ iret ;AN030;;J.K.
+
+Int_2F_5800_Func: ;AN030;
+
+IF BUFFERFLAG
+; int 3
+ cmp di, 80h
+ jne st_flag
+ mov byte ptr cs:LOCKFLAG, 0
+ jmp Int_2f_5800_Good_Exit
+st_flag:
+ cmp di, 81h
+ jne Int_2f_5800_Err_Exit
+ mov byte ptr cs:LOCKFLAG, 1
+ jmp Int_2f_5800_Good_Exit
+ELSE
+
+ push si ;AN030;; ;an000; dms;
+
+; mov si,offset EMSReservedArray ;point to array containing pages ;an000; dms;
+ mov si, EMSRESERVEDARRAY ;AN030;;J.K.
+
+ cmp di,0feh ;AN030;;VDISK or FASTOPEN request? ;an000; dms;
+ jne Int_2F_5800_Buff_Ck ;AN030;;no - check for buffers ;an000; dms;
+
+ cmp word ptr cs:[si],0ffffh ;AN030;;valid entry? ;an000; dms;
+ je Int_2F_5800_Err_Exit ;AN030;;no - exit ;an000; dms;
+
+ mov es,word ptr cs:[si] ;AN030;;get segment value ;an000; dms;
+ mov di,word ptr cs:[si+2] ;AN030;;get physical page value ;an000; dms;
+ jmp Int_2F_5800_Good_Exit ;AN030;;exit routine ;an000; dms;
+
+Int_2F_5800_Buff_Ck: ;AN030;
+
+ cmp di,0ffh ;AN030;;BUFFERS request? ;an000; dms;
+ jne Int_2F_5800_Err_Exit ;AN030;;no - exit with error ;an000; dms;
+
+ add si,4 ;AN030;;point to second element in array ;an000; dms;
+
+ cmp word ptr cs:[si],0ffffh ;AN034;;valid entry? ;an000; dms;
+ je Int_2F_5800_Err_Exit ;AN034;;no - exit ;an000; dms;
+
+ mov es,word ptr cs:[si] ;AN030;;get segment value ;an000; dms;
+ mov di,word ptr cs:[si+2] ;AN030;;get physical page value ;an000; dms;
+
+ENDIF
+
+Int_2F_5800_Good_Exit: ;AN030;
+
+ xor ax,ax ;AN030;;signal good return ;an000; dms;
+ jmp Int_2F_Exit ;AN030;;exit routine ;an000; dms;
+
+Int_2F_5800_Err_Exit: ;AN030;
+
+ mov ax,0ffffh ;AN030;;signal error ;an000; dms;
+
+Int_2F_Exit: ;AN030;
+
+
+IF NOT BUFFERFLAG
+ pop si ;AN030;;restore regs ;an000; dms;
+ENDIF
+ iret ;AN030;;return to caller ;an000; dms;
+
+
+
+;-------------------------------------------------------------------
+;
+; INT 67h Filter
+;
+; This routine filters INT 67's looking for AH=58h. When initialized,
+; the original INT 67 handler is called and the mappable address array
+; is changed to "reserve" two pages for DOS use. This new array is
+; then returned to the calling program when INT 67 AH=58h is found.
+;
+; Information about the two pages "reserved" for DOS is returned
+; via an unpublished INT 2Fh interface.
+;
+; 5/10/88 for DOS 4.0.
+;-------------------------------------------------------------------
+
+IF NOT BUFFERFLAG
+
+GetMappableArray equ 58h ; INT 67 function code for Get Mappable Array
+GetPageFrame equ 41h ; function code for getting the page frame address
+null equ 0 ; zero value
+I67Error8F equ 8fh ;AN031;; invalid sub-function error
+
+ENDIF
+
+;-------------------------------------------------------------------
+NEW67_OFFSET equ $-EMS_STUB_START ;J.K.
+Int67Filter: ;AN030;
+
+IF BUFFERFLAG
+; int 3
+ cmp byte ptr cs:LOCKFLAG, 1
+ jne PassThru
+ mov ah, 80h
+ stc
+ iret
+ELSE
+ cmp ah,GETMAPPABLEARRAY ;AN030;; is this the INT 67 call we are interested in?
+ jne PassThru ;AN030;; no, pass it to old INT 67 handler
+ ;AN030;; yes ...
+ cmp al,0 ;AN031;; AL=0 return count and table
+ je I67Fcn0
+
+ cmp al,1 ;AN031;; AL=1 return count only
+ jne I67Error ;AN031;; otherwise, error
+
+
+; return count of mappable pages
+
+ sti ;AN031;; turn interrupts on
+
+ mov cx,word ptr cs:EMSPAGE_CNT ;AN031;J.K. get number of mappable pages in fake table
+ xor ah,ah ;AN031;; good return code
+ iret
+
+; return invalid sub-function code
+
+I67Error:
+ sti ;AN031;; turn interrupts on
+ mov ah,I67Error8F ;AN031;; invalid sub-function error
+ iret
+
+
+I67Fcn0: ;AN031
+
+; copy the fake table to user's buffer
+
+ sti ;AN030;; turn interrupts on
+
+ push ds ;AN030; save some regs
+ push di ;AN030;
+ push si ;AN030;
+
+ mov cx,word ptr cs:EMSPAGE_CNT ;AN030;J.K. get number of mappable pages in fake table
+ shl cx,1 ;AN030;; count * 2 = number of words to copy
+
+ push cs ;AN030;; point DS:SI to fake table
+ pop ds ;AN030;
+; lea si,MappableArray
+ mov si, MAPPABLEARRAY ;AN030;;J.K.
+
+ rep movsw ;AN030;; copy CX words from DS:SI to ES:DI
+
+ xor ah,ah ;AN030;; good return code
+ mov cx,word ptr cs:EMSPAGE_CNT ;AN030;; page count returned to user in CX
+
+
+ pop si ;AN030;; restore some regs
+ pop di ;AN030;
+ pop ds ;AN030;
+
+ iret ;AN030;; end of INT 67 filter routine
+
+ENDIF
+
+;-------------------------------------------------------------------
+;
+; PassThru - send request to old INT 67 handler
+;
+;-------------------------------------------------------------------
+
+PassThru:
+ jmp dword ptr cs:OldINT67_VECTOR ;AN030;;J.K. jump to old INT 67 handler
+ ; (IRET will return to calling program)
+
+
+EMS_STUB_END label byte ;AN030;
+;-------------------------------------------------------------------
+
+IF NOT BUFFERFLAG
+;-------------------------------------------------------------------
+;
+; Int67FilterInit - This routine is called to initialize the INT 67
+; filter. It should be called as soon as possible after installation.
+;
+;-------------------------------------------------------------------
+
+Int67FilterInit: ;AN030;
+ push es ;AN030;; save caller's ES:DI
+ push di ;AN030;
+
+ push cs ;AN030;; make ES:DI point to our array
+ pop es ;AN030;
+ mov di,offset MappableArray_X ;AN030;
+
+; call dword ptr cs:OldInt67 ; get mappable array from EMS DD
+
+ mov ah, GetMappableArray ;AN030;
+ xor al,al ;AN030;
+ int 67h ;AN030;;J.K.
+
+
+;------------------------
+; scan table looking for highest phys_page_number
+
+ xor ax,ax ;AN030;;
+
+ cmp cx,0 ;AN033;; are the any pages left?
+ je NoMoreEMSPages ;AN033;; no, don't bother looking any more
+
+ call GetHighestPage ;AN030;; get highest entry from table
+
+ mov EMSReservedArray_X+4,bx ;AN030;; phys_page_segment
+ mov EMSReservedArray_X+6,ax ;AN030;; phys_page_number
+
+ cmp cx,0 ;AN033;; are the any pages left?
+ je NoMoreEMSPages ;AN033;; no, don't bother looking any more
+
+ call GetHighestPage ;AN030;; get next highest entry from table
+
+ mov EMSReservedArray_X+0,bx ;AN030;; phys_page_segment
+ mov EMSReservedArray_X+2,ax ;AN030;; phys_page_number
+
+NoMoreEMSPages: ;AN033;;
+ mov EMSPageCount,cx ;AN030;; save new page count for INT 67 filter
+
+ pop di
+ pop es
+ ret ;AN030;; return to calling program
+
+
+ page
+;-------------------------------------------------------------------
+;
+; GetHighestPage - returns highest physical page number in AX
+; and segment for it in BX. A -1 means no valid page found.
+;
+;-------------------------------------------------------------------
+GetHighestPage:
+
+ xor ax,ax ;AN030;; zero candidate register
+ mov bx,ax ;AN030;; zero pointer to candidate page
+
+ push cx ;AN030;; save count
+ push dx ;AN030;
+ push di ;AN030;; save pointer
+
+PageScanLoop: ;AN030;
+ cmp ax,ES:[di+2] ;AN030;; get phys_page_number
+ ja LookAtNextPage ;AN030;; this one is lower than the one we are holding
+
+ cmp es:[di], 0a000h ; Only reserve pages in memory above 640K..
+ jb LookAtNextPage ; fix for ps2emm and m20emm with motherboard
+ ; disabled. 7/25/88. HKN.
+
+ mov ax,ES:[di+2] ;AN030;; this one is higher, make it new candidate
+ mov bx,di ;AN030;; pointer to new candidate page, used to zero
+ ; it later so we don't get the same one again
+ mov dx,cx ;AN030;; save count where we found candidate
+
+LookAtNextPage: ;AN030;
+ add di,4 ;AN030;; point to next entry in mappable table
+
+ loop PageScanLoop ;AN030;; look at next entry
+
+ cmp bx,null ;AN030;; did we find any pages?
+ jne FoundOne ;AN030;; yes, exit
+
+ jmp ReturnError ;AN030;
+
+;------------------------
+FoundOne: ;AN030;
+ cmp ax,3 ;AN030;; could the one we found be part of a page frame
+ ja NotFrame ;AN030;; no, carry on
+
+; yes, find out if it is part of frame
+
+ push ax ;AN030;; save physical page number
+ push bx ;an030;; dms; bx destroyed by call
+ mov ah,GetPageFrame ;AN030;; function code to get page frame ...
+; call dword ptr cs:OldInt67 ; ... from the EMS DD
+ int 67h ;AN030;;J.K.
+ or ah,ah ;an030;;dms; error?
+ pop bx ;an030;;dms; restore bx
+ pop ax ;AN030;; restore phys page number
+ jnz NotFrame ;AN030;; no frame available, carry on
+
+; there is a frame, this page is part of frame, so return -1's
+
+ReturnError: ;AN030;
+ mov ax,0ffffh ;AN030;; indicate failure
+ mov bx,ax ;AN030;; ax and bx = -1
+
+ pop di ;AN030;; restore pointer
+ pop dx
+ pop cx ;AN030;; restore count
+
+ jmp GHPExit ;AN030;
+
+
+
+
+;------------------------
+; Found a page, and it is not part of a page frame, so re-pack table
+; and return info. The entry we "reserve" for DOS must be removed
+; from the table and the other entries moved up to repack the table.
+; The count must be reduced by 1 to reflect this change.
+
+Notframe: ;AN030;
+
+ mov di,bx ;AN030;; make ES:DI point to highest page table entry
+
+ mov bx,ES:[di] ;AN030;; get segment address of page
+
+ mov cx,dx ;AN030;; get count from candidate page
+
+ push ax ;AN030;
+PackLoop: ;AN030;
+ mov ax, es:[di+4] ;AN030;
+ mov es:[di+0], ax ;AN030;
+ mov ax, es:[di+6] ;AN030;
+ mov es:[di+2], ax ;AN030;
+ add di, 4 ;AN030;
+ loop PackLoop ;AN030;; do it until done
+ pop ax ;AN030;
+
+ pop di ;AN030;; restore pointer
+ pop dx ;AN030;
+ pop cx ;AN030;; restore count
+
+ sub cx,1 ;AN030;; reduce count by one, one less page in table now
+
+GHPExit: ;AN030;
+
+ ret ;AN030;; return to caller
+
+ENDIF
+
+;=========================================================================
+; EMS_Install_Check : THIS MODULE DETERMINES WHETHER OR NOT EMS IS
+; INSTALLED FOR THIS SESSION.
+;
+; INPUTS : NONE
+;
+; OUTPUTS : ES:BX - FRAME ARRAY
+; CY - EMS NOT AVAILABLE
+; NC - EMS AVAILABLE
+;
+; Date : 5/6/88
+;=========================================================================
+
+EMS_Install_Check proc near ;AN030;; check if EMS is installed ;an000; dms;
+
+ push ax ;AN030;; save regs ;an000; dms;
+
+ push ds ;AN030;; save ds ;an000; dms;
+ xor ax,ax ;AN030;; set ax to 0 ;an000; dms;
+ mov ds,ax ;AN030;; set ds to 0 ;an000; dms;
+ cmp ds:word ptr[067h*4+0],0 ;AN030;; see if int 67h is there ;an000; dms;
+ pop ds ;AN030;; restore ds ;an000; dms;
+ je EMS_Install_Ck_Err_Exit ;AN030;; exit routine - EMS not loaded ;an000; dms;
+
+ mov ah,40h ;AN030;; Get Status function ;an000; dms;
+ xor al,al ;AN030;; clear al ;an000; dms;
+ int 67h ;AN030;; ;an000; dms;
+ or ah,ah ;AN030;; EMS installed? ;an000; dms;
+ jnz EMS_Install_Ck_Err_Exit ;AN030;; exit routine - EMS not loaded ;an000; dms;
+
+ mov ah,46h ;AN030;; Get Version number ;an000; dms;
+ xor al,al ;AN030;; clear al ;an000; dms;
+ int 67h ;AN030;; ;an000; dms;
+ cmp al,40h ;AN030;; Version 4.0? ;an000; dms;
+ jb EMS_Install_Ck_Err_Exit ;AN030;; exit routine - wrong EMS loaded ;an000; dms;
+
+ clc ;AN030;; signal EMS loaded ;an000; dms;
+ jmp EMS_Install_Ck_Exit ;AN030;; exit routine ;an000; dms;
+
+EMS_Install_Ck_Err_Exit: ;AN030;
+
+ stc ;AN030;; signal EMS not loaded ;an000; dms;
+
+EMS_Install_Ck_Exit: ;AN030;
+
+ pop ax ;AN030;; restore regs ;an000; dms;
+
+ ret ;AN030;; return to caller ;an000; dms;
+
+EMS_Install_Check endp ; ;an000; dms;
+
+EMS_Stub_Handler proc near ;AN030;
+;At the request of Architecture Group, this logic is implemented.
+;Function: If (Buffer_Slash_X <> 0 and EMS_Stub_Installed == 0),
+; then { call Chk_EMS;
+; if EMS is there, then install EMS_Stub dynamically
+; and initialize it.}
+; Note: EMS_Stub consists of INT 2fh EMS handler and INT 67h handler.
+; When EMS_Stub is installed, EMS_Stub_Installed will be set to 1.
+
+ push es ;AN030;
+ push si ;AN030;
+ push ds ;AN030;
+ push di ;AN030;
+ push ax ;AN030;
+ push cx ;AN030;
+ cmp EMS_Stub_Installed, 0 ;AN030;
+ je EMS_Stub_X ;AN030;
+ jmp EMS_SH_Ret ;AN030;
+EMS_Stub_X: ;AN030;
+ cmp Buffer_Slash_X, 0 ;AN030;
+ je EMS_SH_Ret ;AN030;
+ call EMS_Install_Check ;AN030;
+ jc EMS_SH_Ret ;AN030;
+;Install EMS_Stub. ;AN030;
+EMS_Stub_Do:
+ push es ;AN030;
+ xor ax,ax ;AN030;save current Int 2fh, 67h vectors.
+ mov es, ax ;AN030;
+ mov ax, word ptr es:[2fh*4] ;AN030;
+ mov IntV2FO, ax ;AN030;
+ mov ax, word ptr es:[2fh*4+2] ;AN030;
+ mov IntV2FS, ax ;AN030;
+ mov ax, word ptr es:[67h*4] ;AN030;
+ mov word ptr cs:[OldInt67], ax ;AN030;
+ mov ax, word ptr es:[67h*4+2] ;AN030;
+ mov word ptr cs:[OldInt67+2], ax ;AN030;
+ pop es ;AN030;
+
+IF NOT BUFFERFLAG
+;initalize tables in INT 67h handler
+ call Int67FilterInit ;AN030;
+ cmp ax, 0ffffh ; if the page found was part of a lim 4.0 page frame
+ je EMS_SH_ret ; do not install stub. 7/24/88. HKN
+ENDIF
+ call Round ;AN030;
+ mov ax, DEVMARK_EMS_STUB ;AN030;
+ call SetDevMark ;AN030;
+ mov ax, [memhi] ;AN030;
+ mov es, ax ;AN030;
+ assume es:nothing ;AN030;
+ xor di, di ;AN030;
+ push cs ;AN030;
+ pop ds ;AN030;
+ mov cx, offset EMS_STUB_END ;AN030;
+ mov si, offset EMS_STUB_START ;AN030;
+ sub cx, si ;AN030;cx = size in byte
+ mov [memlo], cx ;AN030;
+ rep movsb ;AN030;
+ or [SetDevMarkFlag], FOR_DEVMARK ;AN030;set the devmark_size for MEM command.
+ call Round ;AN030;and get the next [memhi] avaiable.
+ mov EMS_Stub_Installed, 1 ;AN030;
+
+ xor ax, ax ;AN030;
+ mov ds, ax ;AN030;
+ cli ;AN030;
+ mov word ptr ds:[2Fh*4],NEWEMS2F_OFF;AN030;set the new int 2fh, 67h vectors.
+ mov word ptr ds:[2Fh*4+2], es ;AN030;
+ mov word ptr ds:[67h*4],NEW67_OFFSET;AN030;
+ mov word ptr ds:[67h*4+2], es ;AN030;
+ sti ;AN030;
+EMS_SH_Ret: ;AN030;
+ pop cx ;AN030;
+ pop ax ;AN030;
+ pop di ;AN030;
+ pop ds ;AN030;
+ pop si ;AN030;
+ pop es ;AN030;
+ ret ;AN030;
+
+EMS_Stub_Handler endp ;AN030;
+
+
+SYSINITSEG ENDS
+ END
+
\ No newline at end of file
diff --git a/v4.0/src/BIOS/SYSIMES.ASM b/v4.0/src/BIOS/SYSIMES.ASM
new file mode 100644
index 0000000..0640282
--- /dev/null
+++ b/v4.0/src/BIOS/SYSIMES.ASM
@@ -0,0 +1,38 @@
+ ;SCCSID = @(#)sysimes.asm 1.2 85/07/25
+%OUT ...SYSIMES
+
+;==============================================================================
+;REVISION HISTORY:
+;AN000 - New for DOS Version 4.00 - J.K.
+;AC000 - Changed for DOS Version 4.00 - J.K.
+;AN00x - PTM number for DOS Version 4.00 - J.K.
+;==============================================================================
+;AN001 D246, P976 Show "Bad command or parameters - ..." msg 9/22/87 J.K.
+;AN002 P1820 New Message SKL file 10/20/87 J.K.
+;AN003 D486 Share installation for large media 02/24/88 J.K.
+;==============================================================================
+
+iTEST = 0
+include MSequ.INC
+include MSmacro.INC
+
+SYSINITSEG SEGMENT PUBLIC BYTE 'SYSTEM_INIT'
+
+ PUBLIC BADOPM,CRLFM,BADSIZ_PRE,BADLD_PRE,BADCOM,SYSSIZE,BADCOUNTRY
+; PUBLIC BADLD_POST,BADSIZ_POST,BADMEM,BADBLOCK,BADSTACK
+ PUBLIC BADMEM,BADBLOCK,BADSTACK
+ PUBLIC INSUFMEMORY,BADCOUNTRYCOM
+ public BadOrder,Errorcmd ;AN000;
+ public BadParm ;AN001;
+ public SHAREWARNMSG ;AN003;
+
+
+;include sysimes.inc
+include MSbio.cl3 ;AN002;
+
+SYSSIZE LABEL BYTE
+
+PATHEND 001,SYSMES
+
+SYSINITSEG ENDS
+ END
diff --git a/v4.0/src/BIOS/SYSINIT1.ASM b/v4.0/src/BIOS/SYSINIT1.ASM
new file mode 100644
index 0000000..7869b76
--- /dev/null
+++ b/v4.0/src/BIOS/SYSINIT1.ASM
@@ -0,0 +1,2668 @@
+ PAGE ,132 ;
+; SCCSID = @(#)sysinit1.asm 1.7 85/10/24
+TITLE BIOS SYSTEM INITIALIZATION
+%OUT ...SYSINIT1
+;==============================================================================
+;REVISION HISTORY:
+;AN000 - New for DOS Version 4.00 - J.K.
+;AC000 - Changed for DOS Version 4.00 - J.K.
+;AN00x - PTM number for DOS Version 4.00 - J.K.
+;==============================================================================
+;AN001; p40 Boot from the system with no floppy diskette drives 6/26/87 J.K.
+;AN002; d24 MultiTrack= command added. 6/29/87 J.K.
+;AN003; d9 Double word mov for 386 machine 7/15/87 J.K.
+;AN004; p447 BUFFERS = 50 /E without EMS installed hangs 8/25/87 J.K.
+;AN005; d184 Set DEVMARK for MEM command 8/25/87 J.K.
+;AN006; p851 Installable files not recognized corretly. 9/08/87 J.K.
+;AN007; p1299 Set the second entry of DEVMARK for MEM command 9/25/87 J.K.
+;AN008; p1361 New Extended Attribute 9/28/87 J.K.
+;AN009; p1326 Buffers = 50 /e hangs 9/28/87 J.K.
+;AN010; New EMS Interface
+;AN011; New Message SKL file 10/20/87 J.K.
+;AN012; P2211 Setting EA=7 for ANSI.SYS hangs the system 11/02/87 J.K.
+;AN013; p2343 Set the name for SYSINIT_BASE for MEM command 11/11/87 J.K.
+;AN014; D358 New device driver INIT function package 12/03/87 J.K.
+;AN015; For Installed module with no parameter 12/11/87 J.K.
+;AN016; D285 Undo the Extended Attribute handling 12/17/87 J.K.
+;AN017; P2806 Show "Error in CONFIG.SYS ..." for INSTALL= command 12/17/87 J.K.
+;AN018; P2914 Add Extended Memory Size in SYSVAR 01/05/88 J.K.
+;AN019; P3111 Take out the order dependency of the INSTALL= 01/25/88 J.K.
+;AN020; P3497 Performace fix for new buffer scheme 02/15/88 J.K.
+;AN021; D486 SHARE installation for big media 02/23/88 J.K.
+;AN022; D493 Undo D358 & do not show error message for device driv02/24/88 J.K.
+;AN023; D474 Change BUFFERS= /E option to /X for expanded memory 03/16/88 J.K.
+;AN024; D506 Take out the order dependency of the IFS= 03/28/88 J.K.
+;AN025; P4086 Memory allocation error when loading SHARE.EXE 03/31/88 J.K.
+;AN026; D517 New Balanced Real memory buffer set up scheme 04/18/88 J.K.
+;AN027; D528 Install XMAEM.SYS first before everything else 04/29/88 J.K.
+;AN028; P4669 SHARE /NC causes an error 05/03/88 J.K.
+;AN029; P4759 Install EMS INT2fh, INT 67h handler 05/12/88 J.K.
+;AN030; P4934 P4759 INT 2Fh handler number be changed to 1Bh 05/20/88 J.K.
+;==============================================================================
+
+TRUE EQU 0FFFFh
+FALSE EQU 0
+CR equ 13
+LF equ 10
+TAB equ 9
+
+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
+MYCDS_SIZE equ 88 ;J.K. Size of Curdir_List. If it is not
+ ;the same, then will generate compile error.
+
+;
+ IF IBMJAPVER
+NOEXEC EQU TRUE
+ ELSE
+NOEXEC EQU FALSE
+ ENDIF
+
+DOSSIZE EQU 0A000H
+;dossize equ 0C000H ;J.K. for the debugging version of IBMDOS.
+
+.xlist
+; INCLUDE dossym.INC
+ include smdossym.inc ;J.K. Reduced version of DOSSYM.INC
+ INCLUDE devsym.INC
+ include ioctl.INC
+ include BIOSTRUC.INC
+ include smifssym.inc ;AN000;
+ include defems.inc ;AN010;
+ include DEVMARK.inc ;AN005;
+ include cputype.inc
+
+ include version.inc
+
+.list
+
+;AN000 J.K. If MYCDS_SIZE <> CURDIRLEN, then force a compilatiaon error.
+ if MYCDS_SIZE NE CURDIRLEN
+ %OUT !!! SYSINIT1 COMPILATION FAILED. DIFFERENT CDS SIZE !!!
+ .ERRE MYCDS_SIZE EQ CURDIRLEN
+ endif
+
+ IF NOT IBMJAPVER
+ EXTRN RE_INIT:FAR
+ ENDIF
+
+;---------------------------------------
+;Equates for Main stack and stack Initialization program
+ IF STACKSW
+
+EntrySize equ 8
+
+MinCount equ 8
+DefaultCount equ 9
+MaxCount equ 64
+
+MinSize equ 32
+DefaultSize equ 128
+MaxSize equ 512
+
+AllocByte equ es:byte ptr [bp+0]
+IntLevel equ es:byte ptr [bp+1]
+SavedSP equ es:word ptr [bp+2]
+SavedSS equ es:word ptr [bp+4]
+NewSP equ es:word ptr [bp+6]
+Free equ 0
+allocated equ 1
+overflowed equ 2
+clobbered equ 3
+
+
+;External variables in IBMBIO for INT19h handling rouitne. J.K. 10/23/86
+CODE segment public 'code'
+ EXTRN Int19sem:byte
+
+ IRP AA,<02,08,09,0A,0B,0C,0D,0E,70,72,73,74,76,77>
+ EXTRN Int19OLD&AA:dword
+ ENDM
+CODE ends
+ ENDIF
+;---------------------------------------
+;J.K. 6/29/87 External variable defined in IBMBIO module for Multi-track
+MULTRK_ON EQU 10000000B ;User spcified Mutitrack=on, or System turns
+ ; it on after handling CONFIG.SYS file as a
+ ; default value, if MulTrk_flag = MULTRK_OFF1.
+MULTRK_OFF1 EQU 00000000B ;initial value. No "Multitrack=" command entered.
+MULTRK_OFF2 EQU 00000001B ;User specified Multitrack=off.
+
+CODE segment public 'code'
+ EXTRN MulTrk_flag:word ;AN002;
+CODE ends
+;J.K. 6/29/87 End of Multi-track definition.
+
+SYSINITSEG SEGMENT PUBLIC 'SYSTEM_INIT'
+
+ASSUME CS:SYSINITSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
+
+ EXTRN BADCOM:BYTE
+ EXTRN SYSSIZE:BYTE
+ EXTRN CONDEV:BYTE,AUXDEV:BYTE,PRNDEV:BYTE,COMMND:BYTE
+ extrn DeviceParameters:byte
+ extrn DevMark_Addr:word
+ extrn SetDevMarkFlag:byte
+ extrn PathString:byte ;AN021;
+ extrn LShare:byte ;AN021;
+ extrn ShareWarnMsg:byte ;AN021;
+
+ EXTRN INT24:NEAR,MEM_ERR:NEAR
+ EXTRN DOCONF:NEAR
+ extrn Multi_Pass:NEAR ;AN024;
+ extrn BadLoad:near
+ extrn Error_Line:near
+
+ PUBLIC CURRENT_DOS_LOCATION
+ PUBLIC FINAL_DOS_LOCATION
+ PUBLIC DEVICE_LIST
+ PUBLIC SYSI_COUNTRY
+ PUBLIC MEMORY_SIZE
+ PUBLIC DEFAULT_DRIVE
+ PUBLIC BUFFERS
+ PUBLIC FILES
+ PUBLIC NUM_CDS
+ PUBLIC SYSINIT
+ PUBLIC CNTRYFILEHANDLE
+ PUBLIC COMMAND_LINE
+ public Big_Media_Flag ;AN021;Set by IBMINIT
+
+ 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,org_count
+ PUBLIC bufptr,memlo,prmblk,memhi
+ PUBLIC ldoff,area,PACKET,UNITCOUNT
+ PUBLIC BREAK_ADDR,BPB_ADDR,drivenumber
+ public Config_Size
+ public Install_Flag
+ public COM_Level
+ public CMMT
+ public CMMT1
+ public CMMT2
+ public Cmd_Indicator
+ public LineCount
+ public ShowCount
+ public Buffer_LineNum
+ public DoNotShowNum
+ public IFS_Flag
+ public IFS_RH
+ public H_Buffers
+ public Buffer_Slash_X ;AN023;
+ public ConfigMsgFlag ;AN014;
+ public Do_Install_Exec ;AN019;
+ public Multi_Pass_Id ;AN024;
+
+
+;
+SYSINIT$:
+ IF STACKSW
+.SALL
+ include MSSTACK.INC ;Main stack program and data definitions
+; include STKMES.INC ;Fatal stack error message
+ include MSBIO.CL5 ;Fatal stack error message
+.XALL
+ public Endstackcode
+Endstackcode label byte
+ ENDIF
+
+;
+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 ;J.K. 5/29/86 Pointer to
+ DW 0000 ;country table in DOS
+ DW 0000
+
+Fake_Floppy_Drv db 0 ;AN001;Set to 1 if this machine
+ ;does not have any floppies!!!
+Big_Media_Flag db 0 ;AN021;Set by IBMINIT if > 32 MB fixed media exist.
+;
+;Variables for Stack Initialization Program.
+ IF STACKSW
+STACK_COUNT DW DefaultCount
+STACK_SIZE DW DefaultSize
+STACK_ADDR DD 00000000
+ ENDIF
+; various default values
+
+MEMORY_SIZE DW 0001
+DEFAULT_DRIVE DB 00 ;initialized by IBMINIT.
+BUFFERS DW -1 ; initialized during buffer allocation
+H_Buffers dw 0 ;AN000; # of the Heuristic buffers. Initially 0.
+Buffer_Pages dw 0 ;AN000; # of extended memory pages for the buffer.
+BufferBuckets dw 0 ;AN000;
+Buffer_odds dw 0 ;AN000;
+SingleBufferSize dw ? ;AN000; Maximum sector size + buffer header
+MaxNumBuf1 db 15 ;AN026;Num of buffers in a bucket group 1.
+MaxNumBuf2 db 15 ;AN026;Num of buffers in a possible bucket group 2.
+NthBuck db 0 ;AN026; 1st bucket group = 1st bucket through Nth Bucket. The rest = second group
+
+IF BUFFERFLAG
+
+FIRST_PAGE DW 0, 0
+LAST_PAGE DW 0, 0
+NPA640 DW 0
+EMS_SAVE_BUF DB 0,0,0,0,0,0,0,0,0,0,0,0
+
+ENDIF
+
+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
+LineCount dw 0 ;AN000; Line count in config.sys
+ShowCount db ' ',CR,LF,'$' ;AN000; Used to convert Linecount to ASCII.
+Buffer_LineNum dw 0 ;AN000; Line count for "BUFFERS=" command if entered.
+
+Sys_Model_Byte db 0FFh ;model byte used in SYSINIT
+Sys_Scnd_Model_Byte db 0 ;secondary model byte used in SYSINIT
+;
+Buffer_Slash_X db 0 ;AN000;AN023; BUFFERS= ... /X option entered.
+Real_IBM_Page_Id dw 0 ;AN029;
+IBM_Frame_Seg dw 0 ;AN000; segment value for physical IBM page frame.
+Frame_Info_Buffer dw (MAX_NUM_PAGEFRAME * 4) dup (0) ;AN010; For EMS. as per spec. 2 words per entry
+EMSHandleName db 'BUFFERS ' ;AN010; 8 char. EMS handle name
+EMS_Ctrl_Tab dd 0 ;AN010;
+EMS_State_Buf dd 0 ;AN010;
+BUF_PREV_OFF dw 0 ;AN020;
+EMS_Buf_First dw 0 ;AN020;
+
+ IF NOT NOEXEC
+COMEXE EXEC0 <0,COMMAND_LINE,DEFAULT_DRIVE,ZERO>
+ ENDIF
+
+;------------------------------------------------------------------
+;J.K. 2/23/87 ;variables for INSTALL= command.
+
+Multi_Pass_Id db 0 ;AN024;AN027;
+Install_Flag dw 0 ;AN000;
+ HAVE_INSTALL_CMD equ 00000001b ;AN019; CONFIG.SYS has INSTALL= commands
+ HAS_INSTALLED equ 00000010b ;AN019; SYSINIT_BASE installed.
+ SHARE_INSTALL equ 00000100b ;AN021; Used to install SHARE.EXE
+
+Config_Size dw 0 ;AN000; size of config.sys file. Set by SYSCONF.ASM
+Sysinit_Base_Ptr dd 0 ;AN000; pointer to SYSINIT_BASE
+Sysinit_Ptr dd 0 ;AN000; returning addr. from SYSINIT_BASE
+CheckSum dw 0 ;AN000; Used by Sum_up
+
+Ldexec_FCB db 20 dup (' ') ;AN000;big enough
+Ldexec_Line db 0 ;AN000;# of parm characters
+Ldexec_start db ' ' ;AN000;
+Ldexec_parm db 80 dup (0) ;AN000;
+
+INSTEXE EXEC0 <0,Ldexec_Line,Ldexec_FCB,Ldexec_FCB> ;AN000;
+
+;AN016; Undo the extended attribute handling
+;EA_QueryList label byte
+; dw 1 ;AN008; I need just one EA info.
+; db 02h ;AN008; Type is BINARY
+; dw 8000h ;AN008; Flag is SYSTEM DEFINED.
+; db 8 ;AN008; Length of name is 8 bytes
+; db 'FILETYPE' ;AN008; Name is FILETYPE
+;Ext_Attr_List dw 1 ;AN008; Just 1 Extended attribute List
+; db 2 ;AN008;EA_TYPE
+; dw 8000h ;AN008;FLAG
+; db 0 ;AN008;Failure reason
+; db 8 ;AN008;Length of NAME
+; dw 1 ;AN008;Length of VALUE
+; db 'FILETYPE' ;AN008;Name
+;Ext_Attr_Value db 0 ;AN008;Value
+;SIZE_EXT_ATTR_LIST equ $-Ext_Attr_List ;AN008;
+;
+;;Extended attribute value
+;EA_INSTALLABLE equ 4 ;AN008;Value for Installable file
+
+;------------------------------------------------------------------
+;J.K. 5/15/87 ;Request header, variables for IFS= command.
+
+IFS_Flag dw 0 ;AN000; Set to 1 if it is an IFS.
+ IS_IFS equ 00000001b ;IFS command?
+ NOT_IFS equ 11111110b
+
+IFS_RH IFSRH ;AN000; IFS initialization request packet
+
+;------------------------------------------------------------------
+;Variables for Comment=
+COM_Level db 0 ;AN000;level of " " in command line
+CMMT db 0 ;AN000;length of COMMENT string token
+CMMT1 db 0 ;AN000;token
+CMMT2 db 0 ;AN000;token
+Cmd_Indicator db ? ;AN000;
+DoNotShowNum db 0 ;AN000;
+
+;------------------------------------------------------------------
+COUNT DW 0000
+Org_Count dw 0000 ;AN019;
+CHRPTR DW 0000
+CntryFilehandle DW 0000
+Old_Area dw 0 ;AN013;
+Impossible_Owner_Size dw 0 ;AN013; Paragraph
+;------------------------------------------------------------------
+BucketPTR LABEL dword ;AN000;
+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 24 ;AN014; Was 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
+ConfigMsgFlag dw 0 ;AN014;AN022; Used to control "Error in CONFIG.SYS line #" message
+
+TempStack DB 80h DUP (?)
+
+GOINIT:
+;J.K. before doing anything else, let's set the model byte
+;SB33043*****************************************************************
+ mov ah,0c0h ;get system configuration ;SB ;3.30*
+ int 15h ; * ;SB ;3.30*
+;SB33043*****************************************************************
+ jc No_ROM_Config
+ cmp ah, 0 ; double check
+ jne No_ROM_Config
+ mov al, ES:[BX.bios_SD_modelbyte]
+ mov cs:[Sys_Model_Byte], al
+ mov al, ES:[BX.bios_SD_scnd_modelbyte]
+ mov cs:[Sys_Scnd_Model_Byte], al
+ jmp short Move_Myself
+No_ROM_Config: ; Old ROM
+ mov ax, 0f000h
+ mov ds, ax
+ mov al, byte ptr ds:[0fffeh]
+ mov cs:[Sys_Model_Byte], al ;set the model byte.
+;J.K.6/24/87 Set Fake_Floppy_Drv if there is no diskette drives in this machine.
+;SB34SYSINIT1001********************************************************
+;SB execute the equipment determination interrupt and then
+;SB check the returned value to see if we have any floppy drives
+;SB if we have no floppy drive we set cs:Fake_Floppy_Drv to 1
+;SB See the AT Tech Ref BIOS listings for help on the equipment
+;SB flag interrupt (11h)
+
+ int 11h
+ test ax,1 ; has floppy ?
+ jnz Move_Myself
+ mov cs:Fake_Floppy_Drv,1 ; no floppy, fake.
+
+;SB34SYSINIT1001********************************************************
+Move_Myself:
+ CLD ; Set up move
+ XOR SI,SI
+ MOV DI,SI
+
+ IF MSVER
+ MOV CX,cs:[MEMORY_SIZE]
+ 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
+ RET
+AAA_DUMMY ENDP
+;
+; 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)
+ MOV DS,AX
+ MOV AX,[FINAL_DOS_LOCATION] ; Where it is going (set by BIOS)
+ 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
+ ;ES:DI -> SysInitVars_Ext
+ mov ax, word ptr es:[di.SYSI_InitVars] ;J.K. 5/29/86
+ mov word ptr [dosinfo], ax
+ mov ax, word ptr es:[di.SYSI_InitVars+2]
+ mov word ptr [dosinfo+2],ax ;set the sysvar pointer
+
+ mov ax, word ptr es:[di.SYSI_Country_Tab]
+ mov word ptr [SYSI_Country],ax
+ mov ax, word ptr es:[di.SYSI_Country_Tab+2]
+ mov word ptr [SYSI_Country+2],ax ;set the SYSI_Country pointer J.K.
+
+ les di, dosinfo ;es:di -> dosinfo
+
+ clc ;AN018;Get the extended memory size
+;SB34SYSINIT1002**************************************************************
+;SB execute the get extended memory size subfunction in the BIOS INT 15h
+;SB if the function reports an error do nothing else store the extended
+;SB memory size reported at the appropriate location in the dosinfo buffer
+;SB currently pointed to by es:di. Use the offsets specified in the
+;SB definition of the sysinitvars struct in inc\sysvar.inc
+;SB 5 LOCS
+
+ mov ah,88h
+ int 15h ;check extended memory size
+ jc No_Ext_Memory
+ mov es:[di].SYSI_EXT_MEM,ax ;save extended memory size
+No_Ext_Memory:
+
+;SB34SYSINIT1002**************************************************************
+ mov word ptr es:[di.SYSI_IFS], -1 ;AN000; Initialize SYSI_IFS chain.
+ mov word ptr es:[di.SYSI_IFS+2], -1 ;AN000;
+
+ mov ax, es:[di.SYSI_MAXSEC] ;AN020; Get the sector size
+ add ax, BUFINSIZ ;AN020; size of buffer header
+ mov [SingleBufferSize], ax ;AN020; total size for a buffer
+
+ mov al, Default_Drive ;AN000;Get the 1 based boot drive number set by IBMINIT
+ mov es:[di.SYSI_BOOT_DRIVE], al ;AN000; set SYSI_BOOT_DRIVE
+
+; Determine if 386 system...
+ Get_CPU_Type ; macro to determine cpu type
+ cmp ax, 2 ; is it a 386?
+ jne Not_386_System ; no: don't mess with flag
+ mov es:[di.SYSI_DWMOVE], 1 ;AN003;
+Not_386_System: ;AN003;
+ 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 cx, [SingleBufferSize] ;AN020;Temporary Single buffer area
+ shr cx, 1 ;AN020;
+ shr cx, 1 ;AN020;
+ shr cx, 1 ;AN020;
+ shr cx, 1 ;AN020; Paragraphs
+ inc cx ;AN020;
+ sub ax, cx ;AN020;
+ MOV [CONFBOT],AX ; Temp "unsafe" location
+
+ push es ;AN020;
+ push di ;AN020;
+ les di, es:[di.SYSI_BUF] ;AN020;get the buffer hash entry pointer
+ les di, es:[di.HASH_PTR] ;AN020;
+ mov word ptr es:[di.BUFFER_BUCKET],0 ;AN020;
+ mov word ptr es:[di.BUFFER_BUCKET+2], ax ;AN020;
+ mov es, ax ;AN020;
+ xor ax, ax ;AN020;
+ mov di, ax ;AN020;es:di -> Single buffer
+ mov es:[di.BUF_NEXT], ax ;AN020;points to itself
+ mov es:[di.BUF_PREV], ax ;AN020;points to itself
+ mov word ptr es:[di.BUF_ID],00FFh ;AN020;free buffer, clear flag
+ mov word ptr es:[di.BUF_SECTOR], 0 ;AN020;
+ mov word ptr es:[di.BUF_SECTOR+2], 0 ;AN020;
+ pop di ;AN020;
+ pop es ;AN020;
+
+ 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
+;J.K. 2/23/87 Modified to handle INSTALL= command.
+NODRVSET:
+ CALL DOCONF ;DO THE CONFIG STUFF
+ inc cs:Multi_Pass_Id ;AN027;
+ call Multi_Pass ;AN027;
+ inc cs:Multi_Pass_Id ;AN024;
+ call Multi_Pass ;AN024;
+ call EndFile
+ test Install_Flag, HAVE_INSTALL_CMD ;AN019;
+ jz DoLast ;AN019;
+ inc cs:Multi_Pass_Id ;AN024;
+ call Multi_Pass ;AN019;AN024; Execute INSTALL= commands
+
+;J.K. [AREA] has the segment address for the allocated memory of SYSINIT,CONFBOT.
+;Free the CONFBOT area used for CONFIG.SYS and SYSINIT itself.
+DoLast:
+ call LoadShare ;AN021; Try to load share.exe, if needed.
+ mov cs:[DoNotShowNum], 1 ;AN000; Done with CONFIG.SYS. Do not show line number message.
+ mov cx, [area] ;AN000;
+ mov es, cx ;AN000;
+ mov ah, 49h ;AN000; Free allocated memory for command.com
+ int 21h ;AN000;
+
+ test cs:[Install_flag], HAS_INSTALLED ;AN013; SYSINIT_BASE installed?
+ jz Skip_Free_SYSINITBASE ;AN013; No.
+;Set Block from the Old_Area with Impossible_Owner_size.
+;This will free the unnecessary SYSINIT_BASE that had been put in memory to
+;handle INSTALL= command.
+ push es ;AN013;
+ push bx ;AN013;
+ mov ax, cs:[Old_Area] ;AN013;
+ mov es, ax ;AN013;
+ mov bx, cs:[Impossible_Owner_Size] ;AN013;
+ mov ah, SETBLOCK ;AN013;
+ int 21h ;AN013;
+ MOV AX,ES ;AN013;
+ DEC AX ;AN013;
+ MOV ES,AX ;Point to arena
+ MOV ES:[arena_owner],8 ;Set impossible owner
+ pop bx ;AN013;
+ pop es ;AN013;
+Skip_Free_SYSINITBASE: ;AN013;
+ 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
+
+ PUSH CS
+ POP DS
+ASSUME DS:SYSINITSEG
+;
+; SET UP THE PARAMETERS FOR COMMAND
+;
+
+ 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,CR ; 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
+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
+;J.K. 6/24/87 Should handle the system that does not have any floppies.
+;J.K. In this case, we are going to pretended there are two dummy floppies
+;J.K. in the system. Still they have DPB and CDS, but we are going to
+;J.K. 0 out Curdir_Flags, Curdir_devptr of CDS so IBMDOS can issue
+;J.K. "Invalid drive specification" message when the user try to
+;J.K. access them.
+ je Fooset_Zero ;AN001;Don't have any physical drive.
+;SB34SYSINIT1003*************************************************************
+;SB Check to see if we are faking floppy drives. If not go to NORMCDS.
+;SB If we are faking floppy drives then see if this CDS being initialised
+;SB is for drive a: or b: by checking the appropriate field in the DPB
+;SB pointed to by ds:si. If not for a: or b: then go to NORMCDS. If
+;Sb for a: or b: then execute the code given below starting at Fooset_Zero.
+;SB For dpb offsets look at inc\dpb.inc.
+;SB 5 LOCS
+
+ cmp cs:Fake_Floppy_Drv,1 ;fake drive ?
+ jnz NORMCDS
+ cmp ds:[si].dpb_drive,02 ;check for a: or b:
+ jae NORMCDS
+
+;SB34SYSINIT1003*************************************************************
+Fooset_Zero: ;AN001;
+ XOR AX,AX
+ MOV CL,3
+ REP STOSW
+ POP CX
+ JMP SHORT FINCDS
+NORMCDS:
+ POP CX
+;J.K. If a non-fat based media is detected (by DPB.NumberOfFat == 0), then
+; set curdir_flags to 0. This is for signaling IBMDOS and IFSfunc that
+; this media is a non-fat based one.
+ cmp [SI.dpb_FAT_count], 0 ;AN000; Non fat system?
+ je SetNormCDS ;AN000; Yes. Set curdir_Flags to 0. AX = 0 now.
+ MOV AX,CURDIR_INUSE ;AN000; else, FAT system. set the flag to CURDIR_INUSE.
+SetNormCDS: ;AN000;
+ 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
+ mov ax, 0 ;AN000;Clear out 7 bytes (curdir_type,
+ stosw ;AN000; curdir_ifs_hdr, curdir_fsda)
+ stosw ;AN000;
+ stosw ;AN000;
+ stosb ;AN000;
+ 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.
+
+;J.K. 2/23/87 If this procedure has been called to take care of INSTALL= command,
+;then we have to save ES,SI registers.
+
+; test [Install_Flag],IS_INSTALL ;AN000; Called to handle INSTALL=?
+; jz ENDFILE_Cont ;AN000;
+; push es ;AN000; Save es,si for CONFIG.SYS
+; push si ;AN000;
+; test [Install_Flag],HAS_INSTALLED ;AN000; Sysinit_base already installed?
+; jz ENDFILE_Cont ;AN000; No. Install it.
+; jmp DO_Install_EXEC ;AN000; Just handle "INSTALL=" cmd only.
+;ENDFILE_Cont: ;AN000;
+
+ push ds ;AN002;
+ mov ax, Code ;AN002;
+ mov ds, ax ;AN002;
+ assume ds:Code
+ cmp MulTrk_flag, MULTRK_OFF1 ;AN002;=0, MULTRACK= command entered?
+ jne MulTrk_Flag_Done ;AN002;
+ or MulTrk_flag, MULTRK_ON ;AN002; Default will be ON.
+MulTrk_Flag_Done: ;AN002;
+ pop ds ;AN002;
+ assume ds:nothing
+
+ MOV AX,[CONFBOT]
+ MOV [ALLOCLIM],AX
+
+ PUSH CS
+ POP DS
+ INVOKE ROUND
+ MOV AL,[FILES]
+ SUB AL,5
+ JBE DOFCBS
+ push ax ;AN005;
+ mov al, DEVMARK_FILES ;AN005;
+ call SetDevMark ;AN005; Set DEVMARK for SFTS (FILES)
+ pop ax ;AN005;
+ 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
+ or [SetDevMarkFlag], FOR_DEVMARK ;AN005;
+ 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, DEVMARK_FCBS ;AN005;='X'
+ call SetDevMark ;AN005;
+ 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
+ or [SetDevMarkFlag], FOR_DEVMARK ;AN005;
+ 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
+ cmp Buffer_Slash_X, 1 ;AN000;
+ jne DO_Buffer ;AN000;
+ call DoEMS ;AN000; Carry set if (enough) EMS is not available
+ jc DoDefaultBuff ;AN000; Error. Just use default buffer.
+DO_Buffer:
+ jmp DOBUFF ; the user entered the buffers=.
+
+DoDefaultBuff:
+ mov [H_Buffers], 0 ;AN000; Default is no heuristic buffers.
+ 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 size for default buffer count
+; JMP BUFSET ; Jump out of search loop
+NOSETBUF:
+ CMP WORD PTR ES:[BP.DPB_NEXT_DPB],-1
+ jz Chk_Memsize_for_Buffers
+; JZ BUFSET
+ LES BP,ES:[BP.DPB_NEXT_DPB]
+ JMP NEXTDPB
+
+;J.K. 10/15/86 DCR00014.
+;From DOS 3.3, the default number of buffers will be changed according to the
+;memory size too.
+; Default buffers = 2
+; If diskette Media > 360 kb, then default buffers = 3
+; If memory size > 128 kb (2000H para), then default buffers = 5
+; If memory size > 256 kb (4000H para), then default buffers = 10
+; If memory size > 512 kb (8000H para), then default buffers = 15.
+
+Chk_Memsize_for_Buffers:
+ cmp [memory_size], 2000h
+ jbe BufSet
+ mov [buffers], 5
+ cmp [memory_size], 4000h
+ jbe BufSet
+ mov [buffers], 10
+ cmp [memory_size], 8000h
+ jbe BufSet
+ mov [buffers], 15
+
+BUFSET:
+ASSUME DS:NOTHING
+ POP DS
+ POP AX
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;J.K. Here we should put extended stuff and new allocation scheme!!!
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;*******************************************************************************
+; *
+; Function: Actually allocate BUFFERS into the (extended) memory and initialize*
+; it. *
+; If it is installed in real memory, the number of buffers in each *
+; bucket will be balanced out as far as possible for perfermance. *
+; Also, if the user specified the secondary buffer cache, it will *
+; be installed in the real memory. *
+; *
+; Input : *
+; BuffINFO.EMS_MODE - 0=IBM mode, -1 = do not use extended memory. *
+; BuffINFO.Frame_Page - Page frame 0 segment address *
+; MEMHI:MEMLO - Start of the next available memory *
+; Buffer_Pages = Number of extended memory pages for buffer *
+; BUFFERS = Number of buffers *
+; H_Buffers = Number of secondary buffers *
+; *
+; Output: *
+; BuffINFO.Cache_Count - # of caches to be installed. *
+; Hash table set. *
+; BuffINFO set. *
+; BufferBuckets set. *
+; MaxNumBuf1, MaxNumBuf2, and NthBuck set. *
+; *
+; Subroutines to be called: *
+; *
+; Logic: *
+; { *
+; IF (BuffINFO.EMS_MODE == -1) THEN *
+; { *
+; IF BUFFERS < 30 THEN *
+; {# of Bucket = 1; MaxNumBuf1 = BUFFERS; NthBuck = 1} *
+; ELSE { *
+; # of Bucket = BUFFERS/15; *
+; r = BUFFERS mod 15; *
+; IF r == 0 THEN NthBuck = # of Bucket *
+; ELSE *
+; { *
+; AddBuff = r / # of Bucket; *
+; NthBuck = r mod # of Bucket; *
+; MaxNumBuf1 = 15 + AddBuff; /* 1st Bucket - Nth Bucket*
+; MaxNumBuf2 = 15 + AddBuff +1;/*(N+1)th Bucket to last*
+; } *
+; } *
+; } *
+; ELSE *
+; { *
+; # of Bucket = Buffer_Pages * 2; /* 2 buckets per page *
+; }; *
+; *
+; /*Now allocate memory for Hash table */ *
+; Hash Table Size = (size Buffer_Hash_Entry) * # of Bucket; *
+; Set BuffINFO.Hash_ptr to MEMHI:MEMLO; *
+; Adjust MEMHI:MEMLO according to Hash table size; *
+; *
+; /*Set buffers*/ *
+; IF (EMS_MODE <> -1) THEN *
+; Set_EMS_Buffer *
+; ELSE /*Do not use the extended memory */ *
+; Set_Buffer; *
+;/*Now set the caches if specified.*/ *
+; IF (BuffINFO.Cache_count > 0) THEN *
+; {Set BuffINFO.Cache_ptr to MEMHI:MEMLO; *
+; MEMHI:MEMLO = MEMHI:MEMLO + 512 * BuffINFO.Cache_count; *
+; }; *
+; }; *
+; *
+;*******************************************************************************
+DOBUFF: ;AN000;
+ lds bx, cs:[DosInfo] ;AN000; ds:bx -> SYSINITVAR
+
+ mov ax, [Buffers] ;AN000;Set SYSI_BUFFERS
+ mov word ptr ds:[bx.SYSI_BUFFERS], ax ;AN000;
+ mov ax, [H_Buffers] ;AN000;
+ mov word ptr ds:[bx.SYSI_BUFFERS+2], ax ;AN000;
+
+ lds bx, ds:[bx.SYSI_BUF] ;AN000; now, ds:bx -> BuffInfo
+ cmp ds:[bx.EMS_MODE], -1 ;AN000;
+; $IF E, LONG ;AN000;
+ JE $$XL1
+ JMP $$IF1
+$$XL1:
+ xor dx, dx ;AN000;
+ mov ax, [Buffers] ;AN000; < 99
+ cmp al, 30 ;AN026; if less than 30,
+; $IF B ;AN026;
+ JNB $$IF2
+ mov [BufferBuckets], 1 ;AN026; then put every buffer
+ mov ds:[bx.HASH_COUNT], 1 ;AN026; into one bucket
+ mov [MaxNumBuf1], al ;AN026;
+ mov [NthBuck], 1 ;AN026;
+; $ELSE ;AN026; else...
+ JMP SHORT $$EN2
+$$IF2:
+ mov cl, 15 ;AN026; Magic number 15.
+ div cl ;AN026; al=# of buckets, ah=remainders
+ push ax ;AN026; save the result
+ xor ah, ah ;AN026;
+ mov [BufferBuckets], ax ;AN026;
+ mov ds:[bx.HASH_COUNT], ax ;AN026;
+ pop ax ;AN026;
+ or ah, ah ;AN026;
+; $IF Z ;AN026;if no remainders
+ JNZ $$IF4
+ mov [NthBuck], al ;AN026;then set NthBuck=# of bucket for Set_Buffer proc.
+; $ELSE ;AN026;else
+ JMP SHORT $$EN4
+$$IF4:
+ mov cl, al ;AN026;
+ mov al, ah ;AN026;remainder/# of buckets
+ xor ah, ah ;AN026; =
+ div cl ;AN026;al=additional num of buffers
+ or ah, ah ;AN026;ah=Nth bucket
+; $IF Z ;AN026;
+ JNZ $$IF6
+ add [MaxNumBuf1], al ;AN026;
+ mov ax, [BufferBuckets] ;AN026;
+ mov [NthBuck], al ;AN026;
+; $ELSE ;AN026;
+ JMP SHORT $$EN6
+$$IF6:
+ mov [NthBuck], ah ;AN026;
+ add [MaxNumBuf1], al ;AN026;MaxNumNuf are initially set to 15.
+ add [MaxNumBuf2], al ;AN026;
+ inc [MaxNumBuf1] ;AN026;Additional 1 more buffer for group 1 buckets.
+; $ENDIF ;AN026;
+$$EN6:
+; $ENDIF ;AN026;
+$$EN4:
+; $ENDIF ;AN026;
+$$EN2:
+; $ELSE ;AN000; Use the extended memory.
+ JMP SHORT $$EN1
+$$IF1:
+ mov ax, [Buffer_Pages] ;AN000;
+ mov cx, MAXBUCKETINPAGE ;AN000;
+ mul cx ;AN000; gauranteed to be word boundary.
+ mov [BufferBuckets], ax ;AN000;
+ mov ds:[bx.HASH_COUNT], ax ;AN000;
+; $ENDIF ;AN000;
+$$EN1:
+ invoke Round ;AN000; get [MEMHI]:[MEMLO]
+ mov al, DEVMARK_BUF ;AN005; ='B'
+ call SetDevMark ;AN005;
+;Now, allocate Hash table at [memhi]:[memlo]. AX = Hash_Count.
+ mov ax, [BufferBuckets] ;AN026; # of buckets==Hash_Count
+ mov cx, size BUFFER_HASH_ENTRY ;AN000;
+ mul cx ;AN000; now AX = Size of hash table.
+ les di, ds:[bx.HASH_PTR] ;AN000; save Single buffer address.
+ mov cx, [MemLo] ;AN000;
+ mov word ptr ds:[bx.HASH_PTR], cx ;AN000; set BuffINFO.HASH_PTR
+ mov cx, [MemHi] ;AN000;
+ mov word ptr ds:[bx.HASH_PTR+2], cx ;AN000;
+ mov [Memlo], ax ;AN000;
+ or [SetDevMarkFlag], FOR_DEVMARK ;AN005;
+ call Round ;AN000; get new [memhi]:[memlo]
+;Allocate buffers
+ push ds ;AN000; Save Buffer info. ptr.
+ push bx ;AN000;
+ cmp ds:[bx.EMS_MODE], -1 ;AN000;
+; $IF NE ;AN000;
+ JE $$IF13
+ call Set_EMS_Buffer ;AN000;
+; $ELSE ;AN000;
+ JMP SHORT $$EN13
+$$IF13:
+ call Set_Buffer ;AN000;
+; $ENDIF ;AN000;
+$$EN13:
+ pop bx ;AN000;
+ pop ds ;AN000;
+;Now set the secondary buffer if specified.
+ cmp [H_Buffers], 0 ;AN000;
+; $IF NE ;AN000;
+ JE $$IF16
+ call Round ;AN000;
+ mov cx, [MemLo] ;AN000;
+ mov word ptr ds:[bx.CACHE_PTR], cx ;AN000;
+ mov cx, [MemHi] ;AN000;
+ mov word ptr ds:[bx.CACHE_PTR+2], cx ;AN000;
+ mov cx, [H_Buffers] ;AN000;
+ mov ds:[bx.CACHE_COUNT], cx ;AN000;
+ mov ax, 512 ;AN000; 512 byte
+ mul cx ;AN000;
+ mov [Memlo], ax ;AN000;
+ or [SetDevMarkFlag], FOR_DEVMARK ;AN005;
+ call Round ;AN000;
+; $ENDIF ;AN000;
+$$IF16:
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;J.K. END OF NEW BUFFER SCHEME.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;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 word ptr es:[di.buf_Sector],0 ;AN000;
+; mov word ptr es:[di.buf_Sector+2],0 ;AN000;
+; MOV BX,[BX.SYSI_MAXSEC]
+; POP DS
+; ADD BX,BUFINSIZ
+; ADD [MEMLO],BX
+; JMP DOBUFF
+
+;------------------------------------------------------------------------------
+; Allocate CDSs
+;------------------------------------------------------------------------------
+BUF1:
+ INVOKE ROUND
+ push ax ;AN005;
+ mov ax, DEVMARK_CDS ;AN005;='L'
+ call SetDevMark ;AN005;
+ pop ax ;AN005;
+ 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
+ or [SetDevMarkFlag], FOR_DEVMARK ;AN005;
+ 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
+ POP DS
+ ASSUME DS:SYSINITSEG
+
+ IF IBM
+;Don't install the system stack on the PCjr. Ignore STACKS=command too.
+ CMP [Sys_Model_Byte], 0FDh ; PCjr = 0FDh
+ JE SkipStack_brdg
+ ENDIF
+
+;J.K. 10/15/86 DCR00013
+;If the use does not entered STACKS= command, as a default, do not install
+;sytem stacks for PC1, PC XT, PC Portable cases.
+;Otherwise, install it to the user specified value or to the default
+;value of 9, 128 for the rest of the system.
+
+ cmp word ptr [stack_addr], -1 ;Has the user entered "stacks=" command?
+ je DoInstallStack ;Then install as specified by the user
+ cmp [Sys_Scnd_Model_Byte], 0 ;PC1, XT has the secondary model byte = 0
+ jne DoInstallStack ;Other model should have default stack of 9, 128
+ cmp [Sys_Model_Byte], 0FFh ;PC1 ?
+ je SkipStack_brdg
+ cmp [Sys_Model_Byte], 0FEh ;PC/XT or PC Portable ?
+ jne DoInstallStack
+SkipStack_Brdg:
+ jmp SkipStack
+DoInstallStack:
+ mov ax, [stack_count] ;J.K. Stack_count = 0?
+ cmp ax, 0 ;then, stack size must be 0 too.
+ jz SkipStack_brdg ;Don't install stack.
+;J.K. 10/21/86 Dynamic Relocation of Stack code.
+ call Round ;[memhi] = Seg. for stack code
+ ;[memlo] = 0
+;J.K. Set DEVMARK block into memory for MEM command
+;J.K. DEVMARK_ID = 'S' for stack
+ mov al, DEVMARK_STK ;AN005;='S'
+ call SetDevMark
+
+ mov ax, [memhi]
+ mov es, ax ;ES -> Seg. the stack code is going to move.
+ assume es:nothing
+ push cs
+ pop ds
+ xor si,si ;!!We know that Stack code is at the beginning of SYSINIT.
+ xor di,di
+ mov cx, offset Endstackcode
+ mov [memlo],cx
+ call Round ;Have enough space for relocation?
+ rep movsb
+
+ mov ax, [memlo]
+ mov word ptr [stack_addr],ax ;set for stack area initialization
+ mov ax, [memhi] ;This will be used by Stack_Init routine.
+ mov word ptr [stack_addr+2],ax
+
+; Space for Internal Stack area = 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
+ or [SetDevMarkFlag], FOR_DEVMARK ;AN005;To set the DEVMARK_SIZE for Stack by ROUND routine.
+ INVOKE ROUND ; Check for memory error before
+ ; continuing
+ CALL StackInit ; Initialize hardware stack. CS=DS=sysinitseg, ES=Relocated stack code & data
+
+SkipStack:
+ ENDIF
+
+ 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
+
+;J.K.9/29/86 *******************
+;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. By the request of the system architecture group, IBMBIO will
+;issue a global rearm after every 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 Round-Up machine
+; None.
+; where XX stands for any value.
+; For your information, after Naples level machine, the system service bios
+; call (INT 15h), function AH=0C0h returns the system configuration parameters
+;
+
+ cmp [sys_model_byte], 0FDh ;PCjr?
+; je GoCheckInstall
+ je Set_Sysinit_Base
+;SB33045*******************************************************************
+ push ax ;Save Regs ;SB ;3.30*
+ push bx ; * ;SB ;3.30*
+ push dx ; * ;SB ;3.30*
+ push es ; * ;SB ;3.30*
+ mov al,0ffh ;Reset h/w by writing to port ;SB ;3.30*
+ mov dx,2f2h ;Get starting address ;SB ;3.30*
+ 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
+;SB33045*******************************************************************
+
+;SB33046*******************************************************************
+;SB Secondary global rearm ;3.30
+ mov ax,0f000h ;Get machine type ;SB ;3.30*
+ mov es,ax ; * ;SB ;3.30*
+ cmp byte ptr es:[0fffeh],0fch ;Q:Is it a AT type machine ;SB ;3.30*
+ je startrearm ; *if AT no need to check
+ mov ah,0c0h ;Get system configuration ;SB ;3.30*
+ int 15h ; * ;SB ;3.30*
+ jc finishrearm ; *jmp if old rom ;SB ;3.30*
+; ;SB ;3.30*
+; Test feature byte for secondary interrupt controller ;SB ;3.30*
+; ;SB ;3.30*
+ test es:[bx.bios_SD_featurebyte1],ScndIntController ; ;SB ;3.30*
+ je finishrearm ;Jmp if it is there ;SB ;3.30*
+startrearm:
+ mov al,0ffh ;Write any pattern to port ;SB ;3.30*
+ mov dx,6f2h ;Get starting address ;SB ;3.30*
+ out dx,al ;out 06f2h,0ffh
+ inc dx ;Bump address ;SB ;3.30*
+ out dx,al ;out 06f3h,0ffh
+ inc dx ;Bump address ;SB ;3.30*
+ out dx,al ;out 06f4h,0ffh
+ inc dx ;Bump address ;SB ;3.30*
+ inc dx ;Bump address ;SB ;3.30*
+ out dx,al ;out 06f6h,0ffh
+ inc dx ;Bump address ;SB ;3.30*
+ out dx,al ;out 06f7h,0ffh
+finishrearm: ; ;SB ;3.30*
+ pop es ;Restore regs ;SB ;3.30*
+ pop dx ; * ;SB ;3.30*
+ pop bx ; * ;SB ;3.30*
+ pop ax ; * ;SB ;3.30*
+;SB33046*******************************************************************
+
+;J.K. 9/29/86 Global Rearm end *******************
+
+;------------------------------------------------------------------------------
+; Allocate SYSINIT_BASE for INSTALL= command
+;------------------------------------------------------------------------------
+;J.K. SYSINIT_BASE allocation.
+;Check if ENDFILE has been called to handle INSTALL= command.
+
+Set_Sysinit_Base:
+;GoCheckInstall:
+; test [Install_Flag], HAVE_INSTALL_CMD ;AN019;;AN021;install sysinit base all the time.
+; jz Skip_SYSINIT_BASE ;AN019;
+
+;J.K.--------------------------------------------------------------------------
+;SYSINIT_BASE will be established in the secure area of
+;lower memory when it handles the first INSTALL= command.
+;SYSINIT_BASE is the place where the actual EXEC function will be called and
+;will check SYSINIT module in high memory if it is damaged by the application
+;program. If SYSINIT module has been broken, then "Memory error..." message
+;is displayed by SYSINIT_BASE.
+;------------------------------------------------------------------------------
+ push ax ;AN013; Set DEVMARK for MEM command
+ mov ax, [memhi] ;AN013;
+ sub ax, [area] ;AN013;
+ mov [Impossible_owner_size], ax ;AN013;Remember the size in case.
+ mov al, DEVMARK_INST ;AN013;
+ call SetDevMark ;AN013;
+ pop ax ;AN013;
+
+ mov di, [memhi] ;AN000;
+ mov es, di ;AN000;
+ assume es:nothing ;AN000;
+ mov word ptr [sysinit_base_ptr+2],di ;AN000; save this entry for the next use.
+ xor di, di ;AN000;
+ mov word ptr [sysinit_base_ptr], di ;AN000; es:di -> destination.
+ mov si, offset SYSINIT_BASE ;AN000; ds:si -> source code to be relocated.
+ mov cx, Size_SYSINIT_BASE ;AN000;
+ add [memlo],cx ;AN000;
+ or cs:[SetDevMarkFlag], FOR_DEVMARK ;AN013;
+ call round ;AN000; check mem error. Also, readjust MEMHI for the next use.
+ rep movsb ;AN000; reallocate it.
+
+ mov word ptr [Sysinit_Ptr], offset SYSINITPTR ;AN000; Returing address from
+ mov word ptr [Sysinit_Ptr+2], cs ;AN000; SYSINIT_BASE back to SYSINIT.
+ or [Install_Flag],HAS_INSTALLED ;AN000; Set the flag.
+
+;------------------------------------------------------------------------------
+; Free the rest of the memory from MEMHI to CONFBOT. Still from CONFBOT to
+; the top of the memory will be allocated for SYSINIT and CONFIG.SYS if
+; HAVE_INSTALL_CMD.
+;------------------------------------------------------------------------------
+;Skip_SYSINIT_BASE: ;AN021;
+
+ INVOKE ROUND
+ MOV BX,[MEMHI]
+ MOV AX,[AREA]
+ mov [Old_Area], ax ;AN013; Save [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
+
+ mov bx,0ffffh ;AN000;
+ mov ah,Alloc ;AN000;
+ int 21h ;AN000;
+ mov ah,Alloc ;AN000;
+ int 21h ;AN000; Allocate the rest of the memory
+
+ mov [memhi],ax ;AN000; Start of the allocated memory
+ mov [memlo],0 ;AN000; to be used next.
+
+ ;;;; At this moment, memory from [MEMHI]:0 to Top-of-the memory is
+ ;;;; allocated.
+ ;;;; To protect sysinit, confbot module (From CONFBOT (or =ALLOCLIM at
+ ;;;; this time) to the Top-of-the memory), here we are going to
+ ;;;; 1). "SETBLOCK" from MEMHI to CONFBOT.
+ ;;;; 2). "ALLOC" from CONFBOT to the top of the memory.
+ ;;;; 3). "Free Alloc Memory" from MEMHI to CONFBOT.
+;Memory allocation for SYSINIT, CONFBOT module.
+ mov es, ax ;AN000;
+ mov bx, [confbot] ;AN000;
+ sub bx, ax ;AN000; CONFBOT - MEMHI
+ dec bx ;AN000; Make a room for the memory block id.
+ dec bx ;AN000; make sure!!!.
+ mov ah, SETBLOCK ;AN000;
+ int 21h ;AN000; this will free (CONFBOT to top of memory)
+ mov bx, 0ffffh ;AN000;
+ mov ah, ALLOC ;AN000;
+ int 21h ;AN000;
+ mov ah, ALLOC ;AN000;
+ int 21h ;AN000; allocate (CONFBOT to top of memory)
+ mov [area],ax ;AN000; Save Allocated memory segment.
+ ;AN000; Need this to free this area for COMMAND.COM.
+ mov es, [memhi] ;AN000;
+ mov ah, 49h ;AN000; Free Allocated Memory.
+ int 21h ;AN000; Free (Memhi to CONFBOT(=AREA))
+
+; 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
+
+; test cs:[Install_Flag],IS_INSTALL ;AN000;
+; jnz DO_Install_Exec ;AN000;
+
+ENDFILE_Ret:
+ return
+
+
+Do_Install_Exec proc near ;AN000; Now, handles INSTALL= command.
+
+ push si ;AN000; save SI for config.sys again.
+
+ ;;;; We are going to call LOAD/EXEC function.
+ ;;;;;Set ES:BX to the parameter block here;;;;;;;
+ ;;;;;Set DS:DX to the ASCIIZ string. Remember that we already has 0
+ ;;;;;after the filename. So parameter starts after that. If next
+ ;;;;;character is a line feed (i.e. 10), then assume that the 0
+ ;;;;;we already encountered used to be a carrage return. In this
+ ;;;;;case, let's set the length to 0 which will be followed by
+ ;;;;;carridge return.
+;J.K. ES:SI -> command line in CONFIG.SYS. Points to the first non blank
+;character after =.
+ push es ;AN000;
+ push ds ;AN000;
+ pop es ;AN000;
+ pop ds ;AN000; es->sysinitseg, ds->confbot seg
+ assume ds:nothing ;AN000;
+ mov dx, si ;AN000; ds:dx->file name,0 in CONFIG.SYS image.
+;AN016; UNDO THE EXTENDED ATTRIBUTES HANDLING
+; mov ax, OPEN SHL 8 ;AN008;
+; int 21h ;AN008;
+; jc SysInitPtr ;AN008;
+; mov bx, ax ;AN008;handle
+; call Get_Ext_Attribute ;AN008;Get the extended attribute.
+; cmp al, EA_INSTALLABLE ;AN008;
+; je EA_Installable_OK ;AN012;
+; stc ;AN012;
+; jmp SysInitPtr ;AN012;
+;EA_Installable_OK: ;AN012;
+ xor cx,cx ;AN000;
+ cld ;AN000;
+ mov cs:Ldexec_start, ' ' ;AN015; Clear out the parm area
+ mov di, offset Ldexec_parm ;AN000;
+InstallFilename: ;AN000; skip the file name
+ lodsb ;AN000; al = ds:si; si++
+ cmp al, 0 ;AN000;
+ je Got_InstallParm ;AN000;
+ jmp InstallFilename ;AN000;
+Got_InstallParm: ;AN000; copy the parameters to Ldexec_parm
+ lodsb ;AN000;
+ mov es:[di], al ;AN000;
+ cmp al, LF ;AN000;AN028; line feed?
+ je Done_InstallParm ;AN000;AN028;
+ inc cl ;AN000; # of char. in the parm.
+ inc di ;AN000;
+ jmp Got_Installparm ;AN000;
+Done_Installparm: ;AN000;
+ mov byte ptr cs:[Ldexec_line], cl ;AN000; length of the parm.
+ cmp cl, 0 ;AN015;If no parm, then
+ jne Install_Seg_Set ;AN015; let the parm area
+ mov byte ptr cs:[Ldexec_Start],CR ;AN015; starts with CR.
+Install_Seg_Set: ;AN015;
+ mov word ptr cs:0, 0 ;AN000; Make a null environment segment
+ mov ax, cs ;AN000; by overlap JMP instruction of SYSINITSEG.
+ mov cs:[INSTEXE.EXEC0_ENVIRON],ax ;AN000; Set the environment seg.
+ mov word ptr cs:[INSTEXE.EXEC0_COM_LINE+2],ax ;AN000; Set the seg.
+ mov word ptr cs:[INSTEXE.EXEC0_5C_FCB+2],ax ;AN000;
+ mov word ptr cs:[INSTEXE.EXEC0_6C_FCB+2],ax ;AN000;
+ call Sum_up ;AN000;
+ mov es:CheckSum, ax ;AN000; save the value of the sum
+ xor ax,ax ;AN000;
+ mov ah, EXEC ;AN000; Load/Exec
+ mov bx, offset INSTEXE ;AN000; ES:BX -> parm block.
+ push es ;AN000; Save es,ds for Load/Exec
+ push ds ;AN000; these registers will be restored in SYSINIT_BASE.
+ jmp cs:dword ptr SYSINIT_BASE_PTR ;AN000; jmp to SYSINIT_BASE to execute
+ ; LOAD/EXEC function and check sum.
+
+;J.K. This is the returning address from SYSINIT_BASE.
+SYSINITPTR: ;AN000; returning far address from SYSINIT_BASE
+ pop si ;AN000; restore SI for CONFIG.SYS file.
+ push es ;AN000;
+ push ds ;AN000;
+ pop es ;AN000;
+ pop ds ;AN000; now ds - sysinitseg, es - confbot
+ jnc Exec_Exit_Code
+ test cs:Install_Flag, SHARE_INSTALL ;AN021; Called by LoadShare proc?
+ jnz Install_Error_Exit ;AN021; Just exit with carry set.
+ push si ;AN000; Error in loading the file for INSTALL=.
+ call BadLoad ;AN000; ES:SI-> path,filename,0.
+ pop si ;AN000;
+ jmp Install_Exit_Ret
+Exec_Exit_Code:
+ test cs:Install_Flag, SHARE_INSTALL ;AN021; Called by LoadShare proc?
+ jnz Install_Exit_Ret ;AN021; Just exit.
+ mov ah, 4dh ;AN017;
+ int 21h ;AN017;
+ cmp ah, 3 ;AN017;Only accept "Stay Resident" prog.
+ je Install_Exit_Ret ;AN017;
+ call Error_Line ;AN017;Inform the user
+Install_Error_Exit: ;AN021;
+ stc ;AN021;
+Install_Exit_Ret:
+ ret
+Do_Install_Exec endp
+
+Public ParaRound
+ParaRound:
+ ADD AX,15
+ RCR AX,1
+ SHR AX,1
+ SHR AX,1
+ SHR AX,1
+ return
+
+;------------------------------------------------------------------------------
+;J.K. SYSINIT_BASE module.
+;In: After relocation,
+; AX = 4B00h - Load and execute the program DOS function.
+; DS = CONFBOT. Segment of CONFIG.SYS file image
+; ES = Sysinitseg. Segment of SYSINIT module itself.
+; DS:DX = pointer to ASCIIZ string of the path,filename to be executed.
+; ES:BX = pointer to a parameter block for load.
+; SYSSIZE (Byte) - offset vaule of End of SYSINIT module label
+; BIGSIZE (word) - # of word from CONFBOT to SYSSIZE.
+; CHKSUM (word) - Sum of every byte from CONFBOT to SYSSIZE in a
+; word boundary moduler form.
+; SYSINIT_PTR (dword ptr) - Return address to SYSINIT module.
+;Note: SYSINIT should save necessary registers and when the control is back
+
+
+ public Sysinit_Base
+Sysinit_Base: ;AN000;
+ mov word ptr cs:SYSINIT_BASE_SS, SS ;AN000; save stack
+ mov word ptr cs:SYSINIT_BASE_SP, SP ;AN000;
+ int 21h ;AN000; LOAD/EXEC DOS call.
+ mov SS, word ptr cs:SYSINIT_BASE_SS ;AN000; restore stack
+ mov SP, word ptr cs:SYSINIT_BASE_SP ;AN000;
+ pop ds ;AN000; restore CONFBOT seg
+ pop es ;AN000; restore SYSINITSEG
+ jc SysInit_Base_End ;AN000; LOAD/EXEC function failed.
+ ;At this time, I don't have to worry about
+ ;that SYSINIT module has been broken or not.
+ call Sum_up ;AN000; Otherwise, check if it is good.
+ cmp es:CheckSum, AX ;AN000;
+ je SysInit_Base_End ;AN000;
+;Memory broken. Show "Memory allocation error" message and stall.
+ mov ah, 09h ;AN000;
+ push cs ;AN000;
+ pop ds ;AN000;
+ mov dx, Mem_alloc_err_msg ;AN000;
+ int 21h ;AN000;
+Stall_now: jmp Stall_now ;AN000;
+
+SysInit_Base_End: jmp es:Sysinit_Ptr ;AN000; return back to sysinit module
+
+Sum_up: ;AN000;
+;In:
+; ES - SYSINITSEG.
+;OUT: AX - Result
+;Remark: Since this routine will only check starting from "LocStack" to the end of
+; Sysinit segment, the data area, and the current stack area are not
+; coverd. In this sense, this check sum routine only gives a minimal
+; gaurantee to be safe.
+;First sum up CONFBOT seg.
+ push ds ;AN021;
+ mov ax,es:ConfBot ;AN021;
+ mov ds,ax ;AN021;
+ xor si,si ;AN000;
+ xor ax,ax ;AN000;
+ mov cx,es:Config_Size ;AN000; If CONFIG_SIZE has been broken, then this
+ ;whole test better fail.
+ shr cx, 1 ;AN000; make it a word count
+ jz Sum_Sys_Code ;AN025; When CONFIG.SYS file not exist.
+Sum1: ;AN000;
+ add ax, ds:word ptr [si] ;AN000;
+ inc si ;AN000;
+ inc si ;AN000;
+ loop Sum1 ;AN000;
+;Now, sum up SYSINIT module.
+Sum_Sys_Code: ;AN025;
+ mov si, offset LocStack ;AN000; Starting after the stack.
+ ;AN000; This does not cover the possible STACK code!!!
+ mov cx, offset SYSSIZE ;AN000; SYSSIZE is the label at the end of SYSINIT
+ sub cx, si ;AN000; From After_Checksum to SYSSIZE
+ shr cx, 1 ;AN000;
+Sum2: ;AN000;
+ add ax, es:word ptr [si] ;AN000;
+ inc si ;AN000;
+ inc si ;AN000;
+ loop Sum2 ;AN000;
+ pop ds ;AN021;
+ ret ;AN000;
+
+Sysinit_Base_SS equ $-Sysinit_Base ;AN000;
+ dw ? ;AN000;
+Sysinit_Base_SP equ $-Sysinit_Base ;AN000;
+ dw ? ;AN000;
+Mem_Alloc_Err_msg equ $-Sysinit_Base ;AN000;
+;include BASEMES.INC ;AN000; Memory allocation error message
+include MSBIO.CL4 ;AN011; Memory allocation error message
+End_Sysinit_Base label byte ;AN000;
+SIZE_SYSINIT_BASE equ $-Sysinit_Base ;AN000;
+
+;
+;AN016; Undo the extended attribute handling
+; public Get_Ext_Attribute
+;Get_Ext_Attribute proc near ;AN008;
+;;In: BX - file handle
+;;Out: AL = The extended attribute got from the handle.
+;; AX destroyed.
+;; Carry set when DOS function call fails.
+;
+; push ds ;AN008;
+; push si ;AN008;
+; push es ;AN008;
+; push di ;AN008;
+; push cx ;AN008;
+;
+; push cs ;AN008;
+; pop ds ;AN008;
+; push cs ;AN008;
+; pop es ;AN008;
+;
+; mov Ext_Attr_Value, 0ffh ;AN008; Initialize to unrealistic value
+; mov ax, 5702h ;AN008;Get extended attribute by handle thru LIST
+; mov si, offset EA_QueryList ;AN008;
+; mov di, offset Ext_Attr_List ;AN008;
+; mov cx, SIZE_EXT_ATTR_LIST ;AN008;
+; int 21h ;AN008;
+; mov al, Ext_Attr_Value ;AN008;
+; pop cx ;AN008;
+; pop di ;AN008;
+; pop es ;AN008;
+; pop si ;AN008;
+; pop ds ;AN008;
+; ret ;AN008;
+;Get_Ext_Attribute endp ;AN008;
+
+
+;------------------------------------------------------------------------------
+
+DoEMS proc near
+;*******************************************************************************
+; Function: Called prior to DOBUFF subroutine. Only called when /E option *
+; for the buffers= command has been specified. *
+; This routine will check if the extended memory is avaiable, *
+; and determine what is the page number. We only use physical page *
+; 254. if it is there, then this routine will calculate the number *
+; of pages needed for buffers and will allocate logical pages in the *
+; extended memory and get the page handle of them. *
+; *
+; Input : *
+; Buffers - Number of buffers *
+; Buffer_LineNum - Saved line number to be used in case of Error case *
+; *
+; Output: *
+; BuffINFO.EMS_Handle *
+; Buffer_Pages = Number of pages for buffer in the extended memory. *
+; BuffINFO.EMS_MODE = -1 No extended memory or Non-IBM compatible mode. *
+; Buffers = the number will be changed to be a multiple of 30. *
+; Carry set if no extended memory exist or if it is not big enough. *
+; AX, BX, CX, DX destroyed. *
+; *
+; Logic: *
+; { *
+; Get EMS Version (AH=46h); *
+; If (EMS not installed or it is not IBM compatible or *
+; (Available_pages * 30 < Buffers) then *
+; {Show error message "Error in CONFIG.SYS line #"; *
+; Set carry; Exit }; *
+; else *
+; Buffer_Pages = Roundup(BUFFERS/30); /* Round up 30 buffers per page*/ *
+; Buffers = Buffer_Pages * 30; /* Set the new number of Buffers*/*
+; Allocate Buffer_Pages (AH=43h) and set EMS_Handle; *
+; }; *
+; *
+;*******************************************************************************
+
+ push es ;AN000;
+ push di ;AN000; save es, di
+ push si ;AN010;
+ push bx ;AN010;
+ xor di,di ;AN004; if vector pointer of
+ mov es, di ;AN004; EMS (INT 67h) is 0,0
+ mov di, word ptr es:[EMS_INT * 4] ;AN004; then error.
+ mov ax, word ptr es:[EMS_INT * 4 +2] ;AN009;
+ or ax,di ;AN009;
+; $IF NZ,AND,LONG ;AN004;
+ JNZ $$XL2
+ JMP $$IF18
+$$XL2:
+ les di, cs:[DosInfo] ;AN000; es:di -> SYSINITVAR
+ les di, es:[di.SYSI_BUF] ;AN000; now, es:di -> BuffInfo
+
+ mov ah, EMS_STATUS ;AN000; get the status of EMS = 40h
+ int EMS_INT ;AN000;
+ or ah, ah ;AN000; EMS installed?
+; $IF Z,AND,LONG ;AN000;
+ JZ $$XL3
+ JMP $$IF18
+$$XL3:
+ mov ah, EMS_VERSION ;AN010;=46h
+ int EMS_INT ;AN010;
+ cmp AL, EMSVERSION ;AN010;40h = 4.0
+; $IF AE,AND,LONG ;AN010;
+ JAE $$XL4
+ JMP $$IF18
+$$XL4:
+ call Check_IBM_PageID ;AN000; IBM (compatible) mode?
+
+IF BUFFERFLAG
+ mov ax, cs:[LAST_PAGE]
+ mov es:[di.EMS_LAST_PAGE], ax
+ mov ax, cs:[LAST_PAGE+2]
+ mov es:[di.EMS_LAST_PAGE+2], ax
+ mov ax, cs:[FIRST_PAGE]
+ mov es:[di.EMS_FIRST_PAGE], ax
+ mov ax, cs:[FIRST_PAGE+2]
+ mov es:[di.EMS_FIRST_PAGE+2], ax
+ mov ax, cs:[NPA640]
+ mov es:[di.EMS_NPA640], ax
+ mov es:[di.EMS_SAFE_FLAG], 1
+ENDIF
+
+; $IF NC,AND,LONG ;AN000;
+ JNC $$XL5
+ JMP $$IF18
+$$XL5:
+ mov ah, EMAP_STATE ;AN010; Check if the size of
+ mov al, GET_MAP_SIZE ;AN010; the MAP state table
+ mov bx, 1 ;AN010; # of pages
+ int EMS_INT ;AN010; is acceptable.
+ or ah, ah ;AN010;
+; $IF Z,AND ;AN010;
+ JNZ $$IF18
+ cmp al, EMS_MAP_BUFF_SIZE ;AN010; Curretly=12 bytes
+; $IF BE,AND ;AN010;
+ JNBE $$IF18
+ mov ah, EQ_PAGES ;AN000; Get number of unallocated & total pages = 42h
+ int EMS_INT ;AN000; result in BX
+ xor dx, dx ;AN000;
+ mov ax, cs:[Buffers] ;AN000;
+ mov cx, MAXBUFFINBUCKET*MAXBUCKETINPAGE ;AN000;
+ call Roundup ;AN000; find out how many pages are needed.
+ cmp bx, ax ;AN000; AX is the number of pages for [buffers]
+; $IF AE,AND ;AN000;
+ JNAE $$IF18
+ mov cs:[Buffer_Pages], ax ;AN000;
+ mov bx, ax ;AN000; prepare for Get handle call.
+ mul cx ;AN000;
+ mov cs:[Buffers], ax ;AN000; set new [Buffers] for the extended memory.
+ mov ah, E_GET_HANDLE ;AN000; allocate pages = 43h
+ int EMS_INT ;AN000; page handle in DX.
+ or ah, ah ;AN000;
+; $IF Z ;AN000; pages allocated.
+ JNZ $$IF18
+ mov ah, EMS_HANDLE_NAME ;AN010;
+ mov al, SET_HANDLE_NAME ;AN010;
+ push es ;AN010;
+ push di ;AN010;
+ push ds ;AN010;
+ push cs ;AN010;
+ pop ds ;AN010;
+ mov si, offset EMSHandleName ;AN010;
+ int EMS_INT ;AN010; Set the handle name
+ pop ds ;AN010;
+ pop di ;AN010;
+ pop es ;AN010;
+ xor ah,ah ;AN010;
+ mov es:[di.EMS_MODE], ah ;AN000; put 0 in EMS_mode.
+ mov es:[di.EMS_HANDLE], dx ;AN000; save EMS handle
+ mov ax, cs:[IBM_Frame_Seg] ;AN010;
+ mov es:[di.EMS_PAGE_FRAME],ax ;AN010;
+ mov ax, cs:[Real_IBM_Page_Id] ;AN029;
+ mov es:[di.EMS_PAGEFRAME_NUMBER], ax;AN029;
+ mov ax, es ;AN010;
+ mov word ptr cs:[EMS_Ctrl_tab+2],ax ;AN010;
+ mov word ptr cs:[EMS_state_buf+2],ax;AN010;
+ push di ;AN010;save di-> Buffinfo
+ add di, EMS_SEG_CNT ;AN010;
+ mov word ptr cs:[EMS_Ctrl_tab], di ;AN010;
+ pop di ;AN010;
+ add di, EMS_MAP_BUFF ;AN010;
+ mov word ptr cs:[EMS_state_Buf],di ;AN010;
+ clc ;AN000;
+; $ELSE ;AN000;
+ JMP SHORT $$EN18
+$$IF18:
+ mov ax, cs:[Buffer_LineNum] ;AN000; Show error message.
+ push cs:[LineCount] ;AN017; Save current line count
+ mov cs:[LineCount], ax ;AN000; Now, we can change Linecount
+ call Error_Line ;AN000; since we are through with CONFIG.SYS file.
+ pop cs:[LineCount] ;AN017; Restore line count
+ stc ;AN000;
+; $ENDIF
+$$EN18:
+ pop bx ;AN010;
+ pop si ;AN010;
+ pop di ;AN000;
+ pop es ;AN000;
+ ret ;AN000;
+DoEMS endp
+
+;
+Set_Buffer proc near
+;*******************************************************************************
+;Function: Set buffers in the real memory. *
+; For each hash table entry, set the pointer to the *
+; corresponding hash bucket. *
+; Lastly set the memhi, memlo for the next available free address. *
+; ** At the request of IBMDOS, each hash bucket will start at the *
+; ** new segment. *
+; *
+;Input: ds:bx -> BuffInfo. *
+; [Memhi]:[MemLo = 0] = available space for the hash bucket. *
+; BufferInfo.Hash_Ptr -> Hash table. *
+; BufferBuckets = # of buckets to install. *
+; SingleBufferSize = Buffer header size + Sector size *
+; MaxNumBuff1 = Number of buffers in the first group of buckets *
+; MaxNumBuff2 = Number of buffers in the second group of buckets *
+; NthBuck = 1st thru Nth bucket are the first group *
+; *
+;Output: Buffers, hash buckets and Hash table entries established. *
+; [Memhi]:[Memlo] = address of the next available free space. *
+; *
+; { For (every bucket) *
+; { Set Hash table entry; *
+; Next buffer ptr = buffer size; *
+; For (every buffer in the bucket) *
+; { Calll Set_Buffer_Info; /*Set link, id... */ *
+; IF (last buffer in a bucket) THEN *
+; {last buffer's next_ptr -> first buffer; *
+; first buffer's prev_ptr -> last buffer; *
+; }; *
+; Next buffer ptr += buffer size; *
+; }; *
+; }; *
+; MEMHI:MEMLO = Current Buffer_Bucket add + (# of odd * buffer size)*
+; }; *
+;*******************************************************************************
+
+ assume ds:nothing ;AN000;to make sure.
+ lds bx, ds:[bx.HASH_PTR] ;AN000;now, ds:bx -> hash table
+ xor dx, dx ;AN026;To be used to count buckets
+; $DO ;AN000;For each bucket
+$$DO21:
+ inc dl ;AN026; Current bucket number
+ mov word ptr ds:[bx.BUFFER_BUCKET],0 ;AN000;Memlo is 0 after ROUND.
+ mov di, [MemHi] ;AN000;
+ mov word ptr ds:[bx.BUFFER_BUCKET+2], di ;AN000;Hash entry set.
+ mov word ptr ds:[bx.DIRTY_COUNT], 0 ;AN020;set DIRTY_COUNT, BUFFER_RESERVED to 0.
+ mov es, di ;AN000;
+ xor di, di ;AN000;es:di -> hash bucket
+ xor cx, cx ;AN000
+ xor ax, ax ;AN000
+; $DO ;AN000;For each buffer in the bucket
+$$DO22:
+ call Set_Buffer_Info ;AN000;Set buf_link, buf_id...
+ inc cx ;AN000;buffer number
+ cmp dl, [NthBuck] ;AN026;Current bucket number > NthBuck?
+; $IF BE ;AN026;
+ JNBE $$IF23
+ cmp cl, [MaxNumBuf1] ;AN026; last buffer of the 1st group?
+; $ELSE ;AN026;
+ JMP SHORT $$EN23
+$$IF23:
+ cmp cl, [MaxNumBuf2] ;AN026; last buffer of the 2nd group?
+; $ENDIF ;AN026;
+$$EN23:
+
+; $IF E ;AN020;Yes, last buffer
+ JNE $$IF26
+ mov word ptr es:[di.BUF_NEXT], 0 ;AN020;the last buffer's next -> the first buffer in bucket (Circular chain)
+ mov word ptr es:[BUF_PREV], di ;AN020;the first buffer's prev -> the last buffer
+; $ENDIF ;AN020;
+$$IF26:
+ mov di, ax ;AN000;adjust next buffer position
+; $ENDDO E ;AN000;flag set already for testing last buffer.
+ JNE $$DO22
+ add [Memlo], ax ;AN000;AX is the size of this bucket.
+ or [SetDevMarkFlag], FOR_DEVMARK ;AN005;Update DEVMARK_SIZE
+ call Round ;AN000;memhi:memlo adjusted for the next bucket.
+ add bx, size BUFFER_HASH_ENTRY ;AN000;ds:bx -> next hash entry.
+ dec [BufferBuckets] ;AN000;
+; $ENDDO Z ;AN000;
+ JNZ $$DO21
+ ret ;AN000;
+Set_Buffer endp
+
+;
+Set_EMS_Buffer proc near
+;*******************************************************************************
+;Function: Set buffers in the extended memory. *
+; For each hash table entry, set the pointer to the corresponding *
+; hash bucket. *
+; *
+;Input: ds:bx -> BuffInfo. *
+; BuffINFO.Hash_Ptr -> Hash table. *
+; BuffINFO.EMS_Handle = EMS handle *
+; Buffers = tatal # of buffers to install. *
+; Multiple of MAXBUFFINBUCKET*MAXBUCKETINPAGE. *
+; Buffer_Pages = # of extended memory pages for buffers. *
+; BufferBuckets = # of buckets to install. *
+; SingleBufferSize = Buffer header size + Sector size. *
+; *
+;Output: Buffers, hash buckets and Hash table entries established. *
+; *
+; { For (each page) *
+; { Map the page; /*Map the page into Page frame *
+; For (each bucket) /*Each page has two buckets */ *
+; { *
+; Set EMS_Page; *
+; Set Buffer_Bucket; *
+; Next buffer ptr = buffer size; *
+; For (every buffer) /*A bucket has 15 buffers */ *
+; { Set Buf_link to Next buffer ptr; *
+; Set Buffer_ID to free; *
+; If (last buffer in this bucket) THEN *
+; {Buf_link = -1; *
+; Next buffer ptr = 0; *
+; }; *
+; Next buffer ptr += buffer size; *
+; }; *
+; }; *
+; }; *
+; }; *
+;*******************************************************************************
+
+ assume ds:nothing ;AN000;to make sure.
+
+IF BUFFERFLAG
+
+ push ax
+ mov ax, offset ems_save_buf
+ mov word ptr cs:[ems_state_buf], ax
+ push cs
+ pop word ptr cs:[ems_state_buf+2]
+ pop ax
+
+ENDIF
+
+ call Save_MAP_State ;AN010;
+ mov dx, es:[bx.EMS_Handle] ;AN000;save EMS_Handle
+ lds si, ds:[bx.HASH_PTR] ;AN000;now ds:si -> Hash table
+ xor bx, bx ;AN000;starting logical page number.
+; $DO ;AN000;For each page,
+$$DO30:
+ call Map_Page ;AN000;map it to IBM physical page 254.
+ mov di, cs:IBM_Frame_Seg ;AN000;
+ mov es, di ;AN000
+ xor di, di ;AN000;es:di -> bucket
+ xor ax, ax ;AN000
+ xor cx, cx ;AN000
+; $DO ;AN000;For each bucket,
+$$DO31:
+ mov ds:[si.EMS_PAGE_NUM], bx ;AN000;set the logical page number in Hash table.
+ mov word ptr ds:[si.BUFFER_BUCKET], di ;AN000;set the offset in hash table for this bucket.
+ mov word ptr ds:[si.BUFFER_BUCKET+2], es ;AN000;set the segment value in hash table.
+ mov word ptr ds:[si.DIRTY_COUNT], 0 ;AN020;set DIRTY_COUNT, BUFFER_RESERVED to 0.
+ push cx ;AN000;save bucket number
+ xor cx, cx ;AN000;
+; $DO ;AN000;For each buffer in a bucket,
+$$DO32:
+ call Set_Buffer_Info ;AN000;AX adjusted for the next buffer.
+ inc cx ;AN000;inc number of buffers in this bucket.
+ cmp cx, 1 ;AN020;The first buffer in the bucket?
+; $IF E ;AN020;
+ JNE $$IF33
+ mov cs:[EMS_Buf_First], di ;AN020;then save the offset value
+; $ENDIF ;AN020;
+$$IF33:
+ cmp cx, MAXBUFFINBUCKET ;AN000;
+; $IF E ;AN000
+ JNE $$IF35
+ push word ptr cs:[EMS_Buf_First] ;AN020;
+ pop word ptr es:[di.BUF_NEXT] ;AN020;the last buffer's next -> the first buffer in bucket (Circular chain)
+ push di ;AN020;save di
+ push di ;AN020;di-> last buffer
+ mov di, cs:[EMS_Buf_First] ;AN020;es:di-> first buffer
+ pop word ptr es:[di.BUF_PREV] ;AN020;the first buffer's prev -> the last buffer
+ pop di ;AN020;restore di
+; $ENDIF ;AN000;
+$$IF35:
+ mov di, ax ;AN000;advance di to the next buffer position.
+; $ENDDO E ;AN000;
+ JNE $$DO32
+ add si, size BUFFER_HASH_ENTRY ;AN000;ds:si -> next hash table entry
+ pop cx ;AN000;restore bucket number
+ inc cx ;AN000;next bucket
+ cmp cx, MAXBUCKETINPAGE ;AN000;2 buckets per page
+; $ENDDO E ;AN000;
+ JNE $$DO31
+ inc bx ;AN000;increse logical page number
+ cmp bx, cs:[Buffer_Pages] ;AN000;reached the maximum page number?
+; $ENDDO E ;AN000;
+ JNE $$DO30
+ call Restore_MAP_State ;AN010;
+ ret ;AN000;
+Set_EMS_Buffer endp
+
+
+Set_Buffer_Info proc
+;Function: Set buf_link, buf_id, Buf_Sector
+;In: ES:DI -> Buffer header to be set.
+; AX = DI
+;Out:
+; Above entries set.
+
+
+ push [Buf_Prev_Off] ;AN020;
+ pop es:[di.BUF_PREV] ;AN020;
+ mov Buf_Prev_Off, ax ;AN020;
+ add ax, [SingleBufferSize] ;AN000;adjust ax
+ mov word ptr es:[di.BUF_NEXT], ax ;AN020;
+ mov word ptr es:[di.BUF_ID], 00FFh ;AN000;new buffer free
+ mov word ptr es:[di.BUF_SECTOR], 0 ;AN000;To compensate the MASM 3 bug
+ mov word ptr es:[di.BUF_SECTOR+2],0 ;AN000;To compensate the MASM 3 bug
+ ret ;AN000;
+Set_Buffer_Info endp
+
+Check_IBM_PageID proc near
+;Function: check if the physical page 255 exists. (Physical page 255 is only
+; one we are intereseted in, and this will be used for BUFFER
+; manipulation by IBMBIO, IBMDOS)
+;In: nothing
+;Out: Carry clear and IBM_Frame_Seg set if it exist. All registers saved.
+ push es ;AN000;
+ push ax ;AN000;
+ push bx ;AN000;
+ push cx ;AN000;
+ push dx ;AN000;
+ push di ;AN010;
+
+IF NOT BUFFERFLAG
+
+ mov ax, 1B00h ;AN029;AN030;AN0 Check EMS int 2fh installed.
+ int 2fh ;AN029;
+ cmp al, 0ffh ;AN029;
+ jne Cp_IBM_Err ;AN029;If not installed, then no IBM page.
+ mov ax, 1B01h ;AN029;AN030;Then ask if IBM page exists.
+ mov di, IBM_PAGE_ID ;AN029;=255
+ int 2fh ;AN029;
+ or ah, ah ;AN029;
+ jnz Cp_IBM_Err ;AN029;;No IBM Page
+ mov cs:IBM_Frame_Seg, es ;AN029;;Save Physical IBM page frame addr.
+ mov cs:Real_IBM_Page_Id, di ;AN029;;Real page number for it.
+ clc ;AN029;
+ jmp short Cp_ID_Ret ;AN029;
+
+ELSE
+ push cs ;AN000;
+ pop es ;AN000;
+ mov ah, GET_PAGE_FRAME ;AN010;=58h
+ mov al, GET_NUM_PAGEFRAME ;AN010;=01h How many page frames?
+ int EMS_INT ;AN010;
+ or ah, ah ;AN010;
+ jnz hkn_err ;AN010;
+ cmp cx, MAX_NUM_PAGEFRAME ;AN010;
+ ja hkn_err ;AN010; cannot handle this big number
+ push cx ;AN010;
+ mov ah, GET_PAGE_FRAME ;AN010;
+ mov al, GET_PAGEFRAME_TAB ;AN010;
+ mov di, offset Frame_info_Buffer ;AN010;
+ int EMS_INT ;AN010;
+ pop cx ;AN010;
+ or ah, ah ;AN010;
+ jnz cp_IBM_Err ;AN010;
+Cp_IBM_ID: ;AN010;
+
+; mov dx, es:[di]
+; mov cs:[FIRST_PAGE], dx
+; mov dx, es:[di+2]
+; mov cs:[FIRST_PAGE+2], dx
+
+ xor dx, dx
+
+; int 3
+find_page:
+ cmp es:[di], 0a000h ; is current page above 640K
+ jb next ; NO - goto check_last
+
+ inc dx ; count the no. of pages above 640K
+
+ cmp dx, 1
+ jne first_ok
+
+ mov ax, es:[di]
+ mov cs:[FIRST_PAGE], ax
+ mov ax, es:[di+2]
+ mov cs:[FIRST_PAGE+2], ax
+
+first_ok:
+ mov ax, cs:[FIRST_PAGE]
+ cmp ax, es:[di] ; is this page less than the one we have in
+ ; FIRST_PAGE
+ jbe check_last ; NO - goto check_last
+ mov ax, es:[di] ; update FIRST_PAGE with this page segment
+ mov cs:[FIRST_PAGE], ax
+ mov ax, es:[di+2]
+ mov cs:[FIRST_PAGE+2], ax
+ jmp next
+
+hkn_err: jmp cp_ibm_err
+
+check_last:
+ mov ax, cs:[LAST_PAGE] ;
+ cmp ax, es:[di] ; is this page greater than the one we have in
+ ; LAST_PAGE?
+ ja next ; NO - goto next
+ mov ax, es:[di] ; update LAST_PAGE with this value.
+ mov cs:[LAST_PAGE], ax
+ mov ax, es:[di+2]
+ mov cs:[LAST_PAGE+2], ax
+
+next:
+ add di, 4
+ loop find_page
+
+ cmp dx, 3 ; there should be at least 3 pages
+ ; above 640K for the buffers to be
+ ; installed.
+ jb Cp_IBM_Err
+
+ mov ax, cs:[LAST_PAGE]
+ mov cs:IBM_Frame_Seg, ax
+ mov ax, cs:[LAST_PAGE+2]
+ mov cs:Real_IBM_Page_Id, ax
+ mov cs:[NPA640], dx
+ clc
+ jmp short Cp_Id_Ret
+
+ENDIF
+
+
+; cmp word ptr es:[di+2], IBM_PAGE_ID ;AN010; the second word is the id
+; je Got_IBM_ID ;AN010;
+; add di, 4 ;AN010; advance to the next row (4 bytes)
+; loop Cp_IBM_ID ;AN010;
+
+Cp_IBM_Err: ;AN010;;AN029;
+ stc ;AN000;;AN029;
+ jmp short Cp_ID_Ret ;AN000;;AN029;
+
+;Got_IBM_ID: ;AN000;
+; mov ax, word ptr es:[di] ;AN010;Physical seg. addr.
+; mov cs:IBM_Frame_Seg, ax ;AN000;
+; clc ;AN000;
+Cp_ID_Ret: ;AN000;
+ pop di ;AN010;
+ pop dx ;AN000;
+ pop cx ;AN000;
+ pop bx ;AN000;
+ pop ax ;AN000;
+ pop es ;AN000;
+ ret ;AN000;
+Check_IBM_PageID endp
+
+;
+Save_Map_State proc ;AN010;
+;Function: Save the map state.
+;In)
+; EMS_Ctrl_Tab = double word pointer to EMS_state control table address
+; EMS_state_Buf = double word pointer to EMS_MAP_BUFF address
+;Out) Map state saved
+ push ax ;AN010;
+ push ds ;AN010;
+ push si ;AN010;
+ push es ;AN010;
+ push di ;AN010;
+ lds si, cs:EMS_Ctrl_Tab ;AN010;
+ les di, cs:EMS_state_Buf ;AN010;
+ mov ah, EMAP_STATE ;AN010; =4Fh
+ mov al, GET_MAP_STATE ;AN010; =00h
+ int EMS_INT ;AN010;
+ pop di ;AN010;
+ pop es ;AN010;
+ pop si ;AN010;
+ pop ds ;AN010;
+ pop ax ;AN010;
+ ret ;AN010;
+Save_Map_State endp
+;
+Restore_Map_State proc ;AN010;
+ push ax ;AN010;
+ push ds ;AN010;
+ push si ;AN010;
+ lds si, cs:EMS_state_Buf ;AN010;
+ mov ah, EMAP_STATE ;AN010;
+ mov al, SET_MAP_STATE ;AN010;
+ int EMS_INT ;AN010;
+ pop si ;AN010;
+ pop ds ;AN010;
+ pop ax ;AN010;
+ ret ;AN010;
+Restore_Map_State endp
+;
+Map_Page proc near ;AN000;
+;Function: Map the logical page in BX of handle in DX to the physical page 255
+;In)
+; BX = logical page number
+; DX = EMS handle
+; EMS_Ctrl_Tab = double word pointer to EMS_state control table address
+; EMS_state_Buf = double word pointer to EMS_MAP_BUFF address
+;Out) Logical page mapped into first phsical page frame.
+; AX saved.
+
+ push ax ;AN000;
+ mov ah, EMAP_L_TO_P ;AN000;
+ mov al, byte ptr cs:Real_IBM_PAGE_ID ;AN029;= 255
+ int EMS_INT ;AN000;
+ pop ax ;AN000;
+ ret ;AN000;
+Map_Page endp ;AN000;
+;
+
+Roundup proc
+;In: DX;AX - operand
+; CX - divisor
+; Important: DX should be less than CX.
+;out: AX - Quotient (Rounded up)
+
+ div cx ;AN000;
+ or dx, dx ;AN000;
+ jz RU_ret ;AN000;
+ inc AX ;AN000;
+RU_ret: ;AN000;
+ ret ;AN000;
+Roundup endp
+;------------------------------------------------------------------------------
+;J.K. 5/6/86. IBMSTACK initialization routine.
+ IF STACKSW
+.SALL
+
+INCLUDE STKINIT.INC
+
+.XALL
+ ENDIF
+;------------------------------------------------------------------------------
+ public SetDevMark
+SetDevMark proc
+;Set the DEVMARK for MEM command.
+;In: [MEMHI] - the address to place DEVMARK
+; [MEMLO] = 0
+; AL = ID for DEVMARK_ID
+;OUT: DEVMARK established.
+; the address saved in cs:[DevMark_Addr]
+; [MEMHI] increase by 1.
+
+ push es ;AN005;
+ push cx ;AN005;
+
+ mov cx, cs:[memhi] ;AN005;
+ mov cs:[DevMark_Addr],cx ;AN005;
+ mov es, cx ;AN005;
+ mov es:[DEVMARK_ID], al ;AN005;
+ inc cx ;AN007;
+ mov es:[DEVMARK_SEG], cx ;AN007;
+
+ pop cx ;AN005;
+ pop es ;AN005;
+ inc cs:[memhi] ;AN005;
+ ret ;AN005;
+SetDevMark endp
+
+;*******************************************************************************
+;Function: Load SHARE.EXE, if Big_Media_Flag = 1 and SHARE.EXE has not been *
+; loaded yet. *
+; This routine will use the same path for SHELL= command. *
+; If SHELL= command has not been entered, then default to the root *
+; directory. *
+; If load fails, then issue message "Warning: SHARE.EXE not loaded" *
+; *
+;Input: Big_Media_Flag, COMMND *
+;Output: Share.exe loaded if necessary. *
+; *
+;*******************************************************************************
+LoadShare proc near ;AN021;
+ cmp Big_Media_Flag, 1 ;AN021;
+ jne LShare_Ret ;AN021;
+;Check if SHARE is already loaded.
+ mov ax, 1000h ;AN021;multShare installation check
+ int 2fh ;AN021;
+ cmp al, 0ffh ;AN021;
+ jz LShare_Ret ;AN021;Share already loaded!
+;SHARE not loaded.
+ push cs ;AN021;
+ pop ds ;AN021;
+ push cs ;AN021;
+ pop es ;AN021;
+ mov si, offset COMMND ;AN021;
+ mov di, offset PathString ;AN021;
+LShare_String: ;AN021;
+ movsb ;AN021;
+ cmp byte ptr [di-1], 0 ;AN021;reached to the end?
+ jne LShare_string ;AN021;
+ mov si, offset PathString ;AN021;SI= start of PathString
+LShare_Tail: ;AN021;
+ dec di ;AN021;
+ cmp byte ptr [di], "\" ;AN021;
+ je LShare_Got_Tail ;AN021;
+ cmp byte ptr [di], ":" ;AN021;
+ je LShare_Got_Tail ;AN021;
+ cmp di, si ;AN021;No path case (e.g. SHELL=command.com)
+ je LShare_Got_Tail_0 ;AN021;
+ jmp LShare_Tail ;AN021;
+LShare_Got_Tail: ;AN021;di -> "\" or ":"
+ inc di ;AN021;
+LShare_Got_Tail_0: ;AN021;
+ mov si, offset LShare ;AN021;
+LShare_Set_Filename: ;AN021;
+ movsb ;AN021;Tag "SHARE.EXE",0,0Ah to the path.
+ cmp byte ptr [di-1], 0Ah ;AN021;Line feed?
+ jne LShare_Set_Filename ;AN021;
+;Now, we got a path,filename with no parameters for SHARE.EXE
+ mov si, offset PathString ;AN021;
+ or Install_Flag, SHARE_INSTALL ;AN021;Signals Do_Install_Exec that this is for SHARE.EXE.
+ call Do_Install_Exec ;AN021;execute it.
+ jnc LShare_Ret ;AN021;No problem
+;Load/Exec failed. Show "Warning: SHARE should be loaded for large media"
+ push cs ;AN021;
+ pop ds ;AN021;
+ mov dx, offset ShareWarnMsg ;AN021;WARNING! SHARE should be loaded...
+ invoke Print ;AN021;
+LShare_Ret: ;AN021;
+ ret ;AN021;
+LoadShare endp ;AN021;
+
+SYSINITSEG ENDS
+ END
+
\ No newline at end of file
diff --git a/v4.0/src/BIOS/SYSINIT2.ASM b/v4.0/src/BIOS/SYSINIT2.ASM
new file mode 100644
index 0000000..ff8b8ae
--- /dev/null
+++ b/v4.0/src/BIOS/SYSINIT2.ASM
@@ -0,0 +1,1624 @@
+ PAGE ,132 ;
+; SCCSID = @(#)sysinit2.asm 1.13 85/10/15
+TITLE BIOS SYSTEM INITIALIZATION
+%OUT ...SYSINIT2
+
+;==============================================================================
+;REVISION HISTORY:
+;AN000 - New for DOS Version 4.00 - J.K.
+;AC000 - Changed for DOS Version 4.00 - J.K.
+;AN00x - PTM number for DOS Version 4.00 - J.K.
+;==============================================================================
+;AN001; p132 Multiple character device installation problem. 6/27/87 J.K.
+;AN002; d24 MultiTrack= command added. 6/29/87 J.K.
+;AN003; p29 Extra space character in parameters passed.
+; (Modification on ORGANIZE routine for COMMENT= fixed this
+; problem too) 6/29/87 J.K.
+;AN004; d41 REM command in CONFIG.SYS 7/7/87 J.K.
+;AN005; d184 Set DEVMARK for MEM command 8/25/87 J.K.
+;AN006; p1820 New Message SKL file 10/20/87 J.K.
+;AN007; p1821 Include the COPYRIGH.INC file 10/22/87 J.K.
+;AN008; p2210 IBMDOS returns incorrect DBCS vector table length 11/02/87 J.K.
+;AN009; p2667 ccMono_Ptr problem 11/30/87 J.K.
+;AN010; p2792 Device?driver.sys /d:2 command should not work 12/09/87 J.K.
+;AN011; p3120 REM followed by CR, LF causes problem 01/13/88 J.K.
+;AN012; p3111 Take out the order dependency of the INSTALL= 01/25/88 J.K.
+;AN013; d479 New option to disable extended INT 16h function call 02/12/88 J.K.
+;AN014; D486 SHARE installation for big media 02/23/88 J.K.
+;AN015; D526 Add /NC parameter when installing SHARE.EXE 04/28/88 J.K.
+;==============================================================================
+
+TRUE EQU 0FFFFh
+FALSE EQU 0
+LF equ 10
+CR equ 13
+TAB equ 9
+
+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
+
+ IF IBMJAPVER
+NOEXEC EQU TRUE
+ ELSE
+NOEXEC EQU FALSE
+ ENDIF
+
+DOSSIZE EQU 0A000H
+
+.xlist
+; INCLUDE dossym.INC
+ include smdossym.inc ;J.K. Reduced version of DOSSYM.INC
+ INCLUDE devsym.INC
+ include ioctl.INC
+ include DEVMARK.inc
+.list
+
+ IF NOT IBM
+ IF NOT IBMJAPVER
+ EXTRN RE_INIT:FAR
+ ENDIF
+ ENDIF
+
+code segment public 'code'
+ extrn EC35_Flag: byte
+code ends
+
+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
+ 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
+ extrn COM_Level:byte, CMMT:byte, CMMT1:byte, CMMT2:byte
+ extrn Cmd_Indicator:byte
+ extrn DoNotShowNum:byte
+ extrn MultDeviceFlag:byte
+ extrn DevMark_Addr:word ;AN005;
+ extrn SetDevMarkFlag:byte ;AN005;
+ extrn Org_Count:word ;AN012;
+
+ EXTRN Stall:near
+ EXTRN Error_Line:near
+
+ 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
+ PUBLIC Cntry_Drv,Cntry_Root,Cntry_Path
+ PUBLIC Delim
+ public PathString ;AN014;
+ public LShare ;AN014;
+
+;
+; 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
+ push cs
+ pop ds
+ ASSUME DS:SYSINITSEG
+ xor bx,bx
+ mov bl,byte ptr drive
+ inc bl ; get it correct for IOCTL call (1=A,2=B...)
+ mov dx,offset DeviceParameters
+ mov ah, IOCTL
+ mov al, GENERIC_IOCTL
+ mov ch, RAWIO
+ mov cl, SET_DEVICE_PARAMETERS
+ int 21H
+ test word ptr Switches, flagec35
+ jz Not_EC35
+
+ mov cl, byte ptr drive ; which drive was this for?
+ mov ax, Code ; get Code segment
+ mov ds, ax ; set code segment
+ assume ds:code
+ mov al, 1 ; assume drive 0
+ shl al, cl ; set proper bit depending on drive
+ or ds:EC35_Flag, al ; set the bit in the permanent flags
+
+Not_EC35:
+ pop dx ; fix up all the registers
+ pop cx
+ pop bx
+ pop ax
+ pop ds
+ assume ds:nothing
+ ret
+
+;
+; Replace default values for further DRIVPARM commands
+;
+DiddleBack:
+ push ds
+ push cs
+ pop ds
+ assume ds:sysinitseg
+ 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
+ pop ds
+ assume ds:nothing
+ 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
+ ASSUME DS:SYSINITSEG
+NextSwtch:
+ cmp al,CR ; carriage return?
+ jz done_line
+ cmp al,LF ; 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, switchnum ; 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
+ xor ax,ax
+ mov COM_Level, 0
+
+;ORG1: CALL GET ;SKIP LEADING CONTROL CHARACTERS
+; CMP AL,' '
+; JB ORG1
+Org1:
+ call Skip_Comment ;AN000;
+ jz End_Commd_Line ;AN000; found a comment string and skipped.
+ call Get2 ;AN000; Not a comment string. Then get a char.
+ cmp al, LF ;AN000;
+ je End_Commd_Line ;AN000; starts with a blank line.
+ cmp al, ' ' ;AN000;
+ jbe Org1 ;AN000; skip leading control characters
+ jmp Findit ;AN000;
+End_Commd_Line: ;AN000;
+ stosb ;AN000; store line feed char in buffer for the LineCount.
+ mov COM_Level, 0 ;AN000; reset the command level.
+ jmp Org1 ;AN000;
+Findit: ;AN000;
+ 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
+ cmp byte ptr es:[di], CR ;AN011;The next char might be CR,LF
+ je GotCom0 ;AN011; such as in "REM",CR,LF case.
+ cmp byte ptr es:[di], LF ;AN011;
+ je GotCom0 ;AN011;
+ push ax ;AN010;
+ mov al, byte ptr es:[di] ;AN010;Now the next char. should be a delim.
+ call delim ;AN010;
+ pop ax ;AN010;
+ jnz findcom ;AN010;
+GotCom0:
+ POP DI
+ POP SI
+ POP CX
+ JMP SHORT GOTCOM
+
+NOCOM:
+ POP DI
+ POP SI
+ POP CX
+ MOV AL,'Z'
+ stosb ;AN000; save indicator char.
+Skip_Line: ;AN000;
+ call Get2 ;AN000;
+ cmp al, LF ;AN000; skip this bad command line
+ jne Skip_Line ;AN000;
+ jmp End_Commd_Line ;AN000; handle next command line
+
+GOTCOM: STOSB ;SAVE INDICATOR CHAR IN BUFFER
+ mov Cmd_Indicator, al ;AN000; save it for the future use.
+
+ORG2: CALL GET2 ;SKIP the commad name UNTIL DELIMITER
+ cmp al, LF ;AN011;
+ je Org21 ;AN011;
+ cmp al, CR ;AN011;
+ je Org21 ;AN011;
+ CALL DELIM ;
+ JNZ ORG2
+ jmp short Org3 ;AN011;
+Org21: ;AN011;if CR or LF then
+ dec si ;AN011; undo SI, CX register
+ inc cx ;AN011; and continue
+
+;ORG4: CALL GET2
+; call Delim ;J.K. 5/30/86. To permit "device=filename/p..." stuff.
+; jz ORG_EXT ;J.K. 5/30/86
+;Org4_Cont:
+; STOSB
+; CMP AL,' '
+; JA ORG4
+; CMP AL,10
+; JZ ORG1
+;
+; MOV BYTE PTR ES:[DI-1],0
+
+Org3:
+ cmp Cmd_Indicator, 'Y' ;AN000; Comment= command?
+ je Get_Cmt_Token ;AN000;
+ cmp Cmd_Indicator, 'I' ;AN000; Install= command?
+ je Org_file ;AN000;
+ cmp Cmd_Indicator, 'D' ;AN000; Device= command?
+ je Org_file ;AN000;
+ cmp Cmd_Indicator, 'J' ;AN000; IFS= command?
+ je Org_file ;AN000;
+ cmp Cmd_Indicator, 'S' ;AN000; Shell= is a special one!!!
+ je Org_file ;AN000;
+ cmp Cmd_Indicator, '1' ;AN013; SWITCHES= command?
+ je Org_Switch ;AN013;
+ jmp Org4 ;AN000;
+Org_Switch:
+ call Skip_Comment ;AN013;
+ jz End_Commd_Line_Brdg ;AN013;
+ call Get2 ;AN013;
+ call Org_Delim ;AN013;
+ jz Org_Switch ;AN013;
+ stosb ;AN013;
+ jmp Org5 ;AN013;
+Org_file: ;AN000; Get the filename and put 0 at end,
+ call Skip_Comment ;AN000;
+ jz Org_Put_Zero ;AN000;
+ call Get2 ;AN000; Not a comment
+ call Delim ;AN000;
+ jz Org_file ;AN000; Skip the possible delimeters
+ stosb ;AN000; copy the first non delim char found in buffer
+Org_Copy_File: ;AN000;
+ call Skip_Comment ;AN000; comment char in the filename?
+ jz Org_Put_Zero ;AN000; then stop copying filename at that point
+ call Get2 ;AN000;
+ cmp al, '/' ;AN000; a switch char? (device=filename/xxx)
+ je End_File_slash ;AN000; this will be the special case.
+ stosb ;AN000; save the char. in buffer
+ call Delim ;AN000;
+ jz End_Copy_File ;AN000;
+ cmp al, ' ' ;AN000;
+ ja Org_Copy_File ;AN000; keep copying
+ jmp End_Copy_File ;AN000; otherwise, assume end of the filename.
+Get_Cmt_token: ;AN000; get the token. Just max. 2 char.
+ call Get2 ;AN000;
+ cmp al, ' ' ;AN000; skip white spaces or "=" char.
+ je Get_Cmt_Token ;AN000; (we are allowing the other special
+ cmp al, TAB ;AN000; charaters can used for comment id.
+ je Get_Cmt_Token ;AN000; character.)
+ cmp al, '=' ;AN000; = is special in this case.
+ je Get_Cmt_Token ;AN000;
+ cmp al, CR ;AN000;
+ je Get_Cmt_End ;AN000; cannot accept the carridge return
+ cmp al, LF ;AN000;
+ je Get_Cmt_End ;AN000;
+ mov CMMT1, al ;AN000; store it
+ mov CMMT, 1 ;AN000; 1 char. so far.
+ call Get2 ;AN000;
+ cmp al, ' ' ;AN000;
+ je Get_Cmt_End ;AN000;
+ cmp al, TAB ;AN000;
+ je Get_Cmt_End ;AN000;
+ cmp al, CR ;AN000;
+ je Get_Cmt_End ;AN000;
+ cmp al, LF ;AN000;
+ je End_Commd_Line_Brdg ;AN000;
+ mov CMMT2, al ;AN000;
+ inc CMMT ;AN000;
+Get_Cmt_End: ;AN000;
+ call Get2 ;AN000;
+ cmp al, LF ;AN000;
+ jne Get_Cmt_End ;AN000; skip it.
+End_Commd_Line_Brdg: jmp End_Commd_Line ;AN000; else jmp to End_Commd_Line
+
+Org_Put_Zero: ;AN000; Make the filename in front of
+ mov byte ptr es:[di], 0 ;AN000; the comment string to be an asciiz.
+ inc di ;AN000;
+ jmp End_Commd_Line ;AN000; (Maybe null if device=/*)
+End_file_slash: ;AN000; AL = "/" option char.
+ mov byte ptr es:[di],0 ;AN000; make a filename an asciiz
+ inc di ;AN000; and
+ stosb ;AN000; store "/" after that.
+ jmp Org5 ;AN000; continue with the rest of the line
+
+End_Copy_File: ;AN000;
+ mov byte ptr es:[di-1], 0 ;AN000; make it an asciiz and handle the next char.
+ cmp al, LF ;AN000;
+ je End_Commd_Line_brdg ;AN000;
+ jmp Org5 ;AN000;
+
+Org4: ;AN000; Org4 skips all delimiters after the command name except for '/'
+ call Skip_Comment ;AN000;
+ jz End_Commd_Line_brdg ;AN000;
+ call Get2 ;AN000;
+ call Org_Delim ;AN000; skip delimiters EXCEPT '/' (mrw 4/88)
+ jz Org4 ;AN000;
+ jmp Org51 ;AN000;
+Org5: ;AN000; rest of the line
+ call Skip_Comment ;AN000; Comment?
+ jz End_Commd_Line_brdg ;AN000;
+ call Get2 ;AN000; Not a comment.
+Org51: ;AN000;
+ stosb ;AN000; copy the character
+ cmp al, '"' ;AN000; a quote ?
+ je At_Quote ;AN000;
+ cmp al, ' ' ;AN000;
+ ja Org5 ;AN000;
+ cmp al, LF ;AN000; line feed?
+ je Org1_brdg ;AN000; handles the next command line.
+ jmp Org5 ;AN000; handles next char in this line.
+Org1_brdg: jmp Org1 ;AN000;
+At_Quote: ;AN000;
+ cmp COM_Level, 0 ;AN000;
+ je Up_Level ;AN000;
+ mov COM_Level, 0 ;AN000; reset it.
+ jmp Org5 ;AN000;
+Up_Level: ;AN000;
+ inc COM_level ;AN000; set it.
+ jmp Org5 ;AN000;
+
+
+;ORG5: CALL GET2
+; STOSB
+; CMP AL,10
+; JNZ ORG5
+; JMP ORG1
+;
+;ORG_EXT:
+; cmp al,' ' ;space?
+; je Org4_Cont ;then do not make an exception. Go back.
+; cmp al,9 ;Tab?
+; je Org4_Cont
+; mov byte ptr es:[di], 0 ;put 0 at the current DI to make it an ASCIIZ
+; inc DI ;
+; stosb ;and copy the delimeter char.
+; jmp short ORG5 ;and continue as usual.
+
+
+GET2:
+ JCXZ NOGET
+ MOV AL,ES:[SI]
+ INC SI
+ DEC CX
+ return
+
+;GET: JCXZ NOGET
+; MOV AL,ES:[SI]
+; INC SI
+; DEC CX
+; CALL Org_DELIM
+; JZ GET
+; return
+
+Skip_Comment:
+;J.K.Skip the commented string until LF, if current es:si-> a comment string.
+;J.K.In) ES:SI-> sting
+;J.K. CX -> length.
+;J.K.Out) Zero flag not set if not found a comment string.
+;J.K. Zero flag set if found a comment string and skipped it. AL will contain
+;J.K. the line feed charater at this moment when return.
+;J.K. AX register destroyed.
+;J.K. If found, SI, CX register adjusted accordingly.
+
+ jcxz NoGet ;AN000; Get out of the Organize routine.
+ cmp COM_Level, 0 ;AN000; only check it if parameter level is 0.
+ jne No_Commt ;AN000; (Not inside quotations)
+
+ cmp CMMT, 1 ;AN000;
+ jb No_Commt ;AN000;
+ mov al, es:[si] ;AN000;
+ cmp CMMT1, al ;AN000;
+ jne No_Commt ;AN000;
+ cmp CMMT, 2 ;AN000;
+ jne Skip_Cmmt ;AN000;
+ mov al, es:[si+1] ;AN000;
+ cmp CMMT2, al ;AN000;
+ jne No_Commt ;AN000;
+Skip_Cmmt: ;AN000;
+ jcxz NoGet ;AN000; get out of Organize routine.
+ mov al, es:[si] ;AN000;
+ inc si ;AN000;
+ dec cx ;AN000;
+ cmp al, LF ;AN000; line feed?
+ jne Skip_Cmmt ;AN000;
+No_Commt: ;AN000;
+ ret ;AN000;
+
+
+DELIM:
+ CMP AL,'/' ;J.K. 5/30/86. IBM will assume "/" as an delimeter.
+ retz
+ cmp al, 0 ;J.K. 5/23/86 Special case for sysinit!!!
+ retz
+Org_Delim: ;AN000; Used by Organize routine except for getting
+ CMP AL,' ' ;the filename.
+ retz
+ CMP AL,9
+ retz
+ CMP AL,'='
+ retz
+ CMP AL,','
+ retz
+ CMP AL,';'
+ return
+
+
+NOGET: POP CX
+ MOV COUNT,DI
+ mov Org_Count, DI ;AN012;
+ XOR SI,SI
+ MOV CHRPTR,SI
+ return
+
+;Get3: jcxz NOGET ;J.K.do not consider '/',',' as a delim.
+; mov al, es:[si]
+; inc si
+; dec cx
+; call DELIM
+; jnz Get3_ret
+; cmp al,'/'
+; je Get3_ret
+; cmp al,','
+; jne Get3
+;Get3_ret:
+; ret
+
+
+
+;
+; NEWLINE RETURNS WITH FIRST CHARACTER OF NEXT LINE
+;
+NEWLINE:invoke GETCHR ;SKIP NON-CONTROL CHARACTERS
+ retc
+ CMP AL,LF ;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: ;device driver Init failed and aborted.
+ stc
+ pop ax
+ return
+
+SET_BREAK:
+;J.K. 8/14/86 For DOS 3.3, this routine is modified to take care of the
+;Device driver's initialization error and abort.
+;If [break_addr+2] == [memhi] && [break_addr] = 0 then assume
+;that the device driver's initialization has an error and wanted to
+;abort the device driver. In this case, this routine will set carry
+;and return to the caller.
+;J.K. 6/26/87 If MultDeviceFlag <> 0, then do not perform the check.
+;This is to allow the multiple character device driver which uses
+;the same ending address segment with the offset value 0 for each
+;of the drives.
+
+ PUSH AX
+ MOV AX,WORD PTR [BREAK_ADDR+2] ;REMOVE THE INIT CODE
+ cmp MultDeviceFlag, 0 ;AN001;
+ jne Set_Break_Continue ;AN001;Do not check it.
+ cmp ax, [MEMHI]
+ jne Set_Break_Continue ;if not same, then O.K.
+
+ cmp word ptr [BREAK_ADDR],0
+ je Yes_Break_failed ;[Break_addr+2]=[MEMHI] & [Break_addr]=0
+
+Set_Break_Continue:
+ MOV [MEMHI],AX
+ MOV AX,WORD PTR [BREAK_ADDR]
+ MOV [MEMLO],AX
+ POP AX ; NOTE FALL THROUGH
+ or [SetDevMarkFlag], SETBRKDONE ;AN005; Signal the successful Set_break
+
+;
+; 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
+ test cs:[SetDevMarkFlag], FOR_DEVMARK ;AN005;
+ jz Skip_Set_DEVMARKSIZE ;AN005;
+ push es ;AN005;
+ push si ;AN005;
+ mov si, cs:[DevMark_Addr] ;AN005;
+ mov es, si ;AN005;
+ sub ax, si ;AN005;
+ dec ax ;AN005;
+ mov es:[DEVMARK_SIZE], ax ;AN005; Paragraph
+ and cs:[SetDevMarkFlag], NOT_FOR_DEVMARK ;AN005;
+ pop si ;AN005;
+ pop es ;AN005;
+Skip_Set_DEVMARKSIZE: ;AN005;
+ POP AX
+ clc ;clear carry
+ 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 ; J.K.
+ 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 ; J.K.
+ 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, ' ' ;J.K. 5/23/86 space?
+ jz B15 ;J.K. 5/23/86 then end of digits
+ cmp al, ',' ;J.K. 5/23/86 ',' is a seperator!!!
+ jz B15 ;J.K. 5/23/86 then end of digits.
+ cmp al, TAB ;J.K. 5/23/86 TAB
+ jz B15 ;J.K.
+ CMP AL,SepChr ; allow 0 or special separators
+ JZ b15
+ cmp al,SWTCHR ; See if another switch follows
+ JZ b15
+ cmp al,LF ; Line-feed?
+ jz b15
+ cmp al,CR ; 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
+ return
+
+SKIP_DELIM proc near ;J.K.
+;Skip the delimeters pointed by CHRPTR. AL will contain the first non delimeter
+;character encountered and CHRPTR will point to the next character.
+;This rouitne will assume the second "," found as a non delimiter character. So
+;in case if the string is " , , ", this routine will stop at the second ",". At
+;this time, Zero flag is set.
+;If COUNT is exhausted, then carry will be set.
+Skip_delim_char:
+ call getchr
+ jc Skip_delim_exit
+ cmp al, ',' ;the first comma?
+ je Skip_delim_next
+ call delim ;check the charater in AL.
+ jz Skip_delim_char
+ jmp short Skip_delim_exit ;found a non delim char
+Skip_delim_next:
+ call getchr
+ jc Skip_delim_exit
+ cmp al, ',' ;the second comma?
+ je Skip_delim_exit ;done
+ call delim
+ jz Skip_delim_next
+Skip_delim_exit:
+ return
+SKIP_DELIM endp
+
+;J.K. 5/26/86 *****************************************************************
+SetDOSCountryInfo proc near
+;Input: ES:DI -> pointer to DOS_COUNTRY_CDPG_INFO
+; DS:0 -> buffer.
+; SI = 0
+; AX = country id
+; DX = code page id. (If 0, then use ccSysCodePage as a default.)
+; BX = file handle
+; This routine can handle maxium 72 COUNTRY_DATA entries.
+;Output: DOS_country_cdpg_info set.
+; Carry set if any file read failure or wrong information in the file.
+; Carry set and CX = -1 if cannot find the matching COUNTRY_id, CODEPAGE
+; _id in the file.
+
+ push di
+ push ax
+ push dx
+
+ xor cx,cx
+ xor dx,dx
+ mov ax, 512 ;read 512 bytes
+ call ReadInControlBuffer ;Read the file header
+ jc SetDOSData_fail
+ push es
+ push si
+ push cs
+ pop es
+ mov di, offset COUNTRY_FILE_SIGNATURE
+ mov cx, 8 ;length of the signature
+ repz cmpsb
+ pop si
+ pop es
+ jnz SetDOSData_fail ;signature mismatch
+
+ add si, 18 ;SI -> county info type
+ cmp byte ptr ds:[si], 1 ;Only accept type 1 (Currently only 1 header type)
+ jne SetDOSData_fail ;cannot proceed. error return
+ inc si ;SI -> file offset
+ mov dx, word ptr ds:[si] ;Get the INFO file offset.
+ mov cx, word ptr ds:[si+2]
+ mov ax, 1024 ;read 1024 bytes.
+ call ReadInControlBuffer ;Read INFO
+ jc SetDOSData_fail
+ mov cx, word ptr ds:[si] ;get the # of country, codepage combination entries
+ cmp cx, 72 ;cannot handle more than 72 entries.
+ ja SetDOSData_fail
+ inc si
+ inc si ;SI -> entry information packet
+ pop dx ;restore code page id
+ pop ax ;restore country id
+ pop di
+
+SetDOSCntry_find: ;Search for desired country_id,codepage_id.
+ cmp ax, word ptr ds:[si+2] ;compare country_id
+ jne SetDOSCntry_next
+ cmp dx, 0 ;No user specified code page ?
+ je SetDOSCntry_any_codepage;then no need to match code page id.
+ cmp dx, word ptr ds:[si+4] ;compare code page id
+ je SetDOSCntry_got_it
+SetDOSCntry_next:
+ add si, word ptr ds:[si] ;next entry
+ inc si
+ inc si ;take a word for size of entry itself
+ loop SetDOSCntry_find
+ mov cx, -1 ;signals that bad country id entered.
+SetDOSCntry_fail:
+ stc
+ ret
+
+SetDOSData_fail:
+ pop si
+ pop cx
+ pop di
+ jmp short SetDOSCntry_fail
+
+SetDOSCntry_any_CodePage: ;use the code_page_id of the country_id found.
+ mov dx, word ptr ds:[si+4]
+SetDOSCntry_got_it: ;found the matching entry
+ mov cs:CntryCodePage_Id, dx ;save code page ID for this country.
+ mov dx, word ptr ds:[si+10] ;get the file offset of country data
+ mov cx, word ptr ds:[si+12]
+ mov ax, 512 ;read 512 bytes
+ call ReadInControlBuffer
+ jc SetDOSCntry_fail
+ mov cx, word ptr ds:[si] ;get the number of entries to handle.
+ inc si
+ inc si ;SI -> first entry
+
+SetDOSCntry_data:
+ push di ;ES:DI -> DOS_COUNTRY_CDPG_INFO
+ push cx ;save # of entry left
+ push si ;si -> current entry in Control buffer
+
+ mov al, byte ptr ds:[si+2] ;get data entry id
+ call GetCountryDestination ;get the address of destination in ES:DI
+ jc SetDOSCntry_data_next ;No matching data entry id in DOS
+
+
+ mov dx, word ptr ds:[si+4] ;get offset of data
+ mov cx, word ptr ds:[si+6]
+ mov ax, 4200h
+ stc
+ int 21h ;move pointer
+ jc SetDOSData_fail
+ mov dx, 512 ;start of data buffer
+; mov cx, word ptr es:[di] ;length of the corresponding data in DOS.
+; add cx, 10 ;Signature + A word for the length itself
+ mov cx, 20 ;read 20 bytes only. We only need to
+ mov ah, 3fh ;look at the length of the data in the file.
+ stc
+ int 21h ;read the country.sys data
+ jc SetDOSData_fail ;read failure
+ cmp ax, cx
+ jne SetDOSData_fail
+
+ mov dx, word ptr ds:[si+4] ;AN008;get offset of data again.
+ mov cx, word ptr ds:[si+6] ;AN008;
+ mov ax, 4200h ;AN008;
+ stc ;AN008;
+ int 21h ;AN008;move pointer back again
+ jc SetDOSData_fail ;AN008;
+
+ push si ;AN008;
+ mov si, (512+8) ;AN008;get length of the data from the file
+ mov cx, word ptr ds:[si] ;AN008;
+ pop si ;AN008;
+ mov dx, 512 ;AN008;start of data buffer
+ add cx, 10 ;AN008;Signature + A word for the length itself
+ mov ah, 3fh ;AN008;Read the data from the file.
+ stc ;AN008;
+ int 21h ;AN008;
+ jc SetDOSData_fail ;AN008;
+ cmp ax, cx ;AN008;
+ jne SetDOSData_fail ;AN008;
+
+ mov al, byte ptr ds:[si+2] ;save Data id for future use.
+ mov si, (512+8) ;SI-> data buffer + id tag field
+ mov cx, word ptr ds:[si] ;get the length of the file
+ inc cx ;Take care of a word for lenght of tab
+ inc cx ;itself.
+ cmp cx, (2048 - 512 - 8) ;Fit into the buffer?
+ ja SetDOSData_fail
+ cmp al, SetCountryInfo ;is the data for SetCountryInfo table?
+ jne SetDOSCntry_Mov ;no, don't worry
+ push word ptr es:[di+ccMono_Ptr-ccCountryInfoLen] ;AN009;Cannot destroy ccMono_ptr address. Save them.
+ push word ptr es:[di+ccMono_Ptr-ccCountryInfoLen+2] ;AN009;At this time DI -> ccCountryInfoLen
+ push di ;save DI
+
+ push ax
+ mov ax,cs:CntryCodePage_Id ;Do not use the Code Page info in Country_Info
+ mov ds:[si+4], ax ;Use the saved one for this !!!!
+ pop ax
+
+SetDOSCntry_Mov:
+ rep movsb ;copy the table into DOS
+ cmp al, SetCountryInfo ;was the ccMono_ptr saved?
+ jne SetDOSCntry_data_next
+ pop di ;restore DI
+ pop word ptr es:[di+ccMono_Ptr-ccCountryInfoLen+2] ;AN009;restore
+ pop word ptr es:[di+ccMono_Ptr-ccCountryInfoLen] ;AN009;
+
+SetDOSCntry_data_next:
+ pop si ;restore control buffer pointer
+ pop cx ;restore # of entries left
+ pop di ;restore pointer to DSO_COUNTRY_CDPG
+ add si, word ptr ds:[si] ;try to get the next entry
+ inc si
+ inc si ;take a word of entry length itself
+; loop SetDOSCntry_data
+ dec cx ;AN008;
+ cmp cx,0 ;AN008;
+ je SetDOSCntry_OK ;AN008;
+ jmp SetDOSCntry_data ;AN008;
+SetDOSCntry_OK: ;AN008;
+ ret
+SetDOSCountryInfo endp
+;
+
+GetCountryDestination proc near
+;Get the destination address in the DOS country info table.
+;Input: AL - Data ID
+; ES:DI -> DOS_COUNTRY_CDPG_INFO
+;On return:
+; ES:DI -> Destination address of the matching data id
+; carry set if no matching data id found in DOS.
+
+ push cx
+ add di, ccNumber_of_entries ;skip the reserved area, syscodepage etc.
+ mov cx, word ptr es:[di] ;get the number of entries
+ inc di
+ inc di ;SI -> the first start entry id
+GetCntryDest:
+ cmp byte ptr es:[di], al
+ je GetCntryDest_OK
+ cmp byte ptr es:[di], SetCountryInfo ;was it SetCountryInfo entry?
+ je GetCntryDest_1
+ add di, 5 ;next data id
+ jmp short GetCntryDest_loop
+GetCntryDest_1:
+ add di, NEW_COUNTRY_SIZE + 3 ;next data id
+GetCntryDest_loop:
+ loop GetCntryDest
+ stc
+ jmp short GetCntryDest_exit
+GetCntryDest_OK:
+ cmp al, SetCountryInfo ;select country info?
+ jne GetCntryDest_OK1
+ inc di ;now DI -> ccCountryInfoLen
+ jmp short GetCntryDest_exit
+GetCntryDest_OK1:
+ les di, dword ptr es:[di+1] ;get the destination in ES:DI
+GetCntryDest_Exit:
+ pop cx
+ ret
+GetCountryDestination endp
+
+;
+ReadInControlBuffer proc near
+;Move file pointer to CX:DX
+;Read AX bytes into the control buffer. (Should be less than 2 Kb)
+;SI will be set to 0 hence DS:SI points to the control buffer.
+;Entry: CX,DX offset from the start of the file where the read/write pointer
+; be moved.
+; AX - # of bytes to read
+; BX - file handle
+; DS - buffer seg.
+;Return: The control data information is read into DS:0 - DS:0200.
+; CX,DX value destroyed.
+; Carry set if error in Reading file.
+;
+ push ax ;# of bytes to read
+ mov ax, 4200h
+ stc
+ int 21h ;move pointer
+ pop cx ;# of bytes to read
+ jc RICB_exit
+ xor dx,dx ;ds:dx -> control buffer
+ xor si,si
+ mov ah,3fh ;read into the buffer
+ stc
+ int 21h ;should be less than 1024 bytes.
+RICB_exit:
+ ret
+ReadInControlBuffer endp
+
+;
+SET_COUNTRY_PATH proc near
+;In: DS - SYSINITSEG, ES - CONFBOT, SI -> start of the asciiz path string
+; DOSINFO_EXT, CNTRY_DRV, CNTRY_ROOT, CNTRY_PATH
+; Assumes current directory is the ROOT directory.
+;Out: DS:DI -> full path (CNTRY_DRV).
+; Set the CNTRY_DRV string from the COUNTRY=,,path command.
+; DS, ES, SI value saved.
+
+ push si
+ push ds ;switch ds, es
+ push es
+ pop ds
+ pop es ;now DS -> CONFBOT, ES -> SYSINITSEG
+
+ call chk_drive_letter ;current DS:[SI] is a drive letter?
+ jc SCP_Default_drv ;no, use current default drive.
+ mov al, byte ptr DS:[SI]
+ inc si
+ inc si ;SI -> next char after ":"
+ jmp short SCP_SetDrv
+SCP_Default_drv:
+ mov ah, 19h
+ int 21h
+ add al, "A" ;convert it to a character.
+SCP_SetDrv:
+ mov cs:CNTRY_DRV, al ;set the drive letter.
+ mov di, offset CNTRY_PATH
+ mov al, byte ptr DS:[SI]
+ cmp al, "\"
+ je SCP_Root_Dir
+ cmp al, cs:SWTCHR ;let's accept "/" as an directory delim
+ je SCP_Root_Dir
+ jmp short SCP_Path
+SCP_Root_Dir:
+ dec di ;DI -> CNTRY_ROOT
+SCP_Path:
+ call MOVE_ASCIIZ ;copy it
+ mov di, offset CNTRY_DRV
+SCPath_Exit:
+ push ds ;switch ds, es
+ push es
+ pop ds
+ pop es ;DS, ES value restored
+ pop si
+ RET
+SET_COUNTRY_PATH endp
+
+;
+CHK_DRIVE_LETTER proc near
+;Check if DS:[SI] is a drive letter followed by ":".
+;Assume that every alpha charater is already converted to UPPER CASE.
+;Carry set if not.
+;
+ push ax
+ cmp byte ptr ds:[si], "A"
+ jb CDLetter_NO
+ cmp byte ptr ds:[si], "Z"
+ ja CDLetter_NO
+ cmp byte ptr ds:[si+1], ":"
+ jne CDLetter_NO
+ jmp short CDLetter_exit
+CDLetter_NO:
+ stc
+CDLetter_exit:
+ pop ax
+ ret
+CHK_DRIVE_LETTER endp
+
+;
+MOVE_ASCIIZ proc near
+;In: DS:SI -> source ES:DI -> target
+;Out: copy the string until 0.
+;Assumes there exists a 0.
+MASCIIZ_loop:
+ movsb
+ cmp byte ptr DS:[SI-1], 0 ;Was it 0?
+ jne MASCIIZ_loop
+ ret
+MOVE_ASCIIZ endp
+
+;
+; 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
+ mov bx, offset CRLFM ;AN006;
+PRNERR:
+ PUSH CS
+ POP DS
+ call Print
+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
+ call Print
+ cmp DoNotShowNum, 1 ;AN000; suppress line number when handling COMMAND.COM
+ je Prnexit
+ call Error_Line
+PRNEXIT:
+ return
+
+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
+
+;J.K. TEST INT24. Return back to DOS with the fake user response of "FAIL"
+INT24:
+ mov al, 3 ;AN000; Fail the system call
+ iret ;AN000; Return back to DOS.
+
+
+;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,88 Microsoft Corp.",13,10,"$"
+ ENDIF
+
+include copyrigh.inc ;P1821; Copyright statement
+
+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:"
+CNTRY_ROOT DB "\"
+CNTRY_PATH DB "COUNTRY.SYS",0
+ DB 52 DUP (0)
+
+COUNTRY_FILE_SIGNATURE db 0FFh,'COUNTRY'
+
+CntryCodePage_Id DW ?
+
+COMMND DB "\COMMAND.COM",0
+ DB 51 dup (0)
+
+PathString db 64 dup (0) ;AN014;
+LShare db "SHARE.EXE",0,"/NC",0Dh,0Ah ;AN014;AN015;To be used by Load/exec.
+ ;/NC parm will disable file sharing check.
+
+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 10,"MULTITRACK", 'M' ;AN002;
+ DB 8,"DRIVPARM", 'P' ; RS for DOS 3.2
+ IF STACKSW
+ DB 6,"STACKS", 'K' ; BAS for DOS 3.2
+ ENDIF
+ DB 7,"COUNTRY", 'Q'
+ DB 5,"SHELL", 'S'
+ db 7,"INSTALL", 'I' ;AN000;
+ db 3,"IFS", 'J' ;AN000;
+ db 4,"CPSW", 'W' ;AN000;
+;;;; DB 8,"SWITCHAR",'W' ; NO LONGER SUPPORTED
+ db 7,"COMMENT", 'Y' ;AN000;
+ db 3,"REM", '0' ;AN004;
+ db 8,"SWITCHES", '1' ;AN013;
+ 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 0
+
+;
+; 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
+ DD 0
+
+; 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
+ DD 0
+
+; 3 1/2 inch diskette BPB
+
+BPB35 DW 512
+ DB 2
+ DW 1
+ DB 2
+ DW 70h
+ DW 2*9*80
+ DB 0F9H
+ DW 3
+ DW 9
+ DW 2
+ DD 0
+ DD 0
+
+BPB35H DW 0200H
+ DB 01H
+ DW 0001H
+ DB 02H
+ DW 0E0h
+ DW 0B40H
+ DB 0F0H
+ DW 0009H
+ DW 0012H
+ DW 0002H
+ DD 0
+ DD 0
+
+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 BPB35H ; 3-1/2" 1.44MB drive
+
+switchlist db 8,"FHSTDICN" ; Preserve the positions of N and C.
+
+; The following depend on the positions of the various letters in SwitchList
+
+switchnum equ 11111000B ; which switches require number
+
+flagec35 equ 00000100B ; electrically compatible 3.5 inch disk drive
+flagdrive equ 00001000B
+flagcyln equ 00010000B
+flagseclim equ 00100000B
+flagheads equ 01000000B
+flagff equ 10000000B
+
+SWTCHR EQU "/" ; switch follows this character
+
+SYSINITSEG ENDS
+ END
diff --git a/v4.0/src/BOOT/BOOT.SKL b/v4.0/src/BOOT/BOOT.SKL
new file mode 100644
index 0000000..764febd
--- /dev/null
+++ b/v4.0/src/BOOT/BOOT.SKL
@@ -0,0 +1,8 @@
+:class 1
+; MESSAGES FOR THE IBM BOOT SECTOR. NUL Terminated.
+; At this time, for DOS 4.00, we only have maximum 11 bytes left
+; for translation.!!!!!!!!!!!!!!!!!!!!!
+
+:use 001 BOOT SYSMSG
+
+:end
diff --git a/v4.0/src/BOOT/MAKEFILE b/v4.0/src/BOOT/MAKEFILE
new file mode 100644
index 0000000..12ac4d8
--- /dev/null
+++ b/v4.0/src/BOOT/MAKEFILE
@@ -0,0 +1,25 @@
+#******************** makefile for boot *****************************
+
+msg =..\messages
+dos =..\dos
+inc =..\inc
+hinc =..\h
+
+#
+#################### dependencies begin here ############################
+#
+
+all: msboot.bin
+
+boot.cl1: boot.skl \
+ $(msg)\$(COUNTRY).MSG \
+ makefile
+
+msboot.obj: msboot.asm boot.cl1
+
+msboot.bin: msboot.obj
+ link msboot;
+ exe2bin msboot.exe msboot.bin
+ dbof msboot.bin boot.inc 7c00 200
+ copy boot.inc $(inc)
+ del boot.inc
diff --git a/v4.0/src/BOOT/MSBOOT.ASM b/v4.0/src/BOOT/MSBOOT.ASM
new file mode 100644
index 0000000..b2a4103
--- /dev/null
+++ b/v4.0/src/BOOT/MSBOOT.ASM
@@ -0,0 +1,530 @@
+ Page 60,132 ; SCCSID = @(#)msboot.asm 1.1 85/05/13
+TITLE BOOT SECTOR 1 OF TRACK 0 - BOOT LOADER
+
+; Rev 1.0 ChrisP, AaronR and others. 2.0 format boot
+;
+; Rev 3.0 MarkZ PC/AT enhancements
+; 2.50 in label
+; Rev 3.1 MarkZ 3.1 in label due to vagaries of SYSing to IBM drive D's
+; This resulted in the BPB being off by 1. So we now trust
+; 2.0 and 3.1 boot sectors and disbelieve 3.0.
+;
+; Rev 3.2 LeeAc Modify layout of extended BPB for >32M support
+; Move PHYDRV to 3rd byte from end of sector
+; so that it won't have to be moved again
+; FORMAT and SYS count on PHYDRV being in a known location
+;
+; Rev. 3.3 D.C. L. 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 IBMBIO. 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.
+;
+; Rev 4.00 J. K. For DOS 4.00 Modified to handle the extended BPB, and
+; 32 bit sector number calculation to enable the primary
+; partition be started beyond 32 MB boundary.
+;
+;
+; 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
+; (IBMBIO) 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)
+;
+;==============================================================================
+;REVISION HISTORY:
+;AN000 - New for DOS Version 4.00 - J.K.
+;AC000 - Changed for DOS Version 4.00 - J.K.
+;AN00x - PTM number for DOS Version 4.00 - J.K.
+;==============================================================================
+;AN001; d52 Make the fixed positioned variable "CURHD" to be local. 7/6/87 J.K.
+;AN002; d48 Change head settle at boot time. 7/7/87 J.K.
+;AN003; P1820 New message SKL file 10/20/87 J.K.
+;AN004; D304 New structrue of Boot record for OS2. 11/09/87 J.K.
+;==============================================================================
+
+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
+IBMLOADSIZE equ 3 ;J.K. Size of IBMLOAD module in sectors
+ROM_DISKRD equ 2
+include version.inc
+
+;
+; 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
+;
+;J.K. Extened_BPB
+
+if ibmcopyright
+ DB "IBM "
+else
+ DB "MSDOS"
+endif
+ DB "4.0" ;AN005;
+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
+cTotSec DW 4*17*305-1 ; NUMBER OF SECTORS - NUMBER OF HIDDEN SECTORS
+ ; (0 when 32 bit sector number)
+MEDIA DB 0F8H ; MEDIA BYTE
+cSecFat DW 8 ; NUMBER OF FAT SECTORS
+SECLIM DW 17 ; SECTORS PER TRACK
+HDLIM DW 4 ; NUMBER OF SURFACES
+Ext_cSecHid label dword
+cSecHid_L DW 1 ;AN000; NUMBER OF HIDDEN SECTORS
+cSecHid_H dw 0 ;AN000; high order word of Hiden Sectors
+Ext_cTotSec label dword
+ctotsec_L dw 0 ;AN000; 32 bit version of NUMBER OF SECTORS
+ctotsec_H dw 0 ;AN000; (when 16 bit version is zero)
+;
+Phydrv db 80h ;AN004;
+Curhd db 0h ;AN004; Current Head
+Ext_Boot_Sig db 41 ;AN000;
+Boot_Serial dd 0 ;AN000;
+Boot_Vol_Label db 'NO NAME ' ;AN000;
+Boot_System_id db 'FAT12 ' ;AN000;
+
+;J.K. Danger!!! If not 32 bit sector number calculation, FORMAT should
+;set the value of cSecHid_h and Ext_cTotSec to 0 !!!
+;
+
+;
+Public UDATA
+UDATA LABEL byte
+Sec9 equ byte ptr UDATA+0 ;11 byte diskette parm. table
+BIOS$_L EQU WORD PTR UDATA+11
+BIOS$_H equ word ptr UDATA+13 ;AN000;
+CURTRK EQU WORD PTR UDATA+15
+CURSEC EQU BYTE PTR UDATA+17
+DIR$_L EQU WORD PTR UDATA+18
+Dir$_H equ word ptr UDATA+20 ;AN000;
+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.
+;
+;J.K. We copy the disk parameter table into a local area (overlayed into the
+;code), and set the head settle time to 1, and End of Track to SECLIM given
+;by FORMAT.
+
+ 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
+if $ le BIOS$_L
+ %OUT Don't destroy unexcuted code yet!!!
+endif
+ repz movsb ;AN000;
+ push es ;AN000;
+ pop ds ;AN000; DS = ES = code = 0.
+ assume ds:code ;AN000;
+; mov byte ptr [di-2], 1 ;AN000; Head settle time
+;J.K. Change the head settle to 15 ms will slow the boot time quite a bit!!!
+ mov byte ptr [di-2], 0fh ;AN002; Head settle time
+ mov cx, SECLIM ;AN004;
+ mov byte ptr [di-7], cl ;AN000; End of Track
+;
+; Place in new disk parameter table vector.
+;
+ 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
+ jc CKErr ;AN000;
+;
+; 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.
+
+ xor ax,ax ;AN000;
+ cmp cTotSec,ax ;AN000; 32 bit calculation?
+ je Dir_Cont ;AN000;
+ mov cx,cTotSec ;AN000;
+ mov cTotSec_L,cx ;AN000; cTotSec_L,cTotSec_H will be used for calculation
+Dir_Cont: ;AN000;
+ MOV AL,cFat ;Determine sector dir starts on
+ MUL cSecFat ;DX;AX
+ ADD AX,cSecHid_L
+ adc DX,cSecHid_H ;AN000;
+ ADD AX,cSecRes
+ ADC DX,0
+ MOV [DIR$_L],AX ; DX;AX = cFat*cSecFat + cSecRes + cSecHid
+ mov [DIR$_H],DX ;AN000;
+ MOV [BIOS$_L],AX
+ mov [BIOS$_H],DX ;AN000;
+;
+; 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$_L],AX ; Start sector # of Data area
+ adc [BIOS$_H],0 ;AN000;
+
+;
+; 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 dx,[DIR$_H] ;AN000;
+ MOV AX,[DIR$_L] ; logical sector of directory
+ CALL DODIV ; convert to sector, track, head
+ jc CKErr ;AN000; Overflow? BPB must be wrong!!
+; MOV AX,0201H ; disk read 1 sector
+ mov al, 1 ;AN000; disk read 1 sector
+ CALL DOCALL ; do the disk read
+ JB CKERR ; if errors try to recover
+;
+; Now we scan for the presence of IBMBIO COM and IBMDOS COM. Check the
+; first directory entry.
+;
+ MOV DI,BX
+ MOV CX,11
+ MOV SI,OFFSET BIO ; point to "ibmbio 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 "ibmdos 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
+
+Load_Failure:
+ pop ax ;adjust the stack
+ pop ax
+ pop ax
+ jmp short Ckerr ;display message and reboot.
+
+;J.K. We don't have the following error message any more!!!
+;J.K. Sysmsg is fine. This will save space by eliminating DMSSG message.
+;RERROR: MOV SI,OFFSET DMSSG ; DISK ERROR MESSAGE
+; JMP ErrOut
+
+;
+; We now begin to load the BIOS in. Compute the number of sectors needed.
+; J.K. All we have to do is just read in sectors contiguously IBMLOADSIZE
+; J.K. times. We here assume that IBMLOAD module is contiguous. Currently
+; J.K. we estimate that IBMLOAD module will not be more than 3 sectors.
+
+DoLoad:
+ mov BX,BioOff ;offset of ibmbio(IBMLOAD) to be loaded.
+ mov CX,IBMLOADSIZE ;# of sectors to read.
+ mov AX, [BIOS$_L] ;Sector number to read.
+ mov DX, [BIOS$_H] ;AN000;
+Do_While: ;AN000;
+ push AX ;AN000;
+ push DX ;AN000;
+ push CX ;AN000;
+ call DODIV ;AN000; DX;AX = sector number.
+ jc Load_Failure ;AN000; Adjust stack. Show error message
+ mov al, 1 ;AN000; Read 1 sector at a time.
+ ;This is to handle a case of media
+ ;when the first sector of IBMLOAD is the
+ ;the last sector in a track.
+ call DOCALL ;AN000; Read the sector.
+ pop CX ;AN000;
+ pop DX ;AN000;
+ pop AX ;AN000;
+ jc CkErr ;AN000; Read error?
+ add AX,1 ;AN000; Next sector number.
+ adc DX,0 ;AN000;
+ add BX,ByteSec ;AN000; adjust buffer address.
+ loop Do_While ;AN000;
+
+
+; 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
+;J.K.I1. BX was the First data sector on disk (0-based)
+;J.K.I1. IBMBIO init routine should check if the boot record is the
+;J.K.I1. extended one by looking at the extended_boot_signature.
+;J.K.I1. If it is, then should us AX;BX for the starting data sector number.
+
+DISKOK:
+ MOV CH,Media
+ MOV DL,PhyDrv
+ MOV bx,[BIOS$_L] ;AN000; J.K.I1.Get bios sector in bx
+ mov ax,[BIOS$_H] ;AN000; J.K.I1.
+ 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
+; J.K. DX;AX has the sector number. Because of not enough space, we are
+; going to use Simple 32 bit division here.
+; Carry set if DX;AX is too big to handle.
+;
+
+DODIV:
+ cmp dx,Seclim ;AN000; To prevent overflow!!!
+ jae DivOverFlow ;AN000; Compare high word with the divisor.
+ DIV SECLIM ;AX = Total tracks, DX = sector number
+ INC DL ;Since we assume SecLim < 255 (a byte), DH =0.
+ ;Cursec is 1-based.
+ MOV CURSEC, DL ;save it
+ XOR DX,DX
+ DIV HDLIM
+ MOV CURHD,DL ;Also, Hdlim < 255.
+ MOV CURTRK,AX
+ clc ;AN000;
+ ret ;AN000;
+DivOverFlow: ;AN000;
+ stc ;AN000;
+EndWR:
+ ret
+
+;
+;J.K.We don't have space for the following full 32 bit division.
+; convert a logical sector into Track/sector/head. AX has the logical
+; sector number
+; J.K. DX;AX has the sector number.
+;DODIV:
+; push ax
+; mov ax,dx
+; xor dx,dx
+; div SecLim
+; mov Temp_H,ax
+; pop ax
+; div SecLim ;J.K.Temp_H;AX = total tracks, DX=sector
+; INC DL ;Since we assume SecLim < 255 (a byte), DH =0.
+; ;Cursec is 1-based.
+; MOV CURSEC, DL ;save it
+; push ax
+; mov ax,Temp_H
+; XOR DX,DX
+; DIV HDLIM
+; mov Temp_H,ax
+; pop ax
+; div HdLim ;J.K.Temp_H;AX=total cyliners,DX=head
+; MOV CURHD,DL ;Also, Hdlim < 255.
+; cmp Temp_H,0
+; ja TooBigToHandle
+; cmp ax, 1024
+; ja TooBigToHandle
+; MOV CURTRK,AX
+;ENDWR: RET
+;TooBigToHandle:
+; stc
+; ret
+
+;
+; Issue one read request. ES:BX have the transfer address, AL is the number
+; of sectors.
+;
+DOCALL: MOV AH,ROM_DISKRD ;AC000;=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 ibmbtmes.inc
+ include boot.cl1 ;AN003;
+
+
+ IF IBMCOPYRIGHT
+BIO DB "IBMBIO COM"
+DOS DB "IBMDOS COM"
+ ELSE
+BIO DB "IO SYS"
+DOS DB "MSDOS SYS"
+ ENDIF
+
+Free EQU (cbSec - 4) - ($-$start) ;AC000;
+;Free EQU (cbSec - 5) - ($-$start)
+if Free LT 0
+ %out FATAL PROBLEM:boot sector is too large
+endif
+
+ org origin + (cbSec - 2) ;AN004;
+; org origin + (cbSec - 5)
+
+;Warning!! Do not change the position of following unless
+;Warning!! you change BOOTFORM.INC (in COMMON subdirectory) file.
+;Format should set this EOT value for IBMBOOT.
+;FEOT db 12h ;AN000; set by FORMAT. AN004;Use SecLim in BPB instead.
+; FORMAT and SYS count on CURHD,PHYDRV being right here
+;J.K. CURHD has been deleted since it is not being used by anybody.
+;CURHD DB ? ;AN001;Unitialized (J.K. Maybe don't need this).
+;PHYDRV db 0 ;AN000;moved into the header part.
+; Boot sector signature
+ db 55h,0aah
+
+CODE ENDS
+ END
+
\ No newline at end of file
diff --git a/v4.0/src/CMD/APPEND/APPEND.ASM b/v4.0/src/CMD/APPEND/APPEND.ASM
new file mode 100644
index 0000000..5ca2b70
--- /dev/null
+++ b/v4.0/src/CMD/APPEND/APPEND.ASM
@@ -0,0 +1,3462 @@
+page 60,120
+;
+.sall
+title APPEND
+include sysmsg.inc
+msg_utilname
+;-----------------------------------------------------------------------------
+;
+; Title: APPEND
+;
+; Author: G. G. A. Network version
+; B. A. F.` DOS changes
+;
+; Syntax: From the DOS command line:
+;
+; APPEND [d:]path[[;[d:]path]...]
+; - Used to specify the directories to be
+; searched after the working directory.
+;
+; APPEND ;
+; - Used to release all appended directories.
+;
+; APPEND
+; - Used to show appended directories.
+;
+; First time only:
+;
+; APPEND [[d:]path | | /X | /E | /X /E]
+; - [d:]path Normal support and Set path
+; - Normal support
+; - /X Extended support, SEARCH, FIND and EXEC
+; - /E Use DOS Environment for path(s)
+;
+; Revision History:
+; @@01 07/11/86 Fix hang in TopView start PTM P00000??
+; @@02 07/28/86 Fix APPEND size problem PTM P0000045
+; @@03 07/29/86 Fix APPEND status with /E problem PTM P00000??
+; @@04 07/30/86 Fix second APPEND hang PTM P0000053
+; @@05 08/13/86 Fix parameter error PTM P0000125
+; @@06 08/20/86 Fix APPEND xxx fails in TopView PTM P0000217
+; @@07 08/21/86 Resurrect APPEND version message PTM P0000252
+; @@08 08/21/86 APPEND=path first time hangs PTM P0000254
+; @@09 08/22/86 APPEND gets wrong path under nested COMMAND PTM P0000276
+; @@10 08/28/86 Change message for @@05 PTM P0000291
+; @@11 09/10/86 Support message profile and make
+; msg length variable. R.G. PTM P0000479
+; @@12 09/25/86 Allow second external append call. (RG) PTM P0000515
+; @@13 09/30/86 APPEND gets wrong path under nested COMMAND PTM P0000600
+; Again. Fix in COMMAND now, so remove @@09 changes
+; @@14 10/01/86 Lower case drive in path files PTM P0000600
+; @@15 10/06/86 Include "," and "=" in skip leading of
+; argument area parsing. PTM P0000677
+; @@16 10/06/86 Fix not using full APPEND path PTM P0000794
+; @@17 12/03/86 When searching for "APPEND=" string in
+; environment, make sure delimiter precedes.(RG) PTM P0000893
+;
+;-------------------------------------------------------------------
+;
+; AN000 3.30 changes, GGA 6/87 new code. P000
+; AN001 Support DRIVE and PATH modes D043
+; AN002 Add truename function P1276
+; AN003 Add extended handle open function D250
+; AN005
+; AN006 Add DBCS support
+; AN007 Release Environmental Vector space P2666
+; AN008 Allow equal symbol with append - APPEND=A:/1; P2901
+; AN009 Release Environmental Vector on only the P3333
+; first invocation of APPEND
+; AN010 display invalid parm from command line P3908
+;
+;
+;-----------------------------------------------------------------------------
+;Date Rev Comments
+;-----------------------------------------------------------------------------
+;06-02-86 0.0 Begin conversion to PC/DOS version
+;06-20-86 0.0 End conversion to PC/DOS version
+;
+page
+
+cseg segment public para 'CODE'
+ assume cs:cseg
+ assume ds:nothing,es:nothing
+
+;-----------------------------------------------------------------------------
+; Equates
+;-----------------------------------------------------------------------------
+
+.xlist
+;include fsi.lib
+NETSYSUTIL EQU 0C2H ; SYSTEM UTILITIES
+NETENQ EQU 07H ; ENQ RESOURCE
+NETDEQ EQU 08H ; DEQ RESOURCE
+;include task.lib
+TCBR_APPEND EQU 001H ; APPEND ACTIVE
+;include DOS.lib
+DOSSERVER EQU 5DH ; SERVER OPERATION
+DOSSETERROR EQU 0AH ; SET EXTENDED ERROR
+;include server.lib
+DPL STRUC
+DPL_AX DW 0 ;AX REG
+DPL_BX DW 0 ;BX REG
+DPL_CX DW 0 ;CX REG
+DPL_DX DW 0 ;DX REG
+DPL_SI DW 0 ;SI REG
+DPL_DI DW 0 ;DI REG
+DPL_DS DW 0 ;DS REG
+DPL_ES DW 0 ;ES REG
+DPL_XID DW 0 ;RESERVED
+DPL_UID DW 0 ;SERVER USER ID
+DPL_PID DW 0 ;REDIRECTOR PROCESS ID
+DPL ENDS
+include sysmac.lib
+include versiona.inc
+include appendp.inc ; parseing stuff for append ;AN004;
+.list
+; extrn end_address:near ; end of stay resident stuff
+
+; extrn bad_append_msg:byte ; messages
+; extrn path_error_msg:byte
+; extrn parm_error_msg:byte
+; extrn path_parm_error_msg:byte
+; extrn no_append_msg:byte ; @@05
+; extrn append_assign_msg:byte
+; extrn append_TV_msg:byte ; @@01
+; extrn bad_DOS_msg:byte
+; extrn second_APPEND_msg:byte ; @@04
+
+; extrn len_bad_append_msg:word ;@@11
+; extrn len_path_error_msg:word ;@@11
+; extrn len_parm_error_msg:word ;@@11
+; extrn len_path_parm_error_msg:word ;@@11
+; extrn len_no_append_msg:word ;@@11
+; extrn len_append_assign_msg:word ;@@11
+; extrn len_append_TV_msg:word ;@@11
+; extrn len_bad_DOS_msg:word ;@@11
+; extrn len_second_APPEND_msg:word ;@@11
+
+; Environmental Vector
+
+PSP_Env equ 2ch ;Environmental vector segment in PSP ;an007; dms;
+
+; Interrupts
+
+DOS_function equ 21h ; DOS function call interrupt
+int_function equ 2fh ; DOS internal function interrupt, used
+ ; to verify APPEND presence
+termpgm equ 20h ; @@05
+resident equ 27h
+
+; Function calls
+
+get_vector equ 3521h ; DOS function call to get INT 21 vector
+set_vector equ 2521h ; DOS function call to set INT 21 vector
+get_intfcn equ 352fh ; DOS function call to get INT 2f vector
+set_intfcn equ 252fh ; DOS function call to set INT 2f vector
+get_version equ 30h ; DOS function call to get DOS version number
+get_DTA equ 2fh ; DOS function get DTA
+set_DTA equ 1ah ; DOS function set DTA
+get_crit_err equ 3524h ; DOS function call to get INT 24 vector
+set_crit_err equ 2524h ; DOS function call to set INT 24 vector
+get_PSP equ 62h ; DOS function call to get PSP address
+Free_Alloc_Mem equ 49h ; DOS function call to free alloc. mem. ;an007; dms;
+
+print_string equ 09h ; DOS function call to get print a string
+ctrl_break equ 33h ; DOS function call to get/set ctrl-break
+
+awrite equ 40h ; write function
+get_dir equ 47h ; get current dir
+change_dir equ 3bh ; change dir
+get_disk equ 19h ; get current disk
+change_disk equ 0eh ; change disk
+term_stay equ 31h ; terminate a process and stay resident
+term_proc equ 4ch ; terminate a process
+
+redir_flag equ 0000000000001000B ; redir flag for net installation check
+
+; DOS INT 2f function for APPEND presence
+
+append_2f equ 0b7h ; int 2f function code for append
+applic_2f equ 0aeh ; int 2f function code for applications
+COMMAND_2f equ -1 ; int 2f subfunction code for COMMAND call
+append_inst equ 0ffh ; flag means append is there
+
+; INT 2f sub-function codes ;AN000;
+
+are_you_there equ 0 ; function code for presence check
+old_dir_ptr equ 1 ; means APPEND 1.0 is trying to run
+get_app_version equ 2 ; fun code for get ver request
+tv_vector equ 3 ; fun code for set TV vector
+dir_ptr equ 4 ; function code to return dirlist ptr
+get_state equ 6 ; function code to return append ;AN001;
+ ; state ;AN001;
+set_state equ 7 ; function code to set append ;AN001;
+ ; state ;AN001;
+
+DOS_version equ 10h ; function call to get DOS version
+true_name equ 11h ; one-shot truename fcn for ASCIIZ ops ;AN002;
+
+; DOS INT 21 function calls that APPEND traps
+
+FCB_opn equ 0fh
+file_sz equ 23h
+handle_opn equ 3dh
+dat_tim equ 57h
+FCB_sch1 equ 11h
+handle_fnd1 equ 4eh
+exec_proc equ 4bh
+ext_handle_opn equ 6ch ;AN003;
+
+break macro ; this is a dummy break macro so PDB.INC
+ endm ; won't blow up in the build
+
+; define some things for PDB (PSP) ;AN002;
+ ;AN002;
+include pdb.inc ;AN002;
+ ;AN002;
+true_name_flag equ 01h ; flag for true name function ;AN002;
+eo_create equ 00f0h ; mask to check extended opens for create ;AN003;
+
+; Error codes that don't mean stop looking
+
+FCB_failed equ 0ffh ; FCB open failed
+FCB_file_not_found equ 2 ; file not found on FCB open
+handle_file_not_found equ 2 ; file not found on handle open
+handle_path_not_found equ 3 ; path not found on handle open
+FCB_no_more_files equ 18 ; no more matching files
+handle_no_more_files equ 18 ; no more matching files
+
+; Equates for TOPVIEW barrier
+TV_TRUE equ -1 ; this was changed from TRUE ;AN000;
+ ; because 3.30 parser uses TRUE ;AN000;
+false equ 0 ;
+
+; Message equates
+
+tab_char equ 9
+cr equ 13
+lf equ 10
+beep equ 7
+STDOUT equ 0001h ; standard output file
+STDERR equ 0002h ; standard error file
+null equ 0
+
+page
+
+;-----------------------------------------------------------------------------
+; Resident data area
+;-----------------------------------------------------------------------------
+
+version_loc: ; version number
+ db major_version,minor_version
+; dw message_list ; pointer to message table
+
+ even
+vector_offset dw 0 ; save pointer to old int 21 here
+vector_segment dw 0
+crit_vector_offset dw 0 ; save pointer to old int 24 here
+crit_vector_segment dw 0
+intfcn_offset dw 0 ; save pointer to old int 2f here
+intfcn_segment dw 0
+dirlst_offset dw 0 ; save pointer to dir list here
+dirlst_segment dw 0
+tv_vec_off dw 0 ; save TV vector here
+tv_vec_seg dw 0
+
+pars_off dd cseg: SysParse ; save pointer to parser here
+;pars_off dw offset SysParse ; save pointer to parser here
+;pars_seg dw 0
+
+app_dirs_seg dw 0 ; save ES here during FCB
+
+FCB_ptr dd 0 ; save pointer to FCB here
+handle_ptr dd 0 ; save pointer to ASCIIZ string here
+
+stack_offset dw 0
+stack_segment dw 0 ; Calling process stack
+
+incoming_AX dw 0 ; AX saved at entry to interrupt handler
+incoming_CX dw 0 ; CX saved at entry to interrupt handler
+; must be together
+incoming_BX dw 0 ; BX saved at entry to interrupt handler
+incoming_ES dw 0 ; ES saved at entry to interrupt handler
+; must be together
+ax_after_21 dw 0 ; AX saved after call to real INT 21
+; temp_DS_save dw 0 ; DS saved during stack ops
+temp_CS_save dw 0 ; CS saved during stack ops (set_return_flags)
+temp_IP_save dw 0 ; IP saved during stack ops (set_return_flags)
+FCB_drive_id db 0 ; save the drive id for FCB opens here
+
+;------------------------
+; DBCS stuff here ;AN006;
+ ;AN006;
+DBCSEV_OFF DW 0 ; OFFSET OF DBCS EV ;AN006;
+DBCSEV_SEG DW 0 ; SEGMENT OF DBCS EV ;AN006;
+ ;AN006;
+;DEFAULT DBCS ENVIRONMENTAL VECTOR ;AN006;
+EVEV DB 00H,00H ;AN006;
+ DB 00H,00H ;AN006;
+ DB 00H,00H ;AN006;
+ ;AN006;
+dbcs_fb dw 0 ; offset of DBCS first byte chars found
+;------------------------
+
+initial_pass dw 0 ; flag used to indicate inital APPEND ;AN007;
+
+incoming_DX dw 0 ; used for saves for extended open ;AN003;
+incoming_SI dw 0 ; used for saves for extended open ;AN003;
+incoming_DI dw 0 ; used for saves for extended open ;AN003;
+incoming_DS dw 0 ; used for saves for extended open ;AN003;
+true_name_count dw 0 ; used to save number of chars in true_name dir ;AN003;
+
+int_save_ip dw 0 ; save registers here during critical
+int_save_cs dw 0 ; error handler stack ops
+
+work_disk db "?:\" ; user's working disk
+work_dir db 64 dup(" ") ; user's working dir
+app_disk db "?:\" ; user's working disk
+app_dir db 64 dup(" ") ; user's append disk's working dir
+ctrl_break_state db 0 ; save the old ctrl-break state here
+
+end_search db 0 ; end search flag
+try_dir db 128 dup (0) ; try this dir
+fname db 15 dup (0) ; 8.3 filename stripped from original
+ ; ASCIIZ string
+app_dirs_ptr dw 0 ; pointer to appended dir to try
+
+set_name db "SET " ; SET command
+; must be together
+setappend_name db "SET " ; SET command
+append_id db "APPEND=" ; display from here for user
+; must be together
+app_dirs db ";"
+ db 128 dup (0) ; area for storing appended dirs
+ db 0 ; just to insure that the last dir is null terminated
+semicolon db ";",0 ; null list
+
+; Flags / barriers added for TopView
+
+tv_flag db 0 ; flag to indicate re-entr from TopView
+
+parse_flag db 0 ; flag used by APPEND parsing
+
+FCB_ext_err db 0 ; flag used to indicate that FCB
+ ; open failed and ext err was done
+crit_err_flag db 0 ; flag used to indicate that a critical
+ ; error happened
+ext_err_flag db 0 ; flag used to indicate that ext err
+ ; must be set 0 = don't set, 1 = do set
+in_middle db 0 ; flag used to tell if we made it to
+ ; middle of string before finding a space
+equal_found db 0 ; multiple = check
+;crit_sect_flag db 0 ; critical section flag
+
+stack_area dw 99 dup(0) ; stack area for append
+append_stack dw 0
+
+net_config dw 0 ; flag word for what (if any) network
+ ; config we are running under
+ ; as long as this word is zero, a clear determination
+ ; has not been made about the configuration
+
+ even
+ext_err_dpl DPL <> ; reserve a DPL for get/set extended error code
+
+
+save_ext_err DPL <> ; reserve a DPL for first extended
+ ; error code
+
+;------------------------------------------------------------------- ;AN001;
+; ;AN001;
+; mode_flags This status word is used to control the various ;AN001;
+; APPEND functions and modes. ;AN001;
+; ;AN001;
+;------------------------------------------------------------------- ;AN001;
+mode_flags dw Path_mode + Drive_mode + Enabled ;AN001;
+ ; mode control flags ;AN001;
+ ; initially - path, drive and ;AN001;
+ ; enabled ;AN001;
+
+; equates for mode_flags follow: ;AN001;
+
+X_mode equ 8000h ; in /X mode
+E_mode equ 4000h ; in /E mode
+Path_mode equ 2000h ; PATH in string OK ;AN001;
+Drive_mode equ 1000h ; DRIVE in string OK ;AN001;
+Enabled equ 0001h ; APPEND enabled ;AN001;
+
+;-------------------------------------------------------------------
+
+cmd_name@ dd ? ; internal name string
+
+expected_error dw ? ; error to do append scan
+expected_ext_error dw ? ; error to do append scan
+
+cmd_env dw ? ; pointer to COMMANDs environment
+cmd_buf dw ? ; CMDBUF offset (in SS)
+
+incoming_DTA dd ? ; user's DTA (on EXEC)
+exec_DTA db 21+1+2+2+2+2+13 dup(0) ; find DTA for exec emulation
+
+old_syntax db 0 ; using network syntax
+
+res_append db 0 ; resident append call ; @@05
+
+abort_sp dw ? ; sp to restore on errors ; @@05
+
+crlf label byte
+ db CR,LF
+crlf_len equ $ - crlf
+
+;******************************************************************* ;an010;bgb
+; parser message display area ;an010;bgb
+;******************************************************************* ;an010;bgb
+inv_parm db 0bh ;length ;an010;bgb
+ db 0 ;reserved ;an010;bgb
+si_off dw 0 ;put offset of command line here ;an010;bgb
+si_seg dw 0 ;put segment of command line here ;an010;bgb
+ db 0 ;use percent zero ;an010;bgb
+ db Left_Align+Char_Field_ASCIIZ ;type of data ;an010;bgb
+ db 128 ;max width ;an010;bgb
+ db 1 ;min width ;an010;bgb
+ db ' ' ;pad char ;an010;bgb
+
+;-------------------------------------------------------------------
+;
+; resident message area
+;
+;-------------------------------------------------------------------
+
+MSG_SERVICES
+MSG_SERVICES ;an010;bgb
+MSG_SERVICES
+
+.xlist
+;-----------------------------------------------------------------------------
+; macros
+;-----------------------------------------------------------------------------
+
+;-----------------------------
+; save and restore register macros
+save_regs macro
+ push bx
+ push cx
+ push dx
+
+ push di
+ push si
+ push ds
+ push es
+ endm
+
+restore_regs macro
+ pop es
+ pop ds
+ pop si
+ pop di
+
+ pop dx
+ pop cx
+ pop bx
+ endm
+
+;-----------------------------
+; this macro is used instead of the normal POPF instruction to help
+; prevent a 286 bug from occurring
+popff macro
+ local myret
+ jmp $+3
+myret label near
+ iret
+ push cs
+ call myret
+ endm
+
+;----------------------------- ; @@12
+; check character ; @@12
+; ; @@12
+chkchar macro char ; @@12
+ lodsb ; @@12
+ and al,0dfh ; @@12
+ cmp al,char ; @@12
+ jne ccn_ret ; @@12
+ endm ; @@12
+.list
+
+page
+;-----------------------------------------------------------------------------
+; resident routine - control transferred here on INT 21
+; check to see if this call has a function code we are interested in
+;-----------------------------------------------------------------------------
+
+
+tv_entry:
+ pushf ; @@01
+ jmp check_fcb_open ; @@01
+
+interrupt_hook:
+resident_routine:
+ pushf ; save the user's flags (old stack)
+
+ cmp tv_flag,TV_TRUE ; see if in TV ;AN000;
+ je use_old ; yes, old_vect
+
+check_fcb_open: ; @@01
+
+;------------------------------------------------------------------- ;AN001;
+; first, check to see if APPEND disabled, if so, skip everything ;AN001;
+; and go to real INT 21 handler ;AN001;
+;------------------------------------------------------------------- ;AN001;
+ test mode_flags,Enabled ; APPEND disabled? ;AN001;
+ jz real_jump ; yes, skip all other checks ;AN001;
+
+ cmp ah,FCB_opn ; FCB open?
+ jump E,FCB_open ; yes, do the APPEND
+
+ cmp ah,handle_opn ; handle open?
+ jump E,handle_open ; yes, do the APPEND
+
+ cmp ah,ext_handle_opn ; extended handle open? ;AN003;
+ jump E,ext_handle_open ; yes, do the APPEND ;AN003;
+ ;AN003;
+ cmp ah,file_sz ; file size?
+ jump E,FCB_open ; yes, do the APPEND
+
+
+ test mode_flags,X_mode ; /X mode not selected
+ jz real_jump
+
+ cmp ah,FCB_sch1 ; search?
+ jump E,FCB_search1 ; yes, do the APPEND
+
+ cmp ah,handle_fnd1 ; find?
+ jump E,handle_find1 ; yes, do the APPEND
+
+ cmp tv_flag,TV_TRUE ; cant do in TopView ;AN000;
+ je skip_exec
+ cmp ax,exec_proc*256+0 ; EXEC?
+ jump E,exec_pgm ; yes, do the APPEND
+skip_exec:
+ cmp ax,exec_proc*256+3 ; EXEC?
+ jump E,exec_pgm ; yes, do the APPEND
+
+ page
+;-----------------------------------------------------------------------------
+; By here, we know that the call was not one we are interested in,
+; pass through to old INT 21.
+; Since this is done with a jmp, control will pass back to original caller
+; after DOS is finished.
+;-----------------------------------------------------------------------------
+
+real_jump:
+ cmp tv_flag,TV_TRUE ; see if called by TV ;AN000;
+ jne use_old ; yes, use old vect
+
+ popff ; restore user's flags
+ jmp dword ptr tv_vec_off ; pass through to TV
+
+use_old:
+ popff ; restore user's flags (old stack)
+ jmp dword ptr Vector_Offset ; jump to old INT 21
+
+page
+;-----------------------------------------------------------------------------
+; FCB_search1 - this routine handles FCB search first calls
+;-----------------------------------------------------------------------------
+
+FCB_search1:
+ mov expected_ext_error,fcb_no_more_files
+ jmp short FCB_openx1
+
+;-----------------------------------------------------------------------------
+; FCB_open - this routine handles FCB open calls
+;-----------------------------------------------------------------------------
+
+FCB_open:
+ mov expected_ext_error,fcb_file_not_found
+FCB_openx1:
+ call check_config ; check the config flags
+ call crit_sect_set ; set critical section flag
+
+ call tv_barrier
+
+ mov incoming_AX,ax ; save user's AX
+ mov word ptr FCB_ptr+0,dx ; save FCB pointer
+ mov word ptr FCB_ptr+2,ds
+
+ popff ; restore user's flags
+ call int_21 ; try the open
+
+ cli
+ mov AX_after_21,ax ; save AX as it came back from INT
+ pushf ; save flags from operation
+ cmp al,FCB_failed ; open failed ?
+ je check_error ; yes, lets check extended error
+ jmp set_return_flags ; no, fix the stack, then ret to caller
+
+check_error:
+ call get_ext_err_code ; get the extended error code
+ mov FCB_ext_err,1 ; set FCB ext error
+ call save_first_ext_err ; save first extended error code
+ mov ax,ext_err_dpl.DPL_AX ; get error in ax
+ cmp ax,expected_ext_error ; file not found?
+ je FCB_openx2 ; yes, lets look around for file
+ lea dx,save_ext_err ;
+ call set_ext_err_code ; set the extended error code
+ jmp set_return_flags ; no, fix the stack, then return
+
+FCB_openx2:
+
+; set up APPEND's stack
+
+ popff ; get rid of the flags from the
+ ; real operation
+; mov temp_DS_save,ds ; Save DS reg
+ mov stack_segment,ss ; Save it
+ mov stack_offset,sp ; Save it
+ mov ax,cs ; Get current segment
+ mov ss,ax ; and point stack seg here
+ lea sp,append_stack ; set up new stack
+
+ save_regs ; save registers
+
+ push cs ; establish addressability
+ pop ds
+
+ call ctrl_break_set ; set ctrl-break handler
+ call crit_err_set ; set crit err handler
+
+ mov ext_err_flag,1 ; flag for setting critical error
+
+; fix FCB drive spec
+
+ les bx,dword ptr FCB_ptr ; ES:BX points to FCB
+ mov ah,ES:byte ptr [bx] ; get FCB drive spec
+ cmp ah,-1 ; extended FCB?
+ jne not_ext_FCB1
+ add bx,1+5+1 ; point to real drive letter
+ mov ah,ES:byte ptr [bx] ; get FCB drive spec
+
+not_ext_FCB1:
+ mov FCB_drive_id,ah ; save it for later
+ mov ES:byte ptr [bx],0 ; zero the drive field out to
+ ; use default drive
+
+ mov ah,get_disk ; get disk
+ call int_21 ; call DOS INT 21 handler
+
+ add al,"A" ; make it a character
+ mov work_disk,al ; save it
+
+ mov ah,get_dir ; get directory
+ xor dx,dx ; default drive
+ lea si,work_dir ; save area
+ call int_21 ; call DOS INT 21 handler
+
+ call address_path ; get address of path
+ cmp es: byte ptr [di],";" ; is the append list null?
+ jump E,null_list ; exit append
+ mov app_dirs_seg,es ; save app dirs segment
+ mov si,di ; source
+
+try_another1:
+ lea di,try_dir ; destination
+ call get_app_dir ; copy dir to try into try_dir
+ mov app_dirs_ptr,si ; save updated pointer
+
+
+;-----------------------------
+try_app_dir1:
+ mov app_disk,0 ; zero for current dir
+ cmp try_dir+1,":" ; see if we have a drive
+ jne no_drive ; char should be a colon
+
+; yes, there was a drive specified, must do the change disk function call
+
+ mov ah,change_disk ; change disk
+ mov dl,try_dir ; get the char representation of the drive
+ mov app_disk,dl ; save it away for later use
+ call cap_dl
+ sub dl,"A" ; convert from char to drive spec
+ call int_21 ; call DOS INT 21 handler
+; jc check_end_dir_list ; there was an error, see if there is
+ ; another to try
+
+ cmp crit_err_flag,0 ; did we experience a critical error
+ jne set_err_code ; yes, fake a file_not_found
+
+no_drive:
+ mov ah,get_dir ; get directory
+ xor dx,dx ; default drive
+ lea si,app_dir ; save area
+ call int_21 ; call DOS INT 21 handler
+
+; check to see if there was a critical error
+
+ cmp crit_err_flag,0 ; did we experience a critical error
+ je cd_worked ; no, the cd worked
+ jmp short set_err_code
+
+save_regs_and_set:
+ pushf ; save everything again
+ save_regs
+ push cs ; re-establish addressability
+ pop ds ; ds = cs
+
+set_err_code:
+ xor ah,ah ; make ax look like open failed
+ mov al,FCB_failed
+ mov ax_after_21,ax ; save it away so we can restore it below
+
+ jmp no_more_to_try
+
+cd_worked:
+ lea dx,try_dir ; point dx to dir to try
+ mov ah,change_dir ; change dir to appended directory
+ call int_21 ; call DOS INT 21 handler
+
+; try the open in this dir
+
+ restore_regs ; make regs look like when user
+ mov ax,incoming_AX ; called us
+
+ call int_21 ; call DOS INT 21 handler
+ mov ax_after_21,ax ; save AX
+ cmp crit_err_flag,0 ; did we get critical error?
+ jne save_regs_and_set ; yes, fake a file_not_found
+ cmp al,FCB_failed ; did open work?
+ jne open_ok
+ call get_ext_err_code ; get the extended error code
+
+open_ok:
+ pushf ; save everything again
+ save_regs
+
+ push cs ; re-establish addressability
+ pop ds ; ds = cs
+
+; restore user's working disk and restore the dir on the appended drive
+
+ mov ah,change_disk ; change disk back to our original
+ mov dl,work_disk
+ call cap_dl
+ sub dl,"A" ; convert from char to drive spec
+ call int_21 ; call DOS INT 21 handler
+
+ mov ah,change_dir ; change dir
+ lea dx,app_disk ; save area (this time include drive)
+ call int_21 ; call DOS INT 21 handler
+
+; this is for ..\dirname ptr
+
+ mov ah,change_dir ; change dir
+ lea dx,work_disk ; save area (this time include drive)
+ call int_21 ; call DOS INT 21 handler
+
+ mov ax,ax_after_21 ; restore AX
+ cmp al,FCB_failed ; did open work?
+ jne FCB_open_worked
+ mov ax,ext_err_dpl.DPL_AX
+ cmp ax,expected_ext_error
+ jne no_more_to_try ; not file not found
+
+check_end_dir_list:
+ mov es,app_dirs_seg ; restore es
+ mov si,app_dirs_ptr
+ cmp si,null ; should we try again?
+ je no_more_to_try ; no
+ jmp try_another1 ; yes
+
+FCB_open_worked:
+ mov byte ptr ext_err_flag,0 ; the open worked, no need to set ext err code
+ jmp short set_disk
+
+no_more_to_try:
+; restore user's working disk and dir
+
+; The following code up to label "null_list" which
+; restores the user's drive and path was moved in front
+; of the code to restore the drive spec in FCB.
+;
+ mov ah,change_disk ; change disk
+ mov dl,work_disk
+ call cap_dl
+ sub dl,"A" ; convert from char to drive spec
+ call int_21 ; call DOS INT 21 handler
+
+ mov ah,change_dir ; change dir
+ lea dx,work_disk ; save area (this time include drive)
+ call int_21 ; call DOS INT 21 handler
+
+null_list:
+ mov ah,FCB_drive_id ; get FCB drive spec
+; cmp ah,0 ; did they ask for default drive?
+; je fix_drive_spec ; yes, leave it alone
+ jmp short fix_drive_spec
+
+set_disk: ; set drive number in FCB
+ mov ah,work_disk ; no, give them the found drive spec
+ sub ah,"A"-1 ; convert from char to drive spec
+
+; ah has proper drive spec to put into FCB, do it
+
+fix_drive_spec:
+ les bx,dword ptr FCB_ptr ; ES:BX points to FCB
+ cmp ES:byte ptr[bx],-1 ; extended FCB
+ jne not_ext_FCB2 ; put in the proper drive spec
+ add bx,1+5+1 ; point to real drive letter
+
+not_ext_FCB2:
+ mov ES:byte ptr [bx],ah
+
+
+ call ctrl_break_restore
+ call crit_err_restore
+
+; find out if there is a need to set the extended error code
+
+ cmp ext_err_flag,0 ; do we need to set the extended error code?
+ je no_ext_err ; no, finish up
+ lea dx,ext_err_dpl
+ cmp FCB_ext_err,0
+ je handle_ext_err
+ lea dx,save_ext_err
+
+handle_ext_err:
+ call set_ext_err_code ; yes, go set the ext error info
+
+; all done with append, clean things back up for the user
+
+no_ext_err:
+ restore_regs ; restore registers
+
+ jmp reset_stack ; fix stack, ret to caller
+page
+
+;-----------------------------------------------------------------------------
+; handle_find - APPEND handle find function
+;-----------------------------------------------------------------------------
+
+handle_find1:
+ mov incoming_CX,cx ; save user's CX
+ mov expected_error,handle_no_more_files
+; mov expected_ext_error,handle_no_more_files
+ jmp short handle_openx
+
+;-----------------------------------------------------------------------------
+; exec_pgm - APPEND exec program function
+;-----------------------------------------------------------------------------
+
+exec_pgm:
+ mov incoming_BX,bx ; save user's ES:BX
+ mov incoming_ES,es
+ mov expected_error,handle_file_not_found
+; mov expected_ext_error,handle_no_more_files
+ jmp short handle_openx
+
+;----------------------------------------------------------------------------- ;AN003;
+; ext_handle_open - APPEND extended handle open function ;AN003;
+;----------------------------------------------------------------------------- ;AN003;
+ext_handle_open: ;AN003;
+ test dx,eo_create ; does this call specify create? ;AN003;
+ jz no_eo_create ; no, we can continue ;AN003;
+ ;AN003;
+ jmp real_jump ; yes, do nothing but pass on to real ;AN003;
+ ; INT 21 handler ;AN003;
+ ;AN003;
+; getting here means the caller did not specify the create option ;AN003;
+ ;AN003;
+no_eo_create: ;AN003;
+ ;AN003;
+ mov incoming_BX,bx ; save user's registers ;AN003;
+ mov incoming_CX,cx ; extended open sure does use a lot ;AN003;
+ mov incoming_DX,dx ; of registers ;AN003;
+ mov incoming_SI,si ;AN003;
+ mov incoming_DI,di ;AN003;
+ mov incoming_ES,es ;AN003;
+ mov incoming_DS,ds ;AN003;
+ ;AN003;
+ mov expected_error,handle_file_not_found ;AN003;
+ jmp short handle_openx ; for now ... ;AN003;
+ ;AN003;
+;-----------------------------------------------------------------------------
+; handle_open - APPEND handle open function
+;-----------------------------------------------------------------------------
+
+handle_open:
+ mov expected_error,handle_file_not_found
+; mov expected_ext_error,handle_file_not_found
+
+handle_openx:
+ call check_config ; check the config flags
+ call crit_sect_set ; set critical section flag
+
+ call tv_barrier ; no op on exec
+
+ mov incoming_AX,ax ; save user's AX
+ mov word ptr handle_ptr+0,dx ; save path pointer
+ mov word ptr handle_ptr+2,ds
+
+ popff ; restore user's flags
+ call int_21 ; try the open
+
+ cli
+ mov AX_after_21,ax ; save AX as it came back from INT
+ pushf ; save flags from operation
+
+; find out if we had an error, and if so was it the one we were
+; looking for
+
+ jc what_happened ; yes, lets find out what happened
+ mov incoming_AX,-1 ; insure no exec done later
+ jmp set_return_flags ; no, fix the stack, then ret to caller
+ ; this means that the real call worked,
+ ; APPEND does not need to do anything
+
+what_happened:
+; cmp ax,handle_path_not_found ; normal errors
+; je handle_search ; yes, look for the file
+ cmp ax,expected_error ; was the error file not found?
+ je handle_search ; yes, look for the file
+ jmp set_return_flags ; no, fix the stack, then ret to caller
+
+
+handle_search:
+ call get_ext_err_code ; get the extended error code information
+
+; set up APPEND's stack
+ popff ; get rid of the flags from the
+ ; real operation
+; mov temp_DS_save,ds ; Save DS reg
+ mov stack_segment,ss ; Save it
+ mov stack_offset,sp ; Save it
+ mov ax,cs ; Get current segment
+ mov ss,ax ; and point stack seg here
+ lea sp,append_stack ; set up new stack
+
+ save_regs ; save registers
+ pushf ;
+ push cs ; establish addressability
+ pop ds
+
+ call crit_err_set
+
+ call ctrl_break_set
+
+; all done with the prep stuff, let's get down to business
+
+;------------------------------------------------------------------- ;AN001;
+; ;AN001;
+; before doing anything else, check DRIVE and PATH modes ;AN001;
+; ;AN001;
+;------------------------------------------------------------------- ;AN001;
+; ;AN001;
+
+ pushf ; save flags ;AN001;
+ push ax ; save AX ;AN001;
+ ;AN001;
+ cmp incoming_AX,exec_proc*256 ; is this call an exec?
+ je drive_and_path_ok
+
+
+;-------------------------------------------------------------------
+; Set up ES:SI to point to incoming string
+;-------------------------------------------------------------------
+
+ cmp incoming_AX,ext_handle_opn*256+0 ;is this call an ext open? ;AN003;
+ jne no_eo13 ;AN003;
+ mov si,incoming_SI ; DS:SI points to original name for ex open ;AN003;
+ mov es,incoming_DS ; but this code wants ES:SI to point to it ;AN003;
+ lea di,fname ; DS:DI points to fname area ;AN003;
+ jmp eo_skip3 ; skip the old stuff ;AN003;
+ ;AN003;
+no_eo13: ;AN003;
+ les si,dword ptr handle_ptr ; ES:SI points to original handle
+ lea di,fname ; DS:DI points to fname area
+eo_skip3:
+;-------------------------------------------------------------------
+
+ test mode_flags,Drive_mode ; Drive_mode enabled?
+ jnz check_path_mode ; yes, go check path mode
+
+ call check_for_drive ; no, find out if there is a drive
+ ; specified
+ cmp ax,0 ; was there a drive letter?
+ je check_path_mode ; no, go check path mode
+
+;-------------------------------------------------------------------
+; getting here means that Drive_mode is disabled and that a drive letter
+; was found. This means we give up on this APPEND operation
+
+ jmp drive_or_path_conflict
+
+
+check_path_mode:
+ test mode_flags,Path_mode ; Path_mode enabled?
+ jnz drive_and_path_ok ; yes, go do the APPEND function
+
+ call check_for_path ; no, find out if there is a path
+ ; specified
+
+ cmp ax,0 ; was there a path?
+ jne drive_or_path_conflict ; no, go do the APPEND function
+
+
+ call check_for_drive ; no, find out if there is a drive
+ ; specified
+ cmp ax,0 ; was there a drive letter?
+ je drive_and_path_ok ; no, everything is OK
+ ; yes, fall through and exit w/error
+
+;------------------------------------------------------------------- ;AN001;
+; getting here means that Drive_mode is disabled and that a drive ;AN001;
+; letter was found. This means we give up on this APPEND operatio ;AN001; n
+
+drive_or_path_conflict:
+
+ pop ax ; clean up stack
+ popff
+
+; restore_regs ; restore some regs ;AN002;
+; pop ax
+
+ mov ext_err_flag,1 ; we need to set extended error info
+ mov ax,expected_error ; make ax look like we got file not found
+ mov ax_after_21,ax ; save it away so we can restore it below
+ popff ; get flags from stack
+ stc ; set the carry flag
+ pushf ; put 'em back
+
+ jmp no_more_to_try2
+
+
+drive_and_path_ok: ;AN001;
+ pop ax ; restore AX ;AN001;
+ popff ; restore flags ;AN001;
+ ;AN001;
+;------------------------------------------------------------------- ;AN001;
+; end of code to check DRIVE and PATH modes ;AN001;
+;------------------------------------------------------------------- ;AN001;
+
+ cmp incoming_AX,ext_handle_opn*256+0 ;is this call an ext open? ;AN003;
+ jne no_eo1 ;AN003;
+ mov si,incoming_SI ; DS:SI points to original name for ex open ;AN003;
+ mov es,incoming_DS ; but this code wants ES:SI to point to it ;AN003;
+ lea di,fname ; DS:DI points to fname area ;AN003;
+ jmp eo_skip1 ; skip the old stuff ;AN003;
+ ;AN003;
+no_eo1: ;AN003;
+ les si,dword ptr handle_ptr ; ES:SI points to original handle
+ lea di,fname ; DS:DI points to fname area
+eo_skip1: ;AN003;
+ call get_fname ; strip just the 8.3 filename from
+ ; the original ASCIIZ string
+ call address_path ; address the path
+ cmp es: byte ptr [di],";" ; is append list null ?
+ jump E,no_more_to_try2 ; exit append
+ popff ;
+ mov si,di ; pointer to list of appended directories
+ pushf ; push flags onto stack just for the
+ ; popff below
+
+try_another2:
+ popff
+ lea di,try_dir ; buffer to be filled with dir name
+ ; to try
+ push cx ; save CX
+ call get_app_dir ; this routine will return with a dir
+ ; to try in try_dir
+ mov true_name_count,cx ; save number of chars for later us ;AN003;
+ pop cx
+ mov app_dirs_ptr,si ; save updated pointer
+
+
+;-----------------------------
+try_app_dir2:
+
+ call append_fname ; glue the filename onto the end of the dir to try
+
+
+; we now have an ASCIIZ string that includes the original 8.3 filename
+; and one of the appended dir paths
+
+ mov ax,incoming_AX
+ mov cx,incoming_CX
+ lea dx,try_dir ; point to new ASCIIZ string
+
+ cmp incoming_AX,ext_handle_opn*256+0 ; extended open? ;AN003;
+ jne not_eo1 ;AN003;
+ ;AN003;
+; this is an extended open call ;AN003;
+ ;AN003;
+ save_regs ;AN003;
+ ;AN003;
+ mov si,dx ; ext open wants DS:SI -> filename ;AN003;
+ push cs ;AN003;
+ pop ds ;AN003;
+ ;AN003;
+ mov ax,incoming_AX ; function code ;AN003;
+ mov bx,incoming_BX ; mode word ;AN003;
+ mov cx,incoming_CX ; attributes ;AN003;
+ mov dx,incoming_DX ; flags ;AN003;
+ mov es,incoming_ES ; ES:DI parm_list pointer ;AN003;
+ mov di,incoming_DI ;AN003;
+ ;AN003;
+ call int_21 ; try the extended open ;AN003;
+ ;AN003;
+ restore_regs ;AN003;
+ pushf ; save flags ;AN003;
+; mov es,incoming_ES ; restore es as it was ;AN003;
+ jmp not_exec2 ; go find out what happened ;AN003;
+ ;AN003;
+ ;AN003;
+not_eo1: ;AN003;
+ cmp incoming_AX,exec_proc*256+0 ; exec pgm call
+ jne not_exec1
+
+; this is an exec call ;AN003;
+
+ push es
+ push bx
+ mov ah,get_DTA
+ call int_21
+ mov word ptr incoming_DTA+0,bx ; save callers DTA
+ mov word ptr incoming_DTA+2,es
+ pop bx
+ pop es
+ push ds
+ push dx
+ mov ah,set_DTA
+ lea dx,exec_DTA ; set for fake exec search
+ push cs
+ pop ds
+ call int_21
+ pop dx
+ pop ds
+ mov ah,handle_fnd1 ; precess search by finds
+ mov expected_error,handle_no_more_files
+
+not_exec1:
+
+ push es ; save append's ES
+ push bx ; save append's BX
+ mov es,incoming_ES ; must restore ES before doing the call ; fix for P37, GGA 9/10/87
+ mov bx,incoming_BX ; must resatore user's ES:BX
+
+ call int_21 ; try the open
+
+ pop bx ; restore append's BX
+ pop es ; restore append's es
+ pushf ; save flags
+ cmp incoming_AX,exec_proc*256+0 ; exec pgm call
+ jne not_exec2
+ push ds
+ push dx
+ push ax
+ mov ah,set_DTA
+ mov dx,word ptr incoming_DTA+0 ; restore callers DTA
+ mov ds,word ptr incoming_DTA+2
+ call int_21
+ pop ax
+ pop dx
+ pop ds
+not_exec2:
+ popff
+ pushf
+ jnc found_it_remote ; all done
+
+ cmp crit_err_flag,0 ; process critical errors
+ jne check_crit_err
+
+ cmp ax,handle_path_not_found ; normal errors
+ je should_we_look_more
+
+ cmp ax,expected_error ; was the error we found file not found?
+ je should_we_look_more ; yes, look some more
+ jmp no_more_to_try2 ; no, any other error, we pack it in
+
+should_we_look_more:
+ mov si,app_dirs_ptr ; yes, see if we should look more
+ cmp si,null ; should we try again?
+ je no_more_to_tryx
+ jmp try_another2 ; yes
+no_more_to_tryx:
+ jmp no_more_to_try2
+
+check_crit_err:
+ mov ext_err_flag,1 ; we need to set extended error info
+ mov ax,expected_error ; make ax look like we got file not found
+ mov ax_after_21,ax ; save it away so we can restore it below
+ popff ; get clags from stack
+ stc ; set the carry flag
+ pushf ; put 'em back
+
+ jmp no_more_to_try2
+
+found_it_remote: ; come here only if the file was found in
+ ; an appended directory
+ mov ax_after_21,ax ; save AX
+
+
+; ;AN002;
+; Find out if this process has the true_name flag set in thier PSP. ;AN002;
+; At this point, DS:DX points to the true name of the found file ;AN002;
+; ;AN002;
+ ;AN002;
+ push ax ; save some regs ;AN002;
+ save_regs
+ ;AN002;
+ mov ah,get_PSP ; function code for get PSP operation ;AN002;
+ call int_21 ; get the PSP, segment returned in BX ;AN002;
+ mov es,bx ; need to use it as a segment ;AN002;
+ mov di,PDB_Append ; get pointer to APPEND flag in PDB ;AN002;
+ ;AN002;
+ mov ax,es:[di] ; get APPEND flag into AX ;AN002;
+ test ax,true_name_flag ; is true name flag armed? ;AN002;
+ jz no_true_name ; no, don't copy true name ;AN002;
+ ;AN002;
+ sub ax,true_name_flag ; clear true name flag ;AN002;
+ mov es:[di],ax ; save it in PSP ;AN002;
+ ;AN002;
+ mov di,word ptr handle_ptr+0 ; get user's buffer pointer ES:DI ;AN002;
+ mov es,word ptr handle_ptr+2 ;AN002;
+
+; find out if this is a handle find or an open or an exec
+
+ cmp incoming_AX,exec_proc*256+0 ; exec?
+ je no_true_name ; yes, do nothing with true name
+ ;AN002;
+ cmp incoming_AX,handle_fnd1*256+0 ; handle find?
+ jne not_hf ; no, go do the easy stuff
+ ;AN002;
+; function we are doing is a handle find, must get part of true_name
+; string from append path, part from DTA. Messy!
+
+ lea si,try_dir ; buffer that has last APPEND path tried
+
+ mov cx,true_name_count ; get number of chars in true_name dir ;AN002;
+
+copy_true_name_loop2:
+ mov ah,ds:[si] ; get byte of append dir path ;AN002;
+ mov es:[di],ah ; copy it to user's buffer ;AN002;
+ inc si ; in this loop, the null is not copied ;AN002;
+ inc di ;AN002;
+ loop copy_true_name_loop2 ;AN002;
+
+; put in the "\"
+
+ mov ah,"\" ; get a \
+ mov es:[di],ah ; copy it
+ inc di ; increment pointer
+
+; we have copied the first part of the string, now get the real filename
+; from the DTA
+
+ push es
+ push bx
+
+ mov ah,get_DTA
+ call int_21
+ push es
+ pop ds
+ mov si,bx
+
+ pop bx
+ pop es
+
+copy_true_name_loop3:
+ mov ah,ds:[si+30] ; get byte of actual filename ;AN002;
+ mov es:[di],ah ; copy it to user's buffer ;AN002;
+ cmp ah,null ; is it a null? ;AN002;
+ je true_name_copied ; yes, all done ;AN002;
+ inc si ; in this loop the null is copied ;AN002;
+ inc di ;AN002;
+ jmp copy_true_name_loop3 ;AN002;
+
+not_hf:
+ mov si,dx ; make DS:SI point to true name
+
+copy_true_name_loop: ;AN002;
+ mov ah,ds:[si] ; get byte of true name ;AN002;
+ mov es:[di],ah ; copy it to user's buffer ;AN002;
+ cmp ah,null ; is it a null? ;AN002;
+ je true_name_copied ; yes, all done ;AN002;
+ inc si ;AN002;
+ inc di ;AN002;
+ jmp copy_true_name_loop ;AN002;
+ ;AN002;
+true_name_copied: ;AN002;
+ ;AN002;
+no_true_name: ;AN002;
+ restore_regs ; restore some regs ;AN002;
+ pop ax
+ ;AN002;
+ ;AN002;
+no_more_to_try2:
+
+ call ctrl_break_restore ; restore normal control break address
+ call crit_err_restore ; restore normal critical error address
+
+; find out if there is a need to set the extended error code
+
+ cmp ext_err_flag,0 ; do we need to set the extended error code?
+ je no_ext_err2 ; no, finish up
+ lea dx,ext_err_dpl
+ call set_ext_err_code ; yes, go set the ext error info
+
+; reset flags, and pack it in
+
+no_ext_err2:
+ popff
+ restore_regs ; restore registers
+ pushf ; put the real flags on the stack
+
+ jmp reset_stack ; fix stack, ret to caller
+
+page
+;-------------------------------------------------------------------
+;
+; support routines for drive and path mode checking
+;
+;
+;-------------------------------------------------------------------
+
+
+check_for_drive: ; input: ES:SI -> original string
+ ; output: AX = 0 no drive present
+ ; output: AX = -1 drive present
+
+ xor ax,ax ; assume no drive letter present
+
+ cmp es: byte ptr [si+1],':' ; is the second char a ":"?
+ jne exit_check_for_drive ; no, skip setting the flag
+
+ mov ax,-1 ; yes, set the flag
+
+exit_check_for_drive:
+
+ ret
+
+;-------------------------------------------------------------------
+
+check_for_path: ; input: ES:SI -> original string
+ ; output: AX = 0 no path present
+ ; output: AX = -1 path present
+
+ push si ; save pointer
+
+ xor ax,ax ; assume no path present
+
+
+; walk the string and look for "/", or "\". Any of these mean that a
+; path is present
+
+walk_handle_string:
+
+ push ax ;AN006;
+ mov al,es: byte ptr [si] ; is this a dbcs char? ;AN006;
+ call Chk_DBCS ;AN006;
+ pop ax ;AN006;
+ ;AN006;
+ jnc no_dbcs1 ; no, keep looking ;AN006;
+
+ add si,2 ; yes, skip it and the next char ;AN006;
+ jmp walk_handle_string ; the next char could be a "\", but ;AN006;
+ ; would not mean a path was found ;AN006;
+ ;AN006;
+no_dbcs1: ;AN006;
+ cmp es: byte ptr [si],"\" ; is the char a "\"?
+ je found_path ; yes, set flag and return
+ cmp es: byte ptr [si],"/" ; is the char a "/"?
+ je found_path ; yes, set flag and return
+ cmp es: byte ptr [si],0 ; is the char a null
+ je exit_check_for_path ; yes, got to the end of the
+ ; handle string
+
+ inc si ; point to next char
+ jmp walk_handle_string ; and look again
+
+found_path:
+ mov ax,-1 ; yes, set the flag
+
+exit_check_for_path:
+ pop si ; restore si
+ ret
+
+page
+;-----------------------------------------------------------------------------
+; Entry point for interrupt 2f handler
+;-----------------------------------------------------------------------------
+
+intfcn_hook:
+ cmp ah,append_2f ; is this function call for append?
+;;;;;; je do_appends ; @@12
+ jne ih_10 ; @@12
+ jmp do_appends ; @@12
+ih_10: ; @@12
+ cmp ah,applic_2f ; is this function call for applications
+ je do_applic
+ jmp pass_it_on
+
+do_applic:
+ cmp dx,-1 ; not COMMAND call
+ jump NE,pass_it_on
+ cmp al,0 ; match name request
+ jne ck01
+
+ mov cmd_buf,bx ; save CMDBUF offset
+ call check_cmd_name
+ jne no_internal1
+ mov al,append_inst ; inidicate I want this command
+no_internal1:
+ iret
+
+ck01:
+ cmp al,1 ; match name request
+ jne ck02
+
+; save pointer to parser
+
+ mov word ptr pars_off+0,di ; ES:DI points to COMMAND.COM's parser
+ mov word ptr pars_off+2,es ; save it for later
+
+ mov cmd_env,bx ; save env pointer address
+ call check_cmd_name
+ jne no_internal2
+ call COMMAND_begin ; process internal command
+no_internal2:
+ iret
+
+ck02:
+; cmp al,2 ; set COMMAND active ; @@13; @@09
+; jne ck03 ; @@13; @@09
+; mov cmd_active,1 ; @@13; @@09
+; iret ; @@13; @@09
+ck03: ; @@13; @@09
+; cmp al,3 ; set COMMAND in active ; @@13; @@09
+; jne ck04 ; @@13; @@09
+; mov cmd_active,0 ; @@13; @@09
+; iret ; @@13; @@09
+ck04: ; @@13; @@09
+ jmp pass_it_on
+
+;*******************************************************************************
+; The following old code is commented out. @@12
+;*******************************************************************************
+;check_cmd_name: ; see if internal APPEND
+; push es
+; push cs
+; pop es
+; push di
+; push cx
+; push si
+; cmp ds:byte ptr[si],6 ; length must match
+; jne skip_comp
+; comp append_id,6,[si+1] ; see if APPEND is command
+;skip_comp:
+; pop si
+; pop cx
+; pop di
+; pop es
+; ret
+;*********************************************************************
+check_cmd_name: ; See if APPEND @@12
+ push ax ; @@12
+ push si ; @@12
+ push cx ; @@12
+ push di ; @@12
+ push es ; @@12
+ mov si,cmd_buf ; DS:SI -> cmd buf ended with cr @@12
+ add si,2 ; 1st 2 bytes garbage @@12
+ ; @@12
+ccn_skip_leading: ; @@12
+ lodsb ; skip leading stuff @@12
+
+ call Chk_DBCS ; find out if this is DBCS ;AN006;
+ jnc no_dbcs2 ; no, keep looking ;AN006;
+ lodsb ; yes, skip it and the next byte ;AN006;
+ jmp ccn_skip_leading ; the second byte will be skipper when ;AN006;
+ ; we go back through ;AN006;
+
+no_dbcs2: ;AN006;
+ cmp al," " ; blank @@12
+ je ccn_skip_leading ; @@12
+ cmp al,tab_char ; tab @@12
+ je ccn_skip_leading ; @@12
+ cmp al,"," ; comma @@12
+ je ccn_skip_leading ; @@12
+ cmp al,"=" ; equal @@12
+ je ccn_skip_leading ; @@12
+ cmp al,";" ; semi-colon @@12
+ je ccn_skip_leading ; @@12
+ cmp al,"\" ; back slash @@12
+ je ccn_skip_leading ; @@12
+ cmp al,cr ; bad ret for early terminate @@12
+ jne ccn_02 ; @@12
+ cmp al,0 ; reset z for no match @@12
+ jmp ccn_ret ; @@12
+ccn_02: ; @@12
+ mov di,si ; di -> beginning of possible @@12
+ dec di ; "APPEND " string @@12
+ lodsb ; @@12
+ cmp al,":" ; @@12
+ jne ccn_cont ; @@12
+ mov di,si ; @@12
+ lodsb ; @@12
+ccn_cont: ; @@12
+ call Chk_DBCS ;AN006;
+ jnc no_dbcs3 ; no, carry on ;AN006;
+ add si,2 ; yes, skip it and the next byte ;AN006;
+ jmp ccn_20 ;AN006;
+ ;AN006;
+no_dbcs3: ;AN006;
+ cmp al,"\" ; move di up upon "\" @@12
+ jne ccn_20 ; @@12
+ mov di,si ; @@12
+ccn_10: ; @@12
+ lodsb ; @@12
+ jmp ccn_cont ; @@12
+ccn_20: ; @@12
+ cmp al," " ; look for separator @@12
+ je ccn_30 ; if found, then have command @@12
+ cmp al,"=" ; @@12
+ je ccn_30 ; @@12
+ cmp al,cr ; @@12
+ je ccn_30 ; @@12
+ cmp al,tab_char ; @@12
+ je ccn_30 ; @@12
+ cmp al,"," ; @@12
+ je ccn_30 ; @@12
+ cmp al,";" ; @@12
+ jne ccn_10 ; @@12
+
+ccn_30: ; @@12
+ sub si,di ; @@12
+ cmp si,7 ; @@12
+ jne ccn_ret ; no match @@12
+ ; @@12
+ mov si,di ; @@12
+ chkchar "A" ; look for "APPEND" string @@12
+ chkchar "P" ; @@12
+ chkchar "P" ; @@12
+ chkchar "E" ; @@12
+ chkchar "N" ; @@12
+ chkchar "D" ; @@12
+ ; exit with z set for match @@12
+ccn_ret: ; @@12
+ pop es ; @@12
+ pop di ; @@12
+ pop cx ; @@12
+ pop si ; @@12
+ pop ax ; @@12
+ ret ; @@12
+
+page
+;------------------------------------------------------------------- ;AN000;
+; ;AN000;
+; do_appends ;AN000;
+; ;AN000;
+; This is the INT 2F handler for the APPEND ;AN000;
+; subfunction ;AN000;
+; ;AN000;
+; New functions added for 3.30: ;AN000;
+; ;AN000;
+; ;AN000;
+; ;AN000;
+; Get /X status ;AN000;
+; ;AN000;
+; Input: AX = B706 ;AN000;
+; ;AN000;
+; Output: BX = 0000 /X not active ;AN000;
+; = 0001 /X active ;AN000;
+; ;AN000;
+; ;AN000;
+; ;AN000;
+; Set /X status ;AN000;
+; ;AN000;
+; Input: AX = B707 ;AN000;
+; ;AN000;
+; BX = 0000 turn /X off ;AN000;
+; BX = 0001 turn /X on (active) ;AN000;
+; ;AN000;
+;------------------------------------------------------------------- ;AN000;
+;
+do_appends:
+ cmp al,are_you_there ; is the function request for presence?
+ jne ck1
+
+ mov al,-1 ; set flag to indicate we are here
+ iret ; return to user
+
+ck1:
+ cmp al,dir_ptr ; is the function request for pointer?
+ jne ck2
+
+ les di,dword ptr dirlst_offset ; return dirlist pointer to caller
+ iret
+
+ck2:
+ cmp al,get_app_version ; is the function request for version?
+ jne ck3 ; no, check for next function
+
+ mov ax,-1 ; yes, set NOT NETWORK version
+ iret
+
+ck3:
+ cmp al,tv_vector ; is the function request for TV vector?
+ jne ck4 ; no, check for old dir ptr
+
+ mov tv_vec_seg,es ; yes, save the TV vector
+ mov tv_vec_off,di
+
+ push cs ; set ES:DI to tv ent pnt
+ pop es ;
+ lea di,tv_entry
+
+ xor byte ptr tv_flag,TV_TRUE ; set flag ;AN000;
+ iret
+
+ck4: ;
+ cmp al,old_dir_ptr ; is it the old dir ptr
+ jne ck5 ; no, pass it on
+
+ push ds
+ push cs
+ pop ds
+
+ call sysloadmsg ;AN000;
+ ;AN000;
+ mov ax,1 ; message number ;AN000;
+ mov bx,STDERR ; handle ;AN000;
+ xor cx,cx ; sub count ;AN000;
+ xor dl,dl ; no input ;AN000;
+ mov dh,-1 ; message class ;AN000;
+ call sysdispmsg ;AN000;
+
+ pop ds
+ mov al,1
+ call terminate ; exit to DOS ; @@05
+
+ck5: ;
+ cmp al,DOS_version ; is it the new version check
+ jne ck6 ; no, pass it on
+
+ mov ax,mode_flags ; set mode bits
+ xor bx,bx ; destroy registers
+ xor cx,cx
+ mov dl,byte ptr version_loc ; major version num
+ mov dh,byte ptr version_loc+1 ; minor version num
+ iret
+
+ck6: ;AN000;
+ cmp al,get_state ; is it get state call? ;AN001;
+ jne ck7 ; no, look some more ;AN000;
+ ;AN000;
+ mov bx,mode_flags ; get mode bits ;AN000;
+ iret ; return to user ;AN000;
+ ;AN000;
+ck7: ;AN000;
+ cmp al,set_state ; is it set state call? ;AN001;
+ jne ck8 ; no, look some more ;AN000;
+ ;AN000;
+ mov mode_flags,bx ; save the new state ;AN001;
+ iret ;AN000;
+ ;AN000;
+ck8: ;AN000;
+
+ cmp al,true_name ; is it the set true name function? ;AN002;
+ jne ck9 ; no, look some more ;AN002;
+ ;AN002;
+ push ax ; save some regs ;AN002;
+ push bx ;AN002;
+ push es ;AN002;
+ push di ;AN002;
+ ;AN002;
+ ;AN002;
+; get the PSP and then get the APPEND flags byte
+
+ mov ah,get_PSP ; function code to get PSP address ;AN002;
+ call int_21 ; get the PSP address ;AN002;
+ mov es,bx ; need to use it as a segment ;AN002;
+ mov di,PDB_Append ; get pointer to APPEND flag in PDB ;AN002;
+ ;AN002;
+; is the flag already set?
+
+ mov ax,es:[di] ; get APPEND flag into AX ;AN002;
+ test ax,true_name_flag ; is it set? ;AN002;
+ jnz no_set_true_name ; yes, do nothing ;AN002;
+ ;AN002;
+; set the true_name flag
+
+set_true_name: ;AN002;
+ add ax,true_name_flag ; set true name flag ;AN002;
+ mov es:[di],ax ; save in PSP ;AN002;
+ ;AN002;
+no_set_true_name:
+ pop di ; restore some regs ;AN002;
+ pop es ;AN002;
+ pop bx ;AN002;
+ pop ax ;AN002;
+ ;AN002;
+ iret ; return ;AN002;
+ ;AN002;
+ck9: ;AN002;
+
+;-------------------------------------------------------------------
+; fill in additional 2F functions here
+;-------------------------------------------------------------------
+
+pass_it_on: ; the function call (ah) was not for append
+ jmp dword ptr intfcn_Offset ; jump to old INT 2f
+
+page
+;-----------------------------------------------------------------------------
+; Entry point for interrupt 24 handler
+;-----------------------------------------------------------------------------
+
+crit_err_handler:
+
+ mov crit_err_flag,0ffh ; set critical error flag
+ mov al,3 ; fail int 21h
+ iret
+
+page
+;-----------------------------------------------------------------------------
+; miscellaneous routines
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; tv_barrier
+;-----------------------------------------------------------------------------
+
+tv_barrier:
+
+ cmp tv_flag,TV_TRUE ; in Topview ;AN000;
+ jne no_barrier
+
+ push ax
+ mov ax,2002h ; wait on DOS barrier
+ int 2Ah
+ pop ax
+no_barrier:
+ ret
+
+;-----------------------------
+; check_config - this routine is called by both the FCB and handle open
+; code. I checks the net_config flag to see if it is zero, if so it
+; does an installation check. If it is non-zero, nothing is done.
+
+check_config:
+
+ push ax ; save a few registers
+ push bx
+
+; examine the config flag to see if we already know what config we have
+
+ cmp net_config,0
+ jne do_not_look ; we know config already
+
+; the flag word has not been set before, go find out what config we have
+
+ mov ax,0b800h ; installation code function code
+ int 2fh ; do the installation check
+
+ mov net_config,bx ; save flag word for later
+
+do_not_look:
+ pop bx ;restore regs and leave
+ pop ax
+ ret
+
+;*( Chk_DBCS ) *************************************************************
+;* *
+;* Function: Check if a specified byte is in ranges of the DBCS lead bytes*
+;* Attention: If your code is resident, comment out the lines marked *
+;* ;** . *
+;* *
+;* Input: *
+;* AL = Code to be examined *
+;* *
+;* *
+;* Output: *
+;* If CF is on then a lead byte of DBCS *
+;* *
+;* Register: *
+;* FL is used for the output, others are unchanged. *
+;* *
+;***************************************************************************
+Chk_DBCS PROC
+ PUSH DS
+ PUSH SI
+; CMP CS:DBCSEV_SEG,0 ; ALREADY SET ? ;**
+; JNE DBCS00 ;**
+ MOV SI,OFFSET EVEV ; SET DEFAULT OFFSET ;**
+ PUSH CS ;**
+ POP DS ; SET DEFAULT SEGMENT ;**
+ PUSH AX
+ MOV AX,6300H ; GET DBCS EV CALL
+ INT 21H
+ MOV CS:DBCSEV_OFF,SI ;**
+ MOV CS:DBCSEV_SEG,DS ;**
+ POP AX
+DBCS00:
+ MOV SI,CS:DBCSEV_OFF ;**
+ MOV DS,CS:DBCSEV_SEG ;**
+DBCS_LOOP:
+ CMP WORD PTR [SI],0
+ JE NON_DBCS
+ CMP AL,[SI]
+ JB DBCS01
+ CMP AL,[SI+1]
+ JA DBCS01
+ STC
+ JMP DBCS_EXIT
+DBCS01:
+ ADD SI,2
+ JMP DBCS_LOOP
+NON_DBCS:
+ CLC
+DBCS_EXIT:
+ POP SI
+ POP DS
+ RET
+Chk_DBCS ENDP
+
+
+;-----------------------------
+; append_fname - glues the fname onto the end of the dir to try
+
+append_fname:
+ push es
+ push ds
+ pop es
+ lea di,try_dir ; destination, sort of (dir name)
+ lea si,fname ; source (filename)
+
+; find the end of the dir name
+
+ mov dbcs_fb,-1 ; set flag for no dbcs first byte chars ;AN006;
+
+walk_dir_name:
+ mov al,byte ptr [di] ; get a char from dir name
+ cmp al,null ; are we at the end?
+ je end_of_dir ; yes, add on the fname
+
+ call Chk_DBCS ; char is in al ;AN006;
+ jnc no_dbcs4 ; no, keep looking ;AN006;
+ mov dbcs_fb,di ; save offset ;AN006;
+ inc di ; skip second byte
+
+no_dbcs4:
+ inc di ; no, keep stepping
+ jmp walk_dir_name
+
+; now it is time to append the filename
+
+end_of_dir:
+ mov al,byte ptr [di-1] ; get last char of dir name
+ cmp al,"\" ; is it a dir seperator?
+ jne check_next_dir_sep ; no, check the next dir sep char ;AN006;
+ ;AN006;
+ sub di,2 ; yes, must find out if real dir sep ;AN006;
+ ; or DBCS second byte ;AN006;
+ cmp dbcs_fb,di ; is the char before our dir sep a DBCS ;AN006;
+ ; first byte? ;AN006;
+ jne no_dbcs4a ; no, must check for the next dir sep ;AN006;
+ ; yes, this means we must put in a dir sep ;AN006;
+ add di,2 ; restore di ;AN006;
+ jmp put_in_dir_sep ; put int the dir sep char ;AN006;
+ ;AN006;
+no_dbcs4a: ;AN006;
+ add di,1 ; restore di, then check next dir sep ;AN006;
+
+check_next_dir_sep:
+ cmp al,"/" ; is it the other dir seperator?
+ je add_fname ; yes, no need to add one
+put_in_dir_sep: ;AN006;
+ mov al,"\" ; get dir seperator
+ stosb ; add to end of dir
+
+add_fname:
+ lodsb ; get a char from fname
+ stosb ; copy the char
+ cmp al,null ; are we at the and of the filename?
+ je eo_name ; yes, all done!
+ jmp add_fname
+
+
+
+
+
+
+
+eo_name:
+ pop es
+ ret
+
+
+;-----------------------------
+; get_fname strips out the 8.3 filename from the original ASCIIZ string
+;
+; INPUT: ES:SI points to original string
+; DS:DI points to area for filename
+
+get_fname:
+
+ mov bx,si ; save the pointer
+ mov dbcs_fb,-1 ; set the dbcs flag off ;AN006;
+
+gfn1:
+ mov ah,ES:byte ptr [si] ; get a char from the source
+ cmp ah,null ; is it a null?
+ je got_the_end ; yes, we found the end
+
+ call chk_dbcs ; is this char a DBCS first byte? ;AN006;
+ jnc no_dbcs5 ; no, carry on
+ mov dbcs_fb,si ; yes, save pointer
+ inc si ; skip second byte
+
+no_dbcs5:
+ inc si ; no, point to next char
+ jmp gfn1 ; loop till end found
+
+got_the_end:
+ mov ah,ES:byte ptr [si] ; get a char
+ cmp ah,"/" ; did we find a /
+ je went_too_far ; yes, we found the start
+ cmp ah,"\" ; did we find a \
+ je found_bslash ; yes, we found the start ;AN006;
+ cmp ah,":" ; did we find a :
+ je went_too_far ; yes, we found the start
+ cmp si,bx ; are we back to the original start?
+ je got_the_beg ; yes, we found the start of the fname
+ dec si ; step back a char, then look some more
+ jmp got_the_end
+
+found_bslash: ; found a backslash, must figure out if ;AN006;
+ ; is second byte of DBCS ;AN006;
+ dec si ; point to next char ;AN006;
+ cmp si,dbcs_fb ; do they match?
+ jne no_dbcs5a ; no, fix up si and carry on ;AN006;
+ dec si ; skip dbcs byte and loop some more ;AN006;
+ jmp got_the_end ;AN006;
+
+no_dbcs5a: ;AN006;
+ inc si ; went too far by one extra ;AN006;
+ ;AN006;
+went_too_far:
+ inc si ; went one char too far back
+
+; ES:SI now points to the beginning of the filename
+
+got_the_beg:
+ mov ah,ES:byte ptr [si] ; get a char from the source
+ mov byte ptr [di],ah ; copy to dest
+ cmp ah,null ; did we just copy the end?
+ je done_with_fname ; yes, all done
+ inc si ; no, get the next char
+ inc di
+ cmp di,offset app_dirs_ptr ; make sure we dont try to copy past the
+ je done_with_fname ; area
+ jmp got_the_beg
+
+done_with_fname:
+ ret
+
+;-----------------------------
+; this code executed to return to caller after APPEND's stack has been
+; initialized
+
+reset_stack:
+
+; reset the stack ;AN002;
+
+ popff ; restore flags from real open
+ mov ss,Stack_Segment ; Get original stack segment
+ mov sp,Stack_Offset ; Get original stack pointer
+ pushf ; put the flags on the old stack
+
+
+;-----------------------------
+; before jumping to this routine, SS:SP must point to the caller's stack,
+; and the flags from the real INT 21 operation must have been pushed
+
+set_return_flags:
+
+; must be sure to clear the true_name flag before leaving ;AN002;
+ ;AN002;
+ push ax ; save some regs ;AN002;
+ push bx ;AN002;
+ push es ;AN002;
+ push di ;AN002;
+ ;AN002;
+ mov ah,get_PSP ; function code for get PSP operation ;AN002;
+ call int_21 ; get the PSP, segment returned in BX ;AN002;
+ mov es,bx ; need to use it as a segment ;AN002;
+ mov di,PDB_Append ; get pointer to APPEND flag in PDB ;AN002;
+ ;AN002;
+ mov ax,es:[di] ; get APPEND flag into AX ;AN002;
+ test ax,true_name_flag ; is true name flag armed? ;AN002;
+ jz reset_stack2 ; no, don't copy true name ;AN002;
+ ;AN002;
+ sub ax,true_name_flag ; clear true name flag ;AN002;
+ mov es:[di],ax ; save it in PSP ;AN002;
+ ;AN002;
+ ;AN002;
+reset_stack2: ;AN002;
+ ;AN002;
+ pop di ; restore ;AN002;
+ pop es ;AN002;
+ pop bx ;AN002;
+ pop ax ;AN002;
+ ;AN002;
+ cmp tv_flag,TV_TRUE ;AN000;
+ jne tv_flag_not_set
+
+ mov ax,2003h ; clear open barrier
+ int 2Ah
+
+
+; pop down to the old flags on the user's stack
+
+tv_flag_not_set:
+
+ cmp incoming_AX,exec_proc*256+0 ; need to do exec
+ jne not_exec3
+ popff ; discard bad flags
+ mov ax,incoming_AX ; set exec parms
+
+ push ds ; save DS, this must be done ;an005;
+ ; to pervent DS from being trashed on return to caller ;an005;
+
+ push cs
+ pop ds
+ lea dx,try_dir
+ mov bx,incoming_BX
+ mov es,incoming_ES
+ call int_21 ; issue the exec
+
+ pop ds ; restore DS ; an005;
+
+ pushf
+
+not_exec3:
+ popff ; get flags from real int 21 (old stack)
+ pop temp_IP_save ; save IP, CS
+ pop temp_CS_save
+ lahf ; save flags in AH
+ popff ; pop old flags off stack
+ sahf ; replace old with new
+
+; push the new flags onto the stack, then fix CS and IP on stack
+
+ pushf ; push new flags onto stack
+ push temp_CS_save ; restore IP, CS
+ push temp_IP_save
+ mov ax,AX_after_21 ; Set AX as it was after open
+
+ call crit_sect_reset ; clear the critical section flag
+ iret ; return to the calling routine
+
+
+;-----------------------------
+; This routine is used to extract an appended dir from the dir list
+; On entry, DS:DI points to an area for the appended dir
+; and ES:SI points to the source string
+
+get_app_dir:
+
+ xor cx,cx ; keep a count of chars in cx ;AN003;
+copy_dir:
+ mov ah,es:byte ptr [si] ; get the char, and copy it into dest
+ cmp ah,null ; find a null?
+ je no_more_dirs ; yes, inform caller that this is the last one
+
+ cmp ah,";" ; check to see if we are at the end of a dir
+ je update_pointer ; yes,
+
+ mov byte ptr [di],ah ; if not null or semi-colon, then copy it
+ inc si ; increment both pointers
+ inc di
+ inc cx ; count of chars ;AN003;
+ jmp copy_dir ; do it some more
+
+update_pointer:
+ inc si ; point to next char
+ mov ah,es:byte ptr [si] ; get char ; @@16
+ cmp ah,null ; did we reach the end of the dir list?
+ je no_more_dirs ;
+
+ cmp ah,";" ; is is a semi-colon
+ je update_pointer
+ jmp all_done
+
+
+no_more_dirs:
+ xor si,si ; set end search flag
+
+all_done:
+ mov byte ptr [di],null ; null terminate destination
+ ret ; return to caller
+
+;-----------------------------
+; set ctrl-break check off
+; first, save the old state so we can restore it later,
+; then turn ctrl-break checking off
+
+ctrl_break_set:
+
+ mov ah,ctrl_break ; function code for ctrl-break check
+ xor al,al ; 0 = get current state
+ call int_21 ; call DOS INT 21 handler
+
+ mov ctrl_break_state,dl ; save the old ctrl-break state
+
+ mov ah,ctrl_break ; function code for ctrl-break check
+ mov al,01 ; set current state
+ xor dl,dl ; 0 = off
+ call int_21 ; call DOS INT 21 handler
+ ret
+
+
+;-----------------------------
+; restore ctrl-break checking flag to the way it was
+ctrl_break_restore:
+ mov ah,ctrl_break ; function code for ctrl-break check
+ mov al,01 ; set current state
+ mov dl,ctrl_break_state ; get the way is was before we messed with it
+ call int_21 ; call DOS INT 21 handler
+ ret
+
+;-----------------------------
+; restore ctrl-break checking flag to the way it was
+ctrl_break_rest:
+ mov ah,ctrl_break ; function code for ctrl-break check
+ mov al,01 ; set current state
+ mov dl,ctrl_break_state ; get the way is was before we messed with it
+ call int_21
+ ret
+
+;-----------------------------
+;
+crit_err_set:
+ mov crit_err_flag,0 ; clear the critical error flag
+
+ mov ax,get_crit_err ; Get INT 24h vector
+ call int_21 ; call DOS INT 21 handler
+
+ mov crit_vector_offset,bx ; Save it
+ mov ax,es ; es hase segment for resident code
+ mov crit_vector_segment,ax
+
+ lea dx,crit_err_handler ; DS:DX = New INT 21h vector
+ mov ax,set_crit_err ; function code for setting critical error vector
+ call int_21 ; call DOS INT 21 handler
+ ret ; go back to the caller
+
+
+;-----------------------------
+;
+crit_err_restore:
+ push ds ; save ds for this function
+ mov ax,set_crit_err ; function code for setting critical error vector
+ mov dx,crit_vector_offset ; get old int 24 offset
+ mov ds,crit_vector_segment ; get old int 24 segment
+ call int_21 ; call INT 21
+ pop ds
+ ret
+
+;-----------------------------
+; crit_sect_set - issues an enque request to the server to protect
+; against reentry. This request is issued only if the network is started,
+; and then, only for RCV, MSG, and SRV configurations
+crit_sect_set:
+ push ax
+ push bx
+ push di
+ push es
+
+ mov ax,net_config ; check the server config flag
+ cmp ax,0 ; is it zero?
+ je dont_set_crit_sect ; yes, skip it
+
+ cmp ax,redir_flag ; is it a redir?
+ je dont_set_crit_sect ; yes, skip it
+ ; otherwise, issue the request
+
+; the config flag was not zero or redir, so set crit section
+
+ mov ah,NETSYSUTIL
+ mov al,NETENQ
+ mov bx,TCBR_APPEND
+ int 2Ah
+
+dont_set_crit_sect: ; because of the config we don't want
+ pop es ; to set critical section
+ pop di
+ pop bx
+ pop ax
+ ret
+
+;-----------------------------
+;
+crit_sect_reset:
+ push ax
+ push bx
+
+ mov ax,net_config ; check the server config flag
+ cmp ax,0 ; is it zero?
+ je not_set ; yes, skip it
+
+ cmp ax,redir_flag ; is it a redir?
+ je not_set ; yes, skip it
+
+ mov ah,NETSYSUTIL ; turn critical section off
+ mov al,NETDEQ
+ mov bx,TCBR_APPEND
+ int 2Ah
+
+not_set:
+ pop bx
+ pop ax
+ ret
+
+
+;-----------------------------
+; save_first_ext_err - this routine is used to save the extended
+; error info after the first FCB open.
+save_first_ext_err:
+
+ push ax
+
+ mov ax,ext_err_dpl.DPL_AX ; copy all registers
+ mov save_ext_err.DPL_AX,ax
+ mov ax,ext_err_dpl.DPL_BX
+ mov save_ext_err.DPL_BX,ax
+ mov ax,ext_err_dpl.DPL_CX
+ mov save_ext_err.DPL_CX,ax
+ mov ax,ext_err_dpl.DPL_DX
+ mov save_ext_err.DPL_DX,ax
+ mov ax,ext_err_dpl.DPL_SI
+ mov save_ext_err.DPL_SI,ax
+ mov ax,ext_err_dpl.DPL_DI
+ mov save_ext_err.DPL_DI,ax
+ mov ax,ext_err_dpl.DPL_DS
+ mov save_ext_err.DPL_DS,ax
+ mov ax,ext_err_dpl.DPL_ES
+ mov save_ext_err.DPL_ES,ax
+
+ pop ax
+ ret
+
+;-----------------------------
+; get_ext_err_code - this routine is used to get the extended error
+; info for the error that cause append to start its search
+
+get_ext_err_code:
+ push ax ; save register that are changed by this
+ push bx ; DOS function
+ push cx
+ push di
+ push si
+ push es
+ push ds
+
+; get the extended error information
+
+ mov ah,59h ; function code for get extended error
+ xor bx,bx ; version number
+ call int_21 ; get the extended error
+
+; save it away in a DPL for set_ext_error_code
+; all fields in the DPL will be filled in except the last three,
+; which will be left at zero
+
+ mov ext_err_dpl.DPL_AX,ax
+ mov ext_err_dpl.DPL_BX,bx
+ mov ext_err_dpl.DPL_CX,cx
+ mov ext_err_dpl.DPL_DX,dx
+ mov ext_err_dpl.DPL_SI,si
+ mov ext_err_dpl.DPL_DI,di
+ mov ext_err_dpl.DPL_DS,ds
+ mov ext_err_dpl.DPL_ES,es
+
+
+; restore regs and return
+
+ pop ds
+ pop es ; restore registers
+ pop si
+ pop di
+ pop cx
+ pop bx
+ pop ax
+ ret
+
+;-----------------------------
+; set_ext_err_code - this routine is used to get the extended error
+; info for the error that cause append to start its search
+; CS:DX points to return list
+set_ext_err_code:
+ push ax ; save register that are changed by this
+ push ds ; DOS function
+
+; get the extended error information
+
+ mov ah,DOSSERVER ; function code for DOSSERVER call
+ mov al,DOSSETERROR ; sub-function code for set extended error
+ push cs
+ pop ds
+ call int_21 ; set the extended error
+
+; restore regs and return
+
+ pop ds ; restore registers
+ pop ax
+ ret
+page
+;-----------------------------
+; This routine is used to initiate DOS calls from within the APPEND interrupt
+; handlers. An INT instruction can not be used because it would cause APPEND
+; to be re-entered.
+;
+; SS, SP saved incase call is EXEC which blows them away
+int_21: ;
+ cmp tv_flag,TV_TRUE ; see if being re-entered ;AN000;
+ jne use_old_vec ; yes, pass through to DOS
+
+ pushf ; to comp for iret pops
+ call dword ptr tv_vec_off ; Call INT 21h
+ ret ;
+
+use_old_vec:
+ cmp vector_segment,0 ; not installed yet
+ je use_int
+
+ pushf ; to comp for iret pops
+ call dword ptr vector_offset ; Call INT 21h
+ ret ;
+
+use_int:
+ int DOS_function
+ ret
+page
+;-----------------------------
+; This routine is used to locate the current APPEND path string
+; result to ES:DI
+
+address_path:
+address_status: ; @@13
+ test mode_flags,E_mode
+ jnz get_env_mode
+
+address_pathx:
+ mov ax,append_2f*256+dir_ptr ; get from buffer
+ int int_function
+ clc
+ ret
+
+get_env_mode: ; get from environment
+; cmp cmd_active,0 ; different logic ; @@13; @@09
+; jne use_cmd_env ; if in COMMAND ; @@13; @@09
+ push bx
+ mov ah,get_PSP
+ call int_21 ; get the PSP
+ mov es,bx
+ mov bx,002ch ; address environment
+ mov ax,es:word ptr[bx]
+ mov es,ax
+ pop bx
+ cmp ax,0 ; PSP pointer is set
+ je address_pathx ; @@13
+use_cmd_env: ; @@13
+; cmp cmd_env,0 ; have not set my pointer yet
+; je address_pathx ; @@13
+; mov es,cmd_env ; @@13
+env_mode1:
+ mov di,0 ; start at start
+ cmp es:byte ptr[di],0 ; no environment
+ je no_appendeq
+find_append:
+ cmp es:word ptr[di],0 ; at environment end
+ je no_appendeq
+ push di
+ push si
+ push cx
+ push ds
+ push cs
+ pop ds
+ comp ,6+1,append_id ; string = "APPEND="
+ pop ds
+ pop cx
+ pop si
+ pop di
+ je at_appendeq
+ inc di
+ jmp find_append
+at_appendeq: ; must insure this is @@17
+ cmp di,0 ; genuine "APPEND=" string @@17
+ je at_appendeq_genuine ; if start of environ ok @@17
+ dec di ; else check that 0 @@17
+ cmp es:byte ptr[di],0 ; precedes string @@17
+ je at_appendeq_10 ; jmp if ok @@17
+ add di,8 ; else cont.search after @@17
+ jmp find_append ; "=" @@17
+at_appendeq_10: ; @@17
+ inc di ; @@17
+at_appendeq_genuine: ; @@17
+ add di,6+1 ; skip APPEND=
+ cmp es:byte ptr[di],0 ; null value
+ je no_appendeq ; treat as not found
+ cmp es:byte ptr[di]," "
+ je no_appendeq
+ cmp es:byte ptr[di],";"
+ je no_appendeq
+ clc ; set ok
+ ret
+
+no_appendeq: ; not found, use default
+ lea di,semicolon ; null list
+ push cs
+ pop es
+ stc ; set error
+ ret
+
+;----------------------------- ; @@03
+; This routine is used to locate the current APPEND path string ; @@03
+; result to ES:DI. Used by APPEND status. ; @@03
+
+;address_status: ; @@13; @@03
+; test mode_flags,E_mode ; @@13; @@03
+; jump Z,address_pathx ; @@13; @@03
+; jmp use_cmd_env ; @@13; @@03
+
+cap_dl: ; convert dl to uppercase
+ cmp dl,"a" ; find out if we have a lower case; @@14
+ jb cap_dlx ; char ; @@14
+ cmp dl,"z" ; @@14
+ ja cap_dlx ; @@14
+ sub dl,"a"-"A" ; convert char to upper case ; @@14
+cap_dlx:
+ ret
+
+; end_address: ; this is the end of the TSR stuff ;AN002;
+
+page
+;-----------------------------------------------------------------------------
+; Main routine. Used to determine if APPEND has been loaded
+; before. If not, load resident portion of APPEND. Then handle setting
+; or displaying appended directory list.
+;-----------------------------------------------------------------------------
+
+main_begin: ; DOS entry point
+
+ mov ax,seg mystack ; set up stack
+ mov ss,ax
+ lea sp,mystack
+
+ cld
+
+ mov res_append,0 ; set external copy ; @@05
+
+ push cs ; make DS point to CS
+ pop ds
+
+ push cs ; make ES point to CS
+ pop es
+
+
+; find out if append has been loaded ; @@04
+ ; @@04
+ mov ah,append_2f ; int 2f function code for append ; @@04
+ mov al,are_you_there ; function code to ask if append ; @@04
+ ; has been loaded ; @@04
+ int int_function ; @@04
+ ; @@04
+ cmp al,append_inst ; is append there? ; @@04
+ jne not_there_yet ; no ; @@04
+
+ mov dx,0 ; set for network version ; @@07
+ mov ah,append_2f ; int 2F function code for append ; @@07
+ mov al,DOS_version ; function code for get version ; @@07
+ int int_function ; @@07
+ cmp dx,word ptr version_loc ; does the version match? ; @@07
+ jne bad_append_ver ; no, cough up an error messsage ; @@07
+
+
+ call sysloadmsg ;AN000;
+ ;AN000;
+ mov ax,9 ; message number ;AN000;
+ mov bx,STDERR ; handle ;AN000;
+ xor cx,cx ; sub count ;AN000;
+ xor dl,dl ; no input ;AN000;
+ mov dh,-1 ; message class ;AN000;
+ call sysdispmsg ;AN000;
+; mov cx,len_second_APPEND_msg; length of string ;AN000; ; @@04
+; lea dx,second_APPEND_msg ; second load message ;AN000; ; @@04
+; call print_STDERR ; display error message ;AN000; ; @@04
+; lea dx,crlf ; carriage return, line feed ; @@04
+; mov cx,crlf_len ; length of string ; @@04
+; call print_STDERR ; @@04
+ ; @@04
+ mov al,0fch ; second load ; @@05
+ call terminate ; exit to DOS ; @@05
+
+bad_append_ver: ; append version mismatch ; @@07
+ call sysloadmsg ;AN000;
+ ;AN000;
+ mov ax,1 ; message number ;AN000;
+ mov bx,STDERR ; handle ;AN000;
+ xor cx,cx ; sub count ;AN000;
+ xor dl,dl ; no input ;AN000;
+ mov dh,-1 ; message class ;AN000;
+ call sysdispmsg ;AN000;
+; mov cx,len_bad_append_msg ;AN000; ; @@07
+; lea dx,bad_append_msg ; bad app message ;AN000; ; @@07
+; call print_STDERR ;AN000; ; @@07
+; lea dx,crlf ; carriage return, line feed ; @@07
+; mov cx,crlf_len ; length of string ; @@07
+; call print_STDERR ; @@07
+ mov ax,0feh ; bad APPEND version ; @@05
+ call terminate ; exit to DOS ; @@05
+
+not_there_yet: ; @@04
+
+ mov cs:initial_pass,-1 ; set a flag for initial pass ;AN007;
+ call do_command ; do actual APPEND
+
+ mov bx,4 ; close all standard files
+do_closes:
+ mov ah,3eh ; close file handle
+ call int_21
+ dec bx
+ jns do_closes
+
+ call set_vectors ; set append vectors on success ; @@05
+
+ call Release_Environment ; release the environmental vector space ;an007; dms;
+
+ lea dx,end_address+15 ; normal end
+ mov cl,4 ; calc end address in paragraphs
+ shr dx,cl
+ mov ah,get_PSP ; calc space from PSP to my code ; @@02
+ call int_21 ; @@02
+ mov ax,cs ; @@02
+ sub ax,bx ; @@02
+ add dx,ax ; calc length to keep ; @@02
+ mov al,0 ; exit with no error
+ mov ah,term_stay
+ call int_21
+
+page
+
+COMMAND_begin: ; COMMAND entry point
+ save_regs
+ mov word ptr cmd_name@+0,si ; save internal command buffer @
+ mov word ptr cmd_name@+2,ds
+ cld
+
+ mov abort_sp,sp ; save sp for aborts ; @@05
+ mov res_append,1 ; set resident copy ; @@05
+ call do_command ; do actual APPEND
+abort_exit: ; exit to abort append ; @@05
+ mov sp,abort_sp ; @@05
+
+ push es
+ push di
+ les di,cmd_name@
+ mov es:byte ptr[di],0 ; set no command now
+ pop di
+ pop es
+
+ cmp ax,0 ; error
+ jne no_E_mode
+ test mode_flags,E_mode ; no /E processing
+ jz no_E_mode
+
+ mov ax,append_2f*256+dir_ptr; int 2f function code for append
+ int int_function
+ push es
+ pop ds
+ mov si,di
+
+; mov ah,get_PSP ; set new command
+; call int_21
+ mov bx,ss
+ mov es,bx
+ mov bx,cmd_buf ; command line iput buffer
+ inc bx ; skip max length
+ mov es:byte ptr[bx],3+1+6+1
+ mov di,bx ; address command line buffer
+ inc di ; skip current length
+ push ds
+ push si
+ push cs
+ pop ds
+ move ,3+1+6+1,setappend_name ; set in "SET APPEND="
+ pop si
+ pop ds
+ cmp ds:byte ptr[si],";" ; null list is special case
+ jne copy_path
+ mov al," "
+ stosb
+ inc es:byte ptr[bx]
+ jmp short copy_path_done
+copy_path:
+ lodsb
+ cmp al,0
+ je copy_path_done
+ stosb
+ inc es:byte ptr[bx]
+ jmp copy_path
+copy_path_done:
+ mov es:byte ptr[di],cr ; set end delimiter
+
+ les di,cmd_name@
+ mov al,3 ; SET length
+ stosb
+ push cs ; @@06
+ pop ds ; @@06
+ move ,8,set_name ; set up "SET" command
+
+ mov ax,0 ; set to do SET
+no_E_mode:
+
+ restore_regs
+ ret
+
+page
+
+do_command: ; APPEND process
+
+; set ctrl-break check off
+; first, save the old state so we can restore it later,
+; then turn ctrl-break checking off
+
+ mov ah,ctrl_break ; function code for ctrl-break check
+ xor al,al ; 0 = get current state
+ call int_21
+
+ mov ctrl_break_state,dl ; save the old ctrl-break state
+
+ mov ah,ctrl_break ; function code for ctrl-break check
+ mov al,01 ; set current state
+ xor dl,dl ; 0 = off
+ call int_21
+
+; find out if append has been loaded
+
+ mov ah,append_2f ; int 2f function code for append
+ mov al,are_you_there ; function code to ask if append
+ ; has been loaded
+ int int_function
+
+ cmp al,append_inst ; is append there?
+ jne not_already_there ; yes, don't try to put it
+ jmp already_there ; yes, don't try to put it
+ ; there again
+
+; get DOS version and decide if it is in the allowed range for
+; APPEND
+
+not_already_there:
+ mov ah,get_version ; lets find out if we should do it
+ call int_21 ; try the open
+ cmp ax,expected_version ; compare with DOS version
+ jne bad_DOS
+
+ jmp check_assign ; valid range
+ ; lets see if assign has been loaded
+
+; Break it to the user that he's trying to do an APPEND with
+; the wrong DOS version
+
+bad_DOS:
+ cmp al,01 ; DOS 1x or below has no handle fcns ; fixed P134 9/10/87 - gga
+ ja use_STDERR
+; lea dx,bad_DOS_msg ; bad DOS message ;AN000;
+; mov ah,print_string ;AN000;
+; call int_21 ;AN000;
+ call sysloadmsg ;AN000;
+ ;AN000;
+ mov ax,8 ; message number ;AN000;
+ mov bx,NO_HANDLE ; no handle ;AN000;
+ xor cx,cx ; sub count ;AN000;
+ xor dl,dl ; no input ;AN000;
+ mov dh,-1 ; message class ;AN000;
+ call sysdispmsg ;AN000;
+
+
+ call ctrl_break_rest
+ int termpgm ; return to DOS ; @@05
+
+use_STDERR:
+ ;AN000;
+ call sysloadmsg ;AN000;
+ ;AN000;
+ mov ax,8 ; message number ;AN000;
+ mov bx,STDERR ; handle ;AN000;
+ xor cx,cx ; sub count ;AN000;
+ xor dl,dl ; no input ;AN000;
+ mov dh,-1 ; message class ;AN000;
+ call sysdispmsg ;AN000;
+
+; mov cx,len_bad_DOS_msg ; length of string ;AN000;
+; lea dx,bad_DOS_msg ; bad DOS message ;AN000;
+; call print_STDERR ; display error message ;AN000;
+
+ call ctrl_break_rest
+ mov al,0ffh ; bad DOS version ; @@05
+ call terminate ; exit to DOS ; @@05
+
+check_assign:
+ mov ax,0600h
+ int 2fh
+ or al,al
+ jnz assign_there
+ jmp check_TopView ; ASSIGN has not been loaded, ; @@01
+
+; ASSIGN has been loaded before APPEND, bad news!
+
+assign_there:
+ call sysloadmsg ;AN000;
+ ;AN000;
+ mov ax,6 ; message number ;AN000;
+ mov bx,STDERR ; handle ;AN000;
+ xor cx,cx ; sub count ;AN000;
+ xor dl,dl ; no input ;AN000;
+ mov dh,-1 ; message class ;AN000;
+ call sysdispmsg ;AN000;
+
+; mov cx,len_append_assign_msg; length of string
+; lea dx,append_assign_msg
+; call print_STDERR ; display error message
+ jmp conflict_exit ; @@01
+ ; @@01
+check_Topview: ; @@01
+ mov bx,0 ; incase not there ; @@01
+ mov ax,10h*256+34 ; TopView version check ; @@01
+ int 15h ; @@01
+ cmp bx,0 ; @@01
+ jnz TopView_there ; @@01
+ jmp replace_vector ; TopView has not been loaded, ; @@01
+ ; @@01
+; TopView has been loaded before APPEND, bad news! ; @@01
+ ; @@01
+TopView_there: ; @@01
+; mov cx,len_append_TV_msg ; length of string ; @@01
+; lea dx,append_TV_msg ; @@01
+; call print_STDERR ; display error message ; @@01
+ call sysloadmsg ;AN000;
+ ;AN000;
+ mov ax,7 ; message number ;AN000;
+ mov bx,STDERR ; handle ;AN000;
+ xor cx,cx ; sub count ;AN000;
+ xor dl,dl ; no input ;AN000;
+ mov dh,-1 ; message class ;AN000;
+ call sysdispmsg ;AN000;
+
+ ; @@01
+conflict_exit: ; @@01
+ call ctrl_break_rest
+ mov al,0fdh ; @@05
+ call terminate ; exit to DOS ; @@05
+
+; get pointer to dir list, on return ES:DI points to buffer
+
+already_there:
+
+; This code has been moved to main_begin ; @@07
+; ; @@07
+; make sure the right version of APPEND has been loaded ; @@07
+;
+
+; mov dx,0 ; set for network version ; @@07
+; mov ah,append_2f ; int 2F function code for append ; @@07
+; mov al,DOS_version ; function code for get version ; @@07
+; int int_function ; @@07
+; cmp dx,word ptr version_loc ; does the version match? ; @@07
+; jump NE,bad_append_ver ; no, cough up an error messsage ; @@07
+
+process_args: ; process all arguments
+
+;-------------------------------------------------------------------
+ mov si,0081h ; DS:SI points to argument area
+ mov cs:byte ptr e_switch+9,0 ; turn /E switch off
+
+process_argsx: ; process all arguments
+;
+
+
+; make sure that the /PATH and /X switches are re-enabled, and
+; various flags are cleared
+
+ mov ah,"/"
+ mov cs:byte ptr x_switch+9,ah ; re-enable /X switch
+ mov cs:byte ptr path_switch+9,ah ; re-enable /PATH switch
+ mov cs:byte ptr x_result.$P_Type,0 ; clear flag
+ mov cs:byte ptr path_result.$P_Type,0 ; clear flag
+ mov cs:byte ptr dirs_result.$P_Type,0 ; clear flag
+ mov cs:parse_flag,0 ; clear parse flag
+
+; set up things to call PARSER
+
+ push cs ; make sure ES points to segment where
+ pop es ; parm block info is
+ lea di,cs:p_block2 ; ES:DI points to parm block, for secondary parsing
+
+
+ xor cx,cx ; ordinal value, must start as 0
+ xor dx,dx ; must be 0
+
+ call Scan_For_Equal ; yes - let's see if we have "=" symbol ;an008; dms;
+ ; parse past it if we do
+
+get_pars_info:
+ call dword ptr pars_off ; call to COMMAND.COM's parser
+
+ cmp ax,-1 ; end of line?
+ jne not_end_of_line ; no, carry on
+ jmp end_of_line_reached ; yes, go figure out what we got
+
+not_end_of_line:
+
+ cmp ax,0 ; no, find out if there an error
+ je not_parse_error ; no, carry on
+ jmp parse_error ; yes, go display the error message
+
+; got here without any errors, set the proper bits in mode_flags
+
+not_parse_error:
+ mov cs: parse_flag,0ffh ; set parse flag
+
+
+check_e:
+ cmp e_result.$P_Type,3 ; was there a /E in this pass?
+ jne check_x ; no, look for an X
+
+ mov byte ptr e_switch+9,0 ; turn this off so we don't allow another
+ mov e_result.$P_Type,0 ; clear this so we don't get fooled later
+
+ or mode_flags,E_mode ; set E mode on
+
+ jmp get_pars_info ; go get another argument
+
+check_x:
+ cmp x_result.$P_Type,3 ; was there a /X on this pass? list index
+ je set_x ; yes, and it was /X w/o ON or OFF
+
+ cmp x_result.$P_Type,2 ; was there a /X on this pass? list index
+ jne check_path
+
+ mov byte ptr x_switch+9,0 ; turn this off so we don't allow another
+ mov x_result.$P_Type,0 ; clear this so we don't get fooled later
+
+ cmp x_result.$P_Item_Tag,1 ; was /X or /X:ON specified?
+ je set_x ; yes, set X mode on
+ and mode_flags,NOT x_mode ; no, clear it
+ jmp get_pars_info
+
+set_x:
+ or mode_flags,x_mode
+ jmp get_pars_info
+
+check_path:
+ cmp path_result.$P_Type,2 ; was there a /path on this pass? list index
+ jne check_dirs
+
+ xor ah,ah ; turn this off so we don't allow
+ mov byte ptr path_switch+9,ah ; another
+ mov path_result.$P_Type,0 ; clear this so we don't get fooled later
+
+
+ cmp path_result.$P_Item_Tag,1 ; was /PATH:ON specified?
+ je set_path ; yes, set PATH mode
+ and mode_flags,NOT path_mode ; no, clear it
+ jmp get_pars_info
+
+set_path:
+ or mode_flags,path_mode ; set PATH mode on
+ jmp get_pars_info
+
+; find out if dirs specified
+
+check_dirs:
+ cmp dirs_result.$P_Type,3 ; was a simple string returned?
+ je check_dirs2 ; yes, carry on
+ jmp get_pars_info ; no, all done for now
+
+; set up stuff to do the dirs copy
+
+check_dirs2:
+ push es
+ push ds
+ push si
+ push di
+
+ lds si,dword ptr dirs_result.$P_Picked_Val ; get pointer to dirs string
+ mov dirs_result.$P_Type,0 ; clear this so we don't get fooled later
+
+ mov di,0 ; set incase int 2f not installed ; @@08
+ mov es,di ; @@08
+ mov ax,append_2f*256+dir_ptr ; es:di -> internal result area ; @@08
+ int int_function ; @@08
+ mov ax,es ; see if active yet ; @@08
+ or ax,di ; @@08
+ jnz copy_dirs_loop ; ok, do the copy ; @@08
+ push cs ; not active, set myself ; @@08
+ pop es ; @@08
+ lea di,app_dirs ; @@08
+
+copy_dirs_loop:
+ movs es: byte ptr[di],ds:[si]; copy char
+
+ cmp byte ptr ds:[si-1],0 ; is char a null
+ je done_copy_dirs
+
+ jmp copy_dirs_loop
+
+done_copy_dirs:
+
+ pop di
+ pop si
+ pop ds
+ pop es
+
+ jmp get_pars_info ; no error yet, loop till done
+
+end_of_line_reached:
+ mov old_syntax,0 ; process old format operands
+
+ cmp cs:initial_pass,-1 ; is this the first APPEND ;AN006;
+ je first_one ; yes, clear flag and exit ;AN006;
+
+ cmp cs:parse_flag,0 ; if this flag is off, means null command line
+ ; was nothing on the command line
+ je display_dirs ; go display the dirs
+
+first_one: ;AN006;
+ mov cs:initial_pass,0 ; clear first pass flag ;AN006;
+
+done_for_now:
+normal_exit:
+ call ctrl_break_rest ; reset control break checking
+ mov ax,0 ; set string
+ ret ; exit to COMMAND
+
+
+parse_error:
+ push ax ;save parser error code ;an010;bgb
+ call sysloadmsg ;AN000;
+ pop ax ;restore parser error coed ;an010;bgb
+ call do_parse_err ;an010;bgb
+ jmp bad_parmx ; display message and get out
+
+;-------------------------------------------------------------------
+
+; mov si,0081h ; point si to argument area
+; mov bx,ss
+; mov ds,bx
+;
+;process_argsx: ; process all arguments
+; mov di,0 ; set incase int 2f not installed ; @@08
+; mov es,di ; @@08
+; mov ax,append_2f*256+dir_ptr ; es:di -> internal result area ; @@08
+; int int_function ; @@08
+; mov ax,es ; see if active yet ; @@08
+; or ax,di ; @@08
+; jnz have_ptr ; @@08
+; push cs ; not active, set myself ; @@08
+; pop es ; @@08
+; lea di,app_dirs ; @@08
+;have_ptr: ; @@08
+;
+;; step through the DOS command line argument area, and copy the new dir
+;; list to the proper place in APPEND. This requires some parsing for
+;; spaces, tabs chars, equal signs, as well as conversion to upper case
+;
+; cmp byte ptr[si],"=" ; APPEND=path is OK syntax
+; jne skip_leading
+; inc si
+;skip_leading: ; skip leading spaces
+; lodsb
+; cmp al," "
+; je skip_leading
+; cmp al,tab_char
+; je skip_leading
+; cmp al,"," ; @@15
+; je skip_leading ; @@15
+; cmp al,"=" ; @@15
+; je skip_leading ; @@15
+; cmp al,cr ; did we have command line arguments?
+; jump E,display_dirs ; no, display the dirs currently appended
+; cmp al,"/" ; is it a parm starter? ; @@05
+; jump E,bad_path_parm ; yes, it's an error ; @@05
+; dec si
+;
+;copy_args:
+; lodsb ; get char from command line area
+; cmp al,cr ; are we at the end?
+; jump E,found_end ; yes, display the currently appended dirs
+; cmp al," " ; is it a space?
+; je found_space ; yes, at end
+; cmp al,tab_char ; is it a tab?
+; je found_space ; yes, treat it like a space
+; cmp al,"/" ; is it a parm starter?
+; je bad_path_parm ; yes, it's an error ; @@05
+; cmp al,"a" ; find out if we have a lower case char
+; jb copy_char ; @@14
+; cmp al,"z"
+; ja copy_char ; @@14
+; sub al,"a"-"A" ; convert char to upper case ; @@14
+;
+;copy_char:
+; mov in_middle,-1 ; say that we made it to the middle
+; stosb ; no, copy char into resident storage area
+; jmp copy_args ; do it some more
+;
+;found_space:
+; cmp in_middle,0 ; set the space flag then go through
+; jump E,copy_args ; loop some more
+;
+;found_end:
+; cmp in_middle,0 ; if I found the end of string but not
+; jump E,display_dirs ; in the middle, go display some dirs
+;
+; mov es:byte ptr [di],0 ; null terminate the string
+; mov in_middle,0
+; cmp al,cr
+; je past_trailing
+;
+;skip_trailing: ; skip end spaces
+; lodsb
+; cmp al," "
+; je skip_trailing
+; cmp al,tab_char
+; je skip_trailing
+; cmp al,"/" ; path and parm not together ; @@05
+; je bad_path_parm ; @@05
+; cmp al,cr ; only white space allowed at end
+; jne bad_path
+;past_trailing:
+;
+; cmp old_syntax,0 ; go back to normal mode
+; je normal_exit
+; jmp exit_append2
+;normal_exit:
+; call ctrl_break_rest ; reset control break checking
+; mov ax,0 ; set string
+; ret ; exit to COMMAND
+
+bad_path: ; bad paath operand
+; mov cx,len_path_error_msg ; length of string
+; lea dx,path_error_msg
+ call sysloadmsg ;AN000;
+ ;AN000;
+ mov ax,3 ; message number ;AN000;
+ mov bx,STDERR ; handle ;AN000;
+ xor cx,cx ; sub count ;AN000;
+ xor dl,dl ; no input ;AN000;
+ mov dh,-1 ; message class ;AN000;
+;gga call sysdispmsg ;AN000;
+
+ jmp short bad_parmx
+
+bad_path_parm: ; bad parameter ; @@05
+; mov cx,len_path_parm_error_msg ; length of string ; @@05
+; lea dx,path_parm_error_msg ; @@05
+ call sysloadmsg ;AN000;
+ mov ax,3 ; message number ;AN000;
+ mov bx,STDERR ; standard error ;AN000;
+ xor cx,cx ; sub count ;AN000;
+ xor dl,dl ; no input ;AN000;
+ mov dh,-1 ; message class ;AN000;
+ jmp short bad_parmx ; @@05
+bad_parm: ; bad parameter
+; mov cx,len_parm_error_msg ; length of string
+; lea dx,parm_error_msg
+ call sysloadmsg ;AN000;
+ ;AN000;
+ mov ax,3 ; message number ;AN000;
+ mov bx,STDERR ; standard error ;AN000;
+ xor cx,cx ; sub count ;AN000;
+ xor dl,dl ; no input ;AN000;
+ mov dh,-1 ; message class ;AN000;
+
+bad_parmx: ; bad parameter
+ push ds
+ push cs
+ pop ds
+; call print_STDERR ; display error message
+ lea si,inv_parm ; point to msg parm ;an010;bgb
+ call sysdispmsg ;AN000;
+ pop ds
+ call ctrl_break_rest
+ mov al,1 ; @@05
+ call terminate ; exit to DOS ; @@05
+
+; This code has been moved to main_begin ; @@07
+;bad_append_ver: ; append version mismatch ; @@07
+; push ds ; @@07
+; push cs ; @@07
+; pop ds ; @@07
+; mov cx,len_bad_append_msg ; @@07
+; lea dx,bad_append_msg ; bad app message ; @@07
+; call print_STDERR ; @@07
+; lea dx,crlf ; carriage return, line feed ; @@07
+; mov cx,crlf_len ; length of string ; @@07
+; call print_STDERR ; @@07
+; pop ds ; @@07
+; call ctrl_break_rest ; @@07
+; mov ax,0feh ; bad APPEND version ; @@05
+; call terminate ; exit to DOS ; @@05
+
+; Display currently appended directories
+
+display_dirs:
+ call address_status ; get working path ; @@03
+ push ds
+ push es
+ pop ds
+
+ cmp es:byte ptr[di],";" ; no append now
+ je no_dirs_appended
+
+; count the chars in the dir list, cx will hold the count
+
+ mov si,di
+ sub si,6+1 ; move pointer to APPEND
+ mov dx,si ; save pointer to string
+ xor cx,cx
+
+scanit:
+ lodsb ; get character
+ cmp al,null ; are we at end?
+ je print_it ; yes, print it
+ inc cx ; look at the next character
+ jmp scanit ; loop till we find the end
+
+print_it:
+ call print_STDOUT ; display appended dirs
+ push cs
+ pop ds
+ lea dx,crlf ; carriage return, line feed
+ mov cx,crlf_len ; length of string
+ call print_STDOUT
+ pop ds
+
+exit_append:
+ cmp old_syntax,0 ; process old format operands
+ je exit_append2
+ mov si,0081h ; set up rescan
+ mov ah,get_PSP
+ call int_21
+ mov ds,bx
+ jmp process_argsx
+
+exit_append2:
+ mov old_syntax,0 ; after first time this must be off
+ call ctrl_break_rest ; reset control break checking
+ mov ax,-1 ; no action
+ ret ; exit to COMMAND
+
+no_dirs_appended:
+ push cs
+ pop ds
+
+ call sysloadmsg ;AN000;
+ ;AN000;
+ mov ax,5 ; message number ;AN000;
+ mov bx,STDERR ; handle ;AN000;
+ xor cx,cx ; sub count ;AN000;
+ xor dl,dl ; no input ;AN000;
+ mov dh,-1 ; message class ;AN000;
+ call sysdispmsg ;AN000;
+
+; lea dx,no_append_msg ; no dirs message ;AN000;
+; mov cx,len_no_append_msg ; length of string ;AN000;
+; call print_STDOUT ;AN000;
+ pop ds
+ jmp exit_append2 ; APPEND = = fix ;GGA
+
+page
+;-------------------------------------------------------------------
+; Getting here means that APPEND has not been loaded yet. Get the
+; old vector, save it, and point the vector to the new routine.
+;-------------------------------------------------------------------
+
+replace_vector:
+
+ push ds
+ mov si,0081h ; point si to argument area
+ mov ah,get_PSP
+ call int_21
+ mov ds,bx
+
+; Process /X and /E parameters
+
+skip_leading2: ; skip leading spaces
+; lodsb
+; cmp al," "
+; je skip_leading2
+; cmp al,tab_char
+; je skip_leading2
+; cmp al,cr ; at end
+; jump E,parms_done
+; cmp al,"/"
+; jne set_old_syntax
+
+found_slash:
+; lodsb
+; cmp al,"e"
+; je slash_E
+; cmp al,"E"
+; je slash_E
+; cmp al,"x"
+; je slash_X
+; cmp al,"X"
+; je slash_X
+bad_parmy:
+; pop ds
+; jmp bad_parm
+bad_path_parmy:
+; pop ds
+; jmp bad_path_parm
+
+slash_X:
+; test mode_flags,X_mode ; no duplicates allowed
+; jnz bad_parmy
+; or mode_flags,X_mode
+; jmp short slashx
+
+slash_E:
+; test mode_flags,E_mode ; no duplicates allowed
+; jnz bad_parmy
+; or mode_flags,E_mode
+slashx:
+; jmp skip_leading2 ; loop some more
+set_old_syntax:
+;; test mode_flags,0 ; no /? switches on old mode
+;; jne bad_path_parmy
+ mov old_syntax,1
+parms_done:
+ pop ds
+ jmp exit_append
+page
+
+set_vectors: ; set append hooks ; @@05
+ push es
+
+; Get INT 2f vector. Save to call older 2f handlers
+
+ mov ax,get_intfcn ; Get INT 2fh vector
+ call int_21
+ mov intfcn_offset,bx ; Save it
+ mov intfcn_segment,es
+
+; get int 21 vector
+
+ mov ax,get_vector ; Get INT 21h vector
+ call int_21
+ mov vector_offset,bx ; Save it
+ mov vector_segment,es
+ pop es
+
+ push ds ; @@08
+ push cs ; @@08
+ pop ds ; @@08
+ lea dx,intfcn_hook ; DS:DX = New INT 2fh vector
+ mov ax,set_intfcn ; Hook the interrupt
+ call int_21
+
+ lea dx,interrupt_hook ; DS:DX = New INT 21h vector
+ mov ax,set_vector ; Hook the interrupt
+ call int_21
+
+ mov dirlst_segment,cs ; save the address of the dirlist
+ lea dx,app_dirs
+ mov dirlst_offset,dx
+ pop ds ; @@08
+
+ ret ; @@05
+
+terminate: ; terminate to dos or return ; @@05
+ cmp res_append,0 ; @@05
+ jne is_res ; @@05
+ call Release_Environment ; release environmental vector ;ac009; dms;
+ mov ah,term_proc ; return to DOS on first time ; @@05
+ call int_21 ; @@05
+is_res: ; @@05
+ mov ax,-1 ; set abort requested ; @@05
+ jmp abort_exit ; must go back to COMMAND ; @@05
+
+
+print_STDOUT:
+ mov bx,STDOUT ; Standard output device handle
+ mov ah,awrite ; function code for write
+ call int_21
+ ret
+
+print_STDERR:
+ mov bx,STDERR ; Standard output device handle
+ mov ah,awrite
+ call int_21
+ ret
+
+Release_Environment: ;an007; dms;
+
+ push ax ;save regs ;an007; dms;
+ push bx ; ;an007; dms;
+ push es ; ;an007; dms;
+ mov ah,Get_PSP ; get the PSP segment ;an007; dms;
+ call int_21 ; invoke INT 21h ;an007; dms;
+ mov es,bx ; BX contains PSP segment - put in ES ;an007; dms;
+ mov bx,word ptr es:[PSP_Env]; get segment of environmental vector ;an007; dms;
+ mov es,bx ; place segment in ES for Free Memory ;an007; dms;
+ mov ah,Free_Alloc_Mem ; Free Allocated Memory ;an007; dms;
+ int 21h ; invoke INT 21h ;an007; dms;
+ pop es ; restore regs ;an007; dms;
+ pop bx ; ;an007; dms;
+ pop ax ; ;an007; dms;
+
+ ret ; return to caller ;an007; dms;
+
+;=========================================================================
+; Scan_For_Equal : This routine scans the command line from the
+; beginning until it encounters anything other
+; than the equal, tab, or space characters.
+; Register SI is sent back to the caller pointing
+; to the character that does not meet the match
+; criteria.
+;
+; Inputs : DS:SI - pointer to next parm
+;
+; Outputs : SI - adjusted to byte not matching the following:
+; "="
+; " "
+; TAB
+;
+; Author : DS
+; Date : 1/27/88
+; Version : DOS 3.4
+;=========================================================================
+
+Scan_For_Equal:
+
+ push ax ; save regs ;an008; dms;
+ push cx ; ;an008; dms;
+
+ xor cx,cx ; clear cx ;an008; dms;
+ mov cl,byte ptr ds:[80h] ; get length of command line ;an008; dms;
+
+Scan_For_Equal_Loop:
+
+ cmp cx,0 ; at end? ;an008; dms;
+ jbe Scan_For_Equal_Exit ; exit loop ;an008; dms;
+ mov al,byte ptr ds:[si] ; get 1st. character ;an008; dms;
+ call Chk_DBCS ; DBCS lead byte? ;an008; dms;
+ jnc Scan_For_Equal_No_DBCS ; no ;an008; dms;
+ cmp byte ptr ds:[si],81h ; blank lead byte ;an008; dms;
+ jne Scan_For_Equal_Exit ; exit with adjusted SI ;an008; dms;
+ cmp byte ptr ds:[si+1],40h ; DBCS blank ;an008; dms;
+ jne Scan_For_Equal_Exit ; exit with adjusted SI ;an008; dms;
+
+ add si,2 ; yes - DBCS lead byte ;an008; dms;
+ sub dx,2 ; decrease counter ;an008; dms;
+ jmp Scan_For_Equal_Loop
+
+Scan_For_Equal_No_DBCS:
+
+ cmp al,"=" ; = found? ;an008; dms;
+ je Scan_For_Equal_Next ; next character ;an008; dms;
+ cmp al,20h ; space? ;an008; dms;
+ je Scan_For_Equal_Next ; next character ;an008; dms;
+ cmp al,09h ; tab? ;an008; dms;
+ je Scan_For_Equal_Next ; next character ;an008; dms;
+ jmp Scan_For_Equal_Exit ; exit with adjusted SI ;an008; dms;
+
+Scan_For_Equal_Next:
+
+ inc si ; adjust ptr ;an008; dms;
+ dec cx ; decrease counter ;an008; dms;
+ jmp Scan_For_Equal_Loop ; continue loop ;an008; dms;
+
+Scan_For_Equal_Exit:
+
+ pop cx ; ;an008; dms;
+ pop ax ; ;an008; dms;
+
+ ret ; return to caller ;an008; dms;
+
+
+
+;========================================================================= ;an010;bgb
+; do_parse_err : This routine sets up for the display of a parse ;an010;bgb
+; error, and displays the offending parameter. ;an010;bgb
+; ;an010;bgb
+; Inputs : DS:SI - points just past offending parm in command line ;an010;bgb
+; ;an010;bgb
+; Outputs : si_off- parm for msg ret. ;an010;bgb
+; si_seg- parm for msg ret. ;an010;bgb
+; command line - hex zero at end of offending parm ;an010;bgb
+; ;an010;bgb
+; Date : 3/29/88 ;an010;bgb
+; Version : DOS 4.0 (wow!) ;an010;bgb
+;========================================================================= ;an010;bgb
+do_parse_err PROC ;an010;bgb
+;;;;;;;;mov ax,3 ;removed- parser handles this ;an010;bgb
+ mov bx,STDERR ; handle ;an010;bgb
+;;;;;;;;xor cx,cx ; sub count ;an010;bgb
+ mov cx,1 ;display invalid parm ;an010;bgb
+ xor dl,dl ; no input ;an010;bgb
+ mov dh,02 ; message class of parse error ;an010;bgb
+;;;;;;;;mov cs:si_off,81h ;initialize pointer ;an010;bgb
+ ;an010;bgb
+ dec si ;point to last byte of invalid parm ;an010;bgb
+public decsi ;an010;bgb
+decsi: cmp byte ptr [si],' ' ;are we pointing to a space? ;an010;bgb
+; $IF E,OR ;if so, we dont want to do that ;an010;bgb
+ JE $$LL1
+ cmp byte ptr [si],0dh ;are we pointing to CR? ;an010;bgb
+; $IF E ;if so, we dont want to do that ;an010;bgb
+ JNE $$IF1
+$$LL1:
+ dec si ;find the last byte of parm ;an010;bgb
+ jmp decsi ;an010;bgb
+; $ENDIF ;an010;bgb
+$$IF1:
+ mov byte ptr [si+1],00 ;zero terminate display string ;an010;bgb
+nextsi: ;an010;bgb
+public nextsi ;an010;bgb
+ dec si ;look at previous char ;an010;bgb
+ cmp byte ptr [si],' ' ;find parm separator ;an010;bgb
+ jnz nextsi ;loop until begin of parm found ;an010;bgb
+ ;an010;bgb
+ mov cs:si_off,si ;mov si into display parms ;an010;bgb
+ mov cs:si_seg,ds ;initialize pointer ;an010;bgb
+ ret ; return to caller ;an010;bgb
+do_parse_err ENDP ;an010;bgb
+
+
+;-------------------------------------------------------------------
+;
+;-------------------------------------------------------------------
+
+MSG_SERVICES
+MSG_SERVICES
+
+end_address: ; this is the end of the TSR stuff ;AN004;
+
+include parse.asm ; include the parser code
+include msgdcl.inc
+
+cseg ends
+sseg segment para stack 'STACK'
+ assume ss:sseg
+ dw 512 dup(0)
+mystack dw 0
+sseg ends
+
+
+
+ end main_begin
+
\ No newline at end of file
diff --git a/v4.0/src/CMD/APPEND/APPEND.SKL b/v4.0/src/CMD/APPEND/APPEND.SKL
new file mode 100644
index 0000000..3fc30ef
--- /dev/null
+++ b/v4.0/src/CMD/APPEND/APPEND.SKL
@@ -0,0 +1,24 @@
+
+;-------------------------------------------------------------------
+; message retriever skeleton file for APPEND
+;-------------------------------------------------------------------
+:util APPEND
+
+:class a
+;:use 1 COMMON1
+:def 1 "Incorrect APPEND version",CR,LF
+:def 2 "Invalid path",CR,LF
+:def 3 "Invalid parameter",CR,LF
+:def 4 "Invalid combination of parameters",CR,LF
+:def 5 "No Append",CR,LF
+
+:class b
+:def 6 "APPEND / ASSIGN Conflict",CR,LF
+:def 7 "APPEND / TopView Conflict",CR,LF
+:def 8 "Incorrect DOS Version",CR,LF
+:def 9 "APPEND already installed",CR,LF
+;:use 8 COMMON1 ;"Incorrect DOS Version"
+;:use 9 COMMON1 ;"APPEND already installed"
+
+:end
+
\ No newline at end of file
diff --git a/v4.0/src/CMD/APPEND/APPENDM.ASM b/v4.0/src/CMD/APPEND/APPENDM.ASM
new file mode 100644
index 0000000..5cd3f69
--- /dev/null
+++ b/v4.0/src/CMD/APPEND/APPENDM.ASM
@@ -0,0 +1,36 @@
+page 60,120
+; @@04 07/30/86 Fix second APPEND hang PTM P0000053
+; @@05 08/13/86 Fix bad parm message PTM P0000125
+; @@10 08/28/86 Change message for @@05 PTM P0000291
+; @@11 09/10/86 Support message profile and make
+; msg length variable. R.G. PTM P0000479
+cseg segment public para 'CODE'
+ assume cs:cseg
+
+ public bad_append_msg ;@@11
+ public path_error_msg ;@@11
+ public parm_error_msg ;@@11
+ public path_parm_error_msg ;@@11
+ public no_append_msg ;@@11
+ public append_assign_msg ;@@11
+ public append_tv_msg ;@@11
+ public bad_DOS_msg ;@@11
+ public second_append_msg ;@@11
+
+ public len_bad_append_msg ;@@11
+ public len_path_error_msg ;@@11
+ public len_parm_error_msg ;@@11
+ public len_path_parm_error_msg ;@@11
+ public len_no_append_msg ;@@11
+ public len_append_assign_msg ;@@11
+ public len_append_tv_msg ;@@11
+ public len_bad_DOS_msg ;@@11
+ public len_second_append_msg ;@@11
+
+cr equ 13
+lf equ 10
+
+include appendm.inc
+
+cseg ends
+ end
diff --git a/v4.0/src/CMD/APPEND/APPENDP.INC b/v4.0/src/CMD/APPEND/APPENDP.INC
new file mode 100644
index 0000000..432d4ec
--- /dev/null
+++ b/v4.0/src/CMD/APPEND/APPENDP.INC
@@ -0,0 +1,147 @@
+
+INCSW EQU 0 ;INCLUDE PSDATA.INC ;AN000;
+FARSW EQU 1 ;CALL THE PARSER BY NEAR CALL
+DATESW EQU 0 ;SUPPRESS DATE CHECKING ;AN000;
+TIMESW EQU 0 ;SUPPRESS TIME CHECKING ;AN000;
+FILESW EQU 0 ;SUPPRESS CHECKING FILE SPECIFICATION ;AN000;
+CAPSW EQU 0 ;SUPPRESS FILE TABLE CAPS ;AN000;
+CMPXSW EQU 1 ;SUPPRESS CHECKING COMPLEX LIST
+DRVSW EQU 1 ;SUPPRESS SUPPORT OF DRIVE ONLY FORMAT
+QUSSW EQU 0 ;SUPPRESS SUPPORT OF QUOTED STRING FORMAT ;AN000;
+NUMSW EQU 1 ;SUPPRESS CHECKING NUMERIC VALUE
+KEYSW EQU 0 ;SUPPRESS KEYWORD SUPPORT ;AN000;
+SWSW EQU 1 ;DO SUPPORT SWITCHES ;AN000;
+VAL1SW EQU 0 ;SUPPRESS SUPPORT OF VALUE DEFINITION 1 ;AN000;
+VAL2SW EQU 0 ;SUPPRESS SUPPORT OF VALUE DEFINITION 2 ;AN000;
+VAL3SW EQU 1 ;DO SUPPORT VALUE DEFINITION 3
+
+include psdata.inc
+;***********************************************************************
+
+;-------------------------------------------------------------------
+;
+; parser stuff for APPEND
+;
+;-------------------------------------------------------------------
+
+
+
+p_block1 $P_PARMS_Blk ; parm block
+p_block2 $P_PARMS_Blk ; parm block
+
+;------------------------
+; extended parameter block for APPEND first load
+
+px_block1:
+ db 0 ; min number positional operands
+ db 0 ; max number positional operands
+; dw 0 ; offset into control block for positionals
+
+ db 3 ; APPEND has two switches /E, /X, /PATH
+ dw offset e_switch ; control block for /E switch
+ dw offset x_switch ; control block for /X switch
+ dw offset path_switch ; control block for /PATH switch
+
+ db 0 ; max number of keywords
+ dw 0 ; offset of keyword control block
+
+;------------------------
+; extended parameter block for 2nd, 3rd, ... APPEND invocations
+
+px_block2:
+ db 0 ; min number positional operands
+ db 1 ; max number positional operands
+ dw offset dirs_control ; pointer to dirs control block
+
+; db 2 ; APPEND after first load has two switches /X, /PATH
+ db 3 ; APPEND has two switches /E, /X, /PATH
+ dw offset e_switch ; control block for /E switch
+ dw offset x_switch ; control block for /X switch
+ dw offset path_switch ; control block for /PATH switch
+
+ db 0 ; max number of keywords
+
+;------------------------
+dirs_control:
+ dw $P_Simple_S+$P_Optional ; complex, optional string
+ dw $P_CAP_File ; cap by file table
+ dw offset dirs_result ; dirs result buffer
+ dw offset dirs_values ; pointer to null value list
+ db 0 ; no synonyms
+
+dirs_values:
+ db 0 ; null value list for dirs
+
+
+
+;------------------------
+x_switch:
+ dw $P_Simple_s+$P_Optional ; /X, /X:ON, /X:OFF simple, optional string
+ dw $P_CAP_Char ; cap by char table
+ dw offset x_result ; pointer to result block
+ dw offset x_values ; pointer to values block
+ db 1 ; number of switches and synonyms
+ db "/X",0 ; only /X is valid
+
+x_values:
+ db 3 ; string values
+ db 0 ; zeroes here for ranges and
+ db 0 ; values
+ db 2 ; 2 possible string values
+ db 0 ; /X:OFF = 0
+ dw offset off_string ; pointer to "OFF"
+ db 1 ; /X:ON = 1
+ dw offset on_string
+;------------------------
+
+e_switch:
+ dw 0 ; /E
+ dw $P_CAP_Char ; cap by char table
+ dw offset e_result ; pointer to result block
+ dw offset e_values ; pointer to values block, none
+ db 1 ; number of switches and synonyms
+ db "/E",0 ; only /E is valid
+
+e_values:
+ db 0 ; null value list for /E
+
+
+;------------------------
+path_switch:
+ dw $P_Simple_s ; /PATH:ON, /PATH:OFF simple string
+ dw $P_CAP_Char ; cap by char table
+ dw offset path_result ; pointer to result block
+ dw offset path_values ; pointer to values block
+ db 1 ; number of switches and synonyms
+ db "/PATH",0 ; only /PATH is valid
+
+
+path_values:
+ db 3 ; string values
+ db 0 ; zeroes here for ranges and
+ db 0 ; values
+ db 2 ; 2 possible string values
+ db 0 ; /PATH:OFF = 0
+ dw offset off_string ; pointer to "OFF"
+ db 1 ; /PATH:ON = 1
+ dw offset on_string
+
+
+;------------------------
+
+off_string:
+ db "OFF",0 ; off string
+
+on_string:
+ db "ON",0 ; on string
+
+
+;------------------------
+
+x_result $P_Result_Blk <> ; /X result block
+e_result $P_Result_Blk <> ; /E result block
+path_result $P_Result_Blk <> ; /PATH result block
+dirs_result $P_Result_Blk <> ; dirs result block
+
+
+
\ No newline at end of file
diff --git a/v4.0/src/CMD/APPEND/MAKEFILE b/v4.0/src/CMD/APPEND/MAKEFILE
new file mode 100644
index 0000000..73f7dd7
--- /dev/null
+++ b/v4.0/src/CMD/APPEND/MAKEFILE
@@ -0,0 +1,20 @@
+#************************** makefile for cmd\append ***************************
+
+msg =..\..\messages
+dos =..\..\dos
+inc =..\..\inc
+hinc =..\..\h
+
+#
+####################### dependencies begin here. #########################
+#
+
+all: append.exe
+
+append.ctl: append.skl $(msg)\$(COUNTRY).msg
+
+append.obj: append.asm appendp.inc $(inc)\parse.asm append.ctl
+
+append.exe: append.obj
+ link append;
+
diff --git a/v4.0/src/CMD/APPEND/SYSMAC.LIB b/v4.0/src/CMD/APPEND/SYSMAC.LIB
new file mode 100644
index 0000000..7a38a59
--- /dev/null
+++ b/v4.0/src/CMD/APPEND/SYSMAC.LIB
@@ -0,0 +1,361 @@
+;
+; SYSTEM MACROS
+;
+; DISPLAY TEXT ON SCREEN
+;
+DISP MACRO TEXT,SEGM
+ IFNB
+ IFDIF ,
+ PUSH DS
+ MOV AX,SEGM
+ MOV DS,AX
+ ENDIF
+ ENDIF
+ IFNB
+ LEA DX,TEXT
+ ENDIF
+ DOS DSTR
+ IFNB
+ IFDIF ,
+ POP DS
+ ENDIF
+ ENDIF
+ ENDM
+;
+DMSG MACRO MSG
+ IFNB
+ LEA DX,MSG
+ ENDIF
+ DISP
+ ENDM
+;
+DCHAR MACRO CHAR
+ PUSH DX
+ IFNB
+ MOV DL,CHAR ; SET CHARACTER
+ ELSE
+ MOV DL,AL
+ ENDIF
+ DOS DO
+ POP DX
+ ENDM
+;
+; CLEAR SCREEN
+;
+CLEAR MACRO
+ MOV CX,00H*256+00H ; ROW=00, COL=00
+ MOV DX,24H*256+79H ; ROW=24, COL=79
+ MOV BH,07H ; NORMAL ATTRIBUTE
+ MOV AX,06H*256+00H ; CLEAR WHOLE SCREEN
+ INT 10H
+ ENDM
+;
+POS MACRO ROW,COL,PAGE
+ IFNB
+ MOV DX,ROW*256+COL ; SET ROW AND COLUMN
+ ENDIF
+ IFNB
+ MOV BH,PAGE ; SET PAGE
+ ELSE
+ MOV BH,0
+ ENDIF
+ MOV AH,02H ; POSTIION CURSOR
+ INT 10H
+ ENDM
+;
+DEFMSG MACRO ID,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10
+ IFNB
+ID LABEL BYTE ; DEFINE ESSAGE
+ ENDIF
+ IFNB
+ DB T1
+ ENDIF
+ IFNB
+ DB T2
+ ENDIF
+ IFNB
+ DB T3
+ ENDIF
+ IFNB
+ DB T4
+ ENDIF
+ IFNB
+ DB T5
+ ENDIF
+ IFNB
+ DB T6
+ ENDIF
+ IFNB
+ DB T7
+ ENDIF
+ IFNB
+ DB T8
+ ENDIF
+ IFNB
+ DB T9
+ ENDIF
+ IFNB
+ DB T10
+ ENDIF
+ DB '$'
+ ENDM
+;
+MOVE MACRO TO,LEN,FROM
+ IFNB
+ LEA DI,TO ; SET DESTINATION
+ ENDIF
+ IFNB
+ MOV CX,LEN ; SET LENGTH
+ ENDIF
+ IFNB
+ LEA SI,FROM ; SET SOURCE
+ ENDIF
+ REP MOVS BYTE PTR[DI],BYTE PTR[SI]
+ ENDM
+MOVEZ MACRO TO,FROM
+ IFNB
+ LEA DI,TO ; SET DESTINATION
+ ENDIF
+ IFNB
+ LEA SI,FROM ; SET SOURCE
+ ENDIF
+ CALL MOVZ$
+ ENDM
+;
+SCAN MACRO TO,LEN,VALUE,TYPE
+ IFNB
+ LEA DI,TO ; SET DESTINATION
+ ENDIF
+ IFNB
+ MOV CX,LEN ; SET LENGTH
+ ENDIF
+ IFNB
+ MOV AL,VALUE ; SET SOURCE
+ ENDIF
+ IFB
+ REPZ SCASB
+ ENDIF
+ IFIDN ,
+ REPZ SCASB
+ ENDIF
+ IFIDN ,
+ REPZ SCASB
+ ENDIF
+ IFIDN ,
+ REPNZ SCASB
+ ENDIF
+ IFIDN ,
+ REPNZ SCASB
+ ENDIF
+ ENDM
+;
+FILL MACRO TO,LEN,VALUE
+ PUSH DI
+ PUSH CX
+ IFNB
+ LEA DI,TO ; SET DESTINATION
+ ENDIF
+ IFNB
+ MOV CX,LEN ; SET LENGTH
+ ENDIF
+ IFNB
+ MOV AL,VALUE ; SET SOURCE
+ ENDIF
+ REP STOS BYTE PTR[DI]
+ POP CX
+ POP DI
+ ENDM
+;
+COMP MACRO TO,LEN,FROM
+ IFNB
+ LEA DI,TO ; SET DESTINATION
+ ENDIF
+ IFNB
+ MOV CX,LEN ; SET LENGTH
+ ENDIF
+ IFNB
+ LEA SI,FROM ; SET SOURCE
+ ENDIF
+ REPE CMPS BYTE PTR[DI],BYTE PTR[SI]
+ ENDM
+COMPZ MACRO TO,FROM
+ IFNB
+ LEA DI,TO ; SET DESTINATION
+ ENDIF
+ IFNB