diff options
Diffstat (limited to 'v4.0/src/DEV/RAMDRIVE')
| -rw-r--r-- | v4.0/src/DEV/RAMDRIVE/ABOVE.INC | 61 | ||||
| -rw-r--r-- | v4.0/src/DEV/RAMDRIVE/AB_MACRO.INC | 180 | ||||
| -rw-r--r-- | v4.0/src/DEV/RAMDRIVE/DEVSYM.INC | 128 | ||||
| -rw-r--r-- | v4.0/src/DEV/RAMDRIVE/DIRENT.INC | 56 | ||||
| -rw-r--r-- | v4.0/src/DEV/RAMDRIVE/EMM.INC | 223 | ||||
| -rw-r--r-- | v4.0/src/DEV/RAMDRIVE/LOADALL.INC | 35 | ||||
| -rw-r--r-- | v4.0/src/DEV/RAMDRIVE/MAKEFILE | 36 | ||||
| -rw-r--r-- | v4.0/src/DEV/RAMDRIVE/MESSAGES.ASM | 82 | ||||
| -rw-r--r-- | v4.0/src/DEV/RAMDRIVE/MI.INC | 18 | ||||
| -rw-r--r-- | v4.0/src/DEV/RAMDRIVE/RAMDRIVE.ASM | 6218 | ||||
| -rw-r--r-- | v4.0/src/DEV/RAMDRIVE/RAMDRIVE.LNK | 3 | ||||
| -rw-r--r-- | v4.0/src/DEV/RAMDRIVE/SYSCALL.INC | 146 |
12 files changed, 7186 insertions, 0 deletions
diff --git a/v4.0/src/DEV/RAMDRIVE/ABOVE.INC b/v4.0/src/DEV/RAMDRIVE/ABOVE.INC new file mode 100644 index 0000000..52878c8 --- /dev/null +++ b/v4.0/src/DEV/RAMDRIVE/ABOVE.INC | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | BREAK <ABOVE BOARD Equates> | ||
| 2 | |||
| 3 | ; | ||
| 4 | ; Assorted equates for use with Intel Above Board | ||
| 5 | ; | ||
| 6 | |||
| 7 | ; | ||
| 8 | ; EMM INT 67H Function codes | ||
| 9 | ; | ||
| 10 | ABOVE_STATUS EQU 40H | ||
| 11 | ABOVE_GET_SEG EQU 41H | ||
| 12 | ABOVE_GET_FREE EQU 42H | ||
| 13 | ABOVE_ALLOC EQU 43H | ||
| 14 | ABOVE_MAP EQU 44H | ||
| 15 | ABOVE_DEALLOC EQU 45H | ||
| 16 | ABOVE_GET_VERSION EQU 46H | ||
| 17 | ABOVE_SAVE_MAP_PID EQU 47H | ||
| 18 | ABOVE_RESTORE_MAP_PID EQU 48H | ||
| 19 | |||
| 20 | ; | ||
| 21 | ; NEW call not implemented in version 1.00 Above Board | ||
| 22 | ; | ||
| 23 | ABOVE_GETSET_MAP EQU 4EH | ||
| 24 | ; | ||
| 25 | ; 4EH AX equates for subfunctions | ||
| 26 | ; | ||
| 27 | ABOVE_GETSET_GET EQU 4E00H | ||
| 28 | ABOVE_GETSET_SET EQU 4E01H | ||
| 29 | ABOVE_GETSET_GETSET EQU 4E02H | ||
| 30 | |||
| 31 | |||
| 32 | ; | ||
| 33 | ; "Maintenance" calls | ||
| 34 | ; | ||
| 35 | ABOVE_GET_IOPORT EQU 49H | ||
| 36 | ABOVE_GET_MAP_ARRAY EQU 4AH | ||
| 37 | ABOVE_GET_PIDS EQU 4BH | ||
| 38 | ABOVE_GET_PAGES EQU 4CH | ||
| 39 | ABOVE_GET_ALLOC EQU 4DH | ||
| 40 | |||
| 41 | |||
| 42 | ; | ||
| 43 | ; EMM INT 67H AH return values | ||
| 44 | ; | ||
| 45 | ABOVE_SUCCESSFUL EQU 0 | ||
| 46 | ABOVE_ERROR_SOFTWARE EQU 80H | ||
| 47 | ABOVE_ERROR_HARDWARE EQU 81H | ||
| 48 | ABOVE_ERROR_BUSY EQU 82H | ||
| 49 | ABOVE_ERROR_BAD_PID EQU 83H | ||
| 50 | ABOVE_ERROR_BAD_FUNC EQU 84H | ||
| 51 | ABOVE_ERROR_OUT_OF_PIDS EQU 85H | ||
| 52 | ABOVE_ERROR_MAP_CNTXT EQU 86H | ||
| 53 | ABOVE_ERROR_INSUFF_MEM EQU 87H | ||
| 54 | ABOVE_ERROR_INSUFF_FREE EQU 88H | ||
| 55 | ABOVE_ERROR_ALLOC_ZERO EQU 89H | ||
| 56 | ABOVE_ERROR_LOG_INVALID EQU 8AH | ||
| 57 | ABOVE_ERROR_PHYS_INVALID EQU 8BH | ||
| 58 | ABOVE_ERROR_CNTXT_NO_STACK EQU 8CH | ||
| 59 | ABOVE_ERROR_SECOND_SAVE EQU 8DH | ||
| 60 | ABOVE_ERROR_NO_CNTXT EQU 8EH | ||
| 61 | ABOVE_ERROR_BAD_PARM EQU 8FH | ||
diff --git a/v4.0/src/DEV/RAMDRIVE/AB_MACRO.INC b/v4.0/src/DEV/RAMDRIVE/AB_MACRO.INC new file mode 100644 index 0000000..10fb733 --- /dev/null +++ b/v4.0/src/DEV/RAMDRIVE/AB_MACRO.INC | |||
| @@ -0,0 +1,180 @@ | |||
| 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 2 | ; | ||
| 3 | ; MACRO definitions for expanded memory manager | ||
| 4 | ; | ||
| 5 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 6 | ; | ||
| 7 | ; 1. MACRO to save mapping context in case somebody else has | ||
| 8 | ; mapped the page registers. | ||
| 9 | ; | ||
| 10 | save_mapping_context macro | ||
| 11 | local save_agn_m,save_err_m,save_ok_m,save_exit_m | ||
| 12 | ; | ||
| 13 | ; the save mapping call for the above board --> | ||
| 14 | ; | ||
| 15 | ; mov ah,47h | ||
| 16 | ; mov dx,handle | ||
| 17 | ; int 67h | ||
| 18 | ; | ||
| 19 | ; on return ax = 0 signifies success | ||
| 20 | ; | ||
| 21 | ; | ||
| 22 | push ax ; save registers | ||
| 23 | push dx | ||
| 24 | ; | ||
| 25 | ; set up emm registers and execute call to save mapping context | ||
| 26 | ; | ||
| 27 | save_agn_m: | ||
| 28 | mov dx,cs:[above_pid] ; get emm handle | ||
| 29 | mov ah,above_save_map_pid ; save map call | ||
| 30 | int 67h ; call the manager | ||
| 31 | or ah,ah ; is there an error? | ||
| 32 | jz save_ok_m ; if not we are done | ||
| 33 | ; | ||
| 34 | ; error in saving mapping context, check for error | ||
| 35 | ; | ||
| 36 | cmp ah,above_error_busy ; if the emm manager was busy | ||
| 37 | jz save_agn_m ; we would like to try again | ||
| 38 | ; | ||
| 39 | ; unrecoverable error, indicate error type in al | ||
| 40 | ; | ||
| 41 | pop dx | ||
| 42 | pop dx ; pop the regs off the stack | ||
| 43 | ; | ||
| 44 | mov al,02h ; drive not ready | ||
| 45 | cmp ah,above_error_cntxt_no_stack ; | ||
| 46 | jz save_err_m | ||
| 47 | cmp ah,above_error_second_save ; | ||
| 48 | ja save_err_m | ||
| 49 | mov al,0ch ; general failure | ||
| 50 | save_err_m: | ||
| 51 | stc | ||
| 52 | jmp short save_exit_m | ||
| 53 | save_ok_m: | ||
| 54 | clc | ||
| 55 | pop dx | ||
| 56 | pop ax ; restore registers | ||
| 57 | save_exit_m: | ||
| 58 | endm | ||
| 59 | ; | ||
| 60 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 61 | ; | ||
| 62 | ; 2. MACRO to restore the mapping context saved earlier | ||
| 63 | ; | ||
| 64 | restore_mapping_context macro | ||
| 65 | local rest_agn_m, rest_ok_m, rest_exit_m | ||
| 66 | ; | ||
| 67 | ; the restore above map call --> | ||
| 68 | ; | ||
| 69 | ; mov ah,48h | ||
| 70 | ; mov dx,handle | ||
| 71 | ; int 67h | ||
| 72 | ; ah = 0 is success | ||
| 73 | ; | ||
| 74 | ; | ||
| 75 | push ax | ||
| 76 | pushf | ||
| 77 | ; | ||
| 78 | rest_agn_m: | ||
| 79 | mov dx,cs:[above_pid] ; get emm handle | ||
| 80 | mov ah,above_restore_map_pid ; restore map call | ||
| 81 | int 67h ; call manager | ||
| 82 | or ah,ah ; is there any error | ||
| 83 | jz rest_ok_m ; if not go to finish up | ||
| 84 | ; | ||
| 85 | ; error condition, check for recoverable error | ||
| 86 | ; | ||
| 87 | cmp ah,above_error_busy ; if manager was busy | ||
| 88 | jz rest_agn_m ; we sure can try again | ||
| 89 | cmp ah,above_error_no_cntxt ; | ||
| 90 | jz rest_ok_m ; ignore invalid pid error | ||
| 91 | ; | ||
| 92 | ; unrecoverable error | ||
| 93 | ; | ||
| 94 | pop dx | ||
| 95 | pop dx | ||
| 96 | mov al,0ch ; general failure | ||
| 97 | stc | ||
| 98 | jmp short rest_exit_m | ||
| 99 | ; | ||
| 100 | rest_ok_m: | ||
| 101 | popf | ||
| 102 | pop ax | ||
| 103 | rest_exit_m: | ||
| 104 | ; | ||
| 105 | endm | ||
| 106 | ; | ||
| 107 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 108 | ; | ||
| 109 | ; 3. MACRO to map a page in the physical page map onto a logical | ||
| 110 | ; page. | ||
| 111 | ; | ||
| 112 | ; the map above page requires | ||
| 113 | ; mov ah,44h | ||
| 114 | ; mov dx,handle | ||
| 115 | ; mov al,physical_page# (0-3) | ||
| 116 | ; mov bx,logical_page# | ||
| 117 | ; int 67H | ||
| 118 | ; ah = 0 success and this routine zaps ax,dx and bx | ||
| 119 | ; | ||
| 120 | map_page macro | ||
| 121 | local map_agn_m,map_exit_m,map_fin_m | ||
| 122 | ; | ||
| 123 | mov ah,above_map ; function map page | ||
| 124 | mov dx,cs:[above_pid] ; get emm handle | ||
| 125 | ; | ||
| 126 | push ax | ||
| 127 | ; | ||
| 128 | map_agn_m: | ||
| 129 | pop ax | ||
| 130 | push ax | ||
| 131 | push bx | ||
| 132 | push dx ; "damn call above_map zaps these registers" | ||
| 133 | ; | ||
| 134 | int 67h ; map call | ||
| 135 | pop dx | ||
| 136 | pop bx | ||
| 137 | ; | ||
| 138 | or ah,ah ; is there an error? | ||
| 139 | jz map_fin_m ; if not go to finish up | ||
| 140 | ; | ||
| 141 | ; error condition - check for recoverable error | ||
| 142 | ; | ||
| 143 | cmp ah,above_error_busy ; if manager was busy | ||
| 144 | jz map_agn_m ; we sure can try again | ||
| 145 | ; | ||
| 146 | ; unrecoverable error | ||
| 147 | ; | ||
| 148 | pop ax | ||
| 149 | mov al,02h ; device not ready error | ||
| 150 | stc | ||
| 151 | jmp short map_exit_m | ||
| 152 | ; | ||
| 153 | ; exit point | ||
| 154 | ; | ||
| 155 | map_fin_m: | ||
| 156 | clc | ||
| 157 | pop ax | ||
| 158 | map_exit_m: | ||
| 159 | ; | ||
| 160 | endm | ||
| 161 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 162 | ; | ||
| 163 | ; OTHER MACROS | ||
| 164 | ; | ||
| 165 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 166 | ; | ||
| 167 | ; 1) MACRO to switch es:di with ds:si | ||
| 168 | ; | ||
| 169 | src_dest_switch macro | ||
| 170 | ; | ||
| 171 | push ds | ||
| 172 | push es | ||
| 173 | push si | ||
| 174 | mov si,di | ||
| 175 | pop di | ||
| 176 | pop ds | ||
| 177 | pop es | ||
| 178 | ; | ||
| 179 | endm | ||
| 180 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
diff --git a/v4.0/src/DEV/RAMDRIVE/DEVSYM.INC b/v4.0/src/DEV/RAMDRIVE/DEVSYM.INC new file mode 100644 index 0000000..44a1ab8 --- /dev/null +++ b/v4.0/src/DEV/RAMDRIVE/DEVSYM.INC | |||
| @@ -0,0 +1,128 @@ | |||
| 1 | BREAK <Device table and SRH definition> | ||
| 2 | |||
| 3 | ; The device table list has the form: | ||
| 4 | SYSDEV STRUC | ||
| 5 | SDEVNEXT DD ? ;Pointer to next device header | ||
| 6 | SDEVATT DW ? ;Attributes of the device | ||
| 7 | SDEVSTRAT DW ? ;Strategy entry point | ||
| 8 | SDEVINT DW ? ;Interrupt entry point | ||
| 9 | SDEVNAME DB 8 DUP (?) ;Name of device (only first byte used for block) | ||
| 10 | SYSDEV ENDS | ||
| 11 | |||
| 12 | ; | ||
| 13 | ; Attribute bit masks | ||
| 14 | ; | ||
| 15 | ; Character devices: | ||
| 16 | ; | ||
| 17 | ; Bit 15 -> must be 1 | ||
| 18 | ; 14 -> 1 if the device understands IOCTL control strings | ||
| 19 | ; 13 -> 1 if the device supports output-until-busy | ||
| 20 | ; 12 -> unused | ||
| 21 | ; 11 -> 1 if the device understands Open/Close | ||
| 22 | ; 10 -> must be 0 | ||
| 23 | ; 9 -> must be 0 | ||
| 24 | ; 8 -> unused | ||
| 25 | ; 7 -> unused | ||
| 26 | ; 6 -> unused | ||
| 27 | ; 5 -> unused | ||
| 28 | ; 4 -> 1 if device is recipient of INT 29h | ||
| 29 | ; 3 -> 1 if device is clock device | ||
| 30 | ; 2 -> 1 if device is null device | ||
| 31 | ; 1 -> 1 if device is console output | ||
| 32 | ; 0 -> 1 if device is console input | ||
| 33 | ; | ||
| 34 | ; Block devices: | ||
| 35 | ; | ||
| 36 | ; Bit 15 -> must be 0 | ||
| 37 | ; 14 -> 1 if the device understands IOCTL control strings | ||
| 38 | ; 13 -> 1 if the device determines media by examining the FAT ID byte. | ||
| 39 | ; This requires the first sector of the fat to *always* reside in | ||
| 40 | ; the same place. | ||
| 41 | ; 12 -> unused | ||
| 42 | ; 11 -> 1 if the device understands Open/Close/removable media | ||
| 43 | ; 10 -> must be 0 | ||
| 44 | ; 9 -> must be 0 | ||
| 45 | ; 8 -> unused | ||
| 46 | ; 7 -> unused | ||
| 47 | ; 6 -> unused | ||
| 48 | ; 5 -> unused | ||
| 49 | ; 4 -> unused | ||
| 50 | ; 3 -> unused | ||
| 51 | ; 2 -> unused | ||
| 52 | ; 1 -> unused | ||
| 53 | ; 0 -> unused | ||
| 54 | |||
| 55 | DevTyp EQU 8000H ; Bit 15 - 1 if Char, 0 if block | ||
| 56 | CharDev EQU 8000H | ||
| 57 | DevIOCtl EQU 4000H ; Bit 14 - CONTROL mode bit | ||
| 58 | ISFATBYDEV EQU 2000H ; Bit 13 - Device uses FAT ID bytes, | ||
| 59 | ; comp media. | ||
| 60 | OutTilBusy EQU 2000h ; Output until busy is enabled | ||
| 61 | ISNET EQU 1000H ; Bit 12 - 1 if a NET device, 0 if | ||
| 62 | ; not. Currently block only. | ||
| 63 | DEVOPCL EQU 0800H ; Bit 11 - 1 if this device has | ||
| 64 | ; OPEN,CLOSE and REMOVABLE MEDIA | ||
| 65 | ; entry points, 0 if not | ||
| 66 | |||
| 67 | EXTENTBIT EQU 0400H ; Bit 10 - Currently 0 on all devs | ||
| 68 | ; This bit is reserved for future use | ||
| 69 | ; to extend the device header beyond | ||
| 70 | ; its current form. | ||
| 71 | |||
| 72 | ; NOTE Bit 9 is currently used on IBM systems to indicate "drive is shared". | ||
| 73 | ; See IOCTL function 9. THIS USE IS NOT DOCUMENTED, it is used by some | ||
| 74 | ; of the utilities which are supposed to FAIL on shared drives on server | ||
| 75 | ; machines (FORMAT,CHKDSK,RECOVER,..). | ||
| 76 | |||
| 77 | ISSPEC EQU 0010H ;Bit 4 - This device is special | ||
| 78 | ISCLOCK EQU 0008H ;Bit 3 - This device is the clock device. | ||
| 79 | ISNULL EQU 0004H ;Bit 2 - This device is the null device. | ||
| 80 | ISCOUT EQU 0002H ;Bit 1 - This device is the console output. | ||
| 81 | ISCIN EQU 0001H ;Bit 0 - This device is the console input. | ||
| 82 | |||
| 83 | ;Static Request Header | ||
| 84 | SRHEAD STRUC | ||
| 85 | REQLEN DB ? ;Length in bytes of request block | ||
| 86 | REQUNIT DB ? ;Device unit number | ||
| 87 | REQFUNC DB ? ;Type of request | ||
| 88 | REQSTAT DW ? ;Status Word | ||
| 89 | DB 8 DUP(?) ;Reserved for queue links | ||
| 90 | SRHEAD ENDS | ||
| 91 | |||
| 92 | ;Status word masks | ||
| 93 | STERR EQU 8000H ;Bit 15 - Error | ||
| 94 | STBUI EQU 0200H ;Bit 9 - Buisy | ||
| 95 | STDON EQU 0100H ;Bit 8 - Done | ||
| 96 | STECODE EQU 00FFH ;Error code | ||
| 97 | |||
| 98 | ;Function codes | ||
| 99 | DEVINIT EQU 0 ;Initialization | ||
| 100 | DINITHL EQU 26 ;Size of init header | ||
| 101 | DEVMDCH EQU 1 ;Media check | ||
| 102 | DMEDHL EQU 15 ;Size of media check header | ||
| 103 | DEVBPB EQU 2 ;Get BPB | ||
| 104 | DEVRDIOCTL EQU 3 ;IOCTL read | ||
| 105 | DBPBHL EQU 22 ;Size of Get BPB header | ||
| 106 | DEVRD EQU 4 ;Read | ||
| 107 | DRDWRHL EQU 22 ;Size of RD/WR header | ||
| 108 | DEVRDND EQU 5 ;Non destructive read no wait (character devs) | ||
| 109 | DRDNDHL EQU 14 ;Size of non destructive read header | ||
| 110 | DEVIST EQU 6 ;Input status | ||
| 111 | DSTATHL EQU 13 ;Size of status header | ||
| 112 | DEVIFL EQU 7 ;Input flush | ||
| 113 | DFLSHL EQU 15 ;Size of flush header | ||
| 114 | DEVWRT EQU 8 ;Write | ||
| 115 | DEVWRTV EQU 9 ;Write with verify | ||
| 116 | DEVOST EQU 10 ;Output status | ||
| 117 | DEVOFL EQU 11 ;Output flush | ||
| 118 | DEVWRIOCTL EQU 12 ;IOCTL write | ||
| 119 | DEVOPN EQU 13 ;Device open | ||
| 120 | DEVCLS EQU 14 ;Device close | ||
| 121 | DOPCLHL EQU 13 ;Size of OPEN/CLOSE header | ||
| 122 | DEVRMD EQU 15 ;Removable media | ||
| 123 | REMHL EQU 13 ;Size of Removable media header | ||
| 124 | |||
| 125 | DevOUT EQU 16 ; output until busy. | ||
| 126 | DevOutL EQU DevWrt ; length of output until busy | ||
| 127 | |||
| 128 | SUBTTL | ||
diff --git a/v4.0/src/DEV/RAMDRIVE/DIRENT.INC b/v4.0/src/DEV/RAMDRIVE/DIRENT.INC new file mode 100644 index 0000000..e7150c8 --- /dev/null +++ b/v4.0/src/DEV/RAMDRIVE/DIRENT.INC | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | Break <Directory entry> | ||
| 2 | |||
| 3 | ; | ||
| 4 | ; +---------------------------+ | ||
| 5 | ; | (12 BYTE) filename/ext | 0 0 | ||
| 6 | ; +---------------------------+ | ||
| 7 | ; | (BYTE) attributes | 11 B | ||
| 8 | ; +---------------------------+ | ||
| 9 | ; | (10 BYTE) reserved | 12 C | ||
| 10 | ; +---------------------------+ | ||
| 11 | ; | (WORD) time of last write | 22 16 | ||
| 12 | ; +---------------------------+ | ||
| 13 | ; | (WORD) date of last write | 24 18 | ||
| 14 | ; +---------------------------+ | ||
| 15 | ; | (WORD) First cluster | 26 1A | ||
| 16 | ; +---------------------------+ | ||
| 17 | ; | (DWORD) file size | 28 1C | ||
| 18 | ; +---------------------------+ | ||
| 19 | ; | ||
| 20 | ; First byte of filename = E5 -> free directory entry | ||
| 21 | ; = 00 -> end of allocated directory | ||
| 22 | ; Time: Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour | ||
| 23 | ; Date: Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980 | ||
| 24 | ; | ||
| 25 | |||
| 26 | dir_entry STRUC | ||
| 27 | dir_name DB 11 DUP (?) ; file name | ||
| 28 | dir_attr DB ? ; attribute bits | ||
| 29 | dir_pad DB 10 DUP (?) ; reserved for expansion | ||
| 30 | dir_time DW ? ; time of last write | ||
| 31 | dir_date DW ? ; date of last write | ||
| 32 | dir_first DW ? ; first allocation unit of file | ||
| 33 | dir_size_l DW ? ; low 16 bits of file size | ||
| 34 | dir_size_h DW ? ; high 16 bits of file size | ||
| 35 | dir_entry ENDS | ||
| 36 | |||
| 37 | attr_read_only EQU 1h | ||
| 38 | attr_hidden EQU 2h | ||
| 39 | attr_system EQU 4h | ||
| 40 | attr_volume_id EQU 8h | ||
| 41 | attr_directory EQU 10h | ||
| 42 | attr_archive EQU 20h | ||
| 43 | attr_device EQU 40h ; This is a VERY special bit. | ||
| 44 | ; NO directory entry on a disk EVER | ||
| 45 | ; has this bit set. It is set non-zero | ||
| 46 | ; when a device is found by GETPATH | ||
| 47 | |||
| 48 | attr_all EQU attr_hidden+attr_system+attr_directory | ||
| 49 | ; OR of hard attributes for FINDENTRY | ||
| 50 | |||
| 51 | attr_ignore EQU attr_read_only+attr_archive+attr_device | ||
| 52 | ; ignore this(ese) attribute(s) during | ||
| 53 | ; search first/next | ||
| 54 | |||
| 55 | attr_changeable EQU attr_read_only+attr_hidden+attr_system+attr_archive | ||
| 56 | ; changeable via CHMOD | ||
diff --git a/v4.0/src/DEV/RAMDRIVE/EMM.INC b/v4.0/src/DEV/RAMDRIVE/EMM.INC new file mode 100644 index 0000000..ff61ab0 --- /dev/null +++ b/v4.0/src/DEV/RAMDRIVE/EMM.INC | |||
| @@ -0,0 +1,223 @@ | |||
| 1 | BREAK <EMM control sector layout> | ||
| 2 | |||
| 3 | ; | ||
| 4 | ; The EMM control sector is a 1024 byte record which ALWAYS occupies the | ||
| 5 | ; very first 1024 bytes of "extra" memory that needs to be managed. Its | ||
| 6 | ; function is to provide a method to allocate available "extra" memory | ||
| 7 | ; to programs which desire to use it and avoid program conflicts that | ||
| 8 | ; would occur if two different programs attempted to use the same piece | ||
| 9 | ; of "extra" memory. | ||
| 10 | ; | ||
| 11 | |||
| 12 | ; | ||
| 13 | ; The EMM_CTRL structure defines the offsets into the 1024 byte control | ||
| 14 | ; sector of the various fields. The EMM_REC structure defines a sub-structure | ||
| 15 | ; contained within the EMM_CTRL structure which represents a particular | ||
| 16 | ; piece of allocated "extra" memory (an allocation record). | ||
| 17 | ; | ||
| 18 | |||
| 19 | ; Layout of each EMM record. | ||
| 20 | |||
| 21 | EMM_REC STRUC | ||
| 22 | EMM_FLAGS DW 0 | ||
| 23 | EMM_SYSTEM DW 0 | ||
| 24 | EMM_BASE DD ? ; 24 bit address of start of region | ||
| 25 | EMM_KSIZE DW ? ; Size of region in kbytes | ||
| 26 | EMM_REC ENDS | ||
| 27 | |||
| 28 | ; EMM_FLAGS Bits | ||
| 29 | EMM_ALLOC EQU 0000000000000001B ; Zero -> record is free | ||
| 30 | EMM_ISDRIVER EQU 0000000000000010B ; 1 -> driver is installed | ||
| 31 | ; for this region | ||
| 32 | |||
| 33 | ; EMM_SYSTEM Values | ||
| 34 | EMM_EMM EQU 0 ; Allocated to EMM | ||
| 35 | EMM_MSDOS EQU 1 | ||
| 36 | EMM_XENIX EQU 2 | ||
| 37 | EMM_APPLICATION EQU 3 | ||
| 38 | |||
| 39 | ; Layout of EMM control 1024 byte record | ||
| 40 | |||
| 41 | EMM_CTRL STRUC | ||
| 42 | EMM_VER DB 50 DUP(?) | ||
| 43 | EMM_TOTALK DW ? ; EXCLUDING the 1k of this record | ||
| 44 | EMM_AVAILK DW ? ; Amount of above NOT allocated | ||
| 45 | DB SIZE EMM_REC DUP(?) ; NULL (0th) RECORD | ||
| 46 | EMM_RECORD DB (1024 - 50 - 4 - 10 - (SIZE EMM_REC)) DUP(?) | ||
| 47 | ; EMM_REC structures | ||
| 48 | EMM_TAIL_SIG DB 10 DUP(?) | ||
| 49 | EMM_CTRL ENDS | ||
| 50 | |||
| 51 | EMM_NUMREC EQU (1024 - 50 - 4 - 10 - (SIZE EMM_REC)) / (SIZE EMM_REC) | ||
| 52 | |||
| 53 | |||
| 54 | ; | ||
| 55 | ; The current initial (no "extra" memory allocated) EMM_CTRL sector is | ||
| 56 | ; | ||
| 57 | ; EMM_CONTROL LABEL BYTE | ||
| 58 | ; DB "MICROSOFT EMM CTRL VERSION 1.00 CONTROL BLOCK " | ||
| 59 | ; DW EXTMEM_TOTALK - 1 | ||
| 60 | ; DW EXTMEM_TOTALK - 1 | ||
| 61 | ; ; NULL 0th record | ||
| 62 | ; DW EMM_ALLOC + EMM_ISDRIVER | ||
| 63 | ; DW EMM_EMM | ||
| 64 | ; DW EXTMEM_LOW + 1024 | ||
| 65 | ; DW EXTMEM_HIGH | ||
| 66 | ; DW 0 | ||
| 67 | ; ;** | ||
| 68 | ; DB 950 DUP(0) | ||
| 69 | ; DB "ARRARRARRA" | ||
| 70 | ; | ||
| 71 | ; Where EXTMEM_LOW:EXTMEM_HIGH is the 32 bit address of the first byte | ||
| 72 | ; of the EMM_CTRL sector (first byte of "extra" memory) and EXTMEM_TOTALK | ||
| 73 | ; is the size in K of the available "extra" memory. One is subtracted | ||
| 74 | ; from EXTMEM_TOTALK because the sizes in the EMM_CTRL record DO NOT | ||
| 75 | ; include the 1k taken up by the EMM_CTRL sector. | ||
| 76 | ; | ||
| 77 | ; The reason for the existance of the NULL 0th record is to facilitate | ||
| 78 | ; the computation of EMM_BASE for the first EMM_REC allocation record | ||
| 79 | ; created. | ||
| 80 | ; | ||
| 81 | ; The EMM_REC structures CANNOT be sparse. In other words if one sets | ||
| 82 | ; up a scan of the EMM_REC structures in the EMM_CTRL sector, as soon as | ||
| 83 | ; an EMM_REC structure WITHOUT the EMM_ALLOC bit set in its flag word | ||
| 84 | ; is encountered it is not necessary to scan further because it IS KNOWN | ||
| 85 | ; that all of the EMM_REC structures after the first one with EMM_ALLOC | ||
| 86 | ; clear also have EMM_ALLOC clear. What this means is that EMM_CTRL | ||
| 87 | ; memory CANNOT BE deallocated. Once an EMM_REC structure has its | ||
| 88 | ; EMM_ALLOC bit set, there is NO correct program operation which | ||
| 89 | ; can clear the bit UNLESS it IS KNOWN that the next EMM_REC structure | ||
| 90 | ; has its EMM_ALLOC bit clear or the EMM_REC structure is the last one. | ||
| 91 | ; | ||
| 92 | ; | ||
| 93 | ; USING THE EMM_CTRL SECTOR: | ||
| 94 | ; | ||
| 95 | ; A program which wishes to use the EMM_CTRL sector to access "extra" | ||
| 96 | ; memory should work as follows: | ||
| 97 | ; | ||
| 98 | ; Figure out how much memory you wish to allocate | ||
| 99 | ; | ||
| 100 | ; Figure out the location and size of the "extra" memory in the system | ||
| 101 | ; | ||
| 102 | ; IF (the first 1024 bytes of "extra" memory DO NOT contain a valid | ||
| 103 | ; EMM_CTRL record determined by checking for the existence of the | ||
| 104 | ; correct EMM_VER and EMM_TAIL_SIG strings) | ||
| 105 | ; Write a correct initial EMM_CTRL sector to the first 1024 | ||
| 106 | ; bytes of extra memory. Be sure to fill in EMM_TOTALK, | ||
| 107 | ; EMM_AVAILK and EMM_BASE in the 0th record. | ||
| 108 | ; | ||
| 109 | ; Set up a scan of the EMM_REC structures in the EMM_CTRL sector. | ||
| 110 | ; NOTE: You can skip the NULL 0th record if you want since it has | ||
| 111 | ; known value. | ||
| 112 | ; | ||
| 113 | ; FOR (i=0;i<EMM_NUMREC;i++) | ||
| 114 | ; IF ( this EMM_REC has EMM_ALLOC clear) | ||
| 115 | ; IF ( EMM_AVAILK < amount I want to alloc) | ||
| 116 | ; ERROR insufficient memory | ||
| 117 | ; EMM_AVAILK = EMM_AVAILK - amount I want to alloc | ||
| 118 | ; EMM_FLAGS = EMM_ALLOC + EMM_ISDRIVER | ||
| 119 | ; EMM_KSIZE = amount I want to alloc | ||
| 120 | ; EMM_SYSTEM = appropriate value | ||
| 121 | ; EMM_BASE = EMM_BASE of PREVIOUS EMM_REC + | ||
| 122 | ; (1024 * EMM_KSIZE of PREVIOUS EMM_REC) | ||
| 123 | ; break | ||
| 124 | ; ELSE | ||
| 125 | ; address next EMM_REC structure | ||
| 126 | ; | ||
| 127 | ; IF (i >= EMM_NUMREC) | ||
| 128 | ; ERROR no free EMM_REC structures | ||
| 129 | ; | ||
| 130 | ; | ||
| 131 | ; You can now see why we need that NUL 0th EMM_REC structure. In order to | ||
| 132 | ; perform this step | ||
| 133 | ; | ||
| 134 | ; EMM_BASE = EMM_BASE of PREVIOUS EMM_REC + | ||
| 135 | ; (1024 * EMM_KSIZE of PREVIOUS EMM_REC) | ||
| 136 | ; | ||
| 137 | ; when the very first EMM_REC is allocated we must have a "previous EMM_REC" | ||
| 138 | ; structure to point at. | ||
| 139 | ; | ||
| 140 | ; The above code is rather simplistic in that all it does is do a simple | ||
| 141 | ; allocation. The EMM_ISDRIVER bit allows us to do some more sophisticated | ||
| 142 | ; things. In particular in the case of a RAMDrive type of program it is | ||
| 143 | ; desirable to "re-find" the same RAMDrive area in "extra" memory when the | ||
| 144 | ; system is re-booted. The EMM_ISDRIVER bit is used to help us do this. | ||
| 145 | ; | ||
| 146 | ; The EMM_ISDRIVER bit means "there is presently a piece of code in the | ||
| 147 | ; system which is using this memory". If we find an EMM_REC structure | ||
| 148 | ; which has its EMM_ALLOC bit set, but the EMM_ISDRIVER bit is clear | ||
| 149 | ; it means that the piece of code that originally allocated | ||
| 150 | ; the memory is gone and we may want to "re-find" this memory by | ||
| 151 | ; setting the EMM_ISDRIVER bit again. A RAMDrive program would have | ||
| 152 | ; slightly different code than the above: | ||
| 153 | ; | ||
| 154 | ; FOR (i=0;i<EMM_NUMREC;i++) | ||
| 155 | ; IF ( this EMM_REC has EMM_ALLOC clear) | ||
| 156 | ; IF ( EMM_AVAILK < amount I want to alloc) | ||
| 157 | ; ERROR insufficient memory | ||
| 158 | ; EMM_AVAILK = EMM_AVAILK - amount I want to alloc | ||
| 159 | ; EMM_FLAGS = EMM_ALLOC + EMM_ISDRIVER | ||
| 160 | ; EMM_KSIZE = amount I want to alloc | ||
| 161 | ; EMM_SYSTEM = appropriate value | ||
| 162 | ; EMM_BASE = EMM_BASE of PREVIOUS EMM_REC + | ||
| 163 | ; (1024 * EMM_KSIZE of PREVIOUS EMM_REC) | ||
| 164 | ; break | ||
| 165 | ; ELSE | ||
| 166 | ; IF ((EMM_SYSTEM == my value for EMM_SYSTEM) && | ||
| 167 | ; (EMM_ISDRIVER is clear)) | ||
| 168 | ; deal with differences between amount | ||
| 169 | ; I want to allocate and EMM_KSIZE | ||
| 170 | ; Set EMM_ISDRIVER | ||
| 171 | ; EMM_BASE is the base address of this piece | ||
| 172 | ; of memory and EMM_KSIZE is its size. | ||
| 173 | ; break | ||
| 174 | ; address next EMM_REC structure | ||
| 175 | ; | ||
| 176 | ; In this way we "re-find" memory that was previosly allocated (presumably | ||
| 177 | ; by us, or a related program). | ||
| 178 | ; | ||
| 179 | ; NOTE THAT THIS USE OF EMM_ISDRIVER REQUIRES SOME MECHANISM FOR CLEARING | ||
| 180 | ; EMM_ISDRIVER WHEN THE CODE OF INTEREST IS REMOVED FROM THE SYSTEM. | ||
| 181 | ; In the case of a RAMDrive program the code is removed whenever the system | ||
| 182 | ; is re-booted. For this reason a RAMDrive program will need code that is | ||
| 183 | ; invoked whenever a system re-boot is detected. What this code does is | ||
| 184 | ; scan the EMM_REC structures in the EMM_CTRL sector turning off the | ||
| 185 | ; EMM_ISDRIVER bits: | ||
| 186 | ; | ||
| 187 | ; FOR (i=0;i<EMM_NUMREC;i++) | ||
| 188 | ; IF ( this EMM_REC has EMM_ALLOC clear) | ||
| 189 | ; break | ||
| 190 | ; ELSE IF (EMM_SYSTEM == my value for EMM_SYSTEM) | ||
| 191 | ; clear EMM_ISDRIVER bit | ||
| 192 | ; address next EMM_REC | ||
| 193 | ; | ||
| 194 | ; Note that this code clears ALL of the ISDRIVER bits for EMM_SYSTEM | ||
| 195 | ; values of a certain value. This means there is a GLOBAL piece of | ||
| 196 | ; re-boot code for ALL of the programs using a particular EMM_SYSTEM | ||
| 197 | ; value. An alternative is to have each EMM_CTRL user clear the | ||
| 198 | ; EMM_ISDRIVER bits ONLY for those EMM_REC structures that it allocated. | ||
| 199 | ; This requires that the program keep a record of which EMM_REC structures | ||
| 200 | ; it is responsible for: | ||
| 201 | ; | ||
| 202 | ; FOR each of my EMM_REC structures | ||
| 203 | ; INDEX this EMM_REC structure in the EMM_CTRL sector | ||
| 204 | ; Clear EMM_ISDRIVER | ||
| 205 | ; | ||
| 206 | ; NOTE about this step: | ||
| 207 | ; | ||
| 208 | ; deal with differences between amount | ||
| 209 | ; I want to allocate and EMM_KSIZE | ||
| 210 | ; | ||
| 211 | ; in the above code. There are a lot of options here depending on the desired | ||
| 212 | ; behavior. If the NEXT EMM_REC structure has EMM_ALLOC clear, then it may | ||
| 213 | ; be possible for me to grow or shrink the block I found by adjusting | ||
| 214 | ; EMM_KSIZE and EMM_AVAILK. If the NEXT EMM_REC structure has EMM_ALLOC | ||
| 215 | ; set, then I am forced to either adjust the amount I want to allocate | ||
| 216 | ; to match EMM_KSIZE, or skip this EMM_REC without setting EMM_ISDRIVER. | ||
| 217 | ; | ||
| 218 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 219 | ; for rom 1nt15 extended memory interface | ||
| 220 | emm_int equ 15h | ||
| 221 | emm_size equ 88h | ||
| 222 | emm_blkm equ 87h | ||
| 223 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
diff --git a/v4.0/src/DEV/RAMDRIVE/LOADALL.INC b/v4.0/src/DEV/RAMDRIVE/LOADALL.INC new file mode 100644 index 0000000..0476acd --- /dev/null +++ b/v4.0/src/DEV/RAMDRIVE/LOADALL.INC | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | BREAK <LOADALL descriptor caches> | ||
| 2 | |||
| 3 | DEF_ACCESS EQU 92H | ||
| 4 | DEF_LIMIT EQU 0FFFFH | ||
| 5 | |||
| 6 | SEGREG_DESCRIPTOR STRUC | ||
| 7 | SEG_BASE DW ? | ||
| 8 | DB ? | ||
| 9 | SEG_ACCESS DB DEF_ACCESS | ||
| 10 | SEG_LIMIT DW DEF_LIMIT | ||
| 11 | SEGREG_DESCRIPTOR ENDS | ||
| 12 | |||
| 13 | DTR_DESCRIPTOR STRUC | ||
| 14 | DTR_BASE DW ? | ||
| 15 | DB ? | ||
| 16 | DB 0 | ||
| 17 | DTR_LIMIT DW ? | ||
| 18 | DTR_DESCRIPTOR ENDS | ||
| 19 | ; | ||
| 20 | ; 386 Descriptor template | ||
| 21 | ; | ||
| 22 | desc struc | ||
| 23 | lim_0_15 dw 0 ; limit bits (0..15) | ||
| 24 | bas_0_15 dw 0 ; base bits (0..15) | ||
| 25 | bas_16_23 db 0 ; base bits (16..23) | ||
| 26 | access db 0 ; access byte | ||
| 27 | gran db 0 ; granularity byte | ||
| 28 | bas_24_31 db 0 ; base bits (24..31) | ||
| 29 | desc ends | ||
| 30 | |||
| 31 | gdt_descriptor struc | ||
| 32 | gdt_limit dw ? | ||
| 33 | gdt_base_0 dw ? | ||
| 34 | gdt_base_2 dw ? | ||
| 35 | gdt_descriptor ends | ||
diff --git a/v4.0/src/DEV/RAMDRIVE/MAKEFILE b/v4.0/src/DEV/RAMDRIVE/MAKEFILE new file mode 100644 index 0000000..c61e83e --- /dev/null +++ b/v4.0/src/DEV/RAMDRIVE/MAKEFILE | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | #** makefile for Ramdrive | ||
| 2 | |||
| 3 | DEST = ramdrive | ||
| 4 | MSG = messages | ||
| 5 | |||
| 6 | # Definitions for assembler | ||
| 7 | |||
| 8 | ASM = masm | ||
| 9 | AFLAGS = -Mx -t | ||
| 10 | AINC = -I../../inc | ||
| 11 | |||
| 12 | # Definitions for C compiler | ||
| 13 | |||
| 14 | CC = cl | ||
| 15 | CFLAGS = -Ox -X -Zlp | ||
| 16 | CINC = -I../../h | ||
| 17 | |||
| 18 | # Definitions for linker | ||
| 19 | |||
| 20 | LINK = link | ||
| 21 | |||
| 22 | # Dependencies follow | ||
| 23 | |||
| 24 | all: ramdrive.sys | ||
| 25 | |||
| 26 | ramdrive.obj: ramdrive.asm above.inc loadall.inc emm.inc mi.inc \ | ||
| 27 | dirent.inc syscall.inc devsym.inc | ||
| 28 | masm $(AFLAGS) $(AINC) ramdrive; | ||
| 29 | |||
| 30 | messages.obj: messages.asm | ||
| 31 | masm $(AFLAGS) $(AINC) messages; | ||
| 32 | |||
| 33 | ramdrive.sys: ramdrive.obj messages.obj | ||
| 34 | link @ramdrive.lnk | ||
| 35 | exe2bin ramdrive ramdrive.sys | ||
| 36 | del ramdrive.exe | ||
diff --git a/v4.0/src/DEV/RAMDRIVE/MESSAGES.ASM b/v4.0/src/DEV/RAMDRIVE/MESSAGES.ASM new file mode 100644 index 0000000..66c528b --- /dev/null +++ b/v4.0/src/DEV/RAMDRIVE/MESSAGES.ASM | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | TITLE MESSAGE MODULE FOR RAMDRIVE.ASM | ||
| 2 | ; | ||
| 3 | ; WRITTEN BY S. P. 3/3/87 | ||
| 4 | ; | ||
| 5 | PAGE 58,132 | ||
| 6 | |||
| 7 | BREAK MACRO subtitle | ||
| 8 | SUBTTL subtitle | ||
| 9 | PAGE | ||
| 10 | ENDM | ||
| 11 | |||
| 12 | BREAK <messages and common data> | ||
| 13 | |||
| 14 | RAMCODE SEGMENT | ||
| 15 | ASSUME CS:RAMCODE,DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 16 | |||
| 17 | ;** Message texts and common data | ||
| 18 | ; | ||
| 19 | ; Init data. This data is disposed of after initialization. | ||
| 20 | ; it is mostly texts of all of the messages | ||
| 21 | ; | ||
| 22 | ; COMMON to TYPE 1,2,3 and 4 drivers | ||
| 23 | ; | ||
| 24 | ; THIS IS THE START OF DATA SUBJECT TO TRANSLATION | ||
| 25 | |||
| 26 | PUBLIC NO_ABOVE,BAD_ABOVE,BAD_AT,NO_MEM,ERRMSG1,ERRMSG2 | ||
| 27 | PUBLIC ERRMSG2,INIT_IO_ERR,BADVERMES | ||
| 28 | PUBLIC HEADERMES,PATCH2X,DOS_DRV | ||
| 29 | PUBLIC STATMES1,STATMES2,STATMES3,STATMES4,STATMES4,STATMES5 | ||
| 30 | |||
| 31 | NO_ABOVE db "RAMDrive: Expanded Memory Manager not present",13,10,"$" | ||
| 32 | BAD_ABOVE db "RAMDrive: Expanded Memory Status shows error",13,10,"$" | ||
| 33 | BAD_AT db "RAMDrive: Computer must be PC-AT, or PC-AT compatible",13,10,"$" | ||
| 34 | NO_MEM db "RAMDrive: No extended memory available",13,10,"$" | ||
| 35 | ERRMSG1 db "RAMDrive: Invalid parameter",13,10,"$" | ||
| 36 | ERRMSG2 db "RAMDrive: Insufficient memory",13,10,"$" | ||
| 37 | INIT_IO_ERR db "RAMDrive: I/O error accessing drive memory",13,10,"$" | ||
| 38 | BADVERMES db 13,10,"RAMDrive: Incorrect DOS version",13,10,"$" | ||
| 39 | |||
| 40 | ; | ||
| 41 | ; This is the Ramdrive header message. THE MESSAGE IS DYNAMICALLY | ||
| 42 | ; PATCHED AT RUNTIME. The DOS drive letter of the RAMDRIVE | ||
| 43 | ; is patched in at DOS_DRV for DOS versions >= 3.00. For | ||
| 44 | ; DOS versions < 3.00 the three bytes 13,10,"$" are placed | ||
| 45 | ; at the label PATCH2X eliminating the drive specifier since | ||
| 46 | ; this information cannot be determined on 2.X DOS. | ||
| 47 | ; NO PART OF THIS MESSAGE WHICH MUST BE PRINTED ON ALL VERSIONS | ||
| 48 | ; OF DOS CAN BE PLACED AFTER THE LABEL PATCH2X. This may cause | ||
| 49 | ; translation problems for some languages, if this is so | ||
| 50 | ; the only solution is to eliminate the drive letter part of | ||
| 51 | ; the message totally for ALL DOS versions: | ||
| 52 | ; | ||
| 53 | ; HEADERMES db 13,10,"Microsoft RAMDrive version 1.17 " | ||
| 54 | ; PATCH2X db 13,10,"$" | ||
| 55 | ; DOS_DRV db "A" | ||
| 56 | ; | ||
| 57 | ; | ||
| 58 | HEADERMES db 13,10,"Microsoft RAMDrive version 2.12 " | ||
| 59 | PATCH2X db "virtual disk " | ||
| 60 | DOS_DRV db "A" | ||
| 61 | db ":",13,10,"$" | ||
| 62 | |||
| 63 | ; | ||
| 64 | ; This is the status message used to display RAMDRIVE configuration | ||
| 65 | ; it is: | ||
| 66 | ; | ||
| 67 | ; STATMES1<size in K>STATMES2<Sector size in bytes>STATMES3 | ||
| 68 | ; <sectors per alloc unit>STATMES4<Number of root dir entries> | ||
| 69 | ; STATMES5 | ||
| 70 | ; | ||
| 71 | ; It is up to translator to move the message text around the numbers | ||
| 72 | ; so that the message is printed correctly when translated | ||
| 73 | ; | ||
| 74 | STATMES1 db " Disk size: $" | ||
| 75 | STATMES2 db "k",13,10," Sector size: $" | ||
| 76 | STATMES3 db " bytes",13,10," Allocation unit: $" | ||
| 77 | STATMES4 db " sectors",13,10," Directory entries: $" | ||
| 78 | STATMES5 db 13,10,"$" | ||
| 79 | |||
| 80 | |||
| 81 | RAMCODE ENDS | ||
| 82 | END | ||
diff --git a/v4.0/src/DEV/RAMDRIVE/MI.INC b/v4.0/src/DEV/RAMDRIVE/MI.INC new file mode 100644 index 0000000..9d8efed --- /dev/null +++ b/v4.0/src/DEV/RAMDRIVE/MI.INC | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | BREAK <Machine instruction, flag definitions and character types> | ||
| 2 | |||
| 3 | mi_INT EQU 0CDh | ||
| 4 | mi_Long_JMP EQU 0EAh | ||
| 5 | mi_Long_CALL EQU 09Ah | ||
| 6 | mi_Long_RET EQU 0CBh | ||
| 7 | mi_Near_RET EQU 0C3h | ||
| 8 | |||
| 9 | ; xxxxoditszxaxpxc | ||
| 10 | f_Overflow EQU 0000100000000000B | ||
| 11 | f_Direction EQU 0000010000000000B | ||
| 12 | f_Interrupt EQU 0000001000000000B | ||
| 13 | f_Trace EQU 0000000100000000B | ||
| 14 | f_Sign EQU 0000000010000000B | ||
| 15 | f_Zero EQU 0000000001000000B | ||
| 16 | f_Aux EQU 0000000000010000B | ||
| 17 | f_Parity EQU 0000000000000100B | ||
| 18 | f_Carry EQU 0000000000000001B | ||
diff --git a/v4.0/src/DEV/RAMDRIVE/RAMDRIVE.ASM b/v4.0/src/DEV/RAMDRIVE/RAMDRIVE.ASM new file mode 100644 index 0000000..7874042 --- /dev/null +++ b/v4.0/src/DEV/RAMDRIVE/RAMDRIVE.ASM | |||
| @@ -0,0 +1,6218 @@ | |||
| 1 | TITLE EXTENDED MEMORY RAMDRIVE | ||
| 2 | |||
| 3 | PAGE 58,132 | ||
| 4 | |||
| 5 | ; | ||
| 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 | ||
| 9 | ; | ||
| 10 | ; | ||
| 11 | ; device = ramdrive.sys [bbbb] [ssss] [dddd] [/E | /A] | ||
| 12 | ; | ||
| 13 | ; bbbb First numeric argument, if present, is disk size | ||
| 14 | ; in K bytes. Default value is 64. Min is 16. Max | ||
| 15 | ; is 4096 (4 Meg). | ||
| 16 | ; | ||
| 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. | ||
| 26 | ; | ||
| 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. | ||
| 36 | ; | ||
| 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 | ||
| 39 | ; than an IBM PC AT. | ||
| 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. | ||
| 49 | ; | ||
| 50 | ; /A Specifies that Above Board memory is to be used. It | ||
| 51 | ; is an error if the above board device driver is not | ||
| 52 | ; present. | ||
| 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. | ||
| 58 | ; | ||
| 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). | ||
| 81 | ; | ||
| 82 | ; | ||
| 83 | ; | ||
| 84 | ; MODIFICATION HISTORY | ||
| 85 | ; | ||
| 86 | ; 1.00 5/30/85 ARR Initial version. | ||
| 87 | ; | ||
| 88 | ; 1.01 6/03/85 ARR Added CSIZE home code in INIDRV. Does a better | ||
| 89 | ; job of computing good CSIZE value. | ||
| 90 | ; | ||
| 91 | ; 1.10 6/05/85 ARR Changed name of program from VDISK to RAMDRIVE | ||
| 92 | ; | ||
| 93 | ; 1.11 6/06/85 ARR Changed BAD_AT message | ||
| 94 | ; | ||
| 95 | ; 1.12 6/06/85 ARR Fixed bug in /A BLKMOV code. Was forgetting | ||
| 96 | ; to save and restore page mapping context | ||
| 97 | ; | ||
| 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. | ||
| 104 | ; | ||
| 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. | ||
| 108 | ; | ||
| 109 | ; 1.15 6/24/85 ARR Assorted clean up, mostly in Above Board | ||
| 110 | ; code. | ||
| 111 | ; | ||
| 112 | ; 1.16 7/09/85 ARR Align code more closely to the G.L. | ||
| 113 | ; coding standard. | ||
| 114 | ; | ||
| 115 | ; Changed ITOA routine. Smaller and will print any | ||
| 116 | ; 16 bit value. | ||
| 117 | ; | ||
| 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. | ||
| 121 | ; | ||
| 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 | ||
| 127 | ; values. | ||
| 128 | ; | ||
| 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. | ||
| 132 | ; | ||
| 133 | ; 02/11/86 ARR Message area identified by "TRANSLATION" | ||
| 134 | ; and translation notes added to several | ||
| 135 | ; messages | ||
| 136 | ; | ||
| 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. | ||
| 140 | ; | ||
| 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 | ||
| 144 | ; time. | ||
| 145 | ; | ||
| 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. | ||
| 150 | ; | ||
| 151 | ; 2.00 8/23/87 sp 386 support ( both prot mode transfer and int15 ) | ||
| 152 | ; 286 loadall kludge | ||
| 153 | ; new int15 allocation | ||
| 154 | ; new above_blkmov routine (to handle overlapping | ||
| 155 | ; transfers in above board memory | ||
| 156 | ; olivetti support | ||
| 157 | ; removed int 9 trapping | ||
| 158 | ; reset code different for extended memory | ||
| 159 | ; | ||
| 160 | ; 2.01 9/28/87 sp Fixed bug in parsing for /u option | ||
| 161 | ; | ||
| 162 | ; 2.02 3/02/88 sp Extended PS2 model 80 recognition to more than | ||
| 163 | ; one sub-model | ||
| 164 | ; 2.03 5/13/88 SP extended version check to include dos 4.00 | ||
| 165 | ; | ||
| 166 | ; 2.04 5/23/88 SP reworked messages to mention expanded memory | ||
| 167 | ; | ||
| 168 | ; 2.10 6/13/88 CHIPA Merged in HP Vectra stuff | ||
| 169 | ; 11/20/87 RCP Fixed a20 enabling/disabling problems on | ||
| 170 | ; Vectra machines. | ||
| 171 | ; | ||
| 172 | ; 2.12 7/26/88 SP Ramdrives installed between int12 and A000 are | ||
| 173 | ; no longer attempted. | ||
| 174 | |||
| 175 | BREAK MACRO subtitle | ||
| 176 | SUBTTL subtitle | ||
| 177 | PAGE | ||
| 178 | ENDM | ||
| 179 | |||
| 180 | .286p ; Use some 286 instructions in /E code | ||
| 181 | |||
| 182 | DEBUG EQU 0 | ||
| 183 | |||
| 184 | IF1 | ||
| 185 | IF DEBUG | ||
| 186 | %out DEBUG VERSION!!!!!! | ||
| 187 | ENDIF | ||
| 188 | ENDIF | ||
| 189 | |||
| 190 | .xlist | ||
| 191 | include devsym.inc | ||
| 192 | include syscall.inc | ||
| 193 | include dirent.inc | ||
| 194 | include mi.inc | ||
| 195 | .list | ||
| 196 | |||
| 197 | ; The RAMDrive device driver has 4 basic configurations. | ||
| 198 | ; | ||
| 199 | ; TYPE 1 - /E configuration using PC-AT extended memory and the LOADALL | ||
| 200 | ; instruction. | ||
| 201 | ; | ||
| 202 | ; TYPE 2 - /A configuration using Above Board memory and EMM device | ||
| 203 | ; driver. | ||
| 204 | ; | ||
| 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. | ||
| 209 | ; | ||
| 210 | ; TYPE 4 - RESMEM configuration as TYPE 3 EXCEPT that the RAMDrive | ||
| 211 | ; memory is part of the RAMDrive device driver. | ||
| 212 | ; | ||
| 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. | ||
| 215 | ; | ||
| 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. | ||
| 219 | ; | ||
| 220 | ; The TYPE 1 and TYPE 3 configurations use the EMM control sector to | ||
| 221 | ; control access to the available memory | ||
| 222 | |||
| 223 | include emm.inc | ||
| 224 | |||
| 225 | include loadall.inc | ||
| 226 | |||
| 227 | include above.inc | ||
| 228 | |||
| 229 | include ab_macro.inc | ||
| 230 | |||
| 231 | BREAK <I/O Packet offset declarations> | ||
| 232 | |||
| 233 | ; | ||
| 234 | ; Define I/O packet offsets for useful values. | ||
| 235 | ; | ||
| 236 | ; SEE ALSO | ||
| 237 | ; MS-DOS Technical Reference manual section on Installable Device Drivers | ||
| 238 | ; | ||
| 239 | ; MACHINE ID EQUATES | ||
| 240 | S_OLIVETTI EQU 01H ; Olivetti 6300 PLUS machine | ||
| 241 | S_VECTRA EQU 02H ; Vectra PC machine | ||
| 242 | |||
| 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 | ||
| 247 | |||
| 248 | ; MEDIA CHECK PACKET OFFSETS | ||
| 249 | MCH_RETVAL EQU BYTE PTR (SIZE SRHEAD) + 1 | ||
| 250 | MCH_MEDIA EQU BYTE PTR (SIZE SRHEAD) + 0 | ||
| 251 | |||
| 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 | ||
| 256 | |||
| 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 | ||
| 262 | |||
| 263 | BREAK <some segment definitions> | ||
| 264 | |||
| 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. | ||
| 270 | ;; | ||
| 271 | BiosSeg segment at 40h ;; Used to locate 6300 PLUS reset address | ||
| 272 | org 00a2h | ||
| 273 | RealLoc1 dd 0 | ||
| 274 | BiosSeg ends | ||
| 275 | ; | ||
| 276 | R_Mode_IDT segment at 0h | ||
| 277 | R_mode_IDT ends | ||
| 278 | ; | ||
| 279 | |||
| 280 | BREAK <Device header> | ||
| 281 | |||
| 282 | RAMCODE SEGMENT | ||
| 283 | ASSUME CS:RAMCODE,DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 284 | |||
| 285 | ;** | ||
| 286 | ; | ||
| 287 | ; RAMDRIVE DEVICE HEADER | ||
| 288 | ; | ||
| 289 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 290 | ; | ||
| 291 | ; SEE ALSO | ||
| 292 | ; MS-DOS Technical Reference manual section on | ||
| 293 | ; Installable Device Drivers | ||
| 294 | ; | ||
| 295 | |||
| 296 | RAMDEV LABEL WORD | ||
| 297 | DW -1,-1 | ||
| 298 | DEVATS DW DEVOPCL | ||
| 299 | DW STRATEGY | ||
| 300 | DW RAM$IN | ||
| 301 | DB 1 ;1 RAMDRIVE | ||
| 302 | |||
| 303 | |||
| 304 | BREAK <Command dispatch table> | ||
| 305 | |||
| 306 | ;** | ||
| 307 | ; | ||
| 308 | ; This is the device driver command dispatch table. | ||
| 309 | ; | ||
| 310 | ; The first byte indicates the size of the table and therefore defines | ||
| 311 | ; which device function codes are valid. | ||
| 312 | ; | ||
| 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 | ||
| 315 | ; 3 is: | ||
| 316 | ; WORD at ((RAMTBL + 1) + (2 * 3)) | ||
| 317 | ; | ||
| 318 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 319 | ; | ||
| 320 | ; | ||
| 321 | |||
| 322 | RAMTBL LABEL WORD | ||
| 323 | DB 15 ; Max allowed command code | ||
| 324 | DW RAM$INIT | ||
| 325 | DW MEDIA$CHK | ||
| 326 | DW GET$BPB | ||
| 327 | DW CMDERR | ||
| 328 | DW RAM$READ | ||
| 329 | DW DEVEXIT | ||
| 330 | DW DEVEXIT | ||
| 331 | DW DEVEXIT | ||
| 332 | DW RAM$WRIT | ||
| 333 | DW RAM$WRIT | ||
| 334 | DW DEVEXIT | ||
| 335 | DW DEVEXIT | ||
| 336 | DW DEVEXIT | ||
| 337 | DW DEVEXIT | ||
| 338 | DW DEVEXIT | ||
| 339 | DW RAM$REM | ||
| 340 | |||
| 341 | |||
| 342 | BREAK <BPB and boot sector for installed device> | ||
| 343 | |||
| 344 | ;** RAMDRIVE BIOS PARAMETER BLOCK AND BOGUS BOOT SECTOR | ||
| 345 | ; | ||
| 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. | ||
| 349 | ; | ||
| 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. | ||
| 353 | ; | ||
| 354 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 355 | ; | ||
| 356 | ; | ||
| 357 | |||
| 358 | BOOT_SECTOR LABEL BYTE | ||
| 359 | JMP BOOT_START | ||
| 360 | DB "RDV 1.20" | ||
| 361 | |||
| 362 | RDRIVEBPB: | ||
| 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 | ||
| 374 | |||
| 375 | SEC_SHFT DB 8 ; Shifting number of | ||
| 376 | ; sectors LEFT by this | ||
| 377 | ; many bits yields #words | ||
| 378 | ; in that many sectors. | ||
| 379 | ; 128 6 | ||
| 380 | ; 256 7 | ||
| 381 | ; 512 8 | ||
| 382 | ; 1024 9 | ||
| 383 | |||
| 384 | BOOT_START: | ||
| 385 | JMP BOOT_START | ||
| 386 | |||
| 387 | BOOT_SIG LABEL BYTE | ||
| 388 | DB (128 - (OFFSET BOOT_SIG - OFFSET BOOT_SECTOR)) DUP ("A") | ||
| 389 | |||
| 390 | ; | ||
| 391 | ; The following label is used to determine the size of the boot record | ||
| 392 | ; OFFSET BOOT_END - OFFSET BOOT_SECTOR | ||
| 393 | ; | ||
| 394 | BOOT_END LABEL BYTE | ||
| 395 | |||
| 396 | BREAK <Common Device code> | ||
| 397 | |||
| 398 | ; RAMDRIVE DEVICE ENTRY POINTS - STRATEGY, RAM$IN | ||
| 399 | ; | ||
| 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. | ||
| 403 | ; | ||
| 404 | ; RAM$IN uses RAMTBL to dispatch to the appropriate handler | ||
| 405 | ; for each device function. It also does standard packet | ||
| 406 | ; unpacking. | ||
| 407 | ; | ||
| 408 | ; SEE ALSO | ||
| 409 | ; MS-DOS Technical Reference manual section on | ||
| 410 | ; Installable Device Drivers | ||
| 411 | ; | ||
| 412 | |||
| 413 | ASSUME CS:RAMCODE,DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 414 | |||
| 415 | PTRSAV DD 0 ; Storage location for packet addr | ||
| 416 | |||
| 417 | ;** STRATEGY - Device strategy routine | ||
| 418 | ; | ||
| 419 | ; Standard DOS 2.X 3.X device driver strategy routine. All it does | ||
| 420 | ; is save the packet address in PTRSAV. | ||
| 421 | ; | ||
| 422 | ; ENTRY ES:BX -> Device packet | ||
| 423 | ; EXIT NONE | ||
| 424 | ; USES NONE | ||
| 425 | ; | ||
| 426 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 427 | ; | ||
| 428 | ; | ||
| 429 | |||
| 430 | STRATP PROC FAR | ||
| 431 | |||
| 432 | STRATEGY: | ||
| 433 | MOV WORD PTR [PTRSAV],BX ; Save packet addr | ||
| 434 | MOV WORD PTR [PTRSAV+2],ES | ||
| 435 | RET | ||
| 436 | |||
| 437 | STRATP ENDP | ||
| 438 | |||
| 439 | ;** RAM$IN - Device interrupt routine | ||
| 440 | ; | ||
| 441 | ; Standard DOS 2.X 3.X device driver interrupt routine. | ||
| 442 | ; | ||
| 443 | ; | ||
| 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 | ||
| 449 | ; DS = RAMCODE | ||
| 450 | ; STACK has saved values of all regs but FLAGS | ||
| 451 | ; All function handlers must return through one of | ||
| 452 | ; the standard exit points | ||
| 453 | ; USES FLAGS | ||
| 454 | ; | ||
| 455 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 456 | ; | ||
| 457 | ; | ||
| 458 | |||
| 459 | RAM$IN: | ||
| 460 | PUSH SI | ||
| 461 | PUSH AX | ||
| 462 | PUSH CX | ||
| 463 | PUSH DX | ||
| 464 | PUSH DI | ||
| 465 | PUSH BP | ||
| 466 | PUSH DS | ||
| 467 | PUSH ES | ||
| 468 | PUSH BX | ||
| 469 | |||
| 470 | LDS BX,[PTRSAV] ;GET POINTER TO I/O PACKET | ||
| 471 | ; | ||
| 472 | ; Set up registers for READ or WRITE since this is the most common case | ||
| 473 | ; | ||
| 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 | ||
| 478 | CMP AL,AH | ||
| 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. | ||
| 484 | |||
| 485 | LES DI,DS:[BX.RW_TRANS] ; ES:DI transfer address | ||
| 486 | |||
| 487 | PUSH CS | ||
| 488 | POP DS | ||
| 489 | |||
| 490 | ASSUME DS:RAMCODE | ||
| 491 | |||
| 492 | JMP WORD PTR [SI] ; GO DO COMMAND | ||
| 493 | |||
| 494 | ;** EXIT - ALL ROUTINES RETURN THROUGH ONE OF THESE PATHS | ||
| 495 | ; | ||
| 496 | ; Exit code entry points: | ||
| 497 | ; | ||
| 498 | ; SEE ALSO | ||
| 499 | ; MS-DOS Technical Reference manual section on | ||
| 500 | ; Installable Device Drivers | ||
| 501 | ; | ||
| 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 | ||
| 505 | ; header. | ||
| 506 | ; | ||
| 507 | ; CMDERR - Used when an invalid device command is detected | ||
| 508 | ; | ||
| 509 | ; ENTRY Stack has frame set up by RAM$IN | ||
| 510 | ; EXIT Standard Device driver with error 3 | ||
| 511 | ; USES FLAGS | ||
| 512 | ; | ||
| 513 | ; ERR$CNT - Used when READ or WRITE wants to return with error code. | ||
| 514 | ; The packet RW_COUNT field is zeroed | ||
| 515 | ; | ||
| 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 | ||
| 519 | ; USES FLAGS | ||
| 520 | ; | ||
| 521 | ; ERR$EXIT - Used when a function other that READ or WRITE wants to | ||
| 522 | ; return an error | ||
| 523 | ; | ||
| 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 | ||
| 527 | ; USES FLAGS | ||
| 528 | ; | ||
| 529 | ; DEVEXIT - Used when a function wants to return with no error | ||
| 530 | ; | ||
| 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 | ||
| 538 | ; USES FLAGS | ||
| 539 | ; | ||
| 540 | ; ERR1 - Used when a function wants to return with a value | ||
| 541 | ; for the whole status word | ||
| 542 | ; | ||
| 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 | ||
| 546 | ; USES FLAGS | ||
| 547 | ; | ||
| 548 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 549 | ; | ||
| 550 | ; | ||
| 551 | |||
| 552 | ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 553 | |||
| 554 | CMDERR: | ||
| 555 | MOV AL,3 ;UNKNOWN COMMAND ERROR | ||
| 556 | JMP SHORT ERR$EXIT | ||
| 557 | |||
| 558 | ERR$CNT: | ||
| 559 | LDS BX,[PTRSAV] | ||
| 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 | ||
| 563 | JMP SHORT ERR1 | ||
| 564 | |||
| 565 | EXITP PROC FAR | ||
| 566 | |||
| 567 | DEVEXIT: | ||
| 568 | MOV AH,STDON SHR 8 | ||
| 569 | ERR1: | ||
| 570 | LDS BX,[PTRSAV] | ||
| 571 | MOV [BX.REQSTAT],AX ; Set return status | ||
| 572 | |||
| 573 | POP BX | ||
| 574 | POP ES | ||
| 575 | POP DS | ||
| 576 | POP BP | ||
| 577 | POP DI | ||
| 578 | POP DX | ||
| 579 | POP CX | ||
| 580 | POP AX | ||
| 581 | POP SI | ||
| 582 | RET ;RESTORE REGS AND RETURN | ||
| 583 | EXITP ENDP | ||
| 584 | |||
| 585 | |||
| 586 | ;** MEDIA$CHK - Device Driver Media check routine | ||
| 587 | ; | ||
| 588 | ; RAMDRIVE Media check routine. ALWAYS returns media not changed | ||
| 589 | ; | ||
| 590 | ; SEE ALSO | ||
| 591 | ; MS-DOS Technical Reference manual section on | ||
| 592 | ; Installable Device Drivers | ||
| 593 | ; | ||
| 594 | ; ENTRY from RAM$IN | ||
| 595 | ; EXIT through DEVEXIT | ||
| 596 | ; USES DS,BX | ||
| 597 | ; | ||
| 598 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 599 | ; | ||
| 600 | |||
| 601 | MEDIA$CHK: | ||
| 602 | ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 603 | LDS BX,[PTRSAV] | ||
| 604 | ASSUME DS:NOTHING | ||
| 605 | MOV [BX.MCH_RETVAL],1 ; ALWAYS NOT CHANGED | ||
| 606 | JMP DEVEXIT | ||
| 607 | |||
| 608 | ;** GET$BPB - Device Driver Build BPB routine | ||
| 609 | ; | ||
| 610 | ; RAMDRIVE Build BPB routine. Returns pointer to BPB at RDRIVEBPB | ||
| 611 | ; | ||
| 612 | ; SEE ALSO | ||
| 613 | ; MS-DOS Technical Reference manual section on | ||
| 614 | ; Installable Device Drivers | ||
| 615 | ; | ||
| 616 | ; ENTRY from RAM$IN | ||
| 617 | ; EXIT through DEVEXIT | ||
| 618 | ; USES DS,BX | ||
| 619 | ; | ||
| 620 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 621 | ; | ||
| 622 | |||
| 623 | GET$BPB: | ||
| 624 | ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 625 | LDS BX,[PTRSAV] | ||
| 626 | ASSUME DS:NOTHING | ||
| 627 | MOV WORD PTR [BX.BPB_BPB],OFFSET RDRIVEBPB | ||
| 628 | MOV WORD PTR [BX.BPB_BPB + 2],CS | ||
| 629 | JMP DEVEXIT | ||
| 630 | |||
| 631 | ;** RAM$REM - Device Driver Removable Media routine | ||
| 632 | ; | ||
| 633 | ; RAMDRIVE Removable Media routine. ALWAYS returns media not removable | ||
| 634 | ; NOTE: This routine is never called if running on DOS 2.X | ||
| 635 | ; | ||
| 636 | ; SEE ALSO | ||
| 637 | ; MS-DOS Technical Reference manual section on | ||
| 638 | ; Installable Device Drivers | ||
| 639 | ; | ||
| 640 | ; ENTRY from RAM$IN | ||
| 641 | ; EXIT through ERR1 | ||
| 642 | ; USES AX | ||
| 643 | ; | ||
| 644 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 645 | ; | ||
| 646 | |||
| 647 | RAM$REM: | ||
| 648 | ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 649 | MOV AX,STBUI + STDON ; Media NOT removable | ||
| 650 | JMP ERR1 | ||
| 651 | |||
| 652 | ;** RAM$READ - Device Driver READ routine | ||
| 653 | ; | ||
| 654 | ; RAMDRIVE READ routine. Perform device READ by calling MEMIO | ||
| 655 | ; | ||
| 656 | ; SEE ALSO | ||
| 657 | ; MS-DOS Technical Reference manual section on | ||
| 658 | ; Installable Device Drivers | ||
| 659 | ; | ||
| 660 | ; DO_OP entry point used by RAM$WRITE | ||
| 661 | ; | ||
| 662 | ; ENTRY from RAM$IN | ||
| 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 | ||
| 667 | ; USES ALL | ||
| 668 | ; | ||
| 669 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 670 | ; | ||
| 671 | |||
| 672 | RAM$READ: | ||
| 673 | ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 674 | XOR BH,BH | ||
| 675 | DO_OP: | ||
| 676 | CALL MEMIO | ||
| 677 | JC T_ERR | ||
| 678 | JMP DEVEXIT | ||
| 679 | |||
| 680 | T_ERR: ; AL has error number | ||
| 681 | JMP ERR$CNT | ||
| 682 | |||
| 683 | ;** RAM$WRITE - Device Driver WRITE routine | ||
| 684 | ; | ||
| 685 | ; RAMDRIVE WRITE routine. Perform device WRITE by calling MEMIO | ||
| 686 | ; | ||
| 687 | ; SEE ALSO | ||
| 688 | ; MS-DOS Technical Reference manual section on | ||
| 689 | ; Installable Device Drivers | ||
| 690 | ; | ||
| 691 | ; ENTRY from RAM$IN | ||
| 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) | ||
| 696 | ; USES BH | ||
| 697 | ; | ||
| 698 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 699 | ; | ||
| 700 | |||
| 701 | RAM$WRIT: | ||
| 702 | ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 703 | MOV BH,1 | ||
| 704 | JMP DO_OP | ||
| 705 | |||
| 706 | ;** MEMIO - Perform READ or WRITE to RAMDrive | ||
| 707 | ; | ||
| 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. | ||
| 715 | ; | ||
| 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. | ||
| 722 | ; | ||
| 723 | ; ENTRY: | ||
| 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 | ||
| 728 | ; EXIT: | ||
| 729 | ; If error detected | ||
| 730 | ; Carry Set | ||
| 731 | ; Error on operation, AL is error number | ||
| 732 | ; else | ||
| 733 | ; through BLKMOV | ||
| 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 | ||
| 738 | ; USES: | ||
| 739 | ; AX, DX, CX, FLAGS | ||
| 740 | ; | ||
| 741 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 742 | ; | ||
| 743 | |||
| 744 | SEC_NOT_FOUND: | ||
| 745 | MOV AL,8 ; Sector not found error | ||
| 746 | STC | ||
| 747 | RET | ||
| 748 | |||
| 749 | MEMIO: | ||
| 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 | ||
| 753 | MOV AX,DX | ||
| 754 | ADD AX,CX | ||
| 755 | CMP AX,[SECLIM] | ||
| 756 | JA SEC_NOT_FOUND ; End is beyond end | ||
| 757 | ; | ||
| 758 | ; Convert sector count to word count | ||
| 759 | ; | ||
| 760 | MOV AX,CX | ||
| 761 | MOV CL,[SEC_SHFT] | ||
| 762 | SHL AX,CL ; AX is # words to move | ||
| 763 | JNC CNT_SET ; Overflow??? | ||
| 764 | MOV AX,8000H ; Limit to 64K bytes | ||
| 765 | CNT_SET: | ||
| 766 | MOV CX,AX | ||
| 767 | ; | ||
| 768 | ; Now compute start offset of I/O | ||
| 769 | ; | ||
| 770 | MOV AX,DX | ||
| 771 | MUL [SSIZE] ; DX:AX is byte offset of start | ||
| 772 | JMP BLKMOV ; Perform I/O | ||
| 773 | |||
| 774 | BREAK <Work Area for Ramdrive> | ||
| 775 | |||
| 776 | S5_FLAG DB 0 ;; S_OLIVETTI means 6300 PLUS machine | ||
| 777 | ;; S_VECTRA means Vectra machine | ||
| 778 | |||
| 779 | A20On dw 0DF90h | ||
| 780 | A20Off dw 0DD00h | ||
| 781 | |||
| 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. | ||
| 792 | ; | ||
| 793 | ; The system flag bit assignments are: | ||
| 794 | ; | ||
| 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 | ||
| 805 | |||
| 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. | ||
| 808 | ; | ||
| 809 | sys_flg db ? | ||
| 810 | ; | ||
| 811 | ; equates used for the system flag | ||
| 812 | ; | ||
| 813 | M_286 equ 00000001B | ||
| 814 | M_386 equ 00000010B | ||
| 815 | M_PS2 equ 00000100B | ||
| 816 | M_OLI equ 00001000B | ||
| 817 | A20_ST equ 00010000B | ||
| 818 | DOS_33 equ 00100000B | ||
| 819 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 820 | ; A20 address line state determination addresses | ||
| 821 | ; | ||
| 822 | low_mem label dword | ||
| 823 | dw 20h*4 | ||
| 824 | dw 0 | ||
| 825 | |||
| 826 | high_mem label dword | ||
| 827 | dw 20h*4 + 10h | ||
| 828 | dw 0ffffh | ||
| 829 | |||
| 830 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 831 | ; A20 PS2 equates | ||
| 832 | ; | ||
| 833 | PS2_PORTA equ 0092h | ||
| 834 | GATE_A20 equ 010b | ||
| 835 | |||
| 836 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 837 | ; 386 working areas | ||
| 838 | start_gdt label byte | ||
| 839 | nul_des desc <> | ||
| 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> | ||
| 844 | end_gdt label byte | ||
| 845 | |||
| 846 | emm_gdt gdt_descriptor <end_gdt-start_gdt,0,0> | ||
| 847 | ; | ||
| 848 | ; int 15 gdt | ||
| 849 | ; | ||
| 850 | int15_gdt label byte | ||
| 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 | ||
| 857 | |||
| 858 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 859 | |||
| 860 | BREAK <Drive code for /E driver> | ||
| 861 | |||
| 862 | ; | ||
| 863 | ; The following label defines the start of the I/O code which is driver type | ||
| 864 | ; specific. | ||
| 865 | ; | ||
| 866 | ; THE TYPE 2 driver must REPLACE this code with code appropriate | ||
| 867 | ; to the driver type. | ||
| 868 | ; | ||
| 869 | EVEN ; Force start of drive code to word boundary | ||
| 870 | |||
| 871 | DRIVE_CODE LABEL WORD | ||
| 872 | |||
| 873 | EXTMEM_LOW EQU 0000H ; 24 bit addr of start of extended memory | ||
| 874 | EXTMEM_HIGH EQU 0010H | ||
| 875 | |||
| 876 | ;** BASE_ADDR data element | ||
| 877 | ; | ||
| 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. | ||
| 881 | ; | ||
| 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. | ||
| 885 | ; | ||
| 886 | ; NOTE: This data element is shared by TYPE 1, 2 drivers, but | ||
| 887 | ; its meaning and correct initial value are driver type specific. | ||
| 888 | ; | ||
| 889 | |||
| 890 | ;; NOTE: The value at BASE_ADDR is patched during initialization when | ||
| 891 | ;; loading a RAMDrive into upper extended memory on a PLUS | ||
| 892 | ;; | ||
| 893 | BASE_ADDR LABEL DWORD ; 24 bit address of start of this RAMDRV | ||
| 894 | DW EXTMEM_LOW | ||
| 895 | DW EXTMEM_HIGH | ||
| 896 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 897 | ;** BLKMOV - Perform transfer for TYPE 1 driver | ||
| 898 | ; | ||
| 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". | ||
| 909 | ; | ||
| 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. | ||
| 913 | ; | ||
| 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 | ||
| 918 | ; range. | ||
| 919 | ; | ||
| 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. | ||
| 927 | ; | ||
| 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. | ||
| 933 | ; | ||
| 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 | ||
| 940 | ; INT13 MEMORY. | ||
| 941 | ; | ||
| 942 | ; METHOD: | ||
| 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 | ||
| 948 | ; CLI | ||
| 949 | ; copy 80:0 to INT13 buffer | ||
| 950 | ; copy LOADALL info to 80:0 | ||
| 951 | ; LOADALL | ||
| 952 | ; do 256 word transfer | ||
| 953 | ; copy INT13 80:0 buffer back to 80:0 | ||
| 954 | ; STI | ||
| 955 | ; Disable address line 20 | ||
| 956 | ; | ||
| 957 | ; SEE ALSO | ||
| 958 | ; INTEL special documentation of LOADALL instruction | ||
| 959 | ; | ||
| 960 | ; ENTRY: | ||
| 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 | ||
| 965 | ; | ||
| 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 | ||
| 970 | ; | ||
| 971 | ; EXIT: | ||
| 972 | ; Carry Clear | ||
| 973 | ; OK, operation performed successfully | ||
| 974 | ; Carry Set | ||
| 975 | ; Error during operation, AL is error number (INT 13 error) | ||
| 976 | ; | ||
| 977 | ; USES: | ||
| 978 | ; ALL | ||
| 979 | ; | ||
| 980 | ; This routine is specific to TYPE 1 driver | ||
| 981 | ; | ||
| 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 | ||
| 989 | |||
| 990 | BLKMOV: | ||
| 991 | ASSUME DS:ramcode,ES:NOTHING,SS:NOTHING | ||
| 992 | test [sys_flg],M_386 | ||
| 993 | je blkmov_286 | ||
| 994 | jmp blkmov_386 | ||
| 995 | ; | ||
| 996 | ; Compute 32 bit address of start of I/O | ||
| 997 | ; | ||
| 998 | blkmov_286: | ||
| 999 | ADD AX,WORD PTR [BASE_ADDR] | ||
| 1000 | ADC DX,WORD PTR [BASE_ADDR + 2] | ||
| 1001 | ; | ||
| 1002 | ; Dispatch on function | ||
| 1003 | ; | ||
| 1004 | OR BH,BH | ||
| 1005 | JZ READ_IT | ||
| 1006 | ; | ||
| 1007 | ; Write | ||
| 1008 | ; | ||
| 1009 | MOV WORD PTR [ESDES.SEG_BASE],AX | ||
| 1010 | MOV BYTE PTR [ESDES.SEG_BASE + 2],DL | ||
| 1011 | ; MOV [LSI],DI | ||
| 1012 | mov [lbx],di ;sp | ||
| 1013 | MOV [LDI],0 | ||
| 1014 | MOV SI,OFFSET DSDES | ||
| 1015 | JMP SHORT SET_TRANS | ||
| 1016 | |||
| 1017 | READ_IT: | ||
| 1018 | MOV WORD PTR [DSDES.SEG_BASE],AX | ||
| 1019 | MOV BYTE PTR [DSDES.SEG_BASE + 2],DL | ||
| 1020 | MOV [LDI],DI | ||
| 1021 | ; MOV [LSI],0 ;sp | ||
| 1022 | mov [lbx],0 | ||
| 1023 | MOV SI,OFFSET ESDES | ||
| 1024 | SET_TRANS: | ||
| 1025 | MOV AX,ES | ||
| 1026 | CALL SEG_SET ; Set ES or DS segreg | ||
| 1027 | ; | ||
| 1028 | ; Set stack descriptor | ||
| 1029 | ; | ||
| 1030 | MOV AX,SS | ||
| 1031 | MOV [LSSS],AX | ||
| 1032 | MOV SI,OFFSET SSDES | ||
| 1033 | CALL SEG_SET | ||
| 1034 | MOV [LSP],SP | ||
| 1035 | ; SUB [LSP],2 ; CX is on stack at LOADALL | ||
| 1036 | ; | ||
| 1037 | ; the loadall kludge | ||
| 1038 | ; | ||
| 1039 | mov ax,cs ;sp | ||
| 1040 | inc ax ;sp | ||
| 1041 | mov [lcss],ax ;sp | ||
| 1042 | mov si,offset CSDES ;sp | ||
| 1043 | mov ax,cs ;sp | ||
| 1044 | call seg_set ;sp | ||
| 1045 | ; | ||
| 1046 | ; Set Other LOADALL stuff | ||
| 1047 | ; | ||
| 1048 | SMSW [LDSW] | ||
| 1049 | SIDT FWORD PTR [IDTDES] | ||
| 1050 | SGDT FWORD PTR [GDTDES] | ||
| 1051 | ; | ||
| 1052 | ; NOW The damn SXXX instructions store the desriptors in a | ||
| 1053 | ; different order than LOADALL wants | ||
| 1054 | ; | ||
| 1055 | MOV SI,OFFSET IDTDES | ||
| 1056 | CALL FIX_DESCRIPTOR | ||
| 1057 | MOV SI,OFFSET GDTDES | ||
| 1058 | CALL FIX_DESCRIPTOR | ||
| 1059 | ; | ||
| 1060 | ; Enable address line 20 | ||
| 1061 | ; | ||
| 1062 | |||
| 1063 | ;; | ||
| 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. | ||
| 1069 | ;; | ||
| 1070 | |||
| 1071 | ;; MOV AH,0DFH | ||
| 1072 | mov ax,cs:[A20On] ;; set up for PLUS or AT | ||
| 1073 | CALL A20 | ||
| 1074 | Jc NR_ERR | ||
| 1075 | ; JMP SHORT IO_START ;sp | ||
| 1076 | jmp short move_main_loop ;sp | ||
| 1077 | |||
| 1078 | NR_ERR: | ||
| 1079 | MOV AL,02 ; Drive not ready error | ||
| 1080 | STC | ||
| 1081 | RET | ||
| 1082 | io_donej: jmp io_done | ||
| 1083 | ;IOLOOP: ;sp | ||
| 1084 | ; PUSH CX ;sp | ||
| 1085 | |||
| 1086 | move_main_loop: ;sp | ||
| 1087 | assume ds:nothing ;sp | ||
| 1088 | jcxz io_donej ;sp | ||
| 1089 | mov cs:[ldx],cx ;sp | ||
| 1090 | MOV AX,80H | ||
| 1091 | MOV DS,AX | ||
| 1092 | PUSH CS | ||
| 1093 | POP ES | ||
| 1094 | XOR SI,SI | ||
| 1095 | MOV DI,OFFSET cs:[SWAP_80] | ||
| 1096 | MOV CX,102/2 | ||
| 1097 | mov cs:[ssSave],ss | ||
| 1098 | CLD | ||
| 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 | ||
| 1102 | ; of 80:0 | ||
| 1103 | REP MOVSW ; Save contents of 80:0 | ||
| 1104 | mml$1: | ||
| 1105 | PUSH DS | ||
| 1106 | PUSH ES | ||
| 1107 | POP DS | ||
| 1108 | POP ES | ||
| 1109 | XOR DI,DI | ||
| 1110 | MOV SI,OFFSET cs:LOADALL_TBL | ||
| 1111 | MOV CX,102/2 | ||
| 1112 | REP MOVSW ; Transfer in LOADALL info | ||
| 1113 | DW 050FH ; LOADALL INSTRUCTION | ||
| 1114 | AFTER_LOADALL: | ||
| 1115 | ; set up stack for moving 80:0 information back again | ||
| 1116 | ; | ||
| 1117 | xor bp,bp | ||
| 1118 | mov ss,ax | ||
| 1119 | mov si,offset cs:[swap_80] | ||
| 1120 | mov cx,102/2 | ||
| 1121 | test [sys_flg],dos_33 | ||
| 1122 | jne mml$2 | ||
| 1123 | move_loop: | ||
| 1124 | lods word ptr cs:[si] | ||
| 1125 | mov ss:[bp],ax | ||
| 1126 | inc bp | ||
| 1127 | inc bp | ||
| 1128 | loop move_loop | ||
| 1129 | mml$2: | ||
| 1130 | mov ss,cs:[ssSave] | ||
| 1131 | mov cx,dx | ||
| 1132 | mov si,bx | ||
| 1133 | ;critical code | ||
| 1134 | sti | ||
| 1135 | rep movsw | ||
| 1136 | cli ; bugfix sunilp | ||
| 1137 | mov ax,cs | ||
| 1138 | dec ax | ||
| 1139 | push ax | ||
| 1140 | mov ax,offset io_done | ||
| 1141 | push ax | ||
| 1142 | db 0cbh | ||
| 1143 | ; | ||
| 1144 | db 16 dup (0fah) ; bugfix sunilp | ||
| 1145 | mov ax,cs | ||
| 1146 | dec ax | ||
| 1147 | push ax | ||
| 1148 | mov ax,offset resume_int | ||
| 1149 | push ax | ||
| 1150 | db 0cbh | ||
| 1151 | ; | ||
| 1152 | resume_int: | ||
| 1153 | mov cs:[ldi],di | ||
| 1154 | mov cs:[lbx],si | ||
| 1155 | jmp move_main_loop | ||
| 1156 | |||
| 1157 | ; REP MOVSW ; Move data | ||
| 1158 | ;IO_START: | ||
| 1159 | ; JCXZ IODN | ||
| 1160 | ; MOV WORD PTR [LCX],256 ; ASSUME full block | ||
| 1161 | ; SUB CX,256 | ||
| 1162 | ; JNC IOLOOP ; OK | ||
| 1163 | ; ADD [LCX],CX ; OOPs, partial block | ||
| 1164 | ; XOR CX,CX ; This is the last block | ||
| 1165 | ; JMP IOLOOP | ||
| 1166 | |||
| 1167 | ;IODN: | ||
| 1168 | io_done: | ||
| 1169 | sti ; bugfix sunilp | ||
| 1170 | MOV CX,800H ; Retry this many times | ||
| 1171 | OFFLP: | ||
| 1172 | |||
| 1173 | ;; | ||
| 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. | ||
| 1176 | ;; | ||
| 1177 | |||
| 1178 | ;; MOV AH,0DDH | ||
| 1179 | mov ax,cs:[A20Off] ;; setup for PLUS or AT. ah for IBM, al for PLUS | ||
| 1180 | CALL A20 ; Disable address line 20 | ||
| 1181 | jnc dis_done | ||
| 1182 | LOOP OFFLP | ||
| 1183 | dis_done: | ||
| 1184 | CLC | ||
| 1185 | RET | ||
| 1186 | |||
| 1187 | ;** A20 - ENABLE/DISABLE ADDRESS LINE 20 ON IBM PC-AT | ||
| 1188 | ; | ||
| 1189 | ; This routine enables/disables address line 20 by twiddling bits | ||
| 1190 | ; in one of the keyboard controller registers. | ||
| 1191 | ; | ||
| 1192 | ; SEE ALSO | ||
| 1193 | ; IBM Technical Reference Personal Computer AT Manual #1502243 | ||
| 1194 | ; Page 5-155 | ||
| 1195 | ; | ||
| 1196 | ; ENTRY | ||
| 1197 | ; AH = 0DDH to disable A20 | ||
| 1198 | ; AH = 0DFH to enable A20 | ||
| 1199 | ; EXIT | ||
| 1200 | ; CY Failed | ||
| 1201 | ; NC Succeeded | ||
| 1202 | ; USES | ||
| 1203 | ; AL, FLAGS | ||
| 1204 | ; | ||
| 1205 | ; WARNING If this routine is called in a CLI state this routine has | ||
| 1206 | ; the side effect of enabling interrupts. | ||
| 1207 | ; | ||
| 1208 | ; This routine is specific to TYPE 1 driver | ||
| 1209 | ; | ||
| 1210 | |||
| 1211 | A20: | ||
| 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 | ||
| 1217 | jmp a20s5 | ||
| 1218 | test_vec: | ||
| 1219 | cmp cs:[S5_FLAG],S_VECTRA | ||
| 1220 | jne test_ps2 | ||
| 1221 | jmp VecA20 | ||
| 1222 | test_ps2: | ||
| 1223 | test cs:[sys_flg],M_PS2 ; is it a ps2 machine | ||
| 1224 | jne a20ps2 ; if yes it has separate a20 routine | ||
| 1225 | old_a20: | ||
| 1226 | CLI | ||
| 1227 | call check_a20 ; check to see if it can be enb /disb | ||
| 1228 | jc a20suc ; no it may not be toggled | ||
| 1229 | CALL E_8042 | ||
| 1230 | JNZ a20err | ||
| 1231 | MOV AL,0D1H | ||
| 1232 | OUT 64H,AL | ||
| 1233 | CALL E_8042 | ||
| 1234 | JNZ a20err | ||
| 1235 | MOV AL,AH | ||
| 1236 | OUT 60H,AL | ||
| 1237 | CALL E_8042 | ||
| 1238 | JNZ a20err | ||
| 1239 | ; | ||
| 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!) | ||
| 1247 | ; | ||
| 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 | ||
| 1251 | jnz A20Err | ||
| 1252 | |||
| 1253 | A20Suc: sti | ||
| 1254 | clc | ||
| 1255 | RET | ||
| 1256 | A20Err: sti | ||
| 1257 | stc | ||
| 1258 | ret | ||
| 1259 | ; | ||
| 1260 | ; Helper routine for A20. It waits for the keyboard controller to be "ready". | ||
| 1261 | ; | ||
| 1262 | E_8042: | ||
| 1263 | ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 1264 | PUSH CX | ||
| 1265 | XOR CX,CX | ||
| 1266 | E_LOOP: | ||
| 1267 | IN AL,64H | ||
| 1268 | AND AL,2 | ||
| 1269 | LOOPNZ E_LOOP | ||
| 1270 | POP CX | ||
| 1271 | RET | ||
| 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 | ||
| 1276 | ; is allowed | ||
| 1277 | ; | ||
| 1278 | check_a20: | ||
| 1279 | assume ds:nothing,es:nothing,ss:nothing | ||
| 1280 | cmp ah,0ddh ; is it a disable operation | ||
| 1281 | jne check_a20_enable | ||
| 1282 | ; | ||
| 1283 | ; check if a20 disabling allowed | ||
| 1284 | ; | ||
| 1285 | test cs:[sys_flg],a20_st | ||
| 1286 | jne no_toggle | ||
| 1287 | toggle: clc | ||
| 1288 | ret | ||
| 1289 | ; | ||
| 1290 | ; a20 enabling, check if allowed | ||
| 1291 | ; | ||
| 1292 | check_a20_enable: | ||
| 1293 | and cs:[sys_flg], not A20_ST | ||
| 1294 | push cx | ||
| 1295 | push ds | ||
| 1296 | push si | ||
| 1297 | push es | ||
| 1298 | push di | ||
| 1299 | lds si,cs:low_mem | ||
| 1300 | les di,cs:high_mem | ||
| 1301 | mov cx,3 | ||
| 1302 | cld | ||
| 1303 | repe cmpsw | ||
| 1304 | pop di | ||
| 1305 | pop es | ||
| 1306 | pop si | ||
| 1307 | pop ds | ||
| 1308 | jcxz not_enabled | ||
| 1309 | pop cx | ||
| 1310 | or cs:[sys_flg],A20_ST | ||
| 1311 | no_toggle: | ||
| 1312 | stc | ||
| 1313 | ret | ||
| 1314 | not_enabled: | ||
| 1315 | pop cx | ||
| 1316 | clc | ||
| 1317 | ret | ||
| 1318 | |||
| 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. | ||
| 1322 | A20PS2: | ||
| 1323 | assume ds:nothing,es:nothing,ss:nothing | ||
| 1324 | cli | ||
| 1325 | ; | ||
| 1326 | ; first separate disable operation from enable operation | ||
| 1327 | ; | ||
| 1328 | cmp ah,0ddh | ||
| 1329 | je disbl_PS2 | ||
| 1330 | ; | ||
| 1331 | ; enabling the a20 | ||
| 1332 | ; | ||
| 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 | ||
| 1336 | je set_it ; | ||
| 1337 | or cs:[sys_flg],A20_ST ; indicate that it was already set | ||
| 1338 | ps2a20suc: | ||
| 1339 | clc | ||
| 1340 | sti | ||
| 1341 | ret | ||
| 1342 | |||
| 1343 | set_it: push cx | ||
| 1344 | xor cx,cx | ||
| 1345 | or al,GATE_A20 | ||
| 1346 | out PS2_PORTA,al ; set it | ||
| 1347 | see_agn: | ||
| 1348 | in al,PS2_PORTA ; read status again | ||
| 1349 | test al,GATE_A20 | ||
| 1350 | loopz see_agn | ||
| 1351 | pop cx | ||
| 1352 | jz ps2err | ||
| 1353 | clc | ||
| 1354 | sti | ||
| 1355 | ret | ||
| 1356 | ; | ||
| 1357 | ; disabling the ps2 | ||
| 1358 | ; | ||
| 1359 | disbl_PS2: | ||
| 1360 | test cs:[sys_flg],A20_ST | ||
| 1361 | jne ps2a20suc | ||
| 1362 | ; | ||
| 1363 | push cx | ||
| 1364 | xor cx,cx | ||
| 1365 | in al,PS2_PORTA | ||
| 1366 | and al,not GATE_A20 | ||
| 1367 | out PS2_PORTA,al | ||
| 1368 | see_agn1: | ||
| 1369 | in al,PS2_PORTA | ||
| 1370 | test al,GATE_A20 | ||
| 1371 | loopnz see_agn1 | ||
| 1372 | pop cx | ||
| 1373 | jnz ps2err | ||
| 1374 | clc | ||
| 1375 | sti | ||
| 1376 | ret | ||
| 1377 | ; | ||
| 1378 | ps2err: | ||
| 1379 | stc | ||
| 1380 | sti | ||
| 1381 | ret | ||
| 1382 | |||
| 1383 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 1384 | ;;* VECA20 - Address enable/disable routine for Vectra family computers | ||
| 1385 | ;; | ||
| 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. | ||
| 1392 | ;; | ||
| 1393 | ;; Uses al, flags | ||
| 1394 | ;; Has same results as A20 | ||
| 1395 | ;; | ||
| 1396 | VecA20: | ||
| 1397 | CLI | ||
| 1398 | call check_a20 | ||
| 1399 | jc VecA20Suc | ||
| 1400 | call E_8042 | ||
| 1401 | jnz VecA20Err | ||
| 1402 | mov al,ah ;sigle byte command is code passed | ||
| 1403 | out 64H,al | ||
| 1404 | call E_8042 | ||
| 1405 | jnz VecA20Err | ||
| 1406 | ; | ||
| 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 | ||
| 1413 | out 64H,al | ||
| 1414 | call E_8042 | ||
| 1415 | jnz VecA20Err | ||
| 1416 | VecA20Suc: | ||
| 1417 | sti | ||
| 1418 | clc | ||
| 1419 | ret | ||
| 1420 | VecA20Err: | ||
| 1421 | sti | ||
| 1422 | stc | ||
| 1423 | ret | ||
| 1424 | |||
| 1425 | |||
| 1426 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 1427 | ;;* A20S5 - Address enable/disable routine for the 6300 PLUS. | ||
| 1428 | ;; | ||
| 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 | ||
| 1437 | ;; is to continue. | ||
| 1438 | ;; | ||
| 1439 | ;; Uses ax, flags. | ||
| 1440 | ;; Returns with zero flag set. | ||
| 1441 | ;; | ||
| 1442 | A20S5: | ||
| 1443 | ; test [reboot_flg],0ffh ;; sunilp | ||
| 1444 | ; jne a20s5boot ;; sunilp | ||
| 1445 | cli | ||
| 1446 | or al,al ;; if zero, then resetting processor | ||
| 1447 | jnz A20S5Next | ||
| 1448 | call RSet ;; must return with entry value of ax | ||
| 1449 | A20S5Next: | ||
| 1450 | push dx ;; set/reset port | ||
| 1451 | mov dx,3f20h | ||
| 1452 | out dx,al | ||
| 1453 | pop dx | ||
| 1454 | clc ;; sunilp modification cy flag now important | ||
| 1455 | STI | ||
| 1456 | RET | ||
| 1457 | |||
| 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 | ||
| 1461 | cli | ||
| 1462 | jmp short a20s5next | ||
| 1463 | |||
| 1464 | OldStackSeg dw 0 ;; used during PLUS processor reset | ||
| 1465 | ;; to save the stack segment | ||
| 1466 | |||
| 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 | ||
| 1471 | ;; | ||
| 1472 | ;; Uses flags. | ||
| 1473 | ;; | ||
| 1474 | RSet: | ||
| 1475 | pusha ;; save world | ||
| 1476 | push ds ;; save segments | ||
| 1477 | push es | ||
| 1478 | mov ax,BiosSeg ;; point to the bios segment | ||
| 1479 | mov ds,ax ;; ds -> 40h | ||
| 1480 | assume ds:BiosSeg | ||
| 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 | ||
| 1485 | assume ds:nothing | ||
| 1486 | mov [OldStackSeg],ss ;; save the stack segment, too | ||
| 1487 | mov dx,03f00h ;; reset the processor | ||
| 1488 | in ax,dx | ||
| 1489 | nop | ||
| 1490 | nop | ||
| 1491 | nop | ||
| 1492 | cli | ||
| 1493 | hlt ;; should never get here | ||
| 1494 | ReturnBack: | ||
| 1495 | mov ss,[OldStackSeg] ;; start the recovery | ||
| 1496 | assume ds:BiosSeg | ||
| 1497 | pop word ptr [RealLoc1+2] | ||
| 1498 | pop word ptr [RealLoc1] | ||
| 1499 | pop es | ||
| 1500 | pop ds | ||
| 1501 | popa | ||
| 1502 | ret | ||
| 1503 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 1504 | blkmov_386: ;_protect: | ||
| 1505 | assume ds:ramcode,es:nothing,ss:nothing | ||
| 1506 | ; | ||
| 1507 | ; Compute 32 bit address of start of I/O | ||
| 1508 | ; | ||
| 1509 | add ax,word ptr [base_addr] | ||
| 1510 | adc dx,word ptr [base_addr + 2] | ||
| 1511 | ; | ||
| 1512 | push cx | ||
| 1513 | ; | ||
| 1514 | ; Are we in virtual mode | ||
| 1515 | ; | ||
| 1516 | smsw cx | ||
| 1517 | test cx,01B ; is the pe bit set | ||
| 1518 | je pr_mode_tran | ||
| 1519 | |||
| 1520 | jmp int_15_tran | ||
| 1521 | ; | ||
| 1522 | ; Dispatch on function | ||
| 1523 | ; | ||
| 1524 | pr_mode_tran: | ||
| 1525 | or bh,bh | ||
| 1526 | jz read_it_1 | ||
| 1527 | ; | ||
| 1528 | ; Write | ||
| 1529 | ; | ||
| 1530 | ; Update ES descriptor with address of track in cache | ||
| 1531 | ; | ||
| 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 | ||
| 1536 | ; | ||
| 1537 | ; Update DS descriptor with transfer address | ||
| 1538 | ; | ||
| 1539 | mov ax,es | ||
| 1540 | mov cx,16 | ||
| 1541 | mul cx | ||
| 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 | ||
| 1546 | |||
| 1547 | |||
| 1548 | ; Switch SI and DI for write transfer | ||
| 1549 | |||
| 1550 | mov si,di | ||
| 1551 | xor di,di | ||
| 1552 | |||
| 1553 | jmp short set_trans_1 | ||
| 1554 | |||
| 1555 | read_it_1: | ||
| 1556 | ; | ||
| 1557 | ; Update DS descriptor with address of track in cache | ||
| 1558 | ; | ||
| 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 | ||
| 1563 | ; | ||
| 1564 | ; Update ES descriptor with transfer address | ||
| 1565 | ; | ||
| 1566 | mov ax,es | ||
| 1567 | mov cx,16 | ||
| 1568 | mul cx | ||
| 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 | ||
| 1573 | ; | ||
| 1574 | ; Keep SI and DI the same for read transfer | ||
| 1575 | ; | ||
| 1576 | xor si,si | ||
| 1577 | |||
| 1578 | set_trans_1: | ||
| 1579 | ; | ||
| 1580 | ; Restore Transfer Count | ||
| 1581 | ; | ||
| 1582 | pop cx | ||
| 1583 | |||
| 1584 | ; | ||
| 1585 | mov ax,cs:[A20On] | ||
| 1586 | call A20 | ||
| 1587 | jc nr_err_1 | ||
| 1588 | ; | ||
| 1589 | ; we shall do the transfer 1024 words at a time | ||
| 1590 | ; | ||
| 1591 | db 66h | ||
| 1592 | push ax | ||
| 1593 | mov bx,cx | ||
| 1594 | assume ds:nothing | ||
| 1595 | pr_io_agn_1: | ||
| 1596 | mov cx,1024 | ||
| 1597 | cmp bx,cx | ||
| 1598 | ja pr_strt_1 | ||
| 1599 | mov cx,bx | ||
| 1600 | pr_strt_1: | ||
| 1601 | sub bx,cx | ||
| 1602 | cli ; Un interruptable | ||
| 1603 | cld | ||
| 1604 | lgdt fword ptr emm_gdt | ||
| 1605 | |||
| 1606 | |||
| 1607 | ; | ||
| 1608 | ; Switch to protected mode | ||
| 1609 | ; | ||
| 1610 | db 66h,0Fh, 20h, 0 ;mov eax,cr0 | ||
| 1611 | or ax,1 | ||
| 1612 | db 66h,0Fh,22h, 0 ;mov cr0,eax | ||
| 1613 | ; | ||
| 1614 | ; Clear prefetch queue | ||
| 1615 | ; | ||
| 1616 | db 0eah ; far jump | ||
| 1617 | dw offset flush_prefetch | ||
| 1618 | dw cs_des - start_gdt | ||
| 1619 | ; | ||
| 1620 | flush_prefetch: | ||
| 1621 | assume cs:nothing | ||
| 1622 | ; | ||
| 1623 | ; Initialize segment registers | ||
| 1624 | ; | ||
| 1625 | mov ax,ds_des - start_gdt | ||
| 1626 | mov ds,ax | ||
| 1627 | assume ds:nothing | ||
| 1628 | mov ax,es_des - start_gdt | ||
| 1629 | mov es,ax | ||
| 1630 | assume es:nothing | ||
| 1631 | shr cx,1 ; convert word count into dword count | ||
| 1632 | db 0f3h,066h,0a5h ; rep movsd | ||
| 1633 | ; rep movsw ; Move data | ||
| 1634 | ; | ||
| 1635 | ; | ||
| 1636 | ; Return to Real Mode | ||
| 1637 | ; | ||
| 1638 | ; | ||
| 1639 | db 66h,0Fh, 20h, 0 ; mov eax,cr0 | ||
| 1640 | and ax,0FFFEh | ||
| 1641 | db 66h,0Fh, 22h, 0 ; mov cr0,eax | ||
| 1642 | ; | ||
| 1643 | ; Flush Prefetch Queue | ||
| 1644 | ; | ||
| 1645 | db 0EAh ; Far jump | ||
| 1646 | dw offset flushcs | ||
| 1647 | cod_seg dw ? ; Fixed up at initialization time | ||
| 1648 | assume cs:ramcode | ||
| 1649 | flushcs: | ||
| 1650 | ; | ||
| 1651 | sti | ||
| 1652 | ; see if transfer done else go to do next block | ||
| 1653 | ; | ||
| 1654 | or bx,bx | ||
| 1655 | jne pr_io_agn_1 | ||
| 1656 | ; | ||
| 1657 | db 66h | ||
| 1658 | pop ax | ||
| 1659 | mov ax,cs | ||
| 1660 | mov es,ax | ||
| 1661 | assume es:nothing | ||
| 1662 | mov ds,ax | ||
| 1663 | assume ds:ramcode | ||
| 1664 | |||
| 1665 | mov cx,800h ; Retry this many times | ||
| 1666 | offlp_1: | ||
| 1667 | mov ax,cs:[A20Off] | ||
| 1668 | call A20 ; Disable address line 20 | ||
| 1669 | jnc offlp1_out | ||
| 1670 | loop offlp_1 | ||
| 1671 | offlp1_out: | ||
| 1672 | clc | ||
| 1673 | ret | ||
| 1674 | |||
| 1675 | nr_err_1: | ||
| 1676 | |||
| 1677 | mov al,02 ; Drive not ready error | ||
| 1678 | stc | ||
| 1679 | ret | ||
| 1680 | ; | ||
| 1681 | int_15_tran: | ||
| 1682 | assume ds:ramcode,es:nothing,ss:nothing | ||
| 1683 | or bh,bh | ||
| 1684 | jz read_it_2 | ||
| 1685 | ; | ||
| 1686 | ; Write | ||
| 1687 | ; | ||
| 1688 | ; Update tgt descriptor with address of track in cache | ||
| 1689 | ; | ||
| 1690 | mov si,offset tgt | ||
| 1691 | mov [si].bas_0_15,ax | ||
| 1692 | mov [si].bas_16_23,dl | ||
| 1693 | mov [si].bas_24_31,dh | ||
| 1694 | ; | ||
| 1695 | ; Update src descriptor with transfer address | ||
| 1696 | ; | ||
| 1697 | mov ax,es | ||
| 1698 | mov cx,16 | ||
| 1699 | mul cx | ||
| 1700 | add ax,di | ||
| 1701 | adc dx,0 | ||
| 1702 | mov si,offset src | ||
| 1703 | mov [si].bas_0_15,ax | ||
| 1704 | mov [si].bas_16_23,dl | ||
| 1705 | mov [si].bas_24_31,dh | ||
| 1706 | ; | ||
| 1707 | jmp short set_trans_2 | ||
| 1708 | |||
| 1709 | read_it_2: | ||
| 1710 | ; | ||
| 1711 | ; Update src descriptor with address of track in cache | ||
| 1712 | ; | ||
| 1713 | mov si,offset src | ||
| 1714 | mov [si].bas_0_15,ax | ||
| 1715 | mov [si].bas_16_23,dl | ||
| 1716 | mov [si].bas_24_31,dh | ||
| 1717 | ; | ||
| 1718 | ; Update tgt descriptor with transfer address | ||
| 1719 | ; | ||
| 1720 | mov ax,es | ||
| 1721 | mov cx,16 | ||
| 1722 | mul cx | ||
| 1723 | add ax,di | ||
| 1724 | adc dx,0 | ||
| 1725 | mov si,offset tgt | ||
| 1726 | mov [si].bas_0_15,ax | ||
| 1727 | mov [si].bas_16_23,dl | ||
| 1728 | mov [si].bas_24_31,dh | ||
| 1729 | ; | ||
| 1730 | set_trans_2: | ||
| 1731 | ; | ||
| 1732 | ; Restore Transfer Count | ||
| 1733 | ; | ||
| 1734 | pop bx | ||
| 1735 | |||
| 1736 | ; | ||
| 1737 | ; we shall do the transfer 1024 words at a time | ||
| 1738 | ; | ||
| 1739 | pr_io_agn_2: | ||
| 1740 | mov cx,1024 | ||
| 1741 | cmp bx,cx | ||
| 1742 | ja pr_strt_2 | ||
| 1743 | mov cx,bx | ||
| 1744 | pr_strt_2: | ||
| 1745 | sub bx,cx | ||
| 1746 | push cs | ||
| 1747 | pop es | ||
| 1748 | mov si,offset int15_gdt | ||
| 1749 | mov ax,emm_blkm shl 8 | ||
| 1750 | int emm_int | ||
| 1751 | jc nr_err_1 | ||
| 1752 | ; | ||
| 1753 | ; | ||
| 1754 | ; see if transfer done else fo to do next block | ||
| 1755 | ; | ||
| 1756 | or bx,bx | ||
| 1757 | je io_exit | ||
| 1758 | ; | ||
| 1759 | add [src.bas_0_15],2048 | ||
| 1760 | adc [src.bas_16_23],0 | ||
| 1761 | adc [src.bas_24_31],0 | ||
| 1762 | ; | ||
| 1763 | add [tgt.bas_0_15],2048 | ||
| 1764 | adc [tgt.bas_16_23],0 | ||
| 1765 | adc [tgt.bas_24_31],0 | ||
| 1766 | ; | ||
| 1767 | jmp pr_io_agn_2 | ||
| 1768 | io_exit: | ||
| 1769 | clc | ||
| 1770 | ret | ||
| 1771 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 1772 | ;** SEG_SET - Set up a LOADALL segment descriptor as in REAL mode | ||
| 1773 | ; | ||
| 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. | ||
| 1778 | ; | ||
| 1779 | ; SEE ALSO | ||
| 1780 | ; INTEL special documentation of LOADALL instruction | ||
| 1781 | ; | ||
| 1782 | ; ENTRY: | ||
| 1783 | ; DS:SI -> Seg register descriptor | ||
| 1784 | ; AX is seg register value | ||
| 1785 | ; EXIT: | ||
| 1786 | ; NONE | ||
| 1787 | ; USES: | ||
| 1788 | ; AX | ||
| 1789 | ; | ||
| 1790 | ; This routine is specific to TYPE 1 driver | ||
| 1791 | ; | ||
| 1792 | |||
| 1793 | SEG_SET: | ||
| 1794 | ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 1795 | PUSH DX | ||
| 1796 | PUSH CX | ||
| 1797 | MOV CX,16 | ||
| 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 | ||
| 1801 | POP CX | ||
| 1802 | POP DX | ||
| 1803 | RET | ||
| 1804 | |||
| 1805 | ;** FIX_DESCRIPTOR - Shuffle GTD IDT descriptors | ||
| 1806 | ; | ||
| 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 | ||
| 1812 | ; order. | ||
| 1813 | ; | ||
| 1814 | ; SEE ALSO | ||
| 1815 | ; INTEL special documentation of LOADALL instruction | ||
| 1816 | ; INTEL 80286 processor handbook description of SIDT instruction | ||
| 1817 | ; | ||
| 1818 | ; ENTRY: | ||
| 1819 | ; DS:SI points to IDT or GDT descriptor in SIDT form | ||
| 1820 | ; EXIT: | ||
| 1821 | ; DS:SI points to IDT or GDT descriptor in LOADALL form | ||
| 1822 | ; USES: | ||
| 1823 | ; 6 words of stack | ||
| 1824 | ; | ||
| 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. | ||
| 1828 | ; | ||
| 1829 | ; Specific to TYPE 1 driver | ||
| 1830 | ; | ||
| 1831 | |||
| 1832 | FIX_DESCRIPTOR: | ||
| 1833 | ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 1834 | PUSH WORD PTR [SI + 4] | ||
| 1835 | PUSH WORD PTR [SI + 2] | ||
| 1836 | PUSH WORD PTR [SI] | ||
| 1837 | POP WORD PTR [SI + 4] | ||
| 1838 | POP WORD PTR [SI] | ||
| 1839 | POP WORD PTR [SI + 2] | ||
| 1840 | RET | ||
| 1841 | |||
| 1842 | ;** DATA SPECIFIC TO THE LOADALL INSTRUCTION USAGE | ||
| 1843 | ; | ||
| 1844 | ; SWAP_80 and LOADALL_TBL are data elements specific to the use | ||
| 1845 | ; of the LOADALL instruction by TYPE 1 drivers. | ||
| 1846 | ; | ||
| 1847 | |||
| 1848 | ; | ||
| 1849 | ; Swap buffer for contents of 80:0 | ||
| 1850 | ; | ||
| 1851 | EVEN ; Force word alignment of SWAP_80 and LOADALL_TBL | ||
| 1852 | |||
| 1853 | SWAP_80 DB 102 DUP(?) | ||
| 1854 | ssSave dw ? | ||
| 1855 | |||
| 1856 | ; | ||
| 1857 | ; LOADALL data buffer placed at 80:0 | ||
| 1858 | ; | ||
| 1859 | LOADALL_TBL LABEL BYTE | ||
| 1860 | DB 6 DUP(0) | ||
| 1861 | LDSW DW ? | ||
| 1862 | DB 14 DUP (0) | ||
| 1863 | TR DW 0 | ||
| 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 | ||
| 1867 | LDT DW 0 | ||
| 1868 | LDSS DW 8000h | ||
| 1869 | LSSS DW ? | ||
| 1870 | LCSS DW ? | ||
| 1871 | LESS DW ? | ||
| 1872 | LDI DW ? | ||
| 1873 | LSI DW ? | ||
| 1874 | LBP DW ? | ||
| 1875 | LSP DW ? | ||
| 1876 | LBX DW ? | ||
| 1877 | LDX DW ? | ||
| 1878 | LCX DW ? | ||
| 1879 | LAX DW 80H | ||
| 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> | ||
| 1888 | |||
| 1889 | ;** TRUE LOCATION OF ABOVE_PID | ||
| 1890 | ; | ||
| 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: | ||
| 1897 | ; | ||
| 1898 | ; MOV DX,[ABOVE_PID] | ||
| 1899 | ; | ||
| 1900 | ; Would have to be "fixed up" when we moved the ABOVE_BLKMOV | ||
| 1901 | ; code into its final location. | ||
| 1902 | ; | ||
| 1903 | |||
| 1904 | ABOVE_PID EQU WORD PTR $ - 2 ; TRUE location of ABOVE_PID | ||
| 1905 | |||
| 1906 | ; | ||
| 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 | ||
| 1910 | ; | ||
| 1911 | DRIVE_END LABEL WORD | ||
| 1912 | |||
| 1913 | |||
| 1914 | BREAK <BPB POINTER ARRAY> | ||
| 1915 | |||
| 1916 | ;** BPB pointer array data | ||
| 1917 | ; | ||
| 1918 | ; BPB pointer array returned by INIT call. Must be part of resident image. | ||
| 1919 | ; | ||
| 1920 | ; SEE ALSO | ||
| 1921 | ; MS-DOS Technical Reference manual section on | ||
| 1922 | ; Installable Device Drivers | ||
| 1923 | ; | ||
| 1924 | |||
| 1925 | INITAB DW RDRIVEBPB | ||
| 1926 | |||
| 1927 | ; | ||
| 1928 | ; The following label defines the end of the RAMDrive resident code | ||
| 1929 | ; for cases where no INT 9/19 code is included. | ||
| 1930 | ; | ||
| 1931 | DEVICE_END LABEL BYTE | ||
| 1932 | |||
| 1933 | BREAK <INT 19/9/15 Handlers. Incl if FIRST driver in system or /A or new alloc> | ||
| 1934 | |||
| 1935 | ; | ||
| 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. | ||
| 1939 | ; | ||
| 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. | ||
| 1946 | ; | ||
| 1947 | ; The drive TYPE dependant piece of code works as follows: | ||
| 1948 | ; | ||
| 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 | ||
| 1957 | ; time. | ||
| 1958 | ; | ||
| 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 | ||
| 1973 | ; code. | ||
| 1974 | ; | ||
| 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 | ||
| 1983 | ; time. | ||
| 1984 | ; | ||
| 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. | ||
| 1989 | ; | ||
| 1990 | |||
| 1991 | ; | ||
| 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. | ||
| 1995 | ; | ||
| 1996 | OLD_19 LABEL DWORD | ||
| 1997 | DW -1 | ||
| 1998 | DW -1 | ||
| 1999 | |||
| 2000 | ;OLD_9 LABEL DWORD | ||
| 2001 | ; DW -1 | ||
| 2002 | ; DW -1 | ||
| 2003 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 2004 | ; modification to meet new memory allocation standard | ||
| 2005 | OLD_15 LABEL DWORD | ||
| 2006 | DW -1 | ||
| 2007 | DW -1 | ||
| 2008 | int15_size dw 0 | ||
| 2009 | ; | ||
| 2010 | ; | ||
| 2011 | INT_15: | ||
| 2012 | ASSUME DS:NOTHING,SS:NOTHING,ES:NOTHING | ||
| 2013 | ; | ||
| 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 | ||
| 2017 | ; | ||
| 2018 | ; inputs: ah = 88h is of interest | ||
| 2019 | ; outputs: ax = size of extended memory allocated by all before and | ||
| 2020 | ; including us | ||
| 2021 | ; regs used: flags | ||
| 2022 | ; | ||
| 2023 | pushf | ||
| 2024 | cmp ah,88h | ||
| 2025 | je mem_det | ||
| 2026 | popf | ||
| 2027 | jmp [old_15] | ||
| 2028 | mem_det: | ||
| 2029 | mov ax,[int15_size] | ||
| 2030 | popf | ||
| 2031 | clc | ||
| 2032 | sti | ||
| 2033 | iret | ||
| 2034 | |||
| 2035 | ;** INT 9 Keyboard handler | ||
| 2036 | ; | ||
| 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. | ||
| 2042 | ; | ||
| 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. | ||
| 2046 | ; | ||
| 2047 | ; SEE ALSO | ||
| 2048 | ; INT 9 IBM ROM code in ROM BIOS listing of | ||
| 2049 | ; IBM PC Technical Reference manual for any PC family member | ||
| 2050 | ; | ||
| 2051 | ; ENTRY | ||
| 2052 | ; NONE | ||
| 2053 | ; EXIT | ||
| 2054 | ; NONE, via OLD_9 | ||
| 2055 | ; USES | ||
| 2056 | ; FLAGS | ||
| 2057 | ; | ||
| 2058 | ; THIS CODE IS USED BY TYPE 1,2 and 3 drivers. | ||
| 2059 | ; | ||
| 2060 | |||
| 2061 | ;INT_9: | ||
| 2062 | ;ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 2063 | ; PUSH AX | ||
| 2064 | ; PUSH DS | ||
| 2065 | ; IN AL,60H | ||
| 2066 | ; CMP AL,83 ; DEL key? | ||
| 2067 | ; JNZ CHAIN ; No | ||
| 2068 | ; XOR AX,AX | ||
| 2069 | ; MOV DS,AX | ||
| 2070 | ; MOV AL,BYTE PTR DS:[417H] ; Get KB flag | ||
| 2071 | ; NOT AL | ||
| 2072 | ; TEST AL,0CH ; Ctrl Alt? | ||
| 2073 | ; JNZ CHAIN ; No | ||
| 2074 | ; CALL RESET_SYSTEM ; Ctrl Alt DEL | ||
| 2075 | ;CHAIN: | ||
| 2076 | ; POP DS | ||
| 2077 | ; POP AX | ||
| 2078 | ; JMP [OLD_9] | ||
| 2079 | |||
| 2080 | ;** INT 19 Software re-boot handler | ||
| 2081 | ; | ||
| 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. | ||
| 2087 | ; | ||
| 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. | ||
| 2093 | ; | ||
| 2094 | ; SEE ALSO | ||
| 2095 | ; INT 19 IBM ROM code in ROM BIOS listing of | ||
| 2096 | ; IBM PC Technical Reference manual for any PC family member | ||
| 2097 | ; | ||
| 2098 | ; ENTRY | ||
| 2099 | ; NONE | ||
| 2100 | ; EXIT | ||
| 2101 | ; NONE, via OLD_19 | ||
| 2102 | ; USES | ||
| 2103 | ; FLAGS | ||
| 2104 | ; | ||
| 2105 | ; THIS CODE IS USED BY TYPE 1,2 and 3 drivers. | ||
| 2106 | ; | ||
| 2107 | |||
| 2108 | INT_19: | ||
| 2109 | ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 2110 | CALL RESET_SYSTEM | ||
| 2111 | PUSH AX | ||
| 2112 | PUSH DS | ||
| 2113 | XOR AX,AX | ||
| 2114 | MOV DS,AX | ||
| 2115 | ; | ||
| 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. | ||
| 2118 | ; | ||
| 2119 | ; NOTE THAT WE RESET VECTORS DIRECTLY!!!!!!!!!!!!!!!!!! | ||
| 2120 | ; We are not sure that DOS is reliable enough to call. | ||
| 2121 | ; | ||
| 2122 | MOV AX,WORD PTR [OLD_19] | ||
| 2123 | CLI | ||
| 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 | ||
| 2131 | ; | ||
| 2132 | mov ax,word ptr [old_15] | ||
| 2133 | cmp ax,word ptr [old_15+2] | ||
| 2134 | jne res_15 | ||
| 2135 | cmp ax,-1 | ||
| 2136 | je skip_res | ||
| 2137 | res_15: | ||
| 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 | ||
| 2141 | |||
| 2142 | skip_res: | ||
| 2143 | POP DS | ||
| 2144 | POP AX | ||
| 2145 | JMP [OLD_19] | ||
| 2146 | |||
| 2147 | ;** RESET_SYSTEM perform TYPE 1 (/E) driver specific reboot code | ||
| 2148 | ; | ||
| 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 | ||
| 2154 | ; place. | ||
| 2155 | ; | ||
| 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. | ||
| 2159 | ; | ||
| 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 | ||
| 2165 | ; | ||
| 2166 | ; ENTRY | ||
| 2167 | ; NONE | ||
| 2168 | ; EXIT | ||
| 2169 | ; NONE | ||
| 2170 | ; USES | ||
| 2171 | ; NONE | ||
| 2172 | ; | ||
| 2173 | ; This code is specific to TYPE 1 drivers | ||
| 2174 | ; | ||
| 2175 | |||
| 2176 | RESET_SYSTEM: | ||
| 2177 | ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 2178 | ; | ||
| 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 | ||
| 2182 | ; | ||
| 2183 | ; this piece of code cannot be removed because other guys relocate | ||
| 2184 | ; on top of this | ||
| 2185 | ; | ||
| 2186 | jmp reset_ret | ||
| 2187 | ; | ||
| 2188 | PUSHA | ||
| 2189 | PUSH DS | ||
| 2190 | PUSH ES | ||
| 2191 | PUSH CS | ||
| 2192 | POP DS | ||
| 2193 | ASSUME DS:RAMCODE | ||
| 2194 | ; | ||
| 2195 | ; Set up to address EMM_CTRL sector | ||
| 2196 | ; | ||
| 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 | ||
| 2200 | MOV [LSI],0 | ||
| 2201 | MOV [LDI],EMM_RECORD | ||
| 2202 | MOV [LCX],EMM_NUMREC | ||
| 2203 | MOV SI,OFFSET ESDES | ||
| 2204 | MOV AX,ES | ||
| 2205 | CALL SEG_SET ; Set ES segreg | ||
| 2206 | MOV AX,SS | ||
| 2207 | MOV [LSSS],AX | ||
| 2208 | MOV SI,OFFSET SSDES | ||
| 2209 | CALL SEG_SET ; Set SS segreg | ||
| 2210 | MOV [LSP],SP | ||
| 2211 | ON20: | ||
| 2212 | MOV AH,0DFH | ||
| 2213 | CALL A20 ; Enable adress 20 | ||
| 2214 | CLI ; A20 STIs | ||
| 2215 | JNZ ON20 | ||
| 2216 | |||
| 2217 | MOV AX,80H | ||
| 2218 | MOV DS,AX | ||
| 2219 | ASSUME DS:NOTHING | ||
| 2220 | PUSH CS | ||
| 2221 | POP ES | ||
| 2222 | XOR SI,SI | ||
| 2223 | MOV DI,OFFSET SWAP_80 | ||
| 2224 | MOV CX,102/2 | ||
| 2225 | CLD | ||
| 2226 | CLI | ||
| 2227 | REP MOVSW ; Transfer out 80:0 | ||
| 2228 | PUSH DS | ||
| 2229 | PUSH ES | ||
| 2230 | POP DS | ||
| 2231 | POP ES | ||
| 2232 | XOR DI,DI | ||
| 2233 | MOV SI,OFFSET LOADALL_TBL | ||
| 2234 | MOV CX,102/2 | ||
| 2235 | REP MOVSW ; Transfer in LOADALL info | ||
| 2236 | DW 050FH ; LOADALL INSTRUCTION | ||
| 2237 | AFTER_LDA: | ||
| 2238 | ; | ||
| 2239 | ; Scan EMM_CTRL for MS-DOS ISDRIVER regions and turn off ISDRIVER | ||
| 2240 | ; | ||
| 2241 | |||
| 2242 | LOOK_RECY: | ||
| 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 | ||
| 2250 | NEXTRECY: | ||
| 2251 | ADD DI,SIZE EMM_REC | ||
| 2252 | LOOP LOOK_RECY | ||
| 2253 | DONEY: | ||
| 2254 | MOV ES,AX ; LOADALL puts 80H in AX | ||
| 2255 | XOR DI,DI | ||
| 2256 | PUSH CS | ||
| 2257 | POP DS | ||
| 2258 | ASSUME DS:RAMCODE | ||
| 2259 | MOV SI,OFFSET SWAP_80 | ||
| 2260 | MOV CX,102/2 | ||
| 2261 | REP MOVSW ; Restore 80:0 | ||
| 2262 | |||
| 2263 | OFF20: | ||
| 2264 | MOV AH,0DDH ; Disable adress line 20 | ||
| 2265 | CALL A20 | ||
| 2266 | CLI ; A20 STIs | ||
| 2267 | JNZ OFF20 | ||
| 2268 | POP ES | ||
| 2269 | POP DS | ||
| 2270 | ASSUME DS:NOTHING | ||
| 2271 | POPA | ||
| 2272 | reset_ret: | ||
| 2273 | RET | ||
| 2274 | |||
| 2275 | ; | ||
| 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. | ||
| 2282 | ; | ||
| 2283 | RESET_INCLUDE LABEL BYTE | ||
| 2284 | |||
| 2285 | BREAK <COMMON INIT CODE> | ||
| 2286 | |||
| 2287 | ;** DISPOSABLE INIT DATA | ||
| 2288 | ; | ||
| 2289 | ; INIT data which need not be part of resident image | ||
| 2290 | ; | ||
| 2291 | |||
| 2292 | DRIVER_SEL DB 2 ; 0 if /E (TYPE 1), 1 if /A (TYPE 2), | ||
| 2293 | ; 2 if resmem (TYPE 3 or 4) | ||
| 2294 | |||
| 2295 | DEV_SIZE DW 64 ; Size in K of this device | ||
| 2296 | |||
| 2297 | U_SWITCH db 0 ;; for the oliv's special config | ||
| 2298 | |||
| 2299 | special_mem dw 0 ;; at&t special memory | ||
| 2300 | |||
| 2301 | new_all db 0 ; to indicate new allocation scheme | ||
| 2302 | |||
| 2303 | EXT_K DW ? ; Size in K of Exteneded memory. | ||
| 2304 | |||
| 2305 | NUM_ARG DB 1 ; Counter for order dependent numeric | ||
| 2306 | ; arguments bbbb ssss dddd. | ||
| 2307 | |||
| 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. | ||
| 2314 | |||
| 2315 | GOTSWITCH DB 0 ; 0 if no switch, NZ if switch seen | ||
| 2316 | |||
| 2317 | DIRSEC DW ? ; Number of directory SECTORS | ||
| 2318 | |||
| 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 | ||
| 2322 | |||
| 2323 | TRUE_CS DW ? ; Used to store the "true" location of | ||
| 2324 | ; the driver when the relocation at | ||
| 2325 | ; RAMDrive_RELOC is performed. | ||
| 2326 | |||
| 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 | ||
| 2330 | |||
| 2331 | VALID_EMM db 0 ; | ||
| 2332 | ; | ||
| 2333 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 2334 | sys_det proc near | ||
| 2335 | ; | ||
| 2336 | ; author: sunilp, august 1, 1987. thanks to rickha for most of this | ||
| 2337 | ; routine. | ||
| 2338 | ; | ||
| 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. | ||
| 2342 | ; | ||
| 2343 | ; inputs: none | ||
| 2344 | ; | ||
| 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. | ||
| 2348 | ; | ||
| 2349 | ; registers used: ax,es,flags | ||
| 2350 | ;---------------------------------- | ||
| 2351 | ; Clear the state of the system flag | ||
| 2352 | ; | ||
| 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. | ||
| 2358 | ; | ||
| 2359 | push ax ; ax has 0 | ||
| 2360 | popf ; try to put that in the flags | ||
| 2361 | pushf | ||
| 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. | ||
| 2368 | ; | ||
| 2369 | mov ax,0F000h ; N: try to set the high bits | ||
| 2370 | push ax | ||
| 2371 | popf ; ... in the flags | ||
| 2372 | pushf | ||
| 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. | ||
| 2379 | ; | ||
| 2380 | cpu_386: | ||
| 2381 | pushf ; clear | ||
| 2382 | pop ax ; NT | ||
| 2383 | and ax,not 0F000h ; and | ||
| 2384 | push ax ; IOPL | ||
| 2385 | popf ; bits | ||
| 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. | ||
| 2389 | ; | ||
| 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. | ||
| 2399 | ; | ||
| 2400 | or [sys_flg],M_386 ; set 386 bit | ||
| 2401 | jmp short PS2Test | ||
| 2402 | |||
| 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 | ||
| 2406 | ; | ||
| 2407 | cpu_286: | ||
| 2408 | mov ax,0ffffh | ||
| 2409 | mov es,ax | ||
| 2410 | cmp byte ptr es:[0eh],0fch ; AT model byte | ||
| 2411 | jne cpu_err ; if not abort | ||
| 2412 | ; | ||
| 2413 | or [sys_flg],M_286 ; set 286 flag bit | ||
| 2414 | ; | ||
| 2415 | ; | ||
| 2416 | ; Determine if this is a PS/2 system | ||
| 2417 | ; | ||
| 2418 | PS2Test: | ||
| 2419 | call IsPS2Machine | ||
| 2420 | or ax,ax | ||
| 2421 | jz NCRTest | ||
| 2422 | or [sys_flg],M_PS2 | ||
| 2423 | |||
| 2424 | NCRTest: | ||
| 2425 | call IsNCRMachine | ||
| 2426 | or ax,ax | ||
| 2427 | jz cpu_suc | ||
| 2428 | |||
| 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. | ||
| 2431 | ; ChipA 06-16-88 | ||
| 2432 | mov cs:[A20On],0D790h | ||
| 2433 | mov cs:[A20Off],0D500h | ||
| 2434 | |||
| 2435 | |||
| 2436 | ;---------------------------------- | ||
| 2437 | ; success exit:-- | ||
| 2438 | cpu_suc: | ||
| 2439 | clc | ||
| 2440 | ret | ||
| 2441 | |||
| 2442 | ;---------------------------------- | ||
| 2443 | ; error exit:-- | ||
| 2444 | cpu_err: | ||
| 2445 | stc | ||
| 2446 | ret | ||
| 2447 | ; | ||
| 2448 | sys_det endp | ||
| 2449 | |||
| 2450 | |||
| 2451 | ;*--------------------------------------------------------------------------* | ||
| 2452 | ;* * | ||
| 2453 | ;* IsPS2Machine HARDWARE DEP. * | ||
| 2454 | ;* * | ||
| 2455 | ;* Check for PS/2 machine * | ||
| 2456 | ;* * | ||
| 2457 | ;* ARGS: None * | ||
| 2458 | ;* RETS: AX = 1 if we're on a valid PS/2 machine, 0 otherwise * | ||
| 2459 | ;* REGS: AX and Flags clobbered * | ||
| 2460 | ;* * | ||
| 2461 | ;*--------------------------------------------------------------------------* | ||
| 2462 | |||
| 2463 | IsPS2Machine proc near | ||
| 2464 | |||
| 2465 | mov ax,0C300h ; Try to disable the Watchdog timer | ||
| 2466 | stc | ||
| 2467 | int 15h | ||
| 2468 | jc IPMNoPS2 ; Error? Not a PS/2. | ||
| 2469 | |||
| 2470 | IPMFoundIt: mov ax,1 ; Return 1 | ||
| 2471 | ret | ||
| 2472 | |||
| 2473 | IPMNoPS2: xor ax,ax | ||
| 2474 | ret | ||
| 2475 | |||
| 2476 | IsPS2Machine endp | ||
| 2477 | |||
| 2478 | |||
| 2479 | ;*--------------------------------------------------------------------------* | ||
| 2480 | ;* * | ||
| 2481 | ;* IsNCRMachine HARDWARE DEP. * | ||
| 2482 | ;* * | ||
| 2483 | ;* Check for NCR machine * | ||
| 2484 | ;* * | ||
| 2485 | ;* ARGS: None * | ||
| 2486 | ;* RETS: AX = 1 if we're on a valid NCR machine, 0 otherwise * | ||
| 2487 | ;* REGS: AX and Flags clobbered * | ||
| 2488 | ;* * | ||
| 2489 | ;*--------------------------------------------------------------------------* | ||
| 2490 | |||
| 2491 | ; Look for 'NC' at F000:FFEA | ||
| 2492 | |||
| 2493 | IsNCRMachine proc near | ||
| 2494 | |||
| 2495 | mov ax,0F000h | ||
| 2496 | mov es,ax | ||
| 2497 | mov ax,word ptr es:[0FFEAh] | ||
| 2498 | cmp ax,'CN' | ||
| 2499 | je INMFoundIt | ||
| 2500 | xor ax,ax | ||
| 2501 | ret | ||
| 2502 | |||
| 2503 | INMFoundIt: mov ax,1 | ||
| 2504 | ret | ||
| 2505 | |||
| 2506 | IsNCRMachine endp | ||
| 2507 | |||
| 2508 | |||
| 2509 | ;****************************************************************************** | ||
| 2510 | ; IS_B0 - check for 386-B0 | ||
| 2511 | ; | ||
| 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. | ||
| 2520 | ; | ||
| 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 | ||
| 2524 | ; | ||
| 2525 | ; ENTRY: | ||
| 2526 | ; EXIT: | ||
| 2527 | ; USED: AX, flags | ||
| 2528 | ; STACK: | ||
| 2529 | ;------------------------------------------------------------------------------ | ||
| 2530 | is_b0 proc near | ||
| 2531 | push bx | ||
| 2532 | push cx | ||
| 2533 | push dx | ||
| 2534 | push ds | ||
| 2535 | |||
| 2536 | xor bx,bx | ||
| 2537 | mov ds,bx ; DS = 0000 (real mode IDT) | ||
| 2538 | assume ds:R_Mode_IDT | ||
| 2539 | push [bx+(6*4)] | ||
| 2540 | pop cs:[int6_save] ; save old INT 6 offset | ||
| 2541 | push [bx+(6*4)+2] | ||
| 2542 | pop cs:[int6_save+2] ; save old INT 6 segment | ||
| 2543 | |||
| 2544 | mov word ptr [bx+(6*4)],offset int6 | ||
| 2545 | mov [bx+(6*4)+2],cs ; set vector to new INT 6 handler | ||
| 2546 | ; | ||
| 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. | ||
| 2552 | ; | ||
| 2553 | xor ax,ax | ||
| 2554 | mov dx,ax | ||
| 2555 | mov cx,0FF00h ; Extract length (CL)=0, CX=non-zero | ||
| 2556 | db 0Fh,0A6h,0CAh ; XBTS CX,DX,AX,CL | ||
| 2557 | |||
| 2558 | xor bx,bx | ||
| 2559 | mov ds,bx ; DS = 0000 (real mode IDT) | ||
| 2560 | push cs:[int6_save] ; restore original INT 6 offset | ||
| 2561 | pop [bx+(6*4)] ; | ||
| 2562 | push cs:[int6_save+2] ; restore original INT 6 segment | ||
| 2563 | pop [bx+(6*4)+2] | ||
| 2564 | |||
| 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 | ||
| 2568 | ib_exit: | ||
| 2569 | cmc ; flip carry tense | ||
| 2570 | pop ds | ||
| 2571 | pop dx | ||
| 2572 | pop cx | ||
| 2573 | pop bx | ||
| 2574 | ret ; *** RETURN *** | ||
| 2575 | is_b0 endp | ||
| 2576 | ; | ||
| 2577 | ; Temporary INT 6 handler - assumes the cause of the exception was the | ||
| 2578 | ; attempted execution of an XTBS instruction. | ||
| 2579 | ; | ||
| 2580 | int6 proc near | ||
| 2581 | push bp | ||
| 2582 | mov bp,sp | ||
| 2583 | add word ptr [bp+2],3 ; bump IP past faulting instruction | ||
| 2584 | pop bp | ||
| 2585 | iret ; *** RETURN *** | ||
| 2586 | int6_save dw 0000,0000 | ||
| 2587 | int6 endp | ||
| 2588 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 2589 | |||
| 2590 | ;** PRINT - Print a "$" terminated message on stdout | ||
| 2591 | ; | ||
| 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. | ||
| 2596 | ; | ||
| 2597 | ; ENTRY: | ||
| 2598 | ; DX pointer to "$" terminated message (RAMCODE relative) | ||
| 2599 | ; EXIT: | ||
| 2600 | ; NONE | ||
| 2601 | ; USES: | ||
| 2602 | ; AX | ||
| 2603 | ; | ||
| 2604 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 2605 | ; | ||
| 2606 | |||
| 2607 | PRINT: | ||
| 2608 | ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 2609 | PUSH DS | ||
| 2610 | PUSH CS | ||
| 2611 | POP DS | ||
| 2612 | MOV AH,Std_Con_String_Output | ||
| 2613 | INT 21H | ||
| 2614 | POP DS | ||
| 2615 | RET | ||
| 2616 | |||
| 2617 | ;** ITOA - Print Decimal Integer on stdout | ||
| 2618 | ; | ||
| 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 | ||
| 2621 | ; 0 prints as "0". | ||
| 2622 | ; | ||
| 2623 | ; Routine uses divide instruction and a recursive call. Maximum | ||
| 2624 | ; recursion is four (five digit number) plus one word on stack | ||
| 2625 | ; for each level. | ||
| 2626 | ; | ||
| 2627 | ; ENTRY AX has binary value to be printed | ||
| 2628 | ; EXIT NONE | ||
| 2629 | ; USES AX,CX,DX,FLAGS | ||
| 2630 | ; | ||
| 2631 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 2632 | ; | ||
| 2633 | |||
| 2634 | ITOA: | ||
| 2635 | ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 2636 | |||
| 2637 | MOV CX,10 | ||
| 2638 | XOR DX,DX | ||
| 2639 | DIV CX ; DX is low digit, AX is higher digits | ||
| 2640 | OR AX,AX | ||
| 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 | ||
| 2645 | PRINT_THIS_DIGIT: | ||
| 2646 | ADD DL,"0" ; Convert to ASCII | ||
| 2647 | MOV AH,Std_CON_Output | ||
| 2648 | INT 21H | ||
| 2649 | RET | ||
| 2650 | |||
| 2651 | |||
| 2652 | ;** RAM$INIT - Device Driver Initialization routine | ||
| 2653 | ; | ||
| 2654 | ; RAMDRIVE Initialization routine. This is the COMMON initialization | ||
| 2655 | ; code used by ALL driver TYPEs. Its jobs are to: | ||
| 2656 | ; | ||
| 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 | ||
| 2666 | ; | ||
| 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. | ||
| 2673 | ; | ||
| 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. | ||
| 2689 | ; | ||
| 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). | ||
| 2698 | ; | ||
| 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. | ||
| 2706 | ; | ||
| 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. | ||
| 2717 | ; | ||
| 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: | ||
| 2725 | ; | ||
| 2726 | ; DEV_SIZE set to TRUE size of device | ||
| 2727 | ; BASE_ADDR set to TRUE start of device so MEMIO | ||
| 2728 | ; can be called | ||
| 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 | ||
| 2732 | ; be set up | ||
| 2733 | ; RESMEM_SPECIAL set if TYPE 4 driver | ||
| 2734 | ; | ||
| 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. | ||
| 2753 | ; | ||
| 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 | ||
| 2756 | ; from the BPB. | ||
| 2757 | ; | ||
| 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. | ||
| 2760 | ; | ||
| 2761 | ; SEE ALSO | ||
| 2762 | ; MS-DOS Technical Reference manual section on | ||
| 2763 | ; Installable Device Drivers | ||
| 2764 | ; | ||
| 2765 | ; ENTRY from RAM$IN | ||
| 2766 | ; EXIT Through DEVEXIT | ||
| 2767 | ; USES ALL | ||
| 2768 | ; | ||
| 2769 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 2770 | ; | ||
| 2771 | |||
| 2772 | RAM$INIT: | ||
| 2773 | ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 2774 | ; | ||
| 2775 | ; 1. Initialize various global values | ||
| 2776 | ; | ||
| 2777 | MOV WORD PTR [TERM_ADDR + 2],CS | ||
| 2778 | MOV [TRUE_CS],CS | ||
| 2779 | mov [sys_flg],0 | ||
| 2780 | ; | ||
| 2781 | ; 2. Check for correct DOS version and do changes to the device | ||
| 2782 | ; based on the DOS version if needed. | ||
| 2783 | ; | ||
| 2784 | CLD | ||
| 2785 | MOV AH,GET_VERSION | ||
| 2786 | INT 21H | ||
| 2787 | XCHG AH,AL | ||
| 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 | ||
| 2795 | cmp al,30 ; 3.30 | ||
| 2796 | jb ver_ok ; if below we cannot take advantage of 80:0 | ||
| 2797 | ldl_buf_present: | ||
| 2798 | or [sys_flg],DOS_33 ; indicate we have dos 3.3 or above | ||
| 2799 | jmp ver_ok | ||
| 2800 | |||
| 2801 | BADVER: | ||
| 2802 | MOV DX,OFFSET BADVERMES | ||
| 2803 | JMP DEVABORT | ||
| 2804 | |||
| 2805 | VER2X: | ||
| 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],"$" | ||
| 2810 | VER_OK: | ||
| 2811 | ;; | ||
| 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. | ||
| 2814 | ;; | ||
| 2815 | |||
| 2816 | push es ;; Olivetti Machine? | ||
| 2817 | mov ax,0fc00h ;; Look for 'OL' at fc00:50 | ||
| 2818 | mov es,ax | ||
| 2819 | cmp es:[0050h],'LO' | ||
| 2820 | jnz notS5 ;; not found | ||
| 2821 | mov ax,0f000h | ||
| 2822 | mov es,ax | ||
| 2823 | cmp word ptr es:[0fffdh],0fc00h ;; look for 6300 plus | ||
| 2824 | jnz notS5 | ||
| 2825 | mov [S5_FLAG],S_OLIVETTI ;; yep, set flag | ||
| 2826 | jmp notHP | ||
| 2827 | notS5: | ||
| 2828 | ;; Check here for an HP Vectra machine. Look for HP id byte. | ||
| 2829 | ;; | ||
| 2830 | mov ax,0f000H | ||
| 2831 | mov es,ax | ||
| 2832 | cmp es:[0f8H],'PH' | ||
| 2833 | jnz notHP | ||
| 2834 | mov [S5_FLAG],S_VECTRA | ||
| 2835 | notHP: | ||
| 2836 | pop es | ||
| 2837 | ; | ||
| 2838 | ; 3. Parse the command line and set values accordingly | ||
| 2839 | ; | ||
| 2840 | LDS SI,[PTRSAV] | ||
| 2841 | ASSUME DS:NOTHING | ||
| 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 | ||
| 2845 | CALL PRINT | ||
| 2846 | LDS SI,[SI.INIT_BPB] ; DS:SI points to config.sys | ||
| 2847 | SKIPLP1: ; Skip leading delims to start of name | ||
| 2848 | LODSB | ||
| 2849 | CMP AL," " | ||
| 2850 | JZ SKIPLP1 | ||
| 2851 | CMP AL,9 | ||
| 2852 | JZ SKIPLP1 | ||
| 2853 | CMP AL,"," | ||
| 2854 | JZ SKIPLP1 | ||
| 2855 | JMP SHORT SKIPNM | ||
| 2856 | |||
| 2857 | ARGS_DONEJ: | ||
| 2858 | JMP ARGS_DONE | ||
| 2859 | |||
| 2860 | SWITCHJ: | ||
| 2861 | JMP SWITCH | ||
| 2862 | |||
| 2863 | SKIPLP2: ; Skip over device name | ||
| 2864 | LODSB | ||
| 2865 | SKIPNM: | ||
| 2866 | CMP AL,13 | ||
| 2867 | JZ ARGS_DONEJ | ||
| 2868 | CMP AL,10 | ||
| 2869 | JZ ARGS_DONEJ | ||
| 2870 | CMP AL," " | ||
| 2871 | JZ FIRST_ARG | ||
| 2872 | CMP AL,9 | ||
| 2873 | JZ FIRST_ARG | ||
| 2874 | CMP AL,"," | ||
| 2875 | JZ FIRST_ARG | ||
| 2876 | CMP AL,0 ; Need this for 2.0 2.1 | ||
| 2877 | JNZ SKIPLP2 | ||
| 2878 | SCAN_LOOP: ; PROCESS arguments | ||
| 2879 | LODSB | ||
| 2880 | FIRST_ARG: | ||
| 2881 | OR AL,AL ; Need this for 2.0 2.1 | ||
| 2882 | JZ ARGS_DONEJ | ||
| 2883 | CMP AL,13 | ||
| 2884 | JZ ARGS_DONEJ | ||
| 2885 | CMP AL,10 | ||
| 2886 | JZ ARGS_DONEJ | ||
| 2887 | CMP AL," " | ||
| 2888 | JZ SCAN_LOOP | ||
| 2889 | CMP AL,9 | ||
| 2890 | JZ SCAN_LOOP | ||
| 2891 | CMP AL,"," | ||
| 2892 | JZ SCAN_LOOP | ||
| 2893 | CMP AL,"/" | ||
| 2894 | JZ SWITCHJ | ||
| 2895 | CMP AL,"0" | ||
| 2896 | JB BAD_PARMJ | ||
| 2897 | CMP AL,"9" | ||
| 2898 | JA BAD_PARMJ | ||
| 2899 | DEC SI | ||
| 2900 | CALL GETNUM | ||
| 2901 | CMP [NUM_ARG],3 | ||
| 2902 | JA BAD_PARMJ ; Only 3 numeric arguments | ||
| 2903 | JZ SET_DIR | ||
| 2904 | CMP [NUM_ARG],2 | ||
| 2905 | JZ SET_SECTOR | ||
| 2906 | SET_SIZE: | ||
| 2907 | CMP BX,16 | ||
| 2908 | JB BAD_PARMJ | ||
| 2909 | CMP BX,4096 | ||
| 2910 | JA BAD_PARMJ | ||
| 2911 | MOV [DEV_SIZE],BX | ||
| 2912 | JMP SHORT NUM_DONE | ||
| 2913 | |||
| 2914 | BAD_PARMJ: | ||
| 2915 | JMP BAD_PARM | ||
| 2916 | |||
| 2917 | SET_SECTOR: | ||
| 2918 | MOV AL,6 | ||
| 2919 | CMP BX,128 | ||
| 2920 | JZ SET_SEC | ||
| 2921 | INC AL | ||
| 2922 | CMP BX,256 | ||
| 2923 | JZ SET_SEC | ||
| 2924 | INC AL | ||
| 2925 | CMP BX,512 | ||
| 2926 | JZ SET_SEC | ||
| 2927 | INC AL | ||
| 2928 | CMP BX,1024 | ||
| 2929 | JNZ BAD_PARM | ||
| 2930 | SET_SEC: | ||
| 2931 | MOV [SSIZE],BX | ||
| 2932 | MOV [SEC_SHFT],AL | ||
| 2933 | JMP SHORT NUM_DONE | ||
| 2934 | |||
| 2935 | SET_DIR: | ||
| 2936 | CMP BX,2 | ||
| 2937 | JB BAD_PARM | ||
| 2938 | CMP BX,1024 | ||
| 2939 | JA BAD_PARM | ||
| 2940 | ; | ||
| 2941 | ; NOTE: Since DIRNUM is the 3rd numeric arg and SSIZE is the first, | ||
| 2942 | ; we know the desired sector size has been given. | ||
| 2943 | ; | ||
| 2944 | MOV DI,[SSIZE] | ||
| 2945 | MOV CL,5 ; 32 bytes per dir ent | ||
| 2946 | SHR DI,CL ; DI is number of dir ents in a sector | ||
| 2947 | MOV AX,BX | ||
| 2948 | XOR DX,DX | ||
| 2949 | DIV DI ; Rem in DX is partial dir sector | ||
| 2950 | OR DX,DX | ||
| 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 | ||
| 2954 | SET_DSZ: | ||
| 2955 | MOV [DIRNUM],BX | ||
| 2956 | NUM_DONE: | ||
| 2957 | INC [NUM_ARG] ; Next numeric argument | ||
| 2958 | SCAN_LOOPJ: | ||
| 2959 | JMP SCAN_LOOP | ||
| 2960 | |||
| 2961 | BAD_PARM: | ||
| 2962 | MOV DX,OFFSET ERRMSG1 | ||
| 2963 | DEVABORT: | ||
| 2964 | CALL PRINT | ||
| 2965 | DEVABORT_NOMES: | ||
| 2966 | XOR AX,AX ;Indicate no devices | ||
| 2967 | JMP SETBPB ;and return | ||
| 2968 | |||
| 2969 | SWITCH: | ||
| 2970 | MOV AL,0FFH | ||
| 2971 | XCHG AL,[GOTSWITCH] ; Switch already? | ||
| 2972 | OR AL,AL | ||
| 2973 | JNZ BAD_PARM ; Yes, only one allowed | ||
| 2974 | LODSB | ||
| 2975 | CMP AL,"E" | ||
| 2976 | JZ EXT_SET | ||
| 2977 | CMP AL,"e" | ||
| 2978 | JNZ ABOVE_TEST | ||
| 2979 | EXT_SET: | ||
| 2980 | MOV [DRIVER_SEL],0 | ||
| 2981 | JMP SCAN_LOOP | ||
| 2982 | |||
| 2983 | ABOVE_TEST: | ||
| 2984 | ;; Added for /u switch | ||
| 2985 | cmp al,'u' ;; Look for U switch for PLUS | ||
| 2986 | jz S5_TEST | ||
| 2987 | cmp al,'U' ;; | ||
| 2988 | jnz A_TEST | ||
| 2989 | S5_TEST: | ||
| 2990 | cmp [S5_FLAG],S_OLIVETTI ;; No good unless PLUS | ||
| 2991 | jne bad_parm | ||
| 2992 | ; xchg al,[gotswitch] ; switch already | ||
| 2993 | ; or al,al | ||
| 2994 | ; jnz bad_parm | ||
| 2995 | ; | ||
| 2996 | cmp [U_SWITCH],0 | ||
| 2997 | jne bad_parm | ||
| 2998 | dec [U_SWITCH] | ||
| 2999 | jmp ext_set | ||
| 3000 | A_TEST: | ||
| 3001 | |||
| 3002 | CMP AL,"A" | ||
| 3003 | JZ ABOVE_SET | ||
| 3004 | CMP AL,"a" | ||
| 3005 | JNZ BAD_PARM | ||
| 3006 | ABOVE_SET: | ||
| 3007 | MOV [DRIVER_SEL],1 | ||
| 3008 | JMP SCAN_LOOP | ||
| 3009 | |||
| 3010 | ARGS_DONE: | ||
| 3011 | ; | ||
| 3012 | ; 4. Call a TYPE specific INIT routine based on the Parse | ||
| 3013 | ; to set up a specific driver TYPE. | ||
| 3014 | ; | ||
| 3015 | PUSH CS | ||
| 3016 | POP DS | ||
| 3017 | ASSUME DS:RAMCODE | ||
| 3018 | MOV AL,[DRIVER_SEL] ; Find out which init to call | ||
| 3019 | OR AL,AL | ||
| 3020 | JNZ NEXTV | ||
| 3021 | CALL AT_EXT_INIT | ||
| 3022 | JMP SHORT INI_RET | ||
| 3023 | |||
| 3024 | NEXTV: | ||
| 3025 | DEC AL | ||
| 3026 | JNZ DORESM | ||
| 3027 | CALL ABOVE_INIT | ||
| 3028 | JMP SHORT INI_RET | ||
| 3029 | |||
| 3030 | DORESM: | ||
| 3031 | CALL RESMEM_INIT | ||
| 3032 | INI_RET: | ||
| 3033 | JNC I001 | ||
| 3034 | JMP DEVABORT_NOMES | ||
| 3035 | |||
| 3036 | I001: | ||
| 3037 | ; | ||
| 3038 | ; 5. Initialize the DOS volume in the RAMDrive memory if appropriate | ||
| 3039 | ; | ||
| 3040 | CMP [INIT_DRIVE],0 | ||
| 3041 | JNZ INIDRV ; Need to initialize drive | ||
| 3042 | JMP DRIVE_SET ; All set to go | ||
| 3043 | |||
| 3044 | INIDRV: | ||
| 3045 | ; | ||
| 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 | ||
| 3051 | ; | ||
| 3052 | ; Figure out total number of sectors in logical image | ||
| 3053 | MOV AX,[DEV_SIZE] | ||
| 3054 | MOV CX,1024 | ||
| 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 | ||
| 3058 | MOV [SECLIM],AX | ||
| 3059 | ; Compute # of directory sectors | ||
| 3060 | MOV AX,[DIRNUM] | ||
| 3061 | MOV CL,5 ; Mult by 32 bytes per entry | ||
| 3062 | SHL AX,CL ; Don't need to worry about overflow, # ents | ||
| 3063 | ; is at most 1024 | ||
| 3064 | XOR DX,DX | ||
| 3065 | DIV [SSIZE] | ||
| 3066 | OR DX,DX | ||
| 3067 | JZ NOINC | ||
| 3068 | INC AX | ||
| 3069 | NOINC: ; AX is # sectors for root dir | ||
| 3070 | MOV [DIRSEC],AX | ||
| 3071 | ADD AX,2 ; One reserved, At least one FAT sector | ||
| 3072 | CMP AX,[SECLIM] | ||
| 3073 | JB OK001 ; we're OK | ||
| 3074 | MOV [DIRNUM],16 ; Smallest reasonable number | ||
| 3075 | XOR DX,DX | ||
| 3076 | MOV AX,512 ; 16*32 = 512 bytes for dir | ||
| 3077 | DIV [SSIZE] | ||
| 3078 | OR DX,DX | ||
| 3079 | JZ NOINC2 | ||
| 3080 | INC AX | ||
| 3081 | NOINC2: ; AX is # sectors for root dir | ||
| 3082 | MOV [DIRSEC],AX | ||
| 3083 | ADD AX,2 ; One reserved, At least one FAT sector | ||
| 3084 | CMP AX,[SECLIM] | ||
| 3085 | JB OK001 ; 16 directory sectors got us to OK | ||
| 3086 | CALL DISK_ABORT ; Barf | ||
| 3087 | MOV DX,OFFSET ERRMSG2 | ||
| 3088 | JMP DEVABORT | ||
| 3089 | |||
| 3090 | OK001: | ||
| 3091 | mov si,64 ; set a loop bound for the homing process | ||
| 3092 | ; to avoid oscillation in homing | ||
| 3093 | CLUSHOME: | ||
| 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 | ||
| 3098 | XOR CH,CH | ||
| 3099 | FATSUB: | ||
| 3100 | SUB AX,[FATSEC] ; Sub off FAT sectors | ||
| 3101 | LOOP FATSUB | ||
| 3102 | SUB AX,[DIRSEC] ; Sub off directory sectors, AX is # data sectors | ||
| 3103 | MOV BX,1 ; Start at 1 sec per alloc unit | ||
| 3104 | CMP AX,4096-10 | ||
| 3105 | JB CSET ; 1 sector per cluster is OK | ||
| 3106 | MOV BX,2 | ||
| 3107 | CMP AX,(4096-10) * 2 | ||
| 3108 | JB CSET ; 2 sector per cluster is OK | ||
| 3109 | MOV BX,4 | ||
| 3110 | CMP AX,(4096-10) * 4 | ||
| 3111 | JB CSET ; 4 sector per cluster is OK | ||
| 3112 | MOV BX,8 | ||
| 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 | ||
| 3116 | CSET: | ||
| 3117 | ; Figure FAT size. AX is reasonable approx to number of DATA sectors | ||
| 3118 | ; BX is reasonable sec/cluster | ||
| 3119 | XOR DX,DX | ||
| 3120 | DIV BX ; AX is total clusters, ignore remainder | ||
| 3121 | ; can't have a "partial" cluster | ||
| 3122 | MOV CX,AX | ||
| 3123 | SHR CX,1 | ||
| 3124 | JNC ADDIT | ||
| 3125 | INC CX | ||
| 3126 | ADDIT: | ||
| 3127 | ADD AX,CX ; AX is Bytes for fat (1.5 * # of clusters) | ||
| 3128 | ADD AX,3 ; Plus two reserved clusters | ||
| 3129 | XOR DX,DX | ||
| 3130 | DIV [SSIZE] ; AX is # sectors for a FAT this size | ||
| 3131 | OR DX,DX | ||
| 3132 | JZ NOINC4 | ||
| 3133 | INC AX ; Round up | ||
| 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. | ||
| 3145 | HOMFIN: | ||
| 3146 | ; | ||
| 3147 | ; 6. Print out report of RAMDrive parameters | ||
| 3148 | ; | ||
| 3149 | MOV DX,OFFSET STATMES1 | ||
| 3150 | CALL PRINT | ||
| 3151 | MOV AX,[DEV_SIZE] | ||
| 3152 | CALL ITOA | ||
| 3153 | MOV DX,OFFSET STATMES2 | ||
| 3154 | CALL PRINT | ||
| 3155 | MOV AX,[SSIZE] | ||
| 3156 | CALL ITOA | ||
| 3157 | MOV DX,OFFSET STATMES3 | ||
| 3158 | CALL PRINT | ||
| 3159 | MOV AL,[CSIZE] | ||
| 3160 | XOR AH,AH | ||
| 3161 | CALL ITOA | ||
| 3162 | MOV DX,OFFSET STATMES4 | ||
| 3163 | CALL PRINT | ||
| 3164 | MOV AX,[DIRNUM] | ||
| 3165 | CALL ITOA | ||
| 3166 | MOV DX,OFFSET STATMES5 | ||
| 3167 | CALL PRINT | ||
| 3168 | CMP [RESMEM_SPECIAL],0 | ||
| 3169 | JZ NO_RELOC | ||
| 3170 | ; | ||
| 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. | ||
| 3176 | ; | ||
| 3177 | RAMDrive_RELOC: | ||
| 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 | ||
| 3185 | ADC DX,0 | ||
| 3186 | MOV CX,16 | ||
| 3187 | DIV CX ; AX is Seg addr of DATA region | ||
| 3188 | ; | ||
| 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 | ||
| 3193 | ; | ||
| 3194 | MOV BX,AX | ||
| 3195 | MOV DX,CS | ||
| 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 | ||
| 3201 | OKMOV: | ||
| 3202 | MOV ES,AX | ||
| 3203 | XOR SI,SI | ||
| 3204 | MOV DI,SI | ||
| 3205 | MOV CX,OFFSET RAMDrive_END ; Amount to move | ||
| 3206 | CLD | ||
| 3207 | REP MOVSB ; Reloc to data region | ||
| 3208 | PUSH ES ; Push FAR return | ||
| 3209 | MOV AX,OFFSET NO_RELOC | ||
| 3210 | PUSH AX | ||
| 3211 | PUSH ES | ||
| 3212 | POP DS ; DS is NEW RAMCODE | ||
| 3213 | RELOCR PROC FAR | ||
| 3214 | RET | ||
| 3215 | RELOCR ENDP | ||
| 3216 | |||
| 3217 | NO_RELOC: | ||
| 3218 | PUSH CS | ||
| 3219 | POP ES | ||
| 3220 | XOR DX,DX ; Sector 0 | ||
| 3221 | MOV CX,1 ; One sector | ||
| 3222 | MOV DI,OFFSET BOOT_SECTOR ; Boot sector | ||
| 3223 | MOV BH,1 ; Write | ||
| 3224 | CALL INIMEMIO | ||
| 3225 | INC DX ; First FAT sector | ||
| 3226 | MOV DI,OFFSET SECTOR_BUFFER | ||
| 3227 | XOR AX,AX | ||
| 3228 | MOV CX,512 | ||
| 3229 | CLD | ||
| 3230 | REP STOSW | ||
| 3231 | MOV DI,OFFSET SECTOR_BUFFER | ||
| 3232 | MOV CX,1 | ||
| 3233 | MOV WORD PTR ES:[DI],0FFF8H | ||
| 3234 | MOV BYTE PTR ES:[DI + 2],0FFH | ||
| 3235 | CALL INIMEMIO | ||
| 3236 | INC DX ; Next sector | ||
| 3237 | MOV WORD PTR ES:[DI],0 | ||
| 3238 | MOV BYTE PTR ES:[DI + 2],0 | ||
| 3239 | MOV CX,[FATSEC] | ||
| 3240 | DEC CX | ||
| 3241 | JCXZ FATDONE | ||
| 3242 | FATZERO: | ||
| 3243 | PUSH CX | ||
| 3244 | MOV CX,1 | ||
| 3245 | CALL INIMEMIO | ||
| 3246 | INC DX ; Next sector | ||
| 3247 | POP CX | ||
| 3248 | LOOP FATZERO | ||
| 3249 | FATDONE: | ||
| 3250 | MOV CX,1 | ||
| 3251 | MOV DI,OFFSET VOLID | ||
| 3252 | CALL INIMEMIO ; FIRST directory sector | ||
| 3253 | INC DX | ||
| 3254 | MOV CX,[DIRSEC] | ||
| 3255 | DEC CX | ||
| 3256 | JCXZ DRIVE_SET | ||
| 3257 | MOV DI,OFFSET SECTOR_BUFFER | ||
| 3258 | DIRZERO: | ||
| 3259 | PUSH CX | ||
| 3260 | MOV CX,1 | ||
| 3261 | CALL INIMEMIO | ||
| 3262 | INC DX ; Next sector | ||
| 3263 | POP CX | ||
| 3264 | LOOP DIRZERO | ||
| 3265 | ; | ||
| 3266 | DRIVE_SET: | ||
| 3267 | ; | ||
| 3268 | ; BPB IS NOW ALL SET | ||
| 3269 | ; | ||
| 3270 | MOV AL,1 ;Number of ramdrives | ||
| 3271 | ; | ||
| 3272 | ; NOTE FALL THROUGH!!!!!!! | ||
| 3273 | ; | ||
| 3274 | |||
| 3275 | ;** SETBPB - Set INIT packet I/O return values | ||
| 3276 | ; | ||
| 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 | ||
| 3280 | ; with AL = 1 | ||
| 3281 | ; | ||
| 3282 | ; ENTRY | ||
| 3283 | ; AL = INIT packet unit count | ||
| 3284 | ; EXIT | ||
| 3285 | ; through DEVEXIT | ||
| 3286 | ; USES | ||
| 3287 | ; DS, BX, CX | ||
| 3288 | ; | ||
| 3289 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 3290 | ; | ||
| 3291 | |||
| 3292 | SETBPB: | ||
| 3293 | ASSUME DS:NOTHING | ||
| 3294 | ; | ||
| 3295 | ; 7. Set the return INIT I/O packet values | ||
| 3296 | ; | ||
| 3297 | LDS BX,[PTRSAV] | ||
| 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 | ||
| 3304 | MOV CX,[TRUE_CS] | ||
| 3305 | MOV WORD PTR [BX.INIT_BPB + 2],CX | ||
| 3306 | JMP DEVEXIT | ||
| 3307 | |||
| 3308 | ;** INIMEMIO call MEMIO but preserve registers | ||
| 3309 | ; | ||
| 3310 | ; MEMIO is very register destructive, all this routine | ||
| 3311 | ; does is provide a less destructive way to call MEMIO. | ||
| 3312 | ; | ||
| 3313 | ; ENTRY | ||
| 3314 | ; Same as MEMIO | ||
| 3315 | ; EXIT | ||
| 3316 | ; Same as MEMIO | ||
| 3317 | ; USES | ||
| 3318 | ; AX, SI, BP | ||
| 3319 | ; | ||
| 3320 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 3321 | ; | ||
| 3322 | |||
| 3323 | INIMEMIO: | ||
| 3324 | ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 3325 | PUSH ES | ||
| 3326 | PUSH DI | ||
| 3327 | PUSH DS | ||
| 3328 | PUSH CX | ||
| 3329 | PUSH DX | ||
| 3330 | PUSH BX | ||
| 3331 | CALL MEMIO | ||
| 3332 | POP BX | ||
| 3333 | POP DX | ||
| 3334 | POP CX | ||
| 3335 | POP DS | ||
| 3336 | POP DI | ||
| 3337 | POP ES | ||
| 3338 | RET | ||
| 3339 | |||
| 3340 | ;** GETNUM - Read an unsigned integer | ||
| 3341 | ; | ||
| 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. | ||
| 3348 | ; | ||
| 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. | ||
| 3352 | ; | ||
| 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. | ||
| 3356 | ; | ||
| 3357 | ; ENTRY: | ||
| 3358 | ; DS:SI -> ASCII text of number | ||
| 3359 | ; EXIT: | ||
| 3360 | ; BX is binary for number | ||
| 3361 | ; SI advanced to point to char after number | ||
| 3362 | ; USES: | ||
| 3363 | ; AX,BX,DX,SI | ||
| 3364 | ; | ||
| 3365 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 3366 | ; | ||
| 3367 | |||
| 3368 | GETNUM: | ||
| 3369 | ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 3370 | |||
| 3371 | XOR BX,BX | ||
| 3372 | GETNUM1: | ||
| 3373 | LODSB | ||
| 3374 | SUB AL,"0" | ||
| 3375 | JB NUMRET | ||
| 3376 | CMP AL,9 | ||
| 3377 | JA NUMRET | ||
| 3378 | CBW | ||
| 3379 | XCHG AX,BX | ||
| 3380 | MOV DX,10 | ||
| 3381 | MUL DX | ||
| 3382 | ADD BX,AX | ||
| 3383 | JMP GETNUM1 | ||
| 3384 | |||
| 3385 | NUMRET: | ||
| 3386 | DEC SI | ||
| 3387 | RET | ||
| 3388 | |||
| 3389 | BREAK <INITIAL EMM control sector> | ||
| 3390 | |||
| 3391 | ;** INITIAL EMM_CTRL sector | ||
| 3392 | ; | ||
| 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. | ||
| 3398 | ; | ||
| 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. | ||
| 3406 | ; | ||
| 3407 | ; This data is appropriate to TYPE 1 and TYPE 3 drivers | ||
| 3408 | ; | ||
| 3409 | |||
| 3410 | EMM_CONTROL LABEL BYTE | ||
| 3411 | DB "MICROSOFT EMM CTRL VERSION 1.00 CONTROL BLOCK " | ||
| 3412 | DW 0 | ||
| 3413 | DW 0 | ||
| 3414 | ; NULL 0th record | ||
| 3415 | DW EMM_ALLOC + EMM_ISDRIVER | ||
| 3416 | DW EMM_EMM | ||
| 3417 | BASE_RESET LABEL DWORD ; RESMEM driver must patch this value | ||
| 3418 | DW EXTMEM_LOW + 1024 | ||
| 3419 | DW EXTMEM_HIGH | ||
| 3420 | DW 0 | ||
| 3421 | |||
| 3422 | DB 950 DUP(0) | ||
| 3423 | DB "ARRARRARRA" | ||
| 3424 | |||
| 3425 | |||
| 3426 | BREAK <RAMDrive COMMON INIT ROUTINES> | ||
| 3427 | |||
| 3428 | ;** DISK_ABORT - De-install RAMDrive after init | ||
| 3429 | ; | ||
| 3430 | ; This routine MUST BE CALLED to de-install a RAMDrive driver | ||
| 3431 | ; if the de-installation takes place: | ||
| 3432 | ; | ||
| 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. | ||
| 3437 | ; | ||
| 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. | ||
| 3441 | ; | ||
| 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. | ||
| 3446 | ; | ||
| 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). | ||
| 3454 | ; | ||
| 3455 | ; If this is a TYPE 2 driver, an ABOVE_DEALLOC call is made on | ||
| 3456 | ; ABOVE_PID. | ||
| 3457 | ; | ||
| 3458 | ; ENTRY: | ||
| 3459 | ; NONE | ||
| 3460 | ; | ||
| 3461 | ; BASE_RESET valid if TYPE 1 or TYPE 3 | ||
| 3462 | ; ABOVE_PID valid if TYPE 2 | ||
| 3463 | ; | ||
| 3464 | ; EXIT: | ||
| 3465 | ; NONE | ||
| 3466 | ; USES: | ||
| 3467 | ; ALL but DS | ||
| 3468 | ; | ||
| 3469 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 3470 | ; | ||
| 3471 | |||
| 3472 | DISK_ABORT: | ||
| 3473 | ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 3474 | |||
| 3475 | CMP [DRIVER_SEL],1 | ||
| 3476 | JNZ NOT_ABOVE | ||
| 3477 | AGAIN: | ||
| 3478 | ; | ||
| 3479 | ; TYPE 2, De-alloc the Above Board memory | ||
| 3480 | ; | ||
| 3481 | MOV DX,[ABOVE_PID] | ||
| 3482 | MOV AH,ABOVE_DEALLOC | ||
| 3483 | INT 67H | ||
| 3484 | CMP AH,ABOVE_ERROR_BUSY | ||
| 3485 | JZ AGAIN | ||
| 3486 | JMP SHORT RET002 | ||
| 3487 | |||
| 3488 | NOT_ABOVE: | ||
| 3489 | CMP [RESMEM_SPECIAL],0 | ||
| 3490 | JNZ RET002 ; No EMM_CTRL on TYPE 4 | ||
| 3491 | ; | ||
| 3492 | ; sp new int15 allocation for ext memory (except for oli memory) so no | ||
| 3493 | ; emm control for these | ||
| 3494 | ; | ||
| 3495 | ; | ||
| 3496 | cmp [new_all],0 ;new allocation scheme | ||
| 3497 | jne ret002 ; if yes then skip emm updates | ||
| 3498 | ; | ||
| 3499 | ; TYPE 1 or 3, turn off last EMM_ISDRIVER | ||
| 3500 | ; | ||
| 3501 | MOV AX,WORD PTR [BASE_RESET] | ||
| 3502 | MOV DX,WORD PTR [BASE_RESET + 2] | ||
| 3503 | SUB AX,1024 ; Backup to EMM_CTRL | ||
| 3504 | SBB DX,0 | ||
| 3505 | MOV WORD PTR [BASE_ADDR],AX | ||
| 3506 | MOV WORD PTR [BASE_ADDR + 2],DX | ||
| 3507 | XOR BH,BH ; READ | ||
| 3508 | CALL CTRL_IO ; Get EMM_CTRL | ||
| 3509 | JC RET002 | ||
| 3510 | MOV DI,OFFSET SECTOR_BUFFER | ||
| 3511 | MOV SI,DI | ||
| 3512 | ADD DI,EMM_RECORD | ||
| 3513 | MOV BX,-1 ; Init to "no such record" | ||
| 3514 | MOV CX,EMM_NUMREC | ||
| 3515 | LOOK_RECX: | ||
| 3516 | ; | ||
| 3517 | ; Look for last installed MS-DOS region | ||
| 3518 | ; | ||
| 3519 | TEST [DI.EMM_FLAGS],EMM_ALLOC | ||
| 3520 | JZ DONE | ||
| 3521 | TEST [DI.EMM_FLAGS],EMM_ISDRIVER | ||
| 3522 | JZ NEXTRECX ; No Driver | ||
| 3523 | CMP [DI.EMM_SYSTEM],EMM_MSDOS | ||
| 3524 | JNZ NEXTRECX | ||
| 3525 | MOV BX,DI | ||
| 3526 | NEXTRECX: | ||
| 3527 | ADD DI,SIZE EMM_REC | ||
| 3528 | LOOP LOOK_RECX | ||
| 3529 | DONE: | ||
| 3530 | CMP BX,-1 ; DIDn't find it | ||
| 3531 | JZ RET002 | ||
| 3532 | AND [BX.EMM_FLAGS],NOT EMM_ISDRIVER ; Undo install | ||
| 3533 | MOV BH,1 ; WRITE | ||
| 3534 | CALL CTRL_IO ; EMM_CTRL back out | ||
| 3535 | RET002: | ||
| 3536 | ; | ||
| 3537 | ; Reset INT 9 and/or INT 19 if OLD_19 is not -1 | ||
| 3538 | ; | ||
| 3539 | PUSH DS | ||
| 3540 | LDS DX,[OLD_19] | ||
| 3541 | ASSUME DS:NOTHING | ||
| 3542 | MOV AX,DS | ||
| 3543 | CMP AX,-1 | ||
| 3544 | JNZ RESET_VECS | ||
| 3545 | CMP AX,DX | ||
| 3546 | JZ NO_VECS | ||
| 3547 | RESET_VECS: | ||
| 3548 | MOV AX,(Set_Interrupt_Vector SHL 8) OR 19H | ||
| 3549 | INT 21H | ||
| 3550 | ; LDS DX,[OLD_9] | ||
| 3551 | ; MOV AX,(Set_Interrupt_Vector SHL 8) OR 9H | ||
| 3552 | ; INT 21H | ||
| 3553 | ; | ||
| 3554 | ; sp we have to deinstall the int15 handler also if it was installed | ||
| 3555 | ; | ||
| 3556 | lds dx,[old_15] ; get the old 15h handler addressin ds:dx | ||
| 3557 | mov ax,ds | ||
| 3558 | cmp ax,-1 | ||
| 3559 | jne reset_15 | ||
| 3560 | cmp ax,dx | ||
| 3561 | je no_vecs | ||
| 3562 | reset_15: | ||
| 3563 | mov ax,(set_interrupt_vector shl 8) or 15h | ||
| 3564 | int 21h | ||
| 3565 | NO_VECS: | ||
| 3566 | POP DS | ||
| 3567 | RET | ||
| 3568 | |||
| 3569 | ;** CTRL_IO - Read/Write the first 1024 bytes at BASE_ADDR | ||
| 3570 | ; | ||
| 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 | ||
| 3579 | ; SECTOR_BUFFER. | ||
| 3580 | ; | ||
| 3581 | ; ENTRY: | ||
| 3582 | ; BH = 0 for READ, 1 for WRITE | ||
| 3583 | ; EXIT: | ||
| 3584 | ; SECTOR_BUFFER filled in with 1024 bytes at BASE_ADDR | ||
| 3585 | ; USES: | ||
| 3586 | ; ALL but DS | ||
| 3587 | ; | ||
| 3588 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 3589 | ; | ||
| 3590 | |||
| 3591 | CTRL_IO: | ||
| 3592 | ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 3593 | XOR DX,DX | ||
| 3594 | MOV AX,DX ; Offset 0 | ||
| 3595 | MOV CX,512 ; 1024 bytes | ||
| 3596 | PUSH CS | ||
| 3597 | POP ES | ||
| 3598 | MOV DI,OFFSET SECTOR_BUFFER | ||
| 3599 | PUSH DS | ||
| 3600 | CALL BLKMOV ; Read in EMM_CTRL | ||
| 3601 | POP DS | ||
| 3602 | RET | ||
| 3603 | |||
| 3604 | ;** MM_SETDRIVE - Look for/Init EMM_CTRL and DOS volume | ||
| 3605 | ; | ||
| 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. | ||
| 3608 | ; | ||
| 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). | ||
| 3617 | ; | ||
| 3618 | ; ENTRY: | ||
| 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 | ||
| 3624 | ; EXIT: | ||
| 3625 | ; CARRY SET - error, message already printed | ||
| 3626 | ; CARRY CLEAR | ||
| 3627 | ; BASE_ADDR set for this drive | ||
| 3628 | ; INIT_DRIVE set | ||
| 3629 | ; DEV_SIZE set to TRUE size | ||
| 3630 | ; | ||
| 3631 | ; WARNING! Exit conditions MUST match CHECK_DOS_VOL as it transfers | ||
| 3632 | ; to that routine. | ||
| 3633 | ; | ||
| 3634 | ; USES | ||
| 3635 | ; ALL but DS | ||
| 3636 | ; | ||
| 3637 | ; Used by TYPE 1 and TYPE 3 drivers | ||
| 3638 | ; | ||
| 3639 | |||
| 3640 | MM_SETDRIVE: | ||
| 3641 | ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 3642 | XOR BH,BH ; READ | ||
| 3643 | CALL CTRL_IO ; Get EMM_CTRL | ||
| 3644 | MOV DX,OFFSET INIT_IO_ERR | ||
| 3645 | JC ERR_RET2 | ||
| 3646 | CALL FIND_VDRIVE ; Snoop | ||
| 3647 | JC RET001 | ||
| 3648 | PUSHF ; Save zero status for DOS VOL snoop | ||
| 3649 | PUSH ES ; Save EMM_BASE from EMM_REC | ||
| 3650 | PUSH DI | ||
| 3651 | ; | ||
| 3652 | ; once again if we installed according to new int15 standard we should | ||
| 3653 | ; not write emm back | ||
| 3654 | ; | ||
| 3655 | ; | ||
| 3656 | ; test if we installed according to new standard | ||
| 3657 | ; | ||
| 3658 | cmp [new_all],0 ; did we install according to new standard | ||
| 3659 | jne skip_emm_write ; skip writing back emm | ||
| 3660 | ; | ||
| 3661 | MOV BH,1 ; WRITE | ||
| 3662 | CALL CTRL_IO ; Write EMM_CTRL back out | ||
| 3663 | MOV DX,OFFSET INIT_IO_ERR | ||
| 3664 | JC ERR_RET2P | ||
| 3665 | skip_emm_write: | ||
| 3666 | POP WORD PTR [BASE_ADDR] ; Set final correct BASE_ADDR | ||
| 3667 | POP WORD PTR [BASE_ADDR + 2] | ||
| 3668 | POPF | ||
| 3669 | ; | ||
| 3670 | ; NOTE TRANSFER TO DIFFERENT ROUTINE | ||
| 3671 | ; | ||
| 3672 | JZ CHECK_DOS_VOL | ||
| 3673 | CLC ; Leave INIT_DRIVE set | ||
| 3674 | RET001: | ||
| 3675 | RET | ||
| 3676 | |||
| 3677 | ERR_RET2P: | ||
| 3678 | ADD SP,6 | ||
| 3679 | ERR_RET2: | ||
| 3680 | CALL PRINT | ||
| 3681 | STC | ||
| 3682 | RET | ||
| 3683 | |||
| 3684 | ;** CHECK_DOS_VOL examine RAMDrive region for valid DOS volume. | ||
| 3685 | ; | ||
| 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. | ||
| 3690 | ; | ||
| 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. | ||
| 3697 | ; IF they match | ||
| 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 | ||
| 3701 | ; RDRIVEBPB. | ||
| 3702 | ; ELSE | ||
| 3703 | ; Leave INIT_DRIVE set to whatever it was on input (1 or 2) | ||
| 3704 | ; indicating that the drive must be INITed. | ||
| 3705 | ; ELSE | ||
| 3706 | ; Leave INIT_DRIVE set to whatever it was on input (1 or 2) | ||
| 3707 | ; indicating that the drive must be INITed. | ||
| 3708 | ; | ||
| 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. | ||
| 3714 | ; | ||
| 3715 | ; ENTRY: | ||
| 3716 | ; BASE_ADDR set to point at START of DOS device | ||
| 3717 | ; EXIT: | ||
| 3718 | ; CARRY SET - error, message already printed | ||
| 3719 | ; CARRY CLEAR | ||
| 3720 | ; INIT_DRIVE set | ||
| 3721 | ; SECTOR_BUFFER contains first 1024 bytes of device | ||
| 3722 | ; USES: | ||
| 3723 | ; All but DS | ||
| 3724 | ; | ||
| 3725 | ; WARNING! Exit conditions MUST match MM_SETDRIVE as it jumps to this | ||
| 3726 | ; routine. | ||
| 3727 | ; | ||
| 3728 | ; Used by TYPE 1, 2 and 3 drivers | ||
| 3729 | ; | ||
| 3730 | |||
| 3731 | CHECK_DOS_VOL: | ||
| 3732 | ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 3733 | XOR BH,BH ; READ | ||
| 3734 | ; | ||
| 3735 | ; NOTE: WE CANNOT CALL MEMIO, WE MUST STILL USE CTRL_IO because the BPB | ||
| 3736 | ; is not set up. | ||
| 3737 | ; | ||
| 3738 | CALL CTRL_IO ; Since BASE_ADDR is set, reads start of DEVICE | ||
| 3739 | MOV DX,OFFSET INIT_IO_ERR | ||
| 3740 | JC ERR_RET2 | ||
| 3741 | PUSH CS | ||
| 3742 | POP ES | ||
| 3743 | MOV DI,OFFSET SECTOR_BUFFER | ||
| 3744 | MOV SI,OFFSET BOOT_SECTOR | ||
| 3745 | MOV CX,OFFSET RDRIVEBPB - OFFSET BOOT_SECTOR | ||
| 3746 | CLD | ||
| 3747 | REPE CMPSB | ||
| 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 | ||
| 3752 | REPE CMPSB | ||
| 3753 | JNZ OK_RET ; No DOS device | ||
| 3754 | CMP [INIT_DRIVE],2 | ||
| 3755 | JZ NOT_VALID ; Current value 2 means we CANNOT | ||
| 3756 | ; assume this BPB is valid. | ||
| 3757 | ; | ||
| 3758 | ; Check to make sure found BPB has same SSIZE and DIRNUM values | ||
| 3759 | ; | ||
| 3760 | MOV SI,OFFSET SECTOR_BUFFER + (OFFSET SSIZE - OFFSET BOOT_SECTOR) | ||
| 3761 | LODSW | ||
| 3762 | CMP AX,[SSIZE] | ||
| 3763 | JNZ NOT_VALID ; Sector size different than user request | ||
| 3764 | MOV SI,OFFSET SECTOR_BUFFER + (OFFSET DIRNUM - OFFSET BOOT_SECTOR) | ||
| 3765 | LODSW | ||
| 3766 | CMP AX,[DIRNUM] | ||
| 3767 | JNZ NOT_VALID ; Sector size different than user request | ||
| 3768 | |||
| 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 | ||
| 3774 | NOT_VALID: | ||
| 3775 | OK_RET: | ||
| 3776 | CLC | ||
| 3777 | RET | ||
| 3778 | |||
| 3779 | ;** FIND_VDRIVE - Check out EMM_CTRL and alloc | ||
| 3780 | ; | ||
| 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. | ||
| 3790 | ; | ||
| 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 | ||
| 3795 | ; is installed. | ||
| 3796 | ; | ||
| 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. | ||
| 3806 | ; | ||
| 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. | ||
| 3817 | ; | ||
| 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. | ||
| 3828 | ; | ||
| 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: | ||
| 3833 | ; | ||
| 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 | ||
| 3843 | ; ELSE | ||
| 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 | ||
| 3851 | ; size back. | ||
| 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. | ||
| 3857 | ; ELSE | ||
| 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 | ||
| 3868 | ; ELSE | ||
| 3869 | ; We can't do anything, so set DEV_SIZE | ||
| 3870 | ; to EMM_KSIZE and we're done. | ||
| 3871 | ; ELSE | ||
| 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. | ||
| 3882 | ; ELSE | ||
| 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. | ||
| 3888 | ; | ||
| 3889 | ; ENTRY: | ||
| 3890 | ; SECTOR_BUFFER containes POSSIBLE EMM_CTRL sector | ||
| 3891 | ; MUST BE CHECKED | ||
| 3892 | ; EXT_K is set to size of extended memory | ||
| 3893 | ; DEV_SIZE is set to user requested device size | ||
| 3894 | ; EXIT: | ||
| 3895 | ; CARRY SET | ||
| 3896 | ; Error, message already printed | ||
| 3897 | ; CARRY CLEAR | ||
| 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 | ||
| 3901 | ; EMM_CTRL sector | ||
| 3902 | ; DEV_SIZE set to TRUE size | ||
| 3903 | ; Zero SET | ||
| 3904 | ; An existing disk was found, region should be checked | ||
| 3905 | ; for valid MS-DOS volume | ||
| 3906 | ; Zero RESET | ||
| 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). | ||
| 3912 | ; | ||
| 3913 | ; USES: | ||
| 3914 | ; ALL but DS | ||
| 3915 | ; | ||
| 3916 | ; Specific to TYPE 1 and 3 drivers | ||
| 3917 | ; | ||
| 3918 | |||
| 3919 | FIND_VDRIVE: | ||
| 3920 | ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 3921 | PUSH CS | ||
| 3922 | POP ES | ||
| 3923 | MOV DI,OFFSET SECTOR_BUFFER | ||
| 3924 | MOV SI,OFFSET EMM_CONTROL | ||
| 3925 | MOV CX,50 | ||
| 3926 | CLD | ||
| 3927 | REPE CMPSB | ||
| 3928 | JNZ no_emm_rec ; No EMM_CTRL | ||
| 3929 | ADD SI,EMM_TAIL_SIG - 50 | ||
| 3930 | ADD DI,EMM_TAIL_SIG - 50 | ||
| 3931 | MOV CX,10 | ||
| 3932 | REPE CMPSB | ||
| 3933 | jnz no_emm_rec | ||
| 3934 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 3935 | ; JNZ SETCTRL ; No EMM_CTRL | ||
| 3936 | ; MOV DI,OFFSET SECTOR_BUFFER | ||
| 3937 | ; MOV AX,[EXT_K] | ||
| 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 | ||
| 3941 | ;SETCTRL: | ||
| 3942 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 3943 | ; | ||
| 3944 | dec [valid_emm] ; signal prescence of emm record | ||
| 3945 | no_emm_rec: | ||
| 3946 | ; | ||
| 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 | ||
| 3949 | ; | ||
| 3950 | ; | ||
| 3951 | ; check if driver in extended | ||
| 3952 | ; | ||
| 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 | ||
| 3958 | ; | ||
| 3959 | ; for olivetti u memory we still have to install according to ol' microsoft st | ||
| 3960 | ; | ||
| 3961 | old_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 | ||
| 3966 | PUSH DI | ||
| 3967 | MOV SI,OFFSET EMM_CONTROL | ||
| 3968 | MOV CX,1024/2 | ||
| 3969 | REP MOVSW ; Move in initial EMM_CTRL | ||
| 3970 | POP DI | ||
| 3971 | MOV AX,[EXT_K] | ||
| 3972 | DEC AX ; Size in EMM_CTRL doesn't include EMM_CTRL | ||
| 3973 | MOV [DI.EMM_TOTALK],AX | ||
| 3974 | MOV [DI.EMM_AVAILK],AX | ||
| 3975 | SCAN_DEV: | ||
| 3976 | XOR BX,BX ; Will get tripped if a DOS dev found | ||
| 3977 | MOV SI,OFFSET SECTOR_BUFFER ; DS:SI points to EMM_CTRL | ||
| 3978 | MOV DI,SI | ||
| 3979 | ADD DI,EMM_RECORD ; DS:DI points to EMM records | ||
| 3980 | MOV CX,EMM_NUMREC | ||
| 3981 | LOOK_REC: | ||
| 3982 | TEST [DI.EMM_FLAGS],EMM_ALLOC | ||
| 3983 | JNZ CHECK_SYS | ||
| 3984 | JMP GOT_FREE_REC ; Must alloc new region | ||
| 3985 | |||
| 3986 | CHECK_SYS: | ||
| 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] | ||
| 3993 | CMP CX,1 | ||
| 3994 | JBE OK_SET_DEV ; If this is last record, must | ||
| 3995 | ; select this size | ||
| 3996 | CMP AX,[DEV_SIZE] | ||
| 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. | ||
| 4001 | PUSH DI | ||
| 4002 | ADD DI,SIZE EMM_REC | ||
| 4003 | TEST [DI.EMM_FLAGS],EMM_ALLOC | ||
| 4004 | POP DI | ||
| 4005 | JZ SHRINK_BLOCK ; Next block is free, shrink | ||
| 4006 | MOV AX,[DEV_SIZE] | ||
| 4007 | JMP SHORT SET_2 | ||
| 4008 | |||
| 4009 | SHRINK_BLOCK: | ||
| 4010 | SUB AX,[DEV_SIZE] ; AX is amount to shrink | ||
| 4011 | ADD [SI.EMM_AVAILK],AX | ||
| 4012 | MOV AX,[DEV_SIZE] | ||
| 4013 | MOV [DI.EMM_KSIZE],AX | ||
| 4014 | JMP SHORT SET_2 | ||
| 4015 | |||
| 4016 | INSUFF_MEM: ; Size of found block is smaller | ||
| 4017 | ; than requested size. | ||
| 4018 | PUSH DI | ||
| 4019 | ADD DI,SIZE EMM_REC | ||
| 4020 | TEST [DI.EMM_FLAGS],EMM_ALLOC | ||
| 4021 | POP DI | ||
| 4022 | JNZ OK_SET_DEV ; Next block is NOT free, can't grow | ||
| 4023 | TRY_TO_GROW_BLOCK: | ||
| 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 | ||
| 4027 | ; when it shouldn't | ||
| 4028 | SUB AX,[DEV_SIZE] | ||
| 4029 | NEG AX ; AX is amount we would like to grow | ||
| 4030 | SUB [SI.EMM_AVAILK],AX | ||
| 4031 | JNC GOT_THE_MEM | ||
| 4032 | ADD AX,[SI.EMM_AVAILK] ; AX is MAX we can grow | ||
| 4033 | MOV [SI.EMM_AVAILK],0 ; We take all that's left | ||
| 4034 | GOT_THE_MEM: | ||
| 4035 | ADD [DI.EMM_KSIZE],AX | ||
| 4036 | MOV AX,[DI.EMM_KSIZE] | ||
| 4037 | SET_2: | ||
| 4038 | MOV [INIT_DRIVE],2 ; CANNOT TRUST BPB in boot sector | ||
| 4039 | OK_SET_DEV: | ||
| 4040 | MOV [DEV_SIZE],AX | ||
| 4041 | OR [DI.EMM_FLAGS],EMM_ISDRIVER | ||
| 4042 | LES DI,[DI.EMM_BASE] | ||
| 4043 | XOR AX,AX ; Set zero, clear carry | ||
| 4044 | RET | ||
| 4045 | |||
| 4046 | NEXTRECI: | ||
| 4047 | INC BX ; Flag that we ARE NOT first DOS device | ||
| 4048 | NEXTREC: | ||
| 4049 | ADD DI,SIZE EMM_REC ; Next record | ||
| 4050 | LOOP LOOK_RECJ | ||
| 4051 | VERRR: | ||
| 4052 | MOV DX,OFFSET ERRMSG2 | ||
| 4053 | CALL PRINT | ||
| 4054 | STC | ||
| 4055 | RET | ||
| 4056 | |||
| 4057 | LOOK_RECJ: | ||
| 4058 | JMP LOOK_REC | ||
| 4059 | |||
| 4060 | GOT_FREE_REC: | ||
| 4061 | MOV AX,[SI.EMM_AVAILK] | ||
| 4062 | CMP AX,16 | ||
| 4063 | JB VERRR ; 16K is smallest device | ||
| 4064 | CALL SET_RESET ; Set INT 19,9 as per BX | ||
| 4065 | CMP AX,[DEV_SIZE] | ||
| 4066 | JBE GOTSIZE ; Not enough for user spec | ||
| 4067 | MOV AX,[DEV_SIZE] ; User size is OK | ||
| 4068 | GOTSIZE: | ||
| 4069 | MOV [DEV_SIZE],AX | ||
| 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 | ||
| 4074 | PUSH DI | ||
| 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 | ||
| 4079 | MOV CX,1024 | ||
| 4080 | MUL CX ; Mult size by 1024 to get # bytes | ||
| 4081 | ADD AX,BX ; Add size onto base to get next base | ||
| 4082 | ADC DX,DI | ||
| 4083 | POP DI | ||
| 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 | ||
| 4088 | INC AX ; RESET zero | ||
| 4089 | RET | ||
| 4090 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 4091 | ; the new int15 standard | ||
| 4092 | ; | ||
| 4093 | new_st: | ||
| 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 | ||
| 4102 | ; | ||
| 4103 | sub bx,1 ; subtract the emm ctrl record size | ||
| 4104 | mov di,offset sector_buffer ; set up to address the ctrl record | ||
| 4105 | ; read in | ||
| 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 | ||
| 4110 | ; | ||
| 4111 | cmp bx,128 ; is it the minimum required | ||
| 4112 | jb verrr ; if less go to abort | ||
| 4113 | ; | ||
| 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 | ||
| 4116 | ; | ||
| 4117 | no_adjust: | ||
| 4118 | cmp [dev_size],bx ; | ||
| 4119 | jb skip_adj_dev_size ; if enough space we don't need to adj | ||
| 4120 | ; dev_size | ||
| 4121 | mov [dev_size],bx ; else we have compromise on dev size | ||
| 4122 | skip_adj_dev_size: | ||
| 4123 | ; | ||
| 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 | ||
| 4126 | ; | ||
| 4127 | mov bx,[ext_k] ; get memory which was reported by int15 | ||
| 4128 | add bx,[special_mem] ; account for olivetti guys | ||
| 4129 | sub bx,[dev_size] ; | ||
| 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 | ||
| 4133 | ; | ||
| 4134 | push ax | ||
| 4135 | push dx | ||
| 4136 | push bx | ||
| 4137 | push es | ||
| 4138 | mov ax,(get_interrupt_vector shl 8) or 15h | ||
| 4139 | int 21h | ||
| 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 | ||
| 4144 | int 21h | ||
| 4145 | pop es | ||
| 4146 | pop bx | ||
| 4147 | pop dx | ||
| 4148 | pop ax | ||
| 4149 | ; | ||
| 4150 | ; set up int19 vector | ||
| 4151 | ; | ||
| 4152 | xor bx,bx ; for int19 to be installed | ||
| 4153 | call set_reset | ||
| 4154 | ; | ||
| 4155 | ; now fill device base address in es:di | ||
| 4156 | ; | ||
| 4157 | mov ax,[ext_k] | ||
| 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] ; | ||
| 4163 | mov es,dx ; | ||
| 4164 | mov di,ax ; | ||
| 4165 | xor ax,ax ; to say that there | ||
| 4166 | inc ax ; was no dos volume reset 0 | ||
| 4167 | ret | ||
| 4168 | |||
| 4169 | ;** SET_RESET - Set up INT 19/INT 9 vectors | ||
| 4170 | ; | ||
| 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 | ||
| 4178 | ; image. | ||
| 4179 | ; | ||
| 4180 | ; ENTRY: | ||
| 4181 | ; BX is 0 if INT 19/9 code to be installed | ||
| 4182 | ; EXIT: | ||
| 4183 | ; NONE | ||
| 4184 | ; USES: | ||
| 4185 | ; None | ||
| 4186 | ; | ||
| 4187 | ; COMMON TO TYPE 1, 2, 3, 4 drivers | ||
| 4188 | ; | ||
| 4189 | |||
| 4190 | SET_RESET: | ||
| 4191 | ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 4192 | OR BX,BX | ||
| 4193 | JNZ RET005 | ||
| 4194 | cmp [u_switch],0 ; for uswitch don't bother | ||
| 4195 | jne ret005 | ||
| 4196 | PUSH AX | ||
| 4197 | PUSH DX | ||
| 4198 | PUSH BX | ||
| 4199 | PUSH ES | ||
| 4200 | MOV AX,(Get_Interrupt_Vector SHL 8) OR 19H | ||
| 4201 | INT 21H | ||
| 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 | ||
| 4206 | INT 21H | ||
| 4207 | ; MOV AX,(Get_Interrupt_Vector SHL 8) OR 9H | ||
| 4208 | ; INT 21H | ||
| 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 | ||
| 4213 | ; INT 21H | ||
| 4214 | MOV WORD PTR [TERM_ADDR],OFFSET RESET_INCLUDE | ||
| 4215 | POP ES | ||
| 4216 | POP BX | ||
| 4217 | POP DX | ||
| 4218 | POP AX | ||
| 4219 | RET005: | ||
| 4220 | RET | ||
| 4221 | |||
| 4222 | BREAK </E INIT Code> | ||
| 4223 | |||
| 4224 | ;** AT_EXT_INIT - Perform /E (TYPE 1) specific initialization | ||
| 4225 | ; | ||
| 4226 | ; This code does the drive TYPE specific initialization for TYPE 1 | ||
| 4227 | ; drivers. | ||
| 4228 | ; | ||
| 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. | ||
| 4239 | ; | ||
| 4240 | ; ENTRY: | ||
| 4241 | ; Invokation line parameter values set. | ||
| 4242 | ; EXIT: | ||
| 4243 | ; CARRY 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). | ||
| 4247 | ; CARRY CLEAR | ||
| 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. | ||
| 4257 | ; | ||
| 4258 | ; USES: | ||
| 4259 | ; ALL but DS | ||
| 4260 | ; | ||
| 4261 | ; Code is specific to TYPE 1 driver | ||
| 4262 | ; | ||
| 4263 | |||
| 4264 | AT_EXT_INIT: | ||
| 4265 | ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 4266 | push ds | ||
| 4267 | call sys_det ; new routine to do more comprehensive checking | ||
| 4268 | pop ds | ||
| 4269 | jnc at001 ; sp | ||
| 4270 | ; | ||
| 4271 | MOV DX,OFFSET BAD_AT | ||
| 4272 | ERR_RET: | ||
| 4273 | CALL PRINT | ||
| 4274 | STC | ||
| 4275 | RET | ||
| 4276 | |||
| 4277 | AT001: | ||
| 4278 | ;; patch the values of base_reset and base_addr to get the addressing right. | ||
| 4279 | ;; | ||
| 4280 | cmp [U_SWITCH],0 ;; patch the code for /U option | ||
| 4281 | jz AT001A | ||
| 4282 | mov ax,00fah | ||
| 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 | ||
| 4286 | AT001A: | ||
| 4287 | MOV AX,8800H | ||
| 4288 | INT 15H ; Get extended memory size | ||
| 4289 | MOV DX,OFFSET NO_MEM | ||
| 4290 | OR AX,AX | ||
| 4291 | JZ ERR_RET | ||
| 4292 | |||
| 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. | ||
| 4297 | |||
| 4298 | cmp [U_SWITCH],0 ;; did we ask for upper extended memory | ||
| 4299 | jz olstuff ;; no | ||
| 4300 | call UpperMemCheck ;; yes, see if anything there | ||
| 4301 | jc ERR_RET ;; no, quit | ||
| 4302 | mov ax,384 ;; yes, but max allowed is 384K | ||
| 4303 | jmp short at001b | ||
| 4304 | olstuff: | ||
| 4305 | cmp [S5_FLAG],S_OLIVETTI ;; if not 6300 PLUS, go on | ||
| 4306 | jne at001b | ||
| 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 | ||
| 4311 | AT001B: | ||
| 4312 | |||
| 4313 | MOV DX,OFFSET ERRMSG2 | ||
| 4314 | cmp ax,16 | ||
| 4315 | ; CMP AX,17 ; 1k ident block plus 16k min Ramdrive | ||
| 4316 | JB ERR_RET | ||
| 4317 | MOV [EXT_K],AX | ||
| 4318 | MOV BX,AX | ||
| 4319 | ; DEC BX ; BX is MAX possible disk size | ||
| 4320 | CMP [DEV_SIZE],BX | ||
| 4321 | JBE AT002 ; DEV_SIZE OK | ||
| 4322 | MOV [DEV_SIZE],BX ; Limit DEV_SIZE to available | ||
| 4323 | AT002: | ||
| 4324 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 4325 | ; 386 modification | ||
| 4326 | test [sys_flg],M_386 | ||
| 4327 | je loadall_setup | ||
| 4328 | mov ax,cs | ||
| 4329 | mov word ptr [cod_seg],ax | ||
| 4330 | ; set cs descriptor | ||
| 4331 | mov cx,16 | ||
| 4332 | mul cx | ||
| 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 | ||
| 4337 | ; set gdt base | ||
| 4338 | mov si,offset emm_gdt | ||
| 4339 | add ax,offset start_gdt | ||
| 4340 | adc dx,0 | ||
| 4341 | mov [si].gdt_base_0,ax | ||
| 4342 | mov [si].gdt_base_2,dx | ||
| 4343 | jmp common_setup | ||
| 4344 | ; | ||
| 4345 | loadall_setup: | ||
| 4346 | ; | ||
| 4347 | ; Init various pieces of LOADALL info | ||
| 4348 | ; | ||
| 4349 | ;;;; SMSW [LDSW] | ||
| 4350 | ;;;; SIDT QWORD PTR [IDTDES] | ||
| 4351 | ;;;; SGDT QWORD PTR [GDTDES] | ||
| 4352 | ;;;; ; | ||
| 4353 | ;;;; ; NOW The damn SXXX instructions store the desriptors in a | ||
| 4354 | ;;;; ; different order than LOADALL wants | ||
| 4355 | ;;;; ; | ||
| 4356 | ;;;; MOV SI,OFFSET IDTDES | ||
| 4357 | ;;;; CALL FIX_DESCRIPTOR | ||
| 4358 | ;;;; MOV SI,OFFSET GDTDES | ||
| 4359 | ;;;; CALL FIX_DESCRIPTOR | ||
| 4360 | MOV [LCSS],CS | ||
| 4361 | MOV SI,OFFSET CSDES | ||
| 4362 | MOV AX,CS | ||
| 4363 | CALL SEG_SET | ||
| 4364 | common_setup: | ||
| 4365 | CALL MM_SETDRIVE | ||
| 4366 | RET | ||
| 4367 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 4368 | ;;* UpperMemCheck - Called by 6300 PLUS to verify existence of | ||
| 4369 | ;; upper extended memory of 384K at FA0000h | ||
| 4370 | ;; | ||
| 4371 | ;; Returns carry set if no upper extended memory. | ||
| 4372 | ;; | ||
| 4373 | ;; This routine is called only by a 6300 PLUS, and | ||
| 4374 | ;; it reads the hardware switch DSW2 to do the job. | ||
| 4375 | ;; | ||
| 4376 | UpperMemCheck: | ||
| 4377 | push ax | ||
| 4378 | in al,66h | ||
| 4379 | and al,00001111b | ||
| 4380 | cmp al,00001011b | ||
| 4381 | pop ax | ||
| 4382 | jnz nomem | ||
| 4383 | clc | ||
| 4384 | ret | ||
| 4385 | nomem: | ||
| 4386 | stc | ||
| 4387 | ret | ||
| 4388 | |||
| 4389 | |||
| 4390 | |||
| 4391 | BREAK </A INIT Code> | ||
| 4392 | |||
| 4393 | ;** EMM device driver name | ||
| 4394 | ; | ||
| 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. | ||
| 4398 | ; | ||
| 4399 | ; This datum is specific to TYPE 2 drivers | ||
| 4400 | ; | ||
| 4401 | |||
| 4402 | ABOVE_DEV_NAME DB "EMMXXXX0" | ||
| 4403 | |||
| 4404 | ;** ABOVE_INIT - Perform /A (TYPE 2) specific initialization | ||
| 4405 | ; | ||
| 4406 | ; This code performes the driver specific initialization for | ||
| 4407 | ; type 2 drivers. | ||
| 4408 | ; | ||
| 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. | ||
| 4415 | ; | ||
| 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. | ||
| 4428 | ; | ||
| 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. | ||
| 4444 | ; IF it is not | ||
| 4445 | ; Set INIT_DRIVE to 2 to indicate that the found volume | ||
| 4446 | ; is invalid and needs to be re-initialized. | ||
| 4447 | ; | ||
| 4448 | ; SEE ALSO | ||
| 4449 | ; INTEL Expanded Memory Manager Programming Specification | ||
| 4450 | ; | ||
| 4451 | ; ENTRY: | ||
| 4452 | ; Invokation line parameter values set. | ||
| 4453 | ; EXIT: | ||
| 4454 | ; ABOVE_BLKMOV code swapped in at BLKMOV | ||
| 4455 | ; ABOVE_RESET code swapped in at RESET_SYSTEM | ||
| 4456 | ; CARRY SET | ||
| 4457 | ; Error, message already printed. Driver not installed. | ||
| 4458 | ; No Above Board memory allocated. | ||
| 4459 | ; CARRY CLEAR | ||
| 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. | ||
| 4466 | ; | ||
| 4467 | ; USES: | ||
| 4468 | ; ALL but DS | ||
| 4469 | ; | ||
| 4470 | ; Code is specific to TYPE 2 driver | ||
| 4471 | ; | ||
| 4472 | |||
| 4473 | ABOVE_INIT: | ||
| 4474 | ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 4475 | ; | ||
| 4476 | ; Swap above code into place | ||
| 4477 | ; | ||
| 4478 | PUSH CS | ||
| 4479 | POP ES | ||
| 4480 | MOV SI,OFFSET ABOVE_CODE | ||
| 4481 | MOV DI,OFFSET DRIVE_CODE | ||
| 4482 | MOV CX,OFFSET DRIVE_END - OFFSET DRIVE_CODE | ||
| 4483 | REP MOVSB | ||
| 4484 | MOV SI,OFFSET ABOVE_RESET | ||
| 4485 | MOV DI,OFFSET RESET_SYSTEM | ||
| 4486 | MOV CX,OFFSET RESET_INCLUDE - OFFSET RESET_SYSTEM | ||
| 4487 | REP MOVSB | ||
| 4488 | ; | ||
| 4489 | ; Check for presence of Above board memory manager | ||
| 4490 | ; | ||
| 4491 | MOV AX,(Get_Interrupt_Vector SHL 8) OR 67H | ||
| 4492 | INT 21H | ||
| 4493 | MOV DI,SDEVNAME | ||
| 4494 | MOV SI,OFFSET ABOVE_DEV_NAME | ||
| 4495 | MOV CX,8 | ||
| 4496 | REPE CMPSB | ||
| 4497 | JZ GOT_MANAGER | ||
| 4498 | MOV DX,OFFSET NO_ABOVE | ||
| 4499 | ABOVE_ERR: | ||
| 4500 | CALL PRINT | ||
| 4501 | STC | ||
| 4502 | RET | ||
| 4503 | |||
| 4504 | GOT_MANAGER: | ||
| 4505 | ; | ||
| 4506 | ; Check memory status | ||
| 4507 | ; | ||
| 4508 | MOV CX,8000H | ||
| 4509 | STLOOP: | ||
| 4510 | MOV AH,ABOVE_STATUS | ||
| 4511 | INT 67H | ||
| 4512 | CMP AH,ABOVE_SUCCESSFUL | ||
| 4513 | JZ MEM_OK | ||
| 4514 | CMP AH,ABOVE_ERROR_BUSY | ||
| 4515 | LOOPZ STLOOP | ||
| 4516 | ST_ERR: | ||
| 4517 | MOV DX,OFFSET BAD_ABOVE | ||
| 4518 | JMP ABOVE_ERR | ||
| 4519 | |||
| 4520 | MEM_OK: | ||
| 4521 | ; | ||
| 4522 | ; Get base address of map region and set BASE_ADDR | ||
| 4523 | ; | ||
| 4524 | MOV AH,ABOVE_GET_SEG | ||
| 4525 | INT 67H | ||
| 4526 | CMP AH,ABOVE_ERROR_BUSY | ||
| 4527 | JZ MEM_OK | ||
| 4528 | CMP AH,ABOVE_SUCCESSFUL | ||
| 4529 | JNZ ST_ERR | ||
| 4530 | MOV WORD PTR [BASE_ADDR],0 | ||
| 4531 | MOV WORD PTR [BASE_ADDR + 2],BX | ||
| 4532 | ; | ||
| 4533 | ; Allocate drive memory | ||
| 4534 | ; | ||
| 4535 | GET_AVAIL: | ||
| 4536 | MOV AH,ABOVE_GET_FREE | ||
| 4537 | INT 67H | ||
| 4538 | CMP AH,ABOVE_ERROR_BUSY | ||
| 4539 | JZ GET_AVAIL | ||
| 4540 | CMP AH,ABOVE_SUCCESSFUL | ||
| 4541 | JNZ ST_ERR | ||
| 4542 | MOV AX,DX ; AX is total 16K pages | ||
| 4543 | ; BX is un-allocated 16K pages | ||
| 4544 | MOV DX,OFFSET NO_MEM | ||
| 4545 | OR AX,AX | ||
| 4546 | JZ ABOVE_ERR | ||
| 4547 | MOV DX,OFFSET ERRMSG2 | ||
| 4548 | OR BX,BX ; 16k is min Ramdrive | ||
| 4549 | JZ ABOVE_ERR | ||
| 4550 | TEST BX,0F000H | ||
| 4551 | JNZ AB001 ; Avialable K is REAL big | ||
| 4552 | MOV CX,4 | ||
| 4553 | SHL BX,CL ; BX is un-allocated K | ||
| 4554 | CMP [DEV_SIZE],BX | ||
| 4555 | JBE AB001 ; DEV_SIZE OK | ||
| 4556 | MOV [DEV_SIZE],BX ; Limit DEV_SIZE to available | ||
| 4557 | AB001: | ||
| 4558 | MOV BX,[DEV_SIZE] | ||
| 4559 | ; | ||
| 4560 | ; BX is K we want to allocate (limited by available K) | ||
| 4561 | ; BX is at least 16 | ||
| 4562 | ; | ||
| 4563 | MOV AX,BX | ||
| 4564 | MOV CX,4 ; Convert back to # of 16K pages | ||
| 4565 | SHR BX,CL | ||
| 4566 | TEST AX,0FH ; Even???? | ||
| 4567 | JZ OKAYU ; Yes | ||
| 4568 | INC BX ; Gotta round up | ||
| 4569 | PUSH BX | ||
| 4570 | MOV CX,4 | ||
| 4571 | SHL BX,CL | ||
| 4572 | MOV [DEV_SIZE],BX ; Correct dev size too by rounding it up to | ||
| 4573 | ; next multiple of 16K, no sense wasting | ||
| 4574 | ; part of a page. | ||
| 4575 | POP BX | ||
| 4576 | OKAYU: | ||
| 4577 | MOV AH,ABOVE_ALLOC | ||
| 4578 | INT 67H | ||
| 4579 | CMP AH,ABOVE_ERROR_BUSY | ||
| 4580 | JZ OKAYU | ||
| 4581 | CMP AH,ABOVE_SUCCESSFUL | ||
| 4582 | JZ GOT_ID | ||
| 4583 | CMP AH,ABOVE_ERROR_MAP_CNTXT | ||
| 4584 | JZ ST_ERRJ | ||
| 4585 | CMP AH,ABOVE_ERROR_OUT_OF_PIDS | ||
| 4586 | JB ST_ERRJ | ||
| 4587 | MOV DX,OFFSET ERRMSG2 | ||
| 4588 | JMP ABOVE_ERR | ||
| 4589 | |||
| 4590 | ST_ERRJ: | ||
| 4591 | JMP ST_ERR | ||
| 4592 | |||
| 4593 | GOT_ID: | ||
| 4594 | MOV [ABOVE_PID],DX | ||
| 4595 | ; | ||
| 4596 | ; INSTALL ABOVE RESET handler | ||
| 4597 | ; | ||
| 4598 | XOR BX,BX | ||
| 4599 | CALL SET_RESET | ||
| 4600 | ; | ||
| 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 | ||
| 4603 | ; | ||
| 4604 | MOV WORD PTR [TERM_ADDR],OFFSET RESET_SYSTEM + (OFFSET ABOVE_RESET_END - OFFSET ABOVE_RESET) | ||
| 4605 | ; | ||
| 4606 | ; We are now in good shape. Can call BLKMOV to read drive | ||
| 4607 | ; | ||
| 4608 | CALL CHECK_DOS_VOL ; Snoop for DOS volume | ||
| 4609 | JNC DOUBLE_CHECK | ||
| 4610 | CALL DISK_ABORT | ||
| 4611 | STC | ||
| 4612 | RET | ||
| 4613 | |||
| 4614 | DOUBLE_CHECK: | ||
| 4615 | CMP [INIT_DRIVE],0 | ||
| 4616 | JNZ RETAB ; No DOS volume found | ||
| 4617 | ; | ||
| 4618 | ; We MUST check to see if the FOUND DOS volume is consistent | ||
| 4619 | ; with DEV_SIZE. | ||
| 4620 | ; | ||
| 4621 | MOV AX,[SECLIM] | ||
| 4622 | MUL [SSIZE] ; DX:AX is size of volume in bytes | ||
| 4623 | MOV CX,1024 | ||
| 4624 | DIV CX ; AX is size in K | ||
| 4625 | CMP AX,[DEV_SIZE] | ||
| 4626 | JE RETAB ; Volume is OK | ||
| 4627 | RE_INIT: | ||
| 4628 | MOV [INIT_DRIVE],2 ; Force re-compute of volume | ||
| 4629 | RETAB: | ||
| 4630 | CLC | ||
| 4631 | RET | ||
| 4632 | |||
| 4633 | BREAK <Drive code for /A driver. Swapped in at BLKMOV> | ||
| 4634 | |||
| 4635 | ; | ||
| 4636 | ; This label defines the start of the code swapped in at DRIVE_CODE | ||
| 4637 | ; | ||
| 4638 | ABOVE_CODE LABEL WORD | ||
| 4639 | |||
| 4640 | ; | ||
| 4641 | ; WARNING DANGER!!!!!!! | ||
| 4642 | ; | ||
| 4643 | ; This code is tranfered over the /E driver code at DRIVE_CODE | ||
| 4644 | ; | ||
| 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. | ||
| 4652 | |||
| 4653 | IF2 | ||
| 4654 | IF((OFFSET ABOVE_BLKMOV - OFFSET ABOVE_CODE) NE (OFFSET BLKMOV - OFFSET DRIVE_CODE)) | ||
| 4655 | %out ERROR BLKMOV, ABOVE_BLKMOV NOT ALIGNED | ||
| 4656 | ENDIF | ||
| 4657 | IF((OFFSET ABOVE_END - OFFSET ABOVE_CODE) GT (OFFSET DRIVE_END - OFFSET DRIVE_CODE)) | ||
| 4658 | %out ERROR ABOVE CODE TOO BIG | ||
| 4659 | ENDIF | ||
| 4660 | ENDIF | ||
| 4661 | |||
| 4662 | DD ? ; 24 bit address of start of this RAMDRV | ||
| 4663 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 4664 | ;** ABOVE_BLKMOV - Perform transfer for TYPE 2 driver | ||
| 4665 | ; | ||
| 4666 | ; This routine is the transfer routine for moving bytes | ||
| 4667 | ; to and from the Above Board memory containing the cache. | ||
| 4668 | ; | ||
| 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: | ||
| 4674 | ; | ||
| 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 | ; |------------|------------|------------|------------|------------| | ||
| 4679 | ; |---|---| | | | ||
| 4680 | ; | | |---------------- 64K bytes of sectors -------------| | ||
| 4681 | ; Byte | | | | ||
| 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 | ||
| 4694 | ; physical page | ||
| 4695 | ; 0 | ||
| 4696 | ; | ||
| 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 | ||
| 4700 | ; possible to map. | ||
| 4701 | ; | ||
| 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. | ||
| 4707 | ; | ||
| 4708 | ; SEE ALSO | ||
| 4709 | ; INTEL Expanded Memory Manager Programming Specification | ||
| 4710 | ; | ||
| 4711 | ; ENTRY: | ||
| 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 | ||
| 4716 | ; | ||
| 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 | ||
| 4721 | ; | ||
| 4722 | ; EXIT: | ||
| 4723 | ; Carry Clear | ||
| 4724 | ; OK, operation performed successfully | ||
| 4725 | ; Carry Set | ||
| 4726 | ; Error during operation, AL is error number | ||
| 4727 | ; | ||
| 4728 | ; USES: | ||
| 4729 | ; ALL | ||
| 4730 | ; | ||
| 4731 | ; This routine is specific to TYPE 2 driver | ||
| 4732 | ; | ||
| 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 | ||
| 4736 | ; | ||
| 4737 | ; tonyg - above limitation removed - now handles 64kb transfers | ||
| 4738 | ; which can overlap the page frame | ||
| 4739 | ; | ||
| 4740 | above_blkmov: | ||
| 4741 | assume ds:ramcode,es:nothing,ss:nothing | ||
| 4742 | ; | ||
| 4743 | ; save mapping context and return with error if save fails | ||
| 4744 | ; | ||
| 4745 | save_mapping_context | ||
| 4746 | jnc ab_blk$1 | ||
| 4747 | ret | ||
| 4748 | ; | ||
| 4749 | ; find logical page number, offset of i/o in first page | ||
| 4750 | ; | ||
| 4751 | ab_blk$1: | ||
| 4752 | push cx | ||
| 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 | ||
| 4758 | pop cx | ||
| 4759 | ; | ||
| 4760 | ; find case and dispatch accordingly | ||
| 4761 | ; | ||
| 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 | ||
| 4765 | ; | ||
| 4766 | push bx | ||
| 4767 | push cx | ||
| 4768 | ; | ||
| 4769 | ; if( final_user_off < pm_base_addr ) then case 0 | ||
| 4770 | ; | ||
| 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 | ||
| 4777 | shr ax,1 ; | ||
| 4778 | shr ax,1 ; | ||
| 4779 | mov bx,es ; get segment of buffer | ||
| 4780 | add ax,bx ; now we have the last segment of the user buffer | ||
| 4781 | ; with offset < 16 | ||
| 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 | ||
| 4784 | ; | ||
| 4785 | ; if( initial_user_off < pm_base_addr ) then case 2 | ||
| 4786 | ; | ||
| 4787 | mov cx,4 | ||
| 4788 | mov bp,di ; get initial segment in bp | ||
| 4789 | shr bp,cl ; | ||
| 4790 | add bp,bx ; | ||
| 4791 | sub bp,word ptr [base_addr +2] | ||
| 4792 | jc within_pm ; case 2 | ||
| 4793 | ; | ||
| 4794 | ; if ( initial_user_off >= pm_end_addr ) then case1 | ||
| 4795 | ; | ||
| 4796 | cmp bp,4*1024 ; | ||
| 4797 | jae aar_cd ; case 1 | ||
| 4798 | ; | ||
| 4799 | ; case 2 | ||
| 4800 | ; | ||
| 4801 | within_pm: jmp new_code ; user buffer in page map | ||
| 4802 | ; so we need to execute new code | ||
| 4803 | aar_cd: | ||
| 4804 | pop cx | ||
| 4805 | pop bx | ||
| 4806 | ; | ||
| 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 | ||
| 4814 | ; executed. | ||
| 4815 | ; | ||
| 4816 | ; METHOD: | ||
| 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 | ||
| 4820 | ; of the I/O. | ||
| 4821 | ; Set appropriate seg and index registers and CX to perform the | ||
| 4822 | ; main piece of the I/O into the page window | ||
| 4823 | ; REP MOVSW | ||
| 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 | ||
| 4828 | ; REP MOVSW | ||
| 4829 | ; Restore Above Board page mapping context | ||
| 4830 | ; | ||
| 4831 | XOR BP,BP ; No tail page | ||
| 4832 | PUSH BX | ||
| 4833 | ; | ||
| 4834 | ; DX is first page #, SI is byte offset of start of I/O in first page | ||
| 4835 | ; | ||
| 4836 | MOV AX,DX | ||
| 4837 | MOV BX,SI | ||
| 4838 | SHR BX,1 ; # Words in first 16k page which are not part | ||
| 4839 | ; of I/O | ||
| 4840 | PUSH CX | ||
| 4841 | ADD BX,CX ; # of words we need to map to perform I/O | ||
| 4842 | MOV DX,BX | ||
| 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? | ||
| 4848 | JZ NO_REM | ||
| 4849 | INC BX ; Need one more page | ||
| 4850 | NO_REM: | ||
| 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 | ||
| 4854 | JBE NO_TAIL | ||
| 4855 | MOV BP,DX ; Words to move in tail page saved in BP | ||
| 4856 | DEC CX ; Need second map for the 5th page | ||
| 4857 | POP AX | ||
| 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 | ||
| 4861 | NO_TAIL: | ||
| 4862 | ; Map CX pages | ||
| 4863 | MOV DX,[ABOVE_PID] | ||
| 4864 | MOV AX,ABOVE_MAP SHL 8 ; Physical page 0 | ||
| 4865 | PUSH AX | ||
| 4866 | MAP_NEXT: | ||
| 4867 | POP AX ; Recover correct AX register | ||
| 4868 | PUSH AX | ||
| 4869 | PUSH BX | ||
| 4870 | PUSH DX | ||
| 4871 | INT 67H ; Damn call ABOVE_MAP zaps BX,DX,AX | ||
| 4872 | POP DX | ||
| 4873 | POP BX | ||
| 4874 | OR AH,AH | ||
| 4875 | JNZ MAP_ERR1 ; error | ||
| 4876 | IF2 | ||
| 4877 | IF (ABOVE_SUCCESSFUL) | ||
| 4878 | %out ASSUMPTION IN CODE THAT ABOVE_SUCCESSFUL = 0 IS INVALID | ||
| 4879 | ENDIF | ||
| 4880 | ENDIF | ||
| 4881 | NEXT_PAGE: | ||
| 4882 | INC BX ; Next logical page | ||
| 4883 | POP AX | ||
| 4884 | INC AL ; Next physical page | ||
| 4885 | PUSH AX | ||
| 4886 | LOOP MAP_NEXT | ||
| 4887 | POP AX ; Clean stack | ||
| 4888 | POP CX ; Word count for first page mapping | ||
| 4889 | POP AX ; Operation in AH | ||
| 4890 | ; | ||
| 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 | ||
| 4896 | ; | ||
| 4897 | PUSH AX ; Save op for possible second I/O | ||
| 4898 | OR AH,AH | ||
| 4899 | JZ READ_A | ||
| 4900 | ; | ||
| 4901 | ; WRITE | ||
| 4902 | ; | ||
| 4903 | PUSH ES | ||
| 4904 | PUSH DI | ||
| 4905 | MOV DI,SI ; Start page offset to DI | ||
| 4906 | POP SI ; DS:SI is transfer addr | ||
| 4907 | POP DS | ||
| 4908 | ASSUME DS:NOTHING | ||
| 4909 | MOV ES,WORD PTR [BASE_ADDR + 2] ; ES:DI -> start | ||
| 4910 | JMP SHORT FIRST_MOVE | ||
| 4911 | |||
| 4912 | READ_A: | ||
| 4913 | ASSUME DS:ramcode | ||
| 4914 | MOV DS,WORD PTR [BASE_ADDR + 2] ; DS:SI -> start | ||
| 4915 | ASSUME DS:NOTHING | ||
| 4916 | FIRST_MOVE: | ||
| 4917 | REP MOVSW | ||
| 4918 | OR BP,BP ; Tail? | ||
| 4919 | JNZ TAIL_IO ; Yup | ||
| 4920 | ALL_DONE: | ||
| 4921 | POP AX | ||
| 4922 | CLC | ||
| 4923 | REST_CONT: | ||
| 4924 | ; Restore page mapping context | ||
| 4925 | PUSH AX ; Save possible error code | ||
| 4926 | PUSHF ; And carry state | ||
| 4927 | REST_AGN: | ||
| 4928 | MOV DX,[ABOVE_PID] | ||
| 4929 | MOV AH,ABOVE_RESTORE_MAP_PID | ||
| 4930 | INT 67H | ||
| 4931 | OR AH,AH | ||
| 4932 | JZ ROK | ||
| 4933 | IF2 | ||
| 4934 | IF (ABOVE_SUCCESSFUL) | ||
| 4935 | %out ASSUMPTION IN CODE THAT ABOVE_SUCCESSFUL = 0 IS INVALID | ||
| 4936 | ENDIF | ||
| 4937 | ENDIF | ||
| 4938 | CMP AH,ABOVE_ERROR_BUSY | ||
| 4939 | JZ REST_AGN | ||
| 4940 | CMP AH,ABOVE_ERROR_NO_CNTXT | ||
| 4941 | JZ ROK ; Ignore the invalid PID error | ||
| 4942 | POP DX | ||
| 4943 | POP DX ; Clean stack | ||
| 4944 | MOV AL,0cH ; General failure | ||
| 4945 | STC | ||
| 4946 | RET | ||
| 4947 | |||
| 4948 | ROK: | ||
| 4949 | POPF ; Recover carry state | ||
| 4950 | POP AX ; and possible error code | ||
| 4951 | RET | ||
| 4952 | |||
| 4953 | TAIL_IO: | ||
| 4954 | MOV DX,[ABOVE_PID] | ||
| 4955 | MAP_AGN: | ||
| 4956 | MOV AX,ABOVE_MAP SHL 8 ; map logical page BX to phys page 0 | ||
| 4957 | PUSH BX | ||
| 4958 | PUSH DX | ||
| 4959 | INT 67H ; Damn call ABOVE_MAP zaps BX,DX,AX | ||
| 4960 | POP DX | ||
| 4961 | POP BX | ||
| 4962 | OR AH,AH | ||
| 4963 | JNZ MAP_ERR2 ; Error | ||
| 4964 | IF2 | ||
| 4965 | IF (ABOVE_SUCCESSFUL) | ||
| 4966 | %out ASSUMPTION IN CODE THAT ABOVE_SUCCESSFUL = 0 IS INVALID | ||
| 4967 | ENDIF | ||
| 4968 | ENDIF | ||
| 4969 | SECOND_MOVE: | ||
| 4970 | POP AX ; Recover Op type | ||
| 4971 | PUSH AX | ||
| 4972 | OR AH,AH | ||
| 4973 | JZ READ_SEC | ||
| 4974 | ; | ||
| 4975 | ; WRITE | ||
| 4976 | ; | ||
| 4977 | XOR DI,DI ; ES:DI -> start of tail | ||
| 4978 | JMP SHORT SMOVE | ||
| 4979 | |||
| 4980 | READ_SEC: | ||
| 4981 | XOR SI,SI ; DS:SI -> start of tail | ||
| 4982 | SMOVE: | ||
| 4983 | MOV CX,BP | ||
| 4984 | REP MOVSW | ||
| 4985 | JMP ALL_DONE | ||
| 4986 | |||
| 4987 | MAP_ERR1: | ||
| 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 | ||
| 4991 | JMP SHORT DNR_ERR | ||
| 4992 | |||
| 4993 | MAP_ERR2: | ||
| 4994 | CMP AH,ABOVE_ERROR_BUSY | ||
| 4995 | JZ MAP_AGN | ||
| 4996 | ADD SP,2 | ||
| 4997 | DNR_ERR: | ||
| 4998 | MOV AL,02H ; Drive not ready | ||
| 4999 | STC | ||
| 5000 | JMP REST_CONT | ||
| 5001 | ; | ||
| 5002 | ; | ||
| 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 | ||
| 5009 | ; | ||
| 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 | ||
| 5012 | |||
| 5013 | |||
| 5014 | ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 5015 | ; the algorithm is: | ||
| 5016 | ; ****************************************************** | ||
| 5017 | ; [STEP1: determine the page we can use for the cache] | ||
| 5018 | ; | ||
| 5019 | ; if (initial_para_offset_user in page 1, 2 or 3 ) then { | ||
| 5020 | ; physical_cache_page = 0; | ||
| 5021 | ; cache_segment = above board segment; | ||
| 5022 | ; } | ||
| 5023 | ; else { | ||
| 5024 | ; physical_cache_page = 3; | ||
| 5025 | ; cache_segment = above_board_segment + 3*1024; | ||
| 5026 | ; } | ||
| 5027 | ; | ||
| 5028 | ; ****************************************************** | ||
| 5029 | ; [STEP2: initial setup] | ||
| 5030 | ; | ||
| 5031 | ; count = user_count_requested; | ||
| 5032 | ; number_to_be_transferred = min ( count, (16K - si) >> 2 ); | ||
| 5033 | ; exchange source and destination if necessary; | ||
| 5034 | ; | ||
| 5035 | ; ******************************************************* | ||
| 5036 | ; [STEP3: set up transfer and do it] | ||
| 5037 | ; | ||
| 5038 | ; count = count - number_to_be_transferred; | ||
| 5039 | ; map_page cache_handle,physical_cache_page,logical_cache_page | ||
| 5040 | ; mov data | ||
| 5041 | ; | ||
| 5042 | ; ******************************************************* | ||
| 5043 | ; [STEP4: determine if another transfer needed and setup if so] | ||
| 5044 | ; | ||
| 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++ ; | ||
| 5050 | ; | ||
| 5051 | ; ******************************************************* | ||
| 5052 | ; [STEP5: go to do next block] | ||
| 5053 | ; | ||
| 5054 | ; goto [STEP3] | ||
| 5055 | ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 5056 | ; | ||
| 5057 | new_code: | ||
| 5058 | assume ds:ramcode,es:nothing,ss:nothing | ||
| 5059 | ; | ||
| 5060 | ; input parameters: | ||
| 5061 | ; | ||
| 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 | ||
| 5068 | ; | ||
| 5069 | ; on stack { cx,bx } where cx = number of words, bx = read / write status | ||
| 5070 | ; | ||
| 5071 | ; [STEP1: finding physical cache page and page frame] | ||
| 5072 | ; | ||
| 5073 | ; | ||
| 5074 | ; assume is physical page 0 | ||
| 5075 | ; | ||
| 5076 | xor al, al ; use page 0 for cache | ||
| 5077 | mov bx,word ptr [base_addr+2] | ||
| 5078 | ; | ||
| 5079 | ; see if this assumption valid | ||
| 5080 | ; | ||
| 5081 | cmp bp, 4*1024 ; base is below start of page frame | ||
| 5082 | jae ab$300 | ||
| 5083 | cmp bp,1024 ; is initial in page 1 or above | ||
| 5084 | jae ab$30 ; if so or assumption is valid | ||
| 5085 | ; | ||
| 5086 | ; else we have to correct our assumption | ||
| 5087 | ; | ||
| 5088 | ab$300: | ||
| 5089 | mov al, 3 ; use page 3 for cache | ||
| 5090 | add bx, 3*1024 ; segment of page 3 | ||
| 5091 | ; | ||
| 5092 | ; initialise page frame segment | ||
| 5093 | ; | ||
| 5094 | ab$30: | ||
| 5095 | add bp, 2*1024 ; base of second transfer | ||
| 5096 | mov cx, bp | ||
| 5097 | mov ds,bx | ||
| 5098 | ; | ||
| 5099 | assume ds:nothing | ||
| 5100 | ; | ||
| 5101 | ; [STEP2: initialising transfer parameters] | ||
| 5102 | ; | ||
| 5103 | ; | ||
| 5104 | pop bp ; bp will have count of words left to be transferred | ||
| 5105 | pop bx ; read / write status | ||
| 5106 | ; | ||
| 5107 | ; kludged to handle 64k byte transfers | ||
| 5108 | ; | ||
| 5109 | push cx ; base of second transfer | ||
| 5110 | ; | ||
| 5111 | ; initialise the number of words needed for a second transfer to 0 | ||
| 5112 | ; | ||
| 5113 | xor cx,cx ; | ||
| 5114 | ; | ||
| 5115 | ; compare the number to be transferred to 16k words. any more than this | ||
| 5116 | ; will have to be done in the second transfer | ||
| 5117 | ; | ||
| 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 | ||
| 5122 | sub cx,bp ; | ||
| 5123 | ab$301: | ||
| 5124 | ; | ||
| 5125 | ; store this on stack | ||
| 5126 | ; | ||
| 5127 | push cx | ||
| 5128 | ; | ||
| 5129 | ; end of kludge in step 2 | ||
| 5130 | ; | ||
| 5131 | push bx ; save it back again | ||
| 5132 | push dx ; save this too | ||
| 5133 | ; | ||
| 5134 | ; initially si offset into logical page, so we can only do 16*1024 - si | ||
| 5135 | ; byte transfer | ||
| 5136 | ; | ||
| 5137 | mov cx,16*1024 | ||
| 5138 | sub cx,si | ||
| 5139 | shr cx,1 ; convert to word count | ||
| 5140 | ; | ||
| 5141 | ; number to be transferred is the minimum of this and the user requested | ||
| 5142 | ; count | ||
| 5143 | ; | ||
| 5144 | cmp cx,bp | ||
| 5145 | jb ab$31 | ||
| 5146 | mov cx,bp | ||
| 5147 | ; | ||
| 5148 | ab$31: | ||
| 5149 | ; | ||
| 5150 | ; see if write, then we have to switch source with destination | ||
| 5151 | ; | ||
| 5152 | or bh,bh | ||
| 5153 | je ab$32 ; if read we don't have to do anything | ||
| 5154 | ; else we have to switch | ||
| 5155 | src_dest_switch | ||
| 5156 | ab$32: | ||
| 5157 | ; | ||
| 5158 | ; set direction flag so that we don't have to do it repeatedly | ||
| 5159 | ; | ||
| 5160 | cld | ||
| 5161 | ; | ||
| 5162 | ; [STEP3: set up transfer and do it] | ||
| 5163 | ; | ||
| 5164 | ab$33: | ||
| 5165 | ; | ||
| 5166 | ; update count of words still left to be transferred after this | ||
| 5167 | ; | ||
| 5168 | sub bp,cx | ||
| 5169 | ; | ||
| 5170 | ; map the logical page in cache to the physical page selected | ||
| 5171 | ; | ||
| 5172 | mov bx,dx ; get logical page into bx | ||
| 5173 | ; al already holds the physical page # | ||
| 5174 | map_page | ||
| 5175 | jnc ab$34 ; suceeded ? | ||
| 5176 | ; | ||
| 5177 | ; else report error | ||
| 5178 | ; | ||
| 5179 | add sp,6 | ||
| 5180 | stc | ||
| 5181 | jmp restore_mp ; and go to restore page map | ||
| 5182 | ab$34: | ||
| 5183 | ; | ||
| 5184 | ; succeeded, do the transfer | ||
| 5185 | ; | ||
| 5186 | rep movsw | ||
| 5187 | ; | ||
| 5188 | ; | ||
| 5189 | ; [STEP4: check if transfer done, if not set up for next block] | ||
| 5190 | ; [STEP5: go back to STEP3] | ||
| 5191 | ; | ||
| 5192 | ; check if done | ||
| 5193 | ; | ||
| 5194 | or bp,bp ; count 0 | ||
| 5195 | je ab$40 ; yes, go to finish up | ||
| 5196 | ; | ||
| 5197 | ; recover original dx and bx, increment dx and then save both again | ||
| 5198 | ; | ||
| 5199 | pop dx | ||
| 5200 | pop bx | ||
| 5201 | inc dx | ||
| 5202 | push bx | ||
| 5203 | push dx | ||
| 5204 | ; | ||
| 5205 | ; words to be transferred minimum of count and 8*1024 words | ||
| 5206 | ; | ||
| 5207 | mov cx,8*1024 ; 8k words in a page | ||
| 5208 | cmp cx,bp ; | ||
| 5209 | jbe ab$35 ; if below or equal this is what we want | ||
| 5210 | ; | ||
| 5211 | mov cx,bp ; else we can transfer the whole count | ||
| 5212 | ab$35: | ||
| 5213 | ; | ||
| 5214 | ; see whether cache src or dest and accordingly reset either si or di | ||
| 5215 | ; | ||
| 5216 | or bh,bh ; read? | ||
| 5217 | jne ab$36 ; if write go to modify | ||
| 5218 | ; | ||
| 5219 | ; read, zero si and go back to step3 | ||
| 5220 | ; | ||
| 5221 | xor si,si | ||
| 5222 | jmp short ab$33 ; to step 3 | ||
| 5223 | ab$36: | ||
| 5224 | ; | ||
| 5225 | ; write, zero di and go back to step3 | ||
| 5226 | ; | ||
| 5227 | xor di,di | ||
| 5228 | jmp short ab$33 ; to step 3 | ||
| 5229 | ; | ||
| 5230 | ; finishing up we have to restore the page map | ||
| 5231 | ; | ||
| 5232 | ab$40: | ||
| 5233 | ; | ||
| 5234 | ; also kludged to handle 64k byte transfers | ||
| 5235 | ; | ||
| 5236 | pop dx | ||
| 5237 | pop bx | ||
| 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 | ||
| 5245 | xor cx, cx | ||
| 5246 | push cx ; zero count for next time | ||
| 5247 | ; | ||
| 5248 | ; restore the mapping context | ||
| 5249 | ; | ||
| 5250 | clc | ||
| 5251 | push dx ; dx is destroyed by restore mapping context | ||
| 5252 | restore_mapping_context | ||
| 5253 | pop dx ; | ||
| 5254 | jnc ab$401 | ||
| 5255 | ; | ||
| 5256 | ; error we should quit here | ||
| 5257 | ; | ||
| 5258 | add sp, 4 ; throw base & count | ||
| 5259 | ret | ||
| 5260 | ; | ||
| 5261 | ; we need to save the mapping context again | ||
| 5262 | ; | ||
| 5263 | ab$401: | ||
| 5264 | save_mapping_context | ||
| 5265 | jnc ab$406 ; if we couldn't save it then error | ||
| 5266 | add sp, 4 | ||
| 5267 | ret | ||
| 5268 | ; | ||
| 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) | ||
| 5271 | ; | ||
| 5272 | ab$406: | ||
| 5273 | mov cx, word ptr [base_addr+2] | ||
| 5274 | cmp ax, 1024 ; new base in page 0? | ||
| 5275 | jb ab$4060 | ||
| 5276 | cmp ax, 4*1024 | ||
| 5277 | jae ab$4060 | ||
| 5278 | xor ax, ax | ||
| 5279 | jmp short ab$4061 | ||
| 5280 | ab$4060: | ||
| 5281 | mov al, 3 | ||
| 5282 | add cx, 3*1024 | ||
| 5283 | ab$4061: | ||
| 5284 | or bh,bh ; read or write? | ||
| 5285 | jne ab$402 ; if write branch | ||
| 5286 | ; | ||
| 5287 | ; | ||
| 5288 | ; read, reset ds to base address | ||
| 5289 | ; | ||
| 5290 | mov ds,cx | ||
| 5291 | mov cx,16*1024 ; | ||
| 5292 | cmp si, cx ; at end of page? | ||
| 5293 | jbe ab$4030 | ||
| 5294 | inc dx | ||
| 5295 | xor si, si | ||
| 5296 | ab$4030: | ||
| 5297 | sub cx,si | ||
| 5298 | shr cx,1 | ||
| 5299 | |||
| 5300 | ab$403: | ||
| 5301 | push bx ; save these | ||
| 5302 | push dx | ||
| 5303 | ; | ||
| 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 | ||
| 5307 | ab$404: | ||
| 5308 | jmp ab$33 ; and go to do transfer | ||
| 5309 | ; | ||
| 5310 | ab$402: | ||
| 5311 | ; | ||
| 5312 | ; write, reset es to base address | ||
| 5313 | ; | ||
| 5314 | mov es,cx | ||
| 5315 | mov cx,16*1024 | ||
| 5316 | cmp di, cx | ||
| 5317 | jb ab$4020 | ||
| 5318 | xor di, di | ||
| 5319 | inc dx | ||
| 5320 | ab$4020: | ||
| 5321 | sub cx,di | ||
| 5322 | shr cx,1 | ||
| 5323 | jmp short ab$403 | ||
| 5324 | ; | ||
| 5325 | ; add sp,4 | ||
| 5326 | ab$405: | ||
| 5327 | clc | ||
| 5328 | restore_mp: | ||
| 5329 | restore_mapping_context | ||
| 5330 | ret | ||
| 5331 | |||
| 5332 | DW ? ; SPACE for ABOVE_PID | ||
| 5333 | |||
| 5334 | ; | ||
| 5335 | ; This label defines the end of the code swapped in at DRIVE_CODE | ||
| 5336 | ; | ||
| 5337 | ABOVE_END LABEL WORD | ||
| 5338 | |||
| 5339 | BREAK <Drive code for /A driver. Swapped in at RESET_SYSTEM> | ||
| 5340 | |||
| 5341 | |||
| 5342 | ; | ||
| 5343 | ; WARNING DANGER!!!!!!! | ||
| 5344 | ; | ||
| 5345 | ; This code is tranfered over the /E driver code at RESET_SYSTEM | ||
| 5346 | ; | ||
| 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. | ||
| 5352 | ; | ||
| 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. | ||
| 5356 | ; | ||
| 5357 | |||
| 5358 | IF2 | ||
| 5359 | IF((OFFSET ABOVE_RESET_END - OFFSET ABOVE_RESET) GT (OFFSET RESET_INCLUDE - OFFSET RESET_SYSTEM)) | ||
| 5360 | %out ERROR ABOVE_RESET CODE TOO BIG | ||
| 5361 | ENDIF | ||
| 5362 | ENDIF | ||
| 5363 | |||
| 5364 | ;** ABOVE_RESET perform TYPE 2 (/A) driver specific reboot code | ||
| 5365 | ; | ||
| 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". | ||
| 5369 | ; | ||
| 5370 | ; ENTRY | ||
| 5371 | ; NONE | ||
| 5372 | ; EXIT | ||
| 5373 | ; NONE | ||
| 5374 | ; USES | ||
| 5375 | ; NONE | ||
| 5376 | ; | ||
| 5377 | ; This code is specific to TYPE 2 drivers | ||
| 5378 | ; | ||
| 5379 | |||
| 5380 | ABOVE_RESET: | ||
| 5381 | ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 5382 | PUSH AX | ||
| 5383 | PUSH DX | ||
| 5384 | AGAIN_RESET: | ||
| 5385 | MOV DX,[ABOVE_PID] | ||
| 5386 | MOV AH,ABOVE_DEALLOC ; Close PID | ||
| 5387 | INT 67H | ||
| 5388 | CMP AH,ABOVE_ERROR_BUSY | ||
| 5389 | JZ AGAIN_RESET | ||
| 5390 | POP DX | ||
| 5391 | POP AX | ||
| 5392 | RET | ||
| 5393 | |||
| 5394 | ; | ||
| 5395 | ; This label defines the end of the code swapped in at RESET_SYSTEM | ||
| 5396 | ; | ||
| 5397 | ABOVE_RESET_END LABEL BYTE | ||
| 5398 | |||
| 5399 | BREAK <RESMEM INIT Code> | ||
| 5400 | |||
| 5401 | ;** RESMEM specific data | ||
| 5402 | ; | ||
| 5403 | ; The following datums are specific to the RESMEM (TYPE 3 | ||
| 5404 | ; or 4) drivers | ||
| 5405 | ; | ||
| 5406 | ; Specific to TYPE 3 or TYPE 4 drivers | ||
| 5407 | ; | ||
| 5408 | |||
| 5409 | HIGH_SEG DW ? ; Segment addr of "end of memory" from INT 12 | ||
| 5410 | |||
| 5411 | RAMSEG DW 0 ; Segment addr of the start of RAMDrive memory. | ||
| 5412 | ; Basically a segment register version of | ||
| 5413 | ; BASE_ADDR | ||
| 5414 | |||
| 5415 | CRTSEG EQU 0A000H ; Memory past this segment value is RESERVED | ||
| 5416 | ; Memory scan must stop here. | ||
| 5417 | |||
| 5418 | |||
| 5419 | ;** RESMEM_INIT - Perform RESMEM (TYPE 3 or 4) specific initialization | ||
| 5420 | ; | ||
| 5421 | ; This code performs the driver TYPE specific initialization for | ||
| 5422 | ; TYPE 3 and TYPE 4 drivers. | ||
| 5423 | ; | ||
| 5424 | ; Memory scan | ||
| 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. | ||
| 5440 | ; | ||
| 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. | ||
| 5444 | ; | ||
| 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 | ||
| 5450 | ; itself. | ||
| 5451 | ; | ||
| 5452 | ; The scan is NON-DESTRUCTIVE so that any data contained in | ||
| 5453 | ; the memory will not be destroyed. | ||
| 5454 | ; | ||
| 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. | ||
| 5458 | ; | ||
| 5459 | ; | ||
| 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 | ||
| 5467 | ; memory. | ||
| 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 | ||
| 5473 | ; the system. | ||
| 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 | ||
| 5488 | ; checking back on. | ||
| 5489 | ; IF we have valid RAM and end at HAVE_MEM | ||
| 5490 | ; We are TYPE 3. | ||
| 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 | ||
| 5504 | ; We are TYPE 4. | ||
| 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 | ||
| 5510 | ; BASE_ADDR. | ||
| 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 | ||
| 5519 | ; | ||
| 5520 | ; ENTRY: | ||
| 5521 | ; Invokation line parameter values set. | ||
| 5522 | ; EXIT: | ||
| 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 | ||
| 5526 | ; if TYPE 4. | ||
| 5527 | ; CARRY SET | ||
| 5528 | ; Error, message already printed. Driver not installed. | ||
| 5529 | ; If TYPE 3 | ||
| 5530 | ; EMM_CTRL not marked (but MAY be initialized if | ||
| 5531 | ; a valid one was not found). | ||
| 5532 | ; CARRY CLEAR | ||
| 5533 | ; DEV_SIZE set to TRUE size | ||
| 5534 | ; INIT_DRIVE set appropriatly | ||
| 5535 | ; IF TYPE 3 | ||
| 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. | ||
| 5543 | ; IF TYPE 4 | ||
| 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. | ||
| 5549 | ; | ||
| 5550 | ; USES: | ||
| 5551 | ; ALL but DS | ||
| 5552 | ; | ||
| 5553 | ; Code is specific to TYPE 3 and TYPE 4 drivers | ||
| 5554 | ; | ||
| 5555 | |||
| 5556 | RESMEM_INIT: | ||
| 5557 | ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 5558 | ; | ||
| 5559 | ; Swap RESMEM code into place | ||
| 5560 | ; | ||
| 5561 | PUSH CS | ||
| 5562 | POP ES | ||
| 5563 | MOV SI,OFFSET RESMEM_CODE | ||
| 5564 | MOV DI,OFFSET DRIVE_CODE | ||
| 5565 | MOV CX,OFFSET DRIVE_END - OFFSET DRIVE_CODE | ||
| 5566 | REP MOVSB | ||
| 5567 | MOV SI,OFFSET RESMEM_RESET | ||
| 5568 | MOV DI,OFFSET RESET_SYSTEM | ||
| 5569 | MOV CX,OFFSET RESET_INCLUDE - OFFSET RESET_SYSTEM | ||
| 5570 | REP MOVSB | ||
| 5571 | ; | ||
| 5572 | ; We have THREE cases to contend with: | ||
| 5573 | ; | ||
| 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 | ||
| 5579 | ; | ||
| 5580 | ; 2. There is memory immediately after the INT 12H memory size. | ||
| 5581 | ; We will check for a EMM_CTRL there etc. | ||
| 5582 | ; | ||
| 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. | ||
| 5586 | ; | ||
| 5587 | INT 12H ; Get size of memory set on switches | ||
| 5588 | |||
| 5589 | IF DEBUG | ||
| 5590 | |||
| 5591 | JMP SHORT DEB1 | ||
| 5592 | |||
| 5593 | DEB1MES DB 13,10,"INT 12 returned $" | ||
| 5594 | |||
| 5595 | DEB1: | ||
| 5596 | PUSH CX | ||
| 5597 | PUSH DX | ||
| 5598 | PUSHF | ||
| 5599 | PUSH AX | ||
| 5600 | MOV DX,OFFSET DEB1MES | ||
| 5601 | CALL PRINT | ||
| 5602 | POP AX | ||
| 5603 | PUSH AX | ||
| 5604 | CALL ITOA | ||
| 5605 | POP AX | ||
| 5606 | POPF | ||
| 5607 | POP DX | ||
| 5608 | POP CX | ||
| 5609 | ENDIF | ||
| 5610 | |||
| 5611 | MOV CL,6 | ||
| 5612 | SHL AX,CL ; Convert to Segment register value | ||
| 5613 | MOV BX,AX ; Save in BX | ||
| 5614 | MOV [HIGH_SEG],AX ; And here | ||
| 5615 | |||
| 5616 | ; | ||
| 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 | ||
| 5623 | ; | ||
| 5624 | ; **START OF CODE REMOVED | ||
| 5625 | ; | ||
| 5626 | ; | ||
| 5627 | ; CMP BX,CRTSEG | ||
| 5628 | ; | ||
| 5629 | ;IF DEBUG | ||
| 5630 | ; JB DEBX | ||
| 5631 | ; JMP CASE1 | ||
| 5632 | ;DEBX: | ||
| 5633 | ;ELSE | ||
| 5634 | ; JAE CASE1 ; No memory to scan | ||
| 5635 | ;ENDIF | ||
| 5636 | ; | ||
| 5637 | ; IN AL,61H | ||
| 5638 | ; OR AL,20H ; Turn off parity interrupt | ||
| 5639 | ; JMP FOO ; 286 back to back IN OUT bug fix | ||
| 5640 | ;FOO: OUT 61H,AL | ||
| 5641 | ; ; | ||
| 5642 | ; ; SCAN memory | ||
| 5643 | ; ; | ||
| 5644 | ; XOR DI,DI | ||
| 5645 | ; MOV SI,DI | ||
| 5646 | ; MOV ES,BX ;Segment to scan for valid memory | ||
| 5647 | ; MOV DS,BX | ||
| 5648 | ;ASSUME DS:NOTHING | ||
| 5649 | ; CALL TEST_RAM | ||
| 5650 | ; JNZ NO_RAM | ||
| 5651 | ; ; We have case 2 | ||
| 5652 | ;HAVE_START: | ||
| 5653 | ; XOR DX,DX ; DX = 0 means skipping memory | ||
| 5654 | ; MOV [RAMSEG],BX ; This is the start of our memory | ||
| 5655 | ; | ||
| 5656 | ;IF DEBUG | ||
| 5657 | ; | ||
| 5658 | ; JMP SHORT DEB2 | ||
| 5659 | ; | ||
| 5660 | ;DEB2MES DB 13,10,"CASE 1 Ramseg $" | ||
| 5661 | ; | ||
| 5662 | ;DEB2: | ||
| 5663 | ; PUSH CX | ||
| 5664 | ; PUSH DX | ||
| 5665 | ; PUSHF | ||
| 5666 | ; PUSH AX | ||
| 5667 | ; MOV DX,OFFSET DEB2MES | ||
| 5668 | ; CALL PRINT | ||
| 5669 | ; MOV AX,[RAMSEG] | ||
| 5670 | ; CALL ITOA | ||
| 5671 | ; POP AX | ||
| 5672 | ; POPF | ||
| 5673 | ; POP DX | ||
| 5674 | ; POP CX | ||
| 5675 | ;ENDIF | ||
| 5676 | ; | ||
| 5677 | ; JMP SHORT NEXT_K | ||
| 5678 | ; | ||
| 5679 | ;NO_RAM: | ||
| 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 | ||
| 5684 | ;HAVE_MEM: | ||
| 5685 | ; ; | ||
| 5686 | ; ; Driver is TYPE 3 | ||
| 5687 | ; ; | ||
| 5688 | ; SUB BX,[RAMSEG] ; BX is Para of RAMDRV region | ||
| 5689 | ; MOV CX,6 | ||
| 5690 | ; SHR BX,CL ; BX is K in region | ||
| 5691 | ; CMP BX,17 ; Ik EMM_CTRL, 16k min ramdrive | ||
| 5692 | ; | ||
| 5693 | ;IF DEBUG | ||
| 5694 | ; | ||
| 5695 | ; JMP SHORT DEB3 | ||
| 5696 | ; | ||
| 5697 | ;DEB3MESA DB 13,10,"CASE 3 Ramseg $" | ||
| 5698 | ;DEB3MESB DB " AVAIL K $" | ||
| 5699 | ; | ||
| 5700 | ;DEB3: | ||
| 5701 | ; PUSH CX | ||
| 5702 | ; PUSH DX | ||
| 5703 | ; PUSHF | ||
| 5704 | ; PUSH AX | ||
| 5705 | ; MOV DX,OFFSET DEB3MESA | ||
| 5706 | ; CALL PRINT | ||
| 5707 | ; MOV AX,[RAMSEG] | ||
| 5708 | ; CALL ITOA | ||
| 5709 | ; MOV DX,OFFSET DEB3MESB | ||
| 5710 | ; CALL PRINT | ||
| 5711 | ; MOV AX,BX | ||
| 5712 | ; CALL ITOA | ||
| 5713 | ; POP AX | ||
| 5714 | ; POPF | ||
| 5715 | ; POP DX | ||
| 5716 | ; POP CX | ||
| 5717 | ;ENDIF | ||
| 5718 | ; | ||
| 5719 | ; JB RES_NOMEMJ | ||
| 5720 | ; JMP GOT_RESMEM | ||
| 5721 | ; | ||
| 5722 | ;RES_NOMEMJ: | ||
| 5723 | ; JMP RES_NOMEM | ||
| 5724 | ; | ||
| 5725 | ;CONT_SCAN: | ||
| 5726 | ; XOR DI,DI | ||
| 5727 | ; MOV SI,DI | ||
| 5728 | ; MOV ES,BX ;Segment to scan for valid memory | ||
| 5729 | ; MOV DS,BX | ||
| 5730 | ; CALL TEST_RAM | ||
| 5731 | ; JNZ AT_DIS ;No, detected discontinuity | ||
| 5732 | ; OR DX,DX | ||
| 5733 | ; JZ NEXT_K | ||
| 5734 | ; JMP HAVE_START | ||
| 5735 | ; | ||
| 5736 | ;AT_DIS: | ||
| 5737 | ; OR DX,DX | ||
| 5738 | ; JZ NO_RAM | ||
| 5739 | ;NEXT_K: | ||
| 5740 | ; ADD BX,64 ; Next K | ||
| 5741 | ; CMP BX,CRTSEG | ||
| 5742 | ; JB CONT_SCAN | ||
| 5743 | ; CALL ENABLE_PARITY | ||
| 5744 | ; CMP [RAMSEG],0 | ||
| 5745 | ; JNZ HAVE_MEM | ||
| 5746 | ;***END OF CODE REMOVED*** | ||
| 5747 | ;***************************************************************************** | ||
| 5748 | CASE1: | ||
| 5749 | ; | ||
| 5750 | ; Have CASE 1. | ||
| 5751 | ; Driver is TYPE 4 | ||
| 5752 | ; | ||
| 5753 | |||
| 5754 | IF DEBUG | ||
| 5755 | |||
| 5756 | JMP SHORT DEB4 | ||
| 5757 | |||
| 5758 | DEB4MES DB 13,10,"CASE 1$" | ||
| 5759 | |||
| 5760 | DEB4: | ||
| 5761 | PUSH CX | ||
| 5762 | PUSH DX | ||
| 5763 | PUSHF | ||
| 5764 | PUSH AX | ||
| 5765 | MOV DX,OFFSET DEB4MES | ||
| 5766 | CALL PRINT | ||
| 5767 | POP AX | ||
| 5768 | POPF | ||
| 5769 | POP DX | ||
| 5770 | POP CX | ||
| 5771 | ENDIF | ||
| 5772 | |||
| 5773 | PUSH CS | ||
| 5774 | POP DS | ||
| 5775 | ASSUME DS:RAMCODE | ||
| 5776 | INC [RESMEM_SPECIAL] ; Flag SPECIAL case for INIDRV | ||
| 5777 | MOV [INIT_DRIVE],2 ; This type must ALWAYS be inited | ||
| 5778 | ; | ||
| 5779 | ; Compute BASE_ADDR to be right after DEVICE_END, NO INT 19/9 handler | ||
| 5780 | ; | ||
| 5781 | MOV AX,OFFSET DEVICE_END | ||
| 5782 | ADD AX,15 ; Para round up | ||
| 5783 | MOV CL,4 | ||
| 5784 | SHR AX,CL ; # of para in RAMDrive resident code | ||
| 5785 | MOV DX,CS | ||
| 5786 | ADD AX,DX ; AX is seg addr of start of RAMDrive | ||
| 5787 | PUSH AX | ||
| 5788 | MOV CX,16 | ||
| 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 | ||
| 5792 | POP AX | ||
| 5793 | ; | ||
| 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 | ||
| 5797 | ; | ||
| 5798 | MOV DX,[DEV_SIZE] ; Get size in K | ||
| 5799 | ; | ||
| 5800 | ; DEV_SIZE can be at most a 10 bit number as that is 1 Meg, the memory | ||
| 5801 | ; limit on the 8086 | ||
| 5802 | ; | ||
| 5803 | TEST DX,0FC00H ; If any of high 6 bits set, too big | ||
| 5804 | JNZ RES_NOMEM | ||
| 5805 | MOV CL,6 | ||
| 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 | ||
| 5809 | ; | ||
| 5810 | ; Make sure at least 48K left after device | ||
| 5811 | ; | ||
| 5812 | MOV DX,[HIGH_SEG] | ||
| 5813 | SUB DX,0C00H ; 48K worth of PARAs left for system | ||
| 5814 | |||
| 5815 | IF DEBUG | ||
| 5816 | |||
| 5817 | JMP SHORT DEB5 | ||
| 5818 | |||
| 5819 | DEB5MESA DB " Max end is $" | ||
| 5820 | DEB5MESB DB " end is $" | ||
| 5821 | |||
| 5822 | DEB5: | ||
| 5823 | PUSH CX | ||
| 5824 | PUSHF | ||
| 5825 | PUSH DX | ||
| 5826 | PUSH AX | ||
| 5827 | MOV DX,OFFSET DEB5MESA | ||
| 5828 | CALL PRINT | ||
| 5829 | POP DX | ||
| 5830 | POP AX | ||
| 5831 | PUSH AX | ||
| 5832 | PUSH DX | ||
| 5833 | CALL ITOA | ||
| 5834 | MOV DX,OFFSET DEB5MESB | ||
| 5835 | CALL PRINT | ||
| 5836 | POP AX | ||
| 5837 | PUSH AX | ||
| 5838 | CALL ITOA | ||
| 5839 | POP AX | ||
| 5840 | POP DX | ||
| 5841 | POPF | ||
| 5842 | POP CX | ||
| 5843 | ENDIF | ||
| 5844 | |||
| 5845 | JC RES_NOMEM | ||
| 5846 | CMP AX,DX | ||
| 5847 | JA RES_NOMEM ; Too big | ||
| 5848 | MOV WORD PTR [TERM_ADDR],0 | ||
| 5849 | MOV WORD PTR [TERM_ADDR + 2],AX | ||
| 5850 | |||
| 5851 | IF DEBUG | ||
| 5852 | |||
| 5853 | JMP SHORT DEB6 | ||
| 5854 | |||
| 5855 | DEB6MES DB " OK term $" | ||
| 5856 | |||
| 5857 | DEB6: | ||
| 5858 | PUSH CX | ||
| 5859 | PUSHF | ||
| 5860 | PUSH DX | ||
| 5861 | PUSH AX | ||
| 5862 | MOV DX,OFFSET DEB6MES | ||
| 5863 | CALL PRINT | ||
| 5864 | POP AX | ||
| 5865 | PUSH AX | ||
| 5866 | CALL ITOA | ||
| 5867 | POP AX | ||
| 5868 | POP DX | ||
| 5869 | POPF | ||
| 5870 | POP CX | ||
| 5871 | ENDIF | ||
| 5872 | CLC | ||
| 5873 | RET | ||
| 5874 | |||
| 5875 | RES_NOMEM: | ||
| 5876 | ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 5877 | MOV DX,OFFSET ERRMSG2 | ||
| 5878 | CALL PRINT | ||
| 5879 | PUSH CS | ||
| 5880 | POP DS | ||
| 5881 | STC | ||
| 5882 | RET | ||
| 5883 | |||
| 5884 | GOT_RESMEM: | ||
| 5885 | ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 5886 | ; | ||
| 5887 | ; Completion of TYPE 3 initialization. | ||
| 5888 | ; RAMSEG is start seg addr of ramdrv region, BX is its size in K | ||
| 5889 | ; | ||
| 5890 | PUSH CS | ||
| 5891 | POP DS | ||
| 5892 | ASSUME DS:RAMCODE | ||
| 5893 | MOV [EXT_K],BX | ||
| 5894 | DEC BX ; BX is MAX possible disk size | ||
| 5895 | CMP [DEV_SIZE],BX | ||
| 5896 | JBE RES002 ; DEV_SIZE is OK | ||
| 5897 | MOV [DEV_SIZE],BX ; Limit DEV_SIZE to available K | ||
| 5898 | RES002: | ||
| 5899 | MOV AX,[RAMSEG] | ||
| 5900 | MOV CX,16 | ||
| 5901 | MUL CX | ||
| 5902 | MOV WORD PTR [BASE_ADDR],AX | ||
| 5903 | MOV WORD PTR [BASE_ADDR + 2],DX | ||
| 5904 | ADD AX,1024 | ||
| 5905 | ADC DX,0 | ||
| 5906 | MOV WORD PTR [BASE_RESET],AX | ||
| 5907 | MOV WORD PTR [BASE_RESET + 2],DX | ||
| 5908 | CALL MM_SETDRIVE | ||
| 5909 | RET | ||
| 5910 | |||
| 5911 | |||
| 5912 | ;** ENABLE_PARITY - Turn on parity checking of IBM PC AT XT | ||
| 5913 | ; | ||
| 5914 | ; This routine enables the memory parity checking on an IBM PC | ||
| 5915 | ; family machine | ||
| 5916 | ; | ||
| 5917 | ; ENTRY NONE | ||
| 5918 | ; EXIT NONE | ||
| 5919 | ; USES AL | ||
| 5920 | ; | ||
| 5921 | ; SEE ALSO | ||
| 5922 | ; IBM PC Technical Reference manual for any PC family member | ||
| 5923 | ; | ||
| 5924 | ; Code is specific to TYPE 3 and TYPE 4 drivers | ||
| 5925 | ; | ||
| 5926 | |||
| 5927 | ENABLE_PARITY: | ||
| 5928 | ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 5929 | IN AL,61H | ||
| 5930 | AND AL,NOT 20H ;Re-enable parity checking | ||
| 5931 | JMP BAR ; 286 back to back IN OUT bug fix | ||
| 5932 | BAR: OUT 61H,AL | ||
| 5933 | RET | ||
| 5934 | |||
| 5935 | |||
| 5936 | ;** TEST_RAM - Check if valid RAM exists and reset parity if it does | ||
| 5937 | ; | ||
| 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 | ||
| 5941 | ; to itself. | ||
| 5942 | ; | ||
| 5943 | ; TESTS | ||
| 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. | ||
| 5950 | ; | ||
| 5951 | ; ENTRY | ||
| 5952 | ; DS:SI = ES:DI -> a 1k region of RAM to be tested | ||
| 5953 | ; PARITY CHECKING DISABLED | ||
| 5954 | ; EXIT | ||
| 5955 | ; Zero set if RAM is valid | ||
| 5956 | ; Zero reset if RAM is invalid | ||
| 5957 | ; USES | ||
| 5958 | ; AX, SI, DI | ||
| 5959 | ; | ||
| 5960 | ; Code is specific to TYPE 3 and TYPE 4 drivers | ||
| 5961 | ; | ||
| 5962 | |||
| 5963 | TEST_RAM: | ||
| 5964 | ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 5965 | LODSW ; See what's there | ||
| 5966 | NOT AX | ||
| 5967 | MOV [DI],AX ; See if memory can store complement | ||
| 5968 | CMP AX,[DI] ; Memory OK? | ||
| 5969 | JNZ RET007 ; Not valid RAM | ||
| 5970 | NOT AX | ||
| 5971 | STOSW ; Restore correct value | ||
| 5972 | CMP AX,[DI - 2] ; Memory OK? | ||
| 5973 | JNZ RET007 ; Not valid RAM | ||
| 5974 | LODSW ; Next word | ||
| 5975 | MOV WORD PTR [DI],"AR" ; Store fixed value | ||
| 5976 | NOP ; Wait | ||
| 5977 | NOP | ||
| 5978 | NOP | ||
| 5979 | NOP | ||
| 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 | ||
| 5984 | REP MOVSW | ||
| 5985 | RET007: | ||
| 5986 | RET | ||
| 5987 | |||
| 5988 | BREAK <Drive code for resmem driver. Swapped in at BLKMOV> | ||
| 5989 | |||
| 5990 | ; | ||
| 5991 | ; This label defines the start of the TYPE 3 and 4 code swapped | ||
| 5992 | ; in at BLKMOV | ||
| 5993 | ; | ||
| 5994 | RESMEM_CODE LABEL WORD | ||
| 5995 | |||
| 5996 | ; | ||
| 5997 | ; WARNING DANGER!!!!!!! | ||
| 5998 | ; | ||
| 5999 | ; This code is tranfered over the /E driver code at DRIVE_CODE | ||
| 6000 | ; | ||
| 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. | ||
| 6008 | |||
| 6009 | IF2 | ||
| 6010 | IF((OFFSET RESMEM_BLKMOV - OFFSET RESMEM_CODE) NE (OFFSET BLKMOV - OFFSET DRIVE_CODE)) | ||
| 6011 | %out ERROR BLKMOV, RESMEM_BLKMOV NOT ALIGNED | ||
| 6012 | ENDIF | ||
| 6013 | IF((OFFSET RESMEM_END - OFFSET RESMEM_CODE) GT (OFFSET DRIVE_END - OFFSET DRIVE_CODE)) | ||
| 6014 | %out ERROR RESMEM CODE TOO BIG | ||
| 6015 | ENDIF | ||
| 6016 | ENDIF | ||
| 6017 | |||
| 6018 | DD ? ; 24 bit address of start of this RAMDRV | ||
| 6019 | |||
| 6020 | ;** RESMEM_BLKMOV - Perform transfer for TYPE 3 and 4 driver | ||
| 6021 | ; | ||
| 6022 | ; This routine is the transfer routine for moving bytes | ||
| 6023 | ; to and from a RAMDrive located in main memory. | ||
| 6024 | ; | ||
| 6025 | ; METHOD: | ||
| 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 | ||
| 6029 | ; | ||
| 6030 | ; ENTRY: | ||
| 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 | ||
| 6035 | ; | ||
| 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 | ||
| 6040 | ; | ||
| 6041 | ; EXIT: | ||
| 6042 | ; Carry Clear | ||
| 6043 | ; OK, operation performed successfully | ||
| 6044 | ; Carry Set | ||
| 6045 | ; Error during operation, AL is error number | ||
| 6046 | ; | ||
| 6047 | ; USES: | ||
| 6048 | ; ALL | ||
| 6049 | ; | ||
| 6050 | ; This routine is specific to TYPE 3 and 4 drivers | ||
| 6051 | ; | ||
| 6052 | |||
| 6053 | RESMEM_BLKMOV: | ||
| 6054 | ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING | ||
| 6055 | |||
| 6056 | ADD AX,WORD PTR [BASE_ADDR] | ||
| 6057 | ADC DX,WORD PTR [BASE_ADDR + 2] | ||
| 6058 | PUSH CX | ||
| 6059 | MOV CX,16 | ||
| 6060 | DIV CX ; AX is seg reg value, DX is index register | ||
| 6061 | POP CX | ||
| 6062 | OR BH,BH | ||
| 6063 | JZ READ_ITR | ||
| 6064 | ; | ||
| 6065 | ; WRITE | ||
| 6066 | ; | ||
| 6067 | PUSH ES | ||
| 6068 | POP DS | ||
| 6069 | ASSUME DS:NOTHING | ||
| 6070 | MOV SI,DI | ||
| 6071 | MOV ES,AX | ||
| 6072 | MOV DI,DX | ||
| 6073 | TRANS: | ||
| 6074 | REP MOVSW | ||
| 6075 | CLC | ||
| 6076 | RET | ||
| 6077 | |||
| 6078 | READ_ITR: | ||
| 6079 | MOV DS,AX | ||
| 6080 | ASSUME DS:NOTHING | ||
| 6081 | MOV SI,DX | ||
| 6082 | JMP TRANS | ||
| 6083 | |||
| 6084 | ; | ||
| 6085 | ; This label defines the end of the RESMEM code swapped in at BLKMOV | ||
| 6086 | ; | ||
| 6087 | RESMEM_END LABEL WORD | ||
| 6088 | |||
| 6089 | BREAK <Drive code for resmem driver. Swapped in at RESET_SYSTEM> | ||
| 6090 | |||
| 6091 | |||
| 6092 | ; | ||
| 6093 | ; WARNING DANGER!!!!!!! | ||
| 6094 | ; | ||
| 6095 | ; This code is tranfered over the /E driver code at RESET_SYSTEM | ||
| 6096 | ; | ||
| 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. | ||
| 6102 | |||
| 6103 | IF2 | ||
| 6104 | IF((OFFSET RESMEM_RESET_END - OFFSET RESMEM_RESET) GT (OFFSET RESET_INCLUDE - OFFSET RESET_SYSTEM)) | ||
| 6105 | %out ERROR RESMEM_RESET CODE TOO BIG | ||
| 6106 | ENDIF | ||
| 6107 | ENDIF | ||
| 6108 | |||
| 6109 | ;** RESMEM_RESET perform TYPE 3 (RESMEM) driver specific reboot code | ||
| 6110 | ; | ||
| 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. | ||
| 6114 | ; | ||
| 6115 | ; ENTRY | ||
| 6116 | ; NONE | ||
| 6117 | ; EXIT | ||
| 6118 | ; NONE | ||
| 6119 | ; USES | ||
| 6120 | ; NONE | ||
| 6121 | ; | ||
| 6122 | ; This code is specific to TYPE 3 drivers | ||
| 6123 | ; | ||
| 6124 | |||
| 6125 | RESMEM_RESET: | ||
| 6126 | ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 6127 | PUSH SI | ||
| 6128 | PUSH DI | ||
| 6129 | PUSH AX | ||
| 6130 | PUSH BX | ||
| 6131 | PUSH CX | ||
| 6132 | PUSH DX | ||
| 6133 | PUSH DS | ||
| 6134 | PUSH ES | ||
| 6135 | PUSH CS | ||
| 6136 | POP DS | ||
| 6137 | ASSUME DS:RAMCODE | ||
| 6138 | MOV AX,WORD PTR [BASE_ADDR] | ||
| 6139 | MOV DX,WORD PTR [BASE_ADDR + 2] | ||
| 6140 | SUB AX,1024 ; Point back to EMM block | ||
| 6141 | SBB DX,0 | ||
| 6142 | ; | ||
| 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 | ||
| 6146 | ; | ||
| 6147 | MOV CX,16 | ||
| 6148 | DIV CX ; AX is seg reg, DX is index reg | ||
| 6149 | MOV DS,AX | ||
| 6150 | ASSUME DS:NOTHING | ||
| 6151 | MOV SI,DX ; DS:SI -> EMM_CTRL | ||
| 6152 | MOV DI,SI | ||
| 6153 | ADD DI,EMM_RECORD | ||
| 6154 | MOV CX,EMM_NUMREC | ||
| 6155 | LOOK_RECRY: | ||
| 6156 | ; | ||
| 6157 | ; Scan EMM_CTRL for all ISDRIVER MS-DOS regions and turn off ISDRIVER | ||
| 6158 | ; | ||
| 6159 | TEST [DI.EMM_FLAGS],EMM_ALLOC | ||
| 6160 | JZ DONERY | ||
| 6161 | TEST [DI.EMM_FLAGS],EMM_ISDRIVER | ||
| 6162 | JZ NEXTRECRY ; No Driver | ||
| 6163 | CMP [DI.EMM_SYSTEM],EMM_MSDOS | ||
| 6164 | JNZ NEXTRECRY | ||
| 6165 | AND [DI.EMM_FLAGS],NOT EMM_ISDRIVER | ||
| 6166 | NEXTRECRY: | ||
| 6167 | ADD DI,SIZE EMM_REC | ||
| 6168 | LOOP LOOK_RECRY | ||
| 6169 | DONERY: | ||
| 6170 | POP ES | ||
| 6171 | POP DS | ||
| 6172 | ASSUME DS:NOTHING | ||
| 6173 | POP DX | ||
| 6174 | POP CX | ||
| 6175 | POP BX | ||
| 6176 | POP AX | ||
| 6177 | POP DI | ||
| 6178 | POP SI | ||
| 6179 | RET | ||
| 6180 | |||
| 6181 | ; | ||
| 6182 | ; This label defines the end of the RESMEM code swapped in at RESET_SYSTEM | ||
| 6183 | ; | ||
| 6184 | RESMEM_RESET_END LABEL BYTE | ||
| 6185 | |||
| 6186 | BREAK <messages and common data> | ||
| 6187 | |||
| 6188 | ;** Message texts and common data | ||
| 6189 | ; | ||
| 6190 | ; Init data. This data is disposed of after initialization. | ||
| 6191 | ; it is mostly texts of all of the messages | ||
| 6192 | ; | ||
| 6193 | ; COMMON to TYPE 1,2,3 and 4 drivers | ||
| 6194 | ; | ||
| 6195 | ; | ||
| 6196 | ; translatable messages moved to message module (SP) | ||
| 6197 | |||
| 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." | ||
| 6205 | |||
| 6206 | VOLID DB 'MS-RAMDRIVE',ATTR_VOLUME_ID | ||
| 6207 | DB 10 DUP (0) | ||
| 6208 | DW 1100000000000000B ;12:00:00 | ||
| 6209 | DW 0000101011001001B ;JUN 9, 1985 | ||
| 6210 | DW 0,0,0 | ||
| 6211 | |||
| 6212 | SECTOR_BUFFER DB 1024 DUP(0) | ||
| 6213 | |||
| 6214 | RAMDrive_END LABEL BYTE | ||
| 6215 | |||
| 6216 | RAMCODE ENDS | ||
| 6217 | END | ||
| 6218 | \ No newline at end of file | ||
diff --git a/v4.0/src/DEV/RAMDRIVE/RAMDRIVE.LNK b/v4.0/src/DEV/RAMDRIVE/RAMDRIVE.LNK new file mode 100644 index 0000000..98a3458 --- /dev/null +++ b/v4.0/src/DEV/RAMDRIVE/RAMDRIVE.LNK | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | ramdrive messages | ||
| 2 | ramdrive.exe | ||
| 3 | ramdrive.map -map; | ||
diff --git a/v4.0/src/DEV/RAMDRIVE/SYSCALL.INC b/v4.0/src/DEV/RAMDRIVE/SYSCALL.INC new file mode 100644 index 0000000..9761b0c --- /dev/null +++ b/v4.0/src/DEV/RAMDRIVE/SYSCALL.INC | |||
| @@ -0,0 +1,146 @@ | |||
| 1 | BREAK <system call definitions> | ||
| 2 | |||
| 3 | Abort EQU 0 ; 0 0 | ||
| 4 | Std_Con_Input EQU 1 ; 1 1 | ||
| 5 | Std_Con_Output EQU 2 ; 2 2 | ||
| 6 | Std_Aux_Input EQU 3 ; 3 3 | ||
| 7 | Std_Aux_Output EQU 4 ; 4 4 | ||
| 8 | Std_Printer_Output EQU 5 ; 5 5 | ||
| 9 | Raw_Con_IO EQU 6 ; 6 6 | ||
| 10 | Raw_Con_Input EQU 7 ; 7 7 | ||
| 11 | Std_Con_Input_No_Echo EQU 8 ; 8 8 | ||
| 12 | Std_Con_String_Output EQU 9 ; 9 9 | ||
| 13 | Std_Con_String_Input EQU 10 ; 10 A | ||
| 14 | Std_Con_Input_Status EQU 11 ; 11 B | ||
| 15 | Std_Con_Input_Flush EQU 12 ; 12 C | ||
| 16 | Disk_Reset EQU 13 ; 13 D | ||
| 17 | Set_Default_Drive EQU 14 ; 14 E | ||
| 18 | FCB_Open EQU 15 ; 15 F | ||
| 19 | FCB_Close EQU 16 ; 16 10 | ||
| 20 | Dir_Search_First EQU 17 ; 17 11 | ||
| 21 | Dir_Search_Next EQU 18 ; 18 12 | ||
| 22 | FCB_Delete EQU 19 ; 19 13 | ||
| 23 | FCB_Seq_Read EQU 20 ; 20 14 | ||
| 24 | FCB_Seq_Write EQU 21 ; 21 15 | ||
| 25 | FCB_Create EQU 22 ; 22 16 | ||
| 26 | FCB_Rename EQU 23 ; 23 17 | ||
| 27 | Get_Default_Drive EQU 25 ; 25 19 | ||
| 28 | Set_DMA EQU 26 ; 26 1A | ||
| 29 | ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; | ||
| 30 | ; C A V E A T P R O G R A M M E R ; | ||
| 31 | ; ; | ||
| 32 | Get_Default_DPB EQU 31 ; 31 1F | ||
| 33 | ; ; | ||
| 34 | ; C A V E A T P R O G R A M M E R ; | ||
| 35 | ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; | ||
| 36 | FCB_Random_Read EQU 33 ; 33 21 | ||
| 37 | FCB_Random_Write EQU 34 ; 34 22 | ||
| 38 | Get_FCB_File_Length EQU 35 ; 35 23 | ||
| 39 | Get_FCB_Position EQU 36 ; 36 24 | ||
| 40 | Set_Interrupt_Vector EQU 37 ; 37 25 | ||
| 41 | Create_Process_Data_Block EQU 38 ; 38 26 | ||
| 42 | FCB_Random_Read_Block EQU 39 ; 39 27 | ||
| 43 | FCB_Random_Write_Block EQU 40 ; 40 28 | ||
| 44 | Parse_File_Descriptor EQU 41 ; 41 29 | ||
| 45 | Get_Date EQU 42 ; 42 2A | ||
| 46 | Set_Date EQU 43 ; 43 2B | ||
| 47 | Get_Time EQU 44 ; 44 2C | ||
| 48 | Set_Time EQU 45 ; 45 2D | ||
| 49 | Set_Verify_On_Write EQU 46 ; 46 2E | ||
| 50 | ; Extended functionality group | ||
| 51 | Get_DMA EQU 47 ; 47 2F | ||
| 52 | Get_Version EQU 48 ; 48 30 | ||
| 53 | Keep_Process EQU 49 ; 49 31 | ||
| 54 | ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; | ||
| 55 | ; C A V E A T P R O G R A M M E R ; | ||
| 56 | ; ; | ||
| 57 | Get_DPB EQU 50 ; 50 32 | ||
| 58 | ; ; | ||
| 59 | ; C A V E A T P R O G R A M M E R ; | ||
| 60 | ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; | ||
| 61 | Set_CTRL_C_Trapping EQU 51 ; 51 33 | ||
| 62 | Get_InDOS_Flag EQU 52 ; 52 34 | ||
| 63 | Get_Interrupt_Vector EQU 53 ; 53 35 | ||
| 64 | Get_Drive_Freespace EQU 54 ; 54 36 | ||
| 65 | Char_Oper EQU 55 ; 55 37 | ||
| 66 | International EQU 56 ; 56 38 | ||
| 67 | ; Directory Group | ||
| 68 | MKDir EQU 57 ; 57 39 | ||
| 69 | RMDir EQU 58 ; 58 3A | ||
| 70 | CHDir EQU 59 ; 59 3B | ||
| 71 | ; File Group | ||
| 72 | Creat EQU 60 ; 60 3C | ||
| 73 | Open EQU 61 ; 61 3D | ||
| 74 | Close EQU 62 ; 62 3E | ||
| 75 | Read EQU 63 ; 63 3F | ||
| 76 | Write EQU 64 ; 64 40 | ||
| 77 | Unlink EQU 65 ; 65 41 | ||
| 78 | LSeek EQU 66 ; 66 42 | ||
| 79 | CHMod EQU 67 ; 67 43 | ||
| 80 | IOCtl EQU 68 ; 68 44 | ||
| 81 | XDup EQU 69 ; 69 45 | ||
| 82 | XDup2 EQU 70 ; 70 46 | ||
| 83 | Current_Dir EQU 71 ; 71 47 | ||
| 84 | ; Memory Group | ||
| 85 | Alloc EQU 72 ; 72 48 | ||
| 86 | Dealloc EQU 73 ; 73 49 | ||
| 87 | Setblock EQU 74 ; 74 4A | ||
| 88 | ; Process Group | ||
| 89 | Exec EQU 75 ; 75 4B | ||
| 90 | Exit EQU 76 ; 76 4C | ||
| 91 | Wait EQU 77 ; 77 4D | ||
| 92 | Find_First EQU 78 ; 78 4E | ||
| 93 | ; Special Group | ||
| 94 | Find_Next EQU 79 ; 79 4F | ||
| 95 | ; SPECIAL SYSTEM GROUP | ||
| 96 | ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; | ||
| 97 | ; C A V E A T P R O G R A M M E R ; | ||
| 98 | ; ; | ||
| 99 | Set_Current_PDB EQU 80 ; 80 50 | ||
| 100 | Get_Current_PDB EQU 81 ; 81 51 | ||
| 101 | Get_In_Vars EQU 82 ; 82 52 | ||
| 102 | SetDPB EQU 83 ; 83 53 | ||
| 103 | ; ; | ||
| 104 | ; C A V E A T P R O G R A M M E R ; | ||
| 105 | ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; | ||
| 106 | Get_Verify_On_Write EQU 84 ; 84 54 | ||
| 107 | ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; | ||
| 108 | ; C A V E A T P R O G R A M M E R ; | ||
| 109 | ; ; | ||
| 110 | Dup_PDB EQU 85 ; 85 55 | ||
| 111 | ; ; | ||
| 112 | ; C A V E A T P R O G R A M M E R ; | ||
| 113 | ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; | ||
| 114 | Rename EQU 86 ; 86 56 | ||
| 115 | File_Times EQU 87 ; 87 57 | ||
| 116 | AllocOper EQU 88 ; 88 58 | ||
| 117 | ; Network extention system calls | ||
| 118 | GetExtendedError EQU 89 ; 89 59 | ||
| 119 | CreateTempFile EQU 90 ; 90 5A | ||
| 120 | CreateNewFile EQU 91 ; 91 5B | ||
| 121 | LockOper EQU 92 ; 92 5C Lock and Unlock | ||
| 122 | ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; | ||
| 123 | ; C A V E A T P R O G R A M M E R ; | ||
| 124 | ; ; | ||
| 125 | ServerCall EQU 93 ; 93 5D CommitAll, ServerDOSCall, | ||
| 126 | ; CloseByName, CloseUser, | ||
| 127 | ; CloseUserProcess, | ||
| 128 | ; GetOpenFileList | ||
| 129 | ; ; | ||
| 130 | ; C A V E A T P R O G R A M M E R ; | ||
| 131 | ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; | ||
| 132 | UserOper EQU 94 ; 94 5E Get and Set | ||
| 133 | AssignOper EQU 95 ; 95 5F On, Off, Get, Set, Cancel | ||
| 134 | xNameTrans EQU 96 ; 96 60 | ||
| 135 | PathParse EQU 97 ; 97 61 | ||
| 136 | GetCurrentPSP EQU 98 ; 98 62 | ||
| 137 | Hongeul EQU 99 ; 99 63 | ||
| 138 | |||
| 139 | Set_Oem_Handler EQU 248 ; 248 F8 | ||
| 140 | OEM_C1 EQU 249 ; 249 F9 | ||
| 141 | OEM_C2 EQU 250 ; 250 FA | ||
| 142 | OEM_C3 EQU 251 ; 251 FB | ||
| 143 | OEM_C4 EQU 252 ; 252 FC | ||
| 144 | OEM_C5 EQU 253 ; 253 FD | ||
| 145 | OEM_C6 EQU 254 ; 254 FE | ||
| 146 | OEM_C7 EQU 255 ; 255 FF | ||