| 1 | ;
|
|---|
| 2 | ; RMINT.ASM -- Initialize interrupts and handle real-mode interrupts
|
|---|
| 3 | ;
|
|---|
| 4 | ; Copyright (c) 1991-1995 by Eberhard Mattes
|
|---|
| 5 | ;
|
|---|
| 6 | ; This file is part of emx.
|
|---|
| 7 | ;
|
|---|
| 8 | ; emx is free software; you can redistribute it and/or modify it
|
|---|
| 9 | ; under the terms of the GNU General Public License as published by
|
|---|
| 10 | ; the Free Software Foundation; either version 2, or (at your option)
|
|---|
| 11 | ; any later version.
|
|---|
| 12 | ;
|
|---|
| 13 | ; emx is distributed in the hope that it will be useful,
|
|---|
| 14 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 15 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 16 | ; GNU General Public License for more details.
|
|---|
| 17 | ;
|
|---|
| 18 | ; You should have received a copy of the GNU General Public License
|
|---|
| 19 | ; along with emx; see the file COPYING. If not, write to
|
|---|
| 20 | ; the Free Software Foundation, 59 Temple Place - Suite 330,
|
|---|
| 21 | ; Boston, MA 02111-1307, USA.
|
|---|
| 22 | ;
|
|---|
| 23 | ; See emx.asm for a special exception.
|
|---|
| 24 | ;
|
|---|
| 25 |
|
|---|
| 26 | INCLUDE EMX.INC
|
|---|
| 27 | INCLUDE TABLES.INC
|
|---|
| 28 | INCLUDE VCPI.INC
|
|---|
| 29 | INCLUDE PMINT.INC
|
|---|
| 30 | INCLUDE EXCEPT.INC
|
|---|
| 31 | INCLUDE RPRINT.INC
|
|---|
| 32 | INCLUDE SIGNAL.INC
|
|---|
| 33 | INCLUDE PROCESS.INC
|
|---|
| 34 | INCLUDE OPTIONS.INC
|
|---|
| 35 | INCLUDE MISC.INC
|
|---|
| 36 |
|
|---|
| 37 | PUBLIC INIT_INT, CLEANUP_INT, INIT_TIMER, CLEANUP_TIMER
|
|---|
| 38 | PUBLIC SET_RM_INT, RESTORE_RM_INT
|
|---|
| 39 |
|
|---|
| 40 | RM_DEBUGGER = FALSE
|
|---|
| 41 |
|
|---|
| 42 | ;
|
|---|
| 43 | ; The interrupt redirection machinery has four states:
|
|---|
| 44 | ;
|
|---|
| 45 | ; - IC_NOT
|
|---|
| 46 | ; This is the initial state: interrupt vectors have not been
|
|---|
| 47 | ; changed yet. Do not restore interrupt vectors on exit!
|
|---|
| 48 | ;
|
|---|
| 49 | ; - IC_VCPI_SERVER
|
|---|
| 50 | ; There is a VCPI server (EMS emulator) which has already reprogrammed
|
|---|
| 51 | ; the interrupt controller to redirect hardware interrupts. Or a
|
|---|
| 52 | ; different client of the VCPI server has redirected the hardware
|
|---|
| 53 | ; interrupts. This is the simple case as we don't have to touch
|
|---|
| 54 | ; the interrupt controller.
|
|---|
| 55 | ;
|
|---|
| 56 | ; - IC_VCPI_CLIENT
|
|---|
| 57 | ; There is a VCPI server (EMS emulator) which hasn't reprogrammed
|
|---|
| 58 | ; the interrupt controller. We have to reprogram the interrupt
|
|---|
| 59 | ; controller in order to distinguish hardware interrupts from
|
|---|
| 60 | ; processor exceptions. PC design flaw...
|
|---|
| 61 | ;
|
|---|
| 62 | ; - IC_MYSELF
|
|---|
| 63 | ; There is no VCPI server (EMS emulator). We have to reprogram the
|
|---|
| 64 | ; interrupt controller in order to distinguish hardware interrupts from
|
|---|
| 65 | ; processor exceptions. PC design flaw...
|
|---|
| 66 | ;
|
|---|
| 67 |
|
|---|
| 68 | IC_NOT = 0 ; Interrupt vectors not changed
|
|---|
| 69 | IC_VCPI_SERVER = 1 ; VCPI server has changed vectors
|
|---|
| 70 | IC_VCPI_CLIENT = 2 ; VCPI server hasn't changed vectors
|
|---|
| 71 | IC_MYSELF = 3 ; This program has changed vectors
|
|---|
| 72 |
|
|---|
| 73 |
|
|---|
| 74 |
|
|---|
| 75 | SV_DATA SEGMENT
|
|---|
| 76 |
|
|---|
| 77 | IF RM_DEBUGGER
|
|---|
| 78 | ;
|
|---|
| 79 | ; The original debug interrupt vectors.
|
|---|
| 80 | ;
|
|---|
| 81 | OLD_RM_INT01_OFF DW ?
|
|---|
| 82 | OLD_RM_INT01_SEG DW ?
|
|---|
| 83 |
|
|---|
| 84 | OLD_RM_INT03_OFF DW ?
|
|---|
| 85 | OLD_RM_INT03_SEG DW ?
|
|---|
| 86 |
|
|---|
| 87 | ENDIF
|
|---|
| 88 |
|
|---|
| 89 | ;
|
|---|
| 90 | ;
|
|---|
| 91 | ; The original interrupt vectors IRQ0_BASE .. IRQ0_BASE+7.
|
|---|
| 92 | ;
|
|---|
| 93 | SAVED_IVECS DD 8 DUP (?)
|
|---|
| 94 |
|
|---|
| 95 | ;
|
|---|
| 96 | ; Check the interrupt vectors in this table in this sequence for
|
|---|
| 97 | ; 8 successive unused interrupts vectors. The first entry should
|
|---|
| 98 | ; be the safest, the last the most dangerous. But all vectors
|
|---|
| 99 | ; are checked, so that nothing evil should happen if a vector
|
|---|
| 100 | ; is already in use. The danger is that some other program may
|
|---|
| 101 | ; change an interrupt vector used by this program for redirecting
|
|---|
| 102 | ; a hardware interrupt. This would cause a system crash.
|
|---|
| 103 | ;
|
|---|
| 104 | UNUSED_INT_TAB DB 50H, 88H, 90H, 98H
|
|---|
| 105 | DB 0A8H, 0B8H, 0C0H, 0C8H, 0D0H, 0D8H
|
|---|
| 106 | DB 80H, 0A0H, 0B0H, 0E0H, 0E8H, 38H, 78H, 58H, 0F0H
|
|---|
| 107 | DB 00H
|
|---|
| 108 |
|
|---|
| 109 | ;
|
|---|
| 110 | ; These are the offsets for the new interrupt vectors used for IRQ0..IRQ7.
|
|---|
| 111 | ; The code at that address just issues INT 08H .. INT 0FH.
|
|---|
| 112 | ;
|
|---|
| 113 | NEW_IVECS DW HWINT0, HWINT1, HWINT2, HWINT3
|
|---|
| 114 | DW HWINT4, HWINT5, HWINT6, HWINT7
|
|---|
| 115 |
|
|---|
| 116 | ;
|
|---|
| 117 | ; These are the first interrupt vector used for redirecting IRQ0..IRQ7
|
|---|
| 118 | ; and IRQ8..IRQ15, respectively.
|
|---|
| 119 | ;
|
|---|
| 120 | IRQ0_BASE DB ?
|
|---|
| 121 | IRQ8_BASE DB ?
|
|---|
| 122 |
|
|---|
| 123 | ;
|
|---|
| 124 | ; This is the interrupt redirection status.
|
|---|
| 125 | ;
|
|---|
| 126 | INT_CHANGED DB IC_NOT
|
|---|
| 127 | ;
|
|---|
| 128 | ; This is the future interrupt redirection status.
|
|---|
| 129 | ;
|
|---|
| 130 | NEW_INT_CHANGED DB IC_NOT
|
|---|
| 131 |
|
|---|
| 132 | ;
|
|---|
| 133 | ; This message should never be required: The VCPI server (or one of its
|
|---|
| 134 | ; clients) has changed the interrupt vectors. But that mappings aren't
|
|---|
| 135 | ; usable.
|
|---|
| 136 | ;
|
|---|
| 137 | $BAD_VCPI DB "Unusable interrupt vector mappings set by VCPI server", CR, LF, 0
|
|---|
| 138 |
|
|---|
| 139 | IF RM_DEBUGGER
|
|---|
| 140 | ;
|
|---|
| 141 | ; There's no real-mode debugger
|
|---|
| 142 | ;
|
|---|
| 143 | $RM_DEBUG DB "Real-mode breakpoint at ", 0
|
|---|
| 144 |
|
|---|
| 145 | ENDIF
|
|---|
| 146 |
|
|---|
| 147 | SV_DATA ENDS
|
|---|
| 148 |
|
|---|
| 149 |
|
|---|
| 150 | INIT_CODE SEGMENT
|
|---|
| 151 |
|
|---|
| 152 | ASSUME CS:INIT_CODE, DS:NOTHING
|
|---|
| 153 |
|
|---|
| 154 | ;
|
|---|
| 155 | ; The original timer interrupt vector. This is in the code segment because
|
|---|
| 156 | ; we need OLD_RM_INT1C for jumping to the next interrupt handler in the
|
|---|
| 157 | ; chain.
|
|---|
| 158 | ;
|
|---|
| 159 | OLD_RM_INT1C LABEL DWORD
|
|---|
| 160 | OLD_RM_INT1C_OFF DW ?
|
|---|
| 161 | OLD_RM_INT1C_SEG DW ?
|
|---|
| 162 | OLD_RM_INT1C_FLAG DB FALSE
|
|---|
| 163 |
|
|---|
| 164 |
|
|---|
| 165 | ;
|
|---|
| 166 | ; Redirect hardware interrupt IRQ X to real-mode interrupt Y
|
|---|
| 167 | ;
|
|---|
| 168 | ASSUME DS:NOTHING
|
|---|
| 169 | HWINTX MACRO X,Y
|
|---|
| 170 | TALIGN 2
|
|---|
| 171 | HWINT&X: INT Y ; Issue software interrupt
|
|---|
| 172 | IRET ; Return
|
|---|
| 173 | ENDM
|
|---|
| 174 | ;
|
|---|
| 175 | ; Redirect IRQ 0 (-> INT 08H) to IRQ 7 (-> INT 0FH)
|
|---|
| 176 | ;
|
|---|
| 177 | IRPC X, <01234567>
|
|---|
| 178 | HWINTX X, %&X+8
|
|---|
| 179 | ENDM
|
|---|
| 180 |
|
|---|
| 181 |
|
|---|
| 182 | ;
|
|---|
| 183 | ; Access rights for 32-bit interrupt gates
|
|---|
| 184 | ;
|
|---|
| 185 | INT_GATE_0 = 08EH ; DPL=0 (hardware interrupt)
|
|---|
| 186 | INT_GATE_1 = 0AEH ; DPL=1
|
|---|
| 187 | INT_GATE_2 = 0CEH ; DPL=2
|
|---|
| 188 | INT_GATE_3 = 0EEH ; DPL=3 (software interrupt)
|
|---|
| 189 |
|
|---|
| 190 |
|
|---|
| 191 | ;
|
|---|
| 192 | ; Initialize IDT, redirect hardware interrupts
|
|---|
| 193 | ;
|
|---|
| 194 | ; This procedure is also called after spawning a DOS program
|
|---|
| 195 | ;
|
|---|
| 196 |
|
|---|
| 197 | ASSUME DS:SV_DATA
|
|---|
| 198 |
|
|---|
| 199 | TALIGN 2
|
|---|
| 200 | INIT_INT PROC NEAR
|
|---|
| 201 | MOV IRQ0_BASE, 40H
|
|---|
| 202 | MOV IRQ8_BASE, 48H
|
|---|
| 203 | CMP MACHINE, MACH_FMR70 ; Fujitsu FMR70?
|
|---|
| 204 | JE II_TABLE ; Yes -> use above values
|
|---|
| 205 | MOV IRQ0_BASE, 40H
|
|---|
| 206 | MOV IRQ8_BASE, 48H
|
|---|
| 207 | CMP MACHINE, MACH_PC98 ; NEC PC-98?
|
|---|
| 208 | JE II_TABLE ; Yes -> use above values
|
|---|
| 209 | MOV IRQ8_BASE, 70H ; The standard configuration
|
|---|
| 210 | MOV NEW_INT_CHANGED, IC_MYSELF
|
|---|
| 211 | CMP VCPI_FLAG, FALSE ; Use VCPI?
|
|---|
| 212 | JE SHORT II_CHECK_INT ; No -> redirect interrupts
|
|---|
| 213 | CALL GET_INT_MAP ; Get interrupt vector mappings
|
|---|
| 214 | MOV IRQ0_BASE, BL ; Controller 1 address
|
|---|
| 215 | MOV IRQ8_BASE, CL ; Controller 2 address
|
|---|
| 216 | CMP BL, 17 ; Conflict with exceptions?
|
|---|
| 217 | JBE SHORT II_NEED_REMAP ; Yes -> remapping required
|
|---|
| 218 | CMP CL, 17 ; Conflict with exceptions?
|
|---|
| 219 | JBE SHORT II_NEED_REMAP ; Yes -> remapping required
|
|---|
| 220 | ;
|
|---|
| 221 | ; Interrupt vector mapping is usable, VCPI server has done this.
|
|---|
| 222 | ;
|
|---|
| 223 | MOV NEW_INT_CHANGED, IC_VCPI_SERVER
|
|---|
| 224 | JMP SHORT II_TABLE ; VCPI server has done the work
|
|---|
| 225 |
|
|---|
| 226 | II_NEED_REMAP: CMP BL, 08H ; Standard configuration?
|
|---|
| 227 | JNE II_ERROR ; No -> almost impossible
|
|---|
| 228 | CMP CL, 70H ; Standard configuration?
|
|---|
| 229 | JNE II_ERROR ; No -> almost impossible
|
|---|
| 230 | MOV NEW_INT_CHANGED, IC_VCPI_CLIENT
|
|---|
| 231 | JMP SHORT II_MYSELF
|
|---|
| 232 |
|
|---|
| 233 | ;
|
|---|
| 234 | ; There may be programs which redirect IRQ0..IRQ7. As we're not
|
|---|
| 235 | ; running under a VCPI server, we should find this out by hand.
|
|---|
| 236 | ; Here's how:
|
|---|
| 237 | ; - save all the interrupt vectors
|
|---|
| 238 | ; - setup 256 *different* interrupt handlers
|
|---|
| 239 | ; - set a variable V in the code segment to some number I unequal 0..255
|
|---|
| 240 | ; - each handler stores its vector number to V if V equals I
|
|---|
| 241 | ; (this must be done in an atomic operation) and then jumps to the
|
|---|
| 242 | ; original handler for that interrupt vector
|
|---|
| 243 | ; - the main program loops until V != I or a loop counter expires
|
|---|
| 244 | ; - restore interrupt vectors
|
|---|
| 245 | ; - if V == 8, we have the original mapping
|
|---|
| 246 | ; Actually, we aren't doing all this. It isn't worth the trouble.
|
|---|
| 247 | ; There's an explicit check for DESQview in VCPI.ASM, instead.
|
|---|
| 248 | ;
|
|---|
| 249 | II_CHECK_INT:
|
|---|
| 250 |
|
|---|
| 251 | ;
|
|---|
| 252 | ; We have to redirect hardware interrupts. Find 8 sucessive unused
|
|---|
| 253 | ; interrupt vectors for redirecting IRQ0..IRQ7.
|
|---|
| 254 | ;
|
|---|
| 255 | II_MYSELF: LEA SI, UNUSED_INT_TAB ; Table of vectors to check
|
|---|
| 256 | XOR AX, AX ; AH:=0
|
|---|
| 257 | MOV ES, AX ; Access interrupt table
|
|---|
| 258 | II_FIND_1: LODS UNUSED_INT_TAB ; Get interupt vector
|
|---|
| 259 | OR AL, AL ; End of table?
|
|---|
| 260 | JZ SHORT II_FIND_FAIL ; Yes -> be brutal
|
|---|
| 261 | MOV BX, AX ; AH=0
|
|---|
| 262 | SHL BX, 2 ; Compute address of vector
|
|---|
| 263 | MOV EDX, ES:[BX] ; Fetch first vector
|
|---|
| 264 | MOV CX, 7 ; Compare to the following 7
|
|---|
| 265 | II_FIND_2: ADD BX, 4 ; Next vector
|
|---|
| 266 | CMP EDX, ES:[BX] ; Same as first vector?
|
|---|
| 267 | JNE II_FIND_1 ; No -> try next table entry
|
|---|
| 268 | LOOP II_FIND_2 ; Repeat for 7 vectors
|
|---|
| 269 | MOV IRQ0_BASE, AL ; Use this vector
|
|---|
| 270 | JMP SHORT II_TABLE ; Continue
|
|---|
| 271 |
|
|---|
| 272 | ;
|
|---|
| 273 | ; No unused interrupt vectors found. We don't have mercy and use some
|
|---|
| 274 | ; interrupt vectors reserved for BASIC. Starting BASIC while this
|
|---|
| 275 | ; program is running will cause a system crash.
|
|---|
| 276 | ;
|
|---|
| 277 | II_FIND_FAIL: MOV IRQ0_BASE, 0D0H
|
|---|
| 278 |
|
|---|
| 279 | ;
|
|---|
| 280 | ; Initialize all IDT entries.
|
|---|
| 281 | ;
|
|---|
| 282 | II_TABLE: LEA DI, IDT+0
|
|---|
| 283 | MOV CX, 256
|
|---|
| 284 | MOV AL, INT_GATE_0
|
|---|
| 285 | MOV DX, OFFSET SV_CODE:INTERRUPT
|
|---|
| 286 | II_UNUSED_1: CALL SET_INT_GATE
|
|---|
| 287 | ADD DI, 8
|
|---|
| 288 | LOOP II_UNUSED_1
|
|---|
| 289 | ;
|
|---|
| 290 | ; Put exceptions into IDT.
|
|---|
| 291 | ;
|
|---|
| 292 | ; Use interrupt gate instead of trap gate to disable interrupts
|
|---|
| 293 | ;
|
|---|
| 294 | LEA SI, EXC_TAB ; Table of handlers
|
|---|
| 295 | II_EXC_1: LODS EXC_TAB ; Get exception number
|
|---|
| 296 | CMP AX, 0FFFFH ; End of table?
|
|---|
| 297 | JE SHORT II_EXC_3
|
|---|
| 298 | MOV BX, AX
|
|---|
| 299 | SHL AX, 3 ; Compute offset into IDT
|
|---|
| 300 | LEA DI, IDT
|
|---|
| 301 | ADD DI, AX ; Compute pointer into IDT
|
|---|
| 302 | LODS EXC_TAB ; Get offset of handler
|
|---|
| 303 | MOV DX, AX
|
|---|
| 304 | MOV AL, INT_GATE_0 ; Interrupt gate, DPL=0
|
|---|
| 305 | CMP BL, 3 ; Breakpoint?
|
|---|
| 306 | JNE SHORT II_EXC_2 ; No -> use DPL=0
|
|---|
| 307 | MOV AL, INT_GATE_3 ; Use DPL=3 (for breakpoints)
|
|---|
| 308 | II_EXC_2: CALL SET_INT_GATE ; Insert into IDT
|
|---|
| 309 | JMP SHORT II_EXC_1 ; Repeat for all table entries
|
|---|
| 310 | II_EXC_3:
|
|---|
| 311 | ;
|
|---|
| 312 | ; Put task gates for exceptions 8 & 10 into IDT.
|
|---|
| 313 | ;
|
|---|
| 314 | LEA DI, IDT+8*8
|
|---|
| 315 | MOV AX, G_TSS_EX8_SEL
|
|---|
| 316 | CALL SET_TASK_GATE
|
|---|
| 317 | LEA DI, IDT+10*8
|
|---|
| 318 | MOV AX, G_TSS_EX10_SEL
|
|---|
| 319 | CALL SET_TASK_GATE
|
|---|
| 320 | ;
|
|---|
| 321 | ; Put hardware interrupts into IDT.
|
|---|
| 322 | ;
|
|---|
| 323 | LEA SI, PMINT0_TAB
|
|---|
| 324 | MOVZX BX, IRQ0_BASE
|
|---|
| 325 | CALL PUT_HW_INT
|
|---|
| 326 | LEA SI, PMINT8_TAB
|
|---|
| 327 | MOVZX BX, IRQ8_BASE
|
|---|
| 328 | CALL PUT_HW_INT
|
|---|
| 329 | ;
|
|---|
| 330 | ; Put software interrupts into IDT.
|
|---|
| 331 | ;
|
|---|
| 332 | IRP SWINT, <10H, 11H, 14H, 16H, 17H, 21H, 31H, 33H>
|
|---|
| 333 | LEA DI, IDT + SWINT*8
|
|---|
| 334 | MOV DX, OFFSET SV_CODE:PMINT_&SWINT
|
|---|
| 335 | MOV AL, INT_GATE_3
|
|---|
| 336 | CALL SET_INT_GATE
|
|---|
| 337 | ENDM
|
|---|
| 338 | ;
|
|---|
| 339 | ; Setup debug interrupt
|
|---|
| 340 | ;
|
|---|
| 341 | IF RM_DEBUGGER
|
|---|
| 342 | LEA DX, RM_DEBUG
|
|---|
| 343 | MOV AL, 01H
|
|---|
| 344 | CALL SET_RM_INT
|
|---|
| 345 | MOV OLD_RM_INT01_OFF, DX
|
|---|
| 346 | MOV OLD_RM_INT01_SEG, AX
|
|---|
| 347 | LEA DX, RM_DEBUG
|
|---|
| 348 | MOV AL, 03H
|
|---|
| 349 | CALL SET_RM_INT
|
|---|
| 350 | MOV OLD_RM_INT03_OFF, DX
|
|---|
| 351 | MOV OLD_RM_INT03_SEG, AX
|
|---|
| 352 | ENDIF
|
|---|
| 353 | ;
|
|---|
| 354 | ; Copy IRQ0_BASE and IRQ8_BASE to IRQ0_ADD and IRQ8_ADD (in the SV_CODE
|
|---|
| 355 | ; segment), respectively, to make them accessible in the protected-mode
|
|---|
| 356 | ; interrupt handler without setting any segment register (CS will be set
|
|---|
| 357 | ; automatically to SV_CODE_SEL).
|
|---|
| 358 | ;
|
|---|
| 359 | MOV AX, SV_CODE ; Used for setting IRQ0_ADD
|
|---|
| 360 | MOV ES, AX ; and IRQ8_ADD
|
|---|
| 361 | ASSUME ES:SV_CODE
|
|---|
| 362 | MOV AL, IRQ0_BASE
|
|---|
| 363 | MOV IRQ0_ADD, AL ; Set IRQ0_ADD
|
|---|
| 364 | MOV AL, IRQ8_BASE
|
|---|
| 365 | MOV IRQ8_ADD, AL ; Set IRQ8_ADD
|
|---|
| 366 | ASSUME ES:NOTHING ; Access to SV_CODE finished
|
|---|
| 367 | ;
|
|---|
| 368 | ; Redirect hardware interrupts if required: reprogram interrupt controller 1
|
|---|
| 369 | ; and notify VCPI server (if present).
|
|---|
| 370 | ;
|
|---|
| 371 | CLI
|
|---|
| 372 | CMP NEW_INT_CHANGED, IC_MYSELF
|
|---|
| 373 | JNE SHORT II_REDIR_1
|
|---|
| 374 | CALL REDIR_INT_VEC
|
|---|
| 375 | MOV CL, IRQ0_BASE
|
|---|
| 376 | CALL SET_HW_INT_BASE
|
|---|
| 377 | JMP SHORT II_REDIR_END
|
|---|
| 378 |
|
|---|
| 379 | II_REDIR_1: CMP NEW_INT_CHANGED, IC_VCPI_CLIENT
|
|---|
| 380 | JNE SHORT II_REDIR_END
|
|---|
| 381 | CALL REDIR_INT_VEC
|
|---|
| 382 | MOV CL, IRQ0_BASE
|
|---|
| 383 | CALL SET_HW_INT_BASE
|
|---|
| 384 | MOVZX BX, IRQ0_BASE
|
|---|
| 385 | MOVZX CX, IRQ8_BASE ; This is always 70H
|
|---|
| 386 | CALL SET_INT_MAP ; Inform VCPI server
|
|---|
| 387 | ;
|
|---|
| 388 | ; Now we can copy NEW_INT_CHANGED to INT_CHANGED.
|
|---|
| 389 | ;
|
|---|
| 390 | II_REDIR_END: MOV AL, NEW_INT_CHANGED
|
|---|
| 391 | MOV INT_CHANGED, AL
|
|---|
| 392 | RET
|
|---|
| 393 |
|
|---|
| 394 | ;
|
|---|
| 395 | ; We cannot cooperate with a buggy VCPI server; give up.
|
|---|
| 396 | ;
|
|---|
| 397 | II_ERROR: LEA DX, $BAD_VCPI
|
|---|
| 398 | CALL RTEXT
|
|---|
| 399 | MOV AL, 0FFH
|
|---|
| 400 | JMP EXIT
|
|---|
| 401 |
|
|---|
| 402 | INIT_INT ENDP
|
|---|
| 403 |
|
|---|
| 404 | ;
|
|---|
| 405 | ; Put hardware interrupts into IDT
|
|---|
| 406 | ;
|
|---|
| 407 | ; In: BX First interrupt number
|
|---|
| 408 | ; DS:SI Table of vectors
|
|---|
| 409 | ;
|
|---|
| 410 | ASSUME DS:SV_DATA
|
|---|
| 411 | PUT_HW_INT PROC NEAR
|
|---|
| 412 | SHL BX, 3
|
|---|
| 413 | LEA DI, IDT[BX]
|
|---|
| 414 | MOV CX, 8
|
|---|
| 415 | PHI_1: LODS PMINT0_TAB ; ...or PMINT8_TAB
|
|---|
| 416 | MOV DX, AX
|
|---|
| 417 | MOV AL, INT_GATE_0 ; Not accessible from ring 3
|
|---|
| 418 | CALL SET_INT_GATE
|
|---|
| 419 | ADD DI, 8
|
|---|
| 420 | LOOP PHI_1
|
|---|
| 421 | RET
|
|---|
| 422 | PUT_HW_INT ENDP
|
|---|
| 423 |
|
|---|
| 424 | ;
|
|---|
| 425 | ; Put interrupt gate (disables interrupts) into IDT
|
|---|
| 426 | ;
|
|---|
| 427 | ; In: DS:DI Pointer to IDT entry
|
|---|
| 428 | ; DX Offset of interrupt routine (SV_CODE:DX)
|
|---|
| 429 | ; AL INT_GATE_0 ... INT_GATE_3
|
|---|
| 430 | ;
|
|---|
| 431 | ASSUME DS:NOTHING
|
|---|
| 432 |
|
|---|
| 433 | SET_INT_GATE PROC NEAR
|
|---|
| 434 | MOV WORD PTR [DI+0], DX
|
|---|
| 435 | MOV WORD PTR [DI+2], G_SV_CODE_SEL
|
|---|
| 436 | MOV BYTE PTR [DI+4], 0
|
|---|
| 437 | MOV BYTE PTR [DI+5], AL
|
|---|
| 438 | MOV WORD PTR [DI+6], 0
|
|---|
| 439 | RET
|
|---|
| 440 | SET_INT_GATE ENDP
|
|---|
| 441 |
|
|---|
| 442 |
|
|---|
| 443 | ;
|
|---|
| 444 | ; Put task gate into IDT
|
|---|
| 445 | ;
|
|---|
| 446 | ; In: DS:DI Pointer to IDT entry
|
|---|
| 447 | ; AX TSS selector
|
|---|
| 448 | ;
|
|---|
| 449 | ASSUME DS:NOTHING
|
|---|
| 450 | SET_TASK_GATE PROC NEAR
|
|---|
| 451 | MOV WORD PTR [DI+0], 0
|
|---|
| 452 | MOV WORD PTR [DI+2], AX
|
|---|
| 453 | MOV BYTE PTR [DI+4], 0
|
|---|
| 454 | MOV BYTE PTR [DI+5], 85H
|
|---|
| 455 | MOV WORD PTR [DI+6], 0
|
|---|
| 456 | RET
|
|---|
| 457 | SET_TASK_GATE ENDP
|
|---|
| 458 |
|
|---|
| 459 |
|
|---|
| 460 | ;
|
|---|
| 461 | ; Setup real-mode interrupt vectors for redirecting IRQ0..IRQ7.
|
|---|
| 462 | ;
|
|---|
| 463 | ASSUME DS:SV_DATA
|
|---|
| 464 | REDIR_INT_VEC PROC NEAR
|
|---|
| 465 | XOR AX, AX
|
|---|
| 466 | MOV ES, AX
|
|---|
| 467 | LEA SI, NEW_IVECS
|
|---|
| 468 | LEA DI, SAVED_IVECS
|
|---|
| 469 | MOV CX, 8
|
|---|
| 470 | MOVZX BX, IRQ0_BASE
|
|---|
| 471 | SHL BX, 2
|
|---|
| 472 | II_41: MOV AX, ES:[BX+0]
|
|---|
| 473 | MOV [DI+0], AX
|
|---|
| 474 | MOV AX, ES:[BX+2]
|
|---|
| 475 | MOV [DI+2], AX
|
|---|
| 476 | MOV AX, [SI]
|
|---|
| 477 | MOV ES:[BX+0], AX
|
|---|
| 478 | MOV ES:[BX+2], CS
|
|---|
| 479 | ADD BX, 4
|
|---|
| 480 | ADD DI, 4
|
|---|
| 481 | ADD SI, 2
|
|---|
| 482 | LOOP II_41
|
|---|
| 483 | RET
|
|---|
| 484 | REDIR_INT_VEC ENDP
|
|---|
| 485 |
|
|---|
| 486 | ;
|
|---|
| 487 | ; Restore interrupt vectors
|
|---|
| 488 | ;
|
|---|
| 489 | ASSUME DS:SV_DATA
|
|---|
| 490 | RESTORE_INT_VEC PROC NEAR
|
|---|
| 491 | XOR AX, AX
|
|---|
| 492 | MOV ES, AX
|
|---|
| 493 | MOVZX DI, IRQ0_BASE
|
|---|
| 494 | SHL DI, 2
|
|---|
| 495 | LEA SI, SAVED_IVECS
|
|---|
| 496 | MOV CX, 8
|
|---|
| 497 | CLD
|
|---|
| 498 | REP MOVSD
|
|---|
| 499 | RET
|
|---|
| 500 | RESTORE_INT_VEC ENDP
|
|---|
| 501 |
|
|---|
| 502 | ;
|
|---|
| 503 | ; Delay for accessing interrupt controller registers
|
|---|
| 504 | ;
|
|---|
| 505 | IO_DELAY MACRO
|
|---|
| 506 | LOCAL SKIP
|
|---|
| 507 | JMP SHORT SKIP
|
|---|
| 508 | SKIP:
|
|---|
| 509 | ENDM
|
|---|
| 510 |
|
|---|
| 511 |
|
|---|
| 512 | ;
|
|---|
| 513 | ; Reprogram interrupt controller #1
|
|---|
| 514 | ;
|
|---|
| 515 | ; In: CL Interrupt base
|
|---|
| 516 | ;
|
|---|
| 517 | ASSUME DS:SV_DATA
|
|---|
| 518 | SET_HW_INT_BASE PROC NEAR
|
|---|
| 519 | IN AL, 21H ; Read IMR
|
|---|
| 520 | MOV AH, AL ; Save old IMR
|
|---|
| 521 | CMP MACHINE, MACH_INBOARD ; Inboard 386/PC
|
|---|
| 522 | JE SHORT SET_HIB_INB
|
|---|
| 523 | MOV AL, 11H ; ICW1
|
|---|
| 524 | OUT 20H, AL
|
|---|
| 525 | IO_DELAY
|
|---|
| 526 | MOV AL, CL ; ICW2
|
|---|
| 527 | OUT 21H, AL
|
|---|
| 528 | IO_DELAY
|
|---|
| 529 | MOV AL, 04H ; ICW3
|
|---|
| 530 | OUT 21H, AL
|
|---|
| 531 | IO_DELAY
|
|---|
| 532 | MOV AL, 01H ; ICW4
|
|---|
| 533 | OUT 21H, AL
|
|---|
| 534 | IO_DELAY
|
|---|
| 535 | SET_HIB_END: MOV AL, AH
|
|---|
| 536 | OUT 21H, AL ; Write IMR
|
|---|
| 537 | RET
|
|---|
| 538 |
|
|---|
| 539 | ;
|
|---|
| 540 | ; Use the values of the original PC for the Inboard 386/PC
|
|---|
| 541 | ;
|
|---|
| 542 | SET_HIB_INB: MOV AL, 13H ; ICW1
|
|---|
| 543 | OUT 20H,AL
|
|---|
| 544 | IO_DELAY
|
|---|
| 545 | MOV AL, CL ; ICW2
|
|---|
| 546 | OUT 21H,AL
|
|---|
| 547 | IO_DELAY
|
|---|
| 548 | MOV AL, 09H ; ICW4
|
|---|
| 549 | OUT 21H, AL
|
|---|
| 550 | JMP SHORT SET_HIB_END
|
|---|
| 551 |
|
|---|
| 552 | SET_HW_INT_BASE ENDP
|
|---|
| 553 |
|
|---|
| 554 |
|
|---|
| 555 | ;
|
|---|
| 556 | ; Install real-mode interrupt handler
|
|---|
| 557 | ;
|
|---|
| 558 | ; In: AL Interrupt number
|
|---|
| 559 | ; DX Offset of interrupt handler (CS=INIT_CODE)
|
|---|
| 560 | ;
|
|---|
| 561 | ; Out: AX Segment of original interrupt handler
|
|---|
| 562 | ; DX Offset of original interrupt handler
|
|---|
| 563 | ;
|
|---|
| 564 | ASSUME DS:NOTHING
|
|---|
| 565 | SET_RM_INT PROC NEAR
|
|---|
| 566 | PUSH DS
|
|---|
| 567 | PUSH ES
|
|---|
| 568 | PUSH BX
|
|---|
| 569 | MOV AH, 35H
|
|---|
| 570 | INT 21H
|
|---|
| 571 | PUSH CS
|
|---|
| 572 | POP DS
|
|---|
| 573 | PUSH BX
|
|---|
| 574 | PUSH ES
|
|---|
| 575 | MOV AH, 25H
|
|---|
| 576 | INT 21H
|
|---|
| 577 | POP AX
|
|---|
| 578 | POP DX
|
|---|
| 579 | POP BX
|
|---|
| 580 | POP ES
|
|---|
| 581 | POP DS
|
|---|
| 582 | RET
|
|---|
| 583 | SET_RM_INT ENDP
|
|---|
| 584 |
|
|---|
| 585 | ;
|
|---|
| 586 | ; Restore real-mode interrupt vector
|
|---|
| 587 | ;
|
|---|
| 588 | ; This is done only if the interrupt vector still points into INIT_CODE
|
|---|
| 589 | ; (avoid restoring the vector if it has been hooked by somebody else)
|
|---|
| 590 | ;
|
|---|
| 591 | ; In: AL Interrupt number
|
|---|
| 592 | ; DX Original offset
|
|---|
| 593 | ; BX Original segment
|
|---|
| 594 | ;
|
|---|
| 595 | ASSUME DS:NOTHING
|
|---|
| 596 | RESTORE_RM_INT PROC NEAR
|
|---|
| 597 | PUSH ES
|
|---|
| 598 | PUSH BX
|
|---|
| 599 | MOV AH, 35H
|
|---|
| 600 | INT 21H
|
|---|
| 601 | MOV BX, ES
|
|---|
| 602 | CMP BX, INIT_CODE
|
|---|
| 603 | POP BX
|
|---|
| 604 | POP ES
|
|---|
| 605 | JNE SHORT RRI_RET
|
|---|
| 606 | PUSH DS
|
|---|
| 607 | MOV DS, BX
|
|---|
| 608 | MOV AH, 25H
|
|---|
| 609 | INT 21H
|
|---|
| 610 | POP DS
|
|---|
| 611 | RRI_RET: RET
|
|---|
| 612 | RESTORE_RM_INT ENDP
|
|---|
| 613 |
|
|---|
| 614 |
|
|---|
| 615 | ;
|
|---|
| 616 | ; Restore interrupts
|
|---|
| 617 | ;
|
|---|
| 618 | ; This procedure is also called before spawning a DOS program
|
|---|
| 619 | ;
|
|---|
| 620 | ASSUME DS:SV_DATA
|
|---|
| 621 | CLEANUP_INT PROC NEAR
|
|---|
| 622 | CMP INT_CHANGED, IC_NOT ; Interrupt vectors remapped?
|
|---|
| 623 | JE SHORT CI_9 ; No -> skip
|
|---|
| 624 | CLI ; Interrupts must be disabled
|
|---|
| 625 | CMP INT_CHANGED, IC_MYSELF ; Done without VCPI?
|
|---|
| 626 | JNE SHORT CI_1 ; No -> try next case
|
|---|
| 627 | CALL RESTORE_INT_VEC ; Restore interrupt vectors
|
|---|
| 628 | MOV CL, 8 ; Restore interrupt controller
|
|---|
| 629 | CALL SET_HW_INT_BASE
|
|---|
| 630 | JMP SHORT CI_8 ; Done
|
|---|
| 631 |
|
|---|
| 632 | CI_1: CMP INT_CHANGED, IC_VCPI_CLIENT ; Done with VCPI?
|
|---|
| 633 | JNE SHORT CI_8 ; No -> skip
|
|---|
| 634 | CALL RESTORE_INT_VEC ; Restore interrupt vectors
|
|---|
| 635 | MOV CL, 8 ; Restore interrupt controller
|
|---|
| 636 | CALL SET_HW_INT_BASE
|
|---|
| 637 | MOV BX, 8 ; Tell VCPI server about change
|
|---|
| 638 | MOV CX, 70H
|
|---|
| 639 | CALL SET_INT_MAP
|
|---|
| 640 |
|
|---|
| 641 | CI_8: MOV INT_CHANGED, IC_NOT ; Back at original state
|
|---|
| 642 | STI ; Interrupts allowed again
|
|---|
| 643 | CI_9: IF RM_DEBUGGER
|
|---|
| 644 | MOV DX, OLD_RM_INT01_OFF
|
|---|
| 645 | MOV BX, OLD_RM_INT01_SEG
|
|---|
| 646 | MOV AL, 01H
|
|---|
| 647 | CALL RESTORE_RM_INT
|
|---|
| 648 | MOV DX, OLD_RM_INT03_OFF
|
|---|
| 649 | MOV BX, OLD_RM_INT03_SEG
|
|---|
| 650 | MOV AL, 03H
|
|---|
| 651 | CALL RESTORE_RM_INT
|
|---|
| 652 | ENDIF
|
|---|
| 653 | RET
|
|---|
| 654 |
|
|---|
| 655 | CLEANUP_INT ENDP
|
|---|
| 656 |
|
|---|
| 657 |
|
|---|
| 658 | ;
|
|---|
| 659 | ; Initialize timer interrupt
|
|---|
| 660 | ;
|
|---|
| 661 | ; This procedure is not called after spawning a DOS program
|
|---|
| 662 | ;
|
|---|
| 663 |
|
|---|
| 664 | ASSUME DS:SV_DATA
|
|---|
| 665 | TALIGN 2
|
|---|
| 666 | INIT_TIMER PROC NEAR
|
|---|
| 667 | CMP MACHINE, MACH_PC98 ; NEC PC-98?
|
|---|
| 668 | JE SHORT IT_DONE ; Yes -> don't set INT 1CH
|
|---|
| 669 | LEA DX, RM_TIMER
|
|---|
| 670 | MOV AL, 1CH
|
|---|
| 671 | CALL SET_RM_INT
|
|---|
| 672 | MOV OLD_RM_INT1C_FLAG, NOT FALSE
|
|---|
| 673 | MOV OLD_RM_INT1C_OFF, DX
|
|---|
| 674 | MOV OLD_RM_INT1C_SEG, AX
|
|---|
| 675 | IT_DONE: RET
|
|---|
| 676 | INIT_TIMER ENDP
|
|---|
| 677 |
|
|---|
| 678 | ;
|
|---|
| 679 | ; Restore timer interrupt
|
|---|
| 680 | ;
|
|---|
| 681 | ; This procedure is not called before spawning a DOS program
|
|---|
| 682 | ;
|
|---|
| 683 | ASSUME DS:SV_DATA
|
|---|
| 684 | TALIGN 2
|
|---|
| 685 | CLEANUP_TIMER PROC NEAR
|
|---|
| 686 | CMP OLD_RM_INT1C_FLAG, FALSE
|
|---|
| 687 | JE SHORT CT_DONE
|
|---|
| 688 | MOV OLD_RM_INT1C_FLAG, FALSE
|
|---|
| 689 | MOV DX, OLD_RM_INT1C_OFF
|
|---|
| 690 | MOV BX, OLD_RM_INT1C_SEG
|
|---|
| 691 | MOV AL, 1CH
|
|---|
| 692 | CALL RESTORE_RM_INT
|
|---|
| 693 | CT_DONE: RET
|
|---|
| 694 | CLEANUP_TIMER ENDP
|
|---|
| 695 |
|
|---|
| 696 | ;
|
|---|
| 697 | ; The timer interrupt handler. Note that interrupt 1CH is not
|
|---|
| 698 | ; available on NEC PC-98.
|
|---|
| 699 | ;
|
|---|
| 700 | ASSUME DS:NOTHING
|
|---|
| 701 | TALIGN 4
|
|---|
| 702 | RM_TIMER PROC NEAR
|
|---|
| 703 | PUSH EAX
|
|---|
| 704 | PUSH DS
|
|---|
| 705 | MOV AX, SV_DATA
|
|---|
| 706 | MOV DS, AX
|
|---|
| 707 | ASSUME DS:SV_DATA
|
|---|
| 708 | ;
|
|---|
| 709 | ; Update clock for __clock()
|
|---|
| 710 | ;
|
|---|
| 711 | ADD CLOCK_LO, 1
|
|---|
| 712 | ADC CLOCK_HI, 0
|
|---|
| 713 | ;
|
|---|
| 714 | ; Decrement timer for emergency exit
|
|---|
| 715 | ;
|
|---|
| 716 | CMP EMERGENCY_TIMER, 0
|
|---|
| 717 | JE SHORT RMT_SKIP_EMERGENCY
|
|---|
| 718 | DEC EMERGENCY_TIMER
|
|---|
| 719 | TALIGN 4
|
|---|
| 720 | RMT_SKIP_EMERGENCY:
|
|---|
| 721 | ;
|
|---|
| 722 | ; Update software timers
|
|---|
| 723 | ;
|
|---|
| 724 | CMP TIMER_MIN, 0
|
|---|
| 725 | JE SHORT RMT_DONE
|
|---|
| 726 | INC TIMER_TICKS
|
|---|
| 727 | DEC TIMER_MIN
|
|---|
| 728 | JNZ SHORT RMT_DONE
|
|---|
| 729 | CALL RMT_CHECK
|
|---|
| 730 | TALIGN 4
|
|---|
| 731 | RMT_DONE: POP DS
|
|---|
| 732 | ASSUME DS:NOTHING
|
|---|
| 733 | POP EAX
|
|---|
| 734 | JMP OLD_RM_INT1C
|
|---|
| 735 | RM_TIMER ENDP
|
|---|
| 736 |
|
|---|
| 737 | ;
|
|---|
| 738 | ; At least one timer expired; examine all timers
|
|---|
| 739 | ;
|
|---|
| 740 | TALIGN 4
|
|---|
| 741 | ASSUME DS:SV_DATA
|
|---|
| 742 | RMT_CHECK PROC NEAR
|
|---|
| 743 | PUSH BX
|
|---|
| 744 | PUSH CX
|
|---|
| 745 | PUSH EDX
|
|---|
| 746 | PUSH DI
|
|---|
| 747 | MOV CX, MAX_TIMERS
|
|---|
| 748 | LEA BX, TIMER_TABLE
|
|---|
| 749 | ASSUME BX:PTR TIMER
|
|---|
| 750 | XOR EDX, EDX
|
|---|
| 751 | MOV TIMER_MIN, EDX
|
|---|
| 752 | XCHG EDX, TIMER_TICKS
|
|---|
| 753 | RMT_LOOP: CMP [BX].T_TYPE, TT_RUNNING
|
|---|
| 754 | JB SHORT RMT_NEXT
|
|---|
| 755 | SUB [BX].T_TICKS, EDX
|
|---|
| 756 | JA SHORT RMT_MIN
|
|---|
| 757 | MOV AX, TT_EXPIRED
|
|---|
| 758 | XCHG AX, [BX].T_TYPE
|
|---|
| 759 | CMP AX, TT_TERMIO_TIME
|
|---|
| 760 | JE SHORT RMT_TERMIO
|
|---|
| 761 | CMP AX, TT_SLEEP
|
|---|
| 762 | JE SHORT RMT_SLEEP
|
|---|
| 763 | CMP AX, TT_ALARM
|
|---|
| 764 | JNE SHORT RMT_NEXT
|
|---|
| 765 | RMT_ALARM: MOV DI, [BX].T_PROCESS
|
|---|
| 766 | ASSUME DI:PTR PROCESS
|
|---|
| 767 | CMP [DI].P_SIG_HANDLERS[4*SIGALRM], SIG_IGN
|
|---|
| 768 | JE SHORT RMT_NEXT
|
|---|
| 769 | BTS [DI].P_SIG_PENDING, SIGALRM ; Generate SIGALRM
|
|---|
| 770 | ASSUME DI:NOTHING
|
|---|
| 771 | JMP SHORT RMT_NEXT
|
|---|
| 772 |
|
|---|
| 773 | RMT_TERMIO: MOV DI, [BX].T_PROCESS
|
|---|
| 774 | OR (PROCESS PTR [DI]).P_FLAGS, PF_TERMIO_TIME
|
|---|
| 775 | JMP SHORT RMT_NEXT
|
|---|
| 776 |
|
|---|
| 777 | RMT_SLEEP: MOV DI, [BX].T_PROCESS
|
|---|
| 778 | OR (PROCESS PTR [DI]).P_FLAGS, PF_SLEEP_FLAG
|
|---|
| 779 | JMP SHORT RMT_NEXT
|
|---|
| 780 |
|
|---|
| 781 | RMT_MIN: MOV EAX, [BX].T_TICKS
|
|---|
| 782 | CMP TIMER_MIN, 0
|
|---|
| 783 | JE SHORT RMT_SET
|
|---|
| 784 | CMP EAX, TIMER_MIN
|
|---|
| 785 | JAE SHORT RMT_NEXT
|
|---|
| 786 | RMT_SET: MOV TIMER_MIN, EAX
|
|---|
| 787 | RMT_NEXT: ADD BX, SIZE TIMER
|
|---|
| 788 | LOOP RMT_LOOP
|
|---|
| 789 | ASSUME BX:NOTHING
|
|---|
| 790 | POP DI
|
|---|
| 791 | POP EDX
|
|---|
| 792 | POP CX
|
|---|
| 793 | POP BX
|
|---|
| 794 | RET
|
|---|
| 795 | RMT_CHECK ENDP
|
|---|
| 796 |
|
|---|
| 797 | IF RM_DEBUGGER
|
|---|
| 798 | ;
|
|---|
| 799 | ; Debug interrupt in real mode
|
|---|
| 800 | ;
|
|---|
| 801 | ASSUME DS:NOTHING
|
|---|
| 802 | RM_DEBUG PROC NEAR
|
|---|
| 803 | MOV AX, SV_DATA
|
|---|
| 804 | MOV DS, AX
|
|---|
| 805 | ASSUME DS:SV_DATA
|
|---|
| 806 | LEA DX, $RM_DEBUG
|
|---|
| 807 | CALL RTEXT
|
|---|
| 808 | MOV BP, SP
|
|---|
| 809 | MOV AX, [BP+2]
|
|---|
| 810 | CALL RWORD
|
|---|
| 811 | MOV AL, ":"
|
|---|
| 812 | CALL RCHAR
|
|---|
| 813 | MOV AX, [BP+0]
|
|---|
| 814 | CALL RWORD
|
|---|
| 815 | CALL RCRLF
|
|---|
| 816 | JMP EXIT
|
|---|
| 817 | RM_DEBUG ENDP
|
|---|
| 818 |
|
|---|
| 819 | ENDIF
|
|---|
| 820 |
|
|---|
| 821 | INIT_CODE ENDS
|
|---|
| 822 |
|
|---|
| 823 | END
|
|---|