URI: 
                  Updated CRTDRVR Library: Bug Fix and Windows 95 Update
                         Author: Geoff Chappell, Software Analyst
       
       This page was created on 20th July 1997 and was last modified on 16th June
       2008.
       
       The original code in CRTDRVR.ASM, which was written in 1992, was revised in
       June 1996 to fix a bug (that had gone unnoticed for an embarrassingly long
       time) and to accommodate some changes that Windows 95 makes to DOS's startup.
       These revisions are presented together in the new source code but described
       here separately.
       
       === Bug Fix ==================================================================
       
       The driver library has a surprisingly serious bug that is activated when the
       library is used together with the scheme that Chapter Six of DOS Internals
       presents for resident programming. In that scheme, segments are rearranged
       from the DOSSEG order of code then data (essential to the standard run-time
       library of Microsoft C) to the preferred order of resident then non-resident.
       When devising the one programming scheme, I failed to allow for the
       rearrangement devised in the other. Put the two together and the bug corrupts
       one word at an essentially random address just as the driver is about to
       return to SYSINIT after initialising. This bug is fixed by adding two lines to
       the CRTDRVR.ASM source code.
       
       === Windows 95 Update ========================================================
       
       The release of Windows 95 requires one change to the techniques used in
       CRTDRVR and makes another change convenient. The change that must be made is
       due to something that may reasonably be deemed a bug in the DOS 7 kernel. The
       other change is possible only because the DOS 7 kernel fixes something that
       may reasonably be deemed a bug in earlier versions of the kernel.
       
         Resident Termination Must Be Fixed...
       
       New code in the DOS 7 kernel (previously MSDOS.SYS but now bound into IO.SYS)
       makes int 21h function 31h unsafe to use during device driver initialisation.
       This affects any device driver produced by linking the CRTDRVR library with
       code for a DOS program that terminates and stays resident.
       
       Certain VxDs in Windows 95 need to know whether any DOS device drivers and
       programs have used resources of interest. For instance, have any hooked int
       13h or a hardware interrupt? The general scheme for supporting this from the
       DOS side is that some DOS component takes a snapshot of the system state each
       time a DOS device driver gets loaded or a DOS program gets run. When the
       driver or program is done, the system state is compared with the snapshot to
       discover any changes. Information about the driver or program may then be
       recorded for VxDs to study later.
       
       When SYSINIT loads device drivers, only it can easily know when the device
       driver returns from its initialisation, and so SYSINIT has the job of watching
       for drivers that change the system state. The information that SYSINIT records
       about the drivers it loads is entered into structures that are documented in
       the RMD.H file supplied with the Windows 95 DDK and are retrievable at
       run-time via int 2Fh function 1690h (which is documented as W386_Return_RMD).
       
       When SYSINIT is finished loading device drivers, the DOS kernel picks up the
       job of watching for resource use by DOS programs. SYSINIT finds some memory
       for the DOS kernel to use. Some of this memory is used and reused for the
       snapshots of system features that DOS will take before each program's
       execution. Some of the memory is to serve as a permanent record that may be
       examined by VxDs. The layout allows for DOS to note the resource usage of as
       many as 20 TSRs that run outside of Windows. Interestingly, VxDs do not have
       access to this record via the int 21h function 1690h interface. The IOS VxD
       finds the record by knowing that the address is kept as the dword at offset
       1328h in the DOS kernel's data segment. The layout and location of this TSR
       record appear to be undocumented.
       
       Of particular interest to the CRTDRVR library is the method by which DOS
       takes its snapshots of resources used by TSRs. Two routines have been added to
       the DOS kernel. One takes the snapshot before a program runs. It is called
       every time that int 21h function 4Bh is used to start a new process, but only
       provided Windows Enhanced Mode is not running and only provided SYSINIT has
       given DOS the memory in which to record the snapshot (that is, provided that
       the dword at offset 1328h is not null). The other new routine acts when a
       program finishes. It compares with the snapshot that was taken before the
       program runs, and it records what has changed. It is called whenever a program
       terminates via int 21h function 31h and Windows Enhanced Mode is not running.
       
       The problem for the CRTDRVR library is that whereas the first of those
       routines takes its snapshot only if SYSINIT has provided the necessary memory,
       the second routine simply assumes that the memory is there. Specifically, it
       does not check that the dword at offset 1328h is not null. If int 21h function
       31h is used while SYSINIT is still in the business of loading device drivers,
       then the DOS kernel's pointer at offset 1328h will be null and the DOS kernel
       will misbehave, possibly even by trampling over the interrupt vector table.
       
       Note the inconsistency. One routine guards against a null pointer and the
       other doesn't - even though the routines are adjacent in the kernel code. The
       understandable difference from Microsoft's perspective is that int 21h
       function 4Bh is needed while SYSINIT loads device drivers and must guard
       against a null pointer, but int 21h function 31h is not anticipated to be used
       this early and therefore need not guard against a null pointer.
       
       The updated CRTDRVR code works around this problem by providing the DOS
       kernel with the necessary memory temporarily. The new code is enabled only
       when running under DOS version 7.0 or higher.
       
       A first update in 1996 was either too optimistic (thinking that future
       versions of the DOS kernel would guard against the null pointer) or too
       pessimistic (thinking that there would be no future version), and tested for
       DOS 7.0 exactly. I thank Ivan P. de Arruda Campos for bringing to my attention
       a problem that had this test as its cause.
       
         ...But an FCB-SFT Is No Longer Needed
       
       For DOS versions before Windows 95, CRTDRVR already has to work around a
       similar problem in the DOS kernel code, namely that when terminating a
       process, the DOS kernel simply assumes the existence of at least one FCB-SFT.
       Since the FCB-SFTs are not built until SYSINIT finishes loading device
       drivers, all functions for terminating DOS processes are unsafe during device
       driver initialisation. To get around this, the CRTDRVR code presented in DOS
       Internals provides the DOS kernel with a temporary FCB-SFT.
       
       Under Windows 95, Microsoft needs to execute an ordinary program during DOS's
       startup, specifically a program bound into the IO.SYS file and used for
       reading the system registry. This ordinary program will terminate in the
       ordinary way. Since Microsoft now needs to run a program during DOS's startup
       and have the program terminate safely, it is no surprise to find that when the
       DOS kernel for Windows 95 terminates a process, it now checks whether SYSINIT
       has yet provided a block of FCB-SFTs. Thus, the FCB-SFT workaround need not be
       activated when the CRTDRVR code executes under DOS 7 (or higher).
       
       === Download =================================================================
       
       The revisions described above mean that three files must be replaced in the
       DEVTOOLS\DRIVER\CRTDRVR directory of the DOS Internals disk. These files are
       the CRTDRVR assembly-language source, the object code and the library. The
       CRTDRVR.LIB file should also be copied to the LIB directory. For distribution,
       all three files are compressed into one: download the CRTDRVR Bug Fix and
       Windows 95 Update.
       
   BIN crtdrvr-update.zip