diff options
| author | 2024-04-25 21:24:10 +0100 | |
|---|---|---|
| committer | 2024-04-25 22:32:27 +0000 | |
| commit | 2d04cacc5322951f187bb17e017c12920ac8ebe2 (patch) | |
| tree | 80ee017efa878dfd5344b44249e6a241f2a7f6e2 /v4.0/src/DEV/XMAEM | |
| parent | Merge pull request #430 from jpbaltazar/typoptbr (diff) | |
| download | ms-dos-main.tar.gz ms-dos-main.tar.xz ms-dos-main.zip | |
Diffstat (limited to 'v4.0/src/DEV/XMAEM')
25 files changed, 8296 insertions, 0 deletions
diff --git a/v4.0/src/DEV/XMAEM/INDEACC.INC b/v4.0/src/DEV/XMAEM/INDEACC.INC new file mode 100644 index 0000000..01a28b2 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEACC.INC | |||
| @@ -0,0 +1,218 @@ | |||
| 1 | COMMENT # | ||
| 2 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 3 | * * | ||
| 4 | * MODULE NAME : INDEACC * | ||
| 5 | * * | ||
| 6 | * * | ||
| 7 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corporation * | ||
| 8 | * * | ||
| 9 | * DESCRIPTIVE NAME: Access rights byte definitions for 80386 XMA emulator * | ||
| 10 | * * | ||
| 11 | * STATUS (LEVEL) : Version (0) Level (1.0) * | ||
| 12 | * * | ||
| 13 | * FUNCTION : This file defines the access rights bytes used in * | ||
| 14 | * descriptors that define the code and data segments. * | ||
| 15 | * * | ||
| 16 | * MODULE TYPE : INC * | ||
| 17 | * * | ||
| 18 | * REGISTER USAGE : 80386 Standard * | ||
| 19 | * * | ||
| 20 | * RESTRICTIONS : None * | ||
| 21 | * * | ||
| 22 | * DEPENDENCIES : None * | ||
| 23 | * * | ||
| 24 | * EXTERNAL * | ||
| 25 | * REFERENCES : None * | ||
| 26 | * * | ||
| 27 | * CHANGE ACTIVITY : * | ||
| 28 | * * | ||
| 29 | * $MAC(INDEACC) COMP(LOAD) PROD(3270PC) : * | ||
| 30 | * * | ||
| 31 | * $D0=D0004700 410 870530 D : NEW FOR WSP RELEASE 1.1 * | ||
| 32 | * $P1=P0000311 410 870804 D : RENAME MODULE'S LIBRARY FILE TYPE TO "INC" * | ||
| 33 | * * | ||
| 34 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 35 | # | ||
| 36 | |||
| 37 | PAGE | ||
| 38 | ; RECORD DEFINITIONS FOR ACCESS RIGHTS BYTES | ||
| 39 | ; ====== =========== === ====== ====== ===== | ||
| 40 | ; | ||
| 41 | ; Data Segments - Interpretation of access rights for DS/ES/SS | ||
| 42 | |||
| 43 | |||
| 44 | ; Define the bit fields for the access rights byte | ||
| 45 | |||
| 46 | DATA_ACC RECORD PRESENT:1,DPL:2,SEG_TYPE:1,XQTBLE:1,EXPDIR:1,WRTBLE:1,ACCESSED:1 | ||
| 47 | |||
| 48 | ; PRESENT (1 bit) 0 = segment not present in memory | ||
| 49 | ; 1 = segment present in memory | ||
| 50 | ; | ||
| 51 | ; DPL (2 bits) Descriptor privilege level -- 0 to 3 | ||
| 52 | ; | ||
| 53 | ; SEG_TYPE (1 bit) 0 = system segment | ||
| 54 | ; 1 = application segment | ||
| 55 | ; | ||
| 56 | ; XQTBL (1 bit) 0 = segment is not executable (i.e., data) | ||
| 57 | ; 1 = segment is executable (i.e., code) | ||
| 58 | ; | ||
| 59 | ; EXPDIR (1 bit) 0 = expand up, i.e., normal data segment | ||
| 60 | ; 1 = expand down, i.e., stack segment | ||
| 61 | ; | ||
| 62 | ; WRTBLE (1 bit) 0 = data segment is read only | ||
| 63 | ; 1 = data segment is read/write | ||
| 64 | ; | ||
| 65 | ; ACCESSED (1 bit) 0 = segment has not been accessed | ||
| 66 | ; 1 = segment has been accessed | ||
| 67 | |||
| 68 | |||
| 69 | ; Privilege level 3 read/write data segment access rights byte | ||
| 70 | |||
| 71 | CPL3_DATA_ACCESS EQU 11110011B ; Present | ||
| 72 | ; DPL = 3 | ||
| 73 | ; Application segment | ||
| 74 | ; Not executable (i.e. data) | ||
| 75 | ; Expand up | ||
| 76 | ; Readable/Writable | ||
| 77 | ; Accessed | ||
| 78 | |||
| 79 | ; Privilege level 0 read/write data segment access rights byte | ||
| 80 | |||
| 81 | CPL0_DATA_ACCESS EQU 10010011B ; Present | ||
| 82 | ; DPL = 0 | ||
| 83 | ; Application segment | ||
| 84 | ; Not executable (i.e. data) | ||
| 85 | ; Expand up | ||
| 86 | ; Readable/Writable | ||
| 87 | ; Accessed | ||
| 88 | |||
| 89 | |||
| 90 | NULL_ACCESS EQU 00000000B ; Null (Not present) | ||
| 91 | |||
| 92 | |||
| 93 | ; Descriptor privilege levels. These can be ANDed or ORed with the access | ||
| 94 | ; rights byte to get the desired DPL for the descriptor. | ||
| 95 | |||
| 96 | DPL3 EQU 01100000B | ||
| 97 | DPL2 EQU 01000000B | ||
| 98 | DPL1 EQU 00100000B | ||
| 99 | DPL0 EQU 00000000B | ||
| 100 | |||
| 101 | PAGE | ||
| 102 | ; Code Segments - Interpretation of access rights for CS. | ||
| 103 | ; Identical to data segments except for two fields. | ||
| 104 | |||
| 105 | |||
| 106 | CODE_ACC RECORD DATA_HI:5,CONFORM:1,READABLE:1,DATA_LO:1 | ||
| 107 | |||
| 108 | ; DATA_HI (5 bits) Same five bits as described for data segments | ||
| 109 | ; PPRESENT (1), DPL (2), SEG_TYPE (1) and | ||
| 110 | ; XQTBL (1) | ||
| 111 | ; | ||
| 112 | ; CONFORM (1 bit) 0 = Non-conforming - cannot be called by | ||
| 113 | ; someone with a different CPL | ||
| 114 | ; 1 = Conforming - can be called by anyone | ||
| 115 | ; regardless of CPL. CPL remains the same | ||
| 116 | ; | ||
| 117 | ; READABLE (1 bit) 0 = code segment is execute only | ||
| 118 | ; 1 = data segment is executable and readable | ||
| 119 | ; | ||
| 120 | ; DATA_LO (1 bit) Same bit as described for data segments | ||
| 121 | ; ACCESSED (1) | ||
| 122 | |||
| 123 | |||
| 124 | ; Privilege level 3 conforming readable code segment access rights byte | ||
| 125 | ; BUT... | ||
| 126 | ; We switched the DPL to 0. Why? Because the DPL of the current code segment | ||
| 127 | ; determines the current privilege level (CPL). Whatever is running at the | ||
| 128 | ; time can only access data with a DPL >= CPL. So if the DPL for the code | ||
| 129 | ; segment were 3 and we tried to access data with a DPL of 0 we would get a | ||
| 130 | ; fault. By setting the DPL of the code segment to 0 we can access all data | ||
| 131 | ; and will never be bothered by faults. | ||
| 132 | |||
| 133 | CPL3_CODE_ACCESS EQU 10011111B ; Present | ||
| 134 | ; DPL = 0 | ||
| 135 | ; Application segment | ||
| 136 | ; Executable (i.e. code) | ||
| 137 | ; Conforming | ||
| 138 | ; Readable | ||
| 139 | ; Accessed | ||
| 140 | |||
| 141 | ; Access rights to be able to read and write to a code segment. Code segments | ||
| 142 | ; may not be written to. So this access byte will define the segment as a | ||
| 143 | ; read/write data segment. It is the same as CPL3_DATA_ACCESS. | ||
| 144 | |||
| 145 | COMP_CODE_ACCESS EQU CPL3_DATA_ACCESS | ||
| 146 | |||
| 147 | ; Privilege level 0 non-conforming readable code segment access rights byte | ||
| 148 | |||
| 149 | CPL0_CODE_ACCESS EQU 10011011B ; Present | ||
| 150 | ; DPL = 0 | ||
| 151 | ; Application segment | ||
| 152 | ; Executable (i.e. code) | ||
| 153 | ; Non-conforming | ||
| 154 | ; Readable | ||
| 155 | ; Accessed | ||
| 156 | |||
| 157 | PAGE | ||
| 158 | ; System Segments - Interpretation of access rights for TR/LDTR as well as | ||
| 159 | ; the four gate types. The access rights byte for the | ||
| 160 | ; GDTR and IDTR is undefined, meaning anyone can access | ||
| 161 | ; the table (although not necessarily the segments | ||
| 162 | ; defined in the table). The uppermost 4 bits are | ||
| 163 | ; identical to those for data segments; the type field | ||
| 164 | ; occupies the lowermost 4 bits. | ||
| 165 | |||
| 166 | |||
| 167 | SYSTEM_ACC RECORD DATA_H:4,DESC_TYPE:4 | ||
| 168 | |||
| 169 | ; DATA_H (4 bits) Same four bits as described for data segments | ||
| 170 | ; PPRESENT (1), DPL (2) and SEG_TYPE (1) | ||
| 171 | ; | ||
| 172 | ; DESC_TYPE(4 bits) 0000 Intel Reserved | ||
| 173 | ; 0001 Available 286 TSS | ||
| 174 | ; 0010 LDT | ||
| 175 | ; 0011 Busy 286 TSS | ||
| 176 | ; 0100 Call Gate | ||
| 177 | ; 0101 Task Gate | ||
| 178 | ; 0110 286 Interrupt Gate | ||
| 179 | ; 0111 286 Trap Gate | ||
| 180 | ; 1000 Intel Reserved | ||
| 181 | ; 1001 Available 386 TSS | ||
| 182 | ; 1010 Intel Reserved | ||
| 183 | ; 1011 Busy 386 TSS | ||
| 184 | ; 1100 386 Call Gate | ||
| 185 | ; 1101 Intel Reserved | ||
| 186 | ; 1110 386 Interrupt Gate | ||
| 187 | ; 1111 386 Trap Gate | ||
| 188 | ; | ||
| 189 | |||
| 190 | |||
| 191 | ; These equates cover the topmost 4 bits for system segment access | ||
| 192 | ; rights bytes. They define the privilege level. | ||
| 193 | |||
| 194 | LDT_ACCESS EQU 11100000B ; Present, DPL = 3 for LDTs | ||
| 195 | |||
| 196 | TSS_ACCESS EQU 10000000B ; Present, DPL = 0 for TSSs | ||
| 197 | |||
| 198 | GATE_ACCESS EQU 10000000B ; Present, DPL = 0 for Gates | ||
| 199 | |||
| 200 | |||
| 201 | ; These are for the type field. When "OR"ed with one of the above, | ||
| 202 | ; you have a complete access rights byte. | ||
| 203 | |||
| 204 | LDT_DESC EQU 00000010B OR LDT_ACCESS | ||
| 205 | |||
| 206 | FREE_TSS EQU 00000001B OR TSS_ACCESS | ||
| 207 | FREE_TSS_386 EQU 00001001B OR TSS_ACCESS | ||
| 208 | |||
| 209 | BUSY_TSS EQU 00000011B OR TSS_ACCESS | ||
| 210 | |||
| 211 | CALL_GATE EQU 00000100B OR GATE_ACCESS | ||
| 212 | |||
| 213 | TASK_GATE EQU 00000101B OR GATE_ACCESS | ||
| 214 | |||
| 215 | INT_GATE EQU 00000110B OR GATE_ACCESS | ||
| 216 | |||
| 217 | TRAP_GATE EQU 00000111B OR GATE_ACCESS | ||
| 218 | |||
diff --git a/v4.0/src/DEV/XMAEM/INDEDAT.INC b/v4.0/src/DEV/XMAEM/INDEDAT.INC new file mode 100644 index 0000000..6c58eef --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEDAT.INC | |||
| @@ -0,0 +1,535 @@ | |||
| 1 | COMMENT # | ||
| 2 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 3 | * * | ||
| 4 | * MODULE NAME : INDEDAT * | ||
| 5 | * * | ||
| 6 | * * | ||
| 7 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corporation * | ||
| 8 | * * | ||
| 9 | * DESCRIPTIVE NAME: Sytem data structures and equates for 386 XMA emulator * | ||
| 10 | * * | ||
| 11 | * STATUS (LEVEL) : Version (0) Level (1.0) * | ||
| 12 | * * | ||
| 13 | * FUNCTION : This file defines the overlays and constants for most of * | ||
| 14 | * the system data. The following structures are defined * | ||
| 15 | * here: * | ||
| 16 | * The resister save area on our stack * | ||
| 17 | * 80386 Task State Segment (TSS) * | ||
| 18 | * The Global Descriptor Table (GDT) * | ||
| 19 | * 80286 Segment Descriptor * | ||
| 20 | * 80286 Gate Descriptor * | ||
| 21 | * 80286 Task State Segment (TSS) * | ||
| 22 | * * | ||
| 23 | * MODULE TYPE : INC * | ||
| 24 | * * | ||
| 25 | * REGISTER USAGE : 80386 Standard * | ||
| 26 | * * | ||
| 27 | * RESTRICTIONS : None * | ||
| 28 | * * | ||
| 29 | * DEPENDENCIES : None * | ||
| 30 | * * | ||
| 31 | * EXTERNAL * | ||
| 32 | * REFERENCES : None * | ||
| 33 | * * | ||
| 34 | * CHANGE ACTIVITY : * | ||
| 35 | * * | ||
| 36 | * $MAC(INDEDAT) COMP(LOAD) PROD(3270PC) : * | ||
| 37 | * * | ||
| 38 | * $D0=D0004700 410 870529 D : NEW FOR WSP RELEASE 1.1 * | ||
| 39 | * $P1=P0000311 410 870804 D : RENAME MODULES'S LIBRARY FILE TYPE TO "INC" * | ||
| 40 | * $P2=P0000410 410 870918 D : RELOCATE DATA TO MAKE ROOM FOR I/O BIT MAP * | ||
| 41 | * * | ||
| 42 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 43 | # | ||
| 44 | |||
| 45 | ; BPSTACK is an overlay for our stack when we receive control from an | ||
| 46 | ; interrupt that we want to handle. The entry points for these interrupts | ||
| 47 | ; push a 32 but error code and the interrupt number (16 bits) onto the stack. | ||
| 48 | ; Then control goes to INDEEXC which saves the current register values on the | ||
| 49 | ; stack. BP is set to point to the beginning of the register save area. This | ||
| 50 | ; is the mapping of the resulting stack. | ||
| 51 | |||
| 52 | BPSTACK STRUC | ||
| 53 | |||
| 54 | BP_ES DW 0 ; Interrptee's ES | ||
| 55 | BP_DI DW 0 ; Interruptee's EDI (32 bit DI) | ||
| 56 | DW 0 ; | ||
| 57 | BP_SI DW 0 ; Interruptee's ESI (32 bit SI) | ||
| 58 | DW 0 ; | ||
| 59 | BP_BP DW 0 ; Interruptee's EBP (32 bit BP) | ||
| 60 | DW 0 ; | ||
| 61 | BP_PASP DW 0 ; Interruptee's ESP (32 bit SP) | ||
| 62 | BP_PSP2 DW 0 ; (ESP as it was before the PUSHA) | ||
| 63 | BP_BX DW 0 ; Interruptee's EBX (32 bit BX) | ||
| 64 | DW 0 ; | ||
| 65 | BP_DX DW 0 ; Interruptee's EDX (32 bit DX) | ||
| 66 | DW 0 ; | ||
| 67 | BP_CX DW 0 ; Interruptee's ECX (32 bit CX) | ||
| 68 | DW 0 ; | ||
| 69 | BP_AX DW 0 ; Interruptee's EAX (32 bit AX) | ||
| 70 | DW 0 ; | ||
| 71 | BP_DS DW 0 ; Interruptee's DS | ||
| 72 | BP_EX DW 0 ; Exception ID | ||
| 73 | BP_EC DW 0 ; Error Code | ||
| 74 | DW 0 | ||
| 75 | |||
| 76 | ; The following values are placed on our stack by the 80386 | ||
| 77 | |||
| 78 | BP_IP DW 0 ; Interruptee's EIP (32 bit IP) | ||
| 79 | BP_IP2 DW 0 | ||
| 80 | BP_CS DW 0 ; Interruptee's CS (16 bit CS plus 16 bit trash) | ||
| 81 | BP_CS2 DW 0 | ||
| 82 | BP_FL DW 0 ; Interruptee's flags (32 bits) | ||
| 83 | BP_FL2 DW 0 | ||
| 84 | BP_SP DW 0 ; Interruptee's ESP - saved on an inter-level | ||
| 85 | BP_SP2 DW 0 ; interrupt | ||
| 86 | BP_SS DW 0 ; Interruptee's SSP - also saved on inter-level | ||
| 87 | BP_SS2 DW 0 ; interrupt | ||
| 88 | BP_VMES DW 0 ; Virtual mode ES | ||
| 89 | BP_VME2 DW 0 | ||
| 90 | BP_VMDS DW 0 ; Virtual mode DS | ||
| 91 | DW 0 | ||
| 92 | BP_VMFS DW 0 ; Virtual mode FS | ||
| 93 | DW 0 | ||
| 94 | BP_VMGS DW 0 ; Virtual mode GS | ||
| 95 | DW 0 | ||
| 96 | BP_STK DW 0 ; The rest of the stack | ||
| 97 | |||
| 98 | BPSTACK ENDS | ||
| 99 | |||
| 100 | BP_START EQU 0 ; Offset from BP of the start of the stack info | ||
| 101 | |||
| 102 | SUBTTL 80386 TSS - Task State Segment | ||
| 103 | PAGE | ||
| 104 | ;************************************************* | ||
| 105 | ; * | ||
| 106 | ; Start of Debugger's 386 TSS * | ||
| 107 | ; * | ||
| 108 | ;************************************************* | ||
| 109 | |||
| 110 | TSS386 STRUC | ||
| 111 | DW 0 ; Intel reserved | ||
| 112 | ETSS_BACK_LINK DW 0 ; Back link to previous TSS | ||
| 113 | ETSS_SP0 DW 0 ; ESP for privilege level 0 | ||
| 114 | DW 0 | ||
| 115 | ETSS_SS0 DW 0 ; SS for privilege level 0 | ||
| 116 | DW 0 ; Intel reserved | ||
| 117 | ETSS_SP1 DD 0 ; ESP for privilege level 1 | ||
| 118 | ETSS_SS1 DW 0 ; SS for privilege level 1 | ||
| 119 | DW 0 ; Intel reserved | ||
| 120 | ETSS_SP2 DD 0 ; ESP for privilege level 2 | ||
| 121 | ETSS_SS2 DW 0 ; SS for privilege level 2 | ||
| 122 | DW 0 ; Intel reserved | ||
| 123 | ETSS_CR3 DD 0 ; CR3 - Page directory base register | ||
| 124 | ETSS_IP DW 0 ; Task's EIP | ||
| 125 | DW 0 | ||
| 126 | ETSS_FL DW 0 ; Task's Eflags | ||
| 127 | ETSS_FL2 DW 0 | ||
| 128 | ETSS_AX DD 0 ; Task's EAX | ||
| 129 | ETSS_CX DD 0 ; Task's ECX | ||
| 130 | ETSS_DX DD 0 ; Task's EDX | ||
| 131 | ETSS_BX DD 0 ; Task's EBX | ||
| 132 | ETSS_SP DW 0 ; Task's ESP | ||
| 133 | DW 0 | ||
| 134 | ETSS_BP DD 0 ; Task's EBP | ||
| 135 | ETSS_SI DD 0 ; Task's ESI | ||
| 136 | ETSS_DI DD 0 ; Task's EDI | ||
| 137 | ETSS_ES DW 0 ; Task's ES | ||
| 138 | DW 0 ; Intel reserved | ||
| 139 | ETSS_CS DW 0 ; Task's CS | ||
| 140 | DW 0 ; Intel reserved | ||
| 141 | ETSS_SS DW 0 ; Task's SS | ||
| 142 | DW 0 ; Intel reserved | ||
| 143 | ETSS_DS DW 0 ; Task's DS | ||
| 144 | DW 0 ; Intel reserved | ||
| 145 | ETSS_FS DW 0 ; Task's FS | ||
| 146 | DW 0 ; Intel reserved | ||
| 147 | ETSS_GS DW 0 ; Task's GS | ||
| 148 | DW 0 ; Intel reserved | ||
| 149 | ETSS_LDT DW 0 ; Selector for task's LDT | ||
| 150 | DW 0 ; Intel reserved | ||
| 151 | ETSS_TRAP DW 0 ; Trap bit - bit 0 (IBM bit 15) | ||
| 152 | ETSS_BM_OFFSET DW 0 ; I/O bit map base | ||
| 153 | ETSS_AVL DD 0 | ||
| 154 | TSS386 ENDS | ||
| 155 | TSS_386_LEN EQU 68H ; Length of the TSS | ||
| 156 | TSS_BM_LEN EQU 0FFFH-TSS_386_LEN ; Length of the I/O bit map | ||
| 157 | ; The bit map is in the same segment as the TSS | ||
| 158 | ; therefore the descriptor fot the TSS segment | ||
| 159 | ; must have enough room to include the bit map. | ||
| 160 | |||
| 161 | SUBTTL GDT - Global Descriptor Table | ||
| 162 | PAGE | ||
| 163 | |||
| 164 | SUBTTL GDT - GLOBAL DESCRIPTOR TABLE | ||
| 165 | |||
| 166 | ; THE GLOBAL DESCRIPTOR TABLE DEFINITION | ||
| 167 | ; === ====== ========== ===== ========== | ||
| 168 | ; | ||
| 169 | |||
| 170 | GDT_LEN EQU 512 * 8 ; 512 entries total | ||
| 171 | |||
| 172 | GDT_DEF STRUC | ||
| 173 | |||
| 174 | UNUSED_ENTRY DQ 0 ; Seg reg = 0 illegal - this entry is | ||
| 175 | ; not accessible | ||
| 176 | GDT_PTR DQ 0 ; This entry points to this GDT table | ||
| 177 | MON_IDT_PTR DQ 0 ; System interrupt descriptor table | ||
| 178 | RSDA_PTR DQ 0 ; The real system data area (as opposed | ||
| 179 | ; to the virtual SDA's). XMA pages | ||
| 180 | ; start here | ||
| 181 | HUGE_PTR DQ 0 ; Used to address 0-1M as data | ||
| 182 | |||
| 183 | LA_PTR DQ 0 ; Pointer to the LOADALL area (000800H) | ||
| 184 | |||
| 185 | C_BWCRT_PTR DQ 0 ; Compatible blanck and white display | ||
| 186 | C_CCRT_PTR DQ 0 ; Compatible color display | ||
| 187 | E_CCRT_PTR DQ 0 ; Enhanced color display (16 bytes) | ||
| 188 | E_CCRT_PTR2 DQ 0 | ||
| 189 | |||
| 190 | SYS_ROM_CS DQ 0 ; CS for system IDT, ROM resident | ||
| 191 | SYS_ROM_DS DQ 0 ; DS selector to access above as data | ||
| 192 | SYS_PATCH_CS DQ 0 ; CS for system IDT, RAM patch area | ||
| 193 | SYS_PATCH_DS DQ 0 ; DS selector to access above as data | ||
| 194 | |||
| 195 | V_ROM_CS DQ 0 ; CS - virtual IDT, ROM resident | ||
| 196 | V_ROM_DS DQ 0 ; DS selector to access above as data | ||
| 197 | V_PATCH_CS DQ 0 ; CS - virtual IDT, RAM patch area | ||
| 198 | V_PATCH_DS DQ 0 ; DS selector to access above as data | ||
| 199 | |||
| 200 | ES_TEMP DQ 0 ; Dynamic pointer for ES | ||
| 201 | CS_TEMP DQ 0 ; Dynamic pointer for CS | ||
| 202 | SS_TEMP DQ 0 ; Dynamic pointer for SS | ||
| 203 | DS_TEMP DQ 0 ; Dynamic pointer for DS | ||
| 204 | |||
| 205 | ; Monitor descriptors | ||
| 206 | |||
| 207 | MON_LDTR DQ 0 | ||
| 208 | MON_DS DQ 0 | ||
| 209 | MON_ES DQ 0 | ||
| 210 | MON_SS DQ 0 | ||
| 211 | MON_CS DQ 0 | ||
| 212 | MON_TR_SS DQ 0 ; Task register value for single step | ||
| 213 | MON_TR_BP DQ 0 ; " " " " breakpoint | ||
| 214 | MON_TR_HWI DQ 0 ; Read/write (needs special hardware) | ||
| 215 | MON_TR_OI DQ 0 ; " " " " control-break | ||
| 216 | |||
| 217 | KBD_OWNER_SDA DQ 0 ; Fast path to keyboard owner's SDA | ||
| 218 | |||
| 219 | VTIMER_VECTOR DB 16 DUP (8 DUP(0)) ; 16 VM timer-related descriptors | ||
| 220 | |||
| 221 | ; Below are the 32 system exception service routine descriptors. | ||
| 222 | |||
| 223 | SEX_TSS DB 32 DUP (8 DUP(0)) | ||
| 224 | |||
| 225 | ; Below are the 16 hardware interrupt service routine TSS descriptor | ||
| 226 | ; pairs. The first is suitable for TR loading (i.e. target selector | ||
| 227 | ; in the corresponding task gate) and the other is a TSS-as-data | ||
| 228 | ; descriptor. | ||
| 229 | |||
| 230 | HWI_TSS DB 16 DUP (16 DUP(0)) | ||
| 231 | |||
| 232 | ; This is the descriptor pair for the dispatcher (same format as HWI). | ||
| 233 | |||
| 234 | DISPATCH_TASK DQ 0 | ||
| 235 | DQ 0 | ||
| 236 | |||
| 237 | HWI_LDT DQ 0 | ||
| 238 | |||
| 239 | BASICS_SEG DQ 0 ; BASIC's segment (F600) | ||
| 240 | |||
| 241 | BIOSS_SEG DQ 0 ; BIOS's segment (F000) | ||
| 242 | |||
| 243 | ; | ||
| 244 | ; | ||
| 245 | ; Any other GDT things go here. There are around 300 slots left. | ||
| 246 | ; | ||
| 247 | ; | ||
| 248 | |||
| 249 | RSVD_GDT DQ 0 | ||
| 250 | DB (GDT_LEN - (RSVD_GDT + 8) - (18 * 32)) DUP (0) | ||
| 251 | |||
| 252 | ; The above leaves space for the | ||
| 253 | ; descriptors needed for 18 VMs | ||
| 254 | |||
| 255 | PM_VM DB 32 DUP (0) ; Program Manager's virtual machine | ||
| 256 | ; entries. This will function as | ||
| 257 | ; the highest priority machine. | ||
| 258 | USER_CS DQ 0 ; Debugee's code segment | ||
| 259 | USER_SS DQ 0 ; Debugee's stack segment | ||
| 260 | USER_DS DQ 0 ; Debugee's data segment | ||
| 261 | USER_ES DQ 0 ; Debugee's extra segment | ||
| 262 | USER_TSS DQ 0 ; Debugee's Task State Segment | ||
| 263 | USER_TSS_DAT DQ 0 ; Debugee's TSS as a data segment | ||
| 264 | USER_LDT DQ 0 ; Debugee's LDT definition | ||
| 265 | USER_LDT_DAT DQ 0 ; Debugee's LDT as a data segment | ||
| 266 | |||
| 267 | USER_VMS DB 14 DUP (32 DUP(0)) ; 16 user VMs | ||
| 268 | |||
| 269 | SCRUBBER DB 32 DUP (0) ; RAM scrubber - dispatched when no other | ||
| 270 | ; machine has work to do | ||
| 271 | last_gdt_byte db 0 ; marker for last GDT byte + 1 | ||
| 272 | GDT_DEF ENDS | ||
| 273 | |||
| 274 | SUBTTL Virtual Machine Entry | ||
| 275 | PAGE | ||
| 276 | ; Virtual Machine Entry Definition - consists of 4 descriptors | ||
| 277 | ; | ||
| 278 | ; - Pointer to TSS, loadable into the Task Register | ||
| 279 | ; - Pointer to TSS, loadable into a regular segment register | ||
| 280 | ; - Pointer to the LDT, loadable into the LDT Register | ||
| 281 | ; - Pointer to the LDT, loadable into a regular segment register | ||
| 282 | ; | ||
| 283 | ; The first of each pair is for loading into the associated special | ||
| 284 | ; system registers, TR and LDTR. The second allows dynamic access | ||
| 285 | ; and modification of descriptors by the system. | ||
| 286 | |||
| 287 | VM_GDT_ENTRY STRUC | ||
| 288 | |||
| 289 | VM_TR DQ 0 ; TR value for this machine's TSS | ||
| 290 | TSS_PTR DQ 0 ; Data pointer to this machine's TSS | ||
| 291 | VM_LDTR DQ 0 ; LDTR value for this machine's LDT | ||
| 292 | LDT_PTR DQ 0 ; Data pointer to this machine's LDT | ||
| 293 | |||
| 294 | VM_GDT_ENTRY ENDS | ||
| 295 | |||
| 296 | SUBTTL 80286 Segment Descriptor | ||
| 297 | PAGE | ||
| 298 | ; DESCRIPTOR TABLE ENTRY STRUCTURES | ||
| 299 | ; ========== ===== ===== ========== | ||
| 300 | ; | ||
| 301 | ; Segment Descriptor | ||
| 302 | ; | ||
| 303 | ; The following type of descriptor applies to data segments, code | ||
| 304 | ; segments, local, global, and interrupt descriptor table segments, | ||
| 305 | ; and task state segments. | ||
| 306 | |||
| 307 | DATA_DESC STRUC | ||
| 308 | |||
| 309 | SEG_LIMIT DW 0 ; Segment limit (1 - 65535 bytes) | ||
| 310 | BASE_LO_WORD DW 0 ; 24 bit segment physical address | ||
| 311 | BASE_HI_BYTE DB 0 ; (0 - (16M-1)) | ||
| 312 | DATA_ACC_RIGHTS DB 0 ; Access rights byte | ||
| 313 | DATA_RESERVED DW 0 ; Intel reserved | ||
| 314 | |||
| 315 | DATA_DESC ENDS | ||
| 316 | |||
| 317 | SHADOW_ID EQU DATA_RESERVED ; For garbage collection | ||
| 318 | |||
| 319 | SUBTTL 80286 Gate Descriptor | ||
| 320 | PAGE | ||
| 321 | ; 80286 Gate Descriptor | ||
| 322 | |||
| 323 | ; The following type of descriptor applies to task gates, call gates, | ||
| 324 | ; interrupt gates, and trap gates. | ||
| 325 | |||
| 326 | GATE_DESC STRUC | ||
| 327 | |||
| 328 | ENTRY_POINT DW 0 ; Destination routine entry point | ||
| 329 | ; within the target segment. | ||
| 330 | ; This is unused for task gates. | ||
| 331 | CS_SELECTOR DW 0 ; Selector for destination segment. | ||
| 332 | ; For task gates, this must point | ||
| 333 | ; to a valid task state segment | ||
| 334 | ; descriptor. For call, trap, and | ||
| 335 | ; interrupt gates, this must point | ||
| 336 | ; to a valid code segment descriptor. | ||
| 337 | ; The segment defined in that | ||
| 338 | ; descriptor plus the aforementioned | ||
| 339 | ; entry-point defines the actual | ||
| 340 | ; routine address. | ||
| 341 | WORD_COUNT DB 0 ; For call gates only - number of | ||
| 342 | ; words to copy from caller's | ||
| 343 | ; stack to callee's stack | ||
| 344 | GATE_ACC_RIGHTS DB 0 ; Access rights byte | ||
| 345 | GATE_RESERVED DW 0 ; Intel reserved | ||
| 346 | |||
| 347 | GATE_DESC ENDS | ||
| 348 | |||
| 349 | ; Record for the fields in a selector | ||
| 350 | |||
| 351 | SELECTOR RECORD INDEX:13,TI:1,RPL:2 ; Standard 286 selector format | ||
| 352 | |||
| 353 | SUBTTL TSS - Task State Segment | ||
| 354 | PAGE | ||
| 355 | ; TASK STATE SEGMENT | ||
| 356 | ; ==== ===== ======= | ||
| 357 | ; | ||
| 358 | ; There are currently two styles of task state segment (TSS) - one for | ||
| 359 | ; VMs and one for the hardware interrupt service routines. There may | ||
| 360 | ; be more later, depending on the needs and/or whims of the Authors | ||
| 361 | ; of this and follow-on products. They will all have one thing in | ||
| 362 | ; common - they begin with a 44 byte 286-required machine state data | ||
| 363 | ; area. The first structure below is that area's definition. All | ||
| 364 | ; subsequent colors of TSS will start with space for that data, defined | ||
| 365 | ; like so: | ||
| 366 | ; | ||
| 367 | ; first_field_name DB (TYPE TASK_STATE_286) DUP (0) | ||
| 368 | ; | ||
| 369 | ; As a convenience, we use the highest part of the TSS for that | ||
| 370 | ; particular task's stack (or in some cases, stacks - for privilege | ||
| 371 | ; levels 0, 1, and 2). The intermediate area is used for task-specific | ||
| 372 | ; data. | ||
| 373 | |||
| 374 | |||
| 375 | TASK_STATE_286 STRUC | ||
| 376 | |||
| 377 | BACK_LINK DW 0 ; TSS selector from whence we came | ||
| 378 | VM_SP0 DW 0 ; SS:SP for CPL 0 | ||
| 379 | VM_SS0 DW 0 | ||
| 380 | VM_SP1 DW 0 ; SS:SP for CPL 1 | ||
| 381 | VM_SS1 DW 0 | ||
| 382 | VM_SP2 DW 0 ; SS:SP for CPL 2 | ||
| 383 | VM_SS2 DW 0 | ||
| 384 | VM_IP DW 0 ; IP - next instruction to execute | ||
| 385 | VM_FL DW 0 ; Flag word | ||
| 386 | VM_AX DW 0 ; | ||
| 387 | VM_CX DW 0 ; General | ||
| 388 | VM_DX DW 0 ; | ||
| 389 | VM_BX DW 0 ; | ||
| 390 | VM_SP DW 0 ; Purpose | ||
| 391 | VM_BP DW 0 ; | ||
| 392 | VM_SI DW 0 ; | ||
| 393 | VM_DI DW 0 ; Registers | ||
| 394 | VM_ES DW 0 ; | ||
| 395 | VM_CS DW 0 ; Segment | ||
| 396 | VM_SS DW 0 ; Selectors | ||
| 397 | VM_DS DW 0 ; | ||
| 398 | VM_LDT DW 0 ; Selector for this task's LDT | ||
| 399 | |||
| 400 | TASK_STATE_286 ENDS | ||
| 401 | |||
| 402 | ; Note that the actual stacks for CPLs 2, 1, and 0 are part of the | ||
| 403 | ; task state segment. CPL 3's stack is in its own address space. | ||
| 404 | |||
| 405 | SUBTTL Length Equates | ||
| 406 | PAGE | ||
| 407 | ; Length equates | ||
| 408 | |||
| 409 | LA_LEN EQU GDT_LEN ; For new monitor | ||
| 410 | |||
| 411 | SIDT_LEN EQU 256*8 ; Length of the IDT -- 256 interrupt | ||
| 412 | ; entries, 8 bytes each | ||
| 413 | |||
| 414 | TSS_LEN EQU 68H + 2000H ; TSS structure length -- 68H for regs | ||
| 415 | ; 2000H for I/O bit map @P2C | ||
| 416 | |||
| 417 | LDT_LEN EQU 00800H ; LDT structure length (2K) | ||
| 418 | |||
| 419 | VM_ENTRY_LENGTH EQU TYPE VM_GDT_ENTRY ; Length of a VM entry | ||
| 420 | |||
| 421 | VM_ENTRY_WIDTH EQU 5 ; Shift count for priority. Each | ||
| 422 | ; VM entry = 32 bytes, and SHL 5 | ||
| 423 | ; is the same as MUL by 32. | ||
| 424 | NEXT_DESC EQU TYPE DATA_DESC ; Length of a descriptor | ||
| 425 | |||
| 426 | DESC_LEN EQU TYPE DATA_DESC ; Length of a descriptor | ||
| 427 | |||
| 428 | DESC_WIDTH EQU 3 ; Shift count for desc len (8) is 3 | ||
| 429 | |||
| 430 | PM_VM_SIZE EQU 01000H ; Virtual Manager's VM size | ||
| 431 | |||
| 432 | MCRT_SIZE EQU 4*1024 ; Monochrome display size | ||
| 433 | |||
| 434 | CCRT_SIZE EQU 16*1024 ; Compatible color display size | ||
| 435 | |||
| 436 | ECCRT_SIZE EQU 0FFFFH ; Size of each portion of the enhanced | ||
| 437 | ; color display buffer | ||
| 438 | |||
| 439 | MAX_SEG_LEN EQU 0FFFFH ; Maximum segment length = 64K | ||
| 440 | |||
| 441 | NULL_SEG_LEN EQU 00000H ; Null segment length = 0 | ||
| 442 | |||
| 443 | THIRTY_TWO_K EQU 08000H ; Unit of virtual machine size | ||
| 444 | |||
| 445 | |||
| 446 | SUBTTL Location Equates | ||
| 447 | PAGE | ||
| 448 | |||
| 449 | |||
| 450 | ; Location equates | ||
| 451 | |||
| 452 | ; These items are all pre-allocated, and have no SBDs. After these, | ||
| 453 | ; storage structures are all obtained through the memory manager. | ||
| 454 | |||
| 455 | ;----------------------------------------------------------------------------- | ||
| 456 | |||
| 457 | ; From here to the end marker, these guys must stay in order as this is | ||
| 458 | ; how they are allocated. | ||
| 459 | |||
| 460 | GDT_LOC EQU 0C100H ; GDT location relative to CS @P2C | ||
| 461 | |||
| 462 | SIDT_LOC EQU (GDT_LOC + GDT_LEN) ; The system IDT is next | ||
| 463 | |||
| 464 | DISPATCH_LOC EQU (SIDT_LOC + SIDT_LEN) | ||
| 465 | |||
| 466 | ; End marker | ||
| 467 | |||
| 468 | ; Monitor equate used in m_state to tell the estep routine that we're | ||
| 469 | ; single stepping from within ego. | ||
| 470 | GO_MODE EQU 1 ; | ||
| 471 | ; Monitor equate used in m_state to tell the hwi_int routine that we're | ||
| 472 | ; breaking on a memory read address that's executed | ||
| 473 | MEMX EQU 2 ; | ||
| 474 | ; Monitor equate used in m_state to tell mon_go that a breakpoint has been | ||
| 475 | ; set so enable the breakpoint card | ||
| 476 | CARD_ENABL EQU 4 ; | ||
| 477 | S_MODE EQU 2000H ; Selector or segment mode flag | ||
| 478 | |||
| 479 | BOOT_IP EQU 07C00H ; PC1 IP value for boot | ||
| 480 | |||
| 481 | BOOT_CS EQU 00000H ; PC1 CS value for boot | ||
| 482 | |||
| 483 | BOOT_SS EQU 00030H ; PC1 SS value for boot | ||
| 484 | |||
| 485 | BOOT_SP EQU 07FFH ; PC1 SP value for boot | ||
| 486 | |||
| 487 | BOOT_FL EQU 00200H ; Interrupts enabled | ||
| 488 | |||
| 489 | CS_LO_CACHE EQU 00000H ; Code segment | ||
| 490 | |||
| 491 | CS_HI_CACHE EQU 000H ; compatible cache | ||
| 492 | |||
| 493 | SS_LO_CACHE EQU 00300H ; Stack segment | ||
| 494 | |||
| 495 | SS_HI_CACHE EQU 000H ; compatible cache | ||
| 496 | |||
| 497 | OTHER_CACHE EQU 00000H ; GP zero cache | ||
| 498 | |||
| 499 | SUBTTL Display Equates | ||
| 500 | PAGE | ||
| 501 | |||
| 502 | ; The next equates are system definitions for display buffer addresses. | ||
| 503 | |||
| 504 | |||
| 505 | MCRT@_LO EQU 0000H ; | ||
| 506 | ; Monochrome display address | ||
| 507 | MCRT@_HI EQU 0BH ; (0B0000H) | ||
| 508 | |||
| 509 | CCRT@_LO EQU 8000H ; | ||
| 510 | ; Compatible color display address | ||
| 511 | CCRT@_HI EQU 0BH ; (0B8000H) | ||
| 512 | |||
| 513 | ECCRT@_LO_LO EQU 0000H ; | ||
| 514 | ; Enhanced color display address - | ||
| 515 | ECCRT@_LO_HI EQU 0AH ; lower 64K (0A0000H) | ||
| 516 | |||
| 517 | ECCRT@_HI_LO EQU 0000H ; | ||
| 518 | ; Enhanced color display address - | ||
| 519 | ECCRT@_HI_HI EQU 0CH ; upper 64K (0C0000H) | ||
| 520 | |||
| 521 | |||
| 522 | ; Code segment addresses | ||
| 523 | |||
| 524 | |||
| 525 | CSEG@_LO EQU 0000H ; | ||
| 526 | ; ROM code segment address | ||
| 527 | CSEG@_HI EQU 0EH ; (0E0000H) | ||
| 528 | |||
| 529 | NSEG@_LO EQU 0000H ; | ||
| 530 | ; Null segment address | ||
| 531 | NSEG@_HI EQU 00H ; | ||
| 532 | |||
| 533 | VIRTUAL_ENABLE EQU 0000000000000001B | ||
| 534 | |||
| 535 | SUBTTL | ||
diff --git a/v4.0/src/DEV/XMAEM/INDEDES.MAC b/v4.0/src/DEV/XMAEM/INDEDES.MAC new file mode 100644 index 0000000..68d1776 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEDES.MAC | |||
| @@ -0,0 +1,173 @@ | |||
| 1 | COMMENT # | ||
| 2 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 3 | * * | ||
| 4 | * MODULE NAME : INDEDES * | ||
| 5 | * * | ||
| 6 | * * | ||
| 7 | * 5669-196 (C) COPYRIGHT 1988 Microsoft * | ||
| 8 | * * | ||
| 9 | * DESCRIPTIVE NAME: Macros for setting up 80386 descriptors * | ||
| 10 | * * | ||
| 11 | * STATUS (LEVEL) : Version (0) Level (1.0) * | ||
| 12 | * * | ||
| 13 | * FUNCTION : DESCR_DEF - Define storage for a descriptor * | ||
| 14 | * DESCR_INIT - Initialize a descriptor that has already * | ||
| 15 | * been defined * | ||
| 16 | * * | ||
| 17 | * MODULE TYPE : MAC * | ||
| 18 | * * | ||
| 19 | * REGISTER USAGE : 80286 Standard * | ||
| 20 | * * | ||
| 21 | * CHANGE ACTIVITY : * | ||
| 22 | * * | ||
| 23 | * $MAC(INDEDES) COMP(LOAD) PROD(3270PC) : * | ||
| 24 | * * | ||
| 25 | * $D0=D0004700 410 870604 D : NEW FOR RELEASE 1.1 * | ||
| 26 | * $P1=P0000311 410 870804 D : RENAME MODULE'S LIBRARY FILE TYPE TO "MAC" * | ||
| 27 | * * | ||
| 28 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 29 | # | ||
| 30 | |||
| 31 | ; DESCR_DEF: Define a descriptor in-line using DWs and DBs. | ||
| 32 | ; | ||
| 33 | ; Input: For Segment descriptors, TYPE = SEG. | ||
| 34 | ; For Gate descriptors, TYPE = GATE. | ||
| 35 | ; Other parameters are as described by comments below. | ||
| 36 | ; | ||
| 37 | ; Output: DWs (define words) and DBs (define bytes) using the passed | ||
| 38 | ; values. Useful for copying descriptors directly out of the code | ||
| 39 | ; space, as when their values are forever static. | ||
| 40 | ; | ||
| 41 | ; Example: DESCR_DEF SEG, TSS0_LEN, TSS0_LOC, 0, CPL0_DATA_ACCESS | ||
| 42 | ; | ||
| 43 | ; This defines a segment format (limit/base/access) descriptor | ||
| 44 | ; based on the parameters, which are usually equated values. Note | ||
| 45 | ; that the low word of the address is TSS0_LOC and the high byte | ||
| 46 | ; is 0. | ||
| 47 | |||
| 48 | |||
| 49 | DESCR_DEF MACRO TYPE,PARM1,PARM2,PARM3,ARB | ||
| 50 | |||
| 51 | IFIDN <&TYPE>,<SEG> | ||
| 52 | ; | ||
| 53 | ; Segment descriptor definition | ||
| 54 | ; | ||
| 55 | DW &PARM1 ; Segment limit | ||
| 56 | DW &PARM2 ; Segment base address - low word | ||
| 57 | DB &PARM3 ; Segment base address - high byte | ||
| 58 | DB &ARB ; Access rights byte | ||
| 59 | DW 0 ; Intel reserved | ||
| 60 | |||
| 61 | ENDIF | ||
| 62 | |||
| 63 | IFIDN <&TYPE>,<GATE> | ||
| 64 | ; | ||
| 65 | ; Gate descriptor definition | ||
| 66 | ; | ||
| 67 | DW &PARM1 ; Destination offset | ||
| 68 | DW &PARM2 ; Destination segment selector | ||
| 69 | DB &PARM3 ; Word count for stack-to-stack copy | ||
| 70 | ; (only for call gates when PL changes) | ||
| 71 | DB &ARB ; Access rights byte | ||
| 72 | DW 0 ; Intel reserved | ||
| 73 | |||
| 74 | ENDIF | ||
| 75 | |||
| 76 | ENDM | ||
| 77 | |||
| 78 | PAGE | ||
| 79 | |||
| 80 | ; DESCR_INIT: Initialize a descriptor dynamically. | ||
| 81 | ; | ||
| 82 | ; NOTE: ES must already point to the BASE of table | ||
| 83 | ; where you want the descriptor to go. | ||
| 84 | ; | ||
| 85 | ; | ||
| 86 | ; Input: For Segment descriptors, TYPE = SEG. | ||
| 87 | ; For 4K granularity Segment descriptors, TYPE = BSEG. | ||
| 88 | ; For Gate descriptors, TYPE = GATE. | ||
| 89 | ; If the FIELD parameter is supplied, a MOV DI,FIELD is generated. | ||
| 90 | ; Otherwise, its current value is used. Other parameters are as | ||
| 91 | ; described by comments below. | ||
| 92 | ; | ||
| 93 | ; | ||
| 94 | ; Output: DI ends up as DI + 8 (i.e. pointing at next descriptor. This | ||
| 95 | ; is useful if you are initializing several consecutive | ||
| 96 | ; descriptors). | ||
| 97 | ; | ||
| 98 | ; The passed data is stored at ES:DI using string store. This | ||
| 99 | ; macro would be used when creating descriptors dynamically, as | ||
| 100 | ; when allocating virtual machines. | ||
| 101 | ; | ||
| 102 | ; Example: DESCR_INIT GATE,INT13_PTR,INT13_IP,INT13_CS,0,TRAP_GATE_ACCESS | ||
| 103 | ; | ||
| 104 | ; This stores the parameters in gate format (offset/ selector/word | ||
| 105 | ; count/access) through ES:DI, where DI is first loaded with | ||
| 106 | ; INT13_PTR. | ||
| 107 | |||
| 108 | |||
| 109 | DESCR_INIT MACRO TYPE,FIELD,PARM1,PARM2,PARM3,ARB | ||
| 110 | |||
| 111 | PUSH AX ; Save the utility register | ||
| 112 | |||
| 113 | IFNB <&FIELD> | ||
| 114 | |||
| 115 | MOV DI,&FIELD ; Set up index value to proper descriptor | ||
| 116 | ADD DI,GDT_LOC | ||
| 117 | |||
| 118 | ENDIF | ||
| 119 | |||
| 120 | |||
| 121 | IFIDN <&TYPE>,<SEG> | ||
| 122 | ; | ||
| 123 | ; Segment descriptor initialization | ||
| 124 | ; | ||
| 125 | MOV AX,&PARM1 ; PARM1 = Segment Limit; load into AX | ||
| 126 | STOSW ; and store | ||
| 127 | MOV AX,&PARM2 ; PARM2 = BASE_LO_W; load into AX | ||
| 128 | STOSW ; and store | ||
| 129 | MOV AL,&PARM3 ; PARM3 = BASE_HI_B; load into AL, and | ||
| 130 | MOV AH,&ARB ; ARB = Access Rights Byte; load into AH | ||
| 131 | STOSW ; and store both | ||
| 132 | MOV AX,0 ; Make sure the Intel | ||
| 133 | STOSW ; reserved word is zero | ||
| 134 | |||
| 135 | ENDIF | ||
| 136 | |||
| 137 | |||
| 138 | IFIDN <&TYPE>,<BSEG> | ||
| 139 | ; | ||
| 140 | ; Big (4k granularity) segment descriptor initialization | ||
| 141 | ; | ||
| 142 | MOV AX,&PARM1 ; PARM1 = Segment Limit; load into AX | ||
| 143 | STOSW ; and store | ||
| 144 | MOV AX,&PARM2 ; PARM2 = BASE_LO_W; load into AX | ||
| 145 | STOSW ; and store | ||
| 146 | MOV AL,&PARM3 ; PARM3 = BASE_HI_B; load into AL, and | ||
| 147 | MOV AH,&ARB ; ARB = Access Rights Byte; load into AH | ||
| 148 | STOSW ; and store both | ||
| 149 | MOV AX,0080H ; 4k granularity bit | ||
| 150 | STOSW | ||
| 151 | |||
| 152 | ENDIF | ||
| 153 | |||
| 154 | |||
| 155 | IFIDN <&TYPE>,<GATE> | ||
| 156 | ; | ||
| 157 | ; Gate descriptor initialization | ||
| 158 | ; | ||
| 159 | MOV AX,&PARM1 ; PARM1 = Destination offset; load into AX | ||
| 160 | STOSW ; and store | ||
| 161 | MOV AX,&PARM2 ; PARM2 = Destination Selector;load into AX | ||
| 162 | STOSW ; and store | ||
| 163 | MOV AL,&PARM3 ; PARM3 = Word Count; load into AL, and | ||
| 164 | MOV AH,&ARB ; ARB = Access Rights Byte; load into AH | ||
| 165 | STOSW ; and store both | ||
| 166 | MOV AX,0 ; Make sure the Intel | ||
| 167 | STOSW ; reserved word is zero | ||
| 168 | |||
| 169 | ENDIF | ||
| 170 | |||
| 171 | POP AX ; Restore AX | ||
| 172 | |||
| 173 | ENDM | ||
diff --git a/v4.0/src/DEV/XMAEM/INDEDMA.ASM b/v4.0/src/DEV/XMAEM/INDEDMA.ASM new file mode 100644 index 0000000..84d73dc --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEDMA.ASM | |||
| @@ -0,0 +1,660 @@ | |||
| 1 | PAGE 60,132 | ||
| 2 | TITLE INDEDMA - 386 XMA Emulator - DMA Emulation | ||
| 3 | |||
| 4 | COMMENT # | ||
| 5 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 6 | * * | ||
| 7 | * MODULE NAME : INDEDMA * | ||
| 8 | * * | ||
| 9 | * * | ||
| 10 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corporation * | ||
| 11 | * * | ||
| 12 | * DESCRIPTIVE NAME: DMA handler for the 80386 XMA emulator * | ||
| 13 | * * | ||
| 14 | * STATUS (LEVEL) : Version (0) Level (1.0) * | ||
| 15 | * * | ||
| 16 | * FUNCTION : This module intercepts any I/O going to the DMA address * | ||
| 17 | * ports. We can't let the DMA requests go to the virtual * | ||
| 18 | * addresses. On the real XMA card the addresses on the * | ||
| 19 | * bus lines are translated by the card so that it accesses * | ||
| 20 | * the correct memory. But with our emulation the addresses * | ||
| 21 | * are translated before they hit the bus lines. The DMA * | ||
| 22 | * addresses go straight to the bus lines without being * | ||
| 23 | * translated. This would result in DMA reading and writing * | ||
| 24 | * data to the wrong memory location. Not good. Therefore * | ||
| 25 | * we intercept the I/O that is going to the DMA address * | ||
| 26 | * ports. We run these addresses through our paging mech- * | ||
| 27 | * anism and then write the real addresses to the DMA * | ||
| 28 | * address ports. * | ||
| 29 | * * | ||
| 30 | * MODULE TYPE : ASM * | ||
| 31 | * * | ||
| 32 | * REGISTER USAGE : 80386 Standard * | ||
| 33 | * * | ||
| 34 | * RESTRICTIONS : None * | ||
| 35 | * * | ||
| 36 | * DEPENDENCIES : None * | ||
| 37 | * * | ||
| 38 | * ENTRY POINTS : DMAIN - Entry point for "IN" instructions * | ||
| 39 | * DMAOUT - Entry point for "OUT" instructions * | ||
| 40 | * MANPORT - Entry point to issue an OUT to the manufacturing* | ||
| 41 | * port to re-IPL the system * | ||
| 42 | * * | ||
| 43 | * LINKAGE : Jumped to by INDEXMA * | ||
| 44 | * * | ||
| 45 | * INPUT PARMS : None * | ||
| 46 | * * | ||
| 47 | * RETURN PARMS : None * | ||
| 48 | * * | ||
| 49 | * OTHER EFFECTS : None * | ||
| 50 | * * | ||
| 51 | * EXIT NORMAL : Jump to POPIO to return to the V86 task * | ||
| 52 | * * | ||
| 53 | * EXIT ERROR : None * | ||
| 54 | * * | ||
| 55 | * EXTERNAL * | ||
| 56 | * REFERENCES : DISPLAY - Entry point in INDEEXC to signal an error * | ||
| 57 | * POPIO - Entry point in INDEEMU to return to the V86 * | ||
| 58 | * task * | ||
| 59 | * PGTBLOFF - Word in INDEI15 that contains the offset of * | ||
| 60 | * the page tables * | ||
| 61 | * SGTBLOFF - Word in INDEI15 that contains the offset of * | ||
| 62 | * the page directory * | ||
| 63 | * NORMPAGE - Double Word in INDEI15 that contains the * | ||
| 64 | * entry that goes into the first page directory * | ||
| 65 | * entry so that it points to the normal page * | ||
| 66 | * tables * | ||
| 67 | * BUFF_SIZE - Word in INDEI15 that contains the size of the * | ||
| 68 | * MOVEBLOCK buffer * | ||
| 69 | * MAXMEM - Word in INDEI15 that contains the total * | ||
| 70 | * number of K in the box * | ||
| 71 | * WORD_FLAG - Byte in INDEXMA that indicates whether the * | ||
| 72 | * I/O instruction was for a word or a byte * | ||
| 73 | * * | ||
| 74 | * SUB-ROUTINES : XLATE - Translate the virtual DMA address to a real DMA * | ||
| 75 | * address * | ||
| 76 | * * | ||
| 77 | * MACROS : DATAOV - Add prefix for the next instruction so that it * | ||
| 78 | * accesses data as 32 bits wide * | ||
| 79 | * ADDROV - Add prefix for the next instruction so that it * | ||
| 80 | * uses addresses that are 32 bits wide * | ||
| 81 | * LJB - Long jump if below * | ||
| 82 | * LJA - Long jump if above * | ||
| 83 | * LJAE - Long jump if above or equal * | ||
| 84 | * LJNE - Long jump if not equal * | ||
| 85 | * * | ||
| 86 | * CONTROL BLOCKS : INDEDAT.INC - System data structures * | ||
| 87 | * * | ||
| 88 | * CHANGE ACTIVITY : * | ||
| 89 | * * | ||
| 90 | * $MOD(INDEDMA) COMP(LOAD) PROD(3270PC) : * | ||
| 91 | * * | ||
| 92 | * $D0=D0004700 410 870101 D : NEW FOR RELEASE 1.1 * | ||
| 93 | * $P1=P0000312 410 870804 D : CLEAN UP WARNING MESSAGES * | ||
| 94 | * * | ||
| 95 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 96 | # | ||
| 97 | |||
| 98 | .286P ; Enable recognition of 286 privileged instructs. | ||
| 99 | |||
| 100 | .XLIST ; Turn off the listing | ||
| 101 | INCLUDE INDEDAT.INC ; Include system data structures and equates | ||
| 102 | |||
| 103 | IF1 ; Only include macros on the first pass | ||
| 104 | INCLUDE INDEOVP.MAC ; Override prefix macros | ||
| 105 | INCLUDE INDEINS.MAC ; 386 instruction macros | ||
| 106 | ENDIF | ||
| 107 | .LIST ; Turn the listing back on | ||
| 108 | |||
| 109 | PROG SEGMENT PARA PUBLIC 'PROG' | ||
| 110 | |||
| 111 | ASSUME CS:PROG | ||
| 112 | ASSUME DS:PROG | ||
| 113 | ASSUME ES:NOTHING | ||
| 114 | ASSUME SS:NOTHING | ||
| 115 | |||
| 116 | INDEDMA LABEL NEAR | ||
| 117 | |||
| 118 | EXTRN DISPLAY:NEAR ; Entry point in INDEEXC to signal an error | ||
| 119 | EXTRN POPIO:NEAR ; Entry point in INDEEMU to return to the V86 | ||
| 120 | ; task | ||
| 121 | EXTRN PGTBLOFF:WORD ; Word in INDEI15 that contains the offset of | ||
| 122 | ; the page tables | ||
| 123 | EXTRN SGTBLOFF:WORD ; Word in INDEI15 that contains the offset of | ||
| 124 | ; the page directory | ||
| 125 | EXTRN NORMPAGE:WORD ; Double Word in INDEI15 that contains the | ||
| 126 | ; entry that goes into the first page direct- | ||
| 127 | ; ory entry so that it points to the normal | ||
| 128 | ; page tables | ||
| 129 | EXTRN BUFF_SIZE:WORD ; Word in INDEI15 that contains the size of the | ||
| 130 | ; MOVEBLOCK buffer | ||
| 131 | EXTRN MAXMEM:WORD ; Word in INDEI15 that contains the total | ||
| 132 | ; number of K in the box | ||
| 133 | EXTRN WORD_FLAG:BYTE ; Byte in INDEXMA that indicates whether the | ||
| 134 | ; I/O instruction was for a word or a byte | ||
| 135 | |||
| 136 | ; Let these entry points be known to other modules | ||
| 137 | |||
| 138 | PUBLIC INDEDMA | ||
| 139 | PUBLIC DMAIN | ||
| 140 | PUBLIC DMAOUT | ||
| 141 | PUBLIC MANPORT | ||
| 142 | |||
| 143 | PAGE | ||
| 144 | |||
| 145 | ; Define control blocks for each of the DMA channels 0 to 7. The control | ||
| 146 | ; blocks have information on where the user wanted to do DMA, where we will | ||
| 147 | ; actually do the DMA, the channel number and the page port. The following | ||
| 148 | ; is an overlay for the control blocks. After that the actual control | ||
| 149 | ; blocks are defined. | ||
| 150 | |||
| 151 | DMACB STRUC ; DMA control block | ||
| 152 | |||
| 153 | DMACHN DB 0 ; Channel number | ||
| 154 | DMALSB DB 0 ; Least significant address byte | ||
| 155 | DMAMSB DB 0 ; Most significant address byte (16 bits) | ||
| 156 | DMAPAGE DB 0 ; Page - Hi-order of 24-bit address | ||
| 157 | DMALR DB 0 ; Real Least significant address byte | ||
| 158 | DMAMR DB 0 ; Real Most significant address byte (16 bits) | ||
| 159 | DMAPR DB 0 ; Real Page - Hi-order of 24-bit address | ||
| 160 | DMAPP DB 0 ; Compatability mode page port | ||
| 161 | |||
| 162 | DMACB ENDS | ||
| 163 | |||
| 164 | DMASTART EQU 0 | ||
| 165 | DMAENTRYLEN EQU DMAPP+1-DMASTART | ||
| 166 | |||
| 167 | ; Now, the channel control blocks | ||
| 168 | |||
| 169 | DMATABLE DB 0 ; Channel number | ||
| 170 | DB DMAENTRYLEN-2 DUP (0) ; The other stuff | ||
| 171 | DB 87H ; Page port | ||
| 172 | |||
| 173 | DB 1 ; Channel number | ||
| 174 | DB DMAENTRYLEN-2 DUP (0) ; The other stuff | ||
| 175 | DB 83H ; Page port | ||
| 176 | |||
| 177 | DB 2 ; Channel number | ||
| 178 | DB DMAENTRYLEN-2 DUP (0) ; The other stuff | ||
| 179 | DB 81H ; Page port | ||
| 180 | |||
| 181 | DB 3 ; Channel number | ||
| 182 | DB DMAENTRYLEN-2 DUP (0) ; The other stuff | ||
| 183 | DB 82H ; Page port | ||
| 184 | |||
| 185 | DB 4 ; Channel number | ||
| 186 | DB DMAENTRYLEN-2 DUP (0) ; The other stuff | ||
| 187 | DB 8FH ; Page port | ||
| 188 | |||
| 189 | DB 5 ; Channel number | ||
| 190 | DB DMAENTRYLEN-2 DUP (0) ; The other stuff | ||
| 191 | DB 8BH ; Page port | ||
| 192 | |||
| 193 | DB 6 ; Channel number | ||
| 194 | DB DMAENTRYLEN-2 DUP (0) ; The other stuff | ||
| 195 | DB 89H ; Page port | ||
| 196 | |||
| 197 | DB 7 ; Channel number | ||
| 198 | DB DMAENTRYLEN-2 DUP (0) ; The other stuff | ||
| 199 | DB 8AH ; Page port | ||
| 200 | |||
| 201 | ; And now some more variables | ||
| 202 | |||
| 203 | DMACURRENT DB 0 ; Channel we're working on | ||
| 204 | DMABYTE DB 0 ; This flag is toggled between 0 and 1 | ||
| 205 | ; to indicated whether the least | ||
| 206 | ; significant or most significant byte | ||
| 207 | ; of the DMA address is being written | ||
| 208 | DMA_ADV_CHN DB 0 ; Advanced mode channel number | ||
| 209 | |||
| 210 | PAGE | ||
| 211 | |||
| 212 | ; Define the jump table. There are 32 entries in the table that correspond to | ||
| 213 | ; the first 32 ports, 0 to 20H. The code uses the port number as an index into | ||
| 214 | ; this table which then gives control to the appropriate routine for that port. | ||
| 215 | ; The table is initialized so that all entries jump to the code that will pass | ||
| 216 | ; the I/O back to the real port. Then the entries for the ports we want to | ||
| 217 | ; handle are set to the corresponding routines for those ports. | ||
| 218 | |||
| 219 | OUT_TABLE: | ||
| 220 | .XLIST | ||
| 221 | REPT 32 | ||
| 222 | JMP DOOUT | ||
| 223 | ENDM | ||
| 224 | .LIST | ||
| 225 | OUT_TABLE_END: | ||
| 226 | |||
| 227 | ; Set the entries for the ports we want to handle. | ||
| 228 | |||
| 229 | ORG OUT_TABLE+(00H*3) | ||
| 230 | JMP CHN_0 | ||
| 231 | ORG OUT_TABLE+(02H*3) | ||
| 232 | JMP CHN_1 | ||
| 233 | ORG OUT_TABLE+(04H*3) | ||
| 234 | JMP CHN_2 | ||
| 235 | ORG OUT_TABLE+(06H*3) | ||
| 236 | JMP CHN_3 | ||
| 237 | ORG OUT_TABLE+(0CH*3) | ||
| 238 | JMP RESET_BYTE_PTR | ||
| 239 | ORG OUT_TABLE+(18H*3) | ||
| 240 | JMP CHK_FUNCTION | ||
| 241 | ORG OUT_TABLE+(1AH*3) | ||
| 242 | JMP CHK_BASE_REG | ||
| 243 | |||
| 244 | ORG OUT_TABLE_END | ||
| 245 | |||
| 246 | PAGE | ||
| 247 | |||
| 248 | ; Control comes here from INDEXMA when it determines that the "IN" instruction | ||
| 249 | ; is not for one of the XMA ports. On entry, WORD_FLAG is already set for word | ||
| 250 | ; or byte operation. IP points to next instruction minus 1. DX has the port | ||
| 251 | ; value in it. | ||
| 252 | |||
| 253 | DMAIN PROC NEAR | ||
| 254 | CMP WORD_FLAG,0 ; Is this "IN" for a word? | ||
| 255 | JNE GETWORDREAL ; Yes. Then go get a word. | ||
| 256 | |||
| 257 | IN AL,DX ; Else we'll just get a byte | ||
| 258 | MOV BYTE PTR SS:[BP+BP_AX],AL ; And put it into the user's AL reg. | ||
| 259 | JMP INEXIT ; Go return to the user | ||
| 260 | |||
| 261 | GETWORDREAL: | ||
| 262 | IN AX,DX ; Get a word from the port | ||
| 263 | MOV WORD PTR SS:[BP+BP_AX],AX ; Put it into the user's AX register | ||
| 264 | MOV WORD_FLAG,0 ; Reset the word flag | ||
| 265 | |||
| 266 | INEXIT: | ||
| 267 | ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past the instruction, or past | ||
| 268 | ; the port value in the case of I/O | ||
| 269 | ; with an immediate port value | ||
| 270 | JMP POPIO ; Return to the V86 task | ||
| 271 | |||
| 272 | PAGE | ||
| 273 | |||
| 274 | ; Control comes here from INDEXMA when it determines that the "OUT" instruction | ||
| 275 | ; is not for one of the XMA ports. On entry, WORD_FLAG is already set for word | ||
| 276 | ; or byte operation. IP points to next instruction minus 1. DX has the port | ||
| 277 | ; value in it. | ||
| 278 | |||
| 279 | DMAOUT: | ||
| 280 | |||
| 281 | ; Check for DMA page registers in compatibility mode | ||
| 282 | |||
| 283 | MOV AX,SYS_PATCH_DS ; Load DS with the selector for our data | ||
| 284 | MOV DS,AX ; segment | ||
| 285 | CMP WORD_FLAG,0 ; Is this a word operation? | ||
| 286 | LJNE DISPLAY ; No? Sorry. We don't support word DMA | ||
| 287 | ; yet. We'll just have to signal an | ||
| 288 | ; error. | ||
| 289 | LEA BX,DMATABLE ; Point BX to the base of our channel | ||
| 290 | ; control blocks | ||
| 291 | CMP DX,0081H ; Is this out to the channel 2 page port | ||
| 292 | LJB NOT_DMA_PAGE ; If the port number is less than 81H | ||
| 293 | ; then the "OUT" is not to a DMA page | ||
| 294 | JA CHK_CHN_0 ; If the port number is above 81H, then | ||
| 295 | ; go check if it's below 87H, the page | ||
| 296 | ; port for channel 0 | ||
| 297 | ADD BX,DMAENTRYLEN*2 ; If it's not below or above, then it | ||
| 298 | ; must be port 81H! Point BX to the | ||
| 299 | ; control block for channel 2 | ||
| 300 | JMP CHNCOM ; Continue | ||
| 301 | |||
| 302 | CHK_CHN_0: | ||
| 303 | CMP DX,0087H ; Is it the page port for channel 0? | ||
| 304 | JA CHK680 ; Nope. It's above that. Go check for | ||
| 305 | ; the Roundup IPL port | ||
| 306 | JE CHNCOM ; It IS the page port for channel 0. | ||
| 307 | ; BX already points to the control | ||
| 308 | ; block for channel 0. | ||
| 309 | CMP DX,0083H ; Is it the page port for channel 1? | ||
| 310 | JB SET_CHN_3 ; No. It's below that. Then it must | ||
| 311 | ; be the page port for channel 3! | ||
| 312 | LJA DISPLAY ; No. It's above it. We don't know any | ||
| 313 | ; ports between 83H and 87H. Go | ||
| 314 | ; signal an error. | ||
| 315 | ADD BX,DMAENTRYLEN*1 ; Yes. It's the page port for channel 1 | ||
| 316 | ; Point BX to the control block for | ||
| 317 | ; channel 1. | ||
| 318 | JMP CHNCOM ; And continue | ||
| 319 | |||
| 320 | ; The port is greater than 87H | ||
| 321 | |||
| 322 | CHK680: | ||
| 323 | CMP DX,680H ; Is it the manufacturing port (for IPL) | ||
| 324 | ; on the Roundup? | ||
| 325 | JE MANPORT ; Yes. Go IPL the system. | ||
| 326 | JMP DOOUT ; No. Pass the "OUT" on to the real | ||
| 327 | ; port. | ||
| 328 | |||
| 329 | ; The "OUT" is to the page port for channel 3 | ||
| 330 | |||
| 331 | SET_CHN_3: | ||
| 332 | ADD BX,DMAENTRYLEN*3 ; Point BX to the control block for | ||
| 333 | ; channel 3 | ||
| 334 | |||
| 335 | ; Check to see if the value written to the page port is greater than 0FH. | ||
| 336 | ; Why? Let me tell you. Addresses are 20 bits, right? The user puts the | ||
| 337 | ; lower 16 bits into the channel port in two eight bit writes. The value | ||
| 338 | ; written to the page port is the upper eight bits of the address. But to | ||
| 339 | ; address 1M you only need 20 bits. Therefore, only the lower four bits are | ||
| 340 | ; valid if the address is to remain within the 1M address limit. So if the | ||
| 341 | ; value to be written to the page port is 10H or greater it is invalid, so | ||
| 342 | ; we will signal an error. | ||
| 343 | |||
| 344 | CHNCOM: | ||
| 345 | MOV AL,BYTE PTR SS:[BP+BP_AX] ; Get the value that is to be written | ||
| 346 | ; to the page port | ||
| 347 | CMP AL,10H ; Is it 10H or greater? | ||
| 348 | JB CHNCONT ; Nope. We're still OK. | ||
| 349 | |||
| 350 | ; Oops. It's an invalid page port value. Time to signal an error. But wait. | ||
| 351 | ; If we just jump to DISPLAY as usual the code will just return to the V86 | ||
| 352 | ; task. This is not good since we haven't Revised the DMA and it will end | ||
| 353 | ; up going to the wrong address. What we really want to do is kill the system. | ||
| 354 | ; To do this we will issue an interrupt 6, invalid instruction. The exception | ||
| 355 | ; handler checks to see from whence the interrupt came. If it came from the | ||
| 356 | ; emulator then it assumes something is terribly wrong and issues an NMI. | ||
| 357 | ; This is what we want. So we'll issue an INT 6 instead of a JMP DISPLAY. | ||
| 358 | |||
| 359 | INVALID_PAGE: | ||
| 360 | INT 6 ; Signal and error | ||
| 361 | JMP INVALID_PAGE ; Do it again in case control comes | ||
| 362 | ; back here | ||
| 363 | |||
| 364 | ; At this point were still OK. BX points to the control block for the channel. | ||
| 365 | ; Let's translate the address we currently have to its real address and send | ||
| 366 | ; it out to the DMA channel. | ||
| 367 | |||
| 368 | CHNCONT: | ||
| 369 | MOV BYTE PTR [BX+DMAPAGE],AL ; Put the page port value into the | ||
| 370 | ; control block | ||
| 371 | CALL XLATE ; Create the real address entries in | ||
| 372 | ; the control block | ||
| 373 | MOV DL,BYTE PTR [BX+DMACHN] ; Get the channel number from the c.b. | ||
| 374 | SHL DX,1 ; Convert it to a port address | ||
| 375 | MOV AL,BYTE PTR [BX+DMALR] ; Get the LSB of the real address | ||
| 376 | OUT DX,AL ; "OUT" it to the address port | ||
| 377 | JMP $+2 ; Wait a bit | ||
| 378 | MOV AL,BYTE PTR [BX+DMAMR] ; Get the MSB of the real address | ||
| 379 | OUT DX,AL ; "OUT" it to the address port | ||
| 380 | JMP $+2 ; Wait a bit | ||
| 381 | MOV DL,BYTE PTR [BX+DMAPP] ; Get the page port | ||
| 382 | MOV AL,BYTE PTR [BX+DMAPR] ; Get the real page number | ||
| 383 | OUT DX,AL ; Do the "OUT" to the DMA page port | ||
| 384 | JMP OUTEXITDMA ; That's it | ||
| 385 | |||
| 386 | PAGE | ||
| 387 | |||
| 388 | ; This is where we come when we want to simply send the "OUT" to the real port. | ||
| 389 | |||
| 390 | DOOUT: | ||
| 391 | CMP WORD_FLAG,0 ; Is this an "OUT" for a word? | ||
| 392 | JNE PUTWORDREAL ; Aye. Go put out a word. | ||
| 393 | |||
| 394 | MOV AL,BYTE PTR SS:[BP+BP_AX] ; Nay. It is for a byte. Get the | ||
| 395 | ; byte from the user's AL register | ||
| 396 | OUT DX,AL ; And send it out to the port | ||
| 397 | JMP OUTEXITDMA ; Time to leave | ||
| 398 | |||
| 399 | PUTWORDREAL: | ||
| 400 | MOV AX,WORD PTR SS:[BP+BP_AX] ; Get the word form the user's AX | ||
| 401 | OUT DX,AX ; And thrust it out to the port | ||
| 402 | MOV WORD_FLAG,0 ; Reset the word flag | ||
| 403 | |||
| 404 | OUTEXITDMA: | ||
| 405 | |||
| 406 | ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past the instruction, or past | ||
| 407 | ; the port value in the case of I/O | ||
| 408 | ; with an immediate port value | ||
| 409 | JMP POPIO ; Return to the V86 task | ||
| 410 | |||
| 411 | PAGE | ||
| 412 | |||
| 413 | ; It's not an "OUT" to one of the DMA page ports. | ||
| 414 | |||
| 415 | NOT_DMA_PAGE: | ||
| 416 | CMP DX,(OUT_TABLE_END-OUT_TABLE)/3 ; Is the port within the range | ||
| 417 | ; covered by our jump table, i.e., | ||
| 418 | ; 0 to 20H | ||
| 419 | JAE NOTCOWBOY ; Nope. Let's go check if it's the IPL | ||
| 420 | ; port on the AT | ||
| 421 | MOV AL,DL ; Yes, it's handled by our jump table | ||
| 422 | MOV AH,3 ; Convert the port number to an index | ||
| 423 | MUL AH ; into the jump table by multiplying | ||
| 424 | ; by 3. Jump table entry are 3 bytes. | ||
| 425 | LEA CX,OUT_TABLE ; Get the offset of the jump table | ||
| 426 | ADD AX,CX ; And add it on to the index | ||
| 427 | JMP AX ; Jump to the jump table entry for this | ||
| 428 | ; port | ||
| 429 | |||
| 430 | NOTCOWBOY: | ||
| 431 | CMP DX,80H ; Is it the manufacturing (IPL) port for | ||
| 432 | ; the AT? | ||
| 433 | JNE DOOUT ; Negative. Then let's just do a plain | ||
| 434 | ; vanilla "OUT" to the real port. | ||
| 435 | MANPORT: | ||
| 436 | MOV AL,0FEH ; It's the IPL port! Send out a FEH to | ||
| 437 | OUT 064H,AL ; reset the system. | ||
| 438 | |||
| 439 | HALT: HLT ; In case that trick didn't work @P1C | ||
| 440 | JMP HALT ; we'll just wait here until @P1C | ||
| 441 | ; somebody hits the big red switch. | ||
| 442 | |||
| 443 | PAGE | ||
| 444 | |||
| 445 | ; This is the entry for an "OUT" to port 0CH. An "OUT" to this port will | ||
| 446 | ; reset the controller so that the next out will be to the least significant | ||
| 447 | ; byte of the address register. The way you set the lower 16 bits of the | ||
| 448 | ; address is by sending the two bytes to the same port, first the least | ||
| 449 | ; significant byte (LSB) and then the most significant byte (MSB). The port | ||
| 450 | ; knows that successive bytes to the port mean successively higher bytes of | ||
| 451 | ; the address. We emulate this with our DMABYTE flag. Since the user will | ||
| 452 | ; only be sending two bytes to an address port this flag will be toggled | ||
| 453 | ; between 0 and 1 indicating that the "OUT" was to the LSB if 0 and to the | ||
| 454 | ; MSB if 1. A write to port 0CH tells the controller that the next write | ||
| 455 | ; will be for the LSB. We emulate this by setting our DMABYTE flag to 0. | ||
| 456 | |||
| 457 | RESET_BYTE_PTR: | ||
| 458 | MOV DMABYTE,0 ; Reset the byte flag | ||
| 459 | JMP DOOUT ; Send the "OUT" to the real port | ||
| 460 | |||
| 461 | PAGE | ||
| 462 | |||
| 463 | ; The following entries handle the "OUT"s to the address ports for channels | ||
| 464 | ; 0 to 3. These are ports 00, 02, 04 and 06 respectively. As mentioned | ||
| 465 | ; above the address written to these ports is done in two steps. First the | ||
| 466 | ; least significant byte (LSB) is written, the the most significant byte (MSB) | ||
| 467 | ; is written. This results in a 16 bit value in the address port. Combine | ||
| 468 | ; this with the byte in the page port and you have a 24 bit DMA address. The | ||
| 469 | ; code below emulates this by putting the byte that is "OUT"ed to the LSB if | ||
| 470 | ; DMA BYTE is 0 and to the MSB if DMABYTE is 1. DMABYTE is toggled between 0 | ||
| 471 | ; and 1 each time there is a write to the port. So the bytes go alternately | ||
| 472 | ; to the LSB and the MSB. | ||
| 473 | |||
| 474 | ; "OUT" is to port 00, the address port for channel 0. | ||
| 475 | |||
| 476 | CHN_0: | ||
| 477 | LEA BX,DMATABLE ; Point BX to the control block for | ||
| 478 | ; channel 0 | ||
| 479 | JMP MOVBYTE ; Go get the byte | ||
| 480 | |||
| 481 | ; "OUT" is to port 02, the address port for channel 1. | ||
| 482 | |||
| 483 | CHN_1: | ||
| 484 | LEA BX,DMATABLE+(1*DMAENTRYLEN) ; Point BX to the control block for | ||
| 485 | ; channel 1 | ||
| 486 | JMP MOVBYTE ; Go get the byte | ||
| 487 | |||
| 488 | ; "OUT" is to port 04, the address port for channel 2. | ||
| 489 | |||
| 490 | CHN_2: | ||
| 491 | LEA BX,DMATABLE+(2*DMAENTRYLEN) ; Point BX to the control block for | ||
| 492 | ; channel 2 | ||
| 493 | JMP MOVBYTE ; Go get the byte | ||
| 494 | |||
| 495 | ; "OUT" is to port 06, the address port for channel 3. | ||
| 496 | |||
| 497 | CHN_3: | ||
| 498 | LEA BX,DMATABLE+(3*DMAENTRYLEN) ; Point BX to the control block for | ||
| 499 | ; channel 3 | ||
| 500 | |||
| 501 | MOVBYTE: | ||
| 502 | MOV AL,BYTE PTR SS:[BP+BP_AX] ; Get the byte from the user's AL | ||
| 503 | XOR DMABYTE,1 ; Toggle the DMABYTE flag | ||
| 504 | JZ MOVMSB ; Was the flag set to 1? If so, go | ||
| 505 | ; put the byte to the MSB | ||
| 506 | MOV BYTE PTR [BX+DMALSB],AL ; Else it was 0 so put the byte in the | ||
| 507 | ; LSB for this channel | ||
| 508 | JMP OUTEXITDMA ; And exit | ||
| 509 | |||
| 510 | MOVMSB: | ||
| 511 | MOV BYTE PTR [BX+DMAMSB],AL ; Put the byte in the MSB for this | ||
| 512 | ; channel | ||
| 513 | JMP OUTEXITDMA ; And exit | ||
| 514 | |||
| 515 | PAGE | ||
| 516 | |||
| 517 | ; This is the entry point for an "OUT" to port 18H. It has something to do | ||
| 518 | ; with the advanced DMA channels 4 thru 7. If the function number in the high | ||
| 519 | ; nibble of AL is 2, set the base register, then we'll save the advanced channel | ||
| 520 | ; number given in the low nibble of AL. If the function is not 2 then we will | ||
| 521 | ; inhibit the setting of the base register. | ||
| 522 | |||
| 523 | CHK_FUNCTION: | ||
| 524 | MOV AL,BYTE PTR SS:[BP+BP_AX] ; Get the value to be "OUT"ed to 18H | ||
| 525 | SHR AL,4 ; Shift the function number into AL | ||
| 526 | CMP AL,2 ; Is this the function to set the base | ||
| 527 | ; register? | ||
| 528 | JE SAVE_CHN ; Yup. Go save the channel number. | ||
| 529 | MOV DMABYTE,3 ; Nope. Inhibit setting the base reg. | ||
| 530 | JMP DOOUT ; Send the "OUT" to the real port | ||
| 531 | |||
| 532 | SAVE_CHN: | ||
| 533 | MOV AL,BYTE PTR SS:[BP+BP_AX] ; Get the value in AL again | ||
| 534 | AND AL,07H ; Mask off the function number leaving | ||
| 535 | ; the channel number | ||
| 536 | MOV DMA_ADV_CHN,AL ; And save it | ||
| 537 | JMP RESET_BYTE_PTR ; Go reset the byte flag | ||
| 538 | |||
| 539 | PAGE | ||
| 540 | |||
| 541 | ; This is the entry for an "OUT" to port 1AH. | ||
| 542 | |||
| 543 | CHK_BASE_REG: | ||
| 544 | CMP DMABYTE,3 ; Are we inhibiting setting the base | ||
| 545 | ; register? | ||
| 546 | LJAE DOOUT ; Yes. Then just sent the "OUT" to the | ||
| 547 | ; real port | ||
| 548 | LEA BX,DMATABLE ; Point BX to the channel control blocks | ||
| 549 | MOV AL,DMA_ADV_CHN ; Get the current advanced channel | ||
| 550 | MOV AH,DMAENTRYLEN ; and multiply by the size of a | ||
| 551 | MUL AH ; control block. Now AX is the index | ||
| 552 | ; for the current control block | ||
| 553 | ADD BX,AX ; Add this on to the base and BX points | ||
| 554 | ; to the control block | ||
| 555 | SUB AX,AX ; Purge AX | ||
| 556 | MOV AL,DMABYTE ; Get the byte flag | ||
| 557 | ADD BX,AX ; And add it on to BX | ||
| 558 | MOV CL,BYTE PTR SS:[BP+BP_AX] ; Get the out value into CL | ||
| 559 | |||
| 560 | ; Now put it in the control block. Notice that BX is the base of the control | ||
| 561 | ; block plus the byte flag. Now we add on the offset for the LSB entry. A | ||
| 562 | ; little pondering of this code will reveal that for DMABYTE = 0 the byte in | ||
| 563 | ; CL goes to the LSB entry, for DMABYTE = 1 it goes to the MSB entry and for | ||
| 564 | ; DMABYTE = 2 it goes to the page entry. | ||
| 565 | |||
| 566 | MOV BYTE PTR [BX+DMALSB],CL ; Save the byte in the control block | ||
| 567 | INC DMABYTE ; Increment our byte counter | ||
| 568 | CMP DMABYTE,3 ; Was the page entry written? | ||
| 569 | LJNE OUTEXITDMA ; Nope. Let's just exit. | ||
| 570 | |||
| 571 | SUB BX,AX ; The page was written. Point BX back | ||
| 572 | ; to the start of the control block. | ||
| 573 | CMP CL,10H ; Does the page point to over 1M? | ||
| 574 | LJAE INVALID_PAGE ; Yes. Better signal an error. | ||
| 575 | |||
| 576 | CALL XLATE ; The page is OK. Translate the virtual | ||
| 577 | ; address to the real address | ||
| 578 | MOV AL,BYTE PTR [BX+DMALR] ; Get the LSB of the real address | ||
| 579 | OUT 1AH,AL ; "OUT" it to the port 1AH | ||
| 580 | JMP $+2 ; Wait a bit | ||
| 581 | MOV AL,BYTE PTR [BX+DMAMR] ; Get the MSB of the real address | ||
| 582 | OUT 1AH,AL ; "OUT" it to the port 1AH | ||
| 583 | JMP $+2 ; Wait a bit | ||
| 584 | MOV AL,BYTE PTR [BX+DMAPR] ; Get the real page number | ||
| 585 | OUT 1AH,AL ; Do the "OUT" to port 1AH | ||
| 586 | JMP OUTEXITDMA ; That's all | ||
| 587 | |||
| 588 | PAGE | ||
| 589 | |||
| 590 | ; XLATE is a procedure to translate the virtual DMA address to the real DMA | ||
| 591 | ; address. It takes the virtual address that was "OUT"ed to the DMA ports | ||
| 592 | ; and follows it through the page tables to get the real address. It puts | ||
| 593 | ; the real address into the current channel control block. | ||
| 594 | |||
| 595 | XLATE PROC | ||
| 596 | |||
| 597 | ; Calcuate the page fram offset of the real address, the lower 12 bits. | ||
| 598 | |||
| 599 | MOV AX,WORD PTR [BX+DMALSB] ; Get the virtual LSB and MSB | ||
| 600 | AND AH,0FH ; Wipe out the top nibble. This leaves | ||
| 601 | ; us with only the offset into the 4K | ||
| 602 | ; page frame. This real address will | ||
| 603 | ; have the same offset into the page | ||
| 604 | ; frame | ||
| 605 | MOV WORD PTR [BX+DMALR],AX ; So save this in the real LSB | ||
| 606 | |||
| 607 | ; Pick up page table address. | ||
| 608 | |||
| 609 | MOV SI,SGTBLOFF ; Point ST to the first page directory | ||
| 610 | ; entry | ||
| 611 | DATAOV ; Get the address of the current page | ||
| 612 | LODSW ; table | ||
| 613 | SUB AL,AL ; Clear the access rights byte. This | ||
| 614 | ; makes it a real offset. | ||
| 615 | DATAOV ; Point SI to the page table | ||
| 616 | MOV SI,AX | ||
| 617 | MOV AX,WORD PTR [BX+DMAMSB] ; Get the MSB and page | ||
| 618 | SHR AX,4 ; Shift the top four bits off the end | ||
| 619 | ; of the register these four bits are | ||
| 620 | ; not used. We are dealing with a 24 | ||
| 621 | ; bit address where only 20 bits are | ||
| 622 | ; used. | ||
| 623 | SHL AX,4-2 ; Shift back 2 bits. This puts zeroes | ||
| 624 | ; in the high bits while converting | ||
| 625 | ; the address to a page table index. | ||
| 626 | ; Page table entries are 4 bytes long, | ||
| 627 | ; hence, shift left 2 bits. | ||
| 628 | ADD SI,AX ; Add the page table index on to the | ||
| 629 | ; offset of the page table. SI now | ||
| 630 | ; points to the correct page table | ||
| 631 | ; entry. | ||
| 632 | ADD SI,1 ; Step over the access rights byte | ||
| 633 | |||
| 634 | MOV AX,HUGE_PTR ; Load DS with a selector that accesses | ||
| 635 | MOV DS,AX ; all of memory as data | ||
| 636 | ADDROV ; Load the address of the page frame | ||
| 637 | LODSW ; into EAX | ||
| 638 | MOV CX,SYS_PATCH_DS ; Point DS back to our data segment | ||
| 639 | MOV DS,CX | ||
| 640 | |||
| 641 | ; Now AX contains the address of the page frame shifted right 8 bits. Remember | ||
| 642 | ; that we incremented SI to skip the access rights? This gave us the page | ||
| 643 | ; frame offset with out the lower byte. The lSB real address was already set | ||
| 644 | ; above, as well as the low nibble of the real MSB. AX now contains the page | ||
| 645 | ; and MSB of the real address. The low nibble of the MSB was already set so | ||
| 646 | ; we just OR on the high nibble of the MSB. Then we set the real page. Then | ||
| 647 | ; we're all done. | ||
| 648 | |||
| 649 | OR BYTE PTR [BX+DMAMR],AL ; Turn on high 4 bits of the real MSB | ||
| 650 | MOV BYTE PTR [BX+DMAPR],AH ; Set the real page | ||
| 651 | |||
| 652 | RET | ||
| 653 | |||
| 654 | XLATE ENDP | ||
| 655 | |||
| 656 | DMAIN ENDP | ||
| 657 | |||
| 658 | PROG ENDS | ||
| 659 | |||
| 660 | END | ||
diff --git a/v4.0/src/DEV/XMAEM/INDEEMU.ASM b/v4.0/src/DEV/XMAEM/INDEEMU.ASM new file mode 100644 index 0000000..9534ac2 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEEMU.ASM | |||
| @@ -0,0 +1,653 @@ | |||
| 1 | PAGE 60,132 | ||
| 2 | TITLE INDEEMU - 386 XMA EMULATOR - Sensitive Instruction Emulator | ||
| 3 | |||
| 4 | COMMENT # | ||
| 5 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 6 | * * | ||
| 7 | * MODULE NAME : INDEEMU * | ||
| 8 | * * | ||
| 9 | * * | ||
| 10 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corporation * | ||
| 11 | * * | ||
| 12 | * DESCRIPTIVE NAME: 386 XMA emulator - emulate sensitive instructions * | ||
| 13 | * * | ||
| 14 | * STATUS (LEVEL) : VERSION (0) LEVEL (1.0) * | ||
| 15 | * * | ||
| 16 | * FUNCTION : When the I/O privilege level (IOPL) is less than 3 then * | ||
| 17 | * the processor flags an exception and gives control to * | ||
| 18 | * the emulator whenever the virtual 8086 (V86) task tries * | ||
| 19 | * to execute a sensitive instruction. The set of sensitive * | ||
| 20 | * instructions includes: STI, CLI, INT3, INTO, IRET, INT, * | ||
| 21 | * PUSHF, POPF, LOCK, IN and OUT. This moudle will emulate * | ||
| 22 | * these intructions for the V86 task. It will also set the * | ||
| 23 | * IOPL to 3. This will keep the processor from raising * | ||
| 24 | * further exceptions for these instructions. This in turn * | ||
| 25 | * improves performance because the emulator will not be * | ||
| 26 | * given control each time one of these instructions is * | ||
| 27 | * executed by the V86 task. * | ||
| 28 | * * | ||
| 29 | * This module also has a small piece of code to handle * | ||
| 30 | * exception 7, coprocessor not available. This exception * | ||
| 31 | * is raised when the EM (EMulation), MP (Monitor Processor),* | ||
| 32 | * and TS (Task Switch) bits in CR0 are on. When this * | ||
| 33 | * happens it turns off these bits and retries the instruc- * | ||
| 34 | * tion that faulted. * | ||
| 35 | * * | ||
| 36 | * MODULE TYPE : ASM * | ||
| 37 | * * | ||
| 38 | * REGISTER USAGE : 80386 Standard * | ||
| 39 | * * | ||
| 40 | * RESTRICTIONS : None * | ||
| 41 | * * | ||
| 42 | * DEPENDENCIES : None * | ||
| 43 | * * | ||
| 44 | * ENTRY POINT : EMULATE * | ||
| 45 | * * | ||
| 46 | * LINKAGE : Jumped to by INDEEXC * | ||
| 47 | * * | ||
| 48 | * INPUT PARMS : None * | ||
| 49 | * * | ||
| 50 | * RETURN PARMS : None * | ||
| 51 | * * | ||
| 52 | * OTHER EFFECTS : None * | ||
| 53 | * * | ||
| 54 | * EXIT NORMAL : IRET to the V86 task * | ||
| 55 | * * | ||
| 56 | * EXIT ERROR : Jump to error routine in INDEEXC * | ||
| 57 | * * | ||
| 58 | * EXTERNAL * | ||
| 59 | * REFERENCES : POPREGS - Entry point in INDEEXC to pop the registers P1C* | ||
| 60 | * off the stack and IRET to the V86 task. * | ||
| 61 | * DISPLAY - Entry point in INDEEXC for the error routine * | ||
| 62 | * that does the NMI to the error handler. * | ||
| 63 | * INT15 - Entry point to INDEI15, the INT 15 handler. * | ||
| 64 | * XMAIN - Entry point in INDEXMA to handle IN for a byte * | ||
| 65 | * at the port address in DX * | ||
| 66 | * INW - Entry point in INDEXMA to handle IN for a word * | ||
| 67 | * at the port address in DX * | ||
| 68 | * INIMMED - Entry point in INDEXMA to handle IN for a byte * | ||
| 69 | * at the immediate port address given * | ||
| 70 | * INWIMMED- Entry point in INDEXMA to handle IN for a word * | ||
| 71 | * at the immediate port address given * | ||
| 72 | * XMAOUT - Entry point in INDEXMA to handle OUT for a byte * | ||
| 73 | * at the port address in DX * | ||
| 74 | * OUTW - Entry point in INDEXMA to handle OUT for a word * | ||
| 75 | * at the port address in DX * | ||
| 76 | * XMAOUTIMMED - Entry point in INDEXMA to handle OUT for a * | ||
| 77 | * byte at the immediate port address given * | ||
| 78 | * XMAOUTWIMMED - Entry point in INDEXMA to handle OUT for a * | ||
| 79 | * word at the immediate port address given * | ||
| 80 | * MANPORT - Entry point in INDEDMA to issue an out to the * | ||
| 81 | * port that will reIPL the system * | ||
| 82 | * * | ||
| 83 | * SUB-ROUTINES : None * | ||
| 84 | * * | ||
| 85 | * MACROS : DATAOV - Create a prefix for the following instruction * | ||
| 86 | * so that it accesses data 32 bits wide * | ||
| 87 | * ADDROV - Create a prefix for the following instruction * | ||
| 88 | * so that it uses addresses that are 32 bits wide * | ||
| 89 | * CMOV - Move to or from a control register * | ||
| 90 | * * | ||
| 91 | * CONTROL BLOCKS : INDEDAT.INC * | ||
| 92 | * * | ||
| 93 | * CHANGE ACTIVITY : * | ||
| 94 | * * | ||
| 95 | * $MOD(INDEEMU) COMP(LOAD) PROD(3270PC) : * | ||
| 96 | * * | ||
| 97 | * $D0=D0004700 410 870523 D : NEW FOR RELEASE 1.1 * | ||
| 98 | * $P1=P0000312 410 870804 D : CLEAN UP WARNING MESSAGES * | ||
| 99 | * * | ||
| 100 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 101 | # | ||
| 102 | |||
| 103 | .286P ; Enable recognition of 286 privileged instructs. | ||
| 104 | |||
| 105 | .XLIST ; Turn off the listing | ||
| 106 | INCLUDE INDEDAT.INC | ||
| 107 | |||
| 108 | IF1 ; Only include macros on the first pass | ||
| 109 | INCLUDE INDEOVP.MAC | ||
| 110 | INCLUDE INDEINS.MAC | ||
| 111 | ENDIF | ||
| 112 | .LIST ; Turn on the listing | ||
| 113 | |||
| 114 | PUBLIC INDEEMU | ||
| 115 | |||
| 116 | PROG SEGMENT PARA PUBLIC 'PROG' | ||
| 117 | |||
| 118 | ASSUME CS:PROG | ||
| 119 | ASSUME DS:NOTHING | ||
| 120 | ASSUME ES:NOTHING | ||
| 121 | ASSUME SS:NOTHING | ||
| 122 | |||
| 123 | INDEEMU LABEL NEAR | ||
| 124 | |||
| 125 | ; The following entries are in other modules | ||
| 126 | |||
| 127 | EXTRN XMAIN:NEAR ; Byte IN from port # in DX | ||
| 128 | IN_INST EQU XMAIN ; @P1C | ||
| 129 | EXTRN INW:NEAR ; Word IN from port # in DX | ||
| 130 | EXTRN INIMMED:NEAR ; Byte IN from immediate port # | ||
| 131 | EXTRN INWIMMED:NEAR ; Word IN from immediate port # | ||
| 132 | EXTRN XMAOUT:NEAR ; Byte OUT to port # in DX | ||
| 133 | OUT_INST EQU XMAOUT ; @P1C | ||
| 134 | EXTRN OUTW:NEAR ; Word OUT to port # in DX | ||
| 135 | EXTRN XMAOUTIMMED:NEAR ; Byte OUT to immediate port # | ||
| 136 | OUTIMMED EQU XMAOUTIMMED ; | ||
| 137 | EXTRN OUTWIMMED:NEAR ; Word OUT to immediate port # | ||
| 138 | EXTRN DISPLAY:NEAR ; Signal the error handler | ||
| 139 | EXTRN MANPORT:NEAR ; ReIPL the system | ||
| 140 | EXTRN INT15:NEAR ; Handle INT 15 | ||
| 141 | EXTRN POPREGS:NEAR ; Pop the registers and IRET to V86 task @P1C | ||
| 142 | |||
| 143 | PAGE | ||
| 144 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 145 | ;; The following is a jump table for each of the instructions. There are 256 ;; | ||
| 146 | ;; entries, each three bytes long, one for each possible op-code. The op- ;; | ||
| 147 | ;; code is used as an index into the table. Each entry is a jump instruction ;; | ||
| 148 | ;; instruction telling where to jump for each particular op-code. The table ;; | ||
| 149 | ;; is initialized such that all in- structions jump to the routin for ;; | ||
| 150 | ;; unexpected op-codes. Then the entries for the instructions we want to ;; | ||
| 151 | ;; emulate are set to jump to the appropriate routine. ;; | ||
| 152 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 153 | |||
| 154 | TABLE: | ||
| 155 | .XLIST | ||
| 156 | REPT 256 ; Initialize the table so that all instructions | ||
| 157 | JMP UNEXPECTED ; jump to UNEXPECTED | ||
| 158 | ENDM | ||
| 159 | .LIST | ||
| 160 | |||
| 161 | ; Now set up the entries for the instructions we want to emulate | ||
| 162 | |||
| 163 | TABLE_END: | ||
| 164 | ORG TABLE+(0FBH*3) ; 0FBH is the op-code for STI. | ||
| 165 | JMP STI_INST ; @P1C | ||
| 166 | ORG TABLE+(0FAH*3) ; 0FAH is the op-code for CLI. | ||
| 167 | JMP CLI_INST ; @P1C | ||
| 168 | ORG TABLE+(0F0H*3) ; 0F0H is the op-code for LOCK. | ||
| 169 | JMP LOCK_INST ; @P1C | ||
| 170 | ORG TABLE+(0EFH*3) ; 0EFH is the op-code for OUT for a word. | ||
| 171 | JMP OUTW ; | ||
| 172 | ORG TABLE+(0EEH*3) ; 0EEH is the op-code for OUT for a byte. | ||
| 173 | JMP OUT_INST ; @P1C | ||
| 174 | ORG TABLE+(0EDH*3) ; 0EDH is the op-code for IN for a word. | ||
| 175 | JMP INW | ||
| 176 | ORG TABLE+(0ECH*3) ; 0ECH is the op-code for IN for a byte. | ||
| 177 | JMP IN_INST ; @P1C | ||
| 178 | ORG TABLE+(0E7H*3) ; 0E7H is the op-code for OUT for a word to | ||
| 179 | JMP OUTWIMMED ; an immediate port value. | ||
| 180 | ORG TABLE+(0E6H*3) ; 0E6H is the op-code for OUT for a byte to | ||
| 181 | JMP OUTIMMED ; an immediate port value. | ||
| 182 | ORG TABLE+(0E5H*3) ; 0E5H is the op-code for IN for a word to | ||
| 183 | JMP INWIMMED ; an immediate port value. | ||
| 184 | ORG TABLE+(0E4H*3) ; 0E4H is the op-code for IN for a byte to | ||
| 185 | JMP INIMMED ; an immediate port value. | ||
| 186 | ORG TABLE+(0CFH*3) ; 0CFH is the op-code for IRET. | ||
| 187 | JMP IRET_INST ; @P1C | ||
| 188 | ORG TABLE+(0CEH*3) ; 0CEH is the op-code for INTO. | ||
| 189 | JMP INTO_INST ; @P1C | ||
| 190 | ORG TABLE+(0CDH*3) ; 0CDH is the op-code for INT. | ||
| 191 | JMP INT_INST ; @P1C | ||
| 192 | ORG TABLE+(0CCH*3) ; 0CCH is the op-code for INT3. | ||
| 193 | JMP INT3 ; | ||
| 194 | ORG TABLE+(09DH*3) ; 09DH is the op-code for POPF. | ||
| 195 | JMP POPF_INST ; @P1C | ||
| 196 | ORG TABLE+(09CH*3) ; 09CH is the op-code for PUSHF. | ||
| 197 | JMP PUSHF_INST ; @P1C | ||
| 198 | ORG TABLE+(00FH*3) ; 00FH is the op-code for POP CS. | ||
| 199 | JMP MANPORT ; Expedient until 0F opcode properly emulated | ||
| 200 | |||
| 201 | ORG TABLE_END | ||
| 202 | |||
| 203 | VALUE3 DB 3 | ||
| 204 | |||
| 205 | PUBLIC EMULATE | ||
| 206 | PUBLIC POPIO | ||
| 207 | PUBLIC INTCOM | ||
| 208 | |||
| 209 | EMULATE PROC NEAR | ||
| 210 | |||
| 211 | CLD | ||
| 212 | |||
| 213 | PAGE | ||
| 214 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 215 | ;; Get the op-code that faulted from real memory. Use it as an index into ;; | ||
| 216 | ;; the jump table to go to the appropriate routine. ;; | ||
| 217 | ;; ;; | ||
| 218 | ;; Note: The DATAOV macro creates a prefix that makes the instruction that ;; | ||
| 219 | ;; immediately follows access all data as 32 bits wide. Similarly, ;; | ||
| 220 | ;; the ADDROV macro creates a prefix that makes the instruction that ;; | ||
| 221 | ;; immediately follows use addresses that are 32 bits wide. ;; | ||
| 222 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 223 | |||
| 224 | MOV AX,HUGE_PTR ; Load DS with a selector that will | ||
| 225 | MOV DS,AX ; access all of memory as data | ||
| 226 | |||
| 227 | MOV SS:WORD PTR [BP+BP_IP2],0 ; Clear the high words of the V86 | ||
| 228 | MOV SS:WORD PTR [BP+BP_CS2],0 ; task's CS and IP | ||
| 229 | |||
| 230 | DATAOV | ||
| 231 | MOV SI,SS:[BP+BP_IP] ; Get the V86 IP into our SI. The high | ||
| 232 | DATAOV ; order word is zeroes. | ||
| 233 | MOV AX,SS:[BP+BP_CS] ; Get the V86 CS into AX. Again, the | ||
| 234 | DATAOV ; high order word is zeroes. | ||
| 235 | SHL AX,4 ; Multiply CS by 16 to convert it to an | ||
| 236 | DATAOV ; offset. | ||
| 237 | ADD SI,AX ; Add on IP. Now SI contains the offset | ||
| 238 | ; from 0 of the instruction that | ||
| 239 | ; faulted. | ||
| 240 | ADDROV | ||
| 241 | LODSB ; Get the op-code into AL | ||
| 242 | |||
| 243 | ADDROV ; Intel bug # A0-119 | ||
| 244 | NOP ; Intel bug # A0-119 | ||
| 245 | |||
| 246 | MUL VALUE3 ; Multiply the op-code by 3 to get an | ||
| 247 | LEA BX,TABLE ; index into the jump table | ||
| 248 | ADD AX,BX ; Add on the offset of the base of the | ||
| 249 | ; table | ||
| 250 | JMP AX ; Jump to the entry in the table. This | ||
| 251 | ; entry will then jump us to the | ||
| 252 | ; routine that handles this op-code. | ||
| 253 | |||
| 254 | PAGE | ||
| 255 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 256 | ;; Woops! We got an op-code that we did not expect to fault. First let's ;; | ||
| 257 | ;; check if this instruction faulted because the coprocessor was not avail- ;; | ||
| 258 | ;; able. This will be signalled by an exception code of 07. If this is the ;; | ||
| 259 | ;; case then reset the the following bits in CR0: EM (EMulation) says that ;; | ||
| 260 | ;; coprocessor functions are emulated by software when set to 0; MP (monitor ;; | ||
| 261 | ;; Processor), when set to 1 raises an exception 7 when TS (Task Switched) ;; | ||
| 262 | ;; is set to 1 and a WAIT instruction is executed. TS is set every time ;; | ||
| 263 | ;; there is a task switch. ;; | ||
| 264 | ;; ;; | ||
| 265 | ;; If it was not an execption 7 then we'll check the I/O privilege level ;; | ||
| 266 | ;; (IOPL). An IOPL other less than 3 will cause all I/O and some sensitive ;; | ||
| 267 | ;; instructions to fault. We really don't want to be bothered by all these ;; | ||
| 268 | ;; faulting instructions so we'll set the IOPL to 3 which will allow anyone ;; | ||
| 269 | ;; to do I/O and the sensitive instructions. This will improve performance ;; | ||
| 270 | ;; since the V86 task will be interrupted less often. But first we'll check ;; | ||
| 271 | ;; to see if the IOPL is already 3. If so then we got trouble. Most likely ;; | ||
| 272 | ;; it's an invalid op-code. In this case we'll signal the error handler in ;; | ||
| 273 | ;; INDEEXC. ;; | ||
| 274 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 275 | |||
| 276 | UNEXPECTED: | ||
| 277 | CMP SS:WORD PTR [BP+BP_EX],0007H | ||
| 278 | ; Check if it's an 07 exception -- co- | ||
| 279 | ; processor not available | ||
| 280 | JNE TRYIOPL3 ; If no then try setting the IOPL to 3 | ||
| 281 | |||
| 282 | MOV AX,8000H ; Set the paging enabled bit | ||
| 283 | DATAOV | ||
| 284 | SHL AX,16 ; It's the one all the way on the left | ||
| 285 | MOV AX,0001H ; Set protect mode on. Leave all other | ||
| 286 | ; bits off. | ||
| 287 | CMOV CR0,EAX ; Reset CR0 | ||
| 288 | JMP POPREGS ; Return to the V86 task @P1C | ||
| 289 | |||
| 290 | ; Try setting the IOPL to 3 | ||
| 291 | |||
| 292 | TRYIOPL3: | ||
| 293 | MOV BX,AX ; Save the faulty op-code in BX | ||
| 294 | MOV AX,SS:WORD PTR [BP+BP_FL] ; Get the V86 flags and check if | ||
| 295 | AND AX,3000H ; IOPL is already set to 3 | ||
| 296 | CMP AX,3000H | ||
| 297 | JE WHOOPS ; If we're already at IOPL 3 the some- | ||
| 298 | ; things fishy. Time to signal an | ||
| 299 | ; error. | ||
| 300 | OR SS:WORD PTR [BP+BP_FL],3000H | ||
| 301 | ; Otherwise set IOPL to 3 and return to | ||
| 302 | JMP POPREGS ; the V86 task and let it try to @P1C | ||
| 303 | ; execute the instruction again. | ||
| 304 | |||
| 305 | ; We got trouble. | ||
| 306 | |||
| 307 | WHOOPS: | ||
| 308 | |||
| 309 | ; Convert jump address back to opcode in al | ||
| 310 | |||
| 311 | MOV AX,BX ; Put the jump table index back into AX | ||
| 312 | LEA BX,TABLE ; Subtract the offset of the base of the | ||
| 313 | SUB AX,BX ; jump table | ||
| 314 | DIV VALUE3 ; Divide AX by 3 to get the opcode back. | ||
| 315 | JMP DISPLAY ; Go to the error routine in INDEEXC | ||
| 316 | |||
| 317 | PAGE | ||
| 318 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 319 | ;; Emulate the LOCK instruction. This is an instruction we really don't want ;; | ||
| 320 | ;; to emulate so we will set the IOPL to 3 so that further LOCKs won't bother ;; | ||
| 321 | ;; us. If the exception code is for "invalid op-code" then we will just jump ;; | ||
| 322 | ;; to the routine above to set the IOPL to 3. Otherwise we will just step IP ;; | ||
| 323 | ;; past the LOCK instruction thus treating it as a NOP. ;; | ||
| 324 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 325 | |||
| 326 | LOCK_INST: ; @P1C | ||
| 327 | CMP SS:WORD PTR [BP+BP_EX],0006H ; Check if it's an invalid op code | ||
| 328 | JNE TRYIOPL3 ; Try setting the IOPL to 3 | ||
| 329 | ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past the instruction | ||
| 330 | JMP POPIO ; thus treating it as a NOP | ||
| 331 | |||
| 332 | PAGE | ||
| 333 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 334 | ;; Emulate the STI, enable interupts, instruction. This is pretty simple to ;; | ||
| 335 | ;; do. Just get the V86 task's flags and flip on the enable interrupts bit. ;; | ||
| 336 | ;; And while we're at it we'll set the IOPL to 3. ;; | ||
| 337 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 338 | |||
| 339 | STI_INST: ; @P1C | ||
| 340 | OR WORD PTR SS:[BP+BP_FL],3200H ; Set the enable interrupts bit | ||
| 341 | ; and set IOPL to 3 | ||
| 342 | ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past STI instruction | ||
| 343 | JMP POPIO | ||
| 344 | |||
| 345 | PAGE | ||
| 346 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 347 | ;; Emulate the CLI, disable interrupts, instruction. Just as in STI above, ;; | ||
| 348 | ;; all that is needed is to turn of the enable interrups bit. And again, set ;; | ||
| 349 | ;; the IOPL to 3 so that we won't get control again. ;; | ||
| 350 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 351 | |||
| 352 | CLI_INST: ; @P1C | ||
| 353 | AND WORD PTR SS:[BP+BP_FL],3DFFH ; Set interrupts disabled | ||
| 354 | OR WORD PTR SS:[BP+BP_FL],3000H ; Insure IOPL = 3 for speed | ||
| 355 | ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past instruction | ||
| 356 | JMP POPIO | ||
| 357 | |||
| 358 | PAGE | ||
| 359 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 360 | ;; Emulate the INT3 instruction. To do this we put a 3 in the exception code ;; | ||
| 361 | ;; and jump to the portion of the code that emulates the INT instruction. ;; | ||
| 362 | ;; That code uses the exception code to get the interrupt vector from real ;; | ||
| 363 | ;; memory and gives control to the V86 task at the interrupt address. ;; | ||
| 364 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 365 | |||
| 366 | INT3: | ||
| 367 | MOV WORD PTR SS:[BP+BP_EX],3 ; Put a 3 in the exception field | ||
| 368 | ; This will cause the INTCOM | ||
| 369 | ; section to go to interrupt 3 | ||
| 370 | ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past INT3 inscruction | ||
| 371 | JMP INTCOM ; Go get the vector from real | ||
| 372 | ; memory | ||
| 373 | |||
| 374 | PAGE | ||
| 375 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 376 | ;; Emulate the INTO instruction. This is done just like the INT3 above. It ;; | ||
| 377 | ;; puts a 4 in the exception code and jumps to the code in the INT emulator ;; | ||
| 378 | ;; that will get the real address of the interrupt. ;; | ||
| 379 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 380 | |||
| 381 | INTO_INST: ; @P1C | ||
| 382 | MOV WORD PTR SS:[BP+BP_EX],4 ; Put a 4 in the exception field | ||
| 383 | ; This will cause the INTCOM | ||
| 384 | ; section to go to interrupt 4 | ||
| 385 | ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past INTO inscruction | ||
| 386 | JMP INTCOM ; Go get the vector from real | ||
| 387 | ; memory | ||
| 388 | |||
| 389 | PAGE | ||
| 390 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 391 | ;; Emulate the IRET instruction. Get CS, IP and the flags off of the V86 ;; | ||
| 392 | ;; task's stack and place them in the register values on our stack. When we ;; | ||
| 393 | ;; return control to the V86 task these values will be taken off of our stack ;; | ||
| 394 | ;; and placed in the V86 task's registers. ;; | ||
| 395 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 396 | |||
| 397 | IRET_INST: ; @P1C | ||
| 398 | DATAOV ; Get the user's ESP (32 bit SP) | ||
| 399 | MOV AX,SS:[BP+BP_SP] ; and save it in ESI. | ||
| 400 | DATAOV | ||
| 401 | MOV SI,AX | ||
| 402 | ADD AX,6 ; Add 6 to the user's SP. This | ||
| 403 | MOV SS:WORD PTR [BP+BP_SP],AX ; skips over the IP, CS and | ||
| 404 | ; flags on the user's stack. | ||
| 405 | ; This puts SP where it would be | ||
| 406 | ; after the IRET. It assumes | ||
| 407 | ; there are at least six bytes | ||
| 408 | ; on the stack. | ||
| 409 | DATAOV | ||
| 410 | MOV AX,SS:[BP+BP_SS] ; Get the user's SS and multiply | ||
| 411 | DATAOV ; by 16. This converts the | ||
| 412 | SHL AX,4 ; segment value to an offset. | ||
| 413 | DATAOV ; Add this on to the ESP value in | ||
| 414 | ADD SI,AX ; ESI and now ESI is the offset | ||
| 415 | ; from 0 of the user's stack. | ||
| 416 | ADDROV | ||
| 417 | LODSW ; Get the user's EIP into EAX | ||
| 418 | |||
| 419 | ADDROV ; Intel bug # A0-119 | ||
| 420 | NOP ; Intel bug # A0-119 | ||
| 421 | |||
| 422 | MOV WORD PTR SS:[BP+BP_IP],AX ; Put IP into the register values | ||
| 423 | ; on our stack | ||
| 424 | ADDROV | ||
| 425 | LODSW ; Get the user's CS into EAX | ||
| 426 | |||
| 427 | ADDROV ; Intel bug # A0-119 | ||
| 428 | NOP ; Intel bug # A0-119 | ||
| 429 | |||
| 430 | MOV WORD PTR SS:[BP+BP_CS],AX ; Put CS into the register values | ||
| 431 | ; on our stack | ||
| 432 | ADDROV | ||
| 433 | LODSW ; Get the user's flags (32 bits) | ||
| 434 | |||
| 435 | ADDROV ; Intel bug # A0-119 | ||
| 436 | NOP ; Intel bug # A0-119 | ||
| 437 | |||
| 438 | AND AX,3FFFH ; Clean up the flags | ||
| 439 | OR AX,3000H ; Set IOPL to 3 | ||
| 440 | MOV WORD PTR SS:[BP+BP_FL],AX ; Put the flags into the register | ||
| 441 | ; values on our stack | ||
| 442 | JMP POPREGS ; Go return to the V86 task @P1C | ||
| 443 | |||
| 444 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 445 | ;; Emulate the INT instruction. Step the V86 task's CS and IP past the INT ;; | ||
| 446 | ;; instruction. Push the flags, CS and IP in the task's stack. Get the ;; | ||
| 447 | ;; interrupt number and use it to find the appropriate interrupt vector in ;; | ||
| 448 | ;; low memory. Set the task's CS and IP to the interrupt vector and return ;; | ||
| 449 | ;; control to the task. ;; | ||
| 450 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 451 | |||
| 452 | INT_INST: ; @P1C | ||
| 453 | |||
| 454 | ; Get the interrupt number from the instruction. It is the second byte of the | ||
| 455 | ; instruction. DS:SI was used to get the op-code. Now DS:SI points to the next | ||
| 456 | ; byte of the instruction. All we have to do is get it. | ||
| 457 | |||
| 458 | ADDROV | ||
| 459 | LODSB ; Get the interrupt number | ||
| 460 | |||
| 461 | ADDROV ; Intel bug # A0-119 | ||
| 462 | NOP ; Intel bug # A0-119 | ||
| 463 | |||
| 464 | MOV AH,0 ; Clear the high byte | ||
| 465 | MOV WORD PTR SS:[BP+BP_EX],AX ; Save the interrupt number in | ||
| 466 | ; the exception code field | ||
| 467 | |||
| 468 | ; Step IP past the INT instruction. | ||
| 469 | |||
| 470 | ADD WORD PTR SS:[BP+BP_IP],2 ; STEP IP PAST INT INSTRUCTION | ||
| 471 | |||
| 472 | ; Check for INT 15. This is handled by INDEI15. | ||
| 473 | |||
| 474 | INTCONT: | ||
| 475 | CMP AL,15H ; Is it interrupt 15? | ||
| 476 | JNE INTCOM ; If not, continue | ||
| 477 | JMP INT15 ; Else go to INDEI15 | ||
| 478 | |||
| 479 | ; Now use the interrupt number to get the appropriate interrupt vector from | ||
| 480 | ; low core. | ||
| 481 | |||
| 482 | INTCOM: | ||
| 483 | MOV AX,HUGE_PTR ; Load ES with the selector that | ||
| 484 | MOV ES,AX ; accesses all of memory as data | ||
| 485 | DATAOV | ||
| 486 | MOV DI,SS:[BP+BP_SP] ; Load EDI with the user's ESP | ||
| 487 | ; Now ES:EDI points to the user's | ||
| 488 | ; stack | ||
| 489 | SUB DI,6 ; Decrement "SP" to make space for | ||
| 490 | ; the flags, CS snd IP | ||
| 491 | MOV SS:WORD PTR [BP+BP_SP],DI ; Set the user's new SP | ||
| 492 | |||
| 493 | DATAOV | ||
| 494 | MOV AX,SS:[BP+BP_SS] ; Get the user's SS and shift it | ||
| 495 | DATAOV ; left four bits to convert it | ||
| 496 | SHL AX,4 ; to an offset | ||
| 497 | DATAOV ; Add it to EDI so that EDI now | ||
| 498 | ADD DI,AX ; contains the physical offset | ||
| 499 | ; of the user's stack | ||
| 500 | |||
| 501 | ; Now put the flags, CS and IP on the V86 task's stack. They are put on in the | ||
| 502 | ; order IP, CS, flags. This is backwards from the INT push order of flags, CS | ||
| 503 | ; and then IP. This is because we are moving forward through memory (CLD) | ||
| 504 | ; whereas the stack grows backwards through memory as things apushed on to it. | ||
| 505 | |||
| 506 | MOV AX,SS:[BP+BP_IP] | ||
| 507 | ADDROV | ||
| 508 | STOSW ; Put IP on the V86 task's stack | ||
| 509 | ADDROV ; Intel bug # A0-119 | ||
| 510 | NOP ; Intel bug # A0-119 | ||
| 511 | |||
| 512 | MOV AX,SS:[BP+BP_CS] | ||
| 513 | ADDROV | ||
| 514 | STOSW ; Put CS on the V86 task's stack | ||
| 515 | ADDROV ; Intel bug # A0-119 | ||
| 516 | NOP ; Intel bug # A0-119 | ||
| 517 | |||
| 518 | MOV AX,SS:[BP+BP_FL] ; Get the v86 task's flags | ||
| 519 | OR AX,3000H ; Set IPOL to 3 while we're here | ||
| 520 | ADDROV | ||
| 521 | STOSW ; Put the flags on the v86 task's | ||
| 522 | ; stack | ||
| 523 | |||
| 524 | ADDROV ; INTEL BUG # A0-119 | ||
| 525 | NOP ; INTEL BUG # A0-119 | ||
| 526 | AND AX,3CFFH ; Clean up flags for our IRET | ||
| 527 | MOV WORD PTR SS:[BP+BP_FL],AX | ||
| 528 | |||
| 529 | ; Use the interrupt number to get the CS and IP of the interrupt routine | ||
| 530 | |||
| 531 | MOV SI,SS:[BP+BP_EX] ; Get the interrupt number | ||
| 532 | SHL SI,2 ; Multiply by 4 since interrupt | ||
| 533 | ; vectors are 4 bytes long | ||
| 534 | LODSW ; Get the IP for the vector | ||
| 535 | MOV WORD PTR SS:[BP+BP_IP],AX ; Put it in the V86 task's IP | ||
| 536 | LODSW ; Get the CS for the vector | ||
| 537 | MOV WORD PTR SS:[BP+BP_CS],AX ; Put it in the V86 task's CS | ||
| 538 | |||
| 539 | JMP POPREGS ; Go return to the V86 task @P1C | ||
| 540 | |||
| 541 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 542 | ;; Emulate the PUSHF instruction. Get the V86 task's flags and put them on ;; | ||
| 543 | ;; its stack. ;; | ||
| 544 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 545 | |||
| 546 | PUSHF_INST: ; @P1C | ||
| 547 | MOV AX,HUGE_PTR ; Load ES with the selector that | ||
| 548 | MOV ES,AX ; accesses all of memory as data | ||
| 549 | |||
| 550 | DATAOV | ||
| 551 | MOV DI,SS:[BP+BP_SP] ; Load EDI with the V86 task's SP | ||
| 552 | SUB DI,2 ; Decrement "SP" by one word to | ||
| 553 | ; make room for the flags | ||
| 554 | MOV SS:WORD PTR [BP+BP_SP],DI ; Store the new V86 task's SP | ||
| 555 | DATAOV | ||
| 556 | MOV AX,SS:[BP+BP_SS] ; Get the user's SS and shift it | ||
| 557 | DATAOV ; left four bits to convert it | ||
| 558 | SHL AX,4 ; to an offset | ||
| 559 | DATAOV ; Add it to EDI so that EDI now | ||
| 560 | ADD DI,AX ; contains the physical offset | ||
| 561 | ; of the user's stack | ||
| 562 | MOV AX,SS:[BP+BP_FL] ; Get the v86 task's flags | ||
| 563 | OR AX,3000H ; Set IPOL to 3 so that we won't | ||
| 564 | ADDROV ; be bothered anymore | ||
| 565 | STOSW ; Put the flags on the stack | ||
| 566 | ADDROV ; Intel bug # A0-119 | ||
| 567 | NOP ; Intel bug # A0-119 | ||
| 568 | |||
| 569 | ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past PUSHF instruction | ||
| 570 | |||
| 571 | JMP POPIO ; Go return to the V86 task | ||
| 572 | |||
| 573 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 574 | ;; Emulate the POPF instruction. Get the next word off of the V86 task's ;; | ||
| 575 | ;; stack, set IOPL to 3 and put it in the V86 task's flags. ;; | ||
| 576 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 577 | |||
| 578 | POPF_INST: ; @P1C | ||
| 579 | MOV AX,HUGE_PTR ; Big segment selector | ||
| 580 | MOV DS,AX ; Stack seg | ||
| 581 | DATAOV ; Create 32-bit operand prefix for next instruction | ||
| 582 | MOV AX,SS:[BP+BP_SP] ; stack ptr | ||
| 583 | DATAOV ; Create 32-bit operand prefix for next instruction | ||
| 584 | MOV SI,AX ; SI = stack ptr | ||
| 585 | ADD AX,2 | ||
| 586 | MOV SS:WORD PTR [BP+BP_SP],AX ; NEW STACK POINTER | ||
| 587 | DATAOV ; Create 32-bit operand prefix for next instruction | ||
| 588 | MOV AX,SS:[BP+BP_SS] ; Convert ss to 20 bit address | ||
| 589 | DATAOV ; Create 32-bit operand prefix for next instruction | ||
| 590 | SHL AX,4 | ||
| 591 | DATAOV ; Create 32-bit operand prefix for next instruction | ||
| 592 | ADD SI,AX ; Now have 32-bit offset from 0 | ||
| 593 | ADDROV ; Use 32-bit offset | ||
| 594 | LODSW ; GET REAL MODE FLAGS | ||
| 595 | ADDROV ; INTEL BUG # A0-119 | ||
| 596 | NOP ; INTEL BUG # A0-119 | ||
| 597 | AND AX,0FFFH ; CLEAN UP FLAGS FOR OUR IRET | ||
| 598 | ; A POPF at level 3 will not change IOPL - WE WANT TO KEEP IT AT IOPL = 3 | ||
| 599 | OR AX,3000H ; SET IOPL = 3 | ||
| 600 | MOV WORD PTR SS:[BP+BP_FL],AX | ||
| 601 | ADD WORD PTR SS:[BP+BP_IP],1 ; STEP IP PAST INSTRUCTION | ||
| 602 | JMP POPIO ; CHECK FOR SINGLE STEP | ||
| 603 | |||
| 604 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 605 | ;; The following entry point, POPIO, is the exit routine for situations when ;; | ||
| 606 | ;; a single step condition would be lost by a normal IRET to the V86 task. ;; | ||
| 607 | ;; You see, in real mode the single step interrupt gets control whenever the ;; | ||
| 608 | ;; single step flag is on. However, we just got control and emulated the ;; | ||
| 609 | ;; instruction. If we just return to the V86 task at CS:IP then the step ;; | ||
| 610 | ;; between the instruction we just emulated and the next instruction will be ;; | ||
| 611 | ;; missed by the single step routine. Therefore we check the V86 task's flags;; | ||
| 612 | ;; to see if the single step flag is on. If so, then we give control to the ;; | ||
| 613 | ;; singel step interrupt. Otherwise we just IRET to the V86 task's CS:IP. ;; | ||
| 614 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 615 | |||
| 616 | POPIO: | ||
| 617 | CMP SS:WORD PTR [BP+BP_EX],1 ; First check if the reason we got | ||
| 618 | ; control was because of a | ||
| 619 | ; single step | ||
| 620 | JE POPCONT ; If so, then we don't have to | ||
| 621 | ; give control to the single | ||
| 622 | ; step routine 'cause we already | ||
| 623 | ; did it. | ||
| 624 | TEST WORD PTR SS:[BP+BP_FL],0100H ; Was the single step flag on? | ||
| 625 | JZ POPCONT ; If not then just IRET | ||
| 626 | MOV SS:WORD PTR [BP+BP_EX],1 ; Otherwise put a 1 (single step | ||
| 627 | JMP INTCOM ; interrupt number) in the | ||
| 628 | ; exception code and go to | ||
| 629 | ; INTCOM to give control to the | ||
| 630 | ; interrupt | ||
| 631 | POPCONT: | ||
| 632 | |||
| 633 | ; Restore the registers. On entry, in INDEEXC, the registers were pushed as: | ||
| 634 | ; DS, all registers, ES. | ||
| 635 | |||
| 636 | POP ES ; Restore ES | ||
| 637 | DATAOV | ||
| 638 | POPA ; Restore all the registers (32 bits wide) | ||
| 639 | POP DS ; Restore DS | ||
| 640 | ADD SP,(BP_IP-BP_EX); Move SP past the exception ID an error code | ||
| 641 | ; that were put on our stack when the 386 | ||
| 642 | ; gave us control for the exception. | ||
| 643 | ; SS:SP now points to the V86's IP, CS, flags | ||
| 644 | ; for the IRET | ||
| 645 | DATAOV ; IP, CS, and flags are saved 32 bits wide | ||
| 646 | IRET ; Give control back to the V86 task | ||
| 647 | |||
| 648 | EMULATE ENDP | ||
| 649 | |||
| 650 | PROG ENDS | ||
| 651 | |||
| 652 | END | ||
| 653 | |||
diff --git a/v4.0/src/DEV/XMAEM/INDEEXC.ASM b/v4.0/src/DEV/XMAEM/INDEEXC.ASM new file mode 100644 index 0000000..a8faaa5 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEEXC.ASM | |||
| @@ -0,0 +1,799 @@ | |||
| 1 | PAGE 60,132 | ||
| 2 | TITLE INDEEXC - 386 XMA EMULATOR - System Exception Handler | ||
| 3 | |||
| 4 | COMMENT # | ||
| 5 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 6 | * * | ||
| 7 | * MODULE NAME : INDEEXC * | ||
| 8 | * * | ||
| 9 | * * | ||
| 10 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. * | ||
| 11 | * * | ||
| 12 | * DESCRIPTIVE NAME: 80386 XMA Emulator System Exception Handler * | ||
| 13 | * * | ||
| 14 | * STATUS (LEVEL) : VERSION (0) LEVEL (1.0) * | ||
| 15 | * * | ||
| 16 | * FUNCTION : This module gets control whenever an interrupt 00 - 07, * | ||
| 17 | * 09 - 0E or 15 occurs. This is because this module's * | ||
| 18 | * entry point was placed in the IDT entries for these * | ||
| 19 | * interrupts. It determines what course of action to take * | ||
| 20 | * on the interrupt/exception. * | ||
| 21 | * * | ||
| 22 | * First thing it does is is to check to see who caused the * | ||
| 23 | * exception. If the exception came from the virtual 8086 * | ||
| 24 | * (V86) task then it will try to emulate the interrupt if * | ||
| 25 | * necessary. If the exception came from the emulator it- * | ||
| 26 | * self then we may have problems. If it was a general * | ||
| 27 | * protection exception (INT 0D) then it just ignores it and * | ||
| 28 | * passes control back to the V86 task. If it was a page * | ||
| 29 | * fault (INT 14) then it assumes that whatever is running in* | ||
| 30 | * the V86 task came up with a bad address so it terminates * | ||
| 31 | * the application since it is obviously bad. If it is * | ||
| 32 | * neither of these two errors then something has gone bad * | ||
| 33 | * in the emulator. When this happens it signals the error * | ||
| 34 | * handler to prompt the user to take a dump or reIPL the * | ||
| 35 | * system. * | ||
| 36 | * * | ||
| 37 | * The old error routine used to display a panel with the * | ||
| 38 | * contents of the registers and the stack. The new error * | ||
| 39 | * routine just forces the V86 task to run the NMI code. * | ||
| 40 | * The old routine was left in place for debugging purposes. * | ||
| 41 | * * | ||
| 42 | * MODULE TYPE : ASM * | ||
| 43 | * * | ||
| 44 | * REGISTER USAGE : 80386 Standard * | ||
| 45 | * * | ||
| 46 | * RESTRICTIONS : None * | ||
| 47 | * * | ||
| 48 | * DEPENDENCIES : None * | ||
| 49 | * * | ||
| 50 | * ENTRY POINT : VEXCPT13 * | ||
| 51 | * * | ||
| 52 | * LINKAGE : This entry point is placed in the IDT for each interrupt * | ||
| 53 | * we want to handle. Whenever one of those interrupts is * | ||
| 54 | * execupted, control comes here. * | ||
| 55 | * * | ||
| 56 | * INPUT PARMS : None * | ||
| 57 | * * | ||
| 58 | * RETURN PARMS : None * | ||
| 59 | * * | ||
| 60 | * OTHER EFFECTS : None * | ||
| 61 | * * | ||
| 62 | * EXIT NORMAL : IRET to the virtual 8086 task * | ||
| 63 | * * | ||
| 64 | * EXIT ERROR : Force the V86 task to execute an NMI * | ||
| 65 | * * | ||
| 66 | * EXTERNAL * | ||
| 67 | * REFERENCES : EMULATE - Entry point for INDEEMU * | ||
| 68 | * INT15 - Entry point for INDEI15 * | ||
| 69 | * * | ||
| 70 | * SUB-ROUTINES : HEXD - Display the double word in EAX * | ||
| 71 | * HEXW - Display the word in AX * | ||
| 72 | * HEXB - Display the byte in AL * | ||
| 73 | * * | ||
| 74 | * MACROS : DATAOV - Create a prefix for the following instruction * | ||
| 75 | * so that it accesses data 32 bits wide * | ||
| 76 | * ADDROV - Create a prefix for the following instruction * | ||
| 77 | * so that it uses addresses that are 32 bits wide * | ||
| 78 | * * | ||
| 79 | * CONTROL BLOCKS : INDEDAT.INC * | ||
| 80 | * * | ||
| 81 | * CHANGE ACTIVITY : * | ||
| 82 | * * | ||
| 83 | * $MOD(INDEEXC) COMP(LOAD) PROD(3270PC) : * | ||
| 84 | * * | ||
| 85 | * $D0=D0004700 410 870523 D : NEW FOR RELEASE 1.1 * | ||
| 86 | * $P1=P0000312 410 870804 D : CLEAN UP WARNING MESSAGES * | ||
| 87 | * * | ||
| 88 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 89 | # | ||
| 90 | |||
| 91 | .286P ; Enable recognition of 286 privileged instructs. | ||
| 92 | |||
| 93 | .XLIST ; Turn off the listing | ||
| 94 | INCLUDE INDEDAT.INC ; Include system data | ||
| 95 | |||
| 96 | IF1 ; Only include macros on the first pass of | ||
| 97 | INCLUDE INDEOVP.MAC ; of the assembler | ||
| 98 | ENDIF | ||
| 99 | .LIST ; Turn on the listing | ||
| 100 | |||
| 101 | SEX_ATTR EQU 04B00H | ||
| 102 | STACK_ATTR EQU 00700H | ||
| 103 | BLANK EQU 00020H | ||
| 104 | BP_START EQU 0 | ||
| 105 | |||
| 106 | PUBLIC INDEEXC | ||
| 107 | |||
| 108 | PROG SEGMENT PARA PUBLIC 'PROG' | ||
| 109 | |||
| 110 | ASSUME CS:PROG | ||
| 111 | ASSUME DS:NOTHING | ||
| 112 | ASSUME ES:NOTHING | ||
| 113 | ASSUME SS:NOTHING | ||
| 114 | |||
| 115 | INDEEXC LABEL NEAR | ||
| 116 | |||
| 117 | ; External entry points | ||
| 118 | |||
| 119 | EXTRN EMULATE:NEAR ; Entry point to INDEEMU | ||
| 120 | EXTRN INT15:NEAR ; Entry point to INDEI15 | ||
| 121 | |||
| 122 | ; External variables | ||
| 123 | |||
| 124 | EXTRN CRT_SELECTOR:WORD ; Selector for the display buffer (INDEI15) | ||
| 125 | EXTRN XMATID:BYTE ; Current bank ID (INDEXMA) | ||
| 126 | |||
| 127 | PAGE | ||
| 128 | |||
| 129 | VEXCPT13 LABEL NEAR | ||
| 130 | |||
| 131 | PUBLIC SEX | ||
| 132 | PUBLIC POPREGS ; P1C | ||
| 133 | PUBLIC HEXD | ||
| 134 | PUBLIC HEXW | ||
| 135 | PUBLIC HEXB | ||
| 136 | PUBLIC VEXCPT13 | ||
| 137 | PUBLIC DISPLAY | ||
| 138 | |||
| 139 | SEX PROC NEAR | ||
| 140 | |||
| 141 | CLD ; All moves go forward | ||
| 142 | |||
| 143 | ; Save the registers on the stack. These are the registers of the task that | ||
| 144 | ; got interrupted. | ||
| 145 | |||
| 146 | SAVE_REGS: | ||
| 147 | PUSH DS ; Save DS | ||
| 148 | |||
| 149 | DATAOV ; Save all the registers (32 bits wide). They are | ||
| 150 | PUSHA ; pushed in the order: AX, CX, DX, BX, original | ||
| 151 | ; SP (before the PUSHA), BP, SI, DI. | ||
| 152 | |||
| 153 | PUSH ES ; Save ES | ||
| 154 | MOV BP,SP ; Point BP to the start of the register save area | ||
| 155 | |||
| 156 | PAGE | ||
| 157 | ; First let's check to see who caused the exception, the V86 task or us. This | ||
| 158 | ; is done by checking the flags of the routine that was interrupted. The VM | ||
| 159 | ; flag is set for every routine that is running in V86 mode. There are really | ||
| 160 | ; only two entities in the system, the emulator and the V86 task. The V86 task | ||
| 161 | ; has the VM bit set when it is running, the emulator does not. So we can read | ||
| 162 | ; this bit to determine who was interrupted. | ||
| 163 | |||
| 164 | MOV AX,SS:WORD PTR [BP+BP_FL2] ; Get hi-order word of the flags | ||
| 165 | TEST AL,02H ; Check the VM bit | ||
| 166 | JZ DISPLAY ; Uh oh! It's us. | ||
| 167 | JMP LONGWAY ; It's the V86 task | ||
| 168 | |||
| 169 | PAGE | ||
| 170 | ; The following entry point, DISPLAY, is know to other modules. They jump here | ||
| 171 | ; when they encounter a severe error and want to call the error handler. | ||
| 172 | |||
| 173 | DISPLAY: | ||
| 174 | ; JMP DODISP ; Just display the registers. | ||
| 175 | ; Comment out for final product. | ||
| 176 | |||
| 177 | ; Check if it was a general protection exception. If so, then we'll just pass | ||
| 178 | ; control back to the V86 task and let it worry about it. | ||
| 179 | |||
| 180 | MOV BP,SP ; Point BP to the saved registers | ||
| 181 | CMP SS:WORD PTR [BP+BP_EX],0DH ; Was it a general protection | ||
| 182 | ; exception | ||
| 183 | JNE DISPCONT ; If not, the continue | ||
| 184 | JMP POPREGS ; Else just return to the V86 @P1C | ||
| 185 | ; task | ||
| 186 | |||
| 187 | ; Check if it was a page fault. Page faults only occur when the page that is | ||
| 188 | ; addressed is marked not present. When the emulator sets up memory it marks | ||
| 189 | ; all pages as present. And this is true because the emulator does no page | ||
| 190 | ; swapping. It messes with the page tables but it doesn't remove pages from | ||
| 191 | ; memory. Therefore, if the page is not present then whatever is running in | ||
| 192 | ; the V86 task came up with some wierd non-existant address. This guy obviously | ||
| 193 | ; has gone west or doesn't know what he's doing. So we forcr the application | ||
| 194 | ; to be terminated. | ||
| 195 | |||
| 196 | DISPCONT: | ||
| 197 | CMP SS:WORD PTR [BP+BP_EX],0EH ; Was it a page fault? | ||
| 198 | JNE CHKVM ; Nope. Continue checking. | ||
| 199 | JMP PAGE_FAULT ; Yup. Assume application had bad | ||
| 200 | ; addresses. Therefore, termin- | ||
| 201 | ; ate the application. | ||
| 202 | |||
| 203 | ; Lastly we'll check who had the error, them or us. We need to check again | ||
| 204 | ; because anybody can jump to the DISPLAY label above. If the V86 task had | ||
| 205 | ; the exception then we will just terminate whatever was running in the V86 | ||
| 206 | ; task. If the emulator had the exception, then obviously WE don't know | ||
| 207 | ; what WE'RE doing. Oops! In this case we will force an NMI and bring down | ||
| 208 | ; the whole system. If the emulator isn't healthy then nothing else should | ||
| 209 | ; run either. It may sould selfish, but if the emulator is damaged then the | ||
| 210 | ; rest of the system will die soon anyway. | ||
| 211 | |||
| 212 | CHKVM: | ||
| 213 | MOV AX,SS:WORD PTR [BP+BP_FL2] ; Check the VM bit in the flags | ||
| 214 | TEST AL,02H ; to see who was running | ||
| 215 | JZ ERROR ; It was us. Better Force an NMI. | ||
| 216 | JMP TERM_APP ; It was them. Terminate whatever | ||
| 217 | ; is running. | ||
| 218 | |||
| 219 | PAGE | ||
| 220 | ERROR: | ||
| 221 | |||
| 222 | ;----------------------------------------------------------------------------D1A | ||
| 223 | ; We're in big trouble now. Something has gone west and there's no way to D1A | ||
| 224 | ; get back home. At this point we give up and send up a flare. We signal D1A | ||
| 225 | ; the error handler by forcing the V86 task to execute the NMI interrupt. D1A | ||
| 226 | ; We put a marker of 0DEADH at the fixed location 0:4F2. This is in the D1A | ||
| 227 | ; BIOS communication area. The error handler will look here for our marker D1A | ||
| 228 | ; to determine if the NMI came from the emulator. If it finds it, it will D1A | ||
| 229 | ; put up a severe error with our return code and ask the user to take a dump D1A | ||
| 230 | ; or reIPL. The code following this new code is old code to display a debug D1A | ||
| 231 | ; panel with the contents of the registers and stack. It is left here for D1A | ||
| 232 | ; debugging but will not be executed when the new code is in place. D1A | ||
| 233 | ;----------------------------------------------------------------------------D1A | ||
| 234 | ; D1A | ||
| 235 | MOV AX,HUGE_PTR ; Load ES with a selector that @D1A | ||
| 236 | MOV ES,AX ; accesses all of memory as data @D1A | ||
| 237 | ; D1A | ||
| 238 | MOV DI,4F2H ; Put our 0DEADH marker at the @D1A | ||
| 239 | MOV WORD PTR ES:[DI],0DEADH ; fixed location 0:4F2. D1A | ||
| 240 | MOV WORD PTR SS:[BP+BP_EX],2; Put a 2, the NMI interrupt number,@D1A | ||
| 241 | ; in the exception field. The D1A | ||
| 242 | ; code after LONGWAY4 will use D1A | ||
| 243 | ; this number to get the interrupt D1A | ||
| 244 | ; vector. D1A | ||
| 245 | JMP LONGWAY4 ; Go do the NMI @D1A | ||
| 246 | |||
| 247 | PAGE | ||
| 248 | ; The following code will not be executed. It is left as a debugging tool. | ||
| 249 | |||
| 250 | DODISP: | ||
| 251 | ; Blank the display screen | ||
| 252 | MOV DI,CRT_SELECTOR ; Load ES with the selector for the | ||
| 253 | MOV ES,DI ; display buffer | ||
| 254 | XOR DI,DI ; DI points to the start of the buffer | ||
| 255 | MOV CX,80*15 ; Only clear 15 lines | ||
| 256 | MOV AX,STACK_ATTR+BLANK ; AH = white on black attribute | ||
| 257 | ; AL = ASCII for a blank | ||
| 258 | REP STOSW ; Write 15 rows of while blanks on black | ||
| 259 | |||
| 260 | ; Highlite the display area | ||
| 261 | |||
| 262 | XOR DI,DI ; DI points to the start of the buffer | ||
| 263 | MOV CX,80*6 ; Highlite 6 lines | ||
| 264 | MOV AX,SEX_ATTR+BLANK ; AH = white on red attribute | ||
| 265 | ; AL = ASCII for a blank | ||
| 266 | REP STOSW ; Highlight the 6 lines | ||
| 267 | |||
| 268 | ; Display the registers one at at time | ||
| 269 | |||
| 270 | MOV CX,21 ; 18 regs + excpt id + task id + error code | ||
| 271 | MOV SI,SYS_PATCH_DS ; Load DS with the selector for our data | ||
| 272 | MOV DS,SI ; area | ||
| 273 | MOV SI,OFFSET REG_TABLE ; DS:SI now points to the reg table | ||
| 274 | SUB AX,AX ; Clear AH | ||
| 275 | MOV AL,XMATID ; Load AL with the current XMA bank ID | ||
| 276 | MOV WORD PTR SS:[BP+BP_PSP2],AX ; The bank ID gets displayed as | ||
| 277 | ; the task ID | ||
| 278 | |||
| 279 | ; Display one register | ||
| 280 | |||
| 281 | DO_REG: | ||
| 282 | |||
| 283 | ; Calculate the offset into the display buffer | ||
| 284 | |||
| 285 | LODSB ; Get the row coordinate | ||
| 286 | MOV AH,160 ; Multiply by 160 byte to a row | ||
| 287 | MUL AH ; (80 bytes of character, attribute) | ||
| 288 | ADD AL,DS:BYTE PTR [SI] ; Add on the number of columns | ||
| 289 | ADC AH,0 ; Don't forget the carry | ||
| 290 | ADD AL,DS:BYTE PTR [SI] ; Add the columns again (remember - | ||
| 291 | ADC AH,0 ; character, attribute) | ||
| 292 | INC SI ; Point to next entry in the reg table | ||
| 293 | MOV DI,AX ; Load DI with the offset into the | ||
| 294 | ; display buffer | ||
| 295 | |||
| 296 | DO_ID: | ||
| 297 | |||
| 298 | ; Put the register name on the screen. | ||
| 299 | |||
| 300 | MOV BX,SEX_ATTR ; Load the attribute byte into AH | ||
| 301 | MOV AH,BH | ||
| 302 | LODSB ; Get the character to display | ||
| 303 | CMP AL,0 ; Are we at the end of the string yet? | ||
| 304 | JZ DID_ID ; Yup. Then go display the register | ||
| 305 | ; value. | ||
| 306 | STOSW ; Else put the next character of the | ||
| 307 | ; register name on the screen | ||
| 308 | JMP DO_ID ; Go get the next character | ||
| 309 | |||
| 310 | DID_ID: | ||
| 311 | |||
| 312 | ; Put the register value on the screen. | ||
| 313 | |||
| 314 | MOV BP,SP ; BP points the start of the register | ||
| 315 | ; save area | ||
| 316 | LODSW ; Get the offset of this register's | ||
| 317 | ; save area | ||
| 318 | ADD BP,AX ; Add to BP. BP ponts to the register | ||
| 319 | ; value. | ||
| 320 | LODSW ; Get the length of this register's | ||
| 321 | MOV DX,AX ; save area | ||
| 322 | CMP DX,2 ; If the length is not two words | ||
| 323 | JNE MORE ; Then go to the one word code | ||
| 324 | |||
| 325 | DATAOV ; Grab all 32 bits of the register | ||
| 326 | MOV AX,SS:WORD PTR [BP] | ||
| 327 | ADD BP,4 ; Point BP past the register value | ||
| 328 | CALL HEXD ; Display the 32 bit value | ||
| 329 | JMP LOOPREG ; Jump over the one word code | ||
| 330 | |||
| 331 | MORE: | ||
| 332 | MOV AX,SS:WORD PTR [BP] ; Get the word value into AX | ||
| 333 | ADD BP,2 ; Step BP past the register value | ||
| 334 | CALL HEXW ; Display the 16 bit value | ||
| 335 | |||
| 336 | LOOPREG: | ||
| 337 | LOOP DO_REG ; Go do another register | ||
| 338 | |||
| 339 | PAGE | ||
| 340 | ; | ||
| 341 | ; Let's go put up the stack for everyone to see !!! | ||
| 342 | ; | ||
| 343 | MOV BP,SP ; Reset BP to point to the beginning | ||
| 344 | ; of the register save area | ||
| 345 | |||
| 346 | ; If the V86 task faulted, display its stack. Else display our stack. | ||
| 347 | |||
| 348 | MOV AX,SS:WORD PTR [BP+BP_FL2] ; Alright, whose fault was it? | ||
| 349 | TEST AL,02H ; Check the VM flag | ||
| 350 | JZ NOTVM86 ; Gulp! It's us. | ||
| 351 | |||
| 352 | ; It was the V86 task that faulted. Set DS:SI to point to their stack. | ||
| 353 | |||
| 354 | MOV AX,HUGE_PTR ; Load DS with a slector that accesses | ||
| 355 | MOV DS,AX ; all of memory as data | ||
| 356 | DATAOV | ||
| 357 | SUB SI,SI ; Clear all 32 bits of ESI | ||
| 358 | MOV SI,SS:[BP+BP_SP] ; Load SI wiht the V86 task's SP | ||
| 359 | DATAOV | ||
| 360 | SUB AX,AX ; Clear all 32 bits of EAX | ||
| 361 | MOV AX,SS:[BP+BP_SS] ; Get the V86 task's SS | ||
| 362 | DATAOV ; Shift it left 4 bits to convert it | ||
| 363 | SHL AX,4 ; to an offset | ||
| 364 | DATAOV ; Add it on to SP. Now SI contains | ||
| 365 | ADD SI,AX ; the offest of the stack from 0 | ||
| 366 | |||
| 367 | MOV BP,0FFFFH ; I don't know what this code does but | ||
| 368 | DATAOV ; I left it anyway. The following | ||
| 369 | ; comment is the only clue. | ||
| 370 | SHL BP,16 ; Make stack seg limit very large | ||
| 371 | JMP COMSTACK | ||
| 372 | |||
| 373 | ; It was us that faulted. Set DS:SI to point to our stack. | ||
| 374 | |||
| 375 | NOTVM86: | ||
| 376 | MOV AX,SS ; Load DS with our own SS | ||
| 377 | MOV DS,AX | ||
| 378 | DATAOV | ||
| 379 | SUB SI,SI ; Clear all 32 bits of ESI | ||
| 380 | MOV SI,SP ; Now DS:SI points to our stack | ||
| 381 | |||
| 382 | ; DS:SI points to the beginning of a stack. Now display it. | ||
| 383 | |||
| 384 | COMSTACK: | ||
| 385 | MOV DI,1120 ; Load DI with the offset into the | ||
| 386 | ; display buffer of where we want | ||
| 387 | ; to display the stack | ||
| 388 | MOV CX,70H ; Display 70H words of the stack | ||
| 389 | MOV BX,STACK_ATTR ; Load BH with the attribute byte | ||
| 390 | |||
| 391 | DISP_STACK: | ||
| 392 | |||
| 393 | ADDROV ; Get a word off of the stack | ||
| 394 | LODSW | ||
| 395 | ADDROV ; Intel bug # A0-119 | ||
| 396 | NOP ; Intel bug # A0-119 | ||
| 397 | CALL HEXW ; Display the word | ||
| 398 | MOV AX,STACK_ATTR+BLANK ; Put a blank after each word | ||
| 399 | STOSW ; Put that on the screen | ||
| 400 | LOOP DISP_STACK ; Do the rest of the stack | ||
| 401 | |||
| 402 | ; Wait for the operator to press the system request key to go to | ||
| 403 | ; the monitor, or the escape key to perform the reset operation | ||
| 404 | |||
| 405 | WAIT_HERE: | ||
| 406 | |||
| 407 | IN AL,064H ; Poll the keystroke port | ||
| 408 | TEST AL,000000001B ; Did the user hit a key? | ||
| 409 | JZ WAIT_HERE ; Nope. Go check again. | ||
| 410 | |||
| 411 | IN AL,060H ; Get the keystroke | ||
| 412 | CMP AL,054H ; System request key? | ||
| 413 | JNE CHK_ESC ; No. Check for Esc key. | ||
| 414 | |||
| 415 | CMP SS:WORD PTR [BP+BP_EX],0EH ; It was system request key. Now | ||
| 416 | ; check for a page fault. | ||
| 417 | JE PAGE_FAULT ; If so, go remove the extra return code | ||
| 418 | ; from the stack and terminate the | ||
| 419 | ; application running in the V86 task. | ||
| 420 | JMP POPREGS ; Else just return to the V86 task @P1C | ||
| 421 | |||
| 422 | CHK_ESC: | ||
| 423 | CMP AL,001H ; Was the Esc key hit? | ||
| 424 | JNE CHKPRT ; Nope. Go check for Print Screen and | ||
| 425 | ; Ctrl-Alt-Del. | ||
| 426 | MOV BP,SP ; Point BP to the register save area | ||
| 427 | CMP SS:WORD PTR [BP+BP_EX],0EH ; Check for a page fault | ||
| 428 | JE PAGE_FAULT ; If so, go remove the extra return | ||
| 429 | ; code from the stack and terminate | ||
| 430 | ; the application running in the | ||
| 431 | ; V86 task. | ||
| 432 | MOV AX,SS:WORD PTR [BP+BP_FL2] ; Else, Esc key hit and no page fault | ||
| 433 | TEST AL,02H ; Check who faulted, them or us | ||
| 434 | JZ DO_RESET ; If it's us, then reIPL. | ||
| 435 | |||
| 436 | TERM_APP: | ||
| 437 | MOV SS:WORD PTR [BP+BP_EX],21H ; If it's them, termintate whatever | ||
| 438 | MOV SS:WORD PTR [BP+BP_AX],4CFFH ; is running by forcing a DOS | ||
| 439 | ; termintate. Return code is FF. | ||
| 440 | JMP DO_MONITOR ; Go pass the interrupt to the V86 | ||
| 441 | ; task | ||
| 442 | |||
| 443 | PAGE_FAULT: | ||
| 444 | ; | ||
| 445 | ; On a page fault the 80386 processor puts an extra error code on our stack. | ||
| 446 | ; (How handy!) We now need to remove the extra error code so that when we pop | ||
| 447 | ; the registers off our stack at the end we end up with our stack possitioned | ||
| 448 | ; correctly for the IRET. To do this, we move everything on the stack that is | ||
| 449 | ; below the extra error code up four bytes. The error code takes up four bytes. | ||
| 450 | ; | ||
| 451 | |||
| 452 | STD ; Shift into reverse, 'cause stacks | ||
| 453 | ; grow down | ||
| 454 | MOV CX,(BP_EC-BP_START)/2 ; Load CX with the number of words | ||
| 455 | MOV DI,(BP_EC+2-BP_START) ; Point DI to the last word of the | ||
| 456 | ADD DI,BP ; extra error code | ||
| 457 | MOV SI,(BP_EC-2-BP_START) ; Point SI to the last word of the | ||
| 458 | ADD SI,BP ; exception code | ||
| 459 | MOV AX,SS ; Set up the selectors | ||
| 460 | MOV ES,AX | ||
| 461 | MOV DS,AX | ||
| 462 | STACK_LOOP: | ||
| 463 | LODSW ; Get a word off the stack | ||
| 464 | STOSW ; And move it up four bytes | ||
| 465 | LOOP STACK_LOOP ; Do that trick again | ||
| 466 | |||
| 467 | CLD ; Shift back into forward | ||
| 468 | ADD BP,4 ; Scoot BP up four bytes to point to | ||
| 469 | ; pur new register save area | ||
| 470 | MOV SP,BP ; Adjust SP, too | ||
| 471 | JMP TERM_APP ; Go kill whatever is running in the V86 | ||
| 472 | ; task | ||
| 473 | CHKPRT: | ||
| 474 | CMP AL,053H ; Was the Del (as in Ctrl-Alt-Del) key | ||
| 475 | ; pressed? | ||
| 476 | JE DO_RESET ; If so, then reIPL | ||
| 477 | |||
| 478 | CMP AL,037H ; Was the print screen key pressed? | ||
| 479 | JNE WAIT_HERE ; Nope. Must be an invalid key. Go get | ||
| 480 | ; another keystroke. | ||
| 481 | |||
| 482 | MOV BP,SP ; It was a print screen. Reset BP to | ||
| 483 | ; point to our register save area. | ||
| 484 | MOV AX,SS:WORD PTR [BP+BP_FL2] ; If is was us that had the problem | ||
| 485 | TEST AL,02H ; then we don't allow print screen | ||
| 486 | ; because the system is not healthy | ||
| 487 | JZ WAIT_HERE ; Go get another key | ||
| 488 | |||
| 489 | MOV SS:WORD PTR [BP+BP_EX],05H ; If it was them then we can do a | ||
| 490 | JMP DO_MONITOR ; print screen. Force the V86 | ||
| 491 | ; task to do an INT 5 (Prt Sc). | ||
| 492 | |||
| 493 | ; | ||
| 494 | ; Reset the system, i.e. reIPL. Put a 1234 in the BIOS reset flag at 472H. | ||
| 495 | ; This will keep BIOS from running through the whole POST upon reIPL. | ||
| 496 | ; | ||
| 497 | |||
| 498 | DO_RESET: | ||
| 499 | MOV AX,HUGE_PTR ; Load ES with a selector that accesses all | ||
| 500 | MOV ES,AX ; of memory as data | ||
| 501 | DATAOV | ||
| 502 | SUB DI,DI ; Clear EDI (32 bit DI) | ||
| 503 | MOV DI,472H ; Load the offset of the BIOS reset flag | ||
| 504 | MOV AX,1234H | ||
| 505 | ADDROV | ||
| 506 | STOSW ; Put 1234 in the BIOS reset flag | ||
| 507 | |||
| 508 | ADDROV ; Intel bug # A0-119 | ||
| 509 | NOP ; Intel bug # A0-119 | ||
| 510 | |||
| 511 | MOV AL,0FEH ; Now OUT a FE to port 64H. This will cause | ||
| 512 | OUT 064H,AL ; the machine to reIPL. | ||
| 513 | |||
| 514 | HALT: HLT ; Just in case we don't reIPL, this halt @P1C | ||
| 515 | JMP HALT ; loop will keep the processor from doing @P1C | ||
| 516 | ; anything else | ||
| 517 | |||
| 518 | DO_MONITOR: | ||
| 519 | |||
| 520 | ; If the exception camefrom the V86 task then pass the interrupt to the | ||
| 521 | ; real mode interrupt vector. | ||
| 522 | |||
| 523 | MOV BP,SP ; Reset BP to point to our register save area | ||
| 524 | ; on the stack | ||
| 525 | MOV AX,SS:WORD PTR [BP+BP_FL2] ; Check if it was the V86 task that | ||
| 526 | TEST AL,02H ; faulted | ||
| 527 | JNZ LONGWAY ; If so, pass the interrupt on | ||
| 528 | JMP POPREGS ; Otherwise just return @P1C | ||
| 529 | |||
| 530 | PAGE | ||
| 531 | |||
| 532 | ; We come here if the check up front said it was the V86 task that faulted. | ||
| 533 | |||
| 534 | LONGWAY: | ||
| 535 | MOV SS:WORD PTR [BP+BP_SP2],0 ;Purify high-order words of SP, SS | ||
| 536 | MOV SS:WORD PTR [BP+BP_SS2],0 ; and IP | ||
| 537 | MOV SS:WORD PTR [BP+BP_IP2],0 | ||
| 538 | |||
| 539 | ; Test for interrupt versus exception. | ||
| 540 | |||
| 541 | CMP SS:WORD PTR [BP+BP_EX],13 ; Check if it was a general | ||
| 542 | ; protection exception | ||
| 543 | JNE LONGWAY2 ; If not, continue checking | ||
| 544 | JMP EMULATE ; If so, then go to INDEEMU to | ||
| 545 | ; emulate the instruction | ||
| 546 | LONGWAY2: | ||
| 547 | CMP SS:WORD PTR [BP+BP_EX],6 ; Was it an invalid op-code | ||
| 548 | ; exception? | ||
| 549 | JB LONGWAY4 ; If lower, then pass the | ||
| 550 | ; interrupt back to the V86 task | ||
| 551 | CMP SS:WORD PTR [BP+BP_EX],7 ; Was it a coprocessor not avail- | ||
| 552 | ; able exception? | ||
| 553 | JA LONGWAY3 ; If greater then do more checking | ||
| 554 | JMP EMULATE ; Emulation needed for interrupts | ||
| 555 | ; 6 and 7 | ||
| 556 | LONGWAY3: | ||
| 557 | CMP SS:WORD PTR [BP+BP_EX],15H ; Check if it was INT 15 | ||
| 558 | JNE LONGWAY4 ; Nope, pass interrupt back to | ||
| 559 | ; the V86 task | ||
| 560 | JMP INT15 ; Emulation needed for INT 15 | ||
| 561 | |||
| 562 | LONGWAY4: | ||
| 563 | |||
| 564 | ; Pass the interrupt back to the V86 task. | ||
| 565 | |||
| 566 | MOV AX,HUGE_PTR ; Load ES with a selector that accesses | ||
| 567 | MOV ES,AX ; all of memory as data | ||
| 568 | DATAOV | ||
| 569 | SUB DI,DI ; Clear all 32 bits of EDI | ||
| 570 | MOV DI,SS:[BP+BP_SP] ; Load DI with the V86 task's SP | ||
| 571 | SUB DI,6 ; Decrement "SP" to make room for the | ||
| 572 | ; push of IP, CS and the flags. | ||
| 573 | ; Note that this assumes there are at | ||
| 574 | ; least 6 bytes keft on the stack. | ||
| 575 | MOV SS:WORD PTR [BP+BP_SP],DI ; Put the new SP into the V86 register | ||
| 576 | ; save area | ||
| 577 | DATAOV | ||
| 578 | SUB AX,AX ; Clear all 32 bits of EAX | ||
| 579 | MOV AX,SS:[BP+BP_SS] ; Load AX with the V86 task's SS | ||
| 580 | DATAOV ; Shift it left four bits to convert | ||
| 581 | SHL AX,4 ; it to an offset | ||
| 582 | DATAOV ; Add it on to SP. Now DI contains | ||
| 583 | ADD DI,AX ; the offest of the stack from 0 | ||
| 584 | |||
| 585 | ; Now put the V86 task's IP, CS and flags on the stack. They are put on in | ||
| 586 | ; reverse order because the stack grows down, but we are going up as we put | ||
| 587 | ; the stuff on the stack. | ||
| 588 | |||
| 589 | MOV AX,SS:[BP+BP_IP] ; Get the V86 task's IP | ||
| 590 | ADDROV | ||
| 591 | STOSW ; Put it on his stack | ||
| 592 | ADDROV ; Intel bug # A0-119 | ||
| 593 | NOP ; Intel bug # A0-119 | ||
| 594 | |||
| 595 | MOV AX,SS:[BP+BP_CS] ; Get the V86 task's CS | ||
| 596 | ADDROV | ||
| 597 | STOSW ; Put it on his stack | ||
| 598 | ADDROV ; Intel bug # A0-119 | ||
| 599 | NOP ; Intel bug # A0-119 | ||
| 600 | |||
| 601 | MOV AX,SS:[BP+BP_FL] ; Get the V86 task's flags | ||
| 602 | ADDROV | ||
| 603 | STOSW ; Put them on his stack | ||
| 604 | ADDROV ; Intel bug # A0-119 | ||
| 605 | NOP ; Intel bug # A0-119 | ||
| 606 | AND AX,3CFFH ; Clean up the flags for our IRET | ||
| 607 | MOV WORD PTR SS:[BP+BP_FL],AX | ||
| 608 | |||
| 609 | MOV SI,SS:[BP+BP_EX] ; Get the interrupt vector | ||
| 610 | SHL SI,2 ; Multiply by four because interrupt | ||
| 611 | ; vectorsare four bytes long | ||
| 612 | MOV AX,HUGE_PTR ; Load DS with a selector that accesses | ||
| 613 | MOV DS,AX ; all of memory as data | ||
| 614 | LODSW ; Get the IP for the interrupt | ||
| 615 | MOV WORD PTR SS:[BP+BP_IP],AX ; Store it in the V86 task's IP | ||
| 616 | LODSW ; Get the CS for the interrupt | ||
| 617 | MOV WORD PTR SS:[BP+BP_CS],AX ; Store it in the V86 task's CS | ||
| 618 | |||
| 619 | PAGE | ||
| 620 | POPREGS: ; @P1C | ||
| 621 | |||
| 622 | ; Pop the saved registers off of our stack and IRET to the V86 task. | ||
| 623 | |||
| 624 | POP ES ; Restore ES | ||
| 625 | DATAOV ; Restore all the registers | ||
| 626 | POPA ; (32 bit registers) | ||
| 627 | POP DS ; Restore DS | ||
| 628 | ADD SP,(BP_IP-BP_EX) ; Step SP past the error code placed | ||
| 629 | ; on our stack by the 80386 | ||
| 630 | DATAOV | ||
| 631 | IRET ; IRET to the V86 task | ||
| 632 | |||
| 633 | SEX ENDP | ||
| 634 | |||
| 635 | SUBTTL HEXD - Convert DWORD in EAX to ASCII string at ES:DI | ||
| 636 | PAGE | ||
| 637 | ; | ||
| 638 | ; INPUT: EAX = hex double word to display | ||
| 639 | ; BH = attribute byte | ||
| 640 | ; ES:DI = location in the display buffer where the characters are | ||
| 641 | ; to be placed | ||
| 642 | ; | ||
| 643 | ; OUTPUT: DI is incremented past last character displayed | ||
| 644 | ; Characters are placed on the screen | ||
| 645 | ; | ||
| 646 | |||
| 647 | HEXD PROC NEAR | ||
| 648 | DATAOV | ||
| 649 | PUSH AX ; Save EAX on the stack | ||
| 650 | DATAOV | ||
| 651 | SHR AX,24 ; Shift the high order byte into AL | ||
| 652 | CALL HEXB ; Convert the byte in AL to ASCII at ES:DI | ||
| 653 | DATAOV | ||
| 654 | POP AX ; Restore the original EAX | ||
| 655 | PUSH AX ; Save the low word of EAX (i.e. AX) | ||
| 656 | DATAOV | ||
| 657 | SHR AX,16 ; Shift the second highest byte into AL | ||
| 658 | CALL HEXB ; Convert the byte in AL to ASCII at ES:DI | ||
| 659 | POP AX ; Restore the low word of EAX (i.e. AX) | ||
| 660 | PUSH AX ; And save it again | ||
| 661 | XCHG AH,AL ; Move the thrid highest byte into AL | ||
| 662 | CALL HEXB ; Convert the byte in AL to an ASCII string | ||
| 663 | POP AX ; Restore AX | ||
| 664 | CALL HEXB ; And conver the last byte to ASCII at ES:DI | ||
| 665 | RET | ||
| 666 | |||
| 667 | HEXD ENDP | ||
| 668 | |||
| 669 | SUBTTL HEXW - Convert WORD in AX to ASCII string at ES:DI | ||
| 670 | PAGE | ||
| 671 | ; | ||
| 672 | ; INPUT: AX = hex word to display | ||
| 673 | ; BH = attribute byte | ||
| 674 | ; ES:DI = location in the display buffer where the characters are | ||
| 675 | ; to be placed | ||
| 676 | ; | ||
| 677 | ; OUTPUT: DI is incremented past last character | ||
| 678 | ; Characters are placed on the screen | ||
| 679 | ; | ||
| 680 | |||
| 681 | HEXW PROC NEAR | ||
| 682 | |||
| 683 | PUSH AX ; Save the value in AX on the stack | ||
| 684 | XCHG AH,AL ; Move the high byte into AL | ||
| 685 | CALL HEXB ; Convert the byte in AL to a string at ES:DI | ||
| 686 | POP AX ; Restore AX | ||
| 687 | CALL HEXB ; Convert the low byte to ASCII at ES:DI | ||
| 688 | RET | ||
| 689 | |||
| 690 | HEXW ENDP | ||
| 691 | |||
| 692 | SUBTTL HEXD - Convert BYTE in AL to ASCII string at ES:DI | ||
| 693 | PAGE | ||
| 694 | ; | ||
| 695 | ; INPUT: AL = hex byte to display | ||
| 696 | ; BH = attribute byte | ||
| 697 | ; ES:DI = location in the display buffer where the characters are | ||
| 698 | ; to be placed | ||
| 699 | ; | ||
| 700 | ; OUTPUT: DI is incremented past last character | ||
| 701 | ; Characters are placed on the screen | ||
| 702 | ; | ||
| 703 | |||
| 704 | HEXB PROC NEAR | ||
| 705 | |||
| 706 | PUSH AX ; Save the value in AX | ||
| 707 | AND AL,0F0H ; Clear the low nibble of AL | ||
| 708 | SHR AL,1 ; Shift the high nibble into the low nibble | ||
| 709 | SHR AL,1 | ||
| 710 | SHR AL,1 | ||
| 711 | SHR AL,1 | ||
| 712 | ADD AL,030H ; Add '0' to convert to ASCII | ||
| 713 | CMP AL,03AH ; Was this hex digit greater than 9? | ||
| 714 | JC OK1 ; Nope. It's OK, so go display it. | ||
| 715 | ADD AL,7 ; Yup. Then convert to 'A' to 'F'. | ||
| 716 | OK1: MOV AH,BH ; Move the attribute into AH | ||
| 717 | STOSW ; Put the character & attribute into the display | ||
| 718 | ; buffer at ES:DI | ||
| 719 | POP AX ; Restore AX | ||
| 720 | AND AL,00FH ; Clear the high nibble of AL | ||
| 721 | ADD AL,030H ; Convert the low nibble to ASCII as before | ||
| 722 | CMP AL,03AH ; Hex digit greater than 9? | ||
| 723 | JC OK2 ; Nope. It's OK, so go display it. | ||
| 724 | ADD AL,7 ; Yup. Then convert to 'A' to 'F'. | ||
| 725 | OK2: MOV AH,BH | ||
| 726 | STOSW | ||
| 727 | RET | ||
| 728 | |||
| 729 | HEXB ENDP | ||
| 730 | |||
| 731 | PAGE | ||
| 732 | |||
| 733 | REG MACRO NAME,ROW,COL,L | ||
| 734 | DB &ROW ; Display of register &NAME starts in | ||
| 735 | DB &COL ; row &ROW and column &COL | ||
| 736 | DB '&NAME:' ; Name to display for register &NAME | ||
| 737 | DB 0 ; End of string marker | ||
| 738 | DW BP_&NAME ; Offset of value of register &NAME | ||
| 739 | ; that we saved on our stack | ||
| 740 | DW &L ; Number of words in the register | ||
| 741 | ENDM | ||
| 742 | |||
| 743 | SUBTTL Register table | ||
| 744 | PAGE | ||
| 745 | REG_TABLE LABEL NEAR | ||
| 746 | ; | ||
| 747 | ; Declare data used for displaying the registers on the screen. For each | ||
| 748 | ; register there is a structure that contains the row and column of where the | ||
| 749 | ; display of the register starts, the text or register name ended with a 0, the | ||
| 750 | ; offset into the stack where the value in the register was saved, and the | ||
| 751 | ; number of words in the register. | ||
| 752 | ; | ||
| 753 | |||
| 754 | ; First, lets fake a register to put the exception message on the screen. | ||
| 755 | |||
| 756 | DB 1 ; Row 1 | ||
| 757 | DB 10 ; Column 10 | ||
| 758 | DB 'System Exception - ' ; Text | ||
| 759 | DB 0 ; End of text | ||
| 760 | DW BP_EX ; Offset to hex value on the stack | ||
| 761 | DW 1 ; Number of words of data | ||
| 762 | |||
| 763 | ; Now, fake one to put the task id (bank ID) on the screen. | ||
| 764 | |||
| 765 | DB 1 ; Row 1 | ||
| 766 | DB 50 ; Column 50 | ||
| 767 | DB 'Task ID - ' ; Text | ||
| 768 | DB 0 ; End of text | ||
| 769 | DW BP_PSP2 ; Offset to hex value on the stack | ||
| 770 | DW 1 ; Number of words of data | ||
| 771 | |||
| 772 | ; Now, lets do the registers | ||
| 773 | |||
| 774 | REG CS,3,1,1 | ||
| 775 | REG IP,3,9,2 | ||
| 776 | REG SS,3,21,1 | ||
| 777 | REG SP,3,29,2 | ||
| 778 | REG DS,3,41,1 | ||
| 779 | REG SI,3,49,2 | ||
| 780 | REG ES,3,61,1 | ||
| 781 | REG DI,3,69,2 | ||
| 782 | |||
| 783 | REG AX,4,1,2 | ||
| 784 | REG BX,4,13,2 | ||
| 785 | REG CX,4,25,2 | ||
| 786 | REG DX,4,37,2 | ||
| 787 | REG BP,4,49,2 | ||
| 788 | REG EC,4,61,2 | ||
| 789 | |||
| 790 | REG FL,5,1,2 | ||
| 791 | REG VMDS,5,18,1 | ||
| 792 | REG VMES,5,33,1 | ||
| 793 | REG VMFS,5,48,1 | ||
| 794 | REG VMGS,5,63,1 | ||
| 795 | |||
| 796 | PROG ENDS | ||
| 797 | |||
| 798 | END | ||
| 799 | |||
diff --git a/v4.0/src/DEV/XMAEM/INDEGDT.ASM b/v4.0/src/DEV/XMAEM/INDEGDT.ASM new file mode 100644 index 0000000..e945373 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEGDT.ASM | |||
| @@ -0,0 +1,379 @@ | |||
| 1 | PAGE 60,132 | ||
| 2 | TITLE INDEGDT - 386 XMA Emulator - Build Global Descriptor Table | ||
| 3 | |||
| 4 | COMMENT # | ||
| 5 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 6 | * * | ||
| 7 | * MODULE NAME : INDEGDT * | ||
| 8 | * * | ||
| 9 | * * | ||
| 10 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. * | ||
| 11 | * * | ||
| 12 | * DESCRIPTIVE NAME: Build the Global Descriptor Table (GDT) * | ||
| 13 | * * | ||
| 14 | * STATUS (LEVEL) : Version (0) Level (1.0) * | ||
| 15 | * * | ||
| 16 | * FUNCTION : Build the Global Descriptor Table (GDT) for the 80386 * | ||
| 17 | * XMA emulator * | ||
| 18 | * * | ||
| 19 | * MODULE TYPE : ASM * | ||
| 20 | * * | ||
| 21 | * REGISTER USAGE : 80386 Standard * | ||
| 22 | * * | ||
| 23 | * RESTRICTIONS : None * | ||
| 24 | * * | ||
| 25 | * DEPENDENCIES : None * | ||
| 26 | * * | ||
| 27 | * ENTRY POINT : GDT_BLD * | ||
| 28 | * * | ||
| 29 | * LINKAGE : Called NEAR from INDEINI * | ||
| 30 | * * | ||
| 31 | * INPUT PARMS : None * | ||
| 32 | * * | ||
| 33 | * RETURN PARMS : None * | ||
| 34 | * * | ||
| 35 | * OTHER EFFECTS : None * | ||
| 36 | * * | ||
| 37 | * EXIT NORMAL : Return to INDEINI * | ||
| 38 | * * | ||
| 39 | * EXIT ERROR : None * | ||
| 40 | * * | ||
| 41 | * EXTERNAL * | ||
| 42 | * REFERENCES : None * | ||
| 43 | * * | ||
| 44 | * SUB-ROUTINES : SREG_2_24BITS - Convert the 16 bit value in AX to a 24 * | ||
| 45 | * bit value in DH and AX. * | ||
| 46 | * ADDOFF - Add the 16 bit offset in AX to the 24 bit value * | ||
| 47 | * in DH and BX. * | ||
| 48 | * * | ||
| 49 | * MACROS : DESCR_DEF - Declare a descriptor entry * | ||
| 50 | * DESCR_INIT - Initialize a descriptor * | ||
| 51 | * * | ||
| 52 | * CONTROL BLOCKS : INDEDAT - System data structures * | ||
| 53 | * * | ||
| 54 | * CHANGE ACTIVITY : * | ||
| 55 | * * | ||
| 56 | * $MOD(INDEGDT) COMP(LOAD) PROD(3270PC) : * | ||
| 57 | * * | ||
| 58 | * $D0=D0004700 410 870530 D : NEW FOR RELEASE 1.1 * | ||
| 59 | * $P1=P0000293 410 870731 D : LIMIT LINES TO 80 CHARACTERS * | ||
| 60 | * $P2=P0000312 410 870804 D : CHANGE COMPONENT FROM MISC TO LOAD * | ||
| 61 | * $P3=P0000410 410 870918 D : RELOCATE DATA AREAS TO MAKE ROOM FOR BIT MAP * | ||
| 62 | * * | ||
| 63 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 64 | # | ||
| 65 | |||
| 66 | .286P ; Enable recognition of 286 privileged instructs. | ||
| 67 | |||
| 68 | .XLIST ; Turn off the listing | ||
| 69 | INCLUDE INDEDAT.INC ; Include system data structures | ||
| 70 | INCLUDE INDEACC.INC ; Include access byte definitions | ||
| 71 | |||
| 72 | IF1 ; Only include macros on the first pass | ||
| 73 | INCLUDE INDEDES.MAC ; Descriptor macros | ||
| 74 | ENDIF | ||
| 75 | .LIST ; Turn on the listing | ||
| 76 | |||
| 77 | PROG SEGMENT PARA PUBLIC 'PROG' | ||
| 78 | |||
| 79 | ASSUME CS:PROG | ||
| 80 | ASSUME SS:NOTHING | ||
| 81 | ASSUME DS:PROG | ||
| 82 | ASSUME ES:NOTHING | ||
| 83 | |||
| 84 | INDEGDT LABEL NEAR | ||
| 85 | |||
| 86 | PUBLIC INDEGDT | ||
| 87 | PUBLIC GDT_BLD | ||
| 88 | PUBLIC GDT_DATA_START | ||
| 89 | PUBLIC SREG_2_24BITS | ||
| 90 | |||
| 91 | ; The following data define a pre-initialized GDT. They represent | ||
| 92 | ; all structures which will exist when the emulator comes up. | ||
| 93 | ; THESE MUST BE INITIALIZED IN THE ORDER IN WHICH THEY APPEAR IN THE | ||
| 94 | ; GDT_DEF STRUCTURE DEFINITION AS IT APPEARS IN INDEDAT.INC. This data | ||
| 95 | ; area will be copied from the code segment to the final GDT resting | ||
| 96 | ; place during initialization. | ||
| 97 | |||
| 98 | GDT_DATA_START LABEL WORD | ||
| 99 | |||
| 100 | ; First entry is unusable | ||
| 101 | |||
| 102 | DESCR_DEF SEG, 0, 0, 0, 0 | ||
| 103 | |||
| 104 | ; The descriptor for GDT itself | ||
| 105 | |||
| 106 | DESCR_DEF SEG, GDT_LEN, GDT_LOC, 3, CPL0_DATA_ACCESS | ||
| 107 | PAGE | ||
| 108 | |||
| 109 | ; The system IDT descriptor | ||
| 110 | |||
| 111 | DESCR_DEF SEG, SIDT_LEN, SIDT_LOC, 3, CPL0_DATA_ACCESS | ||
| 112 | |||
| 113 | ; The real system data area descriptor (XMA pages) | ||
| 114 | |||
| 115 | DESCR_DEF SEG, 0FFFFH, 0000H, 11H, CPL0_DATA_ACCESS | ||
| 116 | |||
| 117 | ; The virtual IDT descriptor (not needed so use for all memory) | ||
| 118 | |||
| 119 | DESCR_DEF SEG, MAX_SEG_LEN, NSEG@_LO, NSEG@_HI, CPL0_DATA_ACCESS | ||
| 120 | |||
| 121 | ; The LOADALL descriptor | ||
| 122 | |||
| 123 | DESCR_DEF SEG, 0, 0, 0, 0 | ||
| 124 | PAGE | ||
| 125 | |||
| 126 | ; Compatible monochrome display | ||
| 127 | |||
| 128 | DESCR_DEF SEG, MCRT_SIZE, MCRT@_LO, MCRT@_HI, CPL0_DATA_ACCESS | ||
| 129 | |||
| 130 | ; Compatible color display | ||
| 131 | |||
| 132 | DESCR_DEF SEG, CCRT_SIZE, CCRT@_LO, CCRT@_HI, CPL0_DATA_ACCESS | ||
| 133 | |||
| 134 | ; Enhanced color display - one entry for each 64K P1C | ||
| 135 | |||
| 136 | DESCR_DEF SEG, ECCRT_SIZE, ECCRT@_LO_LO, ECCRT@_LO_HI, CPL0_DATA_ACCESS | ||
| 137 | |||
| 138 | ; Second part of enhanced display P1C | ||
| 139 | |||
| 140 | DESCR_DEF SEG, ECCRT_SIZE, ECCRT@_HI_LO, ECCRT@_HI_HI, CPL0_DATA_ACCESS | ||
| 141 | PAGE | ||
| 142 | |||
| 143 | ; Code segment for ROM code, system IDT | ||
| 144 | |||
| 145 | DESCR_DEF SEG, MAX_SEG_LEN, CSEG@_LO, CSEG@_HI, CPL0_CODE_ACCESS | ||
| 146 | |||
| 147 | ; Data segment for ROM code, system IDT | ||
| 148 | |||
| 149 | DESCR_DEF SEG, MAX_SEG_LEN, CSEG@_LO, CSEG@_HI, CPL0_CODE_ACCESS | ||
| 150 | |||
| 151 | ; Temporarily, the monitor is installed using the patch | ||
| 152 | ; segment descriptors in the GDT | ||
| 153 | |||
| 154 | MSEG@_LO EQU 00000H | ||
| 155 | MSEG@_HI EQU 008H | ||
| 156 | |||
| 157 | |||
| 158 | ; Code segment for patch code, system IDT | ||
| 159 | |||
| 160 | DESCR_DEF SEG, MAX_SEG_LEN, MSEG@_LO, MSEG@_HI, CPL0_CODE_ACCESS | ||
| 161 | |||
| 162 | ; Data segment for patch code, system IDT | ||
| 163 | |||
| 164 | DESCR_DEF SEG, MAX_SEG_LEN, MSEG@_LO, MSEG@_HI, CPL0_DATA_ACCESS | ||
| 165 | PAGE | ||
| 166 | |||
| 167 | ; Code segment for ROM code, virtual IDT | ||
| 168 | |||
| 169 | DESCR_DEF SEG, MAX_SEG_LEN, CSEG@_LO, CSEG@_HI, CPL0_CODE_ACCESS | ||
| 170 | |||
| 171 | ; Data segment for ROM code, virtual IDT | ||
| 172 | |||
| 173 | DESCR_DEF SEG, MAX_SEG_LEN, CSEG@_LO, CSEG@_HI, CPL0_CODE_ACCESS | ||
| 174 | |||
| 175 | ; Code segment for patch code, virtual IDT | ||
| 176 | |||
| 177 | DESCR_DEF SEG, NULL_SEG_LEN, NSEG@_LO, NSEG@_HI, NULL_ACCESS | ||
| 178 | |||
| 179 | ; Data segment for patch code, virtual IDT | ||
| 180 | |||
| 181 | DESCR_DEF SEG, NULL_SEG_LEN, NSEG@_LO, NSEG@_HI, NULL_ACCESS | ||
| 182 | PAGE | ||
| 183 | |||
| 184 | ; Temporary descriptors for ES, CS, SS, and DS | ||
| 185 | |||
| 186 | DESCR_DEF SEG, MAX_SEG_LEN, NSEG@_LO, NSEG@_HI, CPL0_DATA_ACCESS | ||
| 187 | |||
| 188 | DESCR_DEF SEG, MAX_SEG_LEN, NSEG@_LO, NSEG@_HI, CPL0_CODE_ACCESS | ||
| 189 | |||
| 190 | DESCR_DEF SEG, MAX_SEG_LEN, NSEG@_LO, NSEG@_HI, CPL0_DATA_ACCESS | ||
| 191 | |||
| 192 | DESCR_DEF SEG, MAX_SEG_LEN, NSEG@_LO, NSEG@_HI, CPL0_DATA_ACCESS | ||
| 193 | PAGE | ||
| 194 | |||
| 195 | ; These DQ's pad out the space between the last MultiPC descriptor and the | ||
| 196 | ; PMVM descriptors. They don't need initialization. | ||
| 197 | |||
| 198 | DQ 9 DUP (0) ; These 9 are for the Monitor descriptors | ||
| 199 | |||
| 200 | ; This is for the keyboard owner (not used) | ||
| 201 | |||
| 202 | DQ 0 | ||
| 203 | |||
| 204 | ; These 16 are for the virtual timer support | ||
| 205 | |||
| 206 | DQ 16 DUP (0) | ||
| 207 | |||
| 208 | ; The following 32 descriptors are for exception condition task gates. | ||
| 209 | |||
| 210 | REPT 32 | ||
| 211 | DQ 0 | ||
| 212 | ENDM | ||
| 213 | |||
| 214 | ; The following 16 pairs are for the hardware interrupt handling tasks. | ||
| 215 | |||
| 216 | REPT 16 | ||
| 217 | DQ 0 | ||
| 218 | DQ 0 | ||
| 219 | ENDM | ||
| 220 | |||
| 221 | ; The following pair is for the DISPATCH task | ||
| 222 | |||
| 223 | DESCR_DEF SEG, TSS_LEN, DISPATCH_LOC, 3, <TSS_ACCESS OR FREE_TSS> | ||
| 224 | DESCR_DEF SEG, TSS_LEN, DISPATCH_LOC, 3, CPL0_DATA_ACCESS | ||
| 225 | |||
| 226 | DESCR_DEF SEG, 0, 0, 0,LDT_DESC | ||
| 227 | |||
| 228 | ; BASIC's segment | ||
| 229 | |||
| 230 | DESCR_DEF SEG, 07FFFH, 06000H, 0FH, CPL0_DATA_ACCESS | ||
| 231 | |||
| 232 | ; BIOS's segment | ||
| 233 | |||
| 234 | DESCR_DEF SEG, 01FFFH, 00000H, 0FH, CPL0_DATA_ACCESS | ||
| 235 | |||
| 236 | DQ 13 DUP (0) ; Reserved guys | ||
| 237 | |||
| 238 | ; The following guys are junk ! Used before the first TSS allocated. These | ||
| 239 | ; have to be in the PMVM location in the GDT. | ||
| 240 | |||
| 241 | DESCR_DEF SEG, TSS_LEN, 0C000H, 0, FREE_TSS ; For the TR | ||
| 242 | |||
| 243 | DESCR_DEF SEG, TSS_LEN, 0C000H, 0, CPL0_DATA_ACCESS ; TSS as data | ||
| 244 | |||
| 245 | DESCR_DEF SEG, GDT_LEN, 0D000H, 0, LDT_DESC ; For the LDTR | ||
| 246 | |||
| 247 | DESCR_DEF SEG, GDT_LEN, 0D000H, 0, CPL0_DATA_ACCESS ; LDT as data | ||
| 248 | |||
| 249 | GDT_DATA_END LABEL WORD | ||
| 250 | |||
| 251 | COPY_LEN EQU GDT_DATA_END-GDT_DATA_START | ||
| 252 | |||
| 253 | ; | ||
| 254 | ; End of pre-allocated GDT | ||
| 255 | ; | ||
| 256 | |||
| 257 | PAGE | ||
| 258 | |||
| 259 | GDT_BLD PROC NEAR | ||
| 260 | |||
| 261 | ; Copy the pre-initialized GDT into its proper location in memory | ||
| 262 | |||
| 263 | CLI ; All string operations go forward | ||
| 264 | |||
| 265 | MOV SI,OFFSET GDT_DATA_START ; DS:SI points to the pre-initialized | ||
| 266 | ; GDT above | ||
| 267 | MOV CX,COPY_LEN/2 ; CX = number of words to copy | ||
| 268 | MOV DI,GDT_LOC ; ES:DI points to the GDT location | ||
| 269 | REP MOVSW ; Copy GDT into its final resting place | ||
| 270 | |||
| 271 | ; Now let's initialize some of the GDT entries | ||
| 272 | |||
| 273 | ; Set up the descriptors for our code segment and data segment | ||
| 274 | |||
| 275 | MOV AX,CS ; Get our CS | ||
| 276 | CALL SREG_2_24BITS ; And convert it to a 24 bit offset | ||
| 277 | MOV BX,AX ; Get the monitor offset | ||
| 278 | |||
| 279 | ALLSET: | ||
| 280 | DESCR_INIT SEG, SYS_PATCH_CS, 07FFFH, BX, DH, CPL0_CODE_ACCESS | ||
| 281 | DESCR_INIT SEG, SYS_PATCH_DS, 0FFFFH, BX, DH, CPL0_DATA_ACCESS | ||
| 282 | |||
| 283 | ; Initialize the descriptor for the GDT | ||
| 284 | |||
| 285 | MOV AX,ES ; Get the segment of the GDT | ||
| 286 | CALL SREG_2_24BITS ; Convert to a 24 bit offset | ||
| 287 | MOV DL,DH ; Save a copy of the hi byte | ||
| 288 | MOV BX,GDT_LOC ; Add on the offset of the GDT | ||
| 289 | CALL ADDOFF | ||
| 290 | |||
| 291 | DESCR_INIT SEG, GDT_PTR, GDT_LEN, BX, DH, CPL0_DATA_ACCESS | ||
| 292 | |||
| 293 | ; Initialize the descriptor for the IDT | ||
| 294 | |||
| 295 | MOV BX,SIDT_LOC ; DH,AX already contains the segment | ||
| 296 | ; converted to 24 bits so all we | ||
| 297 | CALL ADDOFF ; have to do is add on the offset | ||
| 298 | |||
| 299 | DESCR_INIT SEG, MON_IDT_PTR, SIDT_LEN, BX, DH, CPL0_DATA_ACCESS | ||
| 300 | |||
| 301 | ; Initialize the descriptor that accesses all of memory as data | ||
| 302 | |||
| 303 | DESCR_INIT BSEG, HUGE_PTR, 0FFFFH, 0, 0, CPL0_DATA_ACCESS | ||
| 304 | |||
| 305 | ; Initialize the descriptors for the V86 task's LDT | ||
| 306 | |||
| 307 | MOV BX,DISPATCH_LOC ; @P3C | ||
| 308 | CALL ADDOFF | ||
| 309 | |||
| 310 | DESCR_INIT SEG,SCRUBBER.VM_LDTR,00FFFH,BX,DH,LDT_DESC | ||
| 311 | DESCR_INIT SEG,SCRUBBER.LDT_PTR,00FFFH,BX,DH,CPL0_DATA_ACCESS | ||
| 312 | |||
| 313 | ; Initialize the descriptors for the V86 task's TR | ||
| 314 | |||
| 315 | MOV BX,DISPATCH_LOC ; @P3C | ||
| 316 | CALL ADDOFF | ||
| 317 | |||
| 318 | DESCR_INIT SEG,SCRUBBER.VM_TR,TSS_LEN,BX,DH,FREE_TSS_386 ; @P3C | ||
| 319 | DESCR_INIT SEG,SCRUBBER.TSS_PTR,TSS_LEN,BX,DH,CPL0_DATA_ACCESS; @P3C | ||
| 320 | |||
| 321 | RET | ||
| 322 | |||
| 323 | GDT_BLD ENDP | ||
| 324 | |||
| 325 | PAGE | ||
| 326 | ; SREG_2_24BITS converts the segment register 16 bit value in the AX register | ||
| 327 | ; into a 24 bit value in DH and AX | ||
| 328 | ; | ||
| 329 | ; Input : AX = segment register value | ||
| 330 | ; | ||
| 331 | ; Output: AX = 24 bit low word | ||
| 332 | ; DH = 24 bit high byte | ||
| 333 | |||
| 334 | |||
| 335 | SREG_2_24BITS PROC NEAR | ||
| 336 | |||
| 337 | ; Put the high four bits of AH into the low four bits of DH | ||
| 338 | |||
| 339 | MOV DH,AH ; Get the high byte of the segment value | ||
| 340 | ; into DH | ||
| 341 | AND DH,0F0H ; Strip off the low nibble | ||
| 342 | SHR DH,4 ; Shift right four bits | ||
| 343 | |||
| 344 | ; Now shift AX left four bits | ||
| 345 | |||
| 346 | AND AH,00FH ; Strip high nibble from AH | ||
| 347 | ; This keeps the carry flag from being | ||
| 348 | ; set which could effect later ADDs. | ||
| 349 | SHL AX,4 ; Shift AX | ||
| 350 | |||
| 351 | RET | ||
| 352 | |||
| 353 | SREG_2_24BITS ENDP | ||
| 354 | |||
| 355 | PAGE | ||
| 356 | ; ADDOFF adds the 16 bit offset in BX to the 24 bit value in DL and AX. The | ||
| 357 | ; result is left in DH and BX. | ||
| 358 | ; | ||
| 359 | ; Input : DL = 24 bit high byte | ||
| 360 | ; AX = 24 bit low word | ||
| 361 | ; BX = offset to be added | ||
| 362 | ; | ||
| 363 | ; Output: DH = 24 bit high byte | ||
| 364 | ; BX = 24 bit low word | ||
| 365 | |||
| 366 | ADDOFF PROC NEAR | ||
| 367 | |||
| 368 | MOV DH,DL ; Restore the high byte that was saved | ||
| 369 | ; in DL | ||
| 370 | ADD BX,AX ; Add on the offset | ||
| 371 | ADC DH,0 ; Add the carry, if any, to the high | ||
| 372 | ; byte | ||
| 373 | RET | ||
| 374 | |||
| 375 | ADDOFF ENDP | ||
| 376 | |||
| 377 | PROG ENDS | ||
| 378 | |||
| 379 | END | ||
diff --git a/v4.0/src/DEV/XMAEM/INDEI15.ASM b/v4.0/src/DEV/XMAEM/INDEI15.ASM new file mode 100644 index 0000000..047648d --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEI15.ASM | |||
| @@ -0,0 +1,503 @@ | |||
| 1 | PAGE 60,132 | ||
| 2 | TITLE INDEI15 - 386 XMA Emulator - Interrupt 15 handler | ||
| 3 | |||
| 4 | COMMENT # | ||
| 5 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 6 | * * | ||
| 7 | * MODULE NAME : INDEI15 * | ||
| 8 | * * | ||
| 9 | * * | ||
| 10 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. * | ||
| 11 | * * | ||
| 12 | * DESCRIPTIVE NAME: Interrupt 15H handler for the 80386 XMA emulator * | ||
| 13 | * * | ||
| 14 | * STATUS (LEVEL) : Version (0) Level (2.0) * | ||
| 15 | * * | ||
| 16 | * FUNCTION : This module emulates the MOVEBLOCK functions of interrupt * | ||
| 17 | * 15H. The MOVEBLOCK functions are specified by an AH value* | ||
| 18 | * of 87H to 89H. The user can use the MOVEBLOCK functions * | ||
| 19 | * to copy a block of memory to another block of memory. * | ||
| 20 | * This includes copying to and from memory above 1M. This * | ||
| 21 | * is really where this function comes in handy. The user * | ||
| 22 | * can reserve memory above 1M for use by the MOVEBLOCK * | ||
| 23 | * functions by specifying the number of K to be reserved as * | ||
| 24 | * a parameter on the line to load the emulator in the * | ||
| 25 | * CONFIG.SYS file. * | ||
| 26 | * * | ||
| 27 | * DEVICE=INDXMAEM.SYS bbb * | ||
| 28 | * * | ||
| 29 | * "bbb" is the number of K to reserve for MOVEBLOCK * | ||
| 30 | * functions * | ||
| 31 | * * | ||
| 32 | * We allocate a buffer for the MOVEBLOCK functions at the * | ||
| 33 | * top of available memory. Any functions dealing with this * | ||
| 34 | * buffer area must be handles by us. * | ||
| 35 | * * | ||
| 36 | * Function 87H is the actual MOVEBLOCK function. The user * | ||
| 37 | * passes a 32 bit source address and a 32 bit destination * | ||
| 38 | * address in a parameter list pointed to by ES:SI. CX * | ||
| 39 | * contains the number of words to copy. We need to * | ||
| 40 | * intercept this call and check the source and destination * | ||
| 41 | * addresses. If either or both of these addresses is above * | ||
| 42 | * 1M then we need to adjust the addresses so that they * | ||
| 43 | * access the MOVEBLOCK buffer up at the top of memory. You * | ||
| 44 | * see, the user thinks the extended memory starts right * | ||
| 45 | * after the 1M boundary. We want to make it look like the * | ||
| 46 | * MOVEBLOCK buffer sits right after the 1M boundary. So we * | ||
| 47 | * monkey with the user's addresses so that they access the * | ||
| 48 | * MOVEBLOCK buffer instead of real memory after 1M, because * | ||
| 49 | * that memory is us. * | ||
| 50 | * * | ||
| 51 | * Function 88H queries how many K are above the 1M * | ||
| 52 | * boundary. We can't tell him how much is really there * | ||
| 53 | * because some of it is us and our XMA pages. So for this * | ||
| 54 | * function we will just return the size of the MOVEBLOCK * | ||
| 55 | * buffer. This function was moved to a real mode P3C* | ||
| 56 | * interrupt handler in module INDE15H. P3C* | ||
| 57 | * * | ||
| 58 | * Function 89H is reserved for the MOVEBLOCK functions but * | ||
| 59 | * is not in use right now. So for this function we just * | ||
| 60 | * return a bad return code in AH and set the carry flag. * | ||
| 61 | * * | ||
| 62 | * MODULE TYPE : ASM * | ||
| 63 | * * | ||
| 64 | * REGISTER USAGE : 80386 Standard * | ||
| 65 | * * | ||
| 66 | * RESTRICTIONS : None * | ||
| 67 | * * | ||
| 68 | * DEPENDENCIES : None * | ||
| 69 | * * | ||
| 70 | * ENTRY POINT : INT15 * | ||
| 71 | * * | ||
| 72 | * LINKAGE : Jumped to from INDEEXC * | ||
| 73 | * * | ||
| 74 | * INPUT PARMS : None * | ||
| 75 | * * | ||
| 76 | * RETURN PARMS : None * | ||
| 77 | * * | ||
| 78 | * OTHER EFFECTS : None * | ||
| 79 | * * | ||
| 80 | * EXIT NORMAL : Go to POPIO in INDEEMU to IRET to the V86 task * | ||
| 81 | * * | ||
| 82 | * EXIT ERROR : None * | ||
| 83 | * * | ||
| 84 | * EXTERNAL * | ||
| 85 | * REFERENCES : EMULATE - Entry point for INDEEMU * | ||
| 86 | * POPIO - Entry in INDEEMU to check for single step * | ||
| 87 | * interrupts, pop the registers and IRET to the * | ||
| 88 | * V86 task * | ||
| 89 | * POPREGS - Entry point in INDEEXC to pop the registers * | ||
| 90 | * off the stack and IRET to the V86 task P2C* | ||
| 91 | * * | ||
| 92 | * SUB-ROUTINES : None * | ||
| 93 | * * | ||
| 94 | * MACROS : DATAOV - Add prefix for the next instruction so that it * | ||
| 95 | * accesses data as 32 bits wide * | ||
| 96 | * ADDROV - Add prefix for the next instruction so that it * | ||
| 97 | * uses addresses that are 32 bits wide * | ||
| 98 | * * | ||
| 99 | * CONTROL BLOCKS : INDEDAT.INC * | ||
| 100 | * * | ||
| 101 | * CHANGE ACTIVITY : * | ||
| 102 | * * | ||
| 103 | * $MOD(INDEI15) COMP(LOAD) PROD(3270PC) : * | ||
| 104 | * * | ||
| 105 | * $D0=D0004700 410 870603 D : NEW FOR RELEASE 1.1 * | ||
| 106 | * $P1=P0000293 410 870731 D : LIMIT LINES TO 80 CHARACTERS * | ||
| 107 | * $P2=P0000312 410 870804 D : CLEAN UP WARNING MESSAGES * | ||
| 108 | * $D1=D0007100 410 870817 D : CHANGE TO EMULATE XMA 2 * | ||
| 109 | * $P3=P0000xxx 120 880331 D : MOVE FUNCTION 88H HANDLING TO INDE15H * | ||
| 110 | * * | ||
| 111 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 112 | # | ||
| 113 | |||
| 114 | .286P ; Enable recognition of 286 privileged instructs. | ||
| 115 | |||
| 116 | .XLIST ; Turn off the listing | ||
| 117 | INCLUDE INDEDAT.INC ; Include the system data structures | ||
| 118 | |||
| 119 | IF1 ; Only include the macros on the first pass | ||
| 120 | INCLUDE INDEOVP.MAC | ||
| 121 | ENDIF | ||
| 122 | .LIST ; Turn on the listing | ||
| 123 | |||
| 124 | PROG SEGMENT PARA PUBLIC 'PROG' | ||
| 125 | |||
| 126 | ASSUME CS:PROG | ||
| 127 | ASSUME DS:PROG | ||
| 128 | ASSUME ES:NOTHING | ||
| 129 | ASSUME SS:NOTHING | ||
| 130 | |||
| 131 | INDEI15 LABEL NEAR | ||
| 132 | |||
| 133 | EXTRN EMULATE:NEAR ; Entry point for INDEEMU | ||
| 134 | EXTRN POPIO:NEAR ; Entry in INDEEMU to check for single | ||
| 135 | ; step interrupts and return to the | ||
| 136 | ; V86 task | ||
| 137 | EXTRN POPREGS:NEAR ; Entry in INDEEXC to return to the P2C | ||
| 138 | ; V86 task | ||
| 139 | |||
| 140 | PUBLIC INDEI15 | ||
| 141 | PUBLIC INT15 | ||
| 142 | PUBLIC TTTABLE | ||
| 143 | |||
| 144 | PAGE | ||
| 145 | |||
| 146 | INT15 PROC NEAR | ||
| 147 | |||
| 148 | CLD ; All string operations go forward | ||
| 149 | |||
| 150 | ; We handle the INT 15H functions for MOVEBLOCK interface. These functions | ||
| 151 | ; are specified by an AH value of 87H to 89H. Function 87H is the MOVEBLOCK | ||
| 152 | ; function. Function 88H queries the size of memory above 1M. Function 89H | ||
| 153 | ; is reserved but not supported so we return a return code of 86H. | ||
| 154 | |||
| 155 | CMP SS:BYTE PTR [BP+BP_AX+1],87H ; Is AH asking for function 87H? | ||
| 156 | JB NOTMINE ; No. It's too low. It's out of our | ||
| 157 | ; range so we'll pass it on to the | ||
| 158 | ; real vector. | ||
| 159 | JE MOVEBLK ; It is 87H! Let's go do the MOVEBLOCK. | ||
| 160 | |||
| 161 | CMP SS:BYTE PTR [BP+BP_AX+1],89H ; Is AH asking for function 89H? | ||
| 162 | JNE NOTMINE ; No. It's not our function so @P3C | ||
| 163 | ; so we'll pass it on to the real | ||
| 164 | ; vector. | ||
| 165 | ; @P3D | ||
| 166 | MOV SS:BYTE PTR [BP+BP_AX+1],86H ; It's 89H. Sorry we don't support | ||
| 167 | ; that function. Put an 86H return | ||
| 168 | ; code in AH. | ||
| 169 | OR WORD PTR SS:[BP+BP_FL],1 ; Set the carry flag | ||
| 170 | JMP POPIO ; And return to the V86 task | ||
| 171 | |||
| 172 | ; Hey, it's not MY interrupt. | ||
| 173 | |||
| 174 | NOTMINE: | ||
| 175 | JMP DOINT ; Go pass the interrupt back to the | ||
| 176 | ; real INT 15H vector | ||
| 177 | |||
| 178 | |||
| 179 | ; Function 88H code to query the size of memory above 1M was moved to 3@P3D | ||
| 180 | ; INDE15H. | ||
| 181 | |||
| 182 | PAGE | ||
| 183 | ; The user wants to move a block of memory. Now the source and target of the | ||
| 184 | ; MOVEBLOCK can each be below 1M or above 1M. For addresses above 1M we must | ||
| 185 | ; make adjustments so that the MOVEBLOCK is done to and/or from the MOVEBLOCK | ||
| 186 | ; buffer in high memory. The user passes a parameter list which is pointed | ||
| 187 | ; at by ES:SI. At offset 0EH is a 32 bit pointer to the source block. At | ||
| 188 | ; offset 1AH is a 32 bit pointer to the destination block. CX contains the | ||
| 189 | ; number of words to move. Here we go! | ||
| 190 | |||
| 191 | MOVEBLK: | ||
| 192 | MOV AX,HUGE_PTR ; Load DS and ES with a selector that | ||
| 193 | MOV DS,AX ; accesses all of memory as data | ||
| 194 | MOV ES,AX | ||
| 195 | |||
| 196 | ; Get the user's ES:SI and convert it to a 32 bit offset in ESI. | ||
| 197 | |||
| 198 | DATAOV ; Purge ESI | ||
| 199 | SUB SI,SI | ||
| 200 | MOV SI,SS:[BP+BP_SI] ; Load SI with the user's SI | ||
| 201 | |||
| 202 | DATAOV ; Purge EBX | ||
| 203 | SUB BX,BX | ||
| 204 | MOV BX,10H ; Set EBX to 1M by loading it with 10H | ||
| 205 | DATAOV ; and shifting it left 16 bits to | ||
| 206 | SHL BX,16 ; multiply by 64K | ||
| 207 | |||
| 208 | DATAOV ; Sterilize EAX | ||
| 209 | SUB AX,AX | ||
| 210 | MOV AX,SS:[BP+BP_VMES] ; Load AX with the user's ES | ||
| 211 | DATAOV ; Shift it left four bits to convert it | ||
| 212 | SHL AX,4 ; to an offset | ||
| 213 | |||
| 214 | DATAOV ; Add the ES offset on to SI. Now ESI | ||
| 215 | ADD SI,AX ; is the offset from 0 of the user's | ||
| 216 | ; parameter list. | ||
| 217 | DATAOV ; Add 1AH to SI. Now it points to the | ||
| 218 | ADD SI,1AH ; 32 bit destination address. | ||
| 219 | |||
| 220 | DATAOV | ||
| 221 | ADDROV ; Get the 32 bit destination address | ||
| 222 | LODSW ; into EAX | ||
| 223 | |||
| 224 | ADDROV ; Intel bug # A0-119 | ||
| 225 | NOP ; Intel bug # A0-119 | ||
| 226 | |||
| 227 | DATAOV ; Clear the top eight bits of any | ||
| 228 | SHL AX,8 ; residual gunk. Only 24 bit ;P1C | ||
| 229 | DATAOV ; addresses (16M) are allowed anyway. | ||
| 230 | SHR AX,8 ; Shift the bits off the left end and | ||
| 231 | ; shift zeroes back in. | ||
| 232 | DATAOV ; Move this clean value into EDI | ||
| 233 | MOV DI,AX ; EDI now has the destination address | ||
| 234 | |||
| 235 | DATAOV ; Check if this address is over 1M. If | ||
| 236 | CMP DI,BX ; so then it's going to our MOVEBLOCK | ||
| 237 | ; buffer. | ||
| 238 | JB OK1 ; It's below 1M? OK. Leave it alone. | ||
| 239 | |||
| 240 | ; The destination is above 1M so we have to modify the destination address so | ||
| 241 | ; that it points to our MOVEBLOCK buffer. | ||
| 242 | |||
| 243 | PUSH DS ; Save DS | ||
| 244 | MOV AX,SYS_PATCH_DS ; Load DS with the selector for our data | ||
| 245 | MOV DS,AX ; segment | ||
| 246 | |||
| 247 | DATAOV ; Clean up EAX | ||
| 248 | SUB AX,AX | ||
| 249 | MOV AX,MAXMEM ; Load the total number of K on the box | ||
| 250 | SUB AX,BUFF_SIZE ; Subtract the MOVEBLOCK buffer size | ||
| 251 | SUB AX,1024 ; Subtract 1M (/1K) for 0 to 1M. This | ||
| 252 | ; leaves AX with the number of K from | ||
| 253 | ; 1M to the MOVEBLOCK buffer. | ||
| 254 | POP DS ; Restore DS | ||
| 255 | DATAOV ; Multiply EAX by 1K (shift left 10) to | ||
| 256 | SHL AX,10 ; convert it to an offset from 1M of | ||
| 257 | ; the MOVEBLOCK buffer | ||
| 258 | DATAOV ; Add this to EDI. EDI now points to | ||
| 259 | ADD DI,AX ; a location within (hopefully) the | ||
| 260 | ; MOVEBLOCK buffer as if the buffer | ||
| 261 | ; were located at the 1M boundary. | ||
| 262 | |||
| 263 | ; Now let's get the source address | ||
| 264 | |||
| 265 | OK1: | ||
| 266 | DATAOV ; Subtract 0C from ESI to point ESI to | ||
| 267 | SUB SI,0CH ; offset 0E in the parameter list | ||
| 268 | |||
| 269 | DATAOV | ||
| 270 | ADDROV ; Get the 32 bit source address into | ||
| 271 | LODSW ; EAX | ||
| 272 | |||
| 273 | ADDROV ; Intel bug # A0-119 | ||
| 274 | NOP ; Intel bug # A0-119 | ||
| 275 | |||
| 276 | DATAOV ; Clear the top eight bits of any | ||
| 277 | SHL AX,8 ; residual gunk. Only 24 bit address | ||
| 278 | DATAOV ; (16M) are allowed. Shift the gunky | ||
| 279 | SHR AX,8 ; bits off the left end and shift | ||
| 280 | ; zeroes back in. | ||
| 281 | DATAOV ; Move this clean value into ESI | ||
| 282 | MOV SI,AX ; ESI now has the source address | ||
| 283 | |||
| 284 | DATAOV ; Check if this address is over 1M. If | ||
| 285 | CMP SI,BX ; so then it's goin' to our MOVEBLOCK | ||
| 286 | ; buffer. | ||
| 287 | JB OK2 ; It's below 1M? OK. Let it be. | ||
| 288 | |||
| 289 | ; The source is above 1M so we have to modify the source address so that it | ||
| 290 | ; points to our MOVEBLOCK buffer. | ||
| 291 | |||
| 292 | PUSH DS ; Save DS | ||
| 293 | MOV AX,SYS_PATCH_DS ; Load DS with the selector for our data | ||
| 294 | MOV DS,AX ; segment | ||
| 295 | |||
| 296 | DATAOV ; Sanitize up EAX | ||
| 297 | SUB AX,AX | ||
| 298 | MOV AX,MAXMEM ; Load the total number of K on the box | ||
| 299 | SUB AX,BUFF_SIZE ; Subtract the MOVEBLOCK buffer size | ||
| 300 | SUB AX,1024 ; Subtract 1M (/1K) for 0 to 1M. This | ||
| 301 | ; leaves AX with the number of K from | ||
| 302 | ; 1M to the MOVEBLOCK buffer. | ||
| 303 | POP DS ; Restore DS | ||
| 304 | DATAOV ; Multiply EAX by 1K (shift left 10) to | ||
| 305 | SHL AX,10 ; convert it to an offset from 1M of | ||
| 306 | ; the MOVEBLOCK buffer | ||
| 307 | DATAOV ; Add this to ESI. ESI now points to | ||
| 308 | ADD SI,AX ; a location within (hopefully) the | ||
| 309 | ; MOVEBLOCK buffer as if the buffer | ||
| 310 | ; were located at the 1M boundary. | ||
| 311 | |||
| 312 | ; Our pointers are all set. Let's get CX and do the copy for the guy. | ||
| 313 | |||
| 314 | OK2: | ||
| 315 | MOV CX,SS:[BP+BP_CX] ; Get the user's CX | ||
| 316 | TEST CL,01H ; Is this an even number? | ||
| 317 | JZ MOV4 ; If so, we can make the copy faster | ||
| 318 | ; by moving double words | ||
| 319 | ADDROV ; Nope. It's odd. We'll just do the | ||
| 320 | REP MOVSW ; copy with words. | ||
| 321 | |||
| 322 | ADDROV ; Intel bug # A0-119 | ||
| 323 | NOP ; Intel bug # A0-119 | ||
| 324 | |||
| 325 | JMP MOVCOM ; Skip over the double word copy | ||
| 326 | |||
| 327 | MOV4: | ||
| 328 | SHR CX,1 ; Divide the count by two since we'll | ||
| 329 | ; be copying double words | ||
| 330 | DATAOV ; Do it 32 bits wide | ||
| 331 | ADDROV ; Use the 32 bit ESI and EDI | ||
| 332 | REP MOVSW ; Ready? ZOOOOM! | ||
| 333 | |||
| 334 | ADDROV ; Intel bug # A0-119 | ||
| 335 | NOP ; Intel bug # A0-119 | ||
| 336 | |||
| 337 | ; Now let's set the flags and return code in AH to show that every thing went | ||
| 338 | ; A-OK. | ||
| 339 | |||
| 340 | MOVCOM: | ||
| 341 | MOV SS:BYTE PTR [BP+BP_AX+1],0 ; Set a zero return code in AH | ||
| 342 | AND WORD PTR SS:[BP+BP_FL],0FFFEH ; Reset the carry flag | ||
| 343 | OR WORD PTR SS:[BP+BP_FL],40H ; Set the zero flag | ||
| 344 | |||
| 345 | JMP POPIO ; Return to the V86 task | ||
| 346 | |||
| 347 | PAGE | ||
| 348 | |||
| 349 | ; It's not a MOVEBLOCK function so we'll just pass the interrupt on to the real | ||
| 350 | ; interrupt handler. | ||
| 351 | |||
| 352 | DOINT: | ||
| 353 | MOV AX,HUGE_PTR ; Load ES with a selector that accesses | ||
| 354 | MOV ES,AX ; all of memory as data | ||
| 355 | DATAOV ; Load EDI with the user's ESP | ||
| 356 | MOV DI,SS:[BP+BP_SP] | ||
| 357 | |||
| 358 | SUB DI,6 ; Decrement "SP" by six to make room | ||
| 359 | ; for our simulated interrupt that | ||
| 360 | ; will put the flags, CS and IP on | ||
| 361 | ; the stack. This assumes that there | ||
| 362 | ; are indeed six bytes left on the | ||
| 363 | ; stack. | ||
| 364 | MOV SS:WORD PTR [BP+BP_SP],DI ; Set the user's new SP | ||
| 365 | |||
| 366 | DATAOV ; Get the user's SS into our AX | ||
| 367 | MOV AX,SS:[BP+BP_SS] | ||
| 368 | DATAOV ; Shift "SS" left four bits to convert | ||
| 369 | SHL AX,4 ; it to an offset | ||
| 370 | DATAOV ; Add this to "SP" in DI to make EDI | ||
| 371 | ADD DI,AX ; a 32 bit offset from 0 of the user's | ||
| 372 | ; stack | ||
| 373 | |||
| 374 | ; Now put the flags, CS and IP on the V86 task's stack. They are put on in the | ||
| 375 | ; order IP, CS, flags. This is backwards from the INT push order of flags, CS | ||
| 376 | ; and then IP. This is because we are moving forward through memory (CLD) | ||
| 377 | ; whereas the stack grows backwards through memory as things pushed on to it. | ||
| 378 | |||
| 379 | MOV AX,SS:[BP+BP_IP] ; Get the user's IP | ||
| 380 | ADDROV ; And put it on his stack | ||
| 381 | STOSW | ||
| 382 | |||
| 383 | ADDROV ; Intel bug # A0-119 | ||
| 384 | NOP ; Intel bug # A0-119 | ||
| 385 | |||
| 386 | MOV AX,SS:[BP+BP_CS] ; Get the user's CS | ||
| 387 | ADDROV ; And put it on his stack | ||
| 388 | STOSW | ||
| 389 | |||
| 390 | ADDROV ; Intel bug # A0-119 | ||
| 391 | NOP ; Intel bug # A0-119 | ||
| 392 | |||
| 393 | MOV AX,SS:[BP+BP_FL] ; Get the user's flags | ||
| 394 | OR AX,3000H ; Set the IOPL to 3 so we get fewer | ||
| 395 | ; faults | ||
| 396 | ADDROV ; And put them on his stack | ||
| 397 | STOSW | ||
| 398 | |||
| 399 | ADDROV ; Intel bug # A0-119 | ||
| 400 | NOP ; Intel bug # A0-119 | ||
| 401 | |||
| 402 | AND AX,3CFFH ; Clean up the flags for our IRET | ||
| 403 | MOV WORD PTR SS:[BP+BP_FL],AX ; Put them on our stack | ||
| 404 | |||
| 405 | MOV SI,SS:[BP+BP_EX] ; Get the interrupt number | ||
| 406 | SHL SI,2 ; Multiply by four 'cause interrupt | ||
| 407 | ; vectors are four bytes long | ||
| 408 | MOV AX,HUGE_PTR ; Load DS with a selector that accesses | ||
| 409 | MOV DS,AX ; all of memory as data | ||
| 410 | LODSW ; Get the IP of the interrupt vector | ||
| 411 | ; from the interrupt vector table | ||
| 412 | MOV WORD PTR SS:[BP+BP_IP],AX ; Put it in the IP saved on our stack | ||
| 413 | LODSW ; Get the CS of the interrupt vector | ||
| 414 | ; from the interrupt vector table | ||
| 415 | MOV WORD PTR SS:[BP+BP_CS],AX ; Put it in the CS saved on our stack | ||
| 416 | |||
| 417 | JMP POPREGS ; Now when we do an IRET we will @P2C | ||
| 418 | ; actually be giving control to the | ||
| 419 | ; real INT 15H vector. | ||
| 420 | INT15 ENDP | ||
| 421 | |||
| 422 | PAGE | ||
| 423 | ; Macros used to define data areas | ||
| 424 | |||
| 425 | ; DDL - Define a label and make it public | ||
| 426 | |||
| 427 | DDL MACRO NAME,SIZE | ||
| 428 | PUBLIC &NAME | ||
| 429 | &NAME LABEL &SIZE | ||
| 430 | ENDM | ||
| 431 | |||
| 432 | |||
| 433 | ; DDW - Define a word and make it public | ||
| 434 | |||
| 435 | DDW MACRO NAME,VALUE | ||
| 436 | IFNB <&NAME> ;; If a name was given then make it public | ||
| 437 | PUBLIC &NAME | ||
| 438 | ENDIF | ||
| 439 | IFNB <&VALUE> ;; If a value was given then initialize the | ||
| 440 | &NAME DW &VALUE ;; variable to that value | ||
| 441 | ELSE ;; Else initialize it to 0 | ||
| 442 | &NAME DW 0 | ||
| 443 | ENDIF | ||
| 444 | ENDM | ||
| 445 | |||
| 446 | |||
| 447 | ; Now lets define some data. Remember, these are all PUBLIC even though they | ||
| 448 | ; are not listed at the top of the program as being such. It's easy to lose | ||
| 449 | ; these guys. | ||
| 450 | |||
| 451 | DDW REAL_SP,0 ; Our initial SP when we come up in real mode | ||
| 452 | |||
| 453 | DDW REAL_SS,0 ; Our initial SS when we come up in real mode | ||
| 454 | |||
| 455 | DDW REAL_CS,0 ; Our initial CS when we come up in real mode | ||
| 456 | |||
| 457 | DDW PGTBLOFF,0 ; The offset of the normal page tables | ||
| 458 | |||
| 459 | DDW SGTBLOFF,0 ; The offset of the page directory | ||
| 460 | |||
| 461 | DDW NORMPAGE,0 ; The entry for the first page directory entry | ||
| 462 | DDW ,0 ; which points to the first normal page table. | ||
| 463 | ; A 32 bit value | ||
| 464 | DDW XMAPAGE,7 ; Page directory entry that points to the first | ||
| 465 | DDW ,0011H ; XMA page table at 11000:0. Access and present | ||
| 466 | ; bits set. It, too, is a 32 bit value. | ||
| 467 | DDW BUFF_SIZE,0 ; Size of the MOVEBLOCK buffer. Initialized to 0. | ||
| 468 | |||
| 469 | DDW MAXMEM,1000H ; Total amount of K in the box. Initialized to 4M. | ||
| 470 | |||
| 471 | DDW CRT_SELECTOR,C_BWCRT_PTR ; Selector for the display buffer | ||
| 472 | |||
| 473 | ; And now, the world famous Translate Table!! YEAAAA!! | ||
| 474 | ; | ||
| 475 | ; The first 160 entries (0 to 640K) are initialized to blocks 0 to '9F'X. D1A | ||
| 476 | ; This is to emulate the XMA 2 device driver which uses these blocks to back D1A | ||
| 477 | ; the memory on the mother board from 0 to 640K which it disabled. It sets D1A | ||
| 478 | ; up the translate table for bank 0 such that it maps the XMA memory from 0 D1A | ||
| 479 | ; to 640K to conventional memory at 0 to 640K. So we emulate that here by D1A | ||
| 480 | ; initializing the firs 160 entries in the translate table. D1A | ||
| 481 | |||
| 482 | TTTABLE: | ||
| 483 | BLOCK = 0 ; Start with block number 0 @D1A | ||
| 484 | REPT 20 ; Do 20 times (20 x 8 = 160) @D1A | ||
| 485 | DW BLOCK,BLOCK+1,BLOCK+2,BLOCK+3,BLOCK+4,BLOCK+5,BLOCK+6,BLOCK+7 | ||
| 486 | ; Define eight translate table entries @D1A | ||
| 487 | ; initialized to the block number D1A | ||
| 488 | BLOCK = BLOCK + 8 ; Increment the block number to the next set @D1A | ||
| 489 | ENDM ; of eight translate table entries @D1A | ||
| 490 | |||
| 491 | DW 96 + 256*15 DUP(0FFFH) ; The rest of the translate table @D1C | ||
| 492 | |||
| 493 | TTTABLE_END: ; Label to mark the end of the translate table | ||
| 494 | |||
| 495 | |||
| 496 | ; Define our stack for when we're in protect mode | ||
| 497 | |||
| 498 | DDW MON_STACK_BASE,<500 DUP(0)> | ||
| 499 | DDL SP_INIT,WORD ; Top of the stack. The initial SP points here. | ||
| 500 | |||
| 501 | PROG ENDS | ||
| 502 | |||
| 503 | END | ||
diff --git a/v4.0/src/DEV/XMAEM/INDEIDT.ASM b/v4.0/src/DEV/XMAEM/INDEIDT.ASM new file mode 100644 index 0000000..28e9161 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEIDT.ASM | |||
| @@ -0,0 +1,512 @@ | |||
| 1 | PAGE 60,132 | ||
| 2 | TITLE INDEIDT - 386 XMA Emulator - Build Interrupt Descriptor Table | ||
| 3 | |||
| 4 | COMMENT # | ||
| 5 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 6 | * * | ||
| 7 | * MODULE NAME : INDEIDT * | ||
| 8 | * * | ||
| 9 | * * | ||
| 10 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. * | ||
| 11 | * * | ||
| 12 | * DESCRIPTIVE NAME: Build the Interrupt Descriptor Table (IDT) * | ||
| 13 | * * | ||
| 14 | * STATUS (LEVEL) : Version (0) Level (2.0) * | ||
| 15 | * * | ||
| 16 | * FUNCTION : Build the Interrupt Descriptor Table for the 80386 XMA * | ||
| 17 | * emulator. * | ||
| 18 | * * | ||
| 19 | * MODULE TYPE : ASM * | ||
| 20 | * * | ||
| 21 | * REGISTER USAGE : 80386 Standard * | ||
| 22 | * * | ||
| 23 | * RESTRICTIONS : None * | ||
| 24 | * * | ||
| 25 | * DEPENDENCIES : None * | ||
| 26 | * * | ||
| 27 | * ENTRY POINT : SIDT_BLD (not to be confused with SIDTBLD) * | ||
| 28 | * * | ||
| 29 | * LINKAGE : Called by INDEINI * | ||
| 30 | * * | ||
| 31 | * INPUT PARMS : None * | ||
| 32 | * * | ||
| 33 | * RETURN PARMS : None * | ||
| 34 | * * | ||
| 35 | * OTHER EFFECTS : None * | ||
| 36 | * * | ||
| 37 | * EXIT NORMAL : Return to INDEINI * | ||
| 38 | * * | ||
| 39 | * EXIT ERROR : None * | ||
| 40 | * * | ||
| 41 | * EXTERNAL * | ||
| 42 | * REFERENCES : VEXCP13 - Entry point for INDEEXC * | ||
| 43 | * * | ||
| 44 | * SUB-ROUTINES : BLD_IDT - Put the entries into the IDT * | ||
| 45 | * * | ||
| 46 | * MACROS : DATAOV - Create a prefix for the following instruction * | ||
| 47 | * so that it accesses data 32 bits wide * | ||
| 48 | * ADDROV - Create a prefix for the following instruction * | ||
| 49 | * so that it uses addresses that are 32 bits wide * | ||
| 50 | * * | ||
| 51 | * CONTROL BLOCKS : INDEDAT * | ||
| 52 | * * | ||
| 53 | * CHANGE ACTIVITY : * | ||
| 54 | * * | ||
| 55 | * $MOD(INDEIDT) COMP(LOAD) PROD(3270PC) : * | ||
| 56 | * * | ||
| 57 | * $D0=D0004700 410 870530 D : NEW FOR RELEASE 1.1 * | ||
| 58 | * $P1=P0000312 410 870803 D : CHANGE COMPONENT FROM MISC TO LOAD * | ||
| 59 | * $P2=P0000xxx 120 880517 D : HANDLE INT 0D FROM V86 TASK, I.E., OPTICAL DISK * | ||
| 60 | * * | ||
| 61 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 62 | # | ||
| 63 | |||
| 64 | .286P ; Enable recognition of 286 privileged instructs. | ||
| 65 | |||
| 66 | .XLIST ; Turn off the listing | ||
| 67 | INCLUDE INDEDAT.INC ; System data structures and equates | ||
| 68 | |||
| 69 | IF1 ; Only include macros on the first pass | ||
| 70 | INCLUDE INDEOVP.MAC | ||
| 71 | ENDIF | ||
| 72 | .LIST ; Turn on the listing | ||
| 73 | PAGE | ||
| 74 | |||
| 75 | PROG SEGMENT PARA PUBLIC 'PROG' | ||
| 76 | |||
| 77 | ASSUME CS:PROG | ||
| 78 | ASSUME SS:NOTHING | ||
| 79 | ASSUME DS:NOTHING | ||
| 80 | ASSUME ES:NOTHING | ||
| 81 | |||
| 82 | INDEIDT LABEL NEAR | ||
| 83 | |||
| 84 | ; Let these entry points be known to other modules. | ||
| 85 | |||
| 86 | PUBLIC INDEIDT | ||
| 87 | PUBLIC SIDT_BLD | ||
| 88 | |||
| 89 | ; This is the entry point to INDEEXC. | ||
| 90 | |||
| 91 | EXTRN VEXCPT13:NEAR | ||
| 92 | |||
| 93 | PAGE | ||
| 94 | ; Define the stack structure for our fast path. For all the interrupts that we | ||
| 95 | ; don't want to handle we just pass the interrupt back to the real interrupt | ||
| 96 | ; vector. The entry points for these vectors push the interrupt vector offset | ||
| 97 | ; (interrupt number * 4) onto the stack and then call FASTPATH to pass the | ||
| 98 | ; interrupt to the real vector. FASTPATH pushes BP, AX, DI and SI on to the | ||
| 99 | ; stack. The following structure is a map of the stack after these registers | ||
| 100 | ; are pushed. This structure allows us to access info on the stack. | ||
| 101 | |||
| 102 | SPSTACK STRUC | ||
| 103 | |||
| 104 | SP_SI DW 0 ; Saved ESI (32 bit SI) | ||
| 105 | DW 0 | ||
| 106 | SP_DI DW 0 ; Saved EDI (32 bit DI) | ||
| 107 | DW 0 | ||
| 108 | SP_AX DW 0 ; Saved EAX | ||
| 109 | DW 0 | ||
| 110 | SP_BP DW 0 ; Saved BP (only 16 bits) | ||
| 111 | SP_EX DW 0 ; Interrupt vector offset (interrupt number * 4) | ||
| 112 | |||
| 113 | ; The following information is saved by the 80386 | ||
| 114 | |||
| 115 | SP_IP DW 0 ; Interruptee's EIP (32 bit IP) | ||
| 116 | SP_IP2 DW 0 | ||
| 117 | SP_CS DW 0 ; Interruptee's CS (16 bit CS and 16 bit junk) | ||
| 118 | SP_CS2 DW 0 | ||
| 119 | SP_FL DW 0 ; Interruptee's Eflags (32 bit flags) | ||
| 120 | SP_FL2 DW 0 | ||
| 121 | SP_SP DW 0 ; Interruptee's ESP | ||
| 122 | SP_SP2 DW 0 | ||
| 123 | SP_SS DW 0 ; Interruptee's SS | ||
| 124 | SP_SS2 DW 0 | ||
| 125 | SP_VMES DW 0 ; Interruptee's ES | ||
| 126 | DW 0 | ||
| 127 | SP_VMDS DW 0 ; Interruptee's DS | ||
| 128 | DW 0 | ||
| 129 | SP_VMFS DW 0 ; Interruptee's FS | ||
| 130 | DW 0 | ||
| 131 | SP_VMGS DW 0 ; Interruptee's GS | ||
| 132 | DW 0 | ||
| 133 | SP_STK DW 0 ; The rest of the stack | ||
| 134 | |||
| 135 | SPSTACK ENDS | ||
| 136 | |||
| 137 | SP_START EQU 0 ; Offset from BP of the start of the save area | ||
| 138 | ; BP is set ot point to the start of the save area | ||
| 139 | |||
| 140 | PAGE | ||
| 141 | |||
| 142 | SIDTBLD PROC NEAR | ||
| 143 | |||
| 144 | ; Generate the entry points for all (yes, ALL) 256 interrupt vectors. For | ||
| 145 | ; interrupt 0D (general Protection exception) we will check if it was the V86 | ||
| 146 | ; task that faulted. If so, then we will just pass the interrupt back to the | ||
| 147 | ; V86 task. Else, we will go to our exception handler since the interrupt | ||
| 148 | ; happened because of the emulator. | ||
| 149 | ; | ||
| 150 | ; For interrupts 00, 01, 02, 03, 04, 05, 06, 07, 09, 0A, 0B, 0C, 0E and 15 we | ||
| 151 | ; will go to our exception handler. | ||
| 152 | ; | ||
| 153 | ; For all other interrupts we will go to the FASTPATH routine which will pass | ||
| 154 | ; the interrupt back to the V86 interrupt vector. | ||
| 155 | ; | ||
| 156 | ; Note: For interrupts that go to our exception handler we push a 32 bit error | ||
| 157 | ; code and then push the interrupt number. For the FASTPATH interrupts | ||
| 158 | ; we push the interrupt vector offset (interrupt number *4). This results | ||
| 159 | ; in different stack structures depending on how the interrupt is handled. | ||
| 160 | ; So be careful when you're trying to figure out what's on the stack. | ||
| 161 | ; | ||
| 162 | |||
| 163 | ; Interrupt 0D | ||
| 164 | |||
| 165 | IRP V,<0D> | ||
| 166 | VEC&V: | ||
| 167 | PUSH 0&V&H ; Push the interrupt number (0D) | ||
| 168 | PUSH BP ; Save BP | ||
| 169 | DATAOV ; @P2A | ||
| 170 | PUSH AX ; Save EAX, all 32bits of it. @P2A | ||
| 171 | DATAOV ; @P2A | ||
| 172 | PUSH DI ; Save EDI @P2A | ||
| 173 | DATAOV ; @P2A | ||
| 174 | PUSH SI ; Save ESI @P2A | ||
| 175 | MOV BP,SP ; Point BP to the save area @P2A | ||
| 176 | |||
| 177 | ; Now we must check if the INT 0D came from the V86 task P2A | ||
| 178 | ; or if it was a General Protection exception. In the P2A | ||
| 179 | ; case of a General Protection exception the 80386 puts P2A | ||
| 180 | ; an error code on the stack after pushing the EFLAGS, CS P2A | ||
| 181 | ; and EIP. The error code is 32 bits wide. If the V86 P2A | ||
| 182 | ; task issues an INT 0D, an error code is NOT placed on P2A | ||
| 183 | ; the stack. In this case we want to pass the interrupt P2A | ||
| 184 | ; back to the V86 task instead of going to our exception P2A | ||
| 185 | ; handler. The way we check for an error code is by P2A | ||
| 186 | ; checking how much ESP has been decremented since the P2A | ||
| 187 | ; start of the interrupt. The original ESP is saved in P2A | ||
| 188 | ; the TSS. Our stack definition above does not include P2A | ||
| 189 | ; an error code. So if ESP has been decremented more than P2A | ||
| 190 | ; the size of our structure, we can know that an error P2A | ||
| 191 | ; code is on the stack and then go to our exception P2A | ||
| 192 | ; handler. P2A | ||
| 193 | |||
| 194 | MOV AX,SCRUBBER.TSS_PTR ; Load DS with the selector @P2A | ||
| 195 | MOV DS,AX ; that accesses the TSS as data @P2A | ||
| 196 | MOV SI,0 ; Base for reading the TSS @P2A | ||
| 197 | DATAOV ; @P2A | ||
| 198 | MOV AX,[SI].ETSS_SP0 ; Get the original SP before the @P2A | ||
| 199 | DATAOV ; interrupt @P2A | ||
| 200 | SUB AX,SP ; Subtract the current stack @P2A | ||
| 201 | ; pointer @P2A | ||
| 202 | CMP AX,SP_STK ; Check for an error code @P2A | ||
| 203 | ; @P2D | ||
| 204 | JG SKIP&V ; If there's an error code, go @P2C | ||
| 205 | ; handle the exception P2C | ||
| 206 | MOV WORD PTR [BP+SP_EX],0&V&H*4 ; If there is no error @P2A | ||
| 207 | ; code then multiply the vector P2A | ||
| 208 | ; number by four for the FASTPATH P2A | ||
| 209 | ; code. P2A | ||
| 210 | JMP PASS_ON ; Give the interrupt back to the @P2C | ||
| 211 | ; V86 task. | ||
| 212 | SKIP&V: DATAOV ; @P2A | ||
| 213 | POP SI ; Restore ESI from off our stack @P2A | ||
| 214 | DATAOV ; @P2A | ||
| 215 | POP DI ; Restore EDI @P2A | ||
| 216 | DATAOV ; @P2A | ||
| 217 | POP AX ; Restore EAX @P2A | ||
| 218 | POP BP ; Take BP off the stack. This leaves | ||
| 219 | ; the interrupt number that we pushed | ||
| 220 | ; above and the error code that was | ||
| 221 | ; pushed by the 386 on the INT 0D. | ||
| 222 | JMP VEXCPT13 ; Go to the exception handler. | ||
| 223 | |||
| 224 | ENDM | ||
| 225 | |||
| 226 | PAGE | ||
| 227 | ; For interrupts 00, 01, 02, 03, 04, 05, 06, 07, 09, 0A, 0B, 0C, 0E and 15 | ||
| 228 | ; push a dummy error code of 0 and then the interrupt number. Then go to the | ||
| 229 | ; exception handler. | ||
| 230 | |||
| 231 | IRP V,<00,01,02,03,04,05,06,07,09,0A,0B,0C,0E,15> | ||
| 232 | VEC&V: | ||
| 233 | PUSH 0 ; Push a dummy error code of 0 | ||
| 234 | PUSH 0 ; 32 bits wide | ||
| 235 | SKIP&V: | ||
| 236 | PUSH 0&V&H ; Push the interrupt number | ||
| 237 | JMP VEXCPT13 ; Go to the exception handler | ||
| 238 | ENDM | ||
| 239 | |||
| 240 | PAGE | ||
| 241 | ; For the rest of the interrupts push the interrupt vector offset (interrupt | ||
| 242 | ; number * 4) and go to the fast path routine. | ||
| 243 | ; | ||
| 244 | ; INT 08H is given the FASTPATH. It's the double fault interrupt so we are | ||
| 245 | ; dead any way. This interrupt is normally used for the timer interrupt. | ||
| 246 | ; | ||
| 247 | ; INT 10H, BIOS video calls, is given the fastest code path by putting it just | ||
| 248 | ; before the FASTPATH routine. | ||
| 249 | |||
| 250 | IRP V,<08,0F,11,12,13,14,16,17,18,19,1A,1B,1C,1D,1E,1F> | ||
| 251 | VEC&V: | ||
| 252 | PUSH 0&V&H*4 ; Push the interrupt vector offset | ||
| 253 | JMP FASTPATH ; Go to the fastpath routine | ||
| 254 | ENDM | ||
| 255 | IRP V,<20,21,22,23,24,25,26,27,28,29,2A,2B,2C,2D,2E,2F> | ||
| 256 | VEC&V: | ||
| 257 | PUSH 0&V&H*4 ; Push the interrupt vector offset | ||
| 258 | JMP FASTPATH ; Go to the fastpath routine | ||
| 259 | ENDM | ||
| 260 | IRP V,<30,31,32,33,34,35,36,37,38,39,3A,3B,3C,3D,3E,3F> | ||
| 261 | VEC&V: | ||
| 262 | PUSH 0&V&H*4 ; Push the interrupt vector offset | ||
| 263 | JMP FASTPATH ; Go to the fastpath routine | ||
| 264 | ENDM | ||
| 265 | IRP V,<40,41,42,43,44,45,46,47,48,49,4A,4B,4C,4D,4E,4F> | ||
| 266 | VEC&V: | ||
| 267 | PUSH 0&V&H*4 ; Push the interrupt vector offset | ||
| 268 | JMP FASTPATH ; Go to the fastpath routine | ||
| 269 | ENDM | ||
| 270 | IRP V,<50,51,52,53,54,55,56,57,58,59,5A,5B,5C,5D,5E,5F> | ||
| 271 | VEC&V: | ||
| 272 | PUSH 0&V&H*4 ; Push the interrupt vector offset | ||
| 273 | JMP FASTPATH ; Go to the fastpath routine | ||
| 274 | ENDM | ||
| 275 | IRP V,<60,61,62,63,64,65,66,67,68,69,6A,6B,6C,6D,6E,6F> | ||
| 276 | VEC&V: | ||
| 277 | PUSH 0&V&H*4 ; Push the interrupt vector offset | ||
| 278 | JMP FASTPATH ; Go to the fastpath routine | ||
| 279 | ENDM | ||
| 280 | IRP V,<70,71,72,73,74,75,76,77,78,79,7A,7B,7C,7D,7E,7F> | ||
| 281 | VEC&V: | ||
| 282 | PUSH 0&V&H*4 ; Push the interrupt vector offset | ||
| 283 | JMP FASTPATH ; Go to the fastpath routine | ||
| 284 | ENDM | ||
| 285 | IRP V,<80,81,82,83,84,85,86,87,88,89,8A,8B,8C,8D,8E,8F> | ||
| 286 | VEC&V: | ||
| 287 | PUSH 0&V&H*4 ; Push the interrupt vector offset | ||
| 288 | JMP FASTPATH ; Go to the fastpath routine | ||
| 289 | ENDM | ||
| 290 | IRP V,<90,91,92,93,94,95,96,97,98,99,9A,9B,9C,9D,9E,9F> | ||
| 291 | VEC&V: | ||
| 292 | PUSH 0&V&H*4 ; Push the interrupt vector offset | ||
| 293 | JMP FASTPATH ; Go to the fastpath routine | ||
| 294 | ENDM | ||
| 295 | IRP V,<A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF> | ||
| 296 | VEC&V: | ||
| 297 | PUSH 0&V&H*4 ; Push the interrupt vector offset | ||
| 298 | JMP FASTPATH ; Go to the fastpath routine | ||
| 299 | ENDM | ||
| 300 | IRP V,<B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,BA,BB,BC,BD,BE,BF> | ||
| 301 | VEC&V: | ||
| 302 | PUSH 0&V&H*4 ; Push the interrupt vector offset | ||
| 303 | JMP FASTPATH ; Go to the fastpath routine | ||
| 304 | ENDM | ||
| 305 | IRP V,<C0,C1,C2,C3,C4,C5,C6,C7,C8,C9,CA,CB,CC,CD,CE,CF> | ||
| 306 | VEC&V: | ||
| 307 | PUSH 0&V&H*4 ; Push the interrupt vector offset | ||
| 308 | JMP FASTPATH ; Go to the fastpath routine | ||
| 309 | ENDM | ||
| 310 | IRP V,<D0,D1,D2,D3,D4,D5,D6,D7,D8,D9,DA,DB,DC,DD,DE,DF> | ||
| 311 | VEC&V: | ||
| 312 | PUSH 0&V&H*4 ; Push the interrupt vector offset | ||
| 313 | JMP FASTPATH ; Go to the fastpath routine | ||
| 314 | ENDM | ||
| 315 | IRP V,<E0,E1,E2,E3,E4,E5,E6,E7,E8,E9,EA,EB,EC,ED,EE,EF> | ||
| 316 | VEC&V: | ||
| 317 | PUSH 0&V&H*4 ; Push the interrupt vector offset | ||
| 318 | JMP FASTPATH ; Go to the fastpath routine | ||
| 319 | ENDM | ||
| 320 | IRP V,<F0,F1,F2,F3,F4,F5,F6,F7,F8,F9,FA,FB,FC,FD,FE,FF> | ||
| 321 | VEC&V: | ||
| 322 | PUSH 0&V&H*4 ; Push the interrupt vector offset | ||
| 323 | JMP FASTPATH ; Go to the fastpath routine | ||
| 324 | ENDM | ||
| 325 | |||
| 326 | VEC10: | ||
| 327 | PUSH 010H*4 ; Push the interrupt vector offset | ||
| 328 | |||
| 329 | PAGE | ||
| 330 | FASTPATH: | ||
| 331 | PUSH BP ; Save BP | ||
| 332 | DATAOV | ||
| 333 | PUSH AX ; Save EAX, all 32bits of it. | ||
| 334 | DATAOV | ||
| 335 | PUSH DI ; Save EDI | ||
| 336 | DATAOV | ||
| 337 | PUSH SI ; Save ESI | ||
| 338 | MOV BP,SP ; Point BP to the save area | ||
| 339 | |||
| 340 | PASS_ON: ; @P2C | ||
| 341 | CLD ; All string operations go forward | ||
| 342 | |||
| 343 | MOV AX,HUGE_PTR ; Load DS and ES with a selector that | ||
| 344 | MOV DS,AX ; accesses all of memory as data | ||
| 345 | MOV ES,AX | ||
| 346 | DATAOV | ||
| 347 | SUB DI,DI ; Clear EDI | ||
| 348 | MOV DI,SS:[BP+SP_SP] ; Load DI with the interruptee's SP | ||
| 349 | SUB DI,6 ; Decrement "SP" to simulate the pushing | ||
| 350 | ; of the flags, CS and IP on an INT. | ||
| 351 | MOV SS:WORD PTR [BP+SP_SP],DI ; Replace the user's SP | ||
| 352 | |||
| 353 | DATAOV | ||
| 354 | SUB AX,AX ; Clear EAX | ||
| 355 | MOV AX,SS:[BP+SP_SS] ; Load AX with the user's SS register | ||
| 356 | DATAOV ; Shift "SS" left four bits to convert | ||
| 357 | SHL AX,4 ; it to an offset | ||
| 358 | DATAOV ; Add on "SP" to get a 32 bit offset | ||
| 359 | ADD DI,AX ; from 0 of the user's stack. | ||
| 360 | |||
| 361 | ; Put the user's IP, CS and flags onto his stack. This is done in reverse | ||
| 362 | ; order because we are moving forward in memory whereas stacks grow backward. | ||
| 363 | |||
| 364 | MOV AX,SS:[BP+SP_IP] ; Get the user's IP | ||
| 365 | ADDROV | ||
| 366 | STOSW ; And put it on the stack | ||
| 367 | ADDROV ; Intel bug # A0-119 | ||
| 368 | NOP ; Intel bug # A0-119 | ||
| 369 | |||
| 370 | MOV AX,SS:[BP+SP_CS] ; Get the user's CS | ||
| 371 | ADDROV | ||
| 372 | STOSW ; And put it on the stack | ||
| 373 | ADDROV ; Intel bug # A0-119 | ||
| 374 | NOP ; Intel bug # A0-119 | ||
| 375 | |||
| 376 | MOV AX,SS:[BP+SP_FL] ; Get the user's flags | ||
| 377 | ADDROV | ||
| 378 | STOSW ; And put them on the stack | ||
| 379 | ADDROV ; Intel bug # A0-119 | ||
| 380 | NOP ; Intel bug # A0-119 | ||
| 381 | |||
| 382 | AND AX,3CFFH ; Clean up the flags for our IRET by | ||
| 383 | MOV WORD PTR SS:[BP+SP_FL],AX ; setting IOPL to 3 | ||
| 384 | |||
| 385 | ; Replace the interruptee's CS:IP with the CS:IP of the interrupt vector. When | ||
| 386 | ; we IRET back to the V86 task control will go to the interrupt routine. | ||
| 387 | |||
| 388 | MOV SI,SS:[BP+SP_EX] ; Get the interrupt vector offset | ||
| 389 | LODSW ; Get the IP of the interrupt vector | ||
| 390 | MOV WORD PTR SS:[BP+SP_IP],AX ; Replace the user's IP | ||
| 391 | LODSW ; Get the CS of the interrupt vector | ||
| 392 | MOV WORD PTR SS:[BP+SP_CS],AX ; Replace the user's CS | ||
| 393 | |||
| 394 | DATAOV | ||
| 395 | POP SI ; Restore ESI from off our stack | ||
| 396 | DATAOV | ||
| 397 | POP DI ; Restore EDI | ||
| 398 | DATAOV | ||
| 399 | POP AX ; Restore EAX | ||
| 400 | POP BP ; Restore BP | ||
| 401 | ADD SP,(SP_IP-SP_EX) ; Step SP past the interrupt vector | ||
| 402 | ; offset | ||
| 403 | DATAOV | ||
| 404 | IRET ; Give control back to the interruptee | ||
| 405 | |||
| 406 | PAGE | ||
| 407 | |||
| 408 | ; Build a talbe of the offsets of all the interrupt entry points. This table | ||
| 409 | ; is used as input to the procedure that builds the IDT. | ||
| 410 | |||
| 411 | SIDT_OFFSETS LABEL WORD | ||
| 412 | |||
| 413 | IRP V,<00,01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,0F> | ||
| 414 | DW OFFSET VEC&V | ||
| 415 | ENDM | ||
| 416 | IRP V,<10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F> | ||
| 417 | DW OFFSET VEC&V | ||
| 418 | ENDM | ||
| 419 | IRP V,<20,21,22,23,24,25,26,27,28,29,2A,2B,2C,2D,2E,2F> | ||
| 420 | DW OFFSET VEC&V | ||
| 421 | ENDM | ||
| 422 | IRP V,<30,31,32,33,34,35,36,37,38,39,3A,3B,3C,3D,3E,3F> | ||
| 423 | DW OFFSET VEC&V | ||
| 424 | ENDM | ||
| 425 | IRP V,<40,41,42,43,44,45,46,47,48,49,4A,4B,4C,4D,4E,4F> | ||
| 426 | DW OFFSET VEC&V | ||
| 427 | ENDM | ||
| 428 | IRP V,<50,51,52,53,54,55,56,57,58,59,5A,5B,5C,5D,5E,5F> | ||
| 429 | DW OFFSET VEC&V | ||
| 430 | ENDM | ||
| 431 | IRP V,<60,61,62,63,64,65,66,67,68,69,6A,6B,6C,6D,6E,6F> | ||
| 432 | DW OFFSET VEC&V | ||
| 433 | ENDM | ||
| 434 | IRP V,<70,71,72,73,74,75,76,77,78,79,7A,7B,7C,7D,7E,7F> | ||
| 435 | DW OFFSET VEC&V | ||
| 436 | ENDM | ||
| 437 | IRP V,<80,81,82,83,84,85,86,87,88,89,8A,8B,8C,8D,8E,8F> | ||
| 438 | DW OFFSET VEC&V | ||
| 439 | ENDM | ||
| 440 | IRP V,<90,91,92,93,94,95,96,97,98,99,9A,9B,9C,9D,9E,9F> | ||
| 441 | DW OFFSET VEC&V | ||
| 442 | ENDM | ||
| 443 | IRP V,<A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF> | ||
| 444 | DW OFFSET VEC&V | ||
| 445 | ENDM | ||
| 446 | IRP V,<B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,BA,BB,BC,BD,BE,BF> | ||
| 447 | DW OFFSET VEC&V | ||
| 448 | ENDM | ||
| 449 | IRP V,<C0,C1,C2,C3,C4,C5,C6,C7,C8,C9,CA,CB,CC,CD,CE,CF> | ||
| 450 | DW OFFSET VEC&V | ||
| 451 | ENDM | ||
| 452 | IRP V,<D0,D1,D2,D3,D4,D5,D6,D7,D8,D9,DA,DB,DC,DD,DE,DF> | ||
| 453 | DW OFFSET VEC&V | ||
| 454 | ENDM | ||
| 455 | IRP V,<E0,E1,E2,E3,E4,E5,E6,E7,E8,E9,EA,EB,EC,ED,EE,EF> | ||
| 456 | DW OFFSET VEC&V | ||
| 457 | ENDM | ||
| 458 | IRP V,<F0,F1,F2,F3,F4,F5,F6,F7,F8,F9,FA,FB,FC,FD,FE,FF> | ||
| 459 | DW OFFSET VEC&V | ||
| 460 | ENDM | ||
| 461 | PAGE | ||
| 462 | SIDT_BLD: | ||
| 463 | |||
| 464 | ; Build the system IDT. The system IDT will contain 256 interrupt gates. | ||
| 465 | |||
| 466 | MOV AX,CS ; Set DS:SI to point to the table of | ||
| 467 | MOV DS,AX ; interrupt entry points | ||
| 468 | MOV SI,OFFSET SIDT_OFFSETS | ||
| 469 | |||
| 470 | MOV DI,SIDT_LOC ; Set ES:DI to point to the beginning | ||
| 471 | ; of the IDT | ||
| 472 | MOV BX,SYS_PATCH_CS ; Load BX with the selector for the | ||
| 473 | ; segment of the interrupt routines. | ||
| 474 | ; It's our code segment. | ||
| 475 | |||
| 476 | ; DX contains the second highest word of the interrupt descriptor. | ||
| 477 | |||
| 478 | MOV DH,0EEH ; Set DPL to 3 to reduce the number of | ||
| 479 | ; exceptions | ||
| 480 | MOV DL,0 ; The word count field is unused | ||
| 481 | |||
| 482 | MOV CX,256 ; 256 interrupt gates | ||
| 483 | |||
| 484 | CALL BLD_IDT ; Go build the IDT | ||
| 485 | |||
| 486 | RET ; Return to INDEINI | ||
| 487 | |||
| 488 | PAGE | ||
| 489 | |||
| 490 | ; This loop builds descriptors in the IDT. DS:SI points to a table of 16 bit | ||
| 491 | ; offsets for the interrupt entry points. ES:DI points to the start of the IDT. | ||
| 492 | ; BX contains the segment selector of the interrupt entry points. DX contains | ||
| 493 | ; the DPL of the interrupt gates. | ||
| 494 | |||
| 495 | BLD_IDT: | ||
| 496 | MOVSW ; Get an interrupt routine entry point | ||
| 497 | ; and put it in the offset field | ||
| 498 | MOV AX,BX ; Get the segment selector | ||
| 499 | STOSW ; and put it in the selector field | ||
| 500 | MOV AX,DX ; Get the interrupt gate DPL | ||
| 501 | STOSW ; and put it in the access rights field | ||
| 502 | MOV AX,0 ; Zero out the reserved portions | ||
| 503 | STOSW | ||
| 504 | LOOP BLD_IDT ; Repeat for all interrupt vectors | ||
| 505 | |||
| 506 | RET | ||
| 507 | |||
| 508 | SIDTBLD ENDP | ||
| 509 | |||
| 510 | PROG ENDS | ||
| 511 | |||
| 512 | END | ||
diff --git a/v4.0/src/DEV/XMAEM/INDEINI.ASM b/v4.0/src/DEV/XMAEM/INDEINI.ASM new file mode 100644 index 0000000..19c8b79 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEINI.ASM | |||
| @@ -0,0 +1,1474 @@ | |||
| 1 | PAGE 60,132 | ||
| 2 | TITLE INDEINI - 386 XMA EMULATOR - Initialization | ||
| 3 | |||
| 4 | COMMENT # | ||
| 5 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 6 | * * | ||
| 7 | * MODULE NAME : INDEINI * | ||
| 8 | * * | ||
| 9 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. * | ||
| 10 | * * | ||
| 11 | * DESCRIPTIVE NAME: 80386 XMA EMULATOR INITIALIZATION * | ||
| 12 | * * | ||
| 13 | * STATUS (LEVEL) : VERSION (0) LEVEL (2.0) * | ||
| 14 | * * | ||
| 15 | * FUNCTION : Do all the initialization needed for the 386 XMA emulator.* | ||
| 16 | * * | ||
| 17 | * The 386 XMA emulator is installed by putting the follow- * | ||
| 18 | * ing command in the CONFIG.SYS file: * | ||
| 19 | * * | ||
| 20 | * DEVICE=\386XMAEM.SYS bbb * | ||
| 21 | * * | ||
| 22 | * where "bbb" is the number of K reserved for the MOVEBLOCK * | ||
| 23 | * function. If EMS is used, this command must appear * | ||
| 24 | * before the command to load EMS. * | ||
| 25 | * * | ||
| 26 | * This module first of all does all the stuff to set up * | ||
| 27 | * the device driver linkage to DOS. The driver is a * | ||
| 28 | * character device. The only command it recognizes is P3C* | ||
| 29 | * "initialize". When it receives the initialize command * | ||
| 30 | * it does all the set up for the emulator. For information * | ||
| 31 | * on device drivers see the DOS Technical Reference. * | ||
| 32 | * * | ||
| 33 | * Then it checks to see if we're on a model_80 and the * | ||
| 34 | * emulator has not been previously installed. If this is * | ||
| 35 | * the case, then it procedes to do the following: * | ||
| 36 | * Get the MOVEBLOCK buffer size from the parameter list * | ||
| 37 | * Save the maximum XMA block number in the header * | ||
| 38 | * Relocate to high memory * | ||
| 39 | * Initialize the page directory and page tables * | ||
| 40 | * Call INDEIDT to initialize the IDT * | ||
| 41 | * Call INDEGDT to initialize the GDT * | ||
| 42 | * Switch to virtual mode * | ||
| 43 | * Initialize the TSS for the virtual 8086 task * | ||
| 44 | * Initialize the XMA page tables * | ||
| 45 | * Enable paging * | ||
| 46 | * * | ||
| 47 | * This module also contains code to handle the Generic D2A* | ||
| 48 | * IOCTL call which is used to query the highest valid D2A* | ||
| 49 | * XMA block number. This code is left resident. D2A* | ||
| 50 | * * | ||
| 51 | * MODULE TYPE : ASM * | ||
| 52 | * * | ||
| 53 | * REGISTER USAGE : 80386 STANDARD * | ||
| 54 | * * | ||
| 55 | * RESTRICTIONS : None * | ||
| 56 | * * | ||
| 57 | * DEPENDENCIES : None * | ||
| 58 | * * | ||
| 59 | * LINKAGE : Invoked as a DOS device driver * | ||
| 60 | * * | ||
| 61 | * INPUT PARMS : The number of 1K blocks reserved for the MOVE BLOCK * | ||
| 62 | * service can be specified after the DEVICE command in the * | ||
| 63 | * CONFIG.SYS file. 0K is the default. * | ||
| 64 | * * | ||
| 65 | * RETURN PARMS : A return code is returned to DOS in the device header * | ||
| 66 | * at offset 3. * | ||
| 67 | * * | ||
| 68 | * OTHER EFFECTS : None * | ||
| 69 | * * | ||
| 70 | * EXIT NORMAL : Return to DOS after device driver is loaded * | ||
| 71 | * * | ||
| 72 | * EXIT ERROR : Return to DOS after putting up error messages * | ||
| 73 | * * | ||
| 74 | * EXTERNAL * | ||
| 75 | * REFERENCES : SIDT_BLD - Entry point for INDEIDT to build the IDT * | ||
| 76 | * GDT_BLD - Entry point for INDEGDT to build the GDT * | ||
| 77 | * WELCOME - The welcome message * | ||
| 78 | * GOODLOAD - Message saying we loaded OK * | ||
| 79 | * NO_80386 - Error message for not running on a model_80 * | ||
| 80 | * WAS_INST - Error message for protect mode in use * | ||
| 81 | * SP_INIT - Initial protect mode SP * | ||
| 82 | * REAL_CS - Place to save our real mode CS * | ||
| 83 | * REAL_SS - Place to save our real mode SS * | ||
| 84 | * REAL_SP - Place to save our real mode SP * | ||
| 85 | * PGTBLOFF - Offset of the page tables * | ||
| 86 | * SGTBLOFF - Offest of the page directory * | ||
| 87 | * NORMPAGE - Normal page directory entry * | ||
| 88 | * XMAPAGE - Page directory entry for the first XMA page D1A* | ||
| 89 | * BUFF_SIZE- Size of the MOVEBLOCK buffer * | ||
| 90 | * MAXMEM - Maximum amount of memory on the box * | ||
| 91 | * CRT_SELECTOR - Selector for the display buffer * | ||
| 92 | * * | ||
| 93 | * SUB-ROUTINES : GATE_A20 - Gate on or off address bit 20 * | ||
| 94 | * GET_PARMS - Get the MOVEBLOCK buffer size specified on * | ||
| 95 | * the command in CONFIG.SYS and convert to * | ||
| 96 | * binary. * | ||
| 97 | * * | ||
| 98 | * MACROS : DATAOV - Add prefix for the next instruction so that it * | ||
| 99 | * accesses data as 32 bits wide * | ||
| 100 | * ADDROV - Add prefix for the next instruction so that it * | ||
| 101 | * uses addresses that are 32 bits wide * | ||
| 102 | * CMOV - Move to and from control registers * | ||
| 103 | * JUMPFAR - Build an instruction that will jump to the * | ||
| 104 | * offset and segment specified * | ||
| 105 | * * | ||
| 106 | * CONTROL BLOCKS : INDEDAT.INC * | ||
| 107 | * * | ||
| 108 | * CHANGE ACTIVITY : * | ||
| 109 | * * | ||
| 110 | * $MOD(INDEINI) COMP(LOAD) PROD(3270PC) : * | ||
| 111 | * * | ||
| 112 | * $D0=D0004700 410 870521 D : NEW FOR RELEASE 1.1. CHANGES TO THE ORIGINAL * | ||
| 113 | * CODE ARE MARKED WITH D0A. * | ||
| 114 | * $P1=P0000281 410 870730 D : SAVE 32 BIT REGISTERS ON model_80 * | ||
| 115 | * $P2=P0000312 410 870804 D : CHANGE COMPONENT FROM MISC TO LOAD * | ||
| 116 | * $P3=P0000335 410 870811 D : HEADER INFORMATION ALL SCREWED UP * | ||
| 117 | * $D1=D0007100 410 870810 D : CHANGE TO EMULATE XMA 2 * | ||
| 118 | * CHANGE ID STRING TO "386XMAEMULATOR10" * | ||
| 119 | * $P4=P0000649 411 880125 D : A20 NOT ENABLED WHEN PASSWORD SET * | ||
| 120 | * $P5=P0000650 411 880128 D : COPROCESSOR APPLICATIONS FAIL * | ||
| 121 | * $P6=P0000740 411 880129 D : IDSS CAPTURED DCR 87 CODE. REMOVE IT. * | ||
| 122 | * $D2=D0008700 120 880206 D : SUPPORT DOS 3.4 IOCTL CALL * | ||
| 123 | * $P7=P0000xxx 120 880331 D : FIX INT 15. LOAD AS V86 MODE HANDLER. * | ||
| 124 | * * | ||
| 125 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 126 | # | ||
| 127 | |||
| 128 | .286P ; Enable recognition of 286 privileged instructs. | ||
| 129 | |||
| 130 | .XLIST ; Turn off the listing | ||
| 131 | INCLUDE INDEDAT.INC | ||
| 132 | |||
| 133 | IF1 ; Only include the macros in the first pass | ||
| 134 | INCLUDE INDEOVP.MAC ; of the assembler | ||
| 135 | INCLUDE INDEINS.MAC | ||
| 136 | ENDIF | ||
| 137 | .LIST ; Turn on the listing | ||
| 138 | |||
| 139 | ; Let these variables be known to external procedures | ||
| 140 | |||
| 141 | PUBLIC POST | ||
| 142 | PUBLIC INDEINI | ||
| 143 | |||
| 144 | PROG SEGMENT PARA PUBLIC 'PROG' | ||
| 145 | |||
| 146 | ASSUME CS:PROG | ||
| 147 | ASSUME SS:NOTHING | ||
| 148 | ASSUME DS:PROG | ||
| 149 | ASSUME ES:NOTHING | ||
| 150 | |||
| 151 | INDEINI LABEL NEAR | ||
| 152 | |||
| 153 | ; These variables are located in INDEI15 | ||
| 154 | |||
| 155 | EXTRN SP_INIT:WORD ; Initial protect mode SP | ||
| 156 | EXTRN REAL_CS:WORD ; Place to save our real mode CS | ||
| 157 | EXTRN REAL_SS:WORD ; Place to save our real mode SS | ||
| 158 | EXTRN REAL_SP:WORD ; Place to save our real mode SP | ||
| 159 | EXTRN PGTBLOFF:WORD ; Offset of the page tables | ||
| 160 | EXTRN SGTBLOFF:WORD ; Offest of the page directory | ||
| 161 | EXTRN NORMPAGE:WORD ; Normal page directory entry. Points to the | ||
| 162 | ; page table that maps the real 0 to 4M. | ||
| 163 | EXTRN XMAPAGE:WORD ; Page directory entry for the first XMA | ||
| 164 | ; page table (page table for bank 0) @D1A | ||
| 165 | EXTRN BUFF_SIZE:WORD ; Size of the MOVEBLOCK buffer | ||
| 166 | EXTRN MAXMEM:WORD ; Maximum amount of memory on the box | ||
| 167 | EXTRN CRT_SELECTOR:WORD ; Selector for the display buffer | ||
| 168 | |||
| 169 | ; These are the messages | ||
| 170 | |||
| 171 | EXTRN WELCOME:BYTE ; The welcome message | ||
| 172 | EXTRN GOODLOAD:BYTE ; Message saying we loaded OK | ||
| 173 | EXTRN NO_80386:BYTE ; Error message for not running on a model_80 | ||
| 174 | EXTRN WAS_INST:BYTE ; Error message for protect mode in use | ||
| 175 | Extrn Small_Parm:Byte ; Parm value < 64 and > 0 ;an000; dms; | ||
| 176 | Extrn No_Mem:Byte ; Parm value > memory available ;an000; dms; | ||
| 177 | |||
| 178 | ; These entries are located in external procedures | ||
| 179 | |||
| 180 | EXTRN SIDT_BLD:NEAR ; Build the interrupt descriptor table (IDT) | ||
| 181 | EXTRN GDT_BLD:NEAR ; Build the global descriptor table (GDT) | ||
| 182 | |||
| 183 | ; General equates | ||
| 184 | |||
| 185 | DDSIZE EQU GDT_LOC ; Size of the device driver | ||
| 186 | HIGH_SEG EQU 0FFF0H ; The segment we relocate to | ||
| 187 | MEG_SUPPORTED EQU 24 ; Must be a multiple of 4 | ||
| 188 | XMA_PAGES_SEL EQU RSDA_PTR ; Selector for XMA pages | ||
| 189 | DISPSTRG EQU 09H ; DOS display string function number D0A | ||
| 190 | GET_VECT EQU 35H ; DOS get vector function number P7A | ||
| 191 | SET_VECT EQU 25H ; DOS set vector function number P7A | ||
| 192 | model_80 EQU 0F8H ; Model byte for the Wangler D0A | ||
| 193 | XMA640KSTRT EQU 580H ; Start address of XMA block for D0A | ||
| 194 | ; 640K (16000:0 / 1K) D0A P3C | ||
| 195 | |||
| 196 | ; ASCII character equates | ||
| 197 | |||
| 198 | TAB EQU 09H ; ASCII tab | ||
| 199 | LF EQU 0AH ; ASCII line feed | ||
| 200 | CR EQU 0DH ; ASCII carriage return | ||
| 201 | |||
| 202 | SUBTTL Structure Definitions | ||
| 203 | PAGE | ||
| 204 | ;------------------------------------------------------------------------------; | ||
| 205 | ; Request Header (Common portion) ; | ||
| 206 | ;------------------------------------------------------------------------------; | ||
| 207 | |||
| 208 | RH EQU DS:[BX] ; The Request Header structure is based off | ||
| 209 | ; of DS:[BX] | ||
| 210 | |||
| 211 | RHC STRUC ; Fields common to all request types | ||
| 212 | DB ? ; Length of Request Header (including data) | ||
| 213 | DB ? ; Unit code (subunit) | ||
| 214 | RHC_CMD DB ? ; Command code | ||
| 215 | RHC_STA DW ? ; Status | ||
| 216 | DQ ? ; Reserved for DOS | ||
| 217 | RHC ENDS ; End of common portion | ||
| 218 | |||
| 219 | ; Status values for RHC_STA | ||
| 220 | |||
| 221 | STAT_DONE EQU 0100H ; Function complete status (high order byte)@P3C | ||
| 222 | STAT_CMDERR EQU 8003H ; Invalid command code error | ||
| 223 | STAT_GEN EQU 800CH ; General error code D0A | ||
| 224 | |||
| 225 | ;------------------------------------------------------------------------------; | ||
| 226 | ; Request Header for INIT command ; | ||
| 227 | ;------------------------------------------------------------------------------; | ||
| 228 | |||
| 229 | RH0 STRUC | ||
| 230 | DB (TYPE RHC) DUP (?) ; Reserve space for the header | ||
| 231 | |||
| 232 | RH0_NUN DB ? ; Number of units | ||
| 233 | ; Set to 1 if installation succeeds, | ||
| 234 | ; Set to 0 to cause installation failure | ||
| 235 | RH0_ENDO DW ? ; Offset of ending address | ||
| 236 | RH0_ENDS DW ? ; Segment of ending address | ||
| 237 | RH0_BPBO DW ? ; Offset of BPB array address | ||
| 238 | RH0_BPBS DW ? ; Segment of BPB array address | ||
| 239 | RH0_DRIV DB ? ; Drive code (DOS 3 only) | ||
| 240 | RH0 ENDS | ||
| 241 | |||
| 242 | RH0_BPBA EQU DWORD PTR RH0_BPBO ; Offset & segment of BPB array address. | ||
| 243 | ; On the INIT command the BPB points to | ||
| 244 | ; the characters following the "DEVICE=" | ||
| 245 | ; in the CONFIG.SYS file. | ||
| 246 | |||
| 247 | ;---------------------------------------------------------------------------D2A; | ||
| 248 | ; Request Header for Generic IOCTL Request D2A; | ||
| 249 | ;---------------------------------------------------------------------------D2A; | ||
| 250 | |||
| 251 | RH19 STRUC | ||
| 252 | DB (TYPE RHC) DUP (?) ; Reserve space for the header @D2A | ||
| 253 | |||
| 254 | RH19_MAJF DB ? ; Major function @D2A | ||
| 255 | RH19_MINF DB ? ; Minor function @D2A | ||
| 256 | RH19_SI DW ? ; Contents of SI @D2A | ||
| 257 | RH19_DI DW ? ; Contents of DI @D2A | ||
| 258 | RH19_RQPK DD ? ; Pointer to Generic IOCTL request packet @D2A | ||
| 259 | RH19 ENDS | ||
| 260 | |||
| 261 | SUBTTL Device Driver Header | ||
| 262 | PAGE | ||
| 263 | POST PROC NEAR | ||
| 264 | |||
| 265 | ; Declare the device driver header | ||
| 266 | |||
| 267 | ORG 0 ; Device header must the very first thing in the | ||
| 268 | ; device driver | ||
| 269 | DD -1 ; Becomes pointer to next device header | ||
| 270 | DW 0C040H ; Character device, does IOCTL @P3C @D2C | ||
| 271 | DW OFFSET STRATEGY ; Pointer to device "strategy" routine | ||
| 272 | DW OFFSET IRPT ; Pointer to device "interrupt handler" | ||
| 273 | DB "386XMAEM" ; Device name @D0C | ||
| 274 | |||
| 275 | ; End of device driver header | ||
| 276 | |||
| 277 | ;------------------------------------------------------------------------------; | ||
| 278 | ; Request Header (RH) address, saved here by "strategy" routine ; | ||
| 279 | ;------------------------------------------------------------------------------; | ||
| 280 | |||
| 281 | RH_PTRA LABEL DWORD | ||
| 282 | RH_PTRO DW ? ; Offset of the request header | ||
| 283 | RH_PTRS DW ? ; Segment of the request header | ||
| 284 | ; Character ID "386XMAEMULATOR10" deleted 2@D2D | ||
| 285 | HI_XMA_BLK DW ? ; The highest XMA block number @D0A | ||
| 286 | EXT_MEM DW ? ; Number of K of extended memory @P7A | ||
| 287 | ; D0A | ||
| 288 | RBX DW ? ; Temporary save area for register BX @P1A | ||
| 289 | ISmodel_80 DB -1 ; model_80 flag. Set to 1 if on a model_80 @P1A | ||
| 290 | ; Set to 0 if not on a model_80 @D1C | ||
| 291 | |||
| 292 | SUBTTL Device Strategy | ||
| 293 | PAGE | ||
| 294 | ;------------------------------------------------------------------------------; | ||
| 295 | ; Device "strategy" entry point ; | ||
| 296 | ; ; | ||
| 297 | ; Retain the Request Header address for use by Interrupt routine ; | ||
| 298 | ;------------------------------------------------------------------------------; | ||
| 299 | |||
| 300 | STRATEGY PROC FAR | ||
| 301 | |||
| 302 | MOV CS:RH_PTRO,BX ; Save the offset of the request header | ||
| 303 | MOV CS:RH_PTRS,ES ; Save the segment of the request header | ||
| 304 | RET | ||
| 305 | |||
| 306 | STRATEGY ENDP | ||
| 307 | |||
| 308 | SUBTTL Device Interrupt Intry Point | ||
| 309 | PAGE | ||
| 310 | |||
| 311 | ;------------------------------------------------------------------------------; | ||
| 312 | ; Table of command processing routine entry points ; | ||
| 313 | ;------------------------------------------------------------------------------; | ||
| 314 | CMD_TABLE LABEL WORD | ||
| 315 | DW OFFSET INIT_P1 ; 0 - Initialization | ||
| 316 | DW OFFSET MEDIA_CHECK ; 1 - Media check | ||
| 317 | DW OFFSET BLD_BPB ; 2 - Build BPB | ||
| 318 | DW OFFSET INPUT_IOCTL ; 3 - IOCTL input | ||
| 319 | DW OFFSET INPUT ; 4 - Input | ||
| 320 | DW OFFSET INPUT_NOWAIT ; 5 - Non destructive input no wait | ||
| 321 | DW OFFSET INPUT_STATUS ; 6 - Input status | ||
| 322 | DW OFFSET INPUT_FLUSH ; 7 - Input flush | ||
| 323 | DW OFFSET OUTPUT ; 8 - Output | ||
| 324 | DW OFFSET OUTPUT_VERIFY ; 9 - Output with verify | ||
| 325 | DW OFFSET OUTPUT_STATUS ;10 - Output status | ||
| 326 | DW OFFSET OUTPUT_FLUSH ;11 - Output flush | ||
| 327 | DW OFFSET OUTPUT_IOCTL ;12 - IOCTL output | ||
| 328 | DW OFFSET DEVICE_OPEN ;13 - Device OPEN | ||
| 329 | DW OFFSET DEVICE_CLOSE ;14 - Device CLOSE | ||
| 330 | DW OFFSET REMOVABLE_MEDIA ;15 - Removable media | ||
| 331 | DW OFFSET INVALID_FCN ;16 - Invalid IOCTL function @D2A | ||
| 332 | DW OFFSET INVALID_FCN ;17 - Invalid IOCTL function @D2A | ||
| 333 | DW OFFSET INVALID_FCN ;18 - Invalid IOCTL function @D2A | ||
| 334 | DW OFFSET GENERIC_IOCTL ;19 - Generic IOCTL function @D2A | ||
| 335 | DW OFFSET INVALID_FCN ;20 - Invalid IOCTL function @D2A | ||
| 336 | DW OFFSET INVALID_FCN ;21 - Invalid IOCTL function @D2A | ||
| 337 | DW OFFSET INVALID_FCN ;22 - Invalid IOCTL function @D2A | ||
| 338 | DW OFFSET GET_LOG_DEVICE ;23 - Get Logical Device @D2A | ||
| 339 | MAX_CMD EQU ($-CMD_TABLE)/2 ; Highest valid command follows | ||
| 340 | DW OFFSET SET_LOG_DEVICE ;24 - Set Logical Device @D2A | ||
| 341 | |||
| 342 | ;------------------------------------------------------------------------------; | ||
| 343 | ; Device "interrupt" entry point ; | ||
| 344 | ;------------------------------------------------------------------------------; | ||
| 345 | IRPT PROC FAR ; Device interrupt entry point | ||
| 346 | |||
| 347 | ; First we must save all the registers that we use so that when we return to | ||
| 348 | ; DOS the registers are not changed. | ||
| 349 | |||
| 350 | PUSH DS ; Save the segment registers modified | ||
| 351 | PUSH ES | ||
| 352 | |||
| 353 | CMP CS:ISmodel_80,-1; Did we already check what machine we are @D2A | ||
| 354 | JNE DID_CHECK ; running on? @D2A | ||
| 355 | |||
| 356 | MOV CS:RBX,BX ; Save BX @P1A | ||
| 357 | MOV BX,0FFFFH ; Check the model byte at FFFF:000E @D0A @P1M | ||
| 358 | MOV ES,BX ; to see if we're running on a @D0A @P1M | ||
| 359 | MOV BX,0EH ; model_80 (PS/2 model 80). @D0A @P1M | ||
| 360 | CMP BYTE PTR ES:[BX],model_80 ; @P1A | ||
| 361 | MOV BX,CS:RBX ; Restore BX @P1A @D2M | ||
| 362 | JNE NO_model_80 | ||
| 363 | |||
| 364 | MOV CS:ISmodel_80,1 ; Set the flag saying we're on a @P1A @D2M | ||
| 365 | JMP DID_CHECK ; model_80 @D2A | ||
| 366 | |||
| 367 | NO_model_80: | ||
| 368 | MOV CS:ISmodel_80,0 ; Set the flag saying we're not on a @D2M | ||
| 369 | ; model_80 | ||
| 370 | |||
| 371 | DID_CHECK: ; D2A | ||
| 372 | CMP ISmodel_80,1 ; Are we on a model_80? @D2A | ||
| 373 | JE PUSH32 ; If so, go save the 32 bit registers @P1A | ||
| 374 | |||
| 375 | ; Push 16 bit registers onto the stack. | ||
| 376 | |||
| 377 | PUSH AX | ||
| 378 | PUSH BX | ||
| 379 | PUSH CX | ||
| 380 | PUSH DX | ||
| 381 | PUSH DI | ||
| 382 | PUSH SI | ||
| 383 | PUSH BP | ||
| 384 | |||
| 385 | JMP PUSHED ; @P1A | ||
| 386 | |||
| 387 | ; Push 32 bit registers onto the stack P1A | ||
| 388 | ; @D2D | ||
| 389 | PUSH32: DATAOV ; Save all the 32 bit registers. The @P1A | ||
| 390 | PUSHA ; model_80's BIOS uses 32 bit registers, @P1A | ||
| 391 | ; so we must not trash the high order P1A | ||
| 392 | ; words as well as the low order words. P1A | ||
| 393 | |||
| 394 | PUSHED: CLD ; All moves go forward | ||
| 395 | |||
| 396 | LDS BX,CS:RH_PTRA ; Get the request header address passed to the | ||
| 397 | ; "strategy" routine into DS:BX | ||
| 398 | |||
| 399 | MOV AL,RH.RHC_CMD ; Get the command code from the Request Header | ||
| 400 | CBW ; Zero AH (if AL > 7FH, next compare will | ||
| 401 | ; catch that error) | ||
| 402 | |||
| 403 | CMP AL,MAX_CMD ; If command code is too high | ||
| 404 | JA IRPT_CMD_HIGH ; Then jump to error routine | ||
| 405 | |||
| 406 | ADD AX,AX ; Double command code for table offset since | ||
| 407 | ; table entries are words | ||
| 408 | MOV DI,AX ; Put into index register for CALL | ||
| 409 | ; @D2D | ||
| 410 | ; | ||
| 411 | ; At entry to command processing routine: | ||
| 412 | ; | ||
| 413 | ; DS:BX = Request Header address | ||
| 414 | ; CS = 386XMAEM code segment address | ||
| 415 | ; AX = 0 | ||
| 416 | ; | ||
| 417 | CALL CS:CMD_TABLE[DI] ; Call routine to handle the command | ||
| 418 | JMP IRPT_CMD_EXIT | ||
| 419 | |||
| 420 | |||
| 421 | IRPT_CMD_HIGH: ; JMPed to if RHC_CMD > MAX_CMD | ||
| 422 | MOV AX,STAT_CMDERR ; Return "Invalid Command" error code | ||
| 423 | OR AX,STAT_DONE ; Add "done" bit to status word @P3C | ||
| 424 | MOV RH.RHC_STA,AX ; Store status into request header | ||
| 425 | |||
| 426 | IRPT_CMD_EXIT: ; Return from command routine | ||
| 427 | |||
| 428 | ; Restore the registers before returning to DOS. | ||
| 429 | |||
| 430 | CMP CS:ISmodel_80,1 ; Are we on a model_80? @P1A | ||
| 431 | JE POP32 ; Yes. Then pop the 32 bit registers. @P1A | ||
| 432 | |||
| 433 | ; Pop 16 bit registers off of the stack. | ||
| 434 | |||
| 435 | POP BP | ||
| 436 | POP SI | ||
| 437 | POP DI | ||
| 438 | POP DX | ||
| 439 | POP CX | ||
| 440 | POP BX | ||
| 441 | POP AX | ||
| 442 | |||
| 443 | JMP POPPED ; @P1A | ||
| 444 | |||
| 445 | ; Pop 32 bit registers off of the stack. P1A | ||
| 446 | ; P1A | ||
| 447 | POP32: DATAOV ; @P1A | ||
| 448 | POPA ; @P1A | ||
| 449 | |||
| 450 | ; Pop the segment registers off of the stack. | ||
| 451 | |||
| 452 | POPPED: POP ES | ||
| 453 | POP DS | ||
| 454 | |||
| 455 | RET | ||
| 456 | IRPT ENDP | ||
| 457 | |||
| 458 | SUBTTL Command Routines | ||
| 459 | PAGE | ||
| 460 | |||
| 461 | MEDIA_CHECK: ; | ||
| 462 | BLD_BPB: ; | ||
| 463 | INPUT_IOCTL: ; IOCTL input | ||
| 464 | INPUT: ; | ||
| 465 | INPUT_NOWAIT: ; Non-destructive input no wait | ||
| 466 | INPUT_STATUS: ; Input status | ||
| 467 | INPUT_FLUSH: ; Input flush | ||
| 468 | OUTPUT: ; | ||
| 469 | OUTPUT_VERIFY: ; | ||
| 470 | OUTPUT_IOCTL: ; IOCTL output | ||
| 471 | OUTPUT_STATUS: ; Output status | ||
| 472 | OUTPUT_FLUSH: ; Output flush | ||
| 473 | DEVICE_OPEN: ; | ||
| 474 | DEVICE_CLOSE: ; | ||
| 475 | REMOVABLE_MEDIA: ; | ||
| 476 | INVALID_FCN: ; @D2A | ||
| 477 | GET_LOG_DEVICE: ; @D2A | ||
| 478 | SET_LOG_DEVICE: ; @D2A | ||
| 479 | |||
| 480 | MOV AX,STAT_GEN ; Return general error code @D2A | ||
| 481 | OR AX,STAT_DONE ; Add "done" bit to status word @D2A | ||
| 482 | MOV RH.RHC_STA,AX ; Store status into request header @D2A | ||
| 483 | |||
| 484 | RET | ||
| 485 | |||
| 486 | SUBTTL Generic IOCTL Service Routine | ||
| 487 | PAGE | ||
| 488 | |||
| 489 | ;------------------------------------------------------------------------------; | ||
| 490 | ; This routine handles the Generic IOCTL call. The Emulator provides an D2A; | ||
| 491 | ; interface through the Generic IOCTL call to query the number of XMA D2A; | ||
| 492 | ; blocks available. When the function code in the parameter list is 0 the D2A; | ||
| 493 | ; Emulator will return the number of XMA blocks available. There are no D2A; | ||
| 494 | ; other functions uspported at this time. D2A; | ||
| 495 | ;------------------------------------------------------------------------------; | ||
| 496 | |||
| 497 | GIP EQU ES:[DI] ; @D2A | ||
| 498 | |||
| 499 | GEN_IOCTL_PARM STRUC ; @D2A | ||
| 500 | |||
| 501 | GIOPLEN DW ? ; Length of the parameter list @D2A | ||
| 502 | GIOPFCN DW ? ; Function code @D2A | ||
| 503 | GIOPBLK DW ? ; Number of XMA blocks available @D2A | ||
| 504 | |||
| 505 | GEN_IOCTL_PARM ENDS ; @D2A | ||
| 506 | |||
| 507 | MAXFCN EQU 0 ; Highest function number allowed @D2A | ||
| 508 | |||
| 509 | ; Return codes D2A | ||
| 510 | |||
| 511 | GOODRET EQU 0 ; Good return code @D2A | ||
| 512 | BADLEN EQU 1 ; Bad parameter list length @D2A | ||
| 513 | BADFCN EQU 2 ; Bad function number @D2A | ||
| 514 | |||
| 515 | GENERIC_IOCTL: ; D2A | ||
| 516 | |||
| 517 | LES DI,RH.RH19_RQPK ; Point ES:DI to the Generic IOCTL @D2A | ||
| 518 | ; request packet D2A | ||
| 519 | |||
| 520 | ; First check to make sure the parameter list is long enough to return the D2A | ||
| 521 | ; number of XMA blocks. D2A | ||
| 522 | |||
| 523 | CMP GIP.GIOPLEN,4 ; Do we have at least four bytes? @D2A | ||
| 524 | JAE GIP_CHKFCN ; Yup. Go to check function number. @D2A | ||
| 525 | |||
| 526 | MOV GIP.GIOPFCN,BADLEN ; Nope. Sorry. Return the error @D2A | ||
| 527 | JMP GIP_DONE ; code and go to the end. @D2A | ||
| 528 | |||
| 529 | ; Check if the function number in the parameter list is a valid function. D2A | ||
| 530 | |||
| 531 | GIP_CHKFCN: ; D2A | ||
| 532 | CMP GIP.GIOPFCN,MAXFCN ; Is the function code less than or @D2A | ||
| 533 | ; equal to the maximum supported? D2A | ||
| 534 | JLE GIP_CONT ; Yes. Good boy. You get to continue. @D2A | ||
| 535 | |||
| 536 | MOV GIP.GIOPFCN,BADFCN ; No. Shamey, shamey. Set the bad @D2A | ||
| 537 | JMP GIP_DONE ; return code and go to the end. @D2A | ||
| 538 | |||
| 539 | ; Parameter list is OK. Let's return the number of XMA blocks. D2A | ||
| 540 | |||
| 541 | GIP_CONT: ; D2A | ||
| 542 | MOV GIP.GIOPFCN,GOODRET ; Set a good return code @D2A | ||
| 543 | MOV AX,CS:HI_XMA_BLK ; Get the number of XMA blox @D2A | ||
| 544 | MOV GIP.GIOPBLK,AX ; Put it in the paramter list @D2A | ||
| 545 | |||
| 546 | |||
| 547 | GIP_DONE: ; D2A | ||
| 548 | MOV RH.RHC_STA,STAT_DONE ; Store done status and good return @D2A | ||
| 549 | ; code into request header D2A | ||
| 550 | RET ; @D2A | ||
| 551 | |||
| 552 | INT15F88 PROC FAR ; P7A | ||
| 553 | |||
| 554 | ; The following is the interrupt chaining structure specified in the PC AT P7A | ||
| 555 | ; Technical Reference. P7A | ||
| 556 | |||
| 557 | JMP SHORT BEGIN ; P7A | ||
| 558 | |||
| 559 | CHAINOFF DW 0 ; Offest of the previous INT 15 vect. @P7A | ||
| 560 | CHAINSEG DW 0 ; Segment of the previous INT 15 vect.@P7A | ||
| 561 | SIGNATURE DW 424BH ; Says we're doing chaining @P7A | ||
| 562 | FLAGS DB 0 ; @P7A | ||
| 563 | FIRST EQU 80H ; @P7A | ||
| 564 | JMP SHORT RESET ; @P7A | ||
| 565 | RESERVED DB 7 DUP (0) ; @P7A | ||
| 566 | |||
| 567 | ; OK. Let's see if the user asked for function 88H, query memory size. P7A | ||
| 568 | ; The function number is specified in the AL register. If it's P7A | ||
| 569 | ; function88h, then put the memory size in AX and IRET to the caller. P7A | ||
| 570 | ; Else, just pass the interrupt on to the guy who was installed in the INT P7A | ||
| 571 | ; 15 vector before us. P7A | ||
| 572 | |||
| 573 | BEGIN: CMP AH,88H ; Is it function 88H? @P7A | ||
| 574 | JNE NOT_MINE ; It's not ours to handle @P7A | ||
| 575 | |||
| 576 | MOV AX,CS:EXT_MEM ; Put the number of K into AX @P7A | ||
| 577 | IRET ; Return to the caller @P7A | ||
| 578 | |||
| 579 | NOT_MINE: JMP CS:DWORD PTR CHAINOFF | ||
| 580 | ; Pass the interrupt on to the @P7A | ||
| 581 | ; previously installed vector @P7A | ||
| 582 | |||
| 583 | RESET: RET ; This, too, is part of the interrupt@P7A | ||
| 584 | ; chaining structure. We will just@P7A | ||
| 585 | ; return on a call to reset. Note @P7A | ||
| 586 | ; that this is a far return. @P7A | ||
| 587 | INT15F88 ENDP ; @P7A | ||
| 588 | |||
| 589 | LEAVE_RES LABEL NEAR ; Leave code up to here resident.@D0A @D2M | ||
| 590 | |||
| 591 | SUBTTL Initialize Routine | ||
| 592 | PAGE | ||
| 593 | INIT_P1: | ||
| 594 | |||
| 595 | PUSH ES ; Save our code segment at the @D0A | ||
| 596 | MOV DI,0 ; fixed location 0:4F4. This @P3C | ||
| 597 | MOV ES,DI ; gives us a quick way to find CS @P3C | ||
| 598 | MOV DI,4F4H ; and also enables us to break on @P3C | ||
| 599 | MOV ES:[DI],CS ; a write to 0:4F4 which helps us @P3C | ||
| 600 | POP ES ; find the code on the ICE386. @D0A | ||
| 601 | MOV AH,DISPSTRG ; Display the welcome message. @D0A | ||
| 602 | MOV DX,OFFSET WELCOME ; @D0A | ||
| 603 | PUSH DS ; Save DS since DS:BX points to the @D0A | ||
| 604 | PUSH CS ; request header @D0A | ||
| 605 | POP DS ; DS:DX points to the message @D0A | ||
| 606 | INT 21H ; Display the message @D0A | ||
| 607 | POP DS ; Restore DS @D0A | ||
| 608 | ; @P3D | ||
| 609 | MOV RH.RH0_ENDS,CS ; Set the segment and offset of the end | ||
| 610 | MOV RH.RH0_ENDO,OFFSET LEAVE_RES ; of code to leave resident | ||
| 611 | MOV RH.RHC_STA,STAT_DONE ; Store "done" status into request | ||
| 612 | ; header | ||
| 613 | CMP CS:ISmodel_80,1 ; Check if we're on a model_80 @D0A @P1C | ||
| 614 | JE CONT ; If so, then continue @D0A | ||
| 615 | ; D0A | ||
| 616 | MOV RH.RH0_ENDO,0 ; Leave nothing resident @D0A | ||
| 617 | MOV AX,STAT_GEN ; Return general error code @D0A | ||
| 618 | OR AX,STAT_DONE ; Add "done" bit to status word@D0A @P3C | ||
| 619 | MOV RH.RHC_STA,AX ; Store status into request header @D0A | ||
| 620 | ; D0A | ||
| 621 | MOV AH,DISPSTRG ; Display the message that we are @D0A | ||
| 622 | MOV DX,OFFSET NO_80386 ; not on a model_80 @D0A | ||
| 623 | PUSH CS ; @D0A | ||
| 624 | POP DS ; @D0A | ||
| 625 | INT 21H ; @D0A | ||
| 626 | ; D0A | ||
| 627 | RET ; D0A | ||
| 628 | ; D0A | ||
| 629 | CONT: ; @D0M | ||
| 630 | SMSW AX ; Get machine status register | ||
| 631 | TEST AL,1 ; Check if the processor is already in | ||
| 632 | ; protect mode. If so, then someone | ||
| 633 | ; else (maybe us) has already taken | ||
| 634 | ; over protect mode. | ||
| 635 | JZ STILLOK ; If not, keep going @D0C | ||
| 636 | |||
| 637 | MOV RH.RH0_ENDO,0 ; Leave nothing resident @D0A | ||
| 638 | MOV AX,STAT_GEN ; Return general error code @D0A | ||
| 639 | OR AX,STAT_DONE ; Add "done" bit to status word@D0A @P3C | ||
| 640 | MOV RH.RHC_STA,AX ; Store status into request header @D0A | ||
| 641 | ; D0A | ||
| 642 | MOV AH,DISPSTRG ; Display the message that protect @D0A | ||
| 643 | MOV DX,OFFSET WAS_INST ; mode is taken. @D0A | ||
| 644 | PUSH CS ; DS:DX points to the message @D0A | ||
| 645 | POP DS ; @D0A | ||
| 646 | INT 21H ; @D0A | ||
| 647 | |||
| 648 | RET ; | ||
| 649 | STILLOK: ; D0A | ||
| 650 | PUSH 0DEADH ; Push stack delimiter | ||
| 651 | ; Don't have to set character ID @D2D | ||
| 652 | CALL GET_PARMS ; Get the MOVEBLOCK buffer size if | ||
| 653 | jnc StillOK1 | ||
| 654 | MOV RH.RH0_ENDO,0 ; Leave nothing resident @D0A | ||
| 655 | MOV AX,STAT_GEN ; Return general error code @D0A | ||
| 656 | OR AX,STAT_DONE ; Add "done" bit to status word@D0A @P3C | ||
| 657 | MOV RH.RHC_STA,AX ; Store status into request header @D0A | ||
| 658 | ; D0A | ||
| 659 | pop ax | ||
| 660 | ret ; exit program | ||
| 661 | |||
| 662 | StillOK1: | ||
| 663 | ; one was specified | ||
| 664 | CLI ; Disable interrupts | ||
| 665 | |||
| 666 | PUSH CS ; Now we can point DS to our own @P3A | ||
| 667 | POP DS ; code segment @P3A | ||
| 668 | ; 2@D2D | ||
| 669 | MOV AX,CS | ||
| 670 | MOV REAL_CS,AX ; Save real CS for when we @P3C | ||
| 671 | MOV AX,SS ; switch to protect mode | ||
| 672 | MOV REAL_SS,AX ; Save real SS @P3C | ||
| 673 | MOV AX,SP | ||
| 674 | MOV REAL_SP,AX ; Save real SP @P3C | ||
| 675 | |||
| 676 | ;------------------------------------------------------------------------------; | ||
| 677 | ; Enable address line A20 ; | ||
| 678 | ;------------------------------------------------------------------------------; | ||
| 679 | |||
| 680 | ; 3@P4D | ||
| 681 | CALL GATE_A20 | ||
| 682 | |||
| 683 | INT 11H ; Get the BIOS equipment flags | ||
| 684 | AND AL,30H ; Bits 5 and 6 on means it's a mono | ||
| 685 | CMP AL,30H | ||
| 686 | JE LEAVEBW | ||
| 687 | MOV CRT_SELECTOR,C_CCRT_PTR ; Set the CRT selector to color display | ||
| 688 | LEAVEBW: | ||
| 689 | MOV AH,88H ; Get number of 1k blocks above 1M | ||
| 690 | INT 15H | ||
| 691 | ADD AX,1024 ; Add 640K for the memory below 640K @P7C | ||
| 692 | MOV MAXMEM,AX ; Save for later | ||
| 693 | |||
| 694 | ; Get the maximum XMA block number and save it in the header up front D0A | ||
| 695 | ; All memory is treated as XMA memory. D1C | ||
| 696 | ; D0A | ||
| 697 | SUB AX,BUFF_SIZE ; Can't use the MOVEBLOCK buffer for @D0A | ||
| 698 | ; XMA memory. AX = number of K D0A | ||
| 699 | ; available. D0A | ||
| 700 | SUB AX,(1024-640) +128 ; Subtract 128k for the Emulator code ;an000; dms; | ||
| 701 | SHR AX,2 ; Divide by four to get the number of @D0A | ||
| 702 | ; 4K blocks D0A | ||
| 703 | DEC AX ; Subtract 1. This converts the @P3A | ||
| 704 | ; number of blocks available to the P3A | ||
| 705 | ; highest block number available. P3A | ||
| 706 | ; Block numbers are zero based. P3A | ||
| 707 | MOV HI_XMA_BLK,AX ; Save it in the header D0A | ||
| 708 | |||
| 709 | ;------------------------------------------------------------------------------; | ||
| 710 | ; Now lets relocate ourselves to high memory. ; | ||
| 711 | ;------------------------------------------------------------------------------; | ||
| 712 | |||
| 713 | MOV AX,HIGH_SEG ; Set ES to the highest segment value | ||
| 714 | MOV ES,AX | ||
| 715 | MOV DI,0 ; ES:DI points to the place to relocate to | ||
| 716 | MOV AX,CS | ||
| 717 | MOV DS,AX | ||
| 718 | MOV SI,0 ; DS:SI points to our code to be moved | ||
| 719 | MOV CX,DDSIZE/2 ; Length of code / 2 since moving words | ||
| 720 | CLD | ||
| 721 | REP MOVSW ; Copy myself to high memory | ||
| 722 | |||
| 723 | JUMPFAR NEXT,HIGH_SEG ; Jump to my relocated code | ||
| 724 | NEXT: | ||
| 725 | |||
| 726 | MOV AX,HIGH_SEG ; Set DS to be the same as CS | ||
| 727 | MOV DS,AX | ||
| 728 | ;------------------------------------------------------------------------------; | ||
| 729 | ; The machine is still in real mode. Zero out GDT and IDT ram. ; | ||
| 730 | ;------------------------------------------------------------------------------; | ||
| 731 | |||
| 732 | MOV DI,GDT_LOC ; DI points to GDT location | ||
| 733 | |||
| 734 | MOV CX,(GDT_LEN+SIDT_LEN)/2 ; Set GDT and IDT to zero | ||
| 735 | MOV AX,0 ; Store zeroes for now | ||
| 736 | REP STOSW | ||
| 737 | |||
| 738 | ;------------------------------------------------------------------------------; | ||
| 739 | ; Use good-old real-mode selectors to set up the page tables. The ; | ||
| 740 | ; page directory is a 4K block that is placed just before the ; | ||
| 741 | ; beginning of the GDT and on a 4K boundary. Note that the DATAOV ; | ||
| 742 | ; macro creates a prefix for the following instruction so that its ; | ||
| 743 | ; data references are 32 bits wide. ; | ||
| 744 | ;------------------------------------------------------------------------------; | ||
| 745 | |||
| 746 | DATAOV | ||
| 747 | SUB AX,AX ; Clear EAX (32 bit AX reg.) | ||
| 748 | MOV AX,HIGH_SEG ; Get the current code segment | ||
| 749 | DATAOV | ||
| 750 | SUB BX,BX ; Clear EBX (32 bit BX reg.) | ||
| 751 | MOV BX,GDT_LOC/16 ; Load the offset of the GDT, converted | ||
| 752 | ; to paragraphs | ||
| 753 | DATAOV ; Add it on to the current code segment | ||
| 754 | ADD AX,BX ; to get the segment address of the GDT. | ||
| 755 | ; This will be over 1M, so use 32 bits. | ||
| 756 | AND AX,0FF00H ; Round down to nice 4k boundary | ||
| 757 | DATAOV | ||
| 758 | SUB BX,BX ; Clear EBX | ||
| 759 | MOV BX,4096/16 ; Load with the size of the page directory | ||
| 760 | ; converted to paragraphs | ||
| 761 | DATAOV ; Subtract the number of paragraphs needed | ||
| 762 | SUB AX,BX ; for the page directory | ||
| 763 | DATAOV | ||
| 764 | SHL AX,4 ; Convert from paragraphs to bytes | ||
| 765 | CMOV CR3,EAX ; Load the address of the page directory | ||
| 766 | ; into CR3 | ||
| 767 | DATAOV | ||
| 768 | SUB BX,BX ; Clear EBX | ||
| 769 | MOV BX,HIGH_SEG ; Load our current code segment | ||
| 770 | DATAOV | ||
| 771 | SHL BX,4 ; Convert from paragraphs to bytes | ||
| 772 | DATAOV | ||
| 773 | SUB AX,BX ; Subtract from the address of the page | ||
| 774 | ; directory to get the offset of the | ||
| 775 | ; directory in our code segment | ||
| 776 | MOV SGTBLOFF,AX ; Save for later | ||
| 777 | |||
| 778 | ; Now let's clear the page directory | ||
| 779 | |||
| 780 | MOV CX,2048 ; Length is 4K/2 since storing words | ||
| 781 | DATAOV | ||
| 782 | MOV DI,AX ; ES:EDI points to beginning of directory | ||
| 783 | MOV AX,0 | ||
| 784 | REP STOSW ; Clear the page directory! | ||
| 785 | |||
| 786 | ;------------------------------------------------------------------------------; | ||
| 787 | ; Initialize the first directory entries to our page tables ; | ||
| 788 | ;------------------------------------------------------------------------------; | ||
| 789 | |||
| 790 | CMOV EAX,CR3 ; Get back CR3 - the address of the page dir. | ||
| 791 | DATAOV | ||
| 792 | MOV DI,SGTBLOFF ; Point ES:EDI to first entry in directory | ||
| 793 | DATAOV | ||
| 794 | SUB BX,BX ; Clear EBX | ||
| 795 | MOV BX,MEG_SUPPORTED/4*4096 ; Load the size of the page tables. | ||
| 796 | ; Each page table maps 4M of memory, so divide | ||
| 797 | ; the number of Meg supported by 4 to get the | ||
| 798 | ; number of page tables. Each page table is | ||
| 799 | ; 4K in size, so multiply by 4K. | ||
| 800 | DATAOV | ||
| 801 | SUB AX,BX ; Subtract the size needed for the page tables | ||
| 802 | ; from the address of the page directory to | ||
| 803 | ; get the address of the first page table. | ||
| 804 | ADD AX,7 ; Set the present bit and access rights. | ||
| 805 | ; This converts the address to a valid entry | ||
| 806 | ; for the page directory. | ||
| 807 | DATAOV | ||
| 808 | MOV NORMPAGE,AX ; Save for later | ||
| 809 | MOV CX,MEG_SUPPORTED/4 ; Load the number of page tables into CX | ||
| 810 | DATAOV | ||
| 811 | SUB BX,BX ; Clear EBX | ||
| 812 | MOV BX,1000H ; Set up 4k increment | ||
| 813 | ; | ||
| 814 | ; Now we load the page directory. EAX contains the address of the first | ||
| 815 | ; page table, EBX contains 4K, CX contains the number of page tables, and | ||
| 816 | ; ES:EDI (32 bit DI reg.) points to the first page directory entry. Now what | ||
| 817 | ; we do is stuff EAX into the 32bits pointed to by EDI. EDI is then auto- | ||
| 818 | ; incremented by four bytes, because of the 32 bit stuff, and points to the | ||
| 819 | ; next page directory entry. (Page directory and page table entries are four | ||
| 820 | ; bytes long.) Then we add the 4K in EBX to the address in EAX making EAX | ||
| 821 | ; the address of the next page table. This is done for the number of page | ||
| 822 | ; table entries in CX. Pretty slick, huh? | ||
| 823 | ; | ||
| 824 | LPT: | ||
| 825 | DATAOV ; Stuff the page table address into the | ||
| 826 | STOSW ; page directory | ||
| 827 | DATAOV ; Add 4K to the page table address in EAX | ||
| 828 | ADD AX,BX ; so that it contains the address of the | ||
| 829 | ; next page table | ||
| 830 | LOOP LPT ; Do it again | ||
| 831 | |||
| 832 | ; Now calcuate the offset from our code segment of the page tables | ||
| 833 | |||
| 834 | DATAOV | ||
| 835 | SUB BX,BX ; Clear EBX | ||
| 836 | MOV BX,HIGH_SEG ; Load our current code segment | ||
| 837 | DATAOV | ||
| 838 | SHL BX,4 ; Convert paragraphs to bytes | ||
| 839 | DATAOV ; Load EAX with the address of the first | ||
| 840 | MOV AX,NORMPAGE ; page table | ||
| 841 | DATAOV | ||
| 842 | SUB AX,BX ; Convert EAX to an offset | ||
| 843 | AND AL,0F8H ; AND off the access rights | ||
| 844 | MOV PGTBLOFF,AX ; Save for later | ||
| 845 | |||
| 846 | ;------------------------------------------------------------------------------; | ||
| 847 | ; Initialize the page tables ; | ||
| 848 | ;------------------------------------------------------------------------------; | ||
| 849 | |||
| 850 | MOV DI,PGTBLOFF ; ES:DI points to the first page table | ||
| 851 | DATAOV | ||
| 852 | SUB AX,AX ; Zero EAX | ||
| 853 | ADD AX,7 ; Set the present and access rights | ||
| 854 | MOV CX,MEG_SUPPORTED/4*1024 ; Load CX with the number of page table | ||
| 855 | ; entries to initialize. As mentioned | ||
| 856 | ; above, the number of page tables = | ||
| 857 | ; number of Meg / 4. There are 1K | ||
| 858 | ; entries per table so multiply by 1K | ||
| 859 | DATAOV | ||
| 860 | SUB BX,BX ; Clear EBX | ||
| 861 | MOV BX,1000H ; Set up 4k increment | ||
| 862 | ; | ||
| 863 | ; As with the page directory, we use a tight loop to initialize the page tables. | ||
| 864 | ; EAX contains the address of the first page frame, which is 0000, plus the | ||
| 865 | ; access rights. EBX contains a 4K increment. ES:DI points to the first entry | ||
| 866 | ; in the first page table. CX contains the number of page table entries to | ||
| 867 | ; initialize. The stuff and increment works the same as for the page directory | ||
| 868 | ; with an added touch. Note that this does all the page tables in one fell | ||
| 869 | ; swoop. When we finish stuffing the last address into the first page table | ||
| 870 | ; the next place we stuff is into the first entry in the second page table. | ||
| 871 | ; Since our page tables are back to back we can just zoom up the page tables | ||
| 872 | ; incrementing by 4K as we go and thus initialize all the page tables in one | ||
| 873 | ; fell swoop. | ||
| 874 | ; | ||
| 875 | BPT: | ||
| 876 | DATAOV ; Stuff the page frame address into the | ||
| 877 | STOSW ; page table | ||
| 878 | DATAOV | ||
| 879 | ADD AX,BX ; Next 4k page frame | ||
| 880 | LOOP BPT | ||
| 881 | |||
| 882 | ;------------------------------------------------------------------------------; | ||
| 883 | ; Now set up the first 64K over 1M to point to point to the first 64K ; | ||
| 884 | ; in low memory to simulate the segment wrap over 1M. ; | ||
| 885 | ; For now will set it up to point to itself and try to get DOS to load ; | ||
| 886 | ; the device driver up there. Will find out if anyone tries to alter ; | ||
| 887 | ; it because it will be marked for system use only. ; | ||
| 888 | ;------------------------------------------------------------------------------; | ||
| 889 | |||
| 890 | MOV DI,1024 ; 1M offset into page table | ||
| 891 | ADD DI,PGTBLOFF ; Page table offset | ||
| 892 | MOV AX,10H ; Set EAX to contain 1M address by loading | ||
| 893 | DATAOV ; it with 10H and shifting it 16 bits to | ||
| 894 | SHL AX,16 ; get 00100000. (Same as 10000:0) | ||
| 895 | ADD AX,5 ; Present, system use, read only | ||
| 896 | MOV CX,16 ; 16 entries = 64k | ||
| 897 | BPT2: | ||
| 898 | DATAOV | ||
| 899 | STOSW ; Stuff the address in the page table | ||
| 900 | DATAOV | ||
| 901 | ADD AX,BX ; Next 4k page frame | ||
| 902 | LOOP BPT2 | ||
| 903 | |||
| 904 | PAGE | ||
| 905 | ;------------------------------------------------------------------------------; | ||
| 906 | ; Build the Global Descriptor Table and load the GDT register. ; | ||
| 907 | ;------------------------------------------------------------------------------; | ||
| 908 | CALL GDT_BLD | ||
| 909 | |||
| 910 | MOV DI,GDT_PTR ; Get the offset of the GDT descriptor | ||
| 911 | ADD DI,GDT_LOC ; located in the GDT | ||
| 912 | MOV BP,DI ; Transfer the offset to BP | ||
| 913 | LGDT ES:FWORD PTR[BP] ; Put the descriptor for the GDT into | ||
| 914 | ; the GDT register | ||
| 915 | |||
| 916 | PAGE | ||
| 917 | ;------------------------------------------------------------------------------; | ||
| 918 | ; Build and initialize the system Interrupt Descriptor Table, ; | ||
| 919 | ; then load the IDT register. ; | ||
| 920 | ;------------------------------------------------------------------------------; | ||
| 921 | CALL SIDT_BLD | ||
| 922 | |||
| 923 | MOV DI,MON_IDT_PTR ; Get the offset of the IDT descriptor | ||
| 924 | ADD DI,GDT_LOC ; located in the GDT | ||
| 925 | MOV BP,DI ; Transfer the offset to BP | ||
| 926 | |||
| 927 | LIDT ES:FWORD PTR[BP] ; Put the descriptor for the IDT into | ||
| 928 | ; the IDT register | ||
| 929 | |||
| 930 | PAGE | ||
| 931 | ;------------------------------------------------------------------------------; | ||
| 932 | ; At this point we prepare to switch to virtual mode. The first ; | ||
| 933 | ; instruction after the LMSW that causes the switch must be a ; | ||
| 934 | ; jump far to set a protected mode segment selector into CS. ; | ||
| 935 | ;------------------------------------------------------------------------------; | ||
| 936 | |||
| 937 | MOV AX,VIRTUAL_ENABLE ; Machine status word needed to | ||
| 938 | LMSW AX ; switch to virtual mode | ||
| 939 | |||
| 940 | JUMPFAR DONE,SYS_PATCH_CS ; Must purge pre-fetch queue | ||
| 941 | ; and set selector into CS | ||
| 942 | DONE: | ||
| 943 | PAGE | ||
| 944 | ;------------------------------------------------------------------------------; | ||
| 945 | ; Initialize all the segment registers ; | ||
| 946 | ;------------------------------------------------------------------------------; | ||
| 947 | |||
| 948 | MOV AX,SYS_PATCH_DS ; Load DS, ES, and SS with the selector | ||
| 949 | MOV DS,AX ; for our data area. This is the same | ||
| 950 | MOV ES,AX ; as our code area but has read/write | ||
| 951 | ; access. | ||
| 952 | MOV SS,AX | ||
| 953 | MOV SP,OFFSET SP_INIT | ||
| 954 | |||
| 955 | PUSH 0002H ; Clean up our flags. Turn off all bits | ||
| 956 | POPF ; except the one that is always on. | ||
| 957 | |||
| 958 | ;------------------------------------------------------------------------------; | ||
| 959 | ; Load the LDTR to avoid faults ; | ||
| 960 | ;------------------------------------------------------------------------------; | ||
| 961 | |||
| 962 | MOV AX,SCRUBBER.TSS_PTR ; Load DS with the data descriptor for | ||
| 963 | MOV DS,AX ; the virtual machine's TSS | ||
| 964 | MOV AX,SCRUBBER.VM_LDTR ; Get the LDTR for virtual machine | ||
| 965 | MOV DS:VM_LDT,AX ; Set LDTR in TSS | ||
| 966 | LLDT AX ; Set the LDTR. Temporary for now. | ||
| 967 | |||
| 968 | ; Have to always have space allocated for the dispatch task TSS | ||
| 969 | |||
| 970 | MOV AX,SCRUBBER.VM_TR ; Low mem gets clobbered without this @P5C | ||
| 971 | LTR AX ; Set current Task Register | ||
| 972 | ; This TSS is located right after the IDT | ||
| 973 | |||
| 974 | PAGE | ||
| 975 | ;------------------------------------------------------------------------------; | ||
| 976 | ; Now we initialize the TSS (Task State Segment) for the one and only ; | ||
| 977 | ; virtual 8086 task. This task encompasses everything that runs in real ; | ||
| 978 | ; mode. First we clear the TSS and its I/O bit map. Then we initialize ; | ||
| 979 | ; the bit map for all the I/O ports we want to trap. Then we set up the ; | ||
| 980 | ; registers for the V86 task. These registers are given the same values ; | ||
| 981 | ; as we got on entry. IP is set to point to TEST_EXIT. ; | ||
| 982 | ;------------------------------------------------------------------------------; | ||
| 983 | |||
| 984 | MOV AX,SCRUBBER.TSS_PTR ; Load ES and DS with the descriptor | ||
| 985 | MOV DS,AX ; for the VM's TSS with read/write | ||
| 986 | MOV ES,AX ; access rights | ||
| 987 | CLD | ||
| 988 | MOV DI,0 ; Point ES:DI to the beginning of the TSS | ||
| 989 | MOV AX,0 ; Clear AX | ||
| 990 | MOV BX,0 ; Clear BX | ||
| 991 | MOV CX,TSS_386_LEN ; Load CX with the length of the TSS | ||
| 992 | REP STOSB ; Clear the TSS | ||
| 993 | MOV CX,TSS_BM_LEN ; Load CX with the length of the I/O bit | ||
| 994 | ; map. The bit map immediately follows | ||
| 995 | ; the TSS and is in the TSS segment. | ||
| 996 | REP STOSB ; Clear the bit map | ||
| 997 | MOV AL,0FFH ; Intel requires this byte | ||
| 998 | STOSB | ||
| 999 | |||
| 1000 | ; | ||
| 1001 | ; Now set up the bit map. Turn on bits for I/O ports that we want to trap. | ||
| 1002 | ; | ||
| 1003 | |||
| 1004 | MOV DI,0+TSS_386_LEN ; Set bits 0,2,4,6 to 1 - DMA ports | ||
| 1005 | MOV AL,055H | ||
| 1006 | STOSB | ||
| 1007 | MOV DI,1+TSS_386_LEN ; Set C to 1 - DMA port | ||
| 1008 | MOV AL,010H | ||
| 1009 | STOSB | ||
| 1010 | MOV DI,3+TSS_386_LEN ; Set 18,1A to 1 - DMA ports | ||
| 1011 | MOV AL,005H | ||
| 1012 | STOSB | ||
| 1013 | MOV DI,16+TSS_386_LEN ; Set 80-8f to 1s - DMA page ports | ||
| 1014 | MOV AL,0FFH ; + manufacturing port for ctl-alt-del | ||
| 1015 | STOSB | ||
| 1016 | STOSB | ||
| 1017 | MOV DI,0680H/8+TSS_386_LEN ; Set Roundup manuf. port to 1 | ||
| 1018 | MOV AL,001H | ||
| 1019 | STOSB | ||
| 1020 | MOV DI,31A0H/8+TSS_386_LEN ; Set 31a0-31a7 to 1s (XMA) | ||
| 1021 | MOV AL,0FFH | ||
| 1022 | STOSB | ||
| 1023 | |||
| 1024 | MOV WORD PTR [BX].ETSS_BM_OFFSET,TSS_386_LEN | ||
| 1025 | ; Put the bit map offset in the TSS | ||
| 1026 | MOV WORD PTR [BX].ETSS_SP0,OFFSET SP_INIT | ||
| 1027 | ; Put our SP as the SP for privilege | ||
| 1028 | ; level 0 | ||
| 1029 | MOV WORD PTR [BX].ETSS_SS0,SYS_PATCH_DS | ||
| 1030 | ; Put our SS as the SS for privilege | ||
| 1031 | ; level 0 | ||
| 1032 | |||
| 1033 | ; Next we set up the segment registers | ||
| 1034 | |||
| 1035 | MOV WORD PTR [BX].ETSS_GS,SEG PROG ; GS - our code segment | ||
| 1036 | MOV WORD PTR [BX].ETSS_FS,SEG PROG ; FS - our code segment | ||
| 1037 | MOV WORD PTR [BX].ETSS_DS,SEG PROG ; DS - our code segment | ||
| 1038 | MOV WORD PTR [BX].ETSS_ES,SEG PROG ; ES - our code segment | ||
| 1039 | |||
| 1040 | ; Next the SS,SP | ||
| 1041 | |||
| 1042 | MOV AX,CS:REAL_SS ; Set the real mode SS as the SS for the task | ||
| 1043 | MOV WORD PTR [BX].ETSS_SS,AX | ||
| 1044 | MOV AX,CS:REAL_SP ; Set the real mode SP as the SP for the task | ||
| 1045 | MOV WORD PTR [BX].ETSS_SP,AX | ||
| 1046 | |||
| 1047 | ; The flags register | ||
| 1048 | |||
| 1049 | MOV WORD PTR [BX].ETSS_FL2,2 ; Set the VM flag. Task is a V86 task. | ||
| 1050 | MOV WORD PTR [BX].ETSS_FL,0202H ; Set interrupts enabled | ||
| 1051 | |||
| 1052 | ; Set up CS and IP | ||
| 1053 | |||
| 1054 | MOV AX,CS:REAL_CS ; Set the real mode CS as the CS for the task | ||
| 1055 | MOV WORD PTR [BX].ETSS_CS,AX ; This is the CS we got when we loaded | ||
| 1056 | ; in low memory, before relocating | ||
| 1057 | MOV AX,OFFSET PROG:TEST_EXIT ; Set IP to the label TEST_EXIT below. | ||
| 1058 | MOV WORD PTR [BX].ETSS_IP,AX | ||
| 1059 | |||
| 1060 | ; The LDTR | ||
| 1061 | |||
| 1062 | MOV WORD PTR [BX].ETSS_LDT,SCRUBBER.VM_LDTR | ||
| 1063 | |||
| 1064 | ; And finally, CR3, the page directory base register | ||
| 1065 | |||
| 1066 | CMOV EAX,CR3 ; Get CR3 | ||
| 1067 | DATAOV | ||
| 1068 | MOV WORD PTR [BX].ETSS_CR3,AX ; Save it in the TSS | ||
| 1069 | |||
| 1070 | PAGE | ||
| 1071 | ;------------------------------------------------------------------------------; | ||
| 1072 | ; Now initialize our wonderful XMA page tables. Each table maps 4M. ; | ||
| 1073 | ; There is one table for each XMA bank since 4M is enough to map the ; | ||
| 1074 | ; 1M address space. All the XMA tables are initialized to point to ; | ||
| 1075 | ; the real memory at 0 to 4M. This is done by just copying the page ; | ||
| 1076 | ; table entry for 0 to 4M that was initialized above. ; | ||
| 1077 | ;------------------------------------------------------------------------------; | ||
| 1078 | |||
| 1079 | MOV AX,SYS_PATCH_DS ; Load DS with the selector for our data | ||
| 1080 | MOV DS,AX | ||
| 1081 | MOV SI,PGTBLOFF ; DS:SI point to the real page table for 0-4M | ||
| 1082 | MOV AX,XMA_PAGES_SEL ; Load ES with the selector for the XMA pages | ||
| 1083 | MOV ES,AX | ||
| 1084 | SUB DI,DI ; ES:DI point to the first XMA page table | ||
| 1085 | MOV CX,2048 ; Copy 4K / 2 since we're copying words | ||
| 1086 | REP MOVSW ; Copy the first XMA page table | ||
| 1087 | ; | ||
| 1088 | ; Now ES:DI points to the second XMA page table. Set DS:SI to point to the | ||
| 1089 | ; first XMA page table as the source for the copy. Now we can put a count | ||
| 1090 | ; of 15 page tables in CX. After each page is copied it is used as the source | ||
| 1091 | ; for the next page. This method lets us zip up the page tables initializing | ||
| 1092 | ; them all to be the same as the original page table for 0 - 4M. | ||
| 1093 | ; | ||
| 1094 | MOV AX,XMA_PAGES_SEL ; Load DS with the selector for the XMA page | ||
| 1095 | MOV DS,AX ; tables | ||
| 1096 | SUB SI,SI ; DS:SI points to the first XMA page table | ||
| 1097 | MOV CX,2048*15 ; Copy 15 more page tables | ||
| 1098 | REP MOVSW ; Copy to the other 15 XMA ID'S page tables | ||
| 1099 | |||
| 1100 | ; D1A | ||
| 1101 | ; Set the first page directory entry to point to the page table for bank 0. D1A | ||
| 1102 | ; This is another way of saying, "Let's make bank 0 the active bank." We D1A | ||
| 1103 | ; are now emulating the XMA 2 card along with its initialization device D1A | ||
| 1104 | ; driver, INDXMAA.SYS. When the device driver exits, it leaves the XMA 2 D1A | ||
| 1105 | ; card enabled and set to bank 0. Therefore, we must do the same. D1A | ||
| 1106 | ; D1A | ||
| 1107 | ; D1A | ||
| 1108 | MOV AX,SYS_PATCH_DS ; Load DS and ES with our data segment @D1A | ||
| 1109 | MOV DS,AX ; selector @D1A | ||
| 1110 | MOV ES,AX ; @D1A | ||
| 1111 | MOV DI,SGTBLOFF ; Point ES:DI to the first page @D1A | ||
| 1112 | ; directory entry D1A | ||
| 1113 | DATAOV ; Load AX with the page directory entry @D1A | ||
| 1114 | MOV AX,XMAPAGE ; for the first XMA page table @D1A | ||
| 1115 | DATAOV ; Stuff the address of the page table @D1A | ||
| 1116 | STOSW ; for bank 0 into the page directory @D1A | ||
| 1117 | |||
| 1118 | PAGE | ||
| 1119 | ;------------------------------------------------------------------------------; | ||
| 1120 | ; And now, the moment you've all been waiting for -- TURN ON THE PAGING ; | ||
| 1121 | ; MECHANISM!!! ; | ||
| 1122 | ;------------------------------------------------------------------------------; | ||
| 1123 | |||
| 1124 | CMOV EAX,CR0 ; Get CR0 @P5A | ||
| 1125 | MOV BX,8000H ; Set up BX to OR on the Paging Enable bit @P5C | ||
| 1126 | DATAOV | ||
| 1127 | SHL BX,16 ; It's the one all the way on the left @P5C | ||
| 1128 | DATAOV ; @P5A | ||
| 1129 | OR AX,BX ; Set the paging enabled bit @P5A | ||
| 1130 | OR AL,02H ; Set co-processor bit on @P5A | ||
| 1131 | AND AL,0F7H ; Turn off Task Switch bit @P5C | ||
| 1132 | CMOV CR0,EAX ; Here we go... | ||
| 1133 | |||
| 1134 | ; Make sure high order bits of ESP are zero - a1 errata | ||
| 1135 | |||
| 1136 | MOV AX,SP ; Save SP in AX 'cause it changes when we do... | ||
| 1137 | PUSH 0 ; this PUSH. Push 0 for high 16 bits of ESP | ||
| 1138 | PUSH AX ; Push low 16 bits of SP | ||
| 1139 | DATAOV | ||
| 1140 | POP SP ; Pop 32 bit ESP! | ||
| 1141 | |||
| 1142 | PAGE | ||
| 1143 | ;------------------------------------------------------------------------------; | ||
| 1144 | ; Now we give control back to the V86 task by setting up the stack P5C; | ||
| 1145 | ; for an IRET back to the V86 task. This requires putting the V86 P5C; | ||
| 1146 | ; task's segment registers, SS and ESP, and the EFLAGS, CS and IP on P5C; | ||
| 1147 | ; the stack. The 80386 puts all these values on the stack when it P5C; | ||
| 1148 | ; interrupts out of V86 mode, so it expects them there on an IRET P5C; | ||
| 1149 | ; back to V86 mode. But really we are giving control back to ; | ||
| 1150 | ; ourself. The CS:IP on the stack point to the label TEST_EXIT ; | ||
| 1151 | ; below, but it is in the copy of the emulator that was originally ; | ||
| 1152 | ; loaded, not the copy that was relocated to high memory and is now ; | ||
| 1153 | ; running in protect mode. This clever trick will result in the ; | ||
| 1154 | ; original copy of the emulator returning to DOS which will continue ; | ||
| 1155 | ; to load the rest of the system. The system will come up completely ; | ||
| 1156 | ; unaware that it is running in a small universe of a V86 task which ; | ||
| 1157 | ; is being monitored by the XMA emulator. ; | ||
| 1158 | ;------------------------------------------------------------------------------; | ||
| 1159 | |||
| 1160 | |||
| 1161 | MOV AX,SCRUBBER.TSS_PTR ; Load DS with the descriptor for the @P5A | ||
| 1162 | MOV DS,AX ; VM's TSS with read/write access @P5A | ||
| 1163 | MOV BX,0 ; VM's TSS with read/write access @P5A | ||
| 1164 | ; P5A | ||
| 1165 | ; Set up our stack for an IRET to the V86 task. This is an inter-level P5A | ||
| 1166 | ; IRET to a V86 task so we need the V86 task's SS, ESP, ES, DS, FS and GS P5A | ||
| 1167 | ; as well as his EFLAGS, EIP and CS. P5A | ||
| 1168 | ; P5A | ||
| 1169 | DATAOV ; @P5A | ||
| 1170 | PUSH WORD PTR [BX].ETSS_GS ; Put V86 task's GS on the stack @P5A | ||
| 1171 | DATAOV ; @P5A | ||
| 1172 | PUSH WORD PTR [BX].ETSS_FS ; Put V86 task's FS on the stack @P5A | ||
| 1173 | DATAOV ; @P5A | ||
| 1174 | PUSH WORD PTR [BX].ETSS_DS ; Put V86 task's DS on the stack @P5A | ||
| 1175 | DATAOV ; @P5A | ||
| 1176 | PUSH WORD PTR [BX].ETSS_ES ; Put V86 task's ES on the stack @P5A | ||
| 1177 | DATAOV ; @P5A | ||
| 1178 | PUSH WORD PTR [BX].ETSS_SS ; Put V86 task's SS on the stack @P5A | ||
| 1179 | DATAOV ; @P5A | ||
| 1180 | PUSH WORD PTR [BX].ETSS_SP ; Put V86 task's ESP on the stack @P5A | ||
| 1181 | DATAOV ; @P5A | ||
| 1182 | PUSH WORD PTR [BX].ETSS_FL ; Put V86 task's EFLAGS on the stack @P5A | ||
| 1183 | DATAOV ; @P5A | ||
| 1184 | PUSH WORD PTR [BX].ETSS_CS ; Put V86 task's CS on the stack @P5A | ||
| 1185 | DATAOV ; @P5A | ||
| 1186 | PUSH WORD PTR [BX].ETSS_IP ; Put V86 task's EIP on the stack @P5A | ||
| 1187 | DATAOV ; @P5A | ||
| 1188 | IRET ; @P5A | ||
| 1189 | ; @P5D | ||
| 1190 | |||
| 1191 | TEST_EXIT: ; We are now running in V86 mode | ||
| 1192 | POP AX ; Pop the stack until our DEAD delimiter is | ||
| 1193 | CMP AX,0DEADH ; found | ||
| 1194 | JNE TEST_EXIT | ||
| 1195 | |||
| 1196 | ; Replace the interrupt 15 vector with our handler (INT15F88). P7A | ||
| 1197 | |||
| 1198 | MOV AH,GET_VECT ; Get the current vector at interrupt 15H @P7A | ||
| 1199 | MOV AL,15H ; @P7A | ||
| 1200 | INT 21H ; @P7A | ||
| 1201 | |||
| 1202 | MOV CS:CHAINSEG,ES ; Save it in the chaining header in @P7A | ||
| 1203 | MOV CS:CHAINOFF,BX ; INT15F88 @P7A | ||
| 1204 | |||
| 1205 | MOV AH,SET_VECT ; Set the entry point of INT15F88 as the @P7A | ||
| 1206 | MOV AL,15H ; new interrupt 15 vector @P7A | ||
| 1207 | PUSH CS ; @P7A | ||
| 1208 | POP DS ; @P7A | ||
| 1209 | MOV DX,OFFSET INT15F88 ; @P7A | ||
| 1210 | INT 21H ; @P7A | ||
| 1211 | |||
| 1212 | ; Copy the number of K for extended memory from BUFF_SIZE to EXT_MEM. This P7A | ||
| 1213 | ; is needed because BUFF_SIZE does not stay resident, EXT_MEM does. P7A | ||
| 1214 | |||
| 1215 | MOV AX,BUFF_SIZE ; @P7A | ||
| 1216 | MOV EXT_MEM,AX ; @P7A | ||
| 1217 | |||
| 1218 | ; Issue the message that says we installed successfully | ||
| 1219 | |||
| 1220 | MOV AH,DISPSTRG ; Set AH to DOS display string function @D0A | ||
| 1221 | MOV DX,OFFSET GOODLOAD ; @D0A | ||
| 1222 | PUSH CS ; @D0A | ||
| 1223 | POP DS ; DS:DX points to the message @D0A | ||
| 1224 | INT 21H ; Display the message @D0A | ||
| 1225 | |||
| 1226 | RET ; Return to IRPT which called INIT_P1 | ||
| 1227 | |||
| 1228 | SUBTTL Gate A20 | ||
| 1229 | PAGE | ||
| 1230 | ;------------------------------------------------------------------------------; | ||
| 1231 | ; GATE_A20 ; | ||
| 1232 | ; This routine controls a signal which gates address bit 20. ; | ||
| 1233 | ; Bit 2 of port 92H controls the enabling of A20. If bit 2 is on, P4C; | ||
| 1234 | ; then A20 is enabled. Conversely, if bit 2 is off, A20 is disabled. P4C; | ||
| 1235 | ; ; | ||
| 1236 | ;------------------------------------------------------------------------------; | ||
| 1237 | |||
| 1238 | ; Equates for the Gate A20 enable | ||
| 1239 | |||
| 1240 | ENABLE_A20 EQU 02H ; Bit 2 of port 92H turns on A20 @P4C | ||
| 1241 | |||
| 1242 | GATE_A20 PROC | ||
| 1243 | |||
| 1244 | IN AL,92H ; Get the current value of port 92 @P4A | ||
| 1245 | OR AL,ENABLE_A20 ; Turn on the bit to enable A20 @P4A | ||
| 1246 | OUT 92H,AL ; Send it back out to port 92 @P4A | ||
| 1247 | RET | ||
| 1248 | ; 15@P4D | ||
| 1249 | GATE_A20 ENDP | ||
| 1250 | |||
| 1251 | SUBTTL GET_PARMS parameter line scan | ||
| 1252 | PAGE | ||
| 1253 | ;------------------------------------------------------------------------------; | ||
| 1254 | ; GET_PARMS ; | ||
| 1255 | ; This procedure converts the numeric parameter following the DEVICE statement ; | ||
| 1256 | ; in the CONFIG.SYS file to a binary number and saves it in BUFF_SIZE. The ; | ||
| 1257 | ; number is rounded up to the nearest 16K boundary. ; | ||
| 1258 | ; ; | ||
| 1259 | ; Register usage: ; | ||
| 1260 | ; DS:SI indexes parameter string ; | ||
| 1261 | ; AL contains character from parameter string ; | ||
| 1262 | ; CX value from GET_NUMBER ; | ||
| 1263 | ; ; | ||
| 1264 | ;------------------------------------------------------------------------------; | ||
| 1265 | |||
| 1266 | ASSUME DS:NOTHING ; DS:BX point to Request Header | ||
| 1267 | |||
| 1268 | GET_PARMS PROC | ||
| 1269 | |||
| 1270 | PUSH DS ; Save DS | ||
| 1271 | push bx ; save bx ;an000; dms; | ||
| 1272 | |||
| 1273 | LDS SI,RH.RH0_BPBA ; DS:SI point to all text after "DEVICE=" | ||
| 1274 | ; in CONFIG.SYS | ||
| 1275 | XOR AL,AL ; Start with a null character in AL. | ||
| 1276 | |||
| 1277 | ;------------------------------------------------------------------------------; | ||
| 1278 | ; Skip until first delimiter is found. There may be digits in the path string.; | ||
| 1279 | ; ; | ||
| 1280 | ; DS:SI points to \pathstring\386XMAEM.SYS nn nn nn ; | ||
| 1281 | ; The character following 386XMAEM.SYS may have been changed to a null (00H). ; | ||
| 1282 | ; All letters have been changed to uppercase. ; | ||
| 1283 | ;------------------------------------------------------------------------------; | ||
| 1284 | |||
| 1285 | GET_PARMS_A: | ||
| 1286 | CALL GET_PCHAR ; Get a character from the parameter string | ||
| 1287 | JZ Get_Parms_Null ; The zero flag is set if the end of the line | ||
| 1288 | ; is found. If so, then exit. | ||
| 1289 | |||
| 1290 | ; Check for various delimeters | ||
| 1291 | |||
| 1292 | OR AL,AL ; Null | ||
| 1293 | JZ GET_PARMS_B | ||
| 1294 | CMP AL,' ' ; Blank | ||
| 1295 | JE GET_PARMS_B | ||
| 1296 | CMP AL,',' ; Comma | ||
| 1297 | JE GET_PARMS_B | ||
| 1298 | CMP AL,';' ; Semi-colon | ||
| 1299 | JE GET_PARMS_B | ||
| 1300 | CMP AL,'+' ; Plus sign | ||
| 1301 | JE GET_PARMS_B | ||
| 1302 | CMP AL,'=' ; Equals | ||
| 1303 | JE GET_PARMS_B | ||
| 1304 | CMP AL,TAB ; Tab | ||
| 1305 | JNE GET_PARMS_A ; Skip until delimiter or CR is found | ||
| 1306 | |||
| 1307 | GET_PARMS_B: ; Now pointing to first delimiter | ||
| 1308 | CALL SKIP_TO_DIGIT ; Skip to first digit | ||
| 1309 | JZ Get_Parms_C ; Found EOL, no digits remain | ||
| 1310 | |||
| 1311 | CALL GET_NUMBER ; Extract the digits and convert to binary | ||
| 1312 | jmp Get_Parms_Found ; Parm found | ||
| 1313 | |||
| 1314 | Get_Parms_Null: | ||
| 1315 | |||
| 1316 | xor cx,cx ; set cx to 0 ;an000; dms; | ||
| 1317 | |||
| 1318 | Get_Parms_Found: | ||
| 1319 | |||
| 1320 | mov bx,cx ; put cx value in bx ;an000; dms; | ||
| 1321 | |||
| 1322 | cmp cx,0 ; 0 pages requested? ;an000; dms; | ||
| 1323 | jne Get_Parm_Max ; allocate maximum number ;an000; dms; | ||
| 1324 | MOV CS:BUFF_SIZE,0; Store buffer size | ||
| 1325 | jmp Get_Parms_C | ||
| 1326 | |||
| 1327 | Get_Parm_Max: | ||
| 1328 | |||
| 1329 | cmp bx,64 ; >= 64 pages requested? ;an000; dms; | ||
| 1330 | jnb Get_Parms_64_Pg ; yes - continue ;an000; dms; | ||
| 1331 | mov dx,offset Small_Parm ; Parm < 64 and > 0 ;an000; dms; | ||
| 1332 | mov ah,Dispstrg ; Display the welcome message. ;an000; dms; | ||
| 1333 | push ds ; Save DS ;an000; dms; | ||
| 1334 | push cs ; ;an000; dms; | ||
| 1335 | pop ds ; DS:DX points to the message ;an000; dms; | ||
| 1336 | int 21h ; Display the message ;an000; dms; | ||
| 1337 | pop ds ; Restore DS ;an000; dms; | ||
| 1338 | stc ; flag an error occurred ;an000; dms; | ||
| 1339 | jmp Get_Parms_C ; exit routine ;an000; dms; | ||
| 1340 | |||
| 1341 | Get_Parms_64_Pg: | ||
| 1342 | |||
| 1343 | mov ax,bx ; prepare to adjust to Kb value ;an000; dms; | ||
| 1344 | mov cx,10h ; 16Kb per page ;an000; dms; | ||
| 1345 | xor dx,dx ; clear high word ;an000; dms; | ||
| 1346 | mul cx ; get Kb value ;an000; dms; | ||
| 1347 | |||
| 1348 | mov bx,ax ; store page Kb value in bx ;an000; dms; | ||
| 1349 | add bx,128 ; adjust for emulator code | ||
| 1350 | |||
| 1351 | mov ah,88h ; get number of 1k blocks above 1Mb ;an000; dms; | ||
| 1352 | int 15h ; | ||
| 1353 | |||
| 1354 | sub ax,bx ; get number of blocks to allocate for extended ;an000; dms; | ||
| 1355 | jnc Get_Parms_Ext ; set extended memory value in buff size ;an000; dms; | ||
| 1356 | mov dx,offset No_Mem ; not enough memory for parm | ||
| 1357 | mov ah,Dispstrg ; Display the welcome message. ;an000; dms; | ||
| 1358 | push ds ; Save DS ;an000; dms; | ||
| 1359 | push cs ; ;an000; dms; | ||
| 1360 | pop ds ; DS:DX points to the message ;an000; dms; | ||
| 1361 | int 21h ; Display the message ;an000; dms; | ||
| 1362 | pop ds ; Restore DS ;an000; dms; | ||
| 1363 | stc ; flag an error ;an000; dms; | ||
| 1364 | jmp Get_Parms_C ; exit routine ;an000; dms; | ||
| 1365 | |||
| 1366 | Get_Parms_Ext: | ||
| 1367 | |||
| 1368 | MOV CS:BUFF_SIZE,ax ; Store buffer size | ||
| 1369 | clc | ||
| 1370 | |||
| 1371 | GET_PARMS_C: | ||
| 1372 | pop bx ; restore bx ;an000; dms; | ||
| 1373 | POP DS ; Restore DS | ||
| 1374 | |||
| 1375 | RET | ||
| 1376 | |||
| 1377 | ;------------------------------------------------------------------------------; | ||
| 1378 | ; GET_PCHAR -- Get a character from the parameter string into AL ; | ||
| 1379 | ;------------------------------------------------------------------------------; | ||
| 1380 | |||
| 1381 | GET_PCHAR PROC | ||
| 1382 | CMP AL,CR ; Carriage return already encountered? | ||
| 1383 | JE GET_PCHAR_X ; Don't read past end of line | ||
| 1384 | LODSB ; Get character from DS:SI, increment SI | ||
| 1385 | CMP AL,CR ; Is the character a carriage return? | ||
| 1386 | JE GET_PCHAR_X ; Yes, leave the zero flag set to signal end | ||
| 1387 | ; of line | ||
| 1388 | CMP AL,LF ; No, is it a line feed? This will leave the | ||
| 1389 | ; zero flag set if a line feed was found. | ||
| 1390 | GET_PCHAR_X: | ||
| 1391 | RET | ||
| 1392 | |||
| 1393 | GET_PCHAR ENDP | ||
| 1394 | |||
| 1395 | ;------------------------------------------------------------------------------; | ||
| 1396 | ; CHECK_NUM -- Check if the character in AL is a numeric digit, ASCII for ; | ||
| 1397 | ; 0 - 9. The zero flag is set if the character is a digit, ; | ||
| 1398 | ; otherwise it is reset. ; | ||
| 1399 | ;------------------------------------------------------------------------------; | ||
| 1400 | |||
| 1401 | CHECK_NUM PROC | ||
| 1402 | CMP AL,'0' ; If character is less than a "0" then it is not | ||
| 1403 | JB CHECK_NUM_X ; a number, so exit | ||
| 1404 | |||
| 1405 | CMP AL,'9' ; If character is greater than a "9" then it is | ||
| 1406 | JA CHECK_NUM_X ; not a number, so exit | ||
| 1407 | |||
| 1408 | CMP AL,AL ; Set the zero flag to show it is a number | ||
| 1409 | CHECK_NUM_X: | ||
| 1410 | RET ; Zero flag is left reset if character is not | ||
| 1411 | CHECK_NUM ENDP ; a number | ||
| 1412 | |||
| 1413 | ;------------------------------------------------------------------------------; | ||
| 1414 | ; SKIP_TO_DIGIT -- Scan the parameter string until a numeric character is ; | ||
| 1415 | ; found or the end of the line is encountered. If a numeric ; | ||
| 1416 | ; character is not found then the zero flag is set. Else if ; | ||
| 1417 | ; a character was found then the zero flag is reset. ; | ||
| 1418 | ;------------------------------------------------------------------------------; | ||
| 1419 | |||
| 1420 | SKIP_TO_DIGIT PROC | ||
| 1421 | CALL CHECK_NUM ; Is the current character a digit? | ||
| 1422 | JZ SKIP_TO_DIGIT_X ; If zero flag is set then it is a number | ||
| 1423 | |||
| 1424 | CALL GET_PCHAR ; Get the next character from the line | ||
| 1425 | JNZ SKIP_TO_DIGIT ; Loop until first digit or CR or LF is found | ||
| 1426 | RET ; Fall through to here if digit not found | ||
| 1427 | |||
| 1428 | SKIP_TO_DIGIT_X: | ||
| 1429 | CMP AL,0 ; Digit found, reset the zero flag to show digit | ||
| 1430 | RET ; was found | ||
| 1431 | SKIP_TO_DIGIT ENDP | ||
| 1432 | |||
| 1433 | ;------------------------------------------------------------------------------; | ||
| 1434 | ; GET_NUMBER -- Convert the character digits in the parameter string to a ; | ||
| 1435 | ; binary value. The value is returned in CX, unless the ; | ||
| 1436 | ; calculation overflows, in which case return a 0. The next ; | ||
| 1437 | ; character after the digits is left in AL. ; | ||
| 1438 | ;------------------------------------------------------------------------------; | ||
| 1439 | |||
| 1440 | C10 DW 10 | ||
| 1441 | GN_ERR DB ? ; Zero if no overflow in accumulation | ||
| 1442 | |||
| 1443 | GET_NUMBER PROC ; Convert string of digits to binary value | ||
| 1444 | XOR CX,CX ; Clear CX, the resulting number | ||
| 1445 | MOV CS:GN_ERR,CL ; No overflow yet | ||
| 1446 | |||
| 1447 | GET_NUMBER_A: | ||
| 1448 | SUB AL,'0' ; Convert the ASCII character in AL to binary | ||
| 1449 | CBW ; Clear AH | ||
| 1450 | XCHG AX,CX ; Previous accumulation in AX, new digit in CL | ||
| 1451 | MUL CS:C10 ; DX:AX = AX*10 | ||
| 1452 | OR CS:GN_ERR,DL ; Any overflow from AX goes into DX. Any non- | ||
| 1453 | ; zero value in DL will signal an error | ||
| 1454 | ADD AX,CX ; Add the new digit to ten times the previous | ||
| 1455 | ; digits | ||
| 1456 | XCHG AX,CX ; New number now in CX | ||
| 1457 | CALL GET_PCHAR ; Get the next character | ||
| 1458 | CALL CHECK_NUM ; Check if it is numeric | ||
| 1459 | JZ GET_NUMBER_A ; If so, then go back and add this digit to the | ||
| 1460 | ; result | ||
| 1461 | CMP CS:GN_ERR,0 ; Did we overflow? | ||
| 1462 | JE GET_NUMBER_B ; If not, we're done | ||
| 1463 | XOR CX,CX ; Return a zero result if overflow | ||
| 1464 | GET_NUMBER_B: | ||
| 1465 | RET | ||
| 1466 | GET_NUMBER ENDP | ||
| 1467 | |||
| 1468 | GET_PARMS ENDP | ||
| 1469 | |||
| 1470 | POST ENDP | ||
| 1471 | |||
| 1472 | PROG ENDS | ||
| 1473 | END | ||
| 1474 | |||
diff --git a/v4.0/src/DEV/XMAEM/INDEINS.MAC b/v4.0/src/DEV/XMAEM/INDEINS.MAC new file mode 100644 index 0000000..c4b13e5 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEINS.MAC | |||
| @@ -0,0 +1,923 @@ | |||
| 1 | COMMENT # | ||
| 2 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 3 | * * | ||
| 4 | * MODULE NAME : INDEINS * | ||
| 5 | * * | ||
| 6 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. * | ||
| 7 | * * | ||
| 8 | * DESCRIPTIVE NAME: Instructions for the 80386 * | ||
| 9 | * * | ||
| 10 | * STATUS (LEVEL) : Version (0) Level (1.0) * | ||
| 11 | * * | ||
| 12 | * FUNCTION : These macros define instructions that are recognized by * | ||
| 13 | * the 80386 but that are not recognized by MASM 3.0. We * | ||
| 14 | * have to create these instructions ourselves because the * | ||
| 15 | * Macro Assembler won't. * | ||
| 16 | * * | ||
| 17 | * MODULE TYPE : MAC * | ||
| 18 | * * | ||
| 19 | * REGISTER USAGE : 80286 Standard * | ||
| 20 | * * | ||
| 21 | * CHANGE ACTIVITY : * | ||
| 22 | * * | ||
| 23 | * $MAC(INDEINS) COMP(LOAD) PROD(3270PC) : * | ||
| 24 | * * | ||
| 25 | * $D0=D0004700 410 870604 D : NEW FOR RELEASE 1.1 * | ||
| 26 | * $P1=P0000311 410 870804 D : RENAME MODULE'S LIBRARY FILE TYPE TO "MAC" * | ||
| 27 | * * | ||
| 28 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 29 | # | ||
| 30 | |||
| 31 | ; Some information about creating instructions | ||
| 32 | |||
| 33 | ; MODIFIER BYTE VALUES | ||
| 34 | |||
| 35 | ; MOD REG/OPX R/M | ||
| 36 | ; --- ------- --- | ||
| 37 | ; 11 111 111 | ||
| 38 | |||
| 39 | ; EAX AX AL 000 DISP0 00 | ||
| 40 | ; ECX CX CL 001 DISPB 01 | ||
| 41 | ; EDX DX DL 010 DISPW 10 | ||
| 42 | ; EBX BX BL 011 DISPR 11 | ||
| 43 | ; ESP SP AH 100 | ||
| 44 | ; EBP BP CH 101 | ||
| 45 | ; ESI SI DH 110 | ||
| 46 | ; EDI DI BH 111 | ||
| 47 | |||
| 48 | ; ES:0 | ||
| 49 | ; CS:1 | ||
| 50 | ; SS:2 | ||
| 51 | ; DS:3 | ||
| 52 | ; FS:4 | ||
| 53 | ; GS:5 | ||
| 54 | |||
| 55 | |||
| 56 | ; OPX FIELD VALUES | ||
| 57 | |||
| 58 | ; 00F-000 OPCODE VALUES 00F-001 OPCODE VALUES | ||
| 59 | ; --------------------- --------------------- | ||
| 60 | |||
| 61 | ; SLDT 000 SGDT 000 | ||
| 62 | ; STR 001 SIDT 001 | ||
| 63 | ; LLDT 010 LIDT 010 | ||
| 64 | ; LTR 011 LGDT 011 | ||
| 65 | ; VERR 100 SMSW 100 | ||
| 66 | ; VERW 101 ? 101 | ||
| 67 | ; ? 110 LMSW 110 | ||
| 68 | ; ? 111 ? 111 | ||
| 69 | |||
| 70 | |||
| 71 | PAGE | ||
| 72 | |||
| 73 | ; Macros to move to and from the 80386 system registers and to and from the | ||
| 74 | ; new segment registers FS and GS. | ||
| 75 | |||
| 76 | |||
| 77 | ; CMOV - Move to and From Control Registers | ||
| 78 | ; | ||
| 79 | ; Examples: | ||
| 80 | ; | ||
| 81 | ; CMOV CRx,EREG | ||
| 82 | ; CMOV EREG,CRx | ||
| 83 | ; | ||
| 84 | |||
| 85 | CMOV MACRO REG1,REG2 | ||
| 86 | |||
| 87 | _CREGFD = 0 | ||
| 88 | _CRCNT = 0 | ||
| 89 | IRP TREG,<CR3,CR2,CR1,CR0> | ||
| 90 | IFIDN <®1>,<&TREG> | ||
| 91 | _CREGFD = 1 | ||
| 92 | _CRCNT = 0 | ||
| 93 | ELSE | ||
| 94 | _CRCNT = _CRCNT + 1 | ||
| 95 | ENDIF | ||
| 96 | ENDM | ||
| 97 | IFE _CREGFD-1 | ||
| 98 | F_DREG <®2> | ||
| 99 | IF _DREGNUM LT 8 | ||
| 100 | DB 0FH | ||
| 101 | DB 22H | ||
| 102 | DB 0C0H + _CRCNT*8 + _DREGNUM | ||
| 103 | ELSE | ||
| 104 | SYNTAX ERROR - EXTENDED REGISTER EXPECTED | ||
| 105 | ENDIF | ||
| 106 | ELSE | ||
| 107 | _CREGFD = 0 | ||
| 108 | _CRCNT = 0 | ||
| 109 | IRP TREG,<CR3,CR2,CR1,CR0> | ||
| 110 | IFIDN <®2>,<&TREG> | ||
| 111 | _CREGFD = 1 | ||
| 112 | _CRCNT = 0 | ||
| 113 | ELSE | ||
| 114 | _CRCNT = _CRCNT + 1 | ||
| 115 | ENDIF | ||
| 116 | ENDM | ||
| 117 | IFE _CREGFD-1 | ||
| 118 | F_DREG <®1> | ||
| 119 | IF _DREGNUM LT 8 | ||
| 120 | DB 0FH | ||
| 121 | DB 20H | ||
| 122 | DB 0C0H + _CRCNT*8 + _DREGNUM | ||
| 123 | ELSE | ||
| 124 | SYNTAX ERROR - EXTENDED REGISTER EXPECTED | ||
| 125 | ENDIF | ||
| 126 | ELSE | ||
| 127 | SYNTAX ERROR - CONTROL REGISTER EXPECTED | ||
| 128 | ENDIF | ||
| 129 | ENDIF | ||
| 130 | ENDM | ||
| 131 | |||
| 132 | |||
| 133 | ; DMOV - Move to and From Debug Registers | ||
| 134 | ; | ||
| 135 | ; Examples: | ||
| 136 | ; | ||
| 137 | ; DMOV DRx,EREG | ||
| 138 | ; DMOV EREG,DRx | ||
| 139 | ; | ||
| 140 | |||
| 141 | DMOV MACRO REG1,REG2 | ||
| 142 | |||
| 143 | _DREGFD = 0 | ||
| 144 | _DRCNT = 0 | ||
| 145 | IRP TREG,<DR7,DR6,DRX,DRX,DR3,DR2,DR1,DR0> | ||
| 146 | IFIDN <®1>,<&TREG> | ||
| 147 | _DREGFD = 1 | ||
| 148 | _DRCNT = 0 | ||
| 149 | ELSE | ||
| 150 | _DRCNT = _DRCNT + 1 | ||
| 151 | ENDIF | ||
| 152 | ENDM | ||
| 153 | IFE _DREGFD-1 | ||
| 154 | F_DREG <®2> | ||
| 155 | IF _DREGNUM LT 8 | ||
| 156 | DB 0FH | ||
| 157 | DB 23H | ||
| 158 | DB 0C0H + _DRCNT*8 + _DREGNUM | ||
| 159 | ELSE | ||
| 160 | SYNTAX ERROR - EXTENDED REGISTER EXPECTED | ||
| 161 | ENDIF | ||
| 162 | ELSE | ||
| 163 | _DREGFD = 0 | ||
| 164 | _DRCNT = 0 | ||
| 165 | IRP TREG,<DR7,DR6,DRX,DRX,DR3,DR2,DR1,DR0> | ||
| 166 | IFIDN <®2>,<&TREG> | ||
| 167 | _DREGFD = 1 | ||
| 168 | _DRCNT = 0 | ||
| 169 | ELSE | ||
| 170 | _DRCNT = _DRCNT + 1 | ||
| 171 | ENDIF | ||
| 172 | ENDM | ||
| 173 | IFE _DREGFD-1 | ||
| 174 | F_DREG <®1> | ||
| 175 | IF _DREGNUM LT 8 | ||
| 176 | DB 0FH | ||
| 177 | DB 21H | ||
| 178 | DB 0C0H + _DRCNT*8 + _DREGNUM | ||
| 179 | ELSE | ||
| 180 | SYNTAX ERROR - EXTENDED REGISTER EXPECTED | ||
| 181 | ENDIF | ||
| 182 | ELSE | ||
| 183 | SYNTAX ERROR - DEBUG REGISTER EXPECTED | ||
| 184 | ENDIF | ||
| 185 | ENDIF | ||
| 186 | ENDM | ||
| 187 | |||
| 188 | ; TMOV - Move to and From Test Registers | ||
| 189 | ; | ||
| 190 | ; Examples: | ||
| 191 | ; | ||
| 192 | ; TMOV TRx,EREG | ||
| 193 | ; TMOV EREG,TRx | ||
| 194 | ; | ||
| 195 | |||
| 196 | TMOV MACRO REG1,REG2 | ||
| 197 | |||
| 198 | _TREGFD = 0 | ||
| 199 | _TRCNT = 0 | ||
| 200 | IRP TREG,<TR7,TR6> | ||
| 201 | IFIDN <®1>,<&TREG> | ||
| 202 | _TREGFD = 1 | ||
| 203 | _TRCNT = 0 | ||
| 204 | ELSE | ||
| 205 | _TRCNT = _TRCNT + 1 | ||
| 206 | ENDIF | ||
| 207 | ENDM | ||
| 208 | _TRCNT = _TRCNT + 6 | ||
| 209 | IFE _TREGFD-1 | ||
| 210 | F_DREG <®2> | ||
| 211 | IF _DREGNUM LT 8 | ||
| 212 | DB 0FH | ||
| 213 | DB 26H | ||
| 214 | DB 0C0H + _TRCNT*8 + _DREGNUM | ||
| 215 | ELSE | ||
| 216 | SYNTAX ERROR - EXTENDED REGISTER EXPECTED | ||
| 217 | ENDIF | ||
| 218 | ELSE | ||
| 219 | _TREGFD = 0 | ||
| 220 | _TRCNT = 0 | ||
| 221 | IRP TREG,<TR7,TR6> | ||
| 222 | IFIDN <®2>,<&TREG> | ||
| 223 | _TREGFD = 1 | ||
| 224 | _TRCNT = 0 | ||
| 225 | ELSE | ||
| 226 | _TRCNT = _TRCNT + 1 | ||
| 227 | ENDIF | ||
| 228 | ENDM | ||
| 229 | _TRCNT = _TRCNT + 6 | ||
| 230 | IFE _TREGFD-1 | ||
| 231 | F_DREG <®1> | ||
| 232 | IF _DREGNUM LT 8 | ||
| 233 | DB 0FH | ||
| 234 | DB 24H | ||
| 235 | DB 0C0H + _TRCNT*8 + _DREGNUM | ||
| 236 | ELSE | ||
| 237 | SYNTAX ERROR - EXTENDED REGISTER EXPECTED | ||
| 238 | ENDIF | ||
| 239 | ELSE | ||
| 240 | SYNTAX ERROR - TEST REGISTER EXPECTED | ||
| 241 | ENDIF | ||
| 242 | ENDIF | ||
| 243 | ENDM | ||
| 244 | |||
| 245 | ; SMOV - Move to/from FS/GS segment registers from/to general registers | ||
| 246 | ; | ||
| 247 | ; Examples: | ||
| 248 | ; | ||
| 249 | ; SMOV SReg, REG16 | ||
| 250 | ; SMOV REG16, SReg | ||
| 251 | ; | ||
| 252 | |||
| 253 | SMOV MACRO REG1,REG2 | ||
| 254 | _SREGNUM = 8 | ||
| 255 | _SREG1 = 1 | ||
| 256 | IFIDN <®1>,<FS> | ||
| 257 | _SREGNUM = 4 | ||
| 258 | ELSE | ||
| 259 | IFIDN <®1>,<FS> | ||
| 260 | _SREGNUM = 4 | ||
| 261 | ENDIF | ||
| 262 | ENDIF | ||
| 263 | IF _SREGNUM GT 7 | ||
| 264 | IFIDN <®1>,<GS> | ||
| 265 | _SREGNUM = 5 | ||
| 266 | ELSE | ||
| 267 | IFIDN <®1>,<GS> | ||
| 268 | _SREGNUM = 5 | ||
| 269 | ENDIF | ||
| 270 | ENDIF | ||
| 271 | ENDIF | ||
| 272 | IF _SREGNUM GT 7 | ||
| 273 | _SREG1 = 0 | ||
| 274 | IFIDN <®2>,<FS> | ||
| 275 | _SREGNUM = 4 | ||
| 276 | ELSE | ||
| 277 | IFIDN <®2>,<FS> | ||
| 278 | _SREGNUM = 4 | ||
| 279 | ENDIF | ||
| 280 | ENDIF | ||
| 281 | IF _SREGNUM GT 7 | ||
| 282 | IFIDN <®2>,<GS> | ||
| 283 | _SREGNUM = 5 | ||
| 284 | ELSE | ||
| 285 | IFIDN <®2>,<GS> | ||
| 286 | _SREGNUM = 5 | ||
| 287 | ENDIF | ||
| 288 | ENDIF | ||
| 289 | ENDIF | ||
| 290 | ENDIF | ||
| 291 | IF _SREGNUM GT 7 | ||
| 292 | SYNTAX ERROR - FS OR GS SEGMENT REGISTER EXPECTED | ||
| 293 | ELSE | ||
| 294 | IF _SREG1 EQ 1 | ||
| 295 | DB 8EH | ||
| 296 | F_WREG <®2> | ||
| 297 | ELSE | ||
| 298 | DB 8CH | ||
| 299 | F_WREG <®1> | ||
| 300 | ENDIF | ||
| 301 | IF _WREGNUM GT 7 | ||
| 302 | SYNTAX ERROR - WORD REGISTER EXPECTED | ||
| 303 | ELSE | ||
| 304 | DB 0C0H + _SREGNUM*8 + _WREGNUM | ||
| 305 | ENDIF | ||
| 306 | ENDIF | ||
| 307 | ENDM | ||
| 308 | |||
| 309 | F_MOD MACRO TYPE,DISP1,DISP2 | ||
| 310 | _DISP = 2 | ||
| 311 | ;; 1 0 | ||
| 312 | IRP _TEST_,<DISP32, DISP8> | ||
| 313 | IFIDN <&TYPE>,<&_TEST_> | ||
| 314 | _DISP = 0 | ||
| 315 | ELSE | ||
| 316 | _DISP = _DISP + 1 | ||
| 317 | ENDIF | ||
| 318 | ENDM | ||
| 319 | IFE (_DISP LT 2) | ||
| 320 | ;; 1 0 | ||
| 321 | IRP _TEST_,<DISP32, DISP8> | ||
| 322 | IFIDN <&TYPE>,<&_TEST_> | ||
| 323 | _DISP = 0 | ||
| 324 | ELSE | ||
| 325 | _DISP = _DISP + 1 | ||
| 326 | ENDIF | ||
| 327 | ENDM | ||
| 328 | ENDIF | ||
| 329 | IF _DISP LT 2 | ||
| 330 | IFB <&DISP1> | ||
| 331 | SYNTAX ERROR - IMMEDIATE OPERAND EXPECTED | ||
| 332 | ELSE | ||
| 333 | IFE _DISP-1 | ||
| 334 | _MOD = 2 | ||
| 335 | ELSE | ||
| 336 | _MOD = 1 | ||
| 337 | ENDIF | ||
| 338 | ENDIF | ||
| 339 | ELSE | ||
| 340 | _MOD = 0 | ||
| 341 | ENDIF | ||
| 342 | ENDM | ||
| 343 | |||
| 344 | MK_DISP MACRO P3,P4 | ||
| 345 | IFE _DISP | ||
| 346 | DB &P3 | ||
| 347 | ELSE | ||
| 348 | DW &P3 | ||
| 349 | IFNB <&P4> | ||
| 350 | IFDIF <&P4>,<IMMD> | ||
| 351 | DW &P4 | ||
| 352 | ENDIF | ||
| 353 | ELSE | ||
| 354 | DW 0H | ||
| 355 | ENDIF | ||
| 356 | ENDIF | ||
| 357 | ENDM | ||
| 358 | |||
| 359 | MK_IMMD MACRO P2,P3,P4,P5 | ||
| 360 | _IMMDCNT = 3 | ||
| 361 | IRP _PARM,<&P2,&P3,&P4,&P5> | ||
| 362 | IFE _IMMDCNT | ||
| 363 | IF _SIZE EQ 1 | ||
| 364 | DB &_PARM | ||
| 365 | ELSE | ||
| 366 | DW &_PARM | ||
| 367 | ENDIF | ||
| 368 | ELSE | ||
| 369 | IFE _IMMDCNT-1 | ||
| 370 | IF _SIZE EQ 4 | ||
| 371 | IFNB <&_PARM> | ||
| 372 | DW &_PARM | ||
| 373 | ELSE | ||
| 374 | DW 0H | ||
| 375 | ENDIF | ||
| 376 | ENDIF | ||
| 377 | ENDIF | ||
| 378 | ENDIF | ||
| 379 | _IMMDCNT = _IMMDCNT + 1 | ||
| 380 | IFIDN <&_PARM>,<IMMD> | ||
| 381 | _IMMDCNT = 0 | ||
| 382 | ENDIF | ||
| 383 | ENDM | ||
| 384 | ENDM | ||
| 385 | |||
| 386 | F_BREG MACRO TBREG | ||
| 387 | _BREGNUM = 0 | ||
| 388 | IRP TREG,<BH,DH,CH,AH,BL,DL,CL,AL> | ||
| 389 | IFIDN <&TBREG>,<&TREG> | ||
| 390 | _BREGNUM = 0 | ||
| 391 | ELSE | ||
| 392 | _BREGNUM = _BREGNUM + 1 | ||
| 393 | ENDIF | ||
| 394 | ENDM | ||
| 395 | IFE (_BREGNUM LT 8) | ||
| 396 | IRP TREG,<BH,DH,CH,AH,BL,DL,CL,AL> | ||
| 397 | IFIDN <&TDREG>,<&TREG> | ||
| 398 | _BREGNUM = 0 | ||
| 399 | ELSE | ||
| 400 | _BREGNUM = _BREGNUM + 1 | ||
| 401 | ENDIF | ||
| 402 | ENDM | ||
| 403 | ENDIF | ||
| 404 | ENDM | ||
| 405 | |||
| 406 | F_WREG MACRO TWREG | ||
| 407 | _WREGNUM = 0 | ||
| 408 | IRP TREG,<DI,SI,BP,SP,BX,DX,CX,AX> | ||
| 409 | IFIDN <&TWREG>,<&TREG> | ||
| 410 | _WREGNUM = 0 | ||
| 411 | ELSE | ||
| 412 | _WREGNUM = _WREGNUM + 1 | ||
| 413 | ENDIF | ||
| 414 | ENDM | ||
| 415 | IFE (_WREGNUM LT 8) | ||
| 416 | IRP TREG,<DI,SI,BP,SP,BX,DX,CX,AX> | ||
| 417 | IFIDN <&TWREG>,<&TREG> | ||
| 418 | _WREGNUM = 0 | ||
| 419 | ELSE | ||
| 420 | _WREGNUM = _WREGNUM + 1 | ||
| 421 | ENDIF | ||
| 422 | ENDM | ||
| 423 | ENDIF | ||
| 424 | ENDM | ||
| 425 | |||
| 426 | F_DREG MACRO TDREG | ||
| 427 | _DREGNUM = 0 | ||
| 428 | IRP TREG,<EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX> | ||
| 429 | IFIDN <&TDREG>,<&TREG> | ||
| 430 | _DREGNUM = 0 | ||
| 431 | ELSE | ||
| 432 | _DREGNUM = _DREGNUM + 1 | ||
| 433 | ENDIF | ||
| 434 | ENDM | ||
| 435 | IFE (_DREGNUM LT 8) | ||
| 436 | IRP TREG,<EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX> | ||
| 437 | IFIDN <&TDREG>,<&TREG> | ||
| 438 | _DREGNUM = 0 | ||
| 439 | ELSE | ||
| 440 | _DREGNUM = _DREGNUM + 1 | ||
| 441 | ENDIF | ||
| 442 | ENDM | ||
| 443 | ENDIF | ||
| 444 | ENDM | ||
| 445 | |||
| 446 | F_BASE MACRO TBASE | ||
| 447 | _BASE = 0 | ||
| 448 | ;; 7 6 5 4 3 2 1 0 | ||
| 449 | IRP TREG,<[EDI],[ESI],[EBP],[ESP],[EBX],[EDX],[ECX],[EAX]> | ||
| 450 | IFIDN <&TBASE>,<&TREG> | ||
| 451 | _BASE = 0 | ||
| 452 | ELSE | ||
| 453 | _BASE = _BASE + 1 | ||
| 454 | ENDIF | ||
| 455 | ENDM | ||
| 456 | IFE (_BASE LT 8) | ||
| 457 | ;; 7 6 5 4 3 2 1 0 | ||
| 458 | IRP TREG,<[EDI],[ESI],[EBP],[ESP],[EBX],[EDX],[ECX],[EAX]> | ||
| 459 | IFIDN <&TBASE>,<&TREG> | ||
| 460 | _BASE = 0 | ||
| 461 | ELSE | ||
| 462 | _BASE = _BASE + 1 | ||
| 463 | ENDIF | ||
| 464 | ENDM | ||
| 465 | ENDIF | ||
| 466 | ENDM | ||
| 467 | |||
| 468 | F_INDEX MACRO INDX | ||
| 469 | _INDEX = 0 | ||
| 470 | ;; 7 6 5 4 3 2 1 0 | ||
| 471 | IRP TREG,<[EDI,[ESI,[EBP,_XX_,[EBX,[EDX,[ECX,[EAX> | ||
| 472 | IFIDN <&INDX>,<&TREG> | ||
| 473 | _INDEX = 0 | ||
| 474 | ELSE | ||
| 475 | _INDEX = _INDEX + 1 | ||
| 476 | ENDIF | ||
| 477 | ENDM | ||
| 478 | IFE (_INDEX LT 8) | ||
| 479 | ;; 7 6 5 4 3 2 1 0 | ||
| 480 | IRP TREG,<[EDI,[ESI,[EBP,_XX_,[EBX,[EDX,[ECX,[EAX> | ||
| 481 | IFIDN <&INDX>,<&TREG> | ||
| 482 | _INDEX = 0 | ||
| 483 | ELSE | ||
| 484 | _INDEX = _INDEX + 1 | ||
| 485 | ENDIF | ||
| 486 | ENDM | ||
| 487 | ENDIF | ||
| 488 | ENDM | ||
| 489 | |||
| 490 | F_SCALE MACRO TSCALE | ||
| 491 | _SCALE = 0 | ||
| 492 | ;; 3 2 1 0 | ||
| 493 | IRP TREG,<*8], *4], *2], *1]> | ||
| 494 | IFIDN <&TSCALE>,<&TREG> | ||
| 495 | _SCALE = 0 | ||
| 496 | ELSE | ||
| 497 | _SCALE = _SCALE + 1 | ||
| 498 | ENDIF | ||
| 499 | ENDM | ||
| 500 | ENDM | ||
| 501 | |||
| 502 | PAGE | ||
| 503 | |||
| 504 | ; Macros to PUSH and POP the new segment registers FS and GS | ||
| 505 | |||
| 506 | |||
| 507 | ; PUSH_FS - PUSH FS segment register | ||
| 508 | |||
| 509 | PUSH_FS MACRO | ||
| 510 | DB 00FH | ||
| 511 | DB 0A0H | ||
| 512 | ENDM | ||
| 513 | |||
| 514 | |||
| 515 | ; PUSH_GS - PUSH GS segment register | ||
| 516 | |||
| 517 | PUSH_GS MACRO | ||
| 518 | DB 00FH | ||
| 519 | DB 0A8H | ||
| 520 | ENDM | ||
| 521 | |||
| 522 | |||
| 523 | ; POP_FS - POP FS segment register | ||
| 524 | |||
| 525 | POP_FS MACRO | ||
| 526 | DB 00FH | ||
| 527 | DB 0A1H | ||
| 528 | ENDM | ||
| 529 | |||
| 530 | |||
| 531 | ; POP_GS - POP GS segment register | ||
| 532 | |||
| 533 | POP_GS MACRO | ||
| 534 | DB 00FH | ||
| 535 | DB 0A9H | ||
| 536 | ENDM | ||
| 537 | |||
| 538 | PAGE | ||
| 539 | |||
| 540 | ; Macros for multiplication instructions | ||
| 541 | |||
| 542 | ; RIMUL - Uncharacterized Signed Multiply (16-bit) | ||
| 543 | ; Syntax: RIMUL REG,REG/MEM | ||
| 544 | |||
| 545 | RIMUL MACRO REG,OPND | ||
| 546 | LOCAL L1,L2 | ||
| 547 | _2BYTEOP = 1 | ||
| 548 | DB 0FH | ||
| 549 | .XLIST | ||
| 550 | L1 LABEL BYTE | ||
| 551 | .LIST | ||
| 552 | CMP ®,&OPND | ||
| 553 | .XLIST | ||
| 554 | L2 LABEL BYTE | ||
| 555 | ORG OFFSET CS:L1 | ||
| 556 | .LIST | ||
| 557 | DB 0AFH | ||
| 558 | .XLIST | ||
| 559 | ORG OFFSET CS:L2 | ||
| 560 | .LIST | ||
| 561 | ENDM | ||
| 562 | |||
| 563 | ; ERIMUL - 32 bit Uncharacterized Signed Multiply | ||
| 564 | ; Systax: ERIMUL REG,REG/MEM | ||
| 565 | |||
| 566 | ERIMUL MACRO REG,OPND | ||
| 567 | DB 66H | ||
| 568 | RIMUL ®,<&OPND> | ||
| 569 | ENDM | ||
| 570 | |||
| 571 | PAGE | ||
| 572 | |||
| 573 | ; Macros to load pointers with the segment in FS, GS or SS. That is, these are | ||
| 574 | ; just like the instructions LDS and LES but for the FS, GS and SS registers. | ||
| 575 | |||
| 576 | NEWLS MACRO OP,REG,OPND | ||
| 577 | LOCAL L1,L2 | ||
| 578 | DB 0FH | ||
| 579 | .XLIST | ||
| 580 | L1 LABEL BYTE | ||
| 581 | .LIST | ||
| 582 | LDS ®,DWORD PTR &OPND | ||
| 583 | .XLIST | ||
| 584 | L2 LABEL BYTE | ||
| 585 | ORG OFFSET CS:L1 | ||
| 586 | .LIST | ||
| 587 | DB &OP | ||
| 588 | .XLIST | ||
| 589 | ORG OFFSET CS:L2 | ||
| 590 | .LIST | ||
| 591 | ENDM | ||
| 592 | |||
| 593 | ; LFS REG,OPND | ||
| 594 | |||
| 595 | LFS MACRO REG,OPND | ||
| 596 | NEWLS 0B4H,®,<&OPND> | ||
| 597 | ENDM | ||
| 598 | |||
| 599 | ; LGS REG,OPND | ||
| 600 | |||
| 601 | LGS MACRO REG,OPND | ||
| 602 | NEWLS 0B5H,®,<&OPND> | ||
| 603 | ENDM | ||
| 604 | |||
| 605 | ; LSS REG,OPND | ||
| 606 | |||
| 607 | LSS MACRO REG,OPND | ||
| 608 | NEWLS 0B2H,®,<&OPND> | ||
| 609 | ENDM | ||
| 610 | |||
| 611 | ; Now we do 32 bit versions of the above | ||
| 612 | |||
| 613 | ; ELFS REG,OPND | ||
| 614 | |||
| 615 | ELFS MACRO REG,OPND | ||
| 616 | DB 66H | ||
| 617 | NEWLS 0B4H,®,<&OPND> | ||
| 618 | ENDM | ||
| 619 | |||
| 620 | ; ELGS REG,OPND | ||
| 621 | |||
| 622 | ELGS MACRO REG,OPND | ||
| 623 | DB 66H | ||
| 624 | NEWLS 0B5H,®,<&OPND> | ||
| 625 | ENDM | ||
| 626 | |||
| 627 | ; ELSS REG,OPND | ||
| 628 | |||
| 629 | ELSS MACRO REG,OPND | ||
| 630 | DB 66H | ||
| 631 | NEWLS 0B2H,®,<&OPND> | ||
| 632 | ENDM | ||
| 633 | |||
| 634 | PAGE | ||
| 635 | |||
| 636 | ; Macros for some shift instructions | ||
| 637 | |||
| 638 | ; Shift Left Double R/M, Reg [CL = COUNT] [16-bit Operand] | ||
| 639 | ; SHLD OPND,REG (Double left shift) [CL = COUNT] | ||
| 640 | |||
| 641 | SHLD MACRO OPND,REG | ||
| 642 | SHDOP 0A5H,<&OPND>,® | ||
| 643 | ENDM | ||
| 644 | |||
| 645 | |||
| 646 | ; Shift Right Double R/M, Reg [CL = COUNT] [16-bit Operand] | ||
| 647 | ; SHRD OPND,REG (Double right shift) [CL = COUNT] | ||
| 648 | |||
| 649 | SHRD MACRO OPND,REG | ||
| 650 | SHDOP 0ADH,<&OPND>,® | ||
| 651 | ENDM | ||
| 652 | |||
| 653 | |||
| 654 | ; Shift Left Double R/M, Reg, Immd (8-bit) [16-bit Operand] | ||
| 655 | ; SHLDI OPND,REG,IMMD-8 | ||
| 656 | |||
| 657 | SHLDI MACRO OPND,REG,IMMD | ||
| 658 | SHDOP 0A4H,<&OPND>,® | ||
| 659 | DB &IMMD | ||
| 660 | ENDM | ||
| 661 | |||
| 662 | |||
| 663 | ; Shift Right Double R/M, Reg, Immd (8-bit) [16-bit Operand] | ||
| 664 | ; SHRDI OPND,REG,IMMD-8 | ||
| 665 | |||
| 666 | SHRDI MACRO OPND,REG,IMMD | ||
| 667 | SHDOP 0ACH,<&OPND>,® | ||
| 668 | DB &IMMD | ||
| 669 | ENDM | ||
| 670 | |||
| 671 | ; Now 32 bit versions of the above | ||
| 672 | |||
| 673 | ; Shift Left Double R/M, Reg [CL = COUNT] [32-bit Operand] | ||
| 674 | ; ESHLD OPND,REG (Double left shift) [CL = COUNT] | ||
| 675 | |||
| 676 | ESHLD MACRO OPND,REG | ||
| 677 | DB 66H | ||
| 678 | SHDOP 0A5H,<&OPND>,® | ||
| 679 | ENDM | ||
| 680 | |||
| 681 | |||
| 682 | ; Shift Right Double R/M, Reg [CL = COUNT] [32-bit Operand] | ||
| 683 | ; ESHRD OPND,REG (Double right shift) [CL = COUNT] | ||
| 684 | |||
| 685 | ESHRD MACRO OPND,REG | ||
| 686 | DB 66H | ||
| 687 | SHDOP 0ADH,<&OPND>,® | ||
| 688 | ENDM | ||
| 689 | |||
| 690 | |||
| 691 | ; Shift Left Double R/M, Reg, Immd (8-bit) [32-bit Operand] | ||
| 692 | ; ESHLDI OPND,REG,IMMD-8 (Double left shift) | ||
| 693 | |||
| 694 | ESHLDI MACRO OPND,REG,IMMD | ||
| 695 | DB 66H | ||
| 696 | SHDOP 0A4H,<&OPND>,® | ||
| 697 | DB &IMMD | ||
| 698 | ENDM | ||
| 699 | |||
| 700 | |||
| 701 | ; Shift Right Double R/M, Reg, Immd (8-bit) [32-bit Operand] | ||
| 702 | ; ESHRDI OPND,REG,IMMD-8 (Double right shift) | ||
| 703 | |||
| 704 | ESHRDI MACRO OPND,REG,IMMD | ||
| 705 | DB 66H | ||
| 706 | SHDOP 0ACH,<&OPND>,® | ||
| 707 | DB &IMMD | ||
| 708 | ENDM | ||
| 709 | |||
| 710 | |||
| 711 | SHDOP MACRO OP,OPND,REG | ||
| 712 | LOCAL L1,L2 | ||
| 713 | _2BYTEOP = 1 | ||
| 714 | DB 0FH | ||
| 715 | .XLIST | ||
| 716 | L1 LABEL BYTE | ||
| 717 | .LIST | ||
| 718 | OR ®,&OPND | ||
| 719 | .XLIST | ||
| 720 | L2 LABEL BYTE | ||
| 721 | ORG OFFSET CS:L1 | ||
| 722 | .LIST | ||
| 723 | DB &OP | ||
| 724 | .XLIST | ||
| 725 | ORG OFFSET CS:L2 | ||
| 726 | .LIST | ||
| 727 | ENDM | ||
| 728 | |||
| 729 | PAGE | ||
| 730 | |||
| 731 | ; The following two instructions, CALLFAR and JUMPFAR, work in the | ||
| 732 | ; MS Macro Assembler, but not for intersegment direct. The assembler | ||
| 733 | ; generates segments based on 8088 values, and we need them based | ||
| 734 | ; on protect-mode selector values. The assembler works just ducky for | ||
| 735 | ; jump and call far indirect, since you go pick up the offset and | ||
| 736 | ; segment at execution time. | ||
| 737 | |||
| 738 | CALLFAR MACRO DISP,SEGMENT | ||
| 739 | |||
| 740 | DB 09AH ; Call far direct | ||
| 741 | DW (OFFSET &DISP) ; to this offset | ||
| 742 | DW &SEGMENT ; in this segment | ||
| 743 | |||
| 744 | ENDM | ||
| 745 | |||
| 746 | |||
| 747 | JUMPFAR MACRO DISP,SEGMENT | ||
| 748 | |||
| 749 | DB 0EAH ; Jump far direct | ||
| 750 | DW (OFFSET &DISP) ; to this offset | ||
| 751 | DW &SEGMENT ; in this segment | ||
| 752 | |||
| 753 | ENDM | ||
| 754 | |||
| 755 | PAGE | ||
| 756 | |||
| 757 | ; Macros for extended jump instructions | ||
| 758 | |||
| 759 | LJCOND MACRO OP,DISPL | ||
| 760 | _2BYTEOP = 1 | ||
| 761 | TEMP = $ + 4 | ||
| 762 | DB 0FH | ||
| 763 | DB &OP | ||
| 764 | DW (OFFSET &DISPL)-(&TEMP) | ||
| 765 | ENDM | ||
| 766 | |||
| 767 | ; LJO DISPL (Long Jump on Overflow) | ||
| 768 | LJO MACRO DISPL | ||
| 769 | LJCOND 80H,<&DISPL> | ||
| 770 | ENDM | ||
| 771 | |||
| 772 | |||
| 773 | ; LJNO DISPL (Long Jump on NO Overflow) | ||
| 774 | LJNO MACRO DISPL | ||
| 775 | LJCOND 81H,<&DISPL> | ||
| 776 | ENDM | ||
| 777 | |||
| 778 | ; LJB DISPL (Long Jump on Below) | ||
| 779 | LJB MACRO DISPL | ||
| 780 | LJCOND 82H,<&DISPL> | ||
| 781 | ENDM | ||
| 782 | |||
| 783 | ; LJC DISPL (Long Jump on Carry) | ||
| 784 | LJC MACRO DISPL | ||
| 785 | LJCOND 82H,<&DISPL> | ||
| 786 | ENDM | ||
| 787 | |||
| 788 | ; LNAE DISPL (Long Jump on Not Above or Equal) | ||
| 789 | LNAE MACRO DISPL | ||
| 790 | LJCOND 82H,<&DISPL> | ||
| 791 | ENDM | ||
| 792 | |||
| 793 | ; LJNB DISPL (Long Jump on Not Below) | ||
| 794 | LJNB MACRO DISPL | ||
| 795 | LJCOND 83H,<&DISPL> | ||
| 796 | ENDM | ||
| 797 | |||
| 798 | ; LJNC DISPL (Long Jump on No Carry) | ||
| 799 | LJNC MACRO DISPL | ||
| 800 | LJCOND 83H,<&DISPL> | ||
| 801 | ENDM | ||
| 802 | |||
| 803 | ; LJAE DISPL (Long Jump on Above or Equal) | ||
| 804 | LJAE MACRO DISPL | ||
| 805 | LJCOND 83H,<&DISPL> | ||
| 806 | ENDM | ||
| 807 | |||
| 808 | ; LJE DISPL (Long Jump on Equal) | ||
| 809 | LJE MACRO DISPL | ||
| 810 | LJCOND 84H,<&DISPL> | ||
| 811 | ENDM | ||
| 812 | |||
| 813 | ; LJZ DISPL (Long Jump on Zero) | ||
| 814 | LJZ MACRO DISPL | ||
| 815 | LJCOND 84H,<&DISPL> | ||
| 816 | ENDM | ||
| 817 | |||
| 818 | ; LJNE DISPL (Long Jump on Not Equal) | ||
| 819 | LJNE MACRO DISPL | ||
| 820 | LJCOND 85H,<&DISPL> | ||
| 821 | ENDM | ||
| 822 | |||
| 823 | ; LJNZ DISPL (Long Jump on Not Zero) | ||
| 824 | LJNZ MACRO DISPL | ||
| 825 | LJCOND 85H,<&DISPL> | ||
| 826 | ENDM | ||
| 827 | |||
| 828 | ; LJBE DISPL (Long Jump on Below or Equal) | ||
| 829 | LJBE MACRO DISPL | ||
| 830 | LJCOND 86H,<&DISPL> | ||
| 831 | ENDM | ||
| 832 | |||
| 833 | ; LJNA DISPL (Long Jump on Not Above) | ||
| 834 | LJNA MACRO DISPL | ||
| 835 | LJCOND 86H,<&DISPL> | ||
| 836 | ENDM | ||
| 837 | |||
| 838 | ; LJNBE DISPL (Long Jump on Not Below or Equal) | ||
| 839 | LJNBE MACRO DISPL | ||
| 840 | LJCOND 87H,<&DISPL> | ||
| 841 | ENDM | ||
| 842 | |||
| 843 | ; LJA DISPL (Long Jump on Above) | ||
| 844 | LJA MACRO DISPL | ||
| 845 | LJCOND 87H,<&DISPL> | ||
| 846 | ENDM | ||
| 847 | |||
| 848 | ; LJS DISPL (Long Jump on Sign) | ||
| 849 | LJS MACRO DISPL | ||
| 850 | LJCOND 88H,<&DISPL> | ||
| 851 | ENDM | ||
| 852 | |||
| 853 | ; LJNS DISPL (Long Jump on No Sign) | ||
| 854 | LJNS MACRO DISPL | ||
| 855 | LJCOND 89H,<&DISPL> | ||
| 856 | ENDM | ||
| 857 | |||
| 858 | ; LJP DISPL (Long Jump on Parity) | ||
| 859 | LJP MACRO DISPL | ||
| 860 | LJCOND 8AH,<&DISPL> | ||
| 861 | ENDM | ||
| 862 | |||
| 863 | ; LJPE DISPL (Long Jump on Parity Even) | ||
| 864 | LJPE MACRO DISPL | ||
| 865 | LJCOND 8AH,<&DISPL> | ||
| 866 | ENDM | ||
| 867 | |||
| 868 | ; LJNP DISPL (Long Jump on No Parity) | ||
| 869 | LJNP MACRO DISPL | ||
| 870 | LJCOND 8BH,<&DISPL> | ||
| 871 | ENDM | ||
| 872 | |||
| 873 | ; LJPO DISPL (Long Jump on Parity Odd) | ||
| 874 | LJPO MACRO DISPL | ||
| 875 | LJCOND 8BH,<&DISPL> | ||
| 876 | ENDM | ||
| 877 | |||
| 878 | ; LJL DISPL (Long Jump on Less) | ||
| 879 | LJL MACRO DISPL | ||
| 880 | LJCOND 8CH,<&DISPL> | ||
| 881 | ENDM | ||
| 882 | |||
| 883 | ; LJNGE DISPL (Long Jump on Not Greater or Equal) | ||
| 884 | LJNGE MACRO DISPL | ||
| 885 | LJCOND 8CH,<&DISPL> | ||
| 886 | ENDM | ||
| 887 | |||
| 888 | ; LJNL DISPL (Long Jump on Not Less) | ||
| 889 | LJNL MACRO DISPL | ||
| 890 | LJCOND 8DH,<&DISPL> | ||
| 891 | ENDM | ||
| 892 | |||
| 893 | ; LJGE DISPL (Long Jump on Greater than or Equal) | ||
| 894 | LJGE MACRO DISPL | ||
| 895 | LJCOND 8DH,<&DISPL> | ||
| 896 | ENDM | ||
| 897 | |||
| 898 | ; LJLE DISPL (Long Jump on Less than or Equal) | ||
| 899 | LJLE MACRO DISPL | ||
| 900 | LJCOND 8EH,<&DISPL> | ||
| 901 | ENDM | ||
| 902 | |||
| 903 | ; LJNG DISPL (Long Jump on Not Greater than) | ||
| 904 | LJNG MACRO DISPL | ||
| 905 | LJCOND 8EH,<&DISPL> | ||
| 906 | ENDM | ||
| 907 | |||
| 908 | ; LJNLE DISPL (Long Jump on Not Less than or Equal) | ||
| 909 | LJNLE MACRO DISPL | ||
| 910 | LJCOND 8FH,<&DISPL> | ||
| 911 | ENDM | ||
| 912 | |||
| 913 | ; LJG DISPL (Long Jump on Greater than) | ||
| 914 | LJG MACRO DISPL | ||
| 915 | LJCOND 8FH,<&DISPL> | ||
| 916 | ENDM | ||
| 917 | |||
| 918 | ; JECXZ DISPL (Jump short on ECX Zero) | ||
| 919 | JECEXZ MACRO DISPL | ||
| 920 | DB 66H | ||
| 921 | JCXZ &DISPL | ||
| 922 | ENDM | ||
| 923 | |||
diff --git a/v4.0/src/DEV/XMAEM/INDEMAUS.ASM b/v4.0/src/DEV/XMAEM/INDEMAUS.ASM new file mode 100644 index 0000000..1174510 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEMAUS.ASM | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | PAGE 60,132 | ||
| 2 | TITLE INDEMAUS - 386 XMA Emulator - Messages | ||
| 3 | |||
| 4 | COMMENT # | ||
| 5 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 6 | * * | ||
| 7 | * MODULE NAME : INDEMAUS * | ||
| 8 | * * | ||
| 9 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. * | ||
| 10 | * * | ||
| 11 | * DESCRIPTIVE NAME: 80386 XMA Emulator messages -- U.S. * | ||
| 12 | * * | ||
| 13 | * STATUS (LEVEL) : Version (0) Level (1.0) * | ||
| 14 | * * | ||
| 15 | * FUNCTION : Declare the U.S. messages for the 80386 XMA Emulator * | ||
| 16 | * * | ||
| 17 | * MODULE TYPE : ASM * | ||
| 18 | * * | ||
| 19 | * REGISTER USAGE : N/A * | ||
| 20 | * * | ||
| 21 | * RESTRICTIONS : None * | ||
| 22 | * * | ||
| 23 | * DEPENDENCIES : None * | ||
| 24 | * * | ||
| 25 | * ENTRY POINT : None * | ||
| 26 | * * | ||
| 27 | * LINKAGE : The messages are made PUBLIC so that the initialization * | ||
| 28 | * module, INDEINI, can access them. * | ||
| 29 | * * | ||
| 30 | * INPUT PARMS : None * | ||
| 31 | * * | ||
| 32 | * RETURN PARMS : None * | ||
| 33 | * * | ||
| 34 | * OTHER EFFECTS : None * | ||
| 35 | * * | ||
| 36 | * EXIT NORMAL : None * | ||
| 37 | * * | ||
| 38 | * EXIT ERROR : None * | ||
| 39 | * * | ||
| 40 | * EXTERNAL * | ||
| 41 | * REFERENCES : None * | ||
| 42 | * * | ||
| 43 | * SUB-ROUTINES : None * | ||
| 44 | * * | ||
| 45 | * MACROS : None * | ||
| 46 | * * | ||
| 47 | * CONTROL BLOCKS : None * | ||
| 48 | * * | ||
| 49 | * CHANGE ACTIVITY : * | ||
| 50 | * * | ||
| 51 | * $MOD(INDEMAUS) COMP(LOAD) PROD(3270PC) : * | ||
| 52 | * * | ||
| 53 | * $D0=D0004700 410 870629 D : NEW FOR RELEASE 1.1 * | ||
| 54 | * * | ||
| 55 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 56 | # | ||
| 57 | |||
| 58 | SUBTTL Messages ; D0A | ||
| 59 | PAGE ; D0A | ||
| 60 | ; D0A | ||
| 61 | PROG SEGMENT PARA PUBLIC 'PROG' ; D0A | ||
| 62 | ; D0A | ||
| 63 | ASSUME CS:PROG ; D0A | ||
| 64 | ASSUME SS:NOTHING ; D0A | ||
| 65 | ASSUME DS:PROG ; D0A | ||
| 66 | ASSUME ES:NOTHING ; D0A | ||
| 67 | ; D0A | ||
| 68 | INDEMAUS LABEL NEAR ; D0A | ||
| 69 | ; D0A | ||
| 70 | INCLUDE INDEMSUS.INC ; Use the US messages D0A | ||
| 71 | ; D0A | ||
| 72 | PROG ENDS ; D0A | ||
| 73 | END ; D0A | ||
diff --git a/v4.0/src/DEV/XMAEM/INDEMSG.ASM b/v4.0/src/DEV/XMAEM/INDEMSG.ASM new file mode 100644 index 0000000..1adf363 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEMSG.ASM | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | PAGE 60,132 | ||
| 2 | TITLE INDEMSG - 80386 XMA Emulator - Messages | ||
| 3 | |||
| 4 | COMMENT # | ||
| 5 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 6 | * * | ||
| 7 | * MODULE NAME : INDEMSG * | ||
| 8 | * * | ||
| 9 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. * | ||
| 10 | * * | ||
| 11 | * DESCRIPTIVE NAME: 80386 XMA Emulator messages -- U.S. * | ||
| 12 | * * | ||
| 13 | * STATUS (LEVEL) : Version (0) Level (1.10) * | ||
| 14 | * * | ||
| 15 | * FUNCTION : Declare the U.S. messages for the 80386 XMA Emulator * | ||
| 16 | * * | ||
| 17 | * MODULE TYPE : ASM * | ||
| 18 | * * | ||
| 19 | * REGISTER USAGE : N/A * | ||
| 20 | * * | ||
| 21 | * RESTRICTIONS : None * | ||
| 22 | * * | ||
| 23 | * DEPENDENCIES : None * | ||
| 24 | * * | ||
| 25 | * ENTRY POINT : None * | ||
| 26 | * * | ||
| 27 | * LINKAGE : The messages are made PUBLIC so that the initialization * | ||
| 28 | * module, INDEINI, can access them. * | ||
| 29 | * * | ||
| 30 | * INPUT PARMS : None * | ||
| 31 | * * | ||
| 32 | * RETURN PARMS : None * | ||
| 33 | * * | ||
| 34 | * OTHER EFFECTS : None * | ||
| 35 | * * | ||
| 36 | * EXIT NORMAL : None * | ||
| 37 | * * | ||
| 38 | * EXIT ERROR : None * | ||
| 39 | * * | ||
| 40 | * EXTERNAL * | ||
| 41 | * REFERENCES : None * | ||
| 42 | * * | ||
| 43 | * SUB-ROUTINES : None * | ||
| 44 | * * | ||
| 45 | * MACROS : None * | ||
| 46 | * * | ||
| 47 | * CONTROL BLOCKS : None * | ||
| 48 | * * | ||
| 49 | * CHANGE ACTIVITY : * | ||
| 50 | * * | ||
| 51 | * $MOD(INDEMSG) COMP(LOAD) PROD(3270PC) : * | ||
| 52 | * * | ||
| 53 | * $D0=D0004700 410 870629 D : NEW FOR RELEASE 1.1 * | ||
| 54 | * $P1=P0000311 410 870805 D : RENAME MODULE TO INDEMSUS * | ||
| 55 | * $P2=P0000489 410 871002 D : RENAME MODULE TO INDEMSG. DECLARE MESSAGES HERE.* | ||
| 56 | * $P3=P0000649 411 880125 D : NEW VERSION OF THE EMULATOR * | ||
| 57 | * $P4=P0000741 411 880203 D : UPDATE COPYRIGHT * | ||
| 58 | * $D1=D0008700 120 880206 D : SUPPORT DOS 4.00 IOCTL CALL * | ||
| 59 | * * | ||
| 60 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 61 | # | ||
| 62 | |||
| 63 | SUBTTL Messages ; D0A | ||
| 64 | PAGE ; D0A | ||
| 65 | ; D0A | ||
| 66 | PROG SEGMENT PARA PUBLIC 'PROG' ; D0A | ||
| 67 | ; D0A | ||
| 68 | ASSUME CS:PROG ; D0A | ||
| 69 | ASSUME SS:NOTHING ; D0A | ||
| 70 | ASSUME DS:PROG ; D0A | ||
| 71 | ASSUME ES:NOTHING ; D0A | ||
| 72 | ; D0A | ||
| 73 | INDEMSG LABEL NEAR ; D0A | ||
| 74 | ; D0A | ||
| 75 | ;---------------------------------------------------------------------------P2A; | ||
| 76 | ; Declare messages that the emulator will display on the screen. These P2A; | ||
| 77 | ; messages are declared with line lengths of 80 bytes to allow for World P2A; | ||
| 78 | ; Trade translation. The messages are made public so that other modules P2A; | ||
| 79 | ; can access them. P2A; | ||
| 80 | ; Note that the messages are declared 80 bytes long to facilitate world trade translation. P2A; | ||
| 81 | ;---------------------------------------------------------------------------P2A; | ||
| 82 | ; P2A | ||
| 83 | PUBLIC WELCOME ; P2A | ||
| 84 | PUBLIC GOODLOAD ; P2A | ||
| 85 | PUBLIC NO_80386 ; P2A | ||
| 86 | PUBLIC WAS_INST ; P2A | ||
| 87 | Public Small_Parm ;an000; dms; | ||
| 88 | Public No_Mem ;an000; dms; | ||
| 89 | ; P2A | ||
| 90 | CR EQU 13 ; ASCII for a carriage return ; @P2A | ||
| 91 | LF EQU 10 ; ASCII for a line feed ; @P2A | ||
| 92 | ; P2A | ||
| 93 | INCLUDE xmaem.cl1 | ||
| 94 | |||
| 95 | PROG ENDS ; D0A | ||
| 96 | END ; D0A | ||
diff --git a/v4.0/src/DEV/XMAEM/INDEMSUS.ASM b/v4.0/src/DEV/XMAEM/INDEMSUS.ASM new file mode 100644 index 0000000..d73d016 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEMSUS.ASM | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | PAGE 60,132 | ||
| 2 | TITLE INDEMSG - 80386 XMA Emulator - Messages | ||
| 3 | |||
| 4 | COMMENT # | ||
| 5 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 6 | * * | ||
| 7 | * MODULE NAME : INDEMSUS * | ||
| 8 | * * | ||
| 9 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. * | ||
| 10 | * * | ||
| 11 | * DESCRIPTIVE NAME: 80386 XMA Emulator messages -- U.S. * | ||
| 12 | * * | ||
| 13 | * STATUS (LEVEL) : Version (0) Level (1.0) * | ||
| 14 | * * | ||
| 15 | * FUNCTION : Declare the U.S. messages for the 80386 XMA Emulator * | ||
| 16 | * * | ||
| 17 | * MODULE TYPE : ASM * | ||
| 18 | * * | ||
| 19 | * REGISTER USAGE : N/A * | ||
| 20 | * * | ||
| 21 | * RESTRICTIONS : None * | ||
| 22 | * * | ||
| 23 | * DEPENDENCIES : None * | ||
| 24 | * * | ||
| 25 | * ENTRY POINT : None * | ||
| 26 | * * | ||
| 27 | * LINKAGE : The messages are made PUBLIC so that the initialization * | ||
| 28 | * module, INDEINI, can access them. * | ||
| 29 | * * | ||
| 30 | * INPUT PARMS : None * | ||
| 31 | * * | ||
| 32 | * RETURN PARMS : None * | ||
| 33 | * * | ||
| 34 | * OTHER EFFECTS : None * | ||
| 35 | * * | ||
| 36 | * EXIT NORMAL : None * | ||
| 37 | * * | ||
| 38 | * EXIT ERROR : None * | ||
| 39 | * * | ||
| 40 | * EXTERNAL * | ||
| 41 | * REFERENCES : None * | ||
| 42 | * * | ||
| 43 | * SUB-ROUTINES : None * | ||
| 44 | * * | ||
| 45 | * MACROS : None * | ||
| 46 | * * | ||
| 47 | * CONTROL BLOCKS : None * | ||
| 48 | * * | ||
| 49 | * CHANGE ACTIVITY : * | ||
| 50 | * * | ||
| 51 | * $MOD(INDEMSUS) COMP(LOAD) PROD(3270PC) : * | ||
| 52 | * * | ||
| 53 | * $D0=D0004700 410 870629 D : NEW FOR RELEASE 1.1 * | ||
| 54 | * $P1=P0000311 410 870805 D : RENAME MODULE TO INDEMSUS * | ||
| 55 | * * | ||
| 56 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 57 | # | ||
| 58 | |||
| 59 | SUBTTL Messages ; D0A | ||
| 60 | PAGE ; D0A | ||
| 61 | ; D0A | ||
| 62 | PROG SEGMENT PARA PUBLIC 'PROG' ; D0A | ||
| 63 | ; D0A | ||
| 64 | ASSUME CS:PROG ; D0A | ||
| 65 | ASSUME SS:NOTHING ; D0A | ||
| 66 | ASSUME DS:PROG ; D0A | ||
| 67 | ASSUME ES:NOTHING ; D0A | ||
| 68 | ; D0A | ||
| 69 | INDEMSG LABEL NEAR ; D0A | ||
| 70 | ; D0A | ||
| 71 | INCLUDE INDEMSUS.INC ; Use the US messages D0A | ||
| 72 | ; D0A | ||
| 73 | include copyrigh.inc ; DCL p1821 | ||
| 74 | ; | ||
| 75 | PROG ENDS ; D0A | ||
| 76 | END ; D0A | ||
diff --git a/v4.0/src/DEV/XMAEM/INDEMSUS.INC b/v4.0/src/DEV/XMAEM/INDEMSUS.INC new file mode 100644 index 0000000..e352729 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEMSUS.INC | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | COMMENT # | ||
| 2 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 3 | * * | ||
| 4 | * MODULE NAME : INDEMSUS * | ||
| 5 | * * | ||
| 6 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. * | ||
| 7 | * * | ||
| 8 | * DESCRIPTIVE NAME: 80386 XMA Emulator messages -- U.S. * | ||
| 9 | * * | ||
| 10 | * STATUS (LEVEL) : Version (0) Level (1.0) * | ||
| 11 | * * | ||
| 12 | * FUNCTION : Include file for U.S. messages for the 80386 XMA Emulator.* | ||
| 13 | * The messages are made PUBLIC so that the initialization * | ||
| 14 | * module, INDEINI, can access them. * | ||
| 15 | * * | ||
| 16 | * MODULE TYPE : INC * | ||
| 17 | * * | ||
| 18 | * MACROS : None * | ||
| 19 | * * | ||
| 20 | * CONTROL BLOCKS : None * | ||
| 21 | * * | ||
| 22 | * CHANGE ACTIVITY : * | ||
| 23 | * * | ||
| 24 | * $MAC(INDEMSUS) COMP(LOAD) PROD(3270PC) : * | ||
| 25 | * * | ||
| 26 | * $D0=D0004700 410 870722 D : NEW FOR RELEASE 1.1 * | ||
| 27 | * $P1=P0000311 410 870804 D : RENAME MODULE'S LIBRARY FILE TYPE TO "INC" * | ||
| 28 | * $P2=P0036900 110 870826 D : CHG MSG NO. INDXE003 * | ||
| 29 | * * | ||
| 30 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 31 | # | ||
| 32 | |||
| 33 | ;---------------------------------------------------------------------------D0A; | ||
| 34 | ; Declare messages that the emulator will display on the screen. These D0A; | ||
| 35 | ; messages are declared with line lengths of 80 bytes to allow for World D0A; | ||
| 36 | ; Trade translation. The messages are made public so that other modules D0A; | ||
| 37 | ; can access them. D0A; | ||
| 38 | ; Note that the messages are declared 80 bytes long to facilitate world trade translation. D0A; | ||
| 39 | ;---------------------------------------------------------------------------D0A; | ||
| 40 | ; D0A | ||
| 41 | PUBLIC WELCOME ; D0A | ||
| 42 | PUBLIC GOODLOAD ; D0A | ||
| 43 | PUBLIC NO_80386 ; D0A | ||
| 44 | PUBLIC WAS_INST ; D0A | ||
| 45 | ; D0A | ||
| 46 | CR EQU 13 ; ASCII for a carriage return ; @D0A | ||
| 47 | LF EQU 10 ; ASCII for a line feed ; @D0A | ||
| 48 | ; D0A | ||
| 49 | WELCOME DB "INDXE001 80386 XMA Emulator Version 1.00 " ; @D0A | ||
| 50 | DB " (C) Copyright 1988 Microsoft Corporation All rights reserved " ; @D0A | ||
| 51 | DB CR,LF,"$" ; @D0A | ||
| 52 | ; D0A | ||
| 53 | GOODLOAD DB "INDXE002 80386 XMA Emulator installed " ; @D0A | ||
| 54 | DB CR,LF,"$" ; @D0A | ||
| 55 | ; D0A | ||
| 56 | NO_80386 DB "INDXE003 80386 XMA Emulator not installed. This system unit " ; @D0A | ||
| 57 | DB " is not supported. The 80386 XMA Emulator requires " ; @D0A | ||
| 58 | DB " an IBM Personal System/2 Model 80. " ; @D0A | ||
| 59 | DB CR,LF,"$" ; @D0A | ||
| 60 | ; D0A | ||
| 61 | WAS_INST DB "INDXE004 80386 XMA Emulator not installed. " ; @D0A | ||
| 62 | DB " Protected mode already in use. " ; @D0A | ||
| 63 | DB CR,LF,"$" ; @D0A | ||
| 64 | ; D0A | ||
diff --git a/v4.0/src/DEV/XMAEM/INDEOVP.MAC b/v4.0/src/DEV/XMAEM/INDEOVP.MAC new file mode 100644 index 0000000..3f2e213 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEOVP.MAC | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | COMMENT # | ||
| 2 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 3 | * * | ||
| 4 | * MODULE NAME : INDEOVP * | ||
| 5 | * * | ||
| 6 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. * | ||
| 7 | * * | ||
| 8 | * DESCRIPTIVE NAME: Override prefix macros * | ||
| 9 | * * | ||
| 10 | * STATUS (LEVEL) : Version (0) Level (1.0) * | ||
| 11 | * * | ||
| 12 | * FUNCTION : DATAOV - Creates a prefix so that the next instruction * | ||
| 13 | * accesses data twice as wide as it normally would.* | ||
| 14 | * Bytes go to words, and words go to double words. * | ||
| 15 | * ADDROV - Creates a prefix so that the next instruction * | ||
| 16 | * uses 32 bit addresses instead of 16 bit. * | ||
| 17 | * SEGOV - Creates a segment override prefix for the next * | ||
| 18 | * instruction. * | ||
| 19 | * * | ||
| 20 | * MODULE TYPE : MAC * | ||
| 21 | * * | ||
| 22 | * REGISTER USAGE : 80286 Standard * | ||
| 23 | * * | ||
| 24 | * CHANGE ACTIVITY : * | ||
| 25 | * * | ||
| 26 | * $MAC(INDEOVP) COMP(LOAD) PROD(3270PC) : * | ||
| 27 | * * | ||
| 28 | * $D0=D0004700 410 870604 D : NEW FOR RELEASE 1.1 * | ||
| 29 | * $P1=P0000311 410 870804 D : RENAME MODULE'S LIBRARY FILE TYPE TO "MAC" * | ||
| 30 | * * | ||
| 31 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 32 | # | ||
| 33 | |||
| 34 | PAGE | ||
| 35 | ; DATAOV - Create a prefix for an instruction so that it accesses data twice | ||
| 36 | ; as wide as it normally would have. If the instruction was to access | ||
| 37 | ; bytes then it will access words. If it was to access words then it | ||
| 38 | ; will access double words (32 bits). | ||
| 39 | |||
| 40 | DATAOV MACRO | ||
| 41 | DB 066H | ||
| 42 | ENDM | ||
| 43 | |||
| 44 | PAGE | ||
| 45 | ; ADDROV - Create a prefix for an instruction so that it uses 32 bit addresses | ||
| 46 | ; instead of 16 bit addresses. | ||
| 47 | |||
| 48 | ADDROV MACRO | ||
| 49 | DB 067H | ||
| 50 | ENDM | ||
| 51 | |||
| 52 | PAGE | ||
| 53 | ; SEGOV - Segment Prefix Overrides | ||
| 54 | ; This macro will create segment prefix overrides for all the segment registers | ||
| 55 | ; on the 80386. It will also create prefixes for the data override and address | ||
| 56 | ; override as listed in the DATOV and ADDROV macros above. | ||
| 57 | ; | ||
| 58 | ; Syntax: SEGOV ES | CS | SS | DS | FS | GS | DATA | ADDRESS | ||
| 59 | ; | ||
| 60 | |||
| 61 | SEGOV MACRO SR | ||
| 62 | IFIDN <&SR>,<ES> | ||
| 63 | DB 026H | ||
| 64 | ENDIF | ||
| 65 | IFIDN <&SR>,<es> | ||
| 66 | DB 026H | ||
| 67 | ENDIF | ||
| 68 | IFIDN <&SR>,<CS> | ||
| 69 | DB 02EH | ||
| 70 | ENDIF | ||
| 71 | IFIDN <&SR>,<cs> | ||
| 72 | DB 02EH | ||
| 73 | ENDIF | ||
| 74 | IFIDN <&SR>,<SS> | ||
| 75 | DB 036H | ||
| 76 | ENDIF | ||
| 77 | IFIDN <&SR>,<ss> | ||
| 78 | DB 036H | ||
| 79 | ENDIF | ||
| 80 | IFIDN <&SR>,<DS> | ||
| 81 | DB 03EH | ||
| 82 | ENDIF | ||
| 83 | IFIDN <&SR>,<ds> | ||
| 84 | DB 03EH | ||
| 85 | ENDIF | ||
| 86 | IFIDN <&SR>,<FS> | ||
| 87 | DB 064H | ||
| 88 | ENDIF | ||
| 89 | IFIDN <&SR>,<fs> | ||
| 90 | DB 064H | ||
| 91 | ENDIF | ||
| 92 | IFIDN <&SR>,<GS> | ||
| 93 | DB 065H | ||
| 94 | ENDIF | ||
| 95 | IFIDN <&SR>,<gs> | ||
| 96 | DB 065H | ||
| 97 | ENDIF | ||
| 98 | IFIDN <&SR>,<DATA> | ||
| 99 | DB 066H | ||
| 100 | ENDIF | ||
| 101 | IFIDN <&SR>,<data> | ||
| 102 | DB 066H | ||
| 103 | ENDIF | ||
| 104 | IFIDN <&SR>,<ADDRESS> | ||
| 105 | DB 067H | ||
| 106 | ENDIF | ||
| 107 | IFIDN <&SR>,<address> | ||
| 108 | DB 067H | ||
| 109 | ENDIF | ||
| 110 | ENDM | ||
| 111 | |||
diff --git a/v4.0/src/DEV/XMAEM/INDEPAT.ASM b/v4.0/src/DEV/XMAEM/INDEPAT.ASM new file mode 100644 index 0000000..e14d1d8 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEPAT.ASM | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | PAGE 60,132 | ||
| 2 | TITLE INDEPAT - 80386 XMA Emulator - Patch area | ||
| 3 | |||
| 4 | COMMENT # | ||
| 5 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 6 | * * | ||
| 7 | * MODULE NAME : INDEPAT * | ||
| 8 | * * | ||
| 9 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. * | ||
| 10 | * * | ||
| 11 | * DESCRIPTIVE NAME: 80386 XMA Emulator patch area * | ||
| 12 | * * | ||
| 13 | * STATUS (LEVEL) : Version (0) Level (1.0) * | ||
| 14 | * * | ||
| 15 | * FUNCTION : Declare a patch area for the 80386 XMA Emulator * | ||
| 16 | * * | ||
| 17 | * MODULE TYPE : ASM * | ||
| 18 | * * | ||
| 19 | * REGISTER USAGE : N/A * | ||
| 20 | * * | ||
| 21 | * RESTRICTIONS : None * | ||
| 22 | * * | ||
| 23 | * DEPENDENCIES : None * | ||
| 24 | * * | ||
| 25 | * ENTRY POINT : None * | ||
| 26 | * * | ||
| 27 | * LINKAGE : None * | ||
| 28 | * * | ||
| 29 | * INPUT PARMS : None * | ||
| 30 | * * | ||
| 31 | * RETURN PARMS : None * | ||
| 32 | * * | ||
| 33 | * OTHER EFFECTS : None * | ||
| 34 | * * | ||
| 35 | * EXIT NORMAL : None * | ||
| 36 | * * | ||
| 37 | * EXIT ERROR : None * | ||
| 38 | * * | ||
| 39 | * EXTERNAL * | ||
| 40 | * REFERENCES : None * | ||
| 41 | * * | ||
| 42 | * SUB-ROUTINES : None * | ||
| 43 | * * | ||
| 44 | * MACROS : None * | ||
| 45 | * * | ||
| 46 | * CONTROL BLOCKS : None * | ||
| 47 | * * | ||
| 48 | * CHANGE ACTIVITY : * | ||
| 49 | * * | ||
| 50 | * $MOD(INDEPAT) COMP(LOAD) PROD(3270PC) : * | ||
| 51 | * * | ||
| 52 | * $P0=P0000489 410 871002 D : NEW FOR WSP VERSION 1.1 * | ||
| 53 | * * | ||
| 54 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 55 | # | ||
| 56 | |||
| 57 | SUBTTL Patch Area | ||
| 58 | PAGE | ||
| 59 | |||
| 60 | PROG SEGMENT PARA PUBLIC 'PROG' | ||
| 61 | |||
| 62 | ASSUME CS:PROG | ||
| 63 | ASSUME SS:NOTHING | ||
| 64 | ASSUME DS:PROG | ||
| 65 | ASSUME ES:NOTHING | ||
| 66 | |||
| 67 | PUBLIC INDEPAT | ||
| 68 | |||
| 69 | INDEPAT LABEL NEAR | ||
| 70 | |||
| 71 | DB 512 DUP(0EEH) | ||
| 72 | |||
| 73 | PROG ENDS | ||
| 74 | END | ||
diff --git a/v4.0/src/DEV/XMAEM/INDEXMA.ASM b/v4.0/src/DEV/XMAEM/INDEXMA.ASM new file mode 100644 index 0000000..c35dd24 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEXMA.ASM | |||
| @@ -0,0 +1,781 @@ | |||
| 1 | PAGE 60,132 | ||
| 2 | TITLE INDEXMA - 386 XMA Emulator - XMA Emulation | ||
| 3 | |||
| 4 | COMMENT # | ||
| 5 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 6 | * * | ||
| 7 | * MODULE NAME : INDEXMA * | ||
| 8 | * * | ||
| 9 | * 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. * | ||
| 10 | * * | ||
| 11 | * DESCRIPTIVE NAME: Do the XMA emulation for the 80386 XMA Emulator * | ||
| 12 | * * | ||
| 13 | * STATUS (LEVEL) : Version (0) Level (1.0) * | ||
| 14 | * * | ||
| 15 | * FUNCTION : This module does the actual manipulation of the page * | ||
| 16 | * tables to emulate the XMA card. Using the 80386 * | ||
| 17 | * paging mechanism we let the 4K page frames represent * | ||
| 18 | * the 4K XMA blocks on the XMA card. We let the page * | ||
| 19 | * tables represent the translate table. * | ||
| 20 | * * | ||
| 21 | * The XMA "blocks" start at address 12000:0. The D1C* | ||
| 22 | * Emulator emulates the XMA 2 card with the INDXMAA D1C* | ||
| 23 | * device driver. On initial power up, the XMA 2 card is D1C* | ||
| 24 | * disabled. The INDXMAA device driver then disables the D1C* | ||
| 25 | * memory from 0K to 640K and backs it with memory from D1C* | ||
| 26 | * 0K to 640K on the XMA 2 card. The Emulator looks like D1C* | ||
| 27 | * it does the same thing. The XMA blocks for 0K to 640K D1C* | ||
| 28 | * are taken from the system board memory from 0K to D1C* | ||
| 29 | * 640K. This memory on the motherboard is treated as D1C* | ||
| 30 | * XMA memory. This emulates the INDXMAA device driver's D1C* | ||
| 31 | * mapping of 0K to 640K on the XMA card to real memory. D1C* | ||
| 32 | * The XMA "blocks" for 640K and up are located in high D1C* | ||
| 33 | * memory starting at 12000:0. These "blocks" run up to D1C* | ||
| 34 | * the start of the MOVEBLOCK buffer. The MOVEBLOCK D1C* | ||
| 35 | * buffer is a chunk of storage (in 16K multiples) at the D1C* | ||
| 36 | * end of available memory that is reserved for the D1C* | ||
| 37 | * MOVEBLOCK functions. D1C* | ||
| 38 | * * | ||
| 39 | * The page tables are used to emulate the translate * | ||
| 40 | * table. By setting the address of the XMA "block" into * | ||
| 41 | * the page table entry for a specific page frame we can * | ||
| 42 | * make that address access that particular XMA page * | ||
| 43 | * frame. To the user this looks just like the translate * | ||
| 44 | * table is active. * | ||
| 45 | * * | ||
| 46 | * The tricky part comes in disabling pages (blocks). On D1C* | ||
| 47 | * the XMA 2 card, when a translate table entry is D1C* | ||
| 48 | * disabled the addresses for that address range go to D1C* | ||
| 49 | * real memory. If the address is between 0K and 640K D1C* | ||
| 50 | * then any access of that storage gets nothing because D1C* | ||
| 51 | * there is no memory backed from 0K to 640K on the real D1C* | ||
| 52 | * system. All other addresses go to real memory. So D1C* | ||
| 53 | * when the user disables translation of a translate D1C* | ||
| 54 | * table entry we need to check what range that entry D1C* | ||
| 55 | * covers. If the entry points to somewhere between 0K D1C* | ||
| 56 | * and 640K then we will set the page table entry that D1C* | ||
| 57 | * corresponds to the translate table entry to point to D1C* | ||
| 58 | * non-existent memory. For all other addresses we will D1C* | ||
| 59 | * just point the page table entry back to the real D1C* | ||
| 60 | * memory at that address. D1C* | ||
| 61 | * * | ||
| 62 | * This module receives control on all "IN"s and "OUT"s * | ||
| 63 | * done by the user. If the "IN" or "OUT" is not to an * | ||
| 64 | * XMA port then it passes the I/O on to INDEDMA. If it * | ||
| 65 | * is for an XMA port then the request is handled here. * | ||
| 66 | * * | ||
| 67 | * This module keeps its own copies of the XMA registers * | ||
| 68 | * and the translate table. When any I/O comes for the * | ||
| 69 | * XMA card it updates its copies of the registers and * | ||
| 70 | * the translate table. Then it does any needed * | ||
| 71 | * modifications on the page tables to emulate the XMA * | ||
| 72 | * request. * | ||
| 73 | * * | ||
| 74 | * MODULE TYPE : ASM * | ||
| 75 | * * | ||
| 76 | * REGISTER USAGE : 80386 Standard * | ||
| 77 | * * | ||
| 78 | * RESTRICTIONS : None * | ||
| 79 | * * | ||
| 80 | * DEPENDENCIES : None * | ||
| 81 | * * | ||
| 82 | * ENTRY POINTS : INW - Emulate "IN" for a word with port number * | ||
| 83 | * in DX * | ||
| 84 | * INWIMMED - Emulate "IN" for a word with an immediate * | ||
| 85 | * port number * | ||
| 86 | * INIMMED - Emulate "IN" for a byte with an immediate * | ||
| 87 | * port number * | ||
| 88 | * XMAIN - Emulate "OUT" for a byte with port number * | ||
| 89 | * in DX * | ||
| 90 | * OUTW - Emulate "OUT" for a word with port number * | ||
| 91 | * in DX * | ||
| 92 | * OUTWIMMED - Emulate "OUT" for a word with an immediate * | ||
| 93 | * port number * | ||
| 94 | * XMAOUTIMMED - Emulate "OUT" for a byte with an immediate * | ||
| 95 | * port number * | ||
| 96 | * XMAOUT - Emulate "OUT" for a byte with port number * | ||
| 97 | * in DX * | ||
| 98 | * * | ||
| 99 | * LINKAGE : Jumped to by INDEEXC * | ||
| 100 | * * | ||
| 101 | * INPUT PARMS : None * | ||
| 102 | * * | ||
| 103 | * RETURN PARMS : None * | ||
| 104 | * * | ||
| 105 | * OTHER EFFECTS : None * | ||
| 106 | * * | ||
| 107 | * EXIT NORMAL : Go to POPIO in INDEEMU to IRET to the V86 task * | ||
| 108 | * * | ||
| 109 | * EXIT ERROR : None * | ||
| 110 | * * | ||
| 111 | * EXTERNAL * | ||
| 112 | * REFERENCES : POPIO:NEAR - Entry in INDEEMU to return to V86 task * | ||
| 113 | * HEXW:NEAR - Entry in INDEEXC to display word in AX * | ||
| 114 | * DMAIN:NEAR - Entry in INDEDMA to "IN" from DMA port * | ||
| 115 | * DMAOUT:NEAR - Entry in INDEDMA to "OUT" to DMA port * | ||
| 116 | * PGTBLOFF:WORD - Offset of the normal page tables * | ||
| 117 | * SGTBLOFF:WORD - Offset of the page directory * | ||
| 118 | * NORMPAGE:WORD - Entry for the 1st page directory entry * | ||
| 119 | * so that it points to the normal * | ||
| 120 | * page tables * | ||
| 121 | * XMAPAGE:WORD - Entry for the 1st page directory entry * | ||
| 122 | * that points to the XMA page tables * | ||
| 123 | * TTTABLE:WORD - The translate table * | ||
| 124 | * BUFF_SIZE:WORD - Size of the MOVEBLOCK buffer * | ||
| 125 | * MAXMEM:WORD - Number of kilobytes on this machine * | ||
| 126 | * * | ||
| 127 | * SUB-ROUTINES : TTARCHANGED - Put the block number at the translate table * | ||
| 128 | * entry in 31A0H into "ports" 31A2H and 31A4H * | ||
| 129 | * UPDATETT - Update the translate table and page tables * | ||
| 130 | * to reflect the new block number written to * | ||
| 131 | * either 31A2H or 31A4H * | ||
| 132 | * * | ||
| 133 | * MACROS : DATAOV - Add prefix for the next instruction so that it * | ||
| 134 | * accesses data as 32 bits wide * | ||
| 135 | * ADDROV - Add prefix for the next instruction so that it * | ||
| 136 | * uses addresses that are 32 bits wide * | ||
| 137 | * CMOV - Move to and from control registers * | ||
| 138 | * * | ||
| 139 | * CONTROL BLOCKS : INDEDAT.INC - system data structures * | ||
| 140 | * * | ||
| 141 | * CHANGE ACTIVITY : * | ||
| 142 | * * | ||
| 143 | * $MOD(INDEXMA) COMP(LOAD) PROD(3270PC) : * | ||
| 144 | * * | ||
| 145 | * $D0=D0004700 410 870530 D : NEW FOR RELEASE 1.1 * | ||
| 146 | * $P1=P0000293 410 870731 D : LIMIT LINES TO 80 CHARACTERS * | ||
| 147 | * $P2=P0000312 410 870804 D : CHANGE COMPONENT FROM MISC TO LOAD * | ||
| 148 | * $D1=D0007100 410 870810 D : CHANGE TO EMULATE XMA 2 * | ||
| 149 | * * | ||
| 150 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 151 | # | ||
| 152 | |||
| 153 | .286P ; Enable recognition of 286 privileged instructs. | ||
| 154 | |||
| 155 | .XLIST ; Turn off the listing | ||
| 156 | INCLUDE INDEDAT.INC ; Include system data structures | ||
| 157 | |||
| 158 | IF1 ; Only include macros on the first pass | ||
| 159 | INCLUDE INDEOVP.MAC | ||
| 160 | INCLUDE INDEINS.MAC | ||
| 161 | ENDIF | ||
| 162 | .LIST ; Turn on the listing | ||
| 163 | |||
| 164 | CRT_SELECTOR EQU 00030H ; Selector for mono display buffer | ||
| 165 | SEX_ATTR EQU 04B00H ; Attribute for turquoise on red | ||
| 166 | STACK_ATTR EQU 00700H ; Attribute for white o black | ||
| 167 | BLANK EQU 00020H ; ASCII for a blank | ||
| 168 | XMA_PAGES_SEL EQU RSDA_PTR ; Selector for the XMA pages | ||
| 169 | HIMEM EQU 120H ; Adjustment for XMA pages >= 640K. @D1C | ||
| 170 | ; They start at address 12000:0. | ||
| 171 | ; It's the block number corresponding | ||
| 172 | ; to address 12000:0. | ||
| 173 | ; @D1D | ||
| 174 | |||
| 175 | PROG SEGMENT PARA PUBLIC 'PROG' | ||
| 176 | |||
| 177 | ASSUME CS:PROG | ||
| 178 | ASSUME DS:PROG | ||
| 179 | ASSUME ES:NOTHING | ||
| 180 | ASSUME SS:NOTHING | ||
| 181 | |||
| 182 | INDEXMA LABEL NEAR | ||
| 183 | |||
| 184 | ; The following entry points are in other modules | ||
| 185 | |||
| 186 | EXTRN POPIO:NEAR ; Return to V86 task - in INDEEMU | ||
| 187 | EXTRN HEXW:NEAR ; Display word in AX - in INDEEXC | ||
| 188 | EXTRN DMAIN:NEAR ; "IN" from DMA port - in INDEDMA | ||
| 189 | EXTRN DMAOUT:NEAR ; "OUT" to DMA port - in INDEDMA | ||
| 190 | |||
| 191 | ; The following data are in INDEI15.ASM | ||
| 192 | |||
| 193 | EXTRN PGTBLOFF:WORD ; Offset of the normal page tables | ||
| 194 | EXTRN SGTBLOFF:WORD ; Offset of the page directory | ||
| 195 | EXTRN NORMPAGE:WORD ; Entry for the 1st page directory entry | ||
| 196 | ; so that it points to the normal | ||
| 197 | ; page tables | ||
| 198 | EXTRN XMAPAGE:WORD ; Entry for the 1st page directory entry | ||
| 199 | ; that points to the XMA page tables | ||
| 200 | EXTRN TTTABLE:WORD ; The translate table | ||
| 201 | EXTRN BUFF_SIZE:WORD ; Size of the MOVEBLOCK buffer | ||
| 202 | EXTRN MAXMEM:WORD ; Number of kilobytes on this machine | ||
| 203 | |||
| 204 | ; Let the following entries be known to other modules | ||
| 205 | |||
| 206 | PUBLIC INDEXMA | ||
| 207 | PUBLIC INW | ||
| 208 | PUBLIC INWIMMED | ||
| 209 | PUBLIC INIMMED | ||
| 210 | PUBLIC XMAIN | ||
| 211 | PUBLIC OUTW | ||
| 212 | PUBLIC OUTWIMMED | ||
| 213 | PUBLIC XMAOUTIMMED | ||
| 214 | PUBLIC XMAOUT | ||
| 215 | PUBLIC NOTXMAOUT | ||
| 216 | |||
| 217 | ; Let the following data be known to other modules | ||
| 218 | |||
| 219 | PUBLIC WORD_FLAG | ||
| 220 | PUBLIC XMATTAR | ||
| 221 | PUBLIC XMATTIO | ||
| 222 | PUBLIC XMATTII | ||
| 223 | PUBLIC XMATID | ||
| 224 | PUBLIC XMACTL | ||
| 225 | |||
| 226 | ; The following XMA labels represent the XMA ports starting at 31A0H. | ||
| 227 | ; THEY MUST BE KEPT IN THE FOLLOWING ORDER. | ||
| 228 | |||
| 229 | XMATTAR DW 0 ; Port 31A0H - Translate table index | ||
| 230 | XMATTIO DW 0 ; Port 31A2H - XMA block number | ||
| 231 | XMATTII DW 0 ; Port 31A4H - Block number with auto-increment | ||
| 232 | XMATID DB 0 ; Port 31A6H - Bank ID | ||
| 233 | XMACTL DB 02H ; Port 31A7H - Control flags. Virtual @D1C | ||
| 234 | ; enable bit is initially on. | ||
| 235 | |||
| 236 | ; How about some flags? | ||
| 237 | |||
| 238 | WORD_FLAG DB 0 ; If set to 1 then I/O is for a word. | ||
| 239 | ; Else, it's for a byte | ||
| 240 | |||
| 241 | PAGE | ||
| 242 | |||
| 243 | ; Control comes here for an "IN" for a word with the port value in DX | ||
| 244 | |||
| 245 | INW: | ||
| 246 | MOV AX,SYS_PATCH_DS ; Load DS with the selector for our | ||
| 247 | MOV DS,AX ; data segment so we can set WORD_FLAG | ||
| 248 | MOV WORD_FLAG,1 ; Flag this as a word operation | ||
| 249 | JMP XMAIN ; Go do the "IN" | ||
| 250 | |||
| 251 | ; Control comes here for an "IN" for a word with an immediate port value | ||
| 252 | |||
| 253 | INWIMMED: | ||
| 254 | MOV AX,SYS_PATCH_DS ; Load DS with the selector for our | ||
| 255 | MOV DS,AX ; data segment so we can set WORD_FLAG | ||
| 256 | MOV WORD_FLAG,1 ; Flag this as a word operation | ||
| 257 | |||
| 258 | ; Control comes here for an "IN" for a byte with an immediate port value | ||
| 259 | |||
| 260 | INIMMED: | ||
| 261 | |||
| 262 | ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past the "IN" instruction | ||
| 263 | |||
| 264 | ; Get the port address from the instruction. The port address is in the byte | ||
| 265 | ; immediately following the "IN" op-code. We will load the port address into | ||
| 266 | ; DX. This way when we join the code below it will look like the port address | ||
| 267 | ; was in DX all along. | ||
| 268 | |||
| 269 | MOV AX,HUGE_PTR ; Load DS with a selector that accesses | ||
| 270 | MOV DS,AX ; all of memory as data | ||
| 271 | |||
| 272 | MOV SS:WORD PTR [BP+BP_IP2],0 ; Clear the high words of the V86 | ||
| 273 | MOV SS:WORD PTR [BP+BP_CS2],0 ; task's CS and IP | ||
| 274 | |||
| 275 | DATAOV ; Load ESI (32 bit SI) with the V86 | ||
| 276 | MOV SI,SS:[BP+BP_IP] ; task's IP | ||
| 277 | DATAOV | ||
| 278 | MOV AX,SS:[BP+BP_CS] ; Load EAX with the V86 task's CS | ||
| 279 | DATAOV ; and then shift left four bits to | ||
| 280 | SHL AX,4 ; convert it to an offset | ||
| 281 | DATAOV ; Add the CS offset to "IP" in SI | ||
| 282 | ADD SI,AX ; SI now contains CS:IP as a 32 bit | ||
| 283 | ; offset from 0 | ||
| 284 | ADDROV ; Get the byte after the "IN" instruc- | ||
| 285 | LODSB ; tion. This is the port address. | ||
| 286 | |||
| 287 | ADDROV ; Intel bug # A0-119 | ||
| 288 | NOP ; Intel bug # A0-119 | ||
| 289 | |||
| 290 | SUB DX,DX ; Clear DX to prepare for one byte move | ||
| 291 | MOV DL,AL ; DX now has the port address | ||
| 292 | |||
| 293 | ; Control comes here for an "IN" for a byte with the port value in DX | ||
| 294 | |||
| 295 | XMAIN PROC NEAR | ||
| 296 | |||
| 297 | MOV AX,SYS_PATCH_DS ; Load DS with the selector for our | ||
| 298 | MOV DS,AX ; data segment | ||
| 299 | |||
| 300 | CMP DX,31A0H ; Is the port address below 31A0H? | ||
| 301 | JB NOTXMAIN ; Yup. Then it's not XMA. | ||
| 302 | |||
| 303 | CMP DX,31A7H ; Is the port address above 31A7H? | ||
| 304 | JA NOTXMAIN ; Yup. Then it's not XMA. | ||
| 305 | |||
| 306 | ; It's an XMA port so lets do the "IN" for the guy. | ||
| 307 | |||
| 308 | AND XMATTAR,0FFFH ; First lets clear the high nibbles of | ||
| 309 | AND XMATID,0FH ; our ports. This insures that we | ||
| 310 | AND XMACTL,0FH ; have valid values in our ports. | ||
| 311 | |||
| 312 | LEA SI,XMATTAR ; Point SI to the port requested by | ||
| 313 | ADD SI,DX ; first pointing it to port 31A0H | ||
| 314 | SUB SI,31A0H ; and then adding on the difference | ||
| 315 | ; between 31A0H and the requested port | ||
| 316 | CMP WORD_FLAG,0 ; Is this a word operation? | ||
| 317 | JNE GETWORD ; Yes. Then go get a word. | ||
| 318 | |||
| 319 | LODSB ; Else get a byte from the "port" | ||
| 320 | MOV BYTE PTR SS:[BP+BP_AX],AL ; Put it in the V86 task's AL register | ||
| 321 | JMP INEXIT ; Th-th-that's all folks! | ||
| 322 | |||
| 323 | ; For non-XMA ports we just pass the "IN" on to INDEDMA | ||
| 324 | |||
| 325 | NOTXMAIN: | ||
| 326 | JMP DMAIN | ||
| 327 | |||
| 328 | ; The "IN" is for a word | ||
| 329 | |||
| 330 | GETWORD: | ||
| 331 | LODSW ; Get a word from the "port" | ||
| 332 | MOV WORD PTR SS:[BP+BP_AX],AX ; Put it in the V86 task's AX register | ||
| 333 | |||
| 334 | MOV WORD_FLAG,0 ; Reset the word flag | ||
| 335 | |||
| 336 | CMP DX,31A4H ; Is this an "IN" from the auto- | ||
| 337 | ; increment port? | ||
| 338 | JNE INEXIT ; Nope. Then just leave. | ||
| 339 | |||
| 340 | INC XMATTAR ; The "IN" is from the auto-increment | ||
| 341 | ; port so increment the translate | ||
| 342 | CALL TTARCHANGED ; table index and call TTARCHANGED | ||
| 343 | ; to update the status of the "card" | ||
| 344 | INEXIT: | ||
| 345 | ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past the instruction (past | ||
| 346 | ; the port value for immediate insts.) | ||
| 347 | JMP POPIO ; Go return to the V86 task | ||
| 348 | |||
| 349 | PAGE | ||
| 350 | |||
| 351 | ; Control comes here for an "OUT" for a word with the port value in DX | ||
| 352 | |||
| 353 | OUTW: | ||
| 354 | MOV AX,SYS_PATCH_DS ; Load DS with the selector for our | ||
| 355 | MOV DS,AX ; data segment so we can set WORD_FLAG | ||
| 356 | MOV WORD_FLAG,1 ; Flag this as a word operation | ||
| 357 | JMP XMAOUT ; Go do the "OUT" | ||
| 358 | |||
| 359 | ; Control comes here for an "OUT" for a word with an immediate port value | ||
| 360 | |||
| 361 | OUTWIMMED: | ||
| 362 | MOV AX,SYS_PATCH_DS ; Load DS with the selector for our | ||
| 363 | MOV DS,AX ; data segment so we can set WORD_FLAG | ||
| 364 | MOV WORD_FLAG,1 ; Flag this as a word operation | ||
| 365 | |||
| 366 | ; Control comes here for an "OUT" for a byte with an immediate port value | ||
| 367 | |||
| 368 | XMAOUTIMMED: | ||
| 369 | |||
| 370 | ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past the "OUT" instruction | ||
| 371 | |||
| 372 | ; Get the port address from the instruction. The port address is in the byte | ||
| 373 | ; immediately following the "OUT" op-code. We will load the port address into | ||
| 374 | ; DX. This way when we join the code below it will look like the port address | ||
| 375 | ; was in DX all along. | ||
| 376 | |||
| 377 | MOV AX,HUGE_PTR ; Load DS with a selector that accesses | ||
| 378 | MOV DS,AX ; all of memory as data | ||
| 379 | |||
| 380 | MOV SS:WORD PTR [BP+BP_IP2],0 ; Clear the high words of the V86 | ||
| 381 | MOV SS:WORD PTR [BP+BP_CS2],0 ; task's CS and IP | ||
| 382 | |||
| 383 | DATAOV ; Load ESI (32 bit SI) with the V86 | ||
| 384 | MOV SI,SS:[BP+BP_IP] ; task's IP | ||
| 385 | DATAOV | ||
| 386 | MOV AX,SS:[BP+BP_CS] ; Load EAX with the V86 task's CS | ||
| 387 | DATAOV ; and then shift left four bits to | ||
| 388 | SHL AX,4 ; convert it to an offset | ||
| 389 | DATAOV ; Add the CS offset to "IP" in SI | ||
| 390 | ADD SI,AX ; SI now contains CS:IP as a 32 bit | ||
| 391 | ; offset from 0 | ||
| 392 | ADDROV ; Get the byte after the "OUT" instruc- | ||
| 393 | LODSB ; tion. This is the port address. | ||
| 394 | |||
| 395 | ADDROV ; Intel bug # A0-119 | ||
| 396 | NOP ; Intel bug # A0-119 | ||
| 397 | |||
| 398 | SUB DX,DX ; Clear DX to prepare for one byte move | ||
| 399 | MOV DL,AL ; DX now has the port address | ||
| 400 | |||
| 401 | ; Control comes here for an "OUT" for a byte with the port value in DX | ||
| 402 | |||
| 403 | XMAOUT: | ||
| 404 | MOV AX,SYS_PATCH_DS ; Load DS and ES with the selector for | ||
| 405 | MOV DS,AX ; our data area | ||
| 406 | MOV ES,AX | ||
| 407 | |||
| 408 | CMP DX,31A0H ; Is the port address below 31A0H? | ||
| 409 | JB NOTXMAOUT ; Yes. Then it's not XMA. | ||
| 410 | |||
| 411 | CMP DX,31A7H ; Is the port address above 31A7H? | ||
| 412 | JA NOTXMAOUT ; Yes. Then it's not XMA. | ||
| 413 | |||
| 414 | LEA DI,XMATTAR ; Point SI to the port requested by | ||
| 415 | ADD DI,DX ; first pointing it to port 31A0H | ||
| 416 | SUB DI,31A0H ; and then adding on the difference | ||
| 417 | ; between 31A0H and the requested port | ||
| 418 | CMP WORD_FLAG,0 ; Is this a word operation? | ||
| 419 | JNE PUTWORD ; Yes. Then go put a word. | ||
| 420 | |||
| 421 | MOV AL,BYTE PTR SS:[BP+BP_AX] ; Put the value in the V86 task's AL | ||
| 422 | STOSB ; register into the "port" | ||
| 423 | |||
| 424 | CMP DX,31A6H ; Is this "OUT" to the bank ID port? | ||
| 425 | JE CHKCNTRL ; If so, go set the new bank | ||
| 426 | |||
| 427 | CMP DX,31A7H ; Is the "OUT" to the control port? | ||
| 428 | JE CHKCNTRL ; Affirmative. Go handle control bits. | ||
| 429 | |||
| 430 | CMP DX,31A1H ; Is this "OUT" to the TT index? | ||
| 431 | ; (high byte) | ||
| 432 | JBE TTAROUT ; Yup. Go update dependent fields. | ||
| 433 | |||
| 434 | JMP OUTEXIT ; Any other ports just exit. | ||
| 435 | |||
| 436 | ; The "OUT" is for a word | ||
| 437 | |||
| 438 | PUTWORD: | ||
| 439 | MOV AX,WORD PTR SS:[BP+BP_AX] ; Put the value in the V86 task's AX | ||
| 440 | STOSW ; register into the "port" | ||
| 441 | |||
| 442 | MOV WORD_FLAG,0 ; Reset the word flag | ||
| 443 | |||
| 444 | CMP DX,31A0H ; Is the "OUT" to the TT index port? | ||
| 445 | JE TTAROUT ; Si. Go update the dependent fields. | ||
| 446 | |||
| 447 | CMP DX,31A2H ; Is the "OUT" to set a block number? | ||
| 448 | JNE CHKA4 ; No. Go do some more checks. | ||
| 449 | |||
| 450 | MOV XMATTII,AX ; The "OUT" is to 31A2H. Set the auto- | ||
| 451 | ; increment port to the same value. | ||
| 452 | ; The two ports should always be in | ||
| 453 | ; sync. | ||
| 454 | CALL UPDATETT ; Update the "translate table" with the | ||
| 455 | ; new block number | ||
| 456 | JMP OUTEXIT ; That's it. Let's leave. | ||
| 457 | |||
| 458 | CHKA4: | ||
| 459 | CMP DX,31A4H ; Is "OUT" to the auto-increment port | ||
| 460 | JNE CHKCNTRL ; No. Then it must be to the bank ID/ | ||
| 461 | ; control byte port (31A6H). | ||
| 462 | MOV XMATTIO,AX ; The "OUT is to the auto-increment port | ||
| 463 | CALL UPDATETT ; Update the "translate table" | ||
| 464 | INC XMATTAR ; Increment the translate table index | ||
| 465 | CALL TTARCHANGED ; Update fields that depend on the | ||
| 466 | ; translate table index | ||
| 467 | JMP OUTEXIT ; And return to the V86 task | ||
| 468 | |||
| 469 | ; The translate table index was changed | ||
| 470 | |||
| 471 | TTAROUT: | ||
| 472 | CALL TTARCHANGED ; Update fields that depend on the | ||
| 473 | ; setting of the translate table index | ||
| 474 | JMP OUTEXITDMA ; Skip flushing the page-translation | ||
| 475 | ; cache since the page tables have | ||
| 476 | ; not changed. | ||
| 477 | |||
| 478 | ; It's not an XMA "OUT" so pass it on to INDEDMA | ||
| 479 | |||
| 480 | NOTXMAOUT: | ||
| 481 | JMP DMAOUT | ||
| 482 | |||
| 483 | ; The "OUT" is to the bank ID port (31A6H), the control port (31A7H) or both | ||
| 484 | |||
| 485 | CHKCNTRL: | ||
| 486 | |||
| 487 | TEST XMACTL,02H ; Is the virtual enable bit on? | ||
| 488 | JNZ SETXMA ; Aye. Go make the specified XMA bank | ||
| 489 | ; active. | ||
| 490 | DATAOV ; Nay. We simulate disabling the XMA | ||
| 491 | MOV AX,NORMPAGE ; card by making the normal page | ||
| 492 | ; tables active. | ||
| 493 | MOV DI,SGTBLOFF ; This is done by setting the first | ||
| 494 | DATAOV ; entry in the page directory to | ||
| 495 | STOSW ; point to the page table for normal | ||
| 496 | ; memory. | ||
| 497 | JMP OUTEXIT ; Return to the V86 task | ||
| 498 | |||
| 499 | SETXMA: | ||
| 500 | AND XMATID,0FH ; Wipe out the high nibble of the bank | ||
| 501 | MOV AL,XMATID ; ID. XMA only has 16 banks. | ||
| 502 | DATAOV ; Now multiply by 4K (shift left 12 ;P1C | ||
| 503 | SHL AX,28 ; bits) to get the offset from the | ||
| 504 | DATAOV ; base of the XMA page tables of the | ||
| 505 | SHR AX,28-12 ; page table for the requested bank. | ||
| 506 | ; Page tables are 4K in length. In | ||
| 507 | ; the process of shifting we shift the | ||
| 508 | ; high order 16 bits off the left end | ||
| 509 | ; of EAX so that they are 0 when we | ||
| 510 | ; shift back. | ||
| 511 | DATAOV ; Add on the offset of the base of the | ||
| 512 | ADD AX,XMAPAGE ; page tables. EAX now has the offset | ||
| 513 | ; of the page table for the XMA bank. | ||
| 514 | MOV DI,SGTBLOFF ; Point to the first entry in the page | ||
| 515 | ; directory. | ||
| 516 | DATAOV ; Set the first entry in the page | ||
| 517 | STOSW ; directory to point to the XMA page | ||
| 518 | ; table | ||
| 519 | |||
| 520 | ; Since the page tables have changed we need to purge the page-translation | ||
| 521 | ; cache. "For greatest efficiency in address translation, the processor | ||
| 522 | ; stores the most recently used page-table data in an on-chip cache... The | ||
| 523 | ; existence of the page-translation cache is invisible to applications | ||
| 524 | ; programmers but not to systems programmers; operating-system programmers | ||
| 525 | ; must flush the cache whenever the page tables are changed." | ||
| 526 | ; -- 80386 Programmer's Reference Manual (C) Intel 1986 | ||
| 527 | |||
| 528 | OUTEXIT: | ||
| 529 | CMOV EAX,CR3 ; Get the page directory base register | ||
| 530 | NOP ; 386 errata B0-110 | ||
| 531 | CMOV CR3,EAX ; Write it back to reset the cache | ||
| 532 | NOP ; 386 errata B0-110 | ||
| 533 | |||
| 534 | OUTEXITDMA: | ||
| 535 | ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past the "OUT" instruction | ||
| 536 | JMP POPIO ; Return to the V86 task | ||
| 537 | |||
| 538 | PAGE | ||
| 539 | |||
| 540 | ; TTARCHANGED updates all the fields that depend on the translate table index | ||
| 541 | ; in port 31A0H. This is mainly getting the translate table entries for the | ||
| 542 | ; specified index and putting them in the block number ports 31A2H and 31A4H. | ||
| 543 | |||
| 544 | TTARCHANGED PROC | ||
| 545 | |||
| 546 | MOV AX,XMATTAR ; Get the new translate table index | ||
| 547 | AND AX,0FFFH ; The high nibble is not used | ||
| 548 | SHL AX,1 ; Change it to a word index. The | ||
| 549 | ; translate table entries are words. | ||
| 550 | LEA SI,TTTABLE ; Point SI to the translate table base | ||
| 551 | ADD SI,AX ; Add on the offset into the table | ||
| 552 | LODSW ; Get the XMA block number for the | ||
| 553 | ; specified translate table entry | ||
| 554 | MOV XMATTIO,AX ; Put it into "port" 31A2H | ||
| 555 | MOV XMATTII,AX ; Put it into "port" 31A4H | ||
| 556 | |||
| 557 | RET | ||
| 558 | |||
| 559 | TTARCHANGED ENDP | ||
| 560 | |||
| 561 | PAGE | ||
| 562 | |||
| 563 | ; UPDATETT will update the "translate table" and the corresponding page | ||
| 564 | ; tables when an XMA block number is written to either port 31A2H or the | ||
| 565 | ; auto-increment port 31A4H. A write to either of these ports means to set | ||
| 566 | ; the XMA block specified at the translate table entry indicated in port | ||
| 567 | ; 31A0H. | ||
| 568 | ; | ||
| 569 | ; The Emulator is set up to look like an XMA 2 card with the INDXMAA device D1C | ||
| 570 | ; driver. When the system comes up the XMA card is initially disabled. D1C | ||
| 571 | ; INDXMAA then backs memory from 0K to 640K on the system board with memory D1C | ||
| 572 | ; from 0K to 640K on the XMA card. To emulate this, the Emulator treats D1C | ||
| 573 | ; real memory from 0K to 640K as XMA blocks from 0K to 640K on the XMA card. D1C | ||
| 574 | ; This both saves memory and requires no code to back the real memory from D1C | ||
| 575 | ; 0K to 640K with XMA memory on initialization. The Emulator therefore only D1C | ||
| 576 | ; needs to allocate XMA memory for the XMA blocks over 640K. The XMA memory D1C | ||
| 577 | ; for over 640K starts at 12000:0. The XMA blocks 00H to 9FH will be mapped D1C | ||
| 578 | ; to the motherboard memory at 0K to 640K. The XMA blocks A0H and up will D1C | ||
| 579 | ; be mapped to the memory at 12000:0 and up. D1C | ||
| 580 | ; | ||
| 581 | ; Bits 15 (IBM bit 0) and 11 (IBM bit 4) of the XMA block number have | ||
| 582 | ; special meanings. When bit 15 is on it means that the block number is a | ||
| 583 | ; 15 bit number. This is in anticipation of larger block numbers in the | ||
| 584 | ; future. Current block numbers are 11 bits. When bit 11 is on it means | ||
| 585 | ; that the XMA translation for this translation table entry should be | ||
| 586 | ; disabled. The memory for this 4K block should be mapped back to real | ||
| 587 | ; memory. | ||
| 588 | ; | ||
| 589 | ; We also check to make sure that the XMA block is not above the XMA memory | ||
| 590 | ; limit. XMA memory ends where the MOVEBLOCK buffer starts. If the XMA | ||
| 591 | ; block is above the end of XMA memory then the page table entry for that | ||
| 592 | ; address is set to point to non-existent memory. | ||
| 593 | ; | ||
| 594 | ; When address translation is disabled for addresses above 640K then the D1C | ||
| 595 | ; page table entry for that address is set to point back to real memory. D1C | ||
| 596 | ; For disabled pages in the range 0K to 640K the page table entry is set to D1C | ||
| 597 | ; point to non-existent memory. D1C | ||
| 598 | |||
| 599 | UPDATETT PROC | ||
| 600 | |||
| 601 | MOV AX,XMATTAR ; Get the index of the TT entry that | ||
| 602 | ; is to be changed | ||
| 603 | AND AX,0FFFH ; Clear the high four bits. They are | ||
| 604 | ; not used. | ||
| 605 | SHL AX,1 ; Change to a word offset since the TT | ||
| 606 | ; entries are words. | ||
| 607 | LEA DI,TTTABLE ; Point DI to the translate table base | ||
| 608 | ADD DI,AX ; Add on the offset of the entry that | ||
| 609 | ; is to be changed | ||
| 610 | MOV AX,XMATTIO ; Get the block number to be written | ||
| 611 | STOSW ; Store the block number in the TT | ||
| 612 | |||
| 613 | ; Convert bank number to a page address. | ||
| 614 | ; The following code works only with paging enabled at 256k boundary. | ||
| 615 | ; It is intended to support up to 128M at 4k granularity. | ||
| 616 | ; It interprets the high order bits as a superset of XMA. | ||
| 617 | ; Following is a truth table for bits 11 (XMA inhibit bit) and 15 ("enable-hi"). | ||
| 618 | ; 15 11 | ||
| 619 | ; 0 0 = enabled 11 bit address | ||
| 620 | ; 0 1 = disabled address | ||
| 621 | ; 1 x = enabled 15 bit address | ||
| 622 | |||
| 623 | TEST AH,80H ; Is this a 15 bit block number? | ||
| 624 | JZ SMALL ; Far from it. Go do stuff for 11 bit | ||
| 625 | ; block numbers. | ||
| 626 | |||
| 627 | ; We have a 15 bit address | ||
| 628 | |||
| 629 | CMP AX,0FFFFH ; If it's FFFFH then we treat it the | ||
| 630 | ; the same as 0FFFH which means | ||
| 631 | JE DISABLEPAGE ; disable the page | ||
| 632 | |||
| 633 | AND AX,7FFFH ; Turn off the 15 bit address bit | ||
| 634 | JMP BOTH ; leaving a valid block number for | ||
| 635 | ; our calculations later | ||
| 636 | |||
| 637 | SMALL: | ||
| 638 | TEST AH,08H ; Is the disable bit on? | ||
| 639 | JNZ DISABLEPAGE ; Yes. Go disable the page. | ||
| 640 | |||
| 641 | AND AX,07FFH ; No. Turn off the high nibble and the | ||
| 642 | ; disable bit leaving a valid block | ||
| 643 | ; number for our upcoming calculations | ||
| 644 | BOTH: | ||
| 645 | CMP AX,640/4 ; Is this block number for 640K or over? | ||
| 646 | JB NOADJUST ; Yup. There's no adjustment @D1C | ||
| 647 | ; needed for blocks between 0K and | ||
| 648 | ; 640K since we use real memory for | ||
| 649 | ; these blocks. | ||
| 650 | ; XMA 1 emulation code deleted 3@D1D | ||
| 651 | ADD AX,HIMEM-(640/4) ; Add on the adjustment needed for @D1C | ||
| 652 | ; blocks above 640K to point to | ||
| 653 | ; the XMA blocks starting at 12000:0. | ||
| 654 | ; But don't forget to subtract the | ||
| 655 | ; block number for 640K. This makes | ||
| 656 | ; the block number 0 based before we | ||
| 657 | ; add on the block number for 12000:0. | ||
| 658 | NOADJUST: | ||
| 659 | DATAOV ; Shift the high order 16 bits of EAX | ||
| 660 | SHL AX,16 ; off the left end of the register. | ||
| 661 | DATAOV ; Now shift the block number back four | ||
| 662 | SHR AX,16-12 ; bits. This results in a net shift | ||
| 663 | ; left of 12 bits which converts the | ||
| 664 | ; block number to an offset, and it | ||
| 665 | ; clears the high four bits. | ||
| 666 | OR AL,7 ; Set the access and present bits. This | ||
| 667 | ; converts our offset to a valid page | ||
| 668 | ; table entry. | ||
| 669 | DATAOV ; Save the page table entry in EBX for | ||
| 670 | MOV BX,AX ; now | ||
| 671 | |||
| 672 | ; Now we must make sure the offset of our XMA page frame is within the address | ||
| 673 | ; space of the XMA pages, that is, it is below the start of the MOVEBLOCK | ||
| 674 | ; buffer. | ||
| 675 | |||
| 676 | DATAOV ; Clear all 32 bits of EAX | ||
| 677 | SUB AX,AX | ||
| 678 | MOV AX,MAXMEM ; Load up the number of K on the box | ||
| 679 | SUB AX,BUFF_SIZE ; Subtract the number of K reserved | ||
| 680 | ; for the MOVEBLOCK buffer | ||
| 681 | DATAOV ; Multiply by 1K (shift left 10) to | ||
| 682 | SHL AX,10 ; convert it to an offset | ||
| 683 | DATAOV ; Is the XMA page address below the | ||
| 684 | CMP BX,AX ; MOVEBLOCK buffer address? | ||
| 685 | JB ENABLED ; Yup. Whew! Let's go set up the page | ||
| 686 | ; table entry for this XMA block. | ||
| 687 | JMP EMPTY ; Nope. Rats! Well, we'll just have | ||
| 688 | ; to point this TT entry to unbacked | ||
| 689 | ; memory. | ||
| 690 | |||
| 691 | ; We come here when we want to disable translation for this translate table | ||
| 692 | ; entry. For TT entries for 640K and over we just point the translate table | ||
| 693 | ; entry back to real memory. For TT entries between 0K and 640K we point | ||
| 694 | ; the translate table to unbacked memory. This memory on the motherboard | ||
| 695 | ; was disabled under real XMA so we emulate it by pointing to unbacked | ||
| 696 | ; memory. | ||
| 697 | |||
| 698 | DISABLEPAGE: | ||
| 699 | ; XMA 1 emulation code deleted 2@D1D | ||
| 700 | CMP BYTE PTR XMATTAR,640/4 ; Is the address at 640K or above? | ||
| 701 | JNB SPECIAL ; Aye. Go point back to real memory. | ||
| 702 | |||
| 703 | ; The address is between 256K and 640K. Let's set the page table entry to | ||
| 704 | ; point to non-exiatent memory. | ||
| 705 | |||
| 706 | EMPTY: | ||
| 707 | DATAOV ; Clear EAX | ||
| 708 | SUB AX,AX | ||
| 709 | MOV AX,MAXMEM ; Get the total number of K on the box | ||
| 710 | DATAOV ; Multiply by 1024 to convert to an | ||
| 711 | SHL AX,10 ; offset. AX now points to the 4K | ||
| 712 | ; page frame after the end of memory. | ||
| 713 | OR AL,7 ; Turn on the accessed and present bits | ||
| 714 | ; to avoid page faults | ||
| 715 | DATAOV ; Save the page table entry in EBX | ||
| 716 | MOV BX,AX | ||
| 717 | JMP ENABLED ; Go set up the page table | ||
| 718 | |||
| 719 | ; If the address is above 640K then the translate table (page table) entry D1C | ||
| 720 | ; is set to point back to real memory. | ||
| 721 | SPECIAL: | ||
| 722 | MOV AX,XMATTAR ; Get the index of the TT entry that is | ||
| 723 | ; to be disabled | ||
| 724 | DATAOV ; Dump the high 24 bits off the left end | ||
| 725 | SHL AX,24 ; of the register | ||
| 726 | DATAOV ; Now shift it back 12 bits. This | ||
| 727 | SHR AX,24-12 ; results in a net shift left of 12 | ||
| 728 | ; bits which multiplies the TT index | ||
| 729 | ; by 4K while at the same time clear- | ||
| 730 | ; ing the high order bits. EAX is now | ||
| 731 | ; the offset of the memory pointed to | ||
| 732 | ; by the TT entry. | ||
| 733 | OR AL,7 ; Turn on the accessed and present bits | ||
| 734 | ; to make this a page table entry | ||
| 735 | DATAOV ; Save the page table entry in EBX | ||
| 736 | MOV BX,AX | ||
| 737 | |||
| 738 | ; Now let's put the new page table entry in EBX, which represents the XMA block, | ||
| 739 | ; into the page table. | ||
| 740 | ENABLED: | ||
| 741 | MOV AX,XMATTAR ; Get the index of the TT entry | ||
| 742 | |||
| 743 | ; Now we want ot convert the index of the TT entry to an offset into our XMA | ||
| 744 | ; page tables. The bank number is now in AH and the 4K block number of the | ||
| 745 | ; bank is in AL. To point to the right page table we need to multiply the bank | ||
| 746 | ; number by 4K (shift left 12 bits) since page tables are 4K in length. The | ||
| 747 | ; bank number is already shifted left 8 bits by virtue of it being in AH. It | ||
| 748 | ; needs to be shifted left four more bits. In order to access the right entry | ||
| 749 | ; in the page table, the block number in AL must be multiplied by 4 (shifted | ||
| 750 | ; left two bits) because the page table entries are 4 bytes in length. So, | ||
| 751 | ; first we shift AH left two bits and then shift AX left two bits. In the end | ||
| 752 | ; this shifts AH, the bank ID, left four bits and shifts AL, the block number, | ||
| 753 | ; two bits, which is what we wanted. A long explanation for two instructions, | ||
| 754 | ; but they're pretty efficient, don't you think? | ||
| 755 | |||
| 756 | SHL AH,2 ; Shift the bank ID left two bits | ||
| 757 | SHL AX,2 ; Shift the bank ID and the block number | ||
| 758 | ; left two bits | ||
| 759 | MOV DI,AX ; Load DI with the offset of the page | ||
| 760 | ; table entry that is to be changed | ||
| 761 | PUSH ES ; Save ES | ||
| 762 | MOV AX,XMA_PAGES_SEL ; Load ES with the selector for our | ||
| 763 | MOV ES,AX ; XMA page tables. Now ES:DI points | ||
| 764 | ; to the page table entry to be | ||
| 765 | ; changed | ||
| 766 | DATAOV ; Get the new value for the page table | ||
| 767 | MOV AX,BX ; entry which was saved in EBX. | ||
| 768 | DATAOV ; Stuff it into the page table - all | ||
| 769 | STOSW ; 32 bits of it. | ||
| 770 | |||
| 771 | POP ES ; Restore ES | ||
| 772 | |||
| 773 | RET ; And return | ||
| 774 | |||
| 775 | UPDATETT ENDP | ||
| 776 | |||
| 777 | XMAIN ENDP | ||
| 778 | |||
| 779 | PROG ENDS | ||
| 780 | |||
| 781 | END | ||
diff --git a/v4.0/src/DEV/XMAEM/INDEXMAE.SYS b/v4.0/src/DEV/XMAEM/INDEXMAE.SYS new file mode 100644 index 0000000..d0fd31a --- /dev/null +++ b/v4.0/src/DEV/XMAEM/INDEXMAE.SYS | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | MZ% | ||
| 2 | +V386XMAEM#86XMAEMULATOR11...(û&?t.(PSQRWVU.*.(f`.G<w3.6 | ||
| 3 | G.>*t | ||
| 4 | ]^_ZY[Xfaû& PD!G OG(G.>*tGG FE!tGG 9F!ð3.h.Ok.A.?.=5$0<0tS8Q+O-&Ȏؾhؿѹf+f+ۻ f%f+ۻf+f"f+ۻff+ãEf f>Ef+ۻ`f+fGf+ۻfff+ۻffGf+$C>Cf+f+ۻff>Cfff@ы&VO<ы&^`h؎м=6jظ*иظ؎hhUikx8GfhG=6GhG\GXGTGH.?GP.=G8G&G$.AGL|G G` fGh؋6C++xf"jPf\X=u D!u du`Q+d$Yw24t0 | ||
| 5 | t< t<,t<;t<+t<=t< u*t6.O< t< t< | ||
| 6 | <0r<9w:tu< | ||
| 7 | 3.,0.&.t.>t3f`F4t~$ u~$uF4t &F$.>S3 3 Kh+.fFFK<t譋Ѓu fFp | ||
| 8 | F⼋F4t" f+v6f+F:fff | ||
diff --git a/v4.0/src/DEV/XMAEM/MAKEFILE b/v4.0/src/DEV/XMAEM/MAKEFILE new file mode 100644 index 0000000..8aa4237 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/MAKEFILE | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | #************************ makefile for dev\xmaem************************ | ||
| 2 | |||
| 3 | msg =..\..\messages | ||
| 4 | dos =..\..\dos | ||
| 5 | inc =..\..\inc | ||
| 6 | hinc =..\..\h | ||
| 7 | |||
| 8 | # | ||
| 9 | ####################### dependencies begin here. ######################### | ||
| 10 | # | ||
| 11 | |||
| 12 | all: xmaem.sys | ||
| 13 | |||
| 14 | xmaem.ctl: xmaem.skl $(msg)\$(COUNTRY).msg makefile | ||
| 15 | nosrvbld xmaem.skl $(msg)\$(COUNTRY).msg | ||
| 16 | |||
| 17 | INDEINI.obj: INDEINI.ASM | ||
| 18 | |||
| 19 | INDEEMU.obj: INDEEMU.ASM | ||
| 20 | |||
| 21 | INDEEXC.obj: INDEEXC.ASM | ||
| 22 | |||
| 23 | INDEXMA.obj: INDEXMA.ASM | ||
| 24 | |||
| 25 | INDEDMA.obj: INDEDMA.ASM | ||
| 26 | |||
| 27 | INDEIDT.obj: INDEIDT.ASM | ||
| 28 | |||
| 29 | INDEGDT.obj: INDEGDT.ASM | ||
| 30 | |||
| 31 | INDEI15.obj: INDEI15.ASM | ||
| 32 | |||
| 33 | INDEmsg.obj: INDEmsg.ASM xmaem.ctl | ||
| 34 | |||
| 35 | INDEpat.obj: INDEpat.ASM | ||
| 36 | |||
| 37 | xmaem.sys: makefile \ | ||
| 38 | xmaem.ctl \ | ||
| 39 | INDEINI.obj \ | ||
| 40 | INDEEMU.obj \ | ||
| 41 | INDEEXC.obj \ | ||
| 42 | INDEXMA.obj \ | ||
| 43 | INDEDMA.obj \ | ||
| 44 | INDEIDT.obj \ | ||
| 45 | INDEGDT.obj \ | ||
| 46 | INDEI15.obj \ | ||
| 47 | indemaus.obj \ | ||
| 48 | indemsus.inc \ | ||
| 49 | indeovp.mac \ | ||
| 50 | indeins.mac \ | ||
| 51 | indedes.mac \ | ||
| 52 | indemsg.obj \ | ||
| 53 | indepat.obj \ | ||
| 54 | indedat.inc \ | ||
| 55 | indeacc.inc \ | ||
| 56 | xmaem.lnk | ||
| 57 | link @xmaem.lnk | ||
diff --git a/v4.0/src/DEV/XMAEM/XMAEM.ARF b/v4.0/src/DEV/XMAEM/XMAEM.ARF new file mode 100644 index 0000000..acbb2e7 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/XMAEM.ARF | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | INDEINI+ | ||
| 2 | INDEEXC+ | ||
| 3 | INDEEMU+ | ||
| 4 | INDEXMA+ | ||
| 5 | INDEDMA+ | ||
| 6 | INDEI15+ | ||
| 7 | INDEIDT+ | ||
| 8 | INDEGDT+ | ||
| 9 | INDEMSG+ | ||
| 10 | INDEPAT | ||
| 11 | xmaem.sys | ||
| 12 | nul; | ||
| 13 | \ No newline at end of file | ||
diff --git a/v4.0/src/DEV/XMAEM/XMAEM.LC b/v4.0/src/DEV/XMAEM/XMAEM.LC new file mode 100644 index 0000000..37c45f4 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/XMAEM.LC | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | INDEINI.ASM | ||
| 2 | INDEEMU.ASM | ||
| 3 | INDEEXC.ASM | ||
| 4 | INDEXMA.ASM | ||
| 5 | INDEDMA.ASM | ||
| 6 | INDEIDT.ASM | ||
| 7 | INDEGDT.ASM | ||
| 8 | INDEI15.ASM | ||
| 9 | INDEMAUS.ASM | ||
| 10 | INDEMSUS.INC | ||
| 11 | INDEDAT.INC | ||
| 12 | INDEACC.INC | ||
| 13 | INDEOVP.MAC | ||
| 14 | INDEINS.MAC | ||
| 15 | INDEDES.MAC | ||
| 16 | INDEMSUS.ASM | ||
| 17 | INDEMSG.ASM | ||
| 18 | INDEPAT.ASM | ||
| 19 | \ No newline at end of file | ||
diff --git a/v4.0/src/DEV/XMAEM/XMAEM.LNK b/v4.0/src/DEV/XMAEM/XMAEM.LNK new file mode 100644 index 0000000..acbb2e7 --- /dev/null +++ b/v4.0/src/DEV/XMAEM/XMAEM.LNK | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | INDEINI+ | ||
| 2 | INDEEXC+ | ||
| 3 | INDEEMU+ | ||
| 4 | INDEXMA+ | ||
| 5 | INDEDMA+ | ||
| 6 | INDEI15+ | ||
| 7 | INDEIDT+ | ||
| 8 | INDEGDT+ | ||
| 9 | INDEMSG+ | ||
| 10 | INDEPAT | ||
| 11 | xmaem.sys | ||
| 12 | nul; | ||
| 13 | \ No newline at end of file | ||
diff --git a/v4.0/src/DEV/XMAEM/XMAEM.MAK b/v4.0/src/DEV/XMAEM/XMAEM.MAK new file mode 100644 index 0000000..35e6b1b --- /dev/null +++ b/v4.0/src/DEV/XMAEM/XMAEM.MAK | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | COM=G:\COMMON | ||
| 2 | MSG=G:\MESSAGES | ||
| 3 | |||
| 4 | # | ||
| 5 | |||
| 6 | xmaem.cl1: xmaem.skl \ | ||
| 7 | $(MSG)\$(country).MSG \ | ||
| 8 | xmaem.mak | ||
| 9 | nosrvbld xmaem.skl $(MSG)\$(country).msg | ||
| 10 | |||
| 11 | INDEINI.obj: INDEINI.ASM | ||
| 12 | asm87 INDEINI | ||
| 13 | |||
| 14 | INDEEMU.obj: INDEEMU.ASM | ||
| 15 | asm87 INDEEMU | ||
| 16 | |||
| 17 | INDEEXC.obj: INDEEXC.ASM | ||
| 18 | asm87 INDEEXC | ||
| 19 | |||
| 20 | INDEXMA.obj: INDEXMA.ASM | ||
| 21 | asm87 INDEXMA | ||
| 22 | |||
| 23 | INDEDMA.obj: INDEDMA.ASM | ||
| 24 | asm87 INDEDMA | ||
| 25 | |||
| 26 | INDEIDT.obj: INDEIDT.ASM | ||
| 27 | asm87 INDEIDT | ||
| 28 | |||
| 29 | INDEGDT.obj: INDEGDT.ASM | ||
| 30 | asm87 INDEGDT | ||
| 31 | |||
| 32 | INDEI15.obj: INDEI15.ASM | ||
| 33 | asm87 INDEI15 | ||
| 34 | |||
| 35 | INDEmsg.obj: INDEmsg.ASM \ | ||
| 36 | xmaem.cl1 | ||
| 37 | asm87 INDEmsg | ||
| 38 | |||
| 39 | INDEpat.obj: INDEpat.ASM | ||
| 40 | asm87 INDEpat | ||
| 41 | |||
| 42 | |||
| 43 | xmaem.sys: g:\common\setver.bat \ | ||
| 44 | XMAEM.MAK \ | ||
| 45 | INDEINI.asm \ | ||
| 46 | INDEEMU.asm \ | ||
| 47 | INDEEXC.asm \ | ||
| 48 | INDEXMA.asm \ | ||
| 49 | INDEDMA.asm \ | ||
| 50 | INDEIDT.asm \ | ||
| 51 | INDEGDT.asm \ | ||
| 52 | INDEI15.asm \ | ||
| 53 | indemaus.asm \ | ||
| 54 | indemsus.inc \ | ||
| 55 | indeovp.mac \ | ||
| 56 | indeins.mac \ | ||
| 57 | indedes.mac \ | ||
| 58 | indemsus.asm \ | ||
| 59 | indemsg.asm \ | ||
| 60 | indepat.asm \ | ||
| 61 | indedat.inc \ | ||
| 62 | indeacc.inc \ | ||
| 63 | xmaem.arf | ||
| 64 | link @xmaem.arf | ||
| 65 | tag xmaem.sys | ||
| 66 | \ No newline at end of file | ||
diff --git a/v4.0/src/DEV/XMAEM/XMAEM.SKL b/v4.0/src/DEV/XMAEM/XMAEM.SKL new file mode 100644 index 0000000..6275a6c --- /dev/null +++ b/v4.0/src/DEV/XMAEM/XMAEM.SKL | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | :class 1 | ||
| 2 | |||
| 3 | :use 1 xmaem Welcome | ||
| 4 | :use 2 xmaem GoodLoad | ||
| 5 | :use 3 xmaem No_80386 | ||
| 6 | :use 4 xmaem Was_Inst | ||
| 7 | :use 5 xmaem Small_Parm | ||
| 8 | :use 6 xmaem No_Mem | ||
| 9 | |||
| 10 | :end | ||
| 11 | |||
| 12 | |||
| 13 | |||
| 14 | |||
| 15 | |||
| 16 | \ No newline at end of file | ||