1 TITLE EXTENDED MEMORY RAMDRIVE
6 ; Will use IBM extended memory on PC-AT or
7 ; use Above Board on PC, XT, or AT or
8 ; use main memory on PC, XT, or AT
11 ; device = ramdrive.sys [bbbb] [ssss] [dddd] [/E | /A]
13 ; bbbb First numeric argument, if present, is disk size
14 ; in K bytes. Default value is 64. Min is 16. Max
17 ; ssss Second numeric argument, if present, is sector size
18 ; in bytes. Default value is 512. Allowed values are
19 ; 128, 256, 512, 1024.
20 ; NOTE: In the case of IBM PC DOS the MAX value is 512.
21 ; If 1024 is specified the device will not be installed.
22 ; This "error" is detected by DOS and is not due to
23 ; the code in RAMDrive.
24 ; The 1024 byte size is included for those MS-DOS systems
25 ; where it might be allowed.
27 ; dddd Third numeric argument, if present, is the number of
28 ; root directory entries. Default is 64. Min is 2
29 ; max is 1024. The value is rounded up to the nearest
30 ; sector size boundary.
31 ; NOTE: In the event that there is not enough memory
32 ; to create the RAMDrive volume, RAMDrive will try to make
33 ; a DOS volume with 16 directory entries. This may
34 ; result in a volume with a different number of directory
35 ; entries than the dddd parameter specifies.
37 ; /E Specifies that PC AT Extended Memory is to be used.
38 ; It is an error if /E is specified on a machine other
40 ; NOTE: Information on RAMDrive drives in PC AT extended memory
41 ; will be lost at system re-boot (warm or cold). This is
42 ; due to the fact that the IBM PC AT ROM bootstrap code
43 ; zeroes all of memory.
44 ; NOTE: There is 1k of RAMDrive overhead. That is to say,
45 ; if there are 512k bytes of extended memory, there
46 ; will be 511k bytes available for assignment to RAMDrive
47 ; drives. This 1k overhead is fixed and does not depend
48 ; on the number of RAMDrive drives installed.
50 ; /A Specifies that Above Board memory is to be used. It
51 ; is an error if the above board device driver is not
53 ; NOTE: Information on RAMDrive drives in Above Board memory
54 ; will be lost at system re-boot (warm or cold). This is
55 ; due to the fact that the EMM device driver performs a
56 ; destructive test when it is installed which zeros all
57 ; of the Above Board memory.
59 ; Neither /A or /E Specifies drive is to be set up below the
60 ; 640K boundary in main memory.
61 ; The RAMDRIVE.SYS program looks for memory to assign to the RAMDrive
62 ; drives by looking for functioning system RAM between the
63 ; "end of memory" as determined by the INT 12H ROM BIOS
64 ; function, and the start of the video RAM (0A000:0H).
65 ; If RAM is found by the above scan, it is assigned to
66 ; RAMDrive and managed in the same way as extended memory
67 ; is when the /E switch is used. As with /E there is
68 ; 1k of RAMDrive overhead. That is to say, if there are 256k
69 ; bytes of memory above the INT 12 memory size, there
70 ; will be 255k bytes available for assignment to RAMDrive
71 ; drives. This 1k overhead is fixed and does not depend
72 ; on the number of RAMDrive drives installed.
73 ; Information on such RAMDrive drives will NOT be lost on
74 ; a "warm boot" (INT 19H or Ctrl-Alt-DEL).
75 ; If RAM is NOT found by the above scan, RAMDrive will attempt
76 ; to allocate memory for the device AS PART OF THE DEVICE.
77 ; In other words the device starts immediately after the
78 ; RAMDrive resident code.
79 ; Information on such RAMDrive drives WILL BE lost on
80 ; a "warm boot" (INT 19H or Ctrl-Alt-DEL).
84 ; MODIFICATION HISTORY
86 ; 1.00 5/30/85 ARR Initial version.
88 ; 1.01 6/03/85 ARR Added CSIZE home code in INIDRV. Does a better
89 ; job of computing good CSIZE value.
91 ; 1.10 6/05/85 ARR Changed name of program from VDISK to RAMDRIVE
93 ; 1.11 6/06/85 ARR Changed BAD_AT message
95 ; 1.12 6/06/85 ARR Fixed bug in /A BLKMOV code. Was forgetting
96 ; to save and restore page mapping context
98 ; 1.13 6/14/85 ARR Was using 32 bit shifts to do div/mul by
99 ; powers of two. As it turns out, using the
100 ; DIV or MUL instruction is faster. This is
101 ; so even for small numbers like 16. This is
102 ; due to the fact that the LOOP involved in
103 ; doing a 32 bit shift is expensive.
105 ; 1.14 6/14/85 ARR dddd param minimum changed from 4 to 2
106 ; to be IBM compatible. Code added to round
107 ; up to sector size boundaries.
109 ; 1.15 6/24/85 ARR Assorted clean up, mostly in Above Board
112 ; 1.16 7/09/85 ARR Align code more closely to the G.L.
115 ; Changed ITOA routine. Smaller and will print any
118 ; DISK_ABORT would run through EMM_CTRL reset code
119 ; on a RESMEM_SPECIAL driver. Added code
120 ; to skip if this type of driver.
122 ; Added check in CHECK_DOS_VOL in event valid BPB
123 ; is found to make sure SSIZE and DIRNUM values
124 ; match. If you edit DEVICE = to change these
125 ; values on an existing drive and re-boot
126 ; RAMDrive would ignore you and suck up old
129 ; 11/12/85 ARR DEBUG EQU added and some RESMEM debug code
130 ; stuck in to discover that the HP Vectra is
131 ; not as AT compatible as HP thinks.
133 ; 02/11/86 ARR Message area identified by "TRANSLATION"
134 ; and translation notes added to several
137 ; 04/03/86 ARR Changed use of SIDT to set GDT descriptor
138 ; in /E init code to SGDT. Previous masm wouldn't
139 ; assemble SGDT, new one works OK.
141 ; 1.17 5/26/86 ARR New version for "above" insignificgant changes. And
142 ; fixed major oops in /e RESET_SYSTEM code which would
143 ; hang the system if an interrupt occured at the wrong
146 ; 1.19 3/4/87 SP Fixed CSIZ homing oscillation bug. Shifted Ramdriv
147 ; configuration display code before relocation code
148 ; to facilitate creation of message module. Shifted
149 ; translatable messages to message module.
151 ; 2.00 8/23/87 sp 386 support ( both prot mode transfer and int15 )
153 ; new int15 allocation
154 ; new above_blkmov routine (to handle overlapping
155 ; transfers in above board memory
157 ; removed int 9 trapping
158 ; reset code different for extended memory
160 ; 2.01 9/28/87 sp Fixed bug in parsing for /u option
162 ; 2.02 3/02/88 sp Extended PS2 model 80 recognition to more than
164 ; 2.03 5/13/88 SP extended version check to include dos 4.00
166 ; 2.04 5/23/88 SP reworked messages to mention expanded memory
168 ; 2.10 6/13/88 CHIPA Merged in HP Vectra stuff
169 ; 11/20/87 RCP Fixed a20 enabling/disabling problems on
172 ; 2.12 7/26/88 SP Ramdrives installed between int12 and A000 are
173 ; no longer attempted.
180 .286p
; Use some 286 instructions in /E code
186 %
out DEBUG VERSION!!!!!!
197 ; The RAMDrive device driver has 4 basic configurations.
199 ; TYPE 1 - /E configuration using PC-AT extended memory and the LOADALL
202 ; TYPE 2 - /A configuration using Above Board memory and EMM device
205 ; TYPE 3 - Neither /A or /E (RESMEM) configuration using main memory
206 ; and normal 8086 addressing, RAMDrive memory is located
207 ; somewhere AFTER the "end of memory" as indicated by the
208 ; INT 12H memory size.
210 ; TYPE 4 - RESMEM configuration as TYPE 3 EXCEPT that the RAMDrive
211 ; memory is part of the RAMDrive device driver.
213 ; The TYPE 2 driver uses the Above Board EMM device driver via INT 67H
214 ; to control access to, and to access the available memory.
216 ; The TYPE 4 driver needs no external help to control access to the available
217 ; memory since the RAMDrive memory is part of the device driver and
218 ; immediately follows the RAMDrive code in memory.
220 ; The TYPE 1 and TYPE 3 configurations use the EMM control sector to
221 ; control access to the available memory
231 BREAK <I
/O Packet offset declarations
>
234 ; Define I/O packet offsets for useful values.
237 ; MS-DOS Technical Reference manual section on Installable Device Drivers
240 S_OLIVETTI EQU
01H ; Olivetti 6300 PLUS machine
241 S_VECTRA EQU
02H ; Vectra PC machine
243 ; READ/WRITE PACKET OFFSETS
244 RW_COUNT EQU
WORD PTR (SIZE SRHEAD
) + 5
245 RW_TRANS EQU
DWORD PTR (SIZE SRHEAD
) + 1
246 RW_START EQU
WORD PTR (SIZE SRHEAD
) + 7
248 ; MEDIA CHECK PACKET OFFSETS
249 MCH_RETVAL EQU
BYTE PTR (SIZE SRHEAD
) + 1
250 MCH_MEDIA EQU
BYTE PTR (SIZE SRHEAD
) + 0
252 ; BUILD BPB PACKET OFFSETS
253 BPB_BUFFER EQU
DWORD PTR (SIZE SRHEAD
) + 1
254 BPB_MEDIA EQU
BYTE PTR (SIZE SRHEAD
) + 0
255 BPB_BPB EQU
DWORD PTR (SIZE SRHEAD
) + 5
257 ; INIT PACKET OFFSETS
258 INIT_NUM EQU
BYTE PTR (SIZE SRHEAD
) + 0
259 INIT_BREAK EQU
DWORD PTR (SIZE SRHEAD
) + 1
260 INIT_BPB EQU
DWORD PTR (SIZE SRHEAD
) + 5
261 INIT_DOSDEV EQU
BYTE PTR (SIZE SRHEAD
) + 9
263 BREAK <some
segment definitions
>
265 ;; In order to address memory above 1 MB on the AT&T 6300 PLUS, it is
266 ;; necessary to use the special OS-MERGE hardware to activate lines
267 ;; A20 to A23. However, these lines can be disabled only by resetting
268 ;; the processor. The return address offset and segment can be found
269 ;; at 40:a2, noted here as RealLoc1.
271 BiosSeg
segment at 40h
;; Used to locate 6300 PLUS reset address
276 R_Mode_IDT
segment at 0h
280 BREAK <Device header
>
283 ASSUME
CS:RAMCODE
,DS:NOTHING
,ES:NOTHING
,SS:NOTHING
287 ; RAMDRIVE DEVICE HEADER
289 ; COMMON TO TYPE 1, 2, 3, 4 drivers
292 ; MS-DOS Technical Reference manual section on
293 ; Installable Device Drivers
304 BREAK <Command dispatch table
>
308 ; This is the device driver command dispatch table.
310 ; The first byte indicates the size of the table and therefore defines
311 ; which device function codes are valid.
313 ; The entries in the table are NEAR word addresses of the appropriate
314 ; device routine. Thus the address of the routine to handle device function
316 ; WORD at ((RAMTBL + 1) + (2 * 3))
318 ; COMMON TO TYPE 1, 2, 3, 4 drivers
323 DB 15 ; Max allowed command code
342 BREAK <BPB
and boot sector for installed device
>
344 ;** RAMDRIVE BIOS PARAMETER BLOCK AND BOGUS BOOT SECTOR
346 ; This region is a valid DOS 2.X 3.X "boot sector" which contains
347 ; the BPB. This is used for signiture verification of a valid
348 ; RAMDrive as well as for storage of the relevant BPB parameters.
350 ; The BOOT_START code is a very simple stub which does nothing
351 ; except go into an infinite loop. THIS "CODE" SHOULD NEVER
352 ; BE EXECUTED BY ANYONE.
354 ; COMMON TO TYPE 1, 2, 3, 4 drivers
358 BOOT_SECTOR
LABEL BYTE
363 SSIZE
DW 512 ; Physical sector size in bytes
364 CSIZE
DB 0 ; Sectors/allocation unit
365 RESSEC
DW 1 ; Reserved sectors for DOS
366 FATNUM
DB 1 ; No. allocation tables
367 DIRNUM
DW 64 ; Number directory entries
368 SECLIM
DW 0 ; Number sectors
369 DB 0F8H ; Media descriptor
370 FATSEC
DW 1 ; Number of FAT sectors
371 DW 1 ; Number of sectors per track
372 DW 1 ; Number of heads
373 DW 0 ; Number of hidden sectors
375 SEC_SHFT
DB 8 ; Shifting number of
376 ; sectors LEFT by this
377 ; many bits yields #words
378 ; in that many sectors.
388 DB (128 - (OFFSET BOOT_SIG
- OFFSET BOOT_SECTOR
)) DUP ("A")
391 ; The following label is used to determine the size of the boot record
392 ; OFFSET BOOT_END - OFFSET BOOT_SECTOR
396 BREAK <Common Device
code>
398 ; RAMDRIVE DEVICE ENTRY POINTS - STRATEGY, RAM$IN
400 ; This code is standard DOS device driver function dispatch
401 ; code. STRATEGY is the device driver strategy routine, RAM$IN
402 ; is the driver interrupt routine.
404 ; RAM$IN uses RAMTBL to dispatch to the appropriate handler
405 ; for each device function. It also does standard packet
409 ; MS-DOS Technical Reference manual section on
410 ; Installable Device Drivers
413 ASSUME
CS:RAMCODE
,DS:NOTHING
,ES:NOTHING
,SS:NOTHING
415 PTRSAV
DD 0 ; Storage location for packet addr
417 ;** STRATEGY - Device strategy routine
419 ; Standard DOS 2.X 3.X device driver strategy routine. All it does
420 ; is save the packet address in PTRSAV.
422 ; ENTRY ES:BX -> Device packet
426 ; COMMON TO TYPE 1, 2, 3, 4 drivers
433 MOV WORD PTR [PTRSAV
],BX ; Save packet addr
434 MOV WORD PTR [PTRSAV
+2],ES
439 ;** RAM$IN - Device interrupt routine
441 ; Standard DOS 2.X 3.X device driver interrupt routine.
444 ; ENTRY PTRSAV has packet address saved by previous STRATEGY call.
445 ; EXIT Dispatch to appropriate function handler
446 ; CX = Packet RW_COUNT
447 ; DX = Packet RW_START
448 ; ES:DI = Packet RW_TRANS
450 ; STACK has saved values of all regs but FLAGS
451 ; All function handlers must return through one of
452 ; the standard exit points
455 ; COMMON TO TYPE 1, 2, 3, 4 drivers
470 LDS BX,[PTRSAV
] ;GET POINTER TO I/O PACKET
472 ; Set up registers for READ or WRITE since this is the most common case
474 MOV CX,DS:[BX.RW_COUNT
] ;CX = COUNT
475 MOV DX,DS:[BX.RW_START
] ;DX = START SECTOR
476 MOV AL,DS:[BX.REQFUNC
] ; Command code
477 MOV AH,BYTE PTR [RAMTBL
] ; Valid range
479 JA CMDERR
; Out of range command code
480 MOV SI,OFFSET RAMTBL
+ 1 ; Table of routines
481 CBW ; Make command code a word
482 ADD SI,AX ; Add it twice since one word in
483 ADD SI,AX ; table per command.
485 LES DI,DS:[BX.RW_TRANS
] ; ES:DI transfer address
492 JMP WORD PTR [SI] ; GO DO COMMAND
494 ;** EXIT - ALL ROUTINES RETURN THROUGH ONE OF THESE PATHS
496 ; Exit code entry points:
499 ; MS-DOS Technical Reference manual section on
500 ; Installable Device Drivers
502 ; GENERAL ENTRY for all entry points
503 ; All packet values appropriate to the specific device function
504 ; filled in except for the status word in the static request
507 ; CMDERR - Used when an invalid device command is detected
509 ; ENTRY Stack has frame set up by RAM$IN
510 ; EXIT Standard Device driver with error 3
513 ; ERR$CNT - Used when READ or WRITE wants to return with error code.
514 ; The packet RW_COUNT field is zeroed
516 ; ENTRY AL is error code for low byte of packet status word
517 ; Stack has frame set up by RAM$IN
518 ; EXIT Standard Device driver with error AL
521 ; ERR$EXIT - Used when a function other that READ or WRITE wants to
524 ; ENTRY AL is error code for low byte of packet status word
525 ; Stack has frame set up by RAM$IN
526 ; EXIT Standard Device driver with error AL
529 ; DEVEXIT - Used when a function wants to return with no error
531 ; ENTRY AL is value for low byte of packet status word
532 ; NOTE: Typically there is no meaningful value
533 ; in the AL register when EXITing through here.
534 ; This is OK as the low 8 bits of the status word
535 ; have no meaning unless an error occured.
536 ; Stack has frame set up by RAM$IN
537 ; EXIT Standard Device driver with no error
540 ; ERR1 - Used when a function wants to return with a value
541 ; for the whole status word
543 ; ENTRY AX is value for packet status word
544 ; Stack has frame set up by RAM$IN
545 ; EXIT Standard Device driver with or without error
548 ; COMMON TO TYPE 1, 2, 3, 4 drivers
552 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
555 MOV AL,3 ;UNKNOWN COMMAND ERROR
560 MOV [BX.RW_COUNT
],0 ; NO sectors transferred
561 ERR$EXIT
: ; Error in AL
562 MOV AH,(STERR
+ STDON
) SHR 8 ;MARK ERROR RETURN
571 MOV [BX.REQSTAT
],AX ; Set return status
582 RET ;RESTORE REGS AND RETURN
586 ;** MEDIA$CHK - Device Driver Media check routine
588 ; RAMDRIVE Media check routine. ALWAYS returns media not changed
591 ; MS-DOS Technical Reference manual section on
592 ; Installable Device Drivers
595 ; EXIT through DEVEXIT
598 ; COMMON TO TYPE 1, 2, 3, 4 drivers
602 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
605 MOV [BX.MCH_RETVAL
],1 ; ALWAYS NOT CHANGED
608 ;** GET$BPB - Device Driver Build BPB routine
610 ; RAMDRIVE Build BPB routine. Returns pointer to BPB at RDRIVEBPB
613 ; MS-DOS Technical Reference manual section on
614 ; Installable Device Drivers
617 ; EXIT through DEVEXIT
620 ; COMMON TO TYPE 1, 2, 3, 4 drivers
624 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
627 MOV WORD PTR [BX.BPB_BPB
],OFFSET RDRIVEBPB
628 MOV WORD PTR [BX.BPB_BPB
+ 2],CS
631 ;** RAM$REM - Device Driver Removable Media routine
633 ; RAMDRIVE Removable Media routine. ALWAYS returns media not removable
634 ; NOTE: This routine is never called if running on DOS 2.X
637 ; MS-DOS Technical Reference manual section on
638 ; Installable Device Drivers
644 ; COMMON TO TYPE 1, 2, 3, 4 drivers
648 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
649 MOV AX,STBUI
+ STDON
; Media NOT removable
652 ;** RAM$READ - Device Driver READ routine
654 ; RAMDRIVE READ routine. Perform device READ by calling MEMIO
657 ; MS-DOS Technical Reference manual section on
658 ; Installable Device Drivers
660 ; DO_OP entry point used by RAM$WRITE
663 ; ES:DI is transfer address
664 ; CX is sector transfer count
665 ; DX is start sector number
666 ; EXIT through DEVEXIT or ERR$CNT
669 ; COMMON TO TYPE 1, 2, 3, 4 drivers
673 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
680 T_ERR: ; AL has error number
683 ;** RAM$WRITE - Device Driver WRITE routine
685 ; RAMDRIVE WRITE routine. Perform device WRITE by calling MEMIO
688 ; MS-DOS Technical Reference manual section on
689 ; Installable Device Drivers
692 ; ES:DI is transfer address
693 ; CX is sector transfer count
694 ; DX is start sector number
695 ; EXIT Jump to DO_OP to call MEMIO with BH = 1 (WRITE)
698 ; COMMON TO TYPE 1, 2, 3, 4 drivers
702 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
706 ;** MEMIO - Perform READ or WRITE to RAMDrive
708 ; This routine performs common pre-amble code for the BLKMOV
709 ; routine which is the one which does the real work. It checks
710 ; the I/O parameters for validity and sets up the inputs to
711 ; BLKMOV. What it does is convert the sector count in CX to
712 ; the number of words in that many sectors or 8000H which ever
713 ; is less. It also converts the start sector number in DX into
714 ; a 32 bit byte offset equal to that many sectors.
716 ; NOTE that we convert the number of sectors to transfer
717 ; to a number of words to transfer.
718 ; Sector size is always a power of two, therefore a multiple
719 ; of two so there are no "half word" problems.
720 ; DOS NEVER asks for a transfer larger than 64K bytes except
721 ; in one case where we can ignore the extra anyway.
724 ; ES:DI is packet transfer address.
725 ; CX is number of sectors to transfer.
726 ; DX is starting sector number
727 ; BH is 1 for WRITE, 0 for READ
731 ; Error on operation, AL is error number
734 ; ES:DI is packet transfer address.
735 ; CX is number of words to transfer.
736 ; DX:AX is 32 bit start byte offset (0 = sector 0 of RAMDrive drive)
737 ; BH is 1 for WRITE, 0 for READ
741 ; COMMON TO TYPE 1, 2, 3, 4 drivers
745 MOV AL,8 ; Sector not found error
750 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
751 CMP DX,[SECLIM
] ; Check for valid I/O
752 JAE SEC_NOT_FOUND
; Start is beyond end
756 JA SEC_NOT_FOUND
; End is beyond end
758 ; Convert sector count to word count
762 SHL AX,CL ; AX is # words to move
763 JNC CNT_SET
; Overflow???
764 MOV AX,8000H
; Limit to 64K bytes
768 ; Now compute start offset of I/O
771 MUL [SSIZE
] ; DX:AX is byte offset of start
772 JMP BLKMOV
; Perform I/O
774 BREAK <Work Area for Ramdrive
>
776 S5_FLAG
DB 0 ;; S_OLIVETTI means 6300 PLUS machine
777 ;; S_VECTRA means Vectra machine
782 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
783 ; Unfortunately the code in ramdrive is very machine dependent
784 ; necessitating the use of a system flag to store the machine
785 ; configuration. The system flag is initialised during init time
786 ; and used when the caching services are requested. One bit which
787 ; is set and tested during caching is the state of the a20 line
788 ; when the cache code is entered. This is used because there are
789 ; applications which enable the a20 line and leave it enabled
790 ; throughout the duration of execution. Since ramdrive is a device
791 ; driver it shouldn't change the state of the environment.
793 ; The system flag bit assignments are:
795 ; -------------------------------------------------
796 ; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
797 ; -------------------------------------------------
798 ; |-----| | | | | | |
799 ; | | | | | | -----286 (and AT)
800 ; | | | | | -----------386 (later than B0)
801 ; not | | | -----------------PS/2 machine
802 ; used | | -----------------------Olivetti (not used)
803 ; | -----------------------------A20 state (enabled ?)
804 ; -----------------------------------DOS 3.x >= 3.3
806 ; The Olivetti guys have defined a flag of their own. This should be removed
807 ; and the bit assigned out here for them should be used.
811 ; equates used for the system flag
819 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
820 ; A20 address line state determination addresses
830 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
836 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
840 cs_des desc
<0FFFFh,0,0,09Fh,0,0>
841 ss_des desc
<0FFFFh,0,0,093h,0,0>
842 ds_des desc
<0FFFFh,0,0,093h,0,0>
843 es_des desc
<0FFFFh,0,0,093h,0,0>
846 emm_gdt gdt_descriptor
<end_gdt
-start_gdt
,0,0>
851 desc
<> ;dummy descriptor
852 desc
<> ;descriptor for gdt itself
853 src desc
<0ffffh,,,93h
,,>
854 tgt desc
<0ffffh,,,93h
,,>
855 desc
<> ;bios cs descriptor
856 desc
<> ;stack segment descriptor
858 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
860 BREAK <Drive
code for
/E driver
>
863 ; The following label defines the start of the I/O code which is driver type
866 ; THE TYPE 2 driver must REPLACE this code with code appropriate
867 ; to the driver type.
869 EVEN
; Force start of drive code to word boundary
871 DRIVE_CODE
LABEL WORD
873 EXTMEM_LOW EQU
0000H ; 24 bit addr of start of extended memory
874 EXTMEM_HIGH EQU
0010H
876 ;** BASE_ADDR data element
878 ; The next value defines the 24 bit address of the start of the memory for
879 ; the cache. It is equal to the EMM_BASE value in the
880 ; EMM_REC structure for the cache.
882 ; NOTE THAT IT IS INITIALIZED TO THE START OF EXTENDED MEMORY. This is
883 ; because BLKMOV is used to read the EMM_CTRL sector during initialization
884 ; of a TYPE 1 driver.
886 ; NOTE: This data element is shared by TYPE 1, 2 drivers, but
887 ; its meaning and correct initial value are driver type specific.
890 ;; NOTE: The value at BASE_ADDR is patched during initialization when
891 ;; loading a RAMDrive into upper extended memory on a PLUS
893 BASE_ADDR
LABEL DWORD ; 24 bit address of start of this RAMDRV
896 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
897 ;** BLKMOV - Perform transfer for TYPE 1 driver
899 ; This routine is the transfer routine for moving bytes
900 ; to and from the AT extended memory in real mode using
901 ; the LOADALL instruction. The LOADALL instruction is used
902 ; to set up a segment descriptor which has a 24 bit address.
903 ; During the time the LOADALL 24 bit segment descriptor is
904 ; in effect we must have interrupts disabled. If a real mode
905 ; 8086 interrupt handler was given control it might perform
906 ; a segment register operation which would destroy the special
907 ; segment descriptor set up by LOADALL. This is prevented by
908 ; doing a CLI during the "LOADALL time".
910 ; WARNING NUMBER ONE:
911 ; THIS CODE WILL NOT WORK ON ANY 80286 MACHINE WHERE THE NMI
912 ; INTERRUPT IS ANYTHING BUT A FATAL, SYSTEM HALTING ERROR.
914 ; Since it is bad to leave interrupts disabled for a long
915 ; time, the I/O is performed 256 words at a time enabling
916 ; interrupts between each 256 word piece. This keeps the time
917 ; interrupts are disabled down to a reasonable figure in the 100mSec
920 ; To use the LOADALL instruction 102 bytes at location 80:0 must
921 ; be used. INT13 copies the contents of 80:0 into its own buffer,
922 ; copies in the LOADALL info, performs the LOADALL, and then copies
923 ; back the previous contents of 80:0. These operations are all
924 ; performed during the time interrupts are disabled for each 256 word
925 ; block. This must be done with interrupts disabled because this area
926 ; on DOS 2.X and 3.X contains variable BIOS data.
928 ; In order to gain full 24 bit addressing it is also required
929 ; that address line 20 be enabled. This effects 8086 compatibility
930 ; on 80286 systems. This code leaves address line 20 enabled
931 ; for the ENTIRE duration of the I/O because it is too time
932 ; expensive to disable/enable it for each 256 word block.
934 ; WARNING NUMBER TWO:
935 ; IF A MULTITASKING PRE-EMPTIVE SYSTEM SCHEDULES AND RUNS
936 ; AN APPLICATION WHICH RELIES ON THE 1 MEG ADDRESS WRAP
937 ; PROPERTY OF THE 8086 AND 8088 DURING THE TIME INT13
938 ; IS IN THE MIDDLE OF DOING AN I/O WITH ADDRESS LINE 20 ENABLED,
939 ; THE APPLICATION WILL NOT RUN PROPERLY AND MAY DESTRUCT THE
943 ; Perform various LOADALL setup operations
944 ; Enable address line 20
945 ; While there is I/O to perform
946 ; Do "per 256 word block" LOADALL setup operations
947 ; Set up copy of 80:0 to INT13 buffer
949 ; copy 80:0 to INT13 buffer
950 ; copy LOADALL info to 80:0
952 ; do 256 word transfer
953 ; copy INT13 80:0 buffer back to 80:0
955 ; Disable address line 20
958 ; INTEL special documentation of LOADALL instruction
961 ; ES:DI is packet transfer address.
962 ; CX is number of words to transfer.
963 ; DX:AX is 32 bit start byte offset (0 = start of cache)
964 ; BH is 1 for WRITE, 0 for READ
966 ; BASE_ADDR set to point to start of cache memory
967 ; This "input" is not the responsibility of the caller. It
968 ; is up to the initialization code to set it up when the
969 ; device is installed
973 ; OK, operation performed successfully
975 ; Error during operation, AL is error number (INT 13 error)
980 ; This routine is specific to TYPE 1 driver
982 ; sunilp - incorporated blkmov_386 (thanks to gregh)
983 ; incorporated loadall_286 trick (thanks to scottra)
984 ; added new a20 functionality
985 ; ideally the code should be all relocatable abd the 386
986 ; blkmov should be relocated on the 286 blkmov for the
987 ; 386 case. Also the A20 routines for the Olivetti or PS/2
988 ; should also ideally be relocated on top of the normal A20
991 ASSUME
DS:ramcode
,ES:NOTHING
,SS:NOTHING
996 ; Compute 32 bit address of start of I/O
999 ADD AX,WORD PTR [BASE_ADDR
]
1000 ADC DX,WORD PTR [BASE_ADDR
+ 2]
1002 ; Dispatch on function
1009 MOV WORD PTR [ESDES
.SEG_BASE
],AX
1010 MOV BYTE PTR [ESDES
.SEG_BASE
+ 2],DL
1018 MOV WORD PTR [DSDES
.SEG_BASE
],AX
1019 MOV BYTE PTR [DSDES
.SEG_BASE
+ 2],DL
1026 CALL SEG_SET
; Set ES or DS segreg
1028 ; Set stack descriptor
1035 ; SUB [LSP],2 ; CX is on stack at LOADALL
1037 ; the loadall kludge
1042 mov si,offset CSDES
;sp
1046 ; Set Other LOADALL stuff
1049 SIDT FWORD PTR [IDTDES
]
1050 SGDT FWORD PTR [GDTDES
]
1052 ; NOW The damn SXXX instructions store the desriptors in a
1053 ; different order than LOADALL wants
1055 MOV SI,OFFSET IDTDES
1057 MOV SI,OFFSET GDTDES
1060 ; Enable address line 20
1064 ;; Enable address line 20 on the PC AT or activate A20-A23 on the 6300 PLUS.
1065 ;; The former can be done by placing 0dfh in AH and activating the keyboard
1066 ;; processor. On the PLUS, 90h goes in AL and the port at 03f20h is written.
1067 ;; So the combined value of 0df90h can be used for both machines with
1068 ;; appropriate coding of the called routine A20.
1072 mov ax,cs:[A20On
] ;; set up for PLUS or AT
1075 ; JMP SHORT IO_START ;sp
1076 jmp short move_main_loop
;sp
1079 MOV AL,02 ; Drive not ready error
1082 io_donej: jmp io_done
1087 assume
ds:nothing
;sp
1095 MOV DI,OFFSET
cs:[SWAP_80
]
1099 CLI ; Un interruptable
1100 test [sys_flg
],dos_33
; is it dos 3.3 or above
1101 jne mml$1
; if so we don't need to store contents
1103 REP MOVSW ; Save contents of 80:0
1110 MOV SI,OFFSET
cs:LOADALL_TBL
1112 REP MOVSW ; Transfer in LOADALL info
1113 DW 050FH ; LOADALL INSTRUCTION
1115 ; set up stack for moving 80:0 information back again
1119 mov si,offset
cs:[swap_80
]
1121 test [sys_flg
],dos_33
1124 lods word ptr cs:[si]
1140 mov ax,offset io_done
1144 db 16 dup (0fah) ; bugfix sunilp
1148 mov ax,offset resume_int
1157 ; REP MOVSW ; Move data
1160 ; MOV WORD PTR [LCX],256 ; ASSUME full block
1163 ; ADD [LCX],CX ; OOPs, partial block
1164 ; XOR CX,CX ; This is the last block
1170 MOV CX,800H
; Retry this many times
1174 ;; Reset of line A20 on the PC AT requires writing 0ddh to the keyboard
1175 ;; processor. On the PLUS, the appropriate value is 00.
1179 mov ax,cs:[A20Off
] ;; setup for PLUS or AT. ah for IBM, al for PLUS
1180 CALL A20
; Disable address line 20
1187 ;** A20 - ENABLE/DISABLE ADDRESS LINE 20 ON IBM PC-AT
1189 ; This routine enables/disables address line 20 by twiddling bits
1190 ; in one of the keyboard controller registers.
1193 ; IBM Technical Reference Personal Computer AT Manual #1502243
1197 ; AH = 0DDH to disable A20
1198 ; AH = 0DFH to enable A20
1205 ; WARNING If this routine is called in a CLI state this routine has
1206 ; the side effect of enabling interrupts.
1208 ; This routine is specific to TYPE 1 driver
1212 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
1213 ;; CS override needed on S5_FLAG to avoid phase errors on
1214 ;; forward declaration of this variable.
1215 cmp cs:[S5_FLAG
],S_OLIVETTI
;; test for 6300 PLUS
1216 jne test_vec
;; yes, do this code
1219 cmp cs:[S5_FLAG
],S_VECTRA
1223 test cs:[sys_flg
],M_PS2
; is it a ps2 machine
1224 jne a20ps2
; if yes it has separate a20 routine
1227 call check_a20
; check to see if it can be enb /disb
1228 jc a20suc
; no it may not be toggled
1240 ; We must wait for the a20 line to settle down, which (on an AT)
1241 ; may not happen until up to 20 usec after the 8042 has accepted
1242 ; the command. We make use of the fact that the 8042 will not
1243 ; accept another command until it is finished with the last one.
1244 ; The 0FFh command does a NULL 'Pulse Output Port'. Total execution
1245 ; time is on the order of 30 usec, easily satisfying the IBM 8042
1246 ; settling requirement. (Thanks, CW!)
1248 mov al,0FFh ;* Pulse Output Port (pulse no lines)
1249 out 64H
,al ;* send cmd to 8042
1250 CALL E_8042
;* wait for 8042 to accept cmd
1260 ; Helper routine for A20. It waits for the keyboard controller to be "ready".
1263 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
1272 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1273 ; A20 status checking. If request is to enable a20 we must check to
1274 ; see if it is already enabled. If so we just set the sys_flg to
1275 ; indicate this. On disabling the routine checks to see if disabling
1279 assume
ds:nothing
,es:nothing
,ss:nothing
1280 cmp ah,0ddh ; is it a disable operation
1281 jne check_a20_enable
1283 ; check if a20 disabling allowed
1285 test cs:[sys_flg
],a20_st
1290 ; a20 enabling, check if allowed
1293 and cs:[sys_flg
], not A20_ST
1310 or cs:[sys_flg
],A20_ST
1319 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1320 ; A20 routine for PS2s. The PS2 A20 hardware has shifted and toggling
1321 ; a bit in the system port is all that is required.
1323 assume
ds:nothing
,es:nothing
,ss:nothing
1326 ; first separate disable operation from enable operation
1333 and cs:[sys_flg
],not A20_ST
1334 in al,PS2_PORTA
; input a20 status
1335 test al,GATE_A20
; is the a20 line set
1337 or cs:[sys_flg
],A20_ST
; indicate that it was already set
1346 out PS2_PORTA
,al ; set it
1348 in al,PS2_PORTA
; read status again
1360 test cs:[sys_flg
],A20_ST
1383 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1384 ;;* VECA20 - Address enable/disable routine for Vectra family computers
1386 ;; This routine does the same function as A20 for Vectra machines.
1387 ;; Vectra machines require writing single byte as opposed to
1388 ;; double byte commands to the 8041. This is due to a bug
1389 ;; in older versions in the Vectra 8041 controllers. IBM
1390 ;; machines must use double byte commands due to lack of
1391 ;; implementation of single byte commands in some of their machines.
1394 ;; Has same results as A20
1402 mov al,ah ;sigle byte command is code passed
1407 ; See A20 for a description of the following code. It simply makes
1408 ; sure that the previous command has been completed. We cannot
1409 ; pulse the command reg since there is a bug in some Vectra 8041s
1410 ; instead we write the command again knowing that when the second
1411 ; command is accepted the first was already processed.
1412 mov al,ah ; send command again
1426 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1427 ;;* A20S5 - Address enable/disable routine for the 6300 PLUS.
1429 ;; This routine enables lines A20-A23 on the PLUS by writing
1430 ;; to port 03f20h. Bit 7 turns the lines on, and bit 4 sets
1431 ;; the power-up bit. To disable the lines, the processor
1432 ;; must be reset. This is done by saving the world and
1433 ;; jumping to the ROM 80286 reset code. Since the power-up bit
1434 ;; is set, the data segment is set to the BiosSeg at 40h
1435 ;; and a jump is then made to the address at RealLoc1.
1436 ;; At RealLoc1, one can find the CS:IP where the code
1440 ;; Returns with zero flag set.
1443 ; test [reboot_flg],0ffh ;; sunilp
1444 ; jne a20s5boot ;; sunilp
1446 or al,al ;; if zero, then resetting processor
1448 call RSet
;; must return with entry value of ax
1450 push dx ;; set/reset port
1454 clc ;; sunilp modification cy flag now important
1458 ;;* a20S5BOOT - This code bypasses the processor reset on a reboot
1459 ;; of the 6300 PLUS. Otherwise the machine hangs.
1460 a20s5BOOT: ;; use this code before reboot
1464 OldStackSeg dw 0 ;; used during PLUS processor reset
1465 ;; to save the stack segment
1467 ;;* Rset - Reset the 80286 in order to turn off the address lines
1468 ;; on the 6300 PLUS. Only way to do this on the
1469 ;; current hardware. The processor itself can be
1470 ;; reset by reading or writing prot 03f00h
1476 push ds ;; save segments
1478 mov ax,BiosSeg
;; point to the bios segment
1479 mov ds,ax ;; ds -> 40h
1481 push word ptr [RealLoc1
] ;; save what might have been here
1482 push word ptr [RealLoc1
+2]
1483 mov word ptr [RealLoc1
],cs:[offset ReturnBack
] ;; load our return address
1484 mov word ptr [RealLoc1
+2],cs
1486 mov [OldStackSeg
],ss ;; save the stack segment, too
1487 mov dx,03f00h ;; reset the processor
1493 hlt ;; should never get here
1495 mov ss,[OldStackSeg
] ;; start the recovery
1497 pop word ptr [RealLoc1
+2]
1498 pop word ptr [RealLoc1
]
1503 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1504 blkmov_386: ;_protect:
1505 assume
ds:ramcode
,es:nothing
,ss:nothing
1507 ; Compute 32 bit address of start of I/O
1509 add ax,word ptr [base_addr
]
1510 adc dx,word ptr [base_addr
+ 2]
1514 ; Are we in virtual mode
1517 test cx,01B ; is the pe bit set
1522 ; Dispatch on function
1530 ; Update ES descriptor with address of track in cache
1532 mov si,offset es_des
1533 mov [si].bas_0_15
,ax
1534 mov [si].bas_16_23
,dl
1535 mov [si].bas_24_31
,dh
1537 ; Update DS descriptor with transfer address
1542 mov si,offset ds_des
1543 mov [si].bas_0_15
,ax
1544 mov [si].bas_16_23
,dl
1545 mov [si].bas_24_31
,dh
1548 ; Switch SI and DI for write transfer
1553 jmp short set_trans_1
1557 ; Update DS descriptor with address of track in cache
1559 mov si,offset ds_des
1560 mov [si].bas_0_15
,ax
1561 mov [si].bas_16_23
,dl
1562 mov [si].bas_24_31
,dh
1564 ; Update ES descriptor with transfer address
1569 mov si,offset es_des
1570 mov [si].bas_0_15
,ax
1571 mov [si].bas_16_23
,dl
1572 mov [si].bas_24_31
,dh
1574 ; Keep SI and DI the same for read transfer
1580 ; Restore Transfer Count
1589 ; we shall do the transfer 1024 words at a time
1602 cli ; Un interruptable
1604 lgdt fword ptr emm_gdt
1608 ; Switch to protected mode
1610 db 66h
,0Fh, 20h
, 0 ;mov eax,cr0
1612 db 66h
,0Fh,22h
, 0 ;mov cr0,eax
1614 ; Clear prefetch queue
1617 dw offset flush_prefetch
1618 dw cs_des
- start_gdt
1623 ; Initialize segment registers
1625 mov ax,ds_des
- start_gdt
1628 mov ax,es_des
- start_gdt
1631 shr cx,1 ; convert word count into dword count
1632 db 0f3h,066h,0a5h ; rep movsd
1633 ; rep movsw ; Move data
1636 ; Return to Real Mode
1639 db 66h
,0Fh, 20h
, 0 ; mov eax,cr0
1641 db 66h
,0Fh, 22h
, 0 ; mov cr0,eax
1643 ; Flush Prefetch Queue
1647 cod_seg dw ?
; Fixed up at initialization time
1652 ; see if transfer done else go to do next block
1665 mov cx,800h
; Retry this many times
1668 call A20
; Disable address line 20
1677 mov al,02 ; Drive not ready error
1682 assume
ds:ramcode
,es:nothing
,ss:nothing
1688 ; Update tgt descriptor with address of track in cache
1691 mov [si].bas_0_15
,ax
1692 mov [si].bas_16_23
,dl
1693 mov [si].bas_24_31
,dh
1695 ; Update src descriptor with transfer address
1703 mov [si].bas_0_15
,ax
1704 mov [si].bas_16_23
,dl
1705 mov [si].bas_24_31
,dh
1707 jmp short set_trans_2
1711 ; Update src descriptor with address of track in cache
1714 mov [si].bas_0_15
,ax
1715 mov [si].bas_16_23
,dl
1716 mov [si].bas_24_31
,dh
1718 ; Update tgt descriptor with transfer address
1726 mov [si].bas_0_15
,ax
1727 mov [si].bas_16_23
,dl
1728 mov [si].bas_24_31
,dh
1732 ; Restore Transfer Count
1737 ; we shall do the transfer 1024 words at a time
1748 mov si,offset int15_gdt
1749 mov ax,emm_blkm
shl 8
1754 ; see if transfer done else fo to do next block
1759 add [src
.bas_0_15
],2048
1760 adc [src
.bas_16_23
],0
1761 adc [src
.bas_24_31
],0
1763 add [tgt
.bas_0_15
],2048
1764 adc [tgt
.bas_16_23
],0
1765 adc [tgt
.bas_24_31
],0
1771 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1772 ;** SEG_SET - Set up a LOADALL segment descriptor as in REAL mode
1774 ; This routine sets the BASE value in the segment descriptor
1775 ; pointed to by DS:SI with the segment value in AX as the 80286
1776 ; does in REAL mode. This routine is used to set a descriptor
1777 ; which DOES NOT have an extended 24 bit address.
1780 ; INTEL special documentation of LOADALL instruction
1783 ; DS:SI -> Seg register descriptor
1784 ; AX is seg register value
1790 ; This routine is specific to TYPE 1 driver
1794 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
1798 MUL CX ; Believe or not, this is faster than a 32 bit SHIFT
1799 MOV WORD PTR [SI.SEG_BASE
],AX
1800 MOV BYTE PTR [SI.SEG_BASE
+ 2],DL
1805 ;** FIX_DESCRIPTOR - Shuffle GTD IDT descriptors
1807 ; The segment descriptors for the IDT and GDT are stored
1808 ; by the SIDT instruction in a slightly different format
1809 ; than the LOADALL instruction wants them. This routine
1810 ; performs the transformation by PUSHing the contents
1811 ; of the descriptor, and then POPing them in a different
1815 ; INTEL special documentation of LOADALL instruction
1816 ; INTEL 80286 processor handbook description of SIDT instruction
1819 ; DS:SI points to IDT or GDT descriptor in SIDT form
1821 ; DS:SI points to IDT or GDT descriptor in LOADALL form
1825 ; NOTE: The transformation is reversable, so this routine
1826 ; will also work to transform a descriptor in LOADALL
1827 ; format to one in SIDT format.
1829 ; Specific to TYPE 1 driver
1833 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
1834 PUSH WORD PTR [SI + 4]
1835 PUSH WORD PTR [SI + 2]
1837 POP WORD PTR [SI + 4]
1839 POP WORD PTR [SI + 2]
1842 ;** DATA SPECIFIC TO THE LOADALL INSTRUCTION USAGE
1844 ; SWAP_80 and LOADALL_TBL are data elements specific to the use
1845 ; of the LOADALL instruction by TYPE 1 drivers.
1849 ; Swap buffer for contents of 80:0
1851 EVEN
; Force word alignment of SWAP_80 and LOADALL_TBL
1853 SWAP_80
DB 102 DUP(?
)
1857 ; LOADALL data buffer placed at 80:0
1859 LOADALL_TBL
LABEL BYTE
1864 FLAGS
DW 0 ; High 4 bits 0, Int off, Direction clear
1865 ; Trace clear. Rest don't care.
1866 LIP
DW OFFSET AFTER_LOADALL
1880 ESDES SEGREG_DESCRIPTOR
<>
1881 CSDES SEGREG_DESCRIPTOR
<>
1882 SSDES SEGREG_DESCRIPTOR
<>
1883 DSDES SEGREG_DESCRIPTOR
<>
1884 GDTDES DTR_DESCRIPTOR
<>
1885 LDTDES DTR_DESCRIPTOR
<0D000H,0,0FFH,0088H>
1886 IDTDES DTR_DESCRIPTOR
<>
1887 TSSDES DTR_DESCRIPTOR
<0C000H,0,0FFH,0800H>
1889 ;** TRUE LOCATION OF ABOVE_PID
1891 ; Define the TRUE (runtime TYPE 2 driver) location of ABOVE_PID.
1892 ; This is the only piece of TYPE 2 specific data that we need
1893 ; in the resident image. We must define it HERE rather than down
1894 ; at ABOVE_BLKMOV so that we have its TRUE location after the
1895 ; TYPE 2 code is swapped in at initialization. If we defined
1896 ; it down at ABOVE_BLKMOV any instruction like:
1898 ; MOV DX,[ABOVE_PID]
1900 ; Would have to be "fixed up" when we moved the ABOVE_BLKMOV
1901 ; code into its final location.
1904 ABOVE_PID EQU
WORD PTR $ - 2 ; TRUE location of ABOVE_PID
1907 ; The following label defines the end of the region where BLKMOV code
1908 ; may be swapped in. BLKMOV code to be swapped in MUST fit
1909 ; between DRIVE_CODE and DRIVE_END
1911 DRIVE_END
LABEL WORD
1914 BREAK <BPB POINTER ARRAY
>
1916 ;** BPB pointer array data
1918 ; BPB pointer array returned by INIT call. Must be part of resident image.
1921 ; MS-DOS Technical Reference manual section on
1922 ; Installable Device Drivers
1928 ; The following label defines the end of the RAMDrive resident code
1929 ; for cases where no INT 9/19 code is included.
1931 DEVICE_END
LABEL BYTE
1933 BREAK <INT 19/9/15 Handlers
. Incl
if FIRST driver
in system
or /A
or new alloc
>
1936 ; As discussed above in the documentation of the EMM_CTRL sector it
1937 ; is necessary to hear about system re-boots so that the EMM_ISDRIVER
1938 ; bits in the EMM_REC structures can be manipulated correctly.
1940 ; On the IBM PC family of machines there are two events which cause a
1941 ; "soft" system re-boot which we might expect the EMM_CTRL sector to
1942 ; survive through. One is software INT 19H, the other is the Ctrl-Alt-Del
1943 ; character sequence which can be detected by "listening" on INT 9 for
1944 ; it. The code below consists of a handler for INT 19H, a handler
1945 ; for INT 9, and a drive TYPE dependant piece of code.
1947 ; The drive TYPE dependant piece of code works as follows:
1949 ; TYPE 1 uses EMM_CTRL sector so it scans the EMM_CTRL sector
1950 ; looking for all EMM_ALLOC and EMM_MSDOS EMM_REC
1951 ; structures and turns off the EMM_ISDRIVER bit.
1952 ; Since this scan is GLOBAL for all EMM_MSDOS
1953 ; marked structures we need only ONE INT 19/INT 9
1954 ; handler even if we have more than one TYPE 1
1955 ; RAMDrive in the system. The handler is always
1956 ; in the FIRST TYPE 1 RAMDrive installed at boot
1959 ; TYPE 2 DOES NOT use the EMM_CTRL sector but it still has
1960 ; a handler. What this handler does is issue an
1961 ; ABOVE_DEALLOC call to deallocate the Above Board
1962 ; memory allocated to the RAMDrive. In current versions
1963 ; of the EMM device driver this step is unnecessary
1964 ; as the EMM device driver is thrown away together
1965 ; with all of the allocation information when the system
1966 ; is re-booted. We do it anyway because some future version
1967 ; of the EMM device driver may be smarter and retain
1968 ; allocation information through a warm-boot. Currently,
1969 ; doing this doesn't hurt anything. Since this code cannot
1970 ; do a global ABOVE_DEALLOC for all TYPE 2 drivers in the
1971 ; system, it does an ABOVE_DEALLOC only for its memory
1972 ; and EACH TYPE 2 driver in the system includes the INT 19/9
1975 ; TYPE 3 uses EMM_CTRL sector so it scans the EMM_CTRL sector
1976 ; looking for all EMM_ALLOC and EMM_MSDOS EMM_REC
1977 ; structures and turns off the EMM_ISDRIVER bit.
1978 ; Since this scan is GLOBAL for all EMM_MSDOS
1979 ; marked structures we need only ONE INT 19/INT 9
1980 ; handler even if we have more than one TYPE 3
1981 ; RAMDrive in the system. The handler is always
1982 ; in the FIRST TYPE 3 RAMDrive installed at boot
1985 ; TYPE 4 does not use EMM_CTRL or have any other need to hear
1986 ; about re-boots since this type of RAMDrive CANNOT
1987 ; live through a warm boot. So TYPE 4 drivers NEVER
1988 ; include the INT 19/9 code.
1992 ; Storage locations for the "next" INT 19 and INT 9 vectors, the ones
1993 ; that were in the interrupt table when the device driver was loaded.
1994 ; They are initialized to -1 to indicate they contain no useful information.
2003 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2004 ; modification to meet new memory allocation standard
2012 ASSUME
DS:NOTHING
,SS:NOTHING
,ES:NOTHING
2014 ; This piece of code determines the size of extended memory
2015 ; which was allocated before this driver and then subtracts
2016 ; the amount it has allocated for itself
2018 ; inputs: ah = 88h is of interest
2019 ; outputs: ax = size of extended memory allocated by all before and
2035 ;** INT 9 Keyboard handler
2037 ; All this piece of code does is look for the Ctrl-Alt-Del event.
2038 ; If key is not Ctrl-Alt-Del, it jumps to OLD_9 without doing
2039 ; anything. If the Ctrl-Alt-Del key is detected it calls
2040 ; RESET_SYSTEM to perform driver TYPE specific re-boot code
2041 ; and then jumps to OLD_9 to pass on the event.
2043 ; NOTE THAT UNLIKE INT 19 THIS HANDLER DOES NOT NEED TO RESET
2044 ; THE INT 9 AND INT 19 VECTORS. This is because the Ctrl-Alt-Del
2045 ; IBM ROM re-boot code resets these vectors.
2048 ; INT 9 IBM ROM code in ROM BIOS listing of
2049 ; IBM PC Technical Reference manual for any PC family member
2058 ; THIS CODE IS USED BY TYPE 1,2 and 3 drivers.
2062 ;ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
2066 ; CMP AL,83 ; DEL key?
2070 ; MOV AL,BYTE PTR DS:[417H] ; Get KB flag
2072 ; TEST AL,0CH ; Ctrl Alt?
2074 ; CALL RESET_SYSTEM ; Ctrl Alt DEL
2080 ;** INT 19 Software re-boot handler
2082 ; All this piece of code does is sit on INT 19 waiting for
2083 ; a re-boot to be signaled by being called. It calls
2084 ; RESET_SYSTEM to perform driver TYPE specific re-boot code,
2085 ; resets the INT 19 and INT 9 vectors,
2086 ; and then jumps to OLD_19 to pass on the event.
2088 ; NOTE THAT UNLIKE INT 9 THIS HANDLER NEEDS TO RESET
2089 ; THE INT 9 AND INT 19 VECTORS. This is because the INT 19
2090 ; IBM ROM re-boot code DOES NOT reset these vectors, and we
2091 ; don't want to leave them pointing to routines that are not
2092 ; protected from getting stomped on by the re-boot.
2095 ; INT 19 IBM ROM code in ROM BIOS listing of
2096 ; IBM PC Technical Reference manual for any PC family member
2105 ; THIS CODE IS USED BY TYPE 1,2 and 3 drivers.
2109 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
2116 ; Since INT 19 DOES NOT reset any vectors (like INT 9 Ctrl Alt DEL does),
2117 ; we must replace those vectors we have mucked with.
2119 ; NOTE THAT WE RESET VECTORS DIRECTLY!!!!!!!!!!!!!!!!!!
2120 ; We are not sure that DOS is reliable enough to call.
2122 MOV AX,WORD PTR [OLD_19
]
2124 MOV WORD PTR DS:[19H
* 4],AX
2125 MOV AX,WORD PTR [OLD_19
+ 2]
2126 MOV WORD PTR DS:[(19H
* 4) + 2],AX
2127 ; MOV AX,WORD PTR [OLD_9]
2128 ; MOV WORD PTR DS:[9H * 4],AX
2129 ; MOV AX,WORD PTR [OLD_9 + 2]
2130 ; MOV WORD PTR DS:[(9H * 4) + 2],AX
2132 mov ax,word ptr [old_15
]
2133 cmp ax,word ptr [old_15
+2]
2138 mov word ptr ds:[15h
*4],ax
2139 mov ax,word ptr [old_15
+2]
2140 mov word ptr ds:[(15h
*4) +2],ax
2147 ;** RESET_SYSTEM perform TYPE 1 (/E) driver specific reboot code
2149 ; This code performs the EMM_ISDRIVER reset function as described
2150 ; in EMM.ASM for all EMM_REC structures which are EMM_ALLOC and
2151 ; EMM_ISDRIVER and of type EMM_MSDOS. We use the same LOADALL
2152 ; method described at BLKMOV to address the EMM_CTRL sector
2153 ; at the start of extended memory and perform our changes in
2156 ; NOTE: RESET_SYSTEM ALSO defines the start of ANOTHER piece of
2157 ; driver TYPE specific code that TYPE 2, 3 and 4 drivers
2158 ; will have to swap in a different piece of code for.
2160 ; note: type 1 drivers allocation schemes have changed. so now
2161 ; only the olivetti special configuration has an emm
2162 ; control record. this is a 286 machine and we can stick
2163 ; to the code given below for that. would have preferred
2164 ; to give complete support here
2173 ; This code is specific to TYPE 1 drivers
2177 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
2179 ; this piece of code is now redundant with the new aallocation scheme.
2180 ; for type 1 drivers we use the emm control record only in /u option
2181 ; and for that driver this piece of code is never executed
2183 ; this piece of code cannot be removed because other guys relocate
2195 ; Set up to address EMM_CTRL sector
2197 MOV [LIP
],OFFSET AFTER_LDA
2198 MOV WORD PTR [DSDES
.SEG_BASE
],EXTMEM_LOW
2199 MOV BYTE PTR [DSDES
.SEG_BASE
+ 2],EXTMEM_HIGH
2201 MOV [LDI
],EMM_RECORD
2202 MOV [LCX
],EMM_NUMREC
2205 CALL SEG_SET
; Set ES segreg
2209 CALL SEG_SET
; Set SS segreg
2213 CALL A20
; Enable adress 20
2223 MOV DI,OFFSET SWAP_80
2227 REP MOVSW ; Transfer out 80:0
2233 MOV SI,OFFSET LOADALL_TBL
2235 REP MOVSW ; Transfer in LOADALL info
2236 DW 050FH ; LOADALL INSTRUCTION
2239 ; Scan EMM_CTRL for MS-DOS ISDRIVER regions and turn off ISDRIVER
2243 TEST [DI.EMM_FLAGS
],EMM_ALLOC
2244 JZ DONEY
; Hit free record, done
2245 TEST [DI.EMM_FLAGS
],EMM_ISDRIVER
2246 JZ NEXTRECY
; No Driver
2247 CMP [DI.EMM_SYSTEM
],EMM_MSDOS
2248 JNZ NEXTRECY
; Wrong system
2249 AND [DI.EMM_FLAGS
],NOT EMM_ISDRIVER
; No longer a driver
2254 MOV ES,AX ; LOADALL puts 80H in AX
2259 MOV SI,OFFSET SWAP_80
2261 REP MOVSW ; Restore 80:0
2264 MOV AH,0DDH ; Disable adress line 20
2276 ; The following label performs two functions. It defines the end of the
2277 ; Driver TYPE specific RESET_SYSTEM code which will have to be replaced
2278 ; for different driver TYPEs as the code between RESET_SYSTEM and
2279 ; RESET_INCLUDE. Swapped in code MUST FIT between RESET_SYSTEM and
2280 ; RESET_INCLUDE. It also defines the end of the resident device driver
2281 ; code for a driver which wants to include the INT 19/ INT 9 code.
2283 RESET_INCLUDE
LABEL BYTE
2285 BREAK <COMMON INIT
CODE>
2287 ;** DISPOSABLE INIT DATA
2289 ; INIT data which need not be part of resident image
2292 DRIVER_SEL
DB 2 ; 0 if /E (TYPE 1), 1 if /A (TYPE 2),
2293 ; 2 if resmem (TYPE 3 or 4)
2295 DEV_SIZE
DW 64 ; Size in K of this device
2297 U_SWITCH db 0 ;; for the oliv's special config
2299 special_mem dw 0 ;; at&t special memory
2301 new_all db 0 ; to indicate new allocation scheme
2303 EXT_K
DW ?
; Size in K of Exteneded memory.
2305 NUM_ARG
DB 1 ; Counter for order dependent numeric
2306 ; arguments bbbb ssss dddd.
2308 INIT_DRIVE
DB 1 ; 0 means drive is inited
2309 ; 1 means drive is to be inited
2310 ; MUST BE DEFAULT SETTING
2311 ; 2 means drive is to be inited
2312 ; REGARDLESS of the existence of
2313 ; a valid DOS volume signature.
2315 GOTSWITCH
DB 0 ; 0 if no switch, NZ if switch seen
2317 DIRSEC
DW ?
; Number of directory SECTORS
2319 TERM_ADDR
LABEL DWORD ; Address to return as break address in INIT packet
2320 DW OFFSET DEVICE_END
; INIT to NOT include INT 19/9 code
2321 DW ?
; RAMDrive CS filled in at INIT
2323 TRUE_CS
DW ?
; Used to store the "true" location of
2324 ; the driver when the relocation at
2325 ; RAMDrive_RELOC is performed.
2327 RESMEM_SPECIAL
DB 0 ; 0 means NORMAL TYPE 3 RAMDrive
2328 ; NZ means SPECIAL TYPE 4 RESMEM version
2329 ; see code at RAMDrive_RELOC
2333 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2336 ; author: sunilp, august 1, 1987. thanks to rickha for most of this
2339 ; purpose: to determine whether extended memory cache can be installed
2340 ; on this system. also to determine and store in the system
2341 ; flag the machine identification.
2345 ; outputs: CY set if this machine doesn't allow extended memory cache.
2346 ; CY clear if this machine allows extended memory cache and
2347 ; the system flag is set according to the machine type.
2349 ; registers used: ax,es,flags
2350 ;----------------------------------
2351 ; Clear the state of the system flag
2353 assume
ds:ramcode
,es:nothing
,ss:nothing
2354 xor ax,ax ; 0000 into AX
2355 ; mov [sys_flg],al ; clear system flag
2356 ;----------------------------------
2357 ; Determine if 8086/8088 system. If so we should abort immediately.
2360 popf ; try to put that in the flags
2362 pop ax ; look at what really went into flags
2363 and ax,0F000h ; mask off high flag bits
2364 cmp ax,0F000h ; Q: was high nibble all ones ?
2365 je cpu_err
; Y: it's an 8086 (or 8088)
2366 ;----------------------------------
2367 ; Determine if 80286/80386 machine.
2369 mov ax,0F000h ; N: try to set the high bits
2371 popf ; ... in the flags
2373 pop ax ; look at actual flags
2374 and ax,0F000h ; Q: any high bits set ?
2375 je cpu_286
; N: it's an 80286
2376 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2377 ; It is a 386 cpu. We should next try to determine if the ROM is
2378 ; B0 or earlier. We don't want these guys.
2383 and ax,not 0F000h ; and
2386 ;----------------------------------
2387 ; the next three instructions were removed because we are loaded
2388 ; in real mode. So there is no need to check for virtual mode.
2390 ; smsw ax ;check for Virtual Mode
2391 ; test ax,0001 ; Q: Currently in Virtual Mode ?
2392 ; jnz cpu_exit ; Y: quit with error message
2393 ;----------------------------------
2394 ; N: check 386 stepping for B0
2395 call is_b0
; Q: B0 ?
2396 jc cpu_err
; Y: abort
2397 ;----------------------------------
2398 ; We have a valid 386 guy. Set the flag to indicate this.
2400 or [sys_flg
],M_386
; set 386 bit
2403 ;----------------------------------
2404 ; This is a 286 guy. Check for AT model byte. We don't want non-ATs.
2405 ; Set 286 bit if AT type. Then check for PS/2
2410 cmp byte ptr es:[0eh],0fch ; AT model byte
2411 jne cpu_err
; if not abort
2413 or [sys_flg
],M_286
; set 286 flag bit
2416 ; Determine if this is a PS/2 system
2429 ; We're on an NCR machine, send D7 and D5 to the 8042 in order
2430 ; to toggle A20 instead of the DF and DD we usually send.
2432 mov cs:[A20On
],0D790h
2433 mov cs:[A20Off
],0D500h
2436 ;----------------------------------
2442 ;----------------------------------
2451 ;*--------------------------------------------------------------------------*
2453 ;* IsPS2Machine HARDWARE DEP. *
2455 ;* Check for PS/2 machine *
2458 ;* RETS: AX = 1 if we're on a valid PS/2 machine, 0 otherwise *
2459 ;* REGS: AX and Flags clobbered *
2461 ;*--------------------------------------------------------------------------*
2463 IsPS2Machine proc
near
2465 mov ax,0C300h ; Try to disable the Watchdog timer
2468 jc IPMNoPS2
; Error? Not a PS/2.
2470 IPMFoundIt: mov ax,1 ; Return 1
2479 ;*--------------------------------------------------------------------------*
2481 ;* IsNCRMachine HARDWARE DEP. *
2483 ;* Check for NCR machine *
2486 ;* RETS: AX = 1 if we're on a valid NCR machine, 0 otherwise *
2487 ;* REGS: AX and Flags clobbered *
2489 ;*--------------------------------------------------------------------------*
2491 ; Look for 'NC' at F000:FFEA
2493 IsNCRMachine proc
near
2497 mov ax,word ptr es:[0FFEAh]
2503 INMFoundIt: mov ax,1
2509 ;******************************************************************************
2510 ; IS_B0 - check for 386-B0
2512 ; This routine takes advantage of the fact that the bit INSERT and
2513 ; EXTRACT instructions that existed in B0 and earlier versions of the
2514 ; 386 were removed in the B1 stepping. When executed on the B1, INSERT
2515 ; and EXTRACT cause an INT 6 (invalid opcode) exception. This routine
2516 ; can therefore discriminate between B1/later 386s and B0/earlier 386s.
2517 ; It is intended to be used in sequence with other checks to determine
2518 ; processor stepping by exercising specific bugs found in specific
2519 ; steppings of the 386.
2521 ; ENTRY: REAL MODE on 386 processor (CPU ID already performed)
2522 ; EXIT: CF = 0 if B1 or later
2523 ; CF = 1 if B0 or prior
2529 ;------------------------------------------------------------------------------
2537 mov ds,bx ; DS = 0000 (real mode IDT)
2538 assume
ds:R_Mode_IDT
2540 pop cs:[int6_save
] ; save old INT 6 offset
2542 pop cs:[int6_save
+2] ; save old INT 6 segment
2544 mov word ptr [bx+(6*4)],offset int6
2545 mov [bx+(6*4)+2],cs ; set vector to new INT 6 handler
2547 ; Attempt execution of Extract Bit String instruction. Execution on
2548 ; B0 or earlier with length (CL) = 0 will return 0 into the destination
2549 ; (CX in this case). Execution on B1 or later will fail and dummy INT 6
2550 ; handler will return execution to the instruction following the XBTS.
2551 ; CX will remain unchanged in this case.
2555 mov cx,0FF00h ; Extract length (CL)=0, CX=non-zero
2556 db 0Fh,0A6h,0CAh ; XBTS CX,DX,AX,CL
2559 mov ds,bx ; DS = 0000 (real mode IDT)
2560 push cs:[int6_save
] ; restore original INT 6 offset
2562 push cs:[int6_save
+2] ; restore original INT 6 segment
2565 or cx,cx ; Q: CX = 0 (meaning <=B0) ?
2566 jz ib_exit
; Y: exit (carry clear)
2567 stc ; N: set carry to indicate >=B1
2569 cmc ; flip carry tense
2574 ret ; *** RETURN ***
2577 ; Temporary INT 6 handler - assumes the cause of the exception was the
2578 ; attempted execution of an XTBS instruction.
2583 add word ptr [bp+2],3 ; bump IP past faulting instruction
2585 iret ; *** RETURN ***
2586 int6_save dw 0000,0000
2588 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2590 ;** PRINT - Print a "$" terminated message on stdout
2592 ; This routine prints "$" terminated messages on stdout.
2593 ; It may be called with only the DX part of the DS:DX message
2594 ; pointer set, the routine puts the correct value in DS to point
2595 ; at the RAMDrive messages.
2598 ; DX pointer to "$" terminated message (RAMCODE relative)
2604 ; COMMON TO TYPE 1, 2, 3, 4 drivers
2608 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
2612 MOV AH,Std_Con_String_Output
2617 ;** ITOA - Print Decimal Integer on stdout
2619 ; Print an unsigned 16 bit value as a decimal integer on stdout
2620 ; with leading zero supression. Prints from 1 to 5 digits. Value
2623 ; Routine uses divide instruction and a recursive call. Maximum
2624 ; recursion is four (five digit number) plus one word on stack
2627 ; ENTRY AX has binary value to be printed
2629 ; USES AX,CX,DX,FLAGS
2631 ; COMMON TO TYPE 1, 2, 3, 4 drivers
2635 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
2639 DIV CX ; DX is low digit, AX is higher digits
2641 JZ PRINT_THIS_DIGIT
; No more higher digits
2642 PUSH DX ; Save this digit
2643 CALL ITOA
; Print higher digits first
2644 POP DX ; Recover this digit
2646 ADD DL,"0" ; Convert to ASCII
2647 MOV AH,Std_CON_Output
2652 ;** RAM$INIT - Device Driver Initialization routine
2654 ; RAMDRIVE Initialization routine. This is the COMMON initialization
2655 ; code used by ALL driver TYPEs. Its jobs are to:
2657 ; 1. Initialize various global values
2658 ; 2. Check for correct DOS version and do changes to the device
2659 ; based on the DOS version if needed.
2660 ; 3. Parse the command line and set values accordingly
2661 ; 4. Call a TYPE specific INIT routine based on the Parse
2662 ; to set up a specific driver TYPE.
2663 ; 5. Initialize the DOS volume in the RAMDrive memory if appropriate
2664 ; 6. Print out report of RAMDrive parameters
2665 ; 7. Set the return INIT I/O packet values
2667 ; The first two lines perform step 1. Step two starts after and
2668 ; goes through VER_OK. Step 3 starts at VER_OK and goes through
2669 ; ARGS_DONE. Step 4 starts at ARGS_DONE and goes through I001.
2670 ; Step 5 starts at I001 and goes through DRIVE_SET. Step 6 starts
2671 ; at DRIVE_SET and goes through SETBPB. Step 7 starts at SETBPB
2672 ; and ends at the JMP DEVEXIT 10 lines later.
2674 ; At any time during the above steps an error may be detected. When
2675 ; this happens one of the error messages is printed and RAMDrive
2676 ; "de-installs" itself by returning a unit count of 0 in the INIT
2677 ; device I/O packet. The DOS device installation code is responsible
2678 ; for taking care of the details of re-claiming the memory used by
2679 ; the device driver. All RAMDrive needs to do is make sure any INT
2680 ; vectors it changed (INT 9 and INT 19) get restored to what they
2681 ; were when RAMDrive first started. If an EMM_CTRL sector is being
2682 ; used (TYPE 1 and 3) and one of the EMM_REC structures has been
2683 ; marked EMM_ISDRIVER by this driver, it must turn that bit back off
2684 ; since the driver did not install. A TYPE 2 driver must make sure it
2685 ; ABOVE_DEALLOCs any memory it allocated from the EMM device. The duty
2686 ; of reclaiming EMM_CTRL or Above Board memory and re-setting vectors
2687 ; is done by the DISK_ABORT routine which may be called by either
2688 ; this COMMON INIT code, or the TYPE specific INIT code.
2690 ; Step 1 initializes the segment part of TERM_ADDR to the correct
2691 ; value for type 1, 2 and 3 drivers. A TYPE 4 driver will put a
2692 ; different value in TERM_ADDR as it must include the space taken up
2693 ; by the RAMDrive memory itself which is part of the device. TRUE_CS
2694 ; is also initialized. This datum is relevant to the RESMEM_SPECIAL
2695 ; (TYPE 4) driver which relocates the driver code at RAMDrive_RELOC.
2696 ; This datum stores the CS of the REAL driver (the driver location
2697 ; BEFORE the relocation took place).
2699 ; Step 2 checks to make sure that we are running on a DOS in the
2700 ; 2.X or 3.X series which this driver is restricted to. If running
2701 ; on a 2.X series the device header attribute word and device command
2702 ; table are patched to exclude those device calls that don't exist
2703 ; on DOS 2.X. The HEADERMES message is also patched to not include
2704 ; the DOS drive letter part because 2.X DOS does not provide this
2705 ; information to the device at INIT time.
2707 ; Step 3 uses the "DEVICE = xxxxxxxxx" line pointer provided by
2708 ; DOS to look for the various device parameters. NOTE: This pointer
2709 ; IS NOT DOCUMENTED in the DOS 2.X tech ref material, but it does
2710 ; exist in the same way as 3.X. This code is simple even though
2711 ; it looks rather long. First it skips over the device name field
2712 ; to get to the arguments. In then parses the arguments as they are
2713 ; encountered. All parameter errors are detected here. NOTE THAT
2714 ; THIS ROUTINE IS NOT RESPONSIBLE FOR SETTING DEFAULT VALUES OF
2715 ; PARAMETER VARIABLES. This is accomplished by static initialization
2716 ; of the parameter variables.
2718 ; Step 4 calls a device TYPE specific initialization routine based
2719 ; on the parse in step 3 (presence or absense of /E and /A switches).
2720 ; NOTE THAT THERE IS ONE ROUTINE FOR TYPE 3 AND 4 DRIVERS. It is up
2721 ; to this routine itself to make the distinction between TYPE 3 and
2722 ; TYPE 4. NOTE that one of the prime jobs of these device TYPE specific
2723 ; routines is to set all of the variables that are needed by Step
2724 ; 5 and 7 that haven't been set by the COMMON init code:
2726 ; DEV_SIZE set to TRUE size of device
2727 ; BASE_ADDR set to TRUE start of device so MEMIO
2729 ; BASE_RESET set so DISK_ABORT can be called
2730 ; TERM_ADDR set to correct end of device
2731 ; INIT_DRIVE set to indicate if DOS volume needs to
2733 ; RESMEM_SPECIAL set if TYPE 4 driver
2735 ; Step 5 looks at the INIT_DRIVE variable to see if the DOS volume
2736 ; needs to be initialized. The only time we do not need to INITialize
2737 ; the DOS volume is when the driver TYPE specific INIT code finds
2738 ; that there is a VALID DOS volume in the RAMDrive memory it just
2739 ; set up. If the DOS volume does not need to be initialized, we
2740 ; go on to step 6. Otherwise the device BPB must be set, the
2741 ; RESERVED (boot) sector, FAT sectors, and root directory sectors
2742 ; must be initialized and written out to the RAMDrive. The first step
2743 ; is to initialize all of the BPB values. The code is a typical piece
2744 ; of MS-DOS code which given BYTES/SECTOR, TOTAL DISK SIZE
2745 ; and NUMBER OF ROOT DIRECTORY ENTRIES inputs figures out reasonable
2746 ; values for SEC/CLUSTER and SECTORS/FAT and TOTAL NUMBER OF CLUSTERS.
2747 ; NOTE THAT THIS CODE IS TUNED AND SPECIFIC TO 12 BIT FATS. Don't
2748 ; expect it to work AT ALL with a 16 bit FAT. The next step is to write
2749 ; out the BOOT record containing the BPB to sector 0, write out
2750 ; a FAT with all of the clusters free, and write out a root directory
2751 ; with ONE entry (the Volume ID at VOLID). Take CAREFUL note of the
2752 ; special code and comments at RAMDrive_RELOC.
2754 ; Step 6 makes the status report display of DEVICE SIZE, SECTOR SIZE,
2755 ; CLUSTER SIZE, and DIRECTORY SIZE by simply printing out the values
2758 ; Step 7 sets the INIT I/O packet return values for # of units,
2759 ; Break address, and BPB array pointer and returns via DEVEXIT.
2762 ; MS-DOS Technical Reference manual section on
2763 ; Installable Device Drivers
2766 ; EXIT Through DEVEXIT
2769 ; COMMON TO TYPE 1, 2, 3, 4 drivers
2773 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
2775 ; 1. Initialize various global values
2777 MOV WORD PTR [TERM_ADDR
+ 2],CS
2781 ; 2. Check for correct DOS version and do changes to the device
2782 ; based on the DOS version if needed.
2788 CMP AX,(2 SHL 8) + 00
2789 JB BADVER
; Below 2.00, BAD
2790 CMP AX,(3 SHL 8) + 00
2791 JB VER2X
; 2.X requires some patches
2792 CMP AX,(4 SHL 8) + 00
2793 je ldl_buf_present
; indicate that there is a hole for loadall
2794 Ja BADVER
; 3.X ok, 4.0 or above bad
2796 jb ver_ok
; if below we cannot take advantage of 80:0
2798 or [sys_flg
],DOS_33
; indicate we have dos 3.3 or above
2802 MOV DX,OFFSET BADVERMES
2806 AND [DEVATS
],NOT DEVOPCL
; No such bit in 2.X
2807 MOV BYTE PTR [RAMTBL
],11 ; Fewer functions too
2808 MOV WORD PTR [PATCH2X
],0A0DH ; Don't know DOS drive
2809 MOV BYTE PTR [PATCH2X
+ 2],"$"
2812 ;; 2.5 Check here for 6300 PLUS machine. First look for Olivetti Copy-right
2813 ;; and if found, check id byte at f000:fffd.
2816 push es ;; Olivetti Machine?
2817 mov ax,0fc00h ;; Look for 'OL' at fc00:50
2820 jnz notS5
;; not found
2823 cmp word ptr es:[0fffdh],0fc00h ;; look for 6300 plus
2825 mov [S5_FLAG
],S_OLIVETTI
;; yep, set flag
2828 ;; Check here for an HP Vectra machine. Look for HP id byte.
2834 mov [S5_FLAG
],S_VECTRA
2838 ; 3. Parse the command line and set values accordingly
2842 MOV AL,[SI.INIT_DOSDEV
] ; DOS drive letter
2843 ADD CS:[DOS_DRV
],AL ; Need explicit over, this is a forward ref
2844 MOV DX,OFFSET HEADERMES
2846 LDS SI,[SI.INIT_BPB
] ; DS:SI points to config.sys
2847 SKIPLP1: ; Skip leading delims to start of name
2863 SKIPLP2: ; Skip over device name
2876 CMP AL,0 ; Need this for 2.0 2.1
2878 SCAN_LOOP: ; PROCESS arguments
2881 OR AL,AL ; Need this for 2.0 2.1
2902 JA BAD_PARMJ
; Only 3 numeric arguments
2941 ; NOTE: Since DIRNUM is the 3rd numeric arg and SSIZE is the first,
2942 ; we know the desired sector size has been given.
2945 MOV CL,5 ; 32 bytes per dir ent
2946 SHR DI,CL ; DI is number of dir ents in a sector
2949 DIV DI ; Rem in DX is partial dir sector
2951 JZ SET_DSZ
; User specified groovy number
2952 SUB DI,DX ; Figure how much user goofed by
2953 ADD BX,DI ; Round UP by DI entries
2957 INC [NUM_ARG
] ; Next numeric argument
2962 MOV DX,OFFSET ERRMSG1
2966 XOR AX,AX ;Indicate no devices
2967 JMP SETBPB
;and return
2971 XCHG AL,[GOTSWITCH
] ; Switch already?
2973 JNZ BAD_PARM
; Yes, only one allowed
2984 ;; Added for /u switch
2985 cmp al,'u' ;; Look for U switch for PLUS
2990 cmp [S5_FLAG
],S_OLIVETTI
;; No good unless PLUS
2992 ; xchg al,[gotswitch] ; switch already
3012 ; 4. Call a TYPE specific INIT routine based on the Parse
3013 ; to set up a specific driver TYPE.
3018 MOV AL,[DRIVER_SEL
] ; Find out which init to call
3038 ; 5. Initialize the DOS volume in the RAMDrive memory if appropriate
3041 JNZ INIDRV
; Need to initialize drive
3042 JMP DRIVE_SET
; All set to go
3046 ; We must figure out what to do.
3047 ; All values are set so we can call MEMIO to read and write disk
3048 ; SSIZE is user sector size in bytes
3049 ; DIRNUM is user directory entries
3050 ; DEV_SIZE is size of device in K bytes
3052 ; Figure out total number of sectors in logical image
3055 MUL CX ; DX:AX is size in bytes of image
3056 DIV [SSIZE
] ; AX is total sectors
3057 ; Any remainder in DX is ignored
3059 ; Compute # of directory sectors
3061 MOV CL,5 ; Mult by 32 bytes per entry
3062 SHL AX,CL ; Don't need to worry about overflow, # ents
3069 NOINC: ; AX is # sectors for root dir
3071 ADD AX,2 ; One reserved, At least one FAT sector
3074 MOV [DIRNUM
],16 ; Smallest reasonable number
3076 MOV AX,512 ; 16*32 = 512 bytes for dir
3081 NOINC2: ; AX is # sectors for root dir
3083 ADD AX,2 ; One reserved, At least one FAT sector
3085 JB OK001
; 16 directory sectors got us to OK
3086 CALL DISK_ABORT
; Barf
3087 MOV DX,OFFSET ERRMSG2
3091 mov si,64 ; set a loop bound for the homing process
3092 ; to avoid oscillation in homing
3094 ; Figure a reasonable cluster size
3095 MOV AX,[SECLIM
] ; AX is total sectors on disk
3096 SUB AX,[RESSEC
] ; Sub off reserved sectors
3097 MOV CL,[FATNUM
] ; CX is number of FATs
3100 SUB AX,[FATSEC
] ; Sub off FAT sectors
3102 SUB AX,[DIRSEC
] ; Sub off directory sectors, AX is # data sectors
3103 MOV BX,1 ; Start at 1 sec per alloc unit
3105 JB CSET
; 1 sector per cluster is OK
3107 CMP AX,(4096-10) * 2
3108 JB CSET
; 2 sector per cluster is OK
3110 CMP AX,(4096-10) * 4
3111 JB CSET
; 4 sector per cluster is OK
3113 CMP AX,(4096-10) * 8
3114 JB CSET
; 8 sector per cluster is OK
3115 MOV BX,16 ; 16 sector per cluster is OK
3117 ; Figure FAT size. AX is reasonable approx to number of DATA sectors
3118 ; BX is reasonable sec/cluster
3120 DIV BX ; AX is total clusters, ignore remainder
3121 ; can't have a "partial" cluster
3127 ADD AX,CX ; AX is Bytes for fat (1.5 * # of clusters)
3128 ADD AX,3 ; Plus two reserved clusters
3130 DIV [SSIZE
] ; AX is # sectors for a FAT this size
3134 NOINC4: ; AX is # sectors for FAT
3135 XCHG AX,[FATSEC
] ; Set newly computed value
3136 XCHG BL,[CSIZE
] ; Set newly computed value
3137 dec si ; have we looped enough?
3138 jz homfin
; yes, time to get out
3139 CMP BL,[CSIZE
] ; Did we compute a different size?
3140 JNZ CLUSHOME
; Keep performing FATSEC and CSIZE computation
3141 ; until the values don't change.
3142 CMP AX,[FATSEC
] ; Did we compute a different size?
3143 JNZ CLUSHOME
; Keep performing FATSEC and CSIZE computation
3144 ; until the values don't change.
3147 ; 6. Print out report of RAMDrive parameters
3149 MOV DX,OFFSET STATMES1
3153 MOV DX,OFFSET STATMES2
3157 MOV DX,OFFSET STATMES3
3162 MOV DX,OFFSET STATMES4
3166 MOV DX,OFFSET STATMES5
3168 CMP [RESMEM_SPECIAL
],0
3171 ; We are in a special case. The RAMDrive driver area starts at DEVICE_END.
3172 ; If we left this INIT code where it is and executed it the act of
3173 ; Initializing the boot sector, FAT, and root directory would overwrite
3174 ; this INIT code as we are executing it. So what we do is COPY this
3175 ; code into the DATA area of the RAMDrive and execute it from there.
3178 MOV AX,1 ; AX is sec # of start of FAT
3179 ADD AX,[FATSEC
] ; AX is sec # of start of directory
3180 ADD AX,[DIRSEC
] ; AX is sec # of start of DATA
3181 MUL [SSIZE
] ; DX:AX is byte offset of start of DATA
3182 ADD AX,WORD PTR [BASE_ADDR
]
3183 ADC DX,WORD PTR [BASE_ADDR
+ 2] ; DX:AX is 32 addr of first byte of DATA
3184 ADD AX,15 ; PARA round up
3187 DIV CX ; AX is Seg addr of DATA region
3189 ; At this point we need to do a little check. We need to make
3190 ; sure the distance between where we are now, and where we
3191 ; are relocating to is AT LEAST as much as we are moving
3192 ; so that we don't modify ourselves while we're moving
3196 SUB BX,DX ; BX is para between segs
3197 CMP BX,((OFFSET RAMDrive_END
- OFFSET RAMDEV
) + 15) / 16 ; CMP to para moving
3198 JAE OKMOV
; Distance is enough
3199 MOV AX,CS ; Move far enough away
3200 ADD AX,((OFFSET RAMDrive_END
- OFFSET RAMDEV
) + 15) / 16
3205 MOV CX,OFFSET RAMDrive_END
; Amount to move
3207 REP MOVSB ; Reloc to data region
3208 PUSH ES ; Push FAR return
3209 MOV AX,OFFSET NO_RELOC
3212 POP DS ; DS is NEW RAMCODE
3220 XOR DX,DX ; Sector 0
3221 MOV CX,1 ; One sector
3222 MOV DI,OFFSET BOOT_SECTOR
; Boot sector
3225 INC DX ; First FAT sector
3226 MOV DI,OFFSET SECTOR_BUFFER
3231 MOV DI,OFFSET SECTOR_BUFFER
3233 MOV WORD PTR ES:[DI],0FFF8H
3234 MOV BYTE PTR ES:[DI + 2],0FFH
3236 INC DX ; Next sector
3237 MOV WORD PTR ES:[DI],0
3238 MOV BYTE PTR ES:[DI + 2],0
3246 INC DX ; Next sector
3252 CALL INIMEMIO
; FIRST directory sector
3257 MOV DI,OFFSET SECTOR_BUFFER
3262 INC DX ; Next sector
3268 ; BPB IS NOW ALL SET
3270 MOV AL,1 ;Number of ramdrives
3272 ; NOTE FALL THROUGH!!!!!!!
3275 ;** SETBPB - Set INIT packet I/O return values
3277 ; This entry is used in ERROR situations to return
3278 ; a unit count of 0 by jumping here with AL = 0.
3279 ; The successful code path falls through to here
3283 ; AL = INIT packet unit count
3289 ; COMMON TO TYPE 1, 2, 3, 4 drivers
3295 ; 7. Set the return INIT I/O packet values
3298 MOV [BX.INIT_NUM
],AL
3299 MOV CX,WORD PTR [TERM_ADDR
]
3300 MOV WORD PTR [BX.INIT_BREAK
],CX ;SET BREAK ADDRESS
3301 MOV CX,WORD PTR [TERM_ADDR
+ 2]
3302 MOV WORD PTR [BX.INIT_BREAK
+ 2],CX
3303 MOV WORD PTR [BX.INIT_BPB
],OFFSET INITAB
;SET POINTER TO BPB ARRAY
3305 MOV WORD PTR [BX.INIT_BPB
+ 2],CX
3308 ;** INIMEMIO call MEMIO but preserve registers
3310 ; MEMIO is very register destructive, all this routine
3311 ; does is provide a less destructive way to call MEMIO.
3320 ; COMMON TO TYPE 1, 2, 3, 4 drivers
3324 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
3340 ;** GETNUM - Read an unsigned integer
3342 ; This routine looks at DS:SI for a decimal unsigned integer.
3343 ; It is up to the caller to make sure DS:SI points to the start
3344 ; of a number. If it is called without DS:SI pointing to a valid
3345 ; decimal digit the routine will return 0. Any non decimal digit
3346 ; defines the end of the number and SI is advanced over the
3347 ; digits which composed the number. Leading "0"s are OK.
3349 ; THIS ROUTINE DOES NOT CHECK FOR NUMBERS LARGER THAN WILL FIT
3350 ; IN 16 BITS. If it is passed a pointer to a number larger than
3351 ; 16 bits it will return the low 16 bits of the number.
3353 ; This routine uses the MUL instruction to multiply the running
3354 ; number by 10 (initial value is 0) and add the numeric value
3355 ; of the current digit. Any overflow on the MUL or ADD is ignored.
3358 ; DS:SI -> ASCII text of number
3360 ; BX is binary for number
3361 ; SI advanced to point to char after number
3365 ; COMMON TO TYPE 1, 2, 3, 4 drivers
3369 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
3389 BREAK <INITIAL EMM control sector
>
3391 ;** INITIAL EMM_CTRL sector
3393 ; This is a datum which represents a correct initial EMM_CTRL
3394 ; sector as discussed in the EMM_CTRL documentation. It is used
3395 ; to check for the presense of a valid EMM_CTRL by comparing
3396 ; the signature strings, and for correctly initializing the
3397 ; EMM_CTRL sector if needed.
3399 ; The DWORD at BASE_RESET, which is the EMM_BASE of the NULL
3400 ; 0th EMM_REC structure, is used as a storage location of
3401 ; the address of the EMM_CTRL sector (PLUS 1024!!!!!!).
3402 ; This value can be used if it is necessary to re-address the
3403 ; EMM_CTRL sector during initialization. See the DISK_ABORT routine.
3404 ; NOTE THAT BASE_RESET CAN NOT BE USED AT RUNTIME AS THIS DATUM
3405 ; IS NOT PART OF THE RESIDENT IMAGE.
3407 ; This data is appropriate to TYPE 1 and TYPE 3 drivers
3410 EMM_CONTROL
LABEL BYTE
3411 DB "MICROSOFT EMM CTRL VERSION 1.00 CONTROL BLOCK "
3415 DW EMM_ALLOC
+ EMM_ISDRIVER
3417 BASE_RESET
LABEL DWORD ; RESMEM driver must patch this value
3418 DW EXTMEM_LOW
+ 1024
3426 BREAK <RAMDrive
COMMON INIT ROUTINES
>
3428 ;** DISK_ABORT - De-install RAMDrive after init
3430 ; This routine MUST BE CALLED to de-install a RAMDrive driver
3431 ; if the de-installation takes place:
3433 ; AFTER INT 19/INT 9 vectors are replaced
3434 ; AFTER ABOVE_PID is valid for TYPE 2
3435 ; AFTER an EMM_REC structure in the EMM_CTRL sector
3436 ; has been marked EMM_ISDRIVER for TYPE 1 or 3.
3438 ; NOTE: Since a TYPE 4 driver does NONE of the above things it is
3439 ; not necessary to call this routine, but the routine is
3440 ; designed so that it is OK to call for a TYPE 4 driver.
3442 ; In all cases the INT 9 and INT 19 vectors are replaced if the
3443 ; value of both words of OLD_19 is NOT -1. This is why the initial value
3444 ; of this datum is -1. In the event that the INT 9 and INT 19 vectors
3445 ; are replaced, this datum takes on some value other than -1.
3447 ; If this is a TYPE 1 or TYPE 3 driver the EMM_ISDRIVER bit is
3448 ; turned off in the LAST EMM_MSDOS EMM_REC structure.
3449 ; NOTE THAT A TYPE 1 or TYPE 3 DRIVER MUST NOT USE THIS ROUTINE
3450 ; IF IT HAS NOT "TURNED ON" AN EMM_ISDRIVER BIT IN ONE OF THE EMM_REC
3451 ; STRUCTURES. If this is done, this code MAY turn off the WRONG
3452 ; EMM_ISDRIVER bit (probably a bit for a previously installed RAMDrive
3453 ; of the same TYPE).
3455 ; If this is a TYPE 2 driver, an ABOVE_DEALLOC call is made on
3461 ; BASE_RESET valid if TYPE 1 or TYPE 3
3462 ; ABOVE_PID valid if TYPE 2
3469 ; COMMON TO TYPE 1, 2, 3, 4 drivers
3473 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
3479 ; TYPE 2, De-alloc the Above Board memory
3482 MOV AH,ABOVE_DEALLOC
3484 CMP AH,ABOVE_ERROR_BUSY
3489 CMP [RESMEM_SPECIAL
],0
3490 JNZ RET002
; No EMM_CTRL on TYPE 4
3492 ; sp new int15 allocation for ext memory (except for oli memory) so no
3493 ; emm control for these
3496 cmp [new_all
],0 ;new allocation scheme
3497 jne ret002
; if yes then skip emm updates
3499 ; TYPE 1 or 3, turn off last EMM_ISDRIVER
3501 MOV AX,WORD PTR [BASE_RESET
]
3502 MOV DX,WORD PTR [BASE_RESET
+ 2]
3503 SUB AX,1024 ; Backup to EMM_CTRL
3505 MOV WORD PTR [BASE_ADDR
],AX
3506 MOV WORD PTR [BASE_ADDR
+ 2],DX
3508 CALL CTRL_IO
; Get EMM_CTRL
3510 MOV DI,OFFSET SECTOR_BUFFER
3513 MOV BX,-1 ; Init to "no such record"
3517 ; Look for last installed MS-DOS region
3519 TEST [DI.EMM_FLAGS
],EMM_ALLOC
3521 TEST [DI.EMM_FLAGS
],EMM_ISDRIVER
3522 JZ NEXTRECX
; No Driver
3523 CMP [DI.EMM_SYSTEM
],EMM_MSDOS
3530 CMP BX,-1 ; DIDn't find it
3532 AND [BX.EMM_FLAGS
],NOT EMM_ISDRIVER
; Undo install
3534 CALL CTRL_IO
; EMM_CTRL back out
3537 ; Reset INT 9 and/or INT 19 if OLD_19 is not -1
3548 MOV AX,(Set_Interrupt_Vector
SHL 8) OR 19H
3551 ; MOV AX,(Set_Interrupt_Vector SHL 8) OR 9H
3554 ; sp we have to deinstall the int15 handler also if it was installed
3556 lds dx,[old_15
] ; get the old 15h handler addressin ds:dx
3563 mov ax,(set_interrupt_vector
shl 8) or 15h
3569 ;** CTRL_IO - Read/Write the first 1024 bytes at BASE_ADDR
3571 ; This routine is used at INIT time to read the first 1024
3572 ; bytes at BASE_ADDR. If TYPE 1 or TYPE 3 and BASE_ADDR points
3573 ; to the EMM_CTRL address (initial value), the EMM_CTRL sector
3574 ; is read/written. If TYPE 1 or TYPE 3 and BASE_ADDR has been set
3575 ; to the start of a RAMDrive, the first 1024 bytes of the DOS volume
3576 ; are read/written. If TYPE 2 or TYPE 4, the first 1024 bytes of
3577 ; the DOS volume are read/written. All this routine does is
3578 ; set inputs to BLKMOV to transfer 1024 bytes at offset 0 to/from
3582 ; BH = 0 for READ, 1 for WRITE
3584 ; SECTOR_BUFFER filled in with 1024 bytes at BASE_ADDR
3588 ; COMMON TO TYPE 1, 2, 3, 4 drivers
3592 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
3594 MOV AX,DX ; Offset 0
3595 MOV CX,512 ; 1024 bytes
3598 MOV DI,OFFSET SECTOR_BUFFER
3600 CALL BLKMOV
; Read in EMM_CTRL
3604 ;** MM_SETDRIVE - Look for/Init EMM_CTRL and DOS volume
3606 ; This routine is used by TYPE 1 and 3 drivers to check for/initialize
3607 ; the EMM_CTRL sector, and check for a valid DOS volume if approriate.
3609 ; This routine reads the EMM_CTRL sector in to SECTOR_BUFFER
3610 ; CALLS FIND_VDRIVE to check out and alloc or find an EMM_REC
3611 ; Sets BASE_ADDR to point to the start of the RAMDrive memory
3612 ; Writes the updated EMM_CTRL back out from SECTOR_BUFFER
3613 ; JUMPs to CHECK_DOS_VOL to snoop for a valid DOS volume if
3614 ; the return from FIND_VDRIVE indicates this is worth
3615 ; doing, OTHERWISE return leaving INIT_DRIVE set to the
3616 ; default value of 1 (needs to be INITed).
3619 ; BASE_ADDR initialized to point at START of extended memory
3620 ; so that the EMM_CTRL sector can be accessed by
3621 ; doing I/O at offset 0.
3622 ; EXT_K is set to size of extended memory
3623 ; DEV_SIZE is set to user requested device size
3625 ; CARRY SET - error, message already printed
3627 ; BASE_ADDR set for this drive
3629 ; DEV_SIZE set to TRUE size
3631 ; WARNING! Exit conditions MUST match CHECK_DOS_VOL as it transfers
3637 ; Used by TYPE 1 and TYPE 3 drivers
3641 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
3643 CALL CTRL_IO
; Get EMM_CTRL
3644 MOV DX,OFFSET INIT_IO_ERR
3646 CALL FIND_VDRIVE
; Snoop
3648 PUSHF ; Save zero status for DOS VOL snoop
3649 PUSH ES ; Save EMM_BASE from EMM_REC
3652 ; once again if we installed according to new int15 standard we should
3653 ; not write emm back
3656 ; test if we installed according to new standard
3658 cmp [new_all
],0 ; did we install according to new standard
3659 jne skip_emm_write
; skip writing back emm
3662 CALL CTRL_IO
; Write EMM_CTRL back out
3663 MOV DX,OFFSET INIT_IO_ERR
3666 POP WORD PTR [BASE_ADDR
] ; Set final correct BASE_ADDR
3667 POP WORD PTR [BASE_ADDR
+ 2]
3670 ; NOTE TRANSFER TO DIFFERENT ROUTINE
3673 CLC ; Leave INIT_DRIVE set
3684 ;** CHECK_DOS_VOL examine RAMDrive region for valid DOS volume.
3686 ; This routine is used by TYPE 1, 2 and 3 drivers to check and see
3687 ; if the RAMDrive memory contains a valid DOS volume (one that lived
3688 ; through a re-boot). Its prime job is to set INIT_DRIVE to indicate
3689 ; whether the DOS volume needs to be initialized.
3691 ; First the first 1024 bytes of the drive are read in to SECTOR_BUFFER
3692 ; Next we check for a match of the signature areas up at BOOT_SECTOR
3693 ; to see if this drive contains a VALID RAMDrive boot record.
3694 ; IF the signatures are valid AND INIT_DRIVE != 2 (ignore valid signature)
3695 ; We check to make sure that SSIZE and DIRNUM set by the user
3696 ; match the values in the BPB we just found.
3698 ; we set INIT_DRIVE to 0 (don't init)
3699 ; and transfer the BPB out of the boot sector on the drive
3700 ; (in SECTOR_BUFFER) into the BPB for this driver at
3703 ; Leave INIT_DRIVE set to whatever it was on input (1 or 2)
3704 ; indicating that the drive must be INITed.
3706 ; Leave INIT_DRIVE set to whatever it was on input (1 or 2)
3707 ; indicating that the drive must be INITed.
3709 ; WARNING! This routine DOES NOT check to make sure that the size of
3710 ; the device as indicated in the BPB transfered in if a valid
3711 ; DOS volume is found is consistent with the actual size
3712 ; of the memory allocated to the device (DEV_SIZE). It
3713 ; is up to the caller to check this if so desired.
3716 ; BASE_ADDR set to point at START of DOS device
3718 ; CARRY SET - error, message already printed
3721 ; SECTOR_BUFFER contains first 1024 bytes of device
3725 ; WARNING! Exit conditions MUST match MM_SETDRIVE as it jumps to this
3728 ; Used by TYPE 1, 2 and 3 drivers
3732 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
3735 ; NOTE: WE CANNOT CALL MEMIO, WE MUST STILL USE CTRL_IO because the BPB
3738 CALL CTRL_IO
; Since BASE_ADDR is set, reads start of DEVICE
3739 MOV DX,OFFSET INIT_IO_ERR
3743 MOV DI,OFFSET SECTOR_BUFFER
3744 MOV SI,OFFSET BOOT_SECTOR
3745 MOV CX,OFFSET RDRIVEBPB
- OFFSET BOOT_SECTOR
3748 JNZ OK_RET
; No DOS device
3749 ADD DI,OFFSET BOOT_START
- OFFSET RDRIVEBPB
3750 ADD SI,OFFSET BOOT_START
- OFFSET RDRIVEBPB
3751 MOV CX,OFFSET BOOT_END
- OFFSET BOOT_START
3753 JNZ OK_RET
; No DOS device
3755 JZ NOT_VALID
; Current value 2 means we CANNOT
3756 ; assume this BPB is valid.
3758 ; Check to make sure found BPB has same SSIZE and DIRNUM values
3760 MOV SI,OFFSET SECTOR_BUFFER
+ (OFFSET SSIZE
- OFFSET BOOT_SECTOR
)
3763 JNZ NOT_VALID
; Sector size different than user request
3764 MOV SI,OFFSET SECTOR_BUFFER
+ (OFFSET DIRNUM
- OFFSET BOOT_SECTOR
)
3767 JNZ NOT_VALID
; Sector size different than user request
3769 MOV [INIT_DRIVE
],0 ; Found a DOS drive
3770 MOV DI,OFFSET RDRIVEBPB
3771 MOV SI,OFFSET SECTOR_BUFFER
+ (OFFSET RDRIVEBPB
- OFFSET BOOT_SECTOR
)
3772 MOV CX,OFFSET BOOT_START
- OFFSET RDRIVEBPB
3773 REP MOVSB ; Set correct BPB
3779 ;** FIND_VDRIVE - Check out EMM_CTRL and alloc
3781 ; This code checks for a valid EMM_CTRL and sets up
3782 ; an initial one if there isn't. It then performs the
3783 ; algorithm described in the EMM_CTRL documentation
3784 ; to either allocate a NEW EMM_REC of type EMM_MSDOS,
3785 ; or find an existing EMM_REC which is EMM_MSDOS and has
3786 ; its EMM_ISDRIVER bit clear. In the later case it
3787 ; checks to see if DEV_SIZE is consistent with EMM_KSIZE
3788 ; and tries to make adjustments to EMM_KSIZE or DEV_SIZE
3789 ; if they are not consistent.
3791 ; As a side effect of scanning the EMM_CTRL sector for
3792 ; EMM_RECs with EMM_MSDOS and EMM_ISDRIVER we also find
3793 ; out if this is the first TYPE 1 or TYPE 3 driver in the
3794 ; system. If this is the first, then the INT 9/INT 19 code
3797 ; First the EMM_CTRL signature strings are checked.
3798 ; If they are not valid we go to SETCTRL to set up a new
3799 ; empty EMM_CTRL in SECTOR_BUFFER.
3800 ; If the signatures are valid, EMM_TOTALK is checked
3801 ; against EXT_K. If they are the same, the EMM_CTRL sector is
3802 ; valid and we skip to SCAN_DEV. Otherwise we initialize the
3803 ; EMM_CTRL sector at SETCTRL. All we need to do to set up the initial
3804 ; EMM_CTRL sector is transfer the record at EMM_CONTROL into
3805 ; SECTOR_BUFFER and set EMM_TOTALK and EMM_AVAILK to EXT_K - 1.
3807 ; In either case, finding a valid EMM_CTRL or setting up a correct
3808 ; initial one, we end up at SCAN_DEV. This code performs the
3809 ; scan of the EMM_REC structures looking for a "free" one
3810 ; or an allocated one which is EMM_MSDOS and has its EMM_ISDRIVER
3811 ; bit clear as described in the EMM_CTRL sector documentation.
3812 ; NOTE THAT THIS SCAN SETS THE BX REGISTER TO INDICATE WHETHER
3813 ; WE FOUND ANY EMM_REC STRUCTURES WHICH WERE EMM_MSDOS AND HAD
3814 ; THEIR EMM_ISDRIVER BIT SET. If we found such an EMM_REC structure
3815 ; then this IS NOT the first driver in the system and the INT 9/INT 19
3816 ; code SHOULD NOT be installed.
3818 ; If we find a "free" EMM_REC structure we go to GOT_FREE_REC
3819 ; and try to allocate some memory. This attempt will fail if
3820 ; EMM_AVAILK is less than 16K. We then call SET_RESET to do
3821 ; the INT 9/INT 19 setup if the BX register set by the EMM_REC
3822 ; scan indicates we should. We adjust DEV_SIZE to equal the
3823 ; available memory if DEV_SIZE is > EMM_AVAILK. Then all we do
3824 ; is set EMM_AVAILK and all of the fields in the EMM_REC structure
3825 ; as described in the EMM_CTRL sector documentation. We return
3826 ; with zero reset as there cannot be a valid RAMDrive in this
3827 ; region because we just allocated it.
3829 ; If we find an EMM_REC structure with EMM_MSDOS and EMM_ISDRIVER
3830 ; clear then we know this region MIGHT have a valid DOS volume
3831 ; so we will return with zero set (this is set up at OK_SET_DEV).
3832 ; At CHECK_SYS plus 5 lines we:
3834 ; Call SET_RESET to do INT 9/INT 19 setup if BX indicates
3835 ; IF the EMM_REC structure we found is the LAST EMM_REC structure
3836 ; we cannot edit any sizes and whatever the EMM_KSIZE
3837 ; is we stuff it into DEV_SIZE and set the EMM_ISDRIVER
3838 ; bit, and we're done.
3839 ; NOTE: We DO NOT check that EMM_KSIZE is at least
3840 ; 16K as we know this EMM_REC was created
3841 ; by some PREVIOUS RAMDrive program who
3842 ; DID make sure it was at least 16K
3844 ; IF EMM_KSIZE == DEV_SIZE
3845 ; set EMM_ISDRIVER and we're done
3846 ; IF EMM_KSIZE < DEV_SIZE
3847 ; either the user has edited his DEVICE = line since
3848 ; the last time the system was re-booted, or at the
3849 ; time we initially allocated this region EMM_AVAILK
3850 ; was less than DEV_SIZE and we had to trim the device
3852 ; This case is handled at INSUFF_MEM.
3853 ; IF the next EMM_REC structure is not allocated
3854 ; IF EMM_AVAILK == 0
3855 ; We can't do anything, so set DEV_SIZE
3856 ; to EMM_KSIZE and we're done.
3858 ; allocate appropriate amount off of EMM_AVAILK
3859 ; and add it to EMM_KSIZE.
3860 ; Set INIT_DRIVE to 2 and we're done.
3861 ; The reason we set INIT_DRIVE to 2 is because
3862 ; we just changed the size of this block from
3863 ; what it was before so there is no way the BPB
3864 ; in the region (if there is one) can be valid.
3865 ; Setting INIT_DRIVE to 2 means "I don't care if
3866 ; there is a valid boot record in this region,
3867 ; re-initialize it based on DEV_SIZE
3869 ; We can't do anything, so set DEV_SIZE
3870 ; to EMM_KSIZE and we're done.
3872 ; This is the EMM_KSIZE > DEV_SIZE case, it means the
3873 ; user MUST have edited his DEVICE = line.
3874 ; IF next EMM_REC is NOT free
3875 ; We can't shrink the allocation block,
3876 ; but we'll leave DEV_SIZE set to the user
3877 ; specification and let him waste memory.
3878 ; We set INIT_DRIVE to 2 because we're not
3879 ; sure what to do and this is safe and we're done.
3880 ; NOTE that this drive will get re-initialized
3881 ; on EVERY re-boot. Tough cookies.
3883 ; SHRINK the allocation block by adding
3884 ; the extra memory back onto EMM_AVAILK
3885 ; and subtracting it from EMM_KSIZE. Set
3886 ; INIT_DRIVE to 2 because we changed the
3887 ; allocation block size, and we're done.
3890 ; SECTOR_BUFFER containes POSSIBLE EMM_CTRL sector
3892 ; EXT_K is set to size of extended memory
3893 ; DEV_SIZE is set to user requested device size
3896 ; Error, message already printed
3898 ; ES:DI = BASE_ADDR for this drive from EMM_BASE of EMM_REC
3899 ; EMM_REC is marked EMM_ISDRIVER
3900 ; SECTOR_BUFFER must be written out, it contains an updated
3902 ; DEV_SIZE set to TRUE size
3904 ; An existing disk was found, region should be checked
3905 ; for valid MS-DOS volume
3907 ; A new block was allocated from the EMM_CTRL sector
3908 ; TERM_ADDR may be adjusted to include RESET_SYSTEM code and
3909 ; INT 19 and 9 vector patched if this is the first
3910 ; TYPE 1 or TYPE 3 RAMDrive in the system (no other
3911 ; EMM_MSDOS EMM_REC structures marked EMM_ISDRIVER).
3916 ; Specific to TYPE 1 and 3 drivers
3920 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
3923 MOV DI,OFFSET SECTOR_BUFFER
3924 MOV SI,OFFSET EMM_CONTROL
3928 JNZ no_emm_rec
; No EMM_CTRL
3929 ADD SI,EMM_TAIL_SIG
- 50
3930 ADD DI,EMM_TAIL_SIG
- 50
3934 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3935 ; JNZ SETCTRL ; No EMM_CTRL
3936 ; MOV DI,OFFSET SECTOR_BUFFER
3938 ; DEC AX ; Size in EMM_CTRL doesn't include EMM_CTRL
3939 ; CMP AX,[DI.EMM_TOTALK]
3940 ; JZ SCAN_DEV ; EMM_CTRL is valid
3942 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3944 dec [valid_emm
] ; signal prescence of emm record
3947 ; we have to decide which standard to use for installing the driver, the old or
3948 ; the new. driver type 3 - old, driver type 2 not u - new, u driver - old
3951 ; check if driver in extended
3953 cmp [driver_sel
],0 ; if driver not in extended memory
3954 jne old_st
; install according to old standard
3955 cmp [u_switch
],0h
; is it a u driver
3956 jne old_st
; if not go to install acc to new int15
3957 jmp new_st
; standard
3959 ; for olivetti u memory we still have to install according to ol' microsoft st
3962 cmp [valid_emm
],0h
; do we have a valid emm
3963 jne scan_dev
; if yes go to scan structures
3964 set_ctrl: ; else we have to install a new one
3965 MOV DI,OFFSET SECTOR_BUFFER
3967 MOV SI,OFFSET EMM_CONTROL
3969 REP MOVSW ; Move in initial EMM_CTRL
3972 DEC AX ; Size in EMM_CTRL doesn't include EMM_CTRL
3973 MOV [DI.EMM_TOTALK
],AX
3974 MOV [DI.EMM_AVAILK
],AX
3976 XOR BX,BX ; Will get tripped if a DOS dev found
3977 MOV SI,OFFSET SECTOR_BUFFER
; DS:SI points to EMM_CTRL
3979 ADD DI,EMM_RECORD
; DS:DI points to EMM records
3982 TEST [DI.EMM_FLAGS
],EMM_ALLOC
3984 JMP GOT_FREE_REC
; Must alloc new region
3987 CMP [DI.EMM_SYSTEM
],EMM_MSDOS
3988 JNZ NEXTREC
; Not MS-DOS
3989 TEST [DI.EMM_FLAGS
],EMM_ISDRIVER
3990 JNZ NEXTRECI
; Driver already in, I am not first driver
3991 CALL SET_RESET
; Set up INT 19,9 as per BX
3992 MOV AX,[DI.EMM_KSIZE
]
3994 JBE OK_SET_DEV
; If this is last record, must
3997 JZ OK_SET_DEV
; Exact match, Okay
3998 JB INSUFF_MEM
; User asked for more
3999 ; Size of found block is bigger than requested size.
4000 ; User MUST have edited CONFIG.SYS.
4003 TEST [DI.EMM_FLAGS
],EMM_ALLOC
4005 JZ SHRINK_BLOCK
; Next block is free, shrink
4010 SUB AX,[DEV_SIZE
] ; AX is amount to shrink
4011 ADD [SI.EMM_AVAILK
],AX
4013 MOV [DI.EMM_KSIZE
],AX
4016 INSUFF_MEM: ; Size of found block is smaller
4017 ; than requested size.
4020 TEST [DI.EMM_FLAGS
],EMM_ALLOC
4022 JNZ OK_SET_DEV
; Next block is NOT free, can't grow
4024 CMP [SI.EMM_AVAILK
],0
4025 JZ OK_SET_DEV
; Need SPECIAL check for this case so
4026 ; that INIT_DRIVE doesn't get set to 2
4029 NEG AX ; AX is amount we would like to grow
4030 SUB [SI.EMM_AVAILK
],AX
4032 ADD AX,[SI.EMM_AVAILK
] ; AX is MAX we can grow
4033 MOV [SI.EMM_AVAILK
],0 ; We take all that's left
4035 ADD [DI.EMM_KSIZE
],AX
4036 MOV AX,[DI.EMM_KSIZE
]
4038 MOV [INIT_DRIVE
],2 ; CANNOT TRUST BPB in boot sector
4041 OR [DI.EMM_FLAGS
],EMM_ISDRIVER
4042 LES DI,[DI.EMM_BASE
]
4043 XOR AX,AX ; Set zero, clear carry
4047 INC BX ; Flag that we ARE NOT first DOS device
4049 ADD DI,SIZE EMM_REC
; Next record
4052 MOV DX,OFFSET ERRMSG2
4061 MOV AX,[SI.EMM_AVAILK
]
4063 JB VERRR
; 16K is smallest device
4064 CALL SET_RESET
; Set INT 19,9 as per BX
4066 JBE GOTSIZE
; Not enough for user spec
4067 MOV AX,[DEV_SIZE
] ; User size is OK
4070 SUB [SI.EMM_AVAILK
],AX
4071 MOV [DI.EMM_KSIZE
],AX
4072 MOV [DI.EMM_SYSTEM
],EMM_MSDOS
4073 MOV [DI.EMM_FLAGS
],EMM_ALLOC
+ EMM_ISDRIVER
4075 SUB DI,SIZE EMM_REC
; Look at prev record to compute base
4076 MOV AX,[DI.EMM_KSIZE
]
4077 LES BX,[DI.EMM_BASE
]
4078 MOV DI,ES ; DI:BX is prev base
4080 MUL CX ; Mult size by 1024 to get # bytes
4081 ADD AX,BX ; Add size onto base to get next base
4084 MOV WORD PTR [DI.EMM_BASE
],AX
4085 MOV WORD PTR [DI.EMM_BASE
+ 2],DX
4086 LES DI,[DI.EMM_BASE
]
4087 XOR AX,AX ; Set zero, clear carry
4090 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4091 ; the new int15 standard
4094 dec [new_all
] ; indicate new standard allocation
4095 mov bx,[ext_k
] ; contiguous memory reported by int15
4096 cmp [valid_emm
],0 ; is there a valid emm record
4097 je no_adjust
; if not there no need to adjust
4098 ; the memory available
4099 ; else we have to find how much memory is already allocated by the microsoft
4100 ; emm control block and subtract this from the amount that is available. the
4101 ; memory allocated is totalk - availk + 1
4103 sub bx,1 ; subtract the emm ctrl record size
4104 mov di,offset sector_buffer
; set up to address the ctrl record
4106 mov ax,[di.emm_totalk
] ; ax <- totalk
4107 sub ax,[di.emm_availk
] ; ax <- totalk - availk
4108 sub bx,ax ; adjust memory available
4109 jc verrr
; if no memory go to abort
4111 cmp bx,128 ; is it the minimum required
4112 jb verrr
; if less go to abort
4114 ; the memory available has been found and is in bx. now compare it with
4115 ; requested device size and take the minimum of the two
4119 jb skip_adj_dev_size
; if enough space we don't need to adj
4121 mov [dev_size
],bx ; else we have compromise on dev size
4124 ; now that we have the correct dev size we should proceed with the installation
4125 ; of a new int 15 handler which will account for the memory grabbed by this guy
4127 mov bx,[ext_k
] ; get memory which was reported by int15
4128 add bx,[special_mem
] ; account for olivetti guys
4130 mov [int15_size
],bx ; this is the size thaat will be reported
4131 ; by the int 15 handler
4132 ; now install the int15 handler
4138 mov ax,(get_interrupt_vector
shl 8) or 15h
4140 mov word ptr [old_15
],bx
4141 mov word ptr [old_15
+2],es
4142 mov dx,offset int_15
4143 mov ax,(set_interrupt_vector
shl 8) or 15h
4150 ; set up int19 vector
4152 xor bx,bx ; for int19 to be installed
4155 ; now fill device base address in es:di
4158 sub ax,[dev_size
] ; this now has memory left
4159 mov cx,1024 ; we are going to find size in bytes
4160 mul cx ; dx:ax = ax * 1024
4161 add ax,word ptr [base_addr
] ;
4162 adc dx,word ptr [base_addr
+2] ;
4165 xor ax,ax ; to say that there
4166 inc ax ; was no dos volume reset 0
4169 ;** SET_RESET - Set up INT 19/INT 9 vectors
4171 ; This routine will do nothing if BX is non-zero
4172 ; otherwise it will install the INT 9 and INT 19
4173 ; code by saving the current INT 9 and INT 19
4174 ; vectors in OLD_9 and OLD_19 (NOTE: the change in the value of OLD_19
4175 ; to something other than -1 indicates that the vectors have been
4176 ; replaced), setting the vectors to point to INT_9 and INT_19,
4177 ; and adjusting TERM_ADDR to include the code as part of the resident
4181 ; BX is 0 if INT 19/9 code to be installed
4187 ; COMMON TO TYPE 1, 2, 3, 4 drivers
4191 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
4194 cmp [u_switch
],0 ; for uswitch don't bother
4200 MOV AX,(Get_Interrupt_Vector
SHL 8) OR 19H
4202 MOV WORD PTR [OLD_19
],BX
4203 MOV WORD PTR [OLD_19
+ 2],ES
4204 MOV DX,OFFSET INT_19
4205 MOV AX,(Set_Interrupt_Vector
SHL 8) OR 19H
4207 ; MOV AX,(Get_Interrupt_Vector SHL 8) OR 9H
4209 ; MOV WORD PTR [OLD_9],BX
4210 ; MOV WORD PTR [OLD_9 + 2],ES
4211 ; MOV DX,OFFSET INT_9
4212 ; MOV AX,(Set_Interrupt_Vector SHL 8) OR 9H
4214 MOV WORD PTR [TERM_ADDR
],OFFSET RESET_INCLUDE
4222 BREAK </E INIT
Code>
4224 ;** AT_EXT_INIT - Perform /E (TYPE 1) specific initialization
4226 ; This code does the drive TYPE specific initialization for TYPE 1
4229 ; Make sure running on 80286 IBM PC-AT compatible system by
4230 ; making sure the model byte at FFFF:000E is FC.
4231 ; Get the size of extended memory by using 8800H call to INT 15.
4232 ; and make sure it is big enough to accomodate a RAMDrive.
4233 ; Limit DEV_SIZE to the available memory found in the previous step
4234 ; by making DEV_SIZE smaller if necessary.
4235 ; Initialize the GLOBAL parts of the LOADALL information which
4236 ; are not set by each call to BLKMOV.
4237 ; CALL MM_SETDRIVE to look for EMM_CTRL and perform all the
4238 ; other initialization tasks.
4241 ; Invokation line parameter values set.
4244 ; Error, message already printed. Driver not installed.
4245 ; EMM_CTRL not marked (but MAY be initialized if
4246 ; a valid one was not found).
4248 ; BASE_ADDR set for this drive from EMM_BASE of EMM_REC
4249 ; BASE_RESET set from BASE_ADDR
4250 ; EMM_REC is marked EMM_ISDRIVER
4251 ; DEV_SIZE set to TRUE size
4252 ; INIT_DRIVE set appropriatly
4253 ; TERM_ADDR set to correct device end.
4254 ; RESET_SYSTEM code and INT 9/INT 19 code included,
4255 ; INT 19 and 9 vector patched if this is the first
4256 ; TYPE 1 RAMDrive in the system.
4261 ; Code is specific to TYPE 1 driver
4265 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
4267 call sys_det
; new routine to do more comprehensive checking
4271 MOV DX,OFFSET BAD_AT
4278 ;; patch the values of base_reset and base_addr to get the addressing right.
4280 cmp [U_SWITCH
],0 ;; patch the code for /U option
4283 ; mov word ptr [emm_ctrl_addr+2],ax ;; in resident part for reset code
4284 mov word ptr [base_reset
+2],ax ;; patching upper address
4285 mov word ptr [base_addr
+2],ax ;; to FA from 10
4288 INT 15H
; Get extended memory size
4289 MOV DX,OFFSET NO_MEM
4293 ;; If running on a 6300 PLUS, it is necessary to subtract any upper extended
4294 ;; memory from the value obtained by int 15 to determine the correct memory
4295 ;; available for a type /E RAMDrive. If loading a /U RAMDrive, it is necessary
4296 ;; to find out if there IS any upper extended memory.
4298 cmp [U_SWITCH
],0 ;; did we ask for upper extended memory
4300 call UpperMemCheck
;; yes, see if anything there
4301 jc ERR_RET
;; no, quit
4302 mov ax,384 ;; yes, but max allowed is 384K
4305 cmp [S5_FLAG
],S_OLIVETTI
;; if not 6300 PLUS, go on
4307 call UpperMemCheck
;; yes, see if 384K is there
4308 jc at001b
;; no, so int 15h is right
4309 sub ax,384 ;; yes, subtract 384K
4310 mov [special_mem
],384 ;; store special memory size
4313 MOV DX,OFFSET ERRMSG2
4315 ; CMP AX,17 ; 1k ident block plus 16k min Ramdrive
4319 ; DEC BX ; BX is MAX possible disk size
4321 JBE AT002
; DEV_SIZE OK
4322 MOV [DEV_SIZE
],BX ; Limit DEV_SIZE to available
4324 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4326 test [sys_flg
],M_386
4329 mov word ptr [cod_seg
],ax
4333 mov si,offset cs_des
4334 mov [si].bas_0_15
,ax
4335 mov [si].bas_16_23
,dl
4336 mov [si].bas_24_31
,dh
4338 mov si,offset emm_gdt
4339 add ax,offset start_gdt
4341 mov [si].gdt_base_0
,ax
4342 mov [si].gdt_base_2
,dx
4347 ; Init various pieces of LOADALL info
4350 ;;;; SIDT QWORD PTR [IDTDES]
4351 ;;;; SGDT QWORD PTR [GDTDES]
4353 ;;;; ; NOW The damn SXXX instructions store the desriptors in a
4354 ;;;; ; different order than LOADALL wants
4356 ;;;; MOV SI,OFFSET IDTDES
4357 ;;;; CALL FIX_DESCRIPTOR
4358 ;;;; MOV SI,OFFSET GDTDES
4359 ;;;; CALL FIX_DESCRIPTOR
4367 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4368 ;;* UpperMemCheck - Called by 6300 PLUS to verify existence of
4369 ;; upper extended memory of 384K at FA0000h
4371 ;; Returns carry set if no upper extended memory.
4373 ;; This routine is called only by a 6300 PLUS, and
4374 ;; it reads the hardware switch DSW2 to do the job.
4391 BREAK </A INIT
Code>
4393 ;** EMM device driver name
4395 ; The following datum defines the Above Board EMM 8 character
4396 ; device driver name that is looked for as part of TYPE 2
4397 ; specific initialization.
4399 ; This datum is specific to TYPE 2 drivers
4402 ABOVE_DEV_NAME
DB "EMMXXXX0"
4404 ;** ABOVE_INIT - Perform /A (TYPE 2) specific initialization
4406 ; This code performes the driver specific initialization for
4409 ; Swap ABOVE_BLKMOV code in for TYPE 1 code at BLKMOV
4410 ; Swap ABOVE_RESET code in for TYPE 1 code at RESET_SYSTEM
4411 ; Check to make sure EMM Above Board device driver is installed
4412 ; by looking for device name relative to INT 67H segment
4413 ; address. This is method 2 described on page 36 and 37
4414 ; of the Expanded Memory Manager Programming Specification.
4416 ; WARNING! If run on a version of DOS where all INT vectors
4417 ; are managed by the kernel, or on a system where some
4418 ; foreign program (not EMM.SYS) is also using INT 67H, this
4419 ; method will fail to find the EMM device driver.
4420 ; The reason this method was used rather than the more portable
4421 ; method 1 described on pages 33 and 34 of the EMM Programming
4422 ; Specification is that the DOS Installable Device Driver
4423 ; document makes a statement about which DOS system calls
4424 ; may be made in a device initialization routine, and
4425 ; OPEN, IOCTL, and CLOSE are not included in the allowed
4426 ; set. Adherance to the Installable Device Driver document,
4427 ; therefore, excludes the use of method 1.
4429 ; Check the EMM device status
4430 ; Get the EMM map window address and set BASE_ADDR
4431 ; Get the available Above Board memory
4432 ; Adjust DEV_SIZE to be consistent with the available memory if needed,
4433 ; and also round DEV_SIZE up so that it is a multiple of the 16K
4434 ; granularity of the Above Board memory.
4435 ; Allocate DEV_SIZE worth of Above Board memory and set ABOVE_PID.
4436 ; After this point we can use CTRL_IO and/or BLKMOV to
4437 ; read/write the memory we have allocated.
4438 ; Install the INT 9 and INT 19 code by calling SET_RESET with BX = 0.
4439 ; Adjust the TERM_ADDR set by SET_RESET to a more appropriate size.
4440 ; Call CHECK_DOS_VOL to look for a DOS volume and set INIT_DRIVE.
4441 ; IF INIT_DRIVE indicates that a DOS volume was found
4442 ; Check to make sure that the size of the found DOS
4443 ; volume is consistent with DEV_SIZE.
4445 ; Set INIT_DRIVE to 2 to indicate that the found volume
4446 ; is invalid and needs to be re-initialized.
4449 ; INTEL Expanded Memory Manager Programming Specification
4452 ; Invokation line parameter values set.
4454 ; ABOVE_BLKMOV code swapped in at BLKMOV
4455 ; ABOVE_RESET code swapped in at RESET_SYSTEM
4457 ; Error, message already printed. Driver not installed.
4458 ; No Above Board memory allocated.
4460 ; BASE_ADDR set to segment address of Above Board map window
4461 ; ABOVE_PID contains PID of allocated above board memory
4462 ; DEV_SIZE set to TRUE size
4463 ; INIT_DRIVE set appropriatly
4464 ; TERM_ADDR set to correct device end.
4465 ; RESET_SYSTEM code and INT 9/INT 19 code included.
4470 ; Code is specific to TYPE 2 driver
4474 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
4476 ; Swap above code into place
4480 MOV SI,OFFSET ABOVE_CODE
4481 MOV DI,OFFSET DRIVE_CODE
4482 MOV CX,OFFSET DRIVE_END
- OFFSET DRIVE_CODE
4484 MOV SI,OFFSET ABOVE_RESET
4485 MOV DI,OFFSET RESET_SYSTEM
4486 MOV CX,OFFSET RESET_INCLUDE
- OFFSET RESET_SYSTEM
4489 ; Check for presence of Above board memory manager
4491 MOV AX,(Get_Interrupt_Vector
SHL 8) OR 67H
4494 MOV SI,OFFSET ABOVE_DEV_NAME
4498 MOV DX,OFFSET NO_ABOVE
4506 ; Check memory status
4512 CMP AH,ABOVE_SUCCESSFUL
4514 CMP AH,ABOVE_ERROR_BUSY
4517 MOV DX,OFFSET BAD_ABOVE
4522 ; Get base address of map region and set BASE_ADDR
4524 MOV AH,ABOVE_GET_SEG
4526 CMP AH,ABOVE_ERROR_BUSY
4528 CMP AH,ABOVE_SUCCESSFUL
4530 MOV WORD PTR [BASE_ADDR
],0
4531 MOV WORD PTR [BASE_ADDR
+ 2],BX
4533 ; Allocate drive memory
4536 MOV AH,ABOVE_GET_FREE
4538 CMP AH,ABOVE_ERROR_BUSY
4540 CMP AH,ABOVE_SUCCESSFUL
4542 MOV AX,DX ; AX is total 16K pages
4543 ; BX is un-allocated 16K pages
4544 MOV DX,OFFSET NO_MEM
4547 MOV DX,OFFSET ERRMSG2
4548 OR BX,BX ; 16k is min Ramdrive
4551 JNZ AB001
; Avialable K is REAL big
4553 SHL BX,CL ; BX is un-allocated K
4555 JBE AB001
; DEV_SIZE OK
4556 MOV [DEV_SIZE
],BX ; Limit DEV_SIZE to available
4560 ; BX is K we want to allocate (limited by available K)
4564 MOV CX,4 ; Convert back to # of 16K pages
4566 TEST AX,0FH ; Even????
4568 INC BX ; Gotta round up
4572 MOV [DEV_SIZE
],BX ; Correct dev size too by rounding it up to
4573 ; next multiple of 16K, no sense wasting
4579 CMP AH,ABOVE_ERROR_BUSY
4581 CMP AH,ABOVE_SUCCESSFUL
4583 CMP AH,ABOVE_ERROR_MAP_CNTXT
4585 CMP AH,ABOVE_ERROR_OUT_OF_PIDS
4587 MOV DX,OFFSET ERRMSG2
4596 ; INSTALL ABOVE RESET handler
4601 ; The above RESET_SYSTEM handler is real small, and since we include it in
4602 ; EACH driver, we make sure the size is minimal
4604 MOV WORD PTR [TERM_ADDR
],OFFSET RESET_SYSTEM
+ (OFFSET ABOVE_RESET_END
- OFFSET ABOVE_RESET
)
4606 ; We are now in good shape. Can call BLKMOV to read drive
4608 CALL CHECK_DOS_VOL
; Snoop for DOS volume
4616 JNZ RETAB
; No DOS volume found
4618 ; We MUST check to see if the FOUND DOS volume is consistent
4622 MUL [SSIZE
] ; DX:AX is size of volume in bytes
4624 DIV CX ; AX is size in K
4626 JE RETAB
; Volume is OK
4628 MOV [INIT_DRIVE
],2 ; Force re-compute of volume
4633 BREAK <Drive
code for
/A driver
. Swapped
in at BLKMOV
>
4636 ; This label defines the start of the code swapped in at DRIVE_CODE
4638 ABOVE_CODE
LABEL WORD
4641 ; WARNING DANGER!!!!!!!
4643 ; This code is tranfered over the /E driver code at DRIVE_CODE
4645 ; ALL jmps etc. must be IP relative.
4646 ; ALL data references must be to cells at the FINAL, TRUE location
4647 ; (no data cells may be named HERE, must be named up at BLKMOV).
4648 ; OFFSET of ABOVE_BLKMOV relative to ABOVE_CODE MUST be the same as
4649 ; the OFFSET of BLKMOV relative to DRIVE_CODE.
4650 ; SIZE of stuff between ABOVE_CODE and ABOVE_END MUST be less than
4651 ; or equal to size of stuff between DRIVE_CODE and DRIVE_END.
4654 IF((OFFSET ABOVE_BLKMOV
- OFFSET ABOVE_CODE
) NE
(OFFSET BLKMOV
- OFFSET DRIVE_CODE
))
4655 %
out ERROR BLKMOV
, ABOVE_BLKMOV
NOT ALIGNED
4657 IF((OFFSET ABOVE_END
- OFFSET ABOVE_CODE
) GT
(OFFSET DRIVE_END
- OFFSET DRIVE_CODE
))
4658 %
out ERROR ABOVE
CODE TOO BIG
4662 DD ?
; 24 bit address of start of this RAMDRV
4663 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4664 ;** ABOVE_BLKMOV - Perform transfer for TYPE 2 driver
4666 ; This routine is the transfer routine for moving bytes
4667 ; to and from the Above Board memory containing the cache.
4669 ; The Above Board is implemented as 4 16K windows into the Above
4670 ; Board memory, giving a total window of 64K wich starts on some
4671 ; 16K boundary of the Above Board memory. Given that a DOS I/O
4672 ; request is up to 64K bytes starting on some sector boundary,
4673 ; the most general I/O picture is:
4675 ; |------------|------------|------------|------------|------------|
4676 ; | Above Brd | Above Brd | Above Brd | Above Brd | Above Brd |
4677 ; |Log page n |Log page n+1|Log page n+2|log page n+3|Log page n+4|
4678 ; |------------|------------|------------|------------|------------|
4680 ; | | |---------------- 64K bytes of sectors -------------|
4682 ; offset|------------------|------------------------| |
4683 ; of first| Number of words in | |
4684 ; byte of | first part of I/O that |---|---|
4685 ; I/O in | can be performed once Number
4686 ; first | logical pages n - n+3 of words
4687 ; Log page| are mapped into physical in tail
4688 ; | pages 0 - 3 part of I/O
4689 ; Location of that have
4690 ; first byte to be done
4691 ; of sector M, once logical
4692 ; the start sector page n+4 is
4693 ; of the I/O mapped into
4697 ; One or both of "Byte offset of first byte of I/O in first page" and
4698 ; "Number of words in tail part of I/O" may be zero depending on the
4699 ; size of the I/O and its start offset in the first logical page it is
4702 ; WARNING: IF A PRE-EMPTIVE MULTITASKING SYSTEM SCHEDULES A TASK WHICH
4703 ; IS USING THE ABOVE BOARD DURING THE TIME THIS DRIVER IS IN THE
4704 ; MIDDLE OF PERFORMING AN I/O, THE SYSTEM HAD BETTER MANAGE THE A
4705 ; BOARD MAPPING CONTEXT CORRECTLY OR ALL SORTS OF STRANGE UNPLEASANT
4706 ; THINGS WILL OCCUR.
4709 ; INTEL Expanded Memory Manager Programming Specification
4712 ; ES:DI is packet transfer address.
4713 ; CX is number of words to transfer.
4714 ; DX:AX is 32 bit start byte offset (0 = start of cache)
4715 ; BH is 1 for WRITE, 0 for READ
4717 ; BASE_ADDR set to point to Above Board mapping window in main memory
4718 ; This "input" is not the responsibility of the caller. It
4719 ; is up to the initialization code to set it up when the
4720 ; device is installed
4724 ; OK, operation performed successfully
4726 ; Error during operation, AL is error number
4731 ; This routine is specific to TYPE 2 driver
4733 ; sunilp - note that this has one limitation. in the case where
4734 ; one is using the above board for ramdrive and for
4735 ; the buffer then one is limited to 32k byte transfers
4737 ; tonyg - above limitation removed - now handles 64kb transfers
4738 ; which can overlap the page frame
4741 assume
ds:ramcode
,es:nothing
,ss:nothing
4743 ; save mapping context and return with error if save fails
4745 save_mapping_context
4749 ; find logical page number, offset of i/o in first page
4753 mov cx,1024*16 ; 16k bytes / page
4754 div cx ; dx:ax / 16k --> log page numb in ax
4755 ; --> offset of i/o in dx
4756 mov si,dx ; transfer offset to si
4757 mov dx,ax ; store the page number in dx
4760 ; find case and dispatch accordingly
4762 ; case 0 : user buffer below page map, can use aaron's code
4763 ; case 1 : user buffer above page map, can use aaron's code
4764 ; case 2 : user buffer partly/totally in page map, use pai's code
4769 ; if( final_user_off < pm_base_addr ) then case 0
4771 mov ax,di ; get user buffer initial offset into ax
4772 add ax,1 ; round up (add to get carry)
4773 rcr ax,1 ; convert to word offset
4774 dec cx ; convert word count to 0 based number
4775 add ax,cx ; user buffer final word offset
4776 shr ax,1 ; convert to segment
4779 mov bx,es ; get segment of buffer
4780 add ax,bx ; now we have the last segment of the user buffer
4782 sub ax,word ptr [base_addr
+2] ; compare against page map
4783 jc aar_cd
; if end below page map then execute old code
4785 ; if( initial_user_off < pm_base_addr ) then case 2
4788 mov bp,di ; get initial segment in bp
4791 sub bp,word ptr [base_addr
+2]
4792 jc within_pm
; case 2
4794 ; if ( initial_user_off >= pm_end_addr ) then case1
4801 within_pm: jmp new_code
; user buffer in page map
4802 ; so we need to execute new code
4807 ; Referring back to the diagram given above the following routine is
4808 ; to take care of transfer of the most general case.
4809 ; What this routine does is break every I/O down into the above parts.
4810 ; The first or main part of the I/O is performed by mapping 1 to 4
4811 ; sequential logical pages into the 4 physical pages and executing one
4812 ; REP MOVSW. If the tail word count is non-zero then the fith sequential
4813 ; logical page is mapped into physical page 0 and another REP MOVSW is
4817 ; Break I/O down as described above into main piece and tail piece
4818 ; Map the appropriate number of sequential pages (up to 4)
4819 ; into the page window at BASE_ADDR to set up the main piece
4821 ; Set appropriate seg and index registers and CX to perform the
4822 ; main piece of the I/O into the page window
4824 ; IF there is a tail piece
4825 ; Map the next logical page into physical page 0
4826 ; Reset the appropriate index register to point at phsical page 0
4827 ; Move tail piece word count into CX
4829 ; Restore Above Board page mapping context
4831 XOR BP,BP ; No tail page
4834 ; DX is first page #, SI is byte offset of start of I/O in first page
4838 SHR BX,1 ; # Words in first 16k page which are not part
4841 ADD BX,CX ; # of words we need to map to perform I/O
4843 AND DX,1FFFH
; DX is number of words to transfer last page
4844 ; remainder of div by words in 16K bytes
4845 MOV CL,13 ; Div by # words in 16K
4846 SHR BX,CL ; BX is number of pages to map (may need round up)
4847 OR DX,DX ; Remainder?
4849 INC BX ; Need one more page
4851 MOV CX,BX ; CX is total pages we need to map
4852 MOV BX,AX ; BX is first logical page
4853 CMP CX,4 ; We can map up to 4 pages
4855 MOV BP,DX ; Words to move in tail page saved in BP
4856 DEC CX ; Need second map for the 5th page
4858 SUB AX,DX ; Words to move in first 4 pages is input
4859 ; word count minus words in tail page
4860 PUSH AX ; Count for first mapping back on stack
4864 MOV AX,ABOVE_MAP
SHL 8 ; Physical page 0
4867 POP AX ; Recover correct AX register
4871 INT 67H
; Damn call ABOVE_MAP zaps BX,DX,AX
4875 JNZ MAP_ERR1
; error
4877 IF (ABOVE_SUCCESSFUL
)
4878 %
out ASSUMPTION
IN CODE THAT ABOVE_SUCCESSFUL
= 0 IS INVALID
4882 INC BX ; Next logical page
4884 INC AL ; Next physical page
4887 POP AX ; Clean stack
4888 POP CX ; Word count for first page mapping
4889 POP AX ; Operation in AH
4891 ; BX has # of next logical page (Tail page if BP is non-zero)
4892 ; BP has # of words to move in tail page (0 if no tail)
4893 ; CX has # of words to move in current mapping
4894 ; SI is offset into current mapping of start of I/O
4895 ; AH indicates READ or WRITE
4897 PUSH AX ; Save op for possible second I/O
4905 MOV DI,SI ; Start page offset to DI
4906 POP SI ; DS:SI is transfer addr
4909 MOV ES,WORD PTR [BASE_ADDR
+ 2] ; ES:DI -> start
4910 JMP SHORT FIRST_MOVE
4914 MOV DS,WORD PTR [BASE_ADDR
+ 2] ; DS:SI -> start
4924 ; Restore page mapping context
4925 PUSH AX ; Save possible error code
4926 PUSHF ; And carry state
4929 MOV AH,ABOVE_RESTORE_MAP_PID
4934 IF (ABOVE_SUCCESSFUL
)
4935 %
out ASSUMPTION
IN CODE THAT ABOVE_SUCCESSFUL
= 0 IS INVALID
4938 CMP AH,ABOVE_ERROR_BUSY
4940 CMP AH,ABOVE_ERROR_NO_CNTXT
4941 JZ ROK
; Ignore the invalid PID error
4943 POP DX ; Clean stack
4944 MOV AL,0cH ; General failure
4949 POPF ; Recover carry state
4950 POP AX ; and possible error code
4956 MOV AX,ABOVE_MAP
SHL 8 ; map logical page BX to phys page 0
4959 INT 67H
; Damn call ABOVE_MAP zaps BX,DX,AX
4963 JNZ MAP_ERR2
; Error
4965 IF (ABOVE_SUCCESSFUL
)
4966 %
out ASSUMPTION
IN CODE THAT ABOVE_SUCCESSFUL
= 0 IS INVALID
4970 POP AX ; Recover Op type
4977 XOR DI,DI ; ES:DI -> start of tail
4981 XOR SI,SI ; DS:SI -> start of tail
4988 CMP AH,ABOVE_ERROR_BUSY
; Busy?
4989 JZ MAP_NEXT
; Yes, wait till not busy (INTs are ON)
4990 ADD SP,6 ; Clean stack
4994 CMP AH,ABOVE_ERROR_BUSY
4998 MOV AL,02H ; Drive not ready
5003 ; this code has been written to handle te cases of overlapping usage
5004 ; of the above board page frame segment by the cache and user buffer
5005 ; assumption: in dos tracks cannot be more than 64 sectors long so
5006 ; in the worst case we shall have the user buffer occupying three
5007 ; pages is the page frame. we attempt to find the page that is
5008 ; available for the cache and use it repeatedly to access the cache
5010 ; above comment was for smartdrv. 128 sector reads are possible here
5011 ; see the kludge in step 2 and step 4 to handle this
5014 ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5016 ; ******************************************************
5017 ; [STEP1: determine the page we can use for the cache]
5019 ; if (initial_para_offset_user in page 1, 2 or 3 ) then {
5020 ; physical_cache_page = 0;
5021 ; cache_segment = above board segment;
5024 ; physical_cache_page = 3;
5025 ; cache_segment = above_board_segment + 3*1024;
5028 ; ******************************************************
5029 ; [STEP2: initial setup]
5031 ; count = user_count_requested;
5032 ; number_to_be_transferred = min ( count, (16K - si) >> 2 );
5033 ; exchange source and destination if necessary;
5035 ; *******************************************************
5036 ; [STEP3: set up transfer and do it]
5038 ; count = count - number_to_be_transferred;
5039 ; map_page cache_handle,physical_cache_page,logical_cache_page
5042 ; *******************************************************
5043 ; [STEP4: determine if another transfer needed and setup if so]
5045 ; if ( count == 0 ) then exit;
5046 ; if ( operation == read ) then source_offset = 0;
5047 ; else dest_offset = 0;
5048 ; number_to_be_transferred = min ( count, 8*1024 );
5049 ; logical_page_number++ ;
5051 ; *******************************************************
5052 ; [STEP5: go to do next block]
5055 ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5058 assume
ds:ramcode
,es:nothing
,ss:nothing
5062 ; bp : start para offset of user buffer from start of physical page frame
5063 ; ax : end para offset of user buffer in physical page frame
5064 ; di : transfer offset of user buffer
5065 ; es : transfer segment of user buffer
5066 ; dx : logical page number in cache
5067 ; si : offset from start in logical page number
5069 ; on stack { cx,bx } where cx = number of words, bx = read / write status
5071 ; [STEP1: finding physical cache page and page frame]
5074 ; assume is physical page 0
5076 xor al, al ; use page 0 for cache
5077 mov bx,word ptr [base_addr
+2]
5079 ; see if this assumption valid
5081 cmp bp, 4*1024 ; base is below start of page frame
5083 cmp bp,1024 ; is initial in page 1 or above
5084 jae ab$30
; if so or assumption is valid
5086 ; else we have to correct our assumption
5089 mov al, 3 ; use page 3 for cache
5090 add bx, 3*1024 ; segment of page 3
5092 ; initialise page frame segment
5095 add bp, 2*1024 ; base of second transfer
5101 ; [STEP2: initialising transfer parameters]
5104 pop bp ; bp will have count of words left to be transferred
5105 pop bx ; read / write status
5107 ; kludged to handle 64k byte transfers
5109 push cx ; base of second transfer
5111 ; initialise the number of words needed for a second transfer to 0
5115 ; compare the number to be transferred to 16k words. any more than this
5116 ; will have to be done in the second transfer
5118 cmp bp,16*1024 ; more than 16k word transfers
5119 jbe ab$301
; if not cx is fine
5120 mov cx,bp ; else cx = number of words - 16*1024
5121 mov bp,16*1024 ; and bp = 16*1024
5125 ; store this on stack
5129 ; end of kludge in step 2
5131 push bx ; save it back again
5132 push dx ; save this too
5134 ; initially si offset into logical page, so we can only do 16*1024 - si
5139 shr cx,1 ; convert to word count
5141 ; number to be transferred is the minimum of this and the user requested
5150 ; see if write, then we have to switch source with destination
5153 je ab$32
; if read we don't have to do anything
5154 ; else we have to switch
5158 ; set direction flag so that we don't have to do it repeatedly
5162 ; [STEP3: set up transfer and do it]
5166 ; update count of words still left to be transferred after this
5170 ; map the logical page in cache to the physical page selected
5172 mov bx,dx ; get logical page into bx
5173 ; al already holds the physical page #
5175 jnc ab$34
; suceeded ?
5181 jmp restore_mp
; and go to restore page map
5184 ; succeeded, do the transfer
5189 ; [STEP4: check if transfer done, if not set up for next block]
5190 ; [STEP5: go back to STEP3]
5195 je ab$40
; yes, go to finish up
5197 ; recover original dx and bx, increment dx and then save both again
5205 ; words to be transferred minimum of count and 8*1024 words
5207 mov cx,8*1024 ; 8k words in a page
5209 jbe ab$35
; if below or equal this is what we want
5211 mov cx,bp ; else we can transfer the whole count
5214 ; see whether cache src or dest and accordingly reset either si or di
5217 jne ab$36
; if write go to modify
5219 ; read, zero si and go back to step3
5222 jmp short ab$33
; to step 3
5225 ; write, zero di and go back to step3
5228 jmp short ab$33
; to step 3
5230 ; finishing up we have to restore the page map
5234 ; also kludged to handle 64k byte transfers
5238 pop bp ; number of words for second transfer
5239 pop ax ; base of second transfer
5240 or bp,bp ; are we done?
5241 jne ab$407
; no, we have to do another transfer
5242 jmp ab$405
; yes we can go to finish up
5243 ab$407
: ; apologies for such abominations
5244 push ax ; dummy transfer base
5246 push cx ; zero count for next time
5248 ; restore the mapping context
5251 push dx ; dx is destroyed by restore mapping context
5252 restore_mapping_context
5256 ; error we should quit here
5258 add sp, 4 ; throw base & count
5261 ; we need to save the mapping context again
5264 save_mapping_context
5265 jnc ab$406
; if we couldn't save it then error
5269 ; reset physical page to be mapped to 0 and ds or es to page map base
5270 ; and increment logical page if we have si = 0 (read) or di=0 (write)
5273 mov cx, word ptr [base_addr
+2]
5274 cmp ax, 1024 ; new base in page 0?
5284 or bh,bh ; read or write?
5285 jne ab$402
; if write branch
5288 ; read, reset ds to base address
5292 cmp si, cx ; at end of page?
5301 push bx ; save these
5304 cmp cx,bp ; is the cx appropriate
5305 jbe ab$404
; if yes go to do transfer
5306 mov cx,bp ; else cx <--- bp
5308 jmp ab$33
; and go to do transfer
5312 ; write, reset es to base address
5329 restore_mapping_context
5332 DW ?
; SPACE for ABOVE_PID
5335 ; This label defines the end of the code swapped in at DRIVE_CODE
5337 ABOVE_END
LABEL WORD
5339 BREAK <Drive
code for
/A driver
. Swapped
in at RESET_SYSTEM
>
5343 ; WARNING DANGER!!!!!!!
5345 ; This code is tranfered over the /E driver code at RESET_SYSTEM
5347 ; ALL jmps etc. must be IP relative.
5348 ; ALL data references must be to cells at the FINAL, TRUE location
5349 ; (no data cells may be named HERE, must be named up at RESET_SYSTEM).
5350 ; SIZE of stuff between ABOVE_RESET and ABOVE_RESET_END MUST be less than
5351 ; or equal to size of stuff between RESET_SYSTEM and RESET_INCLUDE.
5353 ; NOTE: EACH ABOVE BOARD driver has an INT 19 and 9 handler. This is
5354 ; different from /E and RESMEM in which only the first
5355 ; driver has an INT 19 and 9 handler.
5359 IF((OFFSET ABOVE_RESET_END
- OFFSET ABOVE_RESET
) GT
(OFFSET RESET_INCLUDE
- OFFSET RESET_SYSTEM
))
5360 %
out ERROR ABOVE_RESET
CODE TOO BIG
5364 ;** ABOVE_RESET perform TYPE 2 (/A) driver specific reboot code
5366 ; This code issues an ABOVE_DEALLOC call for the memory
5367 ; associated with this particular TYPE 2 RAMDrive since the
5368 ; system is being re-booted and the driver is "gone".
5377 ; This code is specific to TYPE 2 drivers
5381 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
5386 MOV AH,ABOVE_DEALLOC
; Close PID
5388 CMP AH,ABOVE_ERROR_BUSY
5395 ; This label defines the end of the code swapped in at RESET_SYSTEM
5397 ABOVE_RESET_END
LABEL BYTE
5399 BREAK <RESMEM INIT
Code>
5401 ;** RESMEM specific data
5403 ; The following datums are specific to the RESMEM (TYPE 3
5406 ; Specific to TYPE 3 or TYPE 4 drivers
5409 HIGH_SEG
DW ?
; Segment addr of "end of memory" from INT 12
5411 RAMSEG
DW 0 ; Segment addr of the start of RAMDrive memory.
5412 ; Basically a segment register version of
5415 CRTSEG EQU
0A000H ; Memory past this segment value is RESERVED
5416 ; Memory scan must stop here.
5419 ;** RESMEM_INIT - Perform RESMEM (TYPE 3 or 4) specific initialization
5421 ; This code performs the driver TYPE specific initialization for
5422 ; TYPE 3 and TYPE 4 drivers.
5425 ; The method used by this code to "find" valid RAM between
5426 ; the "end of memory" as determined from the INT 12 memory
5427 ; size and CRTSEG is to look for memory which will correctly
5428 ; store data. It looks on 1K boundaries. If the first 2 words
5429 ; of a 1k block are good, it is assumed that the rest of the
5430 ; 1K block is good without explicitly checking it. The scan
5431 ; is interested only in the FIRST block it finds. If two
5432 ; separated (by invalid RAM) blocks of RAM exist in the
5433 ; above range, the second block WILL NOT be found.
5434 ; NOTE that this can be fooled by a bad memory chip in
5435 ; a block of RAM. In this case RAMDrive will use the
5436 ; memory up to the bad spot and ignore the rest.
5437 ; Also note that since 16K is the minimum RAMDrive
5438 ; size, and the EMM_CTRL sector takes 1k, a block
5439 ; of size < 17K results in an insufficient memory error.
5441 ; Since access to invalid RAM (RAM that isn't present)
5442 ; results in a parity error, the above scan must be done
5443 ; with parity checking disabled.
5445 ; Since the ROM BIOS memory initialization code and tests
5446 ; is only run on the memory indicated by INT 12, one of
5447 ; the things this code must do when it finds memory "above
5448 ; INT 12" is make sure all of the parity bits are set correctly.
5449 ; This is accomplished easily by just copying the memory to
5452 ; The scan is NON-DESTRUCTIVE so that any data contained in
5453 ; the memory will not be destroyed.
5455 ; The result of this scan also makes the determination between
5456 ; a TYPE 3 and TYPE 4 RAMDrive. If memory is found, then we're
5457 ; TYPE 3. If no memory is found, then we're TYPE 4.
5460 ; RESMEM_BLKMOV code swapped in at BLKMOV
5461 ; RESMEM_RESET code swapped in at RESET_SYSTEM
5462 ; NOTE: This step is not needed for a TYPE 4 driver
5463 ; since TYPE 4 NEVER has an INT 9 or INT 19 handler,
5464 ; but it isn't harmful either, so we do it always.
5465 ; Issue INT 12 to get size of memory
5466 ; Convert INT 12 result to segment address of first byte after system
5468 ; IF this segment address is equal to or grater than CRTSEG
5469 ; There cannot be any memory "above INT 12" so we are TYPE 4.
5470 ; Skip the memory scan since there is no memory to scan and
5471 ; go to the TYPE 4 init code at CASE1.
5472 ; Disable parity checking so access to non-existent RAM won't crash
5474 ; Perform the memory scan. This starts at FOO and ends at HAVE_MEM
5475 ; if we find some valid memory, or at CASE1 if we don't.
5476 ; A word about the scan.
5477 ; There are two cases for valid RAM.
5478 ; 1.) Valid memory starts at the INT 12 address
5479 ; 2.) There is invalid RAM for a while, then valid RAM starts.
5480 ; The DX register is used to tell us what is going on. It is
5481 ; non-zero if we are skipping over invalid RAM looking for
5482 ; some valid RAM (case 2), or 0 is we have found some valid RAM
5483 ; (case 1, or case 2 after skipping invalid RAM) and are scanning
5484 ; to set parity and find the end of the valid RAM.
5485 ; RAMSEG is given the initial value of 0 to indicate we have not
5486 ; found the start of a valid block.
5487 ; When the scan is finished ENABLE_PARITY is called to turn parity
5489 ; IF we have valid RAM and end at HAVE_MEM
5491 ; RAMSEG contains the segment address of the start of the block
5492 ; BX is the segment address of the end of the block
5493 ; Subtract RAMSEG from BX to get size of region in paragraphs
5494 ; Convert size in Paragraphs to size in K
5495 ; Check that size is AT LEAST 17k (minimum size)
5496 ; Jump to GOT_RESMEM if OK else error
5497 ; Set EXT_K to size of block
5498 ; Adjust DEV_SIZE if bigger than EXT_K - 1 (-1 for EMM_CTRL)
5499 ; Convert RAMSEG to 32 bit address and set it into BASE_ADDR
5500 ; This sets BASE_ADDR to point to EMM_CTRL sector.
5501 ; Set BASE_RESET to BASE_ADDR plus 1024
5502 ; Call MM_SETDRIVE to complete TYPE 3 specific initialization
5503 ; ELSE we end up at CASE1
5505 ; Set RESMEM_SPECIAL to indicate TYPE 4
5506 ; Set INIT_DRIVE to 2 (DOS volume MUST be initialized)
5507 ; Set BASE_ADDR to be the first para boundary after the resident
5508 ; code (which DOES NOT include INT 19/INT 9 code).
5509 ; Compute TERM_ADDR based on DEV_SIZE Kbytes of device starting at
5511 ; NOTE: We must make sure the specified DEV_SIZE is reasonable:
5512 ; It must not be bigger than 10 bits (1 Meg)
5513 ; as this is the memory limit of the 8086.
5514 ; It must not be so big that there is less than 48k of system
5515 ; memory after the device is installed.
5516 ; This is checked by computing the segment address
5517 ; of the end of the device and comparing it to the
5518 ; INT 12 memory end address minus 48k worth of paragraphs
5521 ; Invokation line parameter values set.
5523 ; RESMEM_BLKMOV code swapped in at BLKMOV
5524 ; RESMEM_RESET code swapped in at RESET_SYSTEM
5525 ; Determination of TYPE 3 or TYPE 4 made by setting RESMEM_SPECIAL
5528 ; Error, message already printed. Driver not installed.
5530 ; EMM_CTRL not marked (but MAY be initialized if
5531 ; a valid one was not found).
5533 ; DEV_SIZE set to TRUE size
5534 ; INIT_DRIVE set appropriatly
5536 ; BASE_ADDR set for this drive from EMM_BASE of EMM_REC
5537 ; BASE_RESET set from BASE_ADDR
5538 ; EMM_REC is marked EMM_ISDRIVER
5539 ; TERM_ADDR set to correct device end.
5540 ; RESET_SYSTEM code and INT 9/INT 19 code included,
5541 ; INT 19 and 9 vector patched if this is the first
5542 ; TYPE 3 RAMDrive in the system.
5544 ; BASE_ADDR set for this drive by computing address of
5545 ; start of memory after RAMDrive code.
5546 ; BASE_RESET set from BASE_ADDR
5547 ; TERM_ADDR set to correct device end which includes
5548 ; the memory taken up by the RAMDrive itself.
5553 ; Code is specific to TYPE 3 and TYPE 4 drivers
5557 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
5559 ; Swap RESMEM code into place
5563 MOV SI,OFFSET RESMEM_CODE
5564 MOV DI,OFFSET DRIVE_CODE
5565 MOV CX,OFFSET DRIVE_END
- OFFSET DRIVE_CODE
5567 MOV SI,OFFSET RESMEM_RESET
5568 MOV DI,OFFSET RESET_SYSTEM
5569 MOV CX,OFFSET RESET_INCLUDE
- OFFSET RESET_SYSTEM
5572 ; We have THREE cases to contend with:
5574 ; 1. There is NO memory above the INT 12H switch setting.
5575 ; In this case we will use the user specified device
5576 ; size (within limits) to allocate some memory as part
5577 ; of the RAMDRIVE.SYS resident image.
5578 ; NOTE: This type of a RAMDrive will not live through a warm boot
5580 ; 2. There is memory immediately after the INT 12H memory size.
5581 ; We will check for a EMM_CTRL there etc.
5583 ; 3. There is memory after the INT 12H memory size, but not
5584 ; Immediately after.
5585 ; We will check for a EMM_CTRL there etc.
5587 INT 12H
; Get size of memory set on switches
5593 DEB1MES
DB 13,10,"INT 12 returned $"
5600 MOV DX,OFFSET DEB1MES
5612 SHL AX,CL ; Convert to Segment register value
5613 MOV BX,AX ; Save in BX
5614 MOV [HIGH_SEG
],AX ; And here
5617 ;*****************************************************************************
5618 ; Ramdrives installed between int12 reported memory and crtseg (A000h) are
5619 ; no longer allowed because on several machines including the model 50/60
5620 ; and the Tandy AT clone this area is used for something else. The idea to
5621 ; install a ramdrive in system memory is bad anyway but we shall still support
5622 ; the installation of a ramdrive in low memory as part of the driver. isp
5624 ; **START OF CODE REMOVED
5634 ; JAE CASE1 ; No memory to scan
5638 ; OR AL,20H ; Turn off parity interrupt
5639 ; JMP FOO ; 286 back to back IN OUT bug fix
5646 ; MOV ES,BX ;Segment to scan for valid memory
5653 ; XOR DX,DX ; DX = 0 means skipping memory
5654 ; MOV [RAMSEG],BX ; This is the start of our memory
5660 ;DEB2MES DB 13,10,"CASE 1 Ramseg $"
5667 ; MOV DX,OFFSET DEB2MES
5680 ; MOV DX,1 ; DX = 1 means skipping hole
5681 ; CMP [RAMSEG],0 ; If ramseg is NZ we are done,
5682 ; JZ NEXT_K ; have case 2 or 3
5683 ; CALL ENABLE_PARITY
5686 ; ; Driver is TYPE 3
5688 ; SUB BX,[RAMSEG] ; BX is Para of RAMDRV region
5690 ; SHR BX,CL ; BX is K in region
5691 ; CMP BX,17 ; Ik EMM_CTRL, 16k min ramdrive
5697 ;DEB3MESA DB 13,10,"CASE 3 Ramseg $"
5698 ;DEB3MESB DB " AVAIL K $"
5705 ; MOV DX,OFFSET DEB3MESA
5709 ; MOV DX,OFFSET DEB3MESB
5728 ; MOV ES,BX ;Segment to scan for valid memory
5731 ; JNZ AT_DIS ;No, detected discontinuity
5740 ; ADD BX,64 ; Next K
5743 ; CALL ENABLE_PARITY
5746 ;***END OF CODE REMOVED***
5747 ;*****************************************************************************
5758 DEB4MES
DB 13,10,"CASE 1$"
5765 MOV DX,OFFSET DEB4MES
5776 INC [RESMEM_SPECIAL
] ; Flag SPECIAL case for INIDRV
5777 MOV [INIT_DRIVE
],2 ; This type must ALWAYS be inited
5779 ; Compute BASE_ADDR to be right after DEVICE_END, NO INT 19/9 handler
5781 MOV AX,OFFSET DEVICE_END
5782 ADD AX,15 ; Para round up
5784 SHR AX,CL ; # of para in RAMDrive resident code
5786 ADD AX,DX ; AX is seg addr of start of RAMDrive
5789 MUL CX ; DX:AX is byte offset of that many paras
5790 MOV WORD PTR [BASE_ADDR
],AX
5791 MOV WORD PTR [BASE_ADDR
+ 2],DX
5794 ; Compute correct ending address and set TERM_ADDR
5795 ; Check that there is at least 48k of system memory after device end
5796 ; AX is the segment address of the start of the device
5798 MOV DX,[DEV_SIZE
] ; Get size in K
5800 ; DEV_SIZE can be at most a 10 bit number as that is 1 Meg, the memory
5803 TEST DX,0FC00H ; If any of high 6 bits set, too big
5806 SHL DX,CL ; DX is # of PARA in that many k
5807 ADD AX,DX ; AX is end seg addr
5808 JC RES_NOMEM
; Overflow
5810 ; Make sure at least 48K left after device
5813 SUB DX,0C00H ; 48K worth of PARAs left for system
5819 DEB5MESA
DB " Max end is $"
5820 DEB5MESB
DB " end is $"
5827 MOV DX,OFFSET DEB5MESA
5834 MOV DX,OFFSET DEB5MESB
5847 JA RES_NOMEM
; Too big
5848 MOV WORD PTR [TERM_ADDR
],0
5849 MOV WORD PTR [TERM_ADDR
+ 2],AX
5855 DEB6MES
DB " OK term $"
5862 MOV DX,OFFSET DEB6MES
5876 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
5877 MOV DX,OFFSET ERRMSG2
5885 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
5887 ; Completion of TYPE 3 initialization.
5888 ; RAMSEG is start seg addr of ramdrv region, BX is its size in K
5894 DEC BX ; BX is MAX possible disk size
5896 JBE RES002
; DEV_SIZE is OK
5897 MOV [DEV_SIZE
],BX ; Limit DEV_SIZE to available K
5902 MOV WORD PTR [BASE_ADDR
],AX
5903 MOV WORD PTR [BASE_ADDR
+ 2],DX
5906 MOV WORD PTR [BASE_RESET
],AX
5907 MOV WORD PTR [BASE_RESET
+ 2],DX
5912 ;** ENABLE_PARITY - Turn on parity checking of IBM PC AT XT
5914 ; This routine enables the memory parity checking on an IBM PC
5922 ; IBM PC Technical Reference manual for any PC family member
5924 ; Code is specific to TYPE 3 and TYPE 4 drivers
5928 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
5930 AND AL,NOT 20H
;Re-enable parity checking
5931 JMP BAR
; 286 back to back IN OUT bug fix
5936 ;** TEST_RAM - Check if valid RAM exists and reset parity if it does
5938 ; This routine checks for valid RAM is a 1k block by performing
5939 ; various tests on the first two words of the block. If the RAM
5940 ; is valid, the parity of the 1k block is set by copying the block
5944 ; See if first word will store its own compliment
5945 ; See if read first word writes out correctly (also resets first
5946 ; word to its original value)
5947 ; See if second word will store a fixed value "AR"
5948 ; On this test we wait a while between the store and
5949 ; the test to allow the buss to settle.
5952 ; DS:SI = ES:DI -> a 1k region of RAM to be tested
5953 ; PARITY CHECKING DISABLED
5955 ; Zero set if RAM is valid
5956 ; Zero reset if RAM is invalid
5960 ; Code is specific to TYPE 3 and TYPE 4 drivers
5964 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
5965 LODSW ; See what's there
5967 MOV [DI],AX ; See if memory can store complement
5968 CMP AX,[DI] ; Memory OK?
5969 JNZ RET007
; Not valid RAM
5971 STOSW ; Restore correct value
5972 CMP AX,[DI - 2] ; Memory OK?
5973 JNZ RET007
; Not valid RAM
5975 MOV WORD PTR [DI],"AR" ; Store fixed value
5980 CMP WORD PTR [DI],"AR" ; Did it store?
5981 JNZ RET007
; Not Valid RAM
5982 STOSW ; Restore correct value
5983 MOV CX,510 ; Copy to self to reset parity in this 1k block
5988 BREAK <Drive
code for resmem driver
. Swapped
in at BLKMOV
>
5991 ; This label defines the start of the TYPE 3 and 4 code swapped
5994 RESMEM_CODE
LABEL WORD
5997 ; WARNING DANGER!!!!!!!
5999 ; This code is tranfered over the /E driver code at DRIVE_CODE
6001 ; ALL jmps etc. must be IP relative.
6002 ; ALL data references must be to cells at the FINAL, TRUE location
6003 ; (no data cells may be named HERE, must be named up at BLKMOV).
6004 ; OFFSET of RESMEM_BLKMOV relative to RESMEM_CODE MUST be the same as
6005 ; the OFFSET of BLKMOV relative to DRIVE_CODE.
6006 ; SIZE of stuff between RESMEM_CODE and RESMEM_END MUST be less than
6007 ; or equal to size of stuff between DRIVE_CODE and DRIVE_END.
6010 IF((OFFSET RESMEM_BLKMOV
- OFFSET RESMEM_CODE
) NE
(OFFSET BLKMOV
- OFFSET DRIVE_CODE
))
6011 %
out ERROR BLKMOV
, RESMEM_BLKMOV
NOT ALIGNED
6013 IF((OFFSET RESMEM_END
- OFFSET RESMEM_CODE
) GT
(OFFSET DRIVE_END
- OFFSET DRIVE_CODE
))
6014 %
out ERROR RESMEM
CODE TOO BIG
6018 DD ?
; 24 bit address of start of this RAMDRV
6020 ;** RESMEM_BLKMOV - Perform transfer for TYPE 3 and 4 driver
6022 ; This routine is the transfer routine for moving bytes
6023 ; to and from a RAMDrive located in main memory.
6026 ; Convert start address into segreg index reg pair
6027 ; Mov computed segreg index reg pairs into correct registers
6028 ; Execute REP MOVSW to perform transfer
6031 ; ES:DI is packet transfer address.
6032 ; CX is number of words to transfer.
6033 ; DX:AX is 32 bit start byte offset (0 = sector 0 of RAMDrive drive)
6034 ; BH is 1 for WRITE, 0 for READ
6036 ; BASE_ADDR set to point to start of RAMDrive memory
6037 ; This "input" is not the responsibility of the caller. It
6038 ; is up to the initialization code to set it up when the
6039 ; device is installed
6043 ; OK, operation performed successfully
6045 ; Error during operation, AL is error number
6050 ; This routine is specific to TYPE 3 and 4 drivers
6054 ASSUME
DS:RAMCODE
,ES:NOTHING
,SS:NOTHING
6056 ADD AX,WORD PTR [BASE_ADDR
]
6057 ADC DX,WORD PTR [BASE_ADDR
+ 2]
6060 DIV CX ; AX is seg reg value, DX is index register
6085 ; This label defines the end of the RESMEM code swapped in at BLKMOV
6087 RESMEM_END
LABEL WORD
6089 BREAK <Drive
code for resmem driver
. Swapped
in at RESET_SYSTEM
>
6093 ; WARNING DANGER!!!!!!!
6095 ; This code is tranfered over the /E driver code at RESET_SYSTEM
6097 ; ALL jmps etc. must be IP relative.
6098 ; ALL data references must be to cells at the FINAL, TRUE location
6099 ; (no data cells may be named HERE, must be named up at RESET_SYSTEM).
6100 ; SIZE of stuff between RESMEM_RESET and RESMEM_RESET_END MUST be less than
6101 ; or equal to size of stuff between RESET_SYSTEM and RESET_INCLUDE.
6104 IF((OFFSET RESMEM_RESET_END
- OFFSET RESMEM_RESET
) GT
(OFFSET RESET_INCLUDE
- OFFSET RESET_SYSTEM
))
6105 %
out ERROR RESMEM_RESET
CODE TOO BIG
6109 ;** RESMEM_RESET perform TYPE 3 (RESMEM) driver specific reboot code
6111 ; This code performs the EMM_ISDRIVER reset function as described
6112 ; in EMM.ASM for all EMM_REC structures which are EMM_ALLOC and
6113 ; EMM_ISDRIVER and of type EMM_MSDOS.
6122 ; This code is specific to TYPE 3 drivers
6126 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
6138 MOV AX,WORD PTR [BASE_ADDR
]
6139 MOV DX,WORD PTR [BASE_ADDR
+ 2]
6140 SUB AX,1024 ; Point back to EMM block
6143 ; NOTE: We can address the EMM block by just backing up
6144 ; by 1024 bytes from BASE_ADDR because the RESET_SYSTEM handler
6145 ; is in the FIRST RAMDrive driver
6148 DIV CX ; AX is seg reg, DX is index reg
6151 MOV SI,DX ; DS:SI -> EMM_CTRL
6157 ; Scan EMM_CTRL for all ISDRIVER MS-DOS regions and turn off ISDRIVER
6159 TEST [DI.EMM_FLAGS
],EMM_ALLOC
6161 TEST [DI.EMM_FLAGS
],EMM_ISDRIVER
6162 JZ NEXTRECRY
; No Driver
6163 CMP [DI.EMM_SYSTEM
],EMM_MSDOS
6165 AND [DI.EMM_FLAGS
],NOT EMM_ISDRIVER
6182 ; This label defines the end of the RESMEM code swapped in at RESET_SYSTEM
6184 RESMEM_RESET_END
LABEL BYTE
6186 BREAK <messages
and common data>
6188 ;** Message texts and common data
6190 ; Init data. This data is disposed of after initialization.
6191 ; it is mostly texts of all of the messages
6193 ; COMMON to TYPE 1,2,3 and 4 drivers
6196 ; translatable messages moved to message module (SP)
6198 EXTRN NO_ABOVE
:BYTE,BAD_ABOVE
:BYTE,BAD_AT
:BYTE,NO_MEM
:BYTE
6199 EXTRN ERRMSG1
:BYTE,ERRMSG2
:BYTE,INIT_IO_ERR
:BYTE,BADVERMES
:BYTE
6200 EXTRN HEADERMES
:BYTE,PATCH2X
:BYTE,DOS_DRV
:BYTE
6201 EXTRN STATMES1
:BYTE,STATMES2
:BYTE,STATMES3
:BYTE
6202 EXTRN STATMES4
:BYTE,STATMES5
:BYTE
6203 db "RAMDrive is a trademark of Microsoft Corporation."
6204 db "This program is the property of Microsoft Corporation."
6206 VOLID
DB 'MS-RAMDRIVE',ATTR_VOLUME_ID
6208 DW 1100000000000000B ;12:00:00
6209 DW 0000101011001001B ;JUN 9, 1985
6212 SECTOR_BUFFER
DB 1024 DUP(0)
6214 RAMDrive_END
LABEL BYTE