Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

937 lines
29 KiB

  1. include intmac.inc
  2. public rgw032Stack
  3. dw 64 dup (?) ; DOSX Ring -> Ring 0 transition stack
  4. ;
  5. ; Interrupts in the range 0-1fh cause a ring transition and leave
  6. ; an outer ring IRET frame right here.
  7. ;
  8. Ring0_EH_DS dw ? ; place to put user DS
  9. Ring0_EH_AX dw ? ; place to put user AX
  10. Ring0_EH_BX dw ? ; place to put user BX
  11. Ring0_EH_CX dw ? ; place to put user CX
  12. Ring0_EH_BP dw ? ; place to put user BP
  13. Ring0_EH_PEC dw ? ; lsw of error code for 386 page fault
  14. ; also near return to PMFaultEntryVector
  15. Ring0_EH_EC dw ? ; error code passed to EH
  16. Ring0_EH_IP dw ? ; interrupted code IP
  17. dw ?
  18. Ring0_EH_CS dw ? ; interrupted code CS
  19. dw ?
  20. Ring0_EH_Flags dw ? ; interrupted code flags
  21. dw ?
  22. Ring0_EH_SP dw ? ; interrupted code SP
  23. dw ?
  24. Ring0_EH_SS dw ? ; interrupted code SS
  25. dw ?
  26. rgw032Stack label word
  27. ; ------------------------------------------------------------------
  28. ; PMFaultAnalyzer -- This routine is the entry point for
  29. ; the protected mode fault/trap/exception handler. It tries
  30. ; to distinguish between bona fide processor faults and
  31. ; hardware/software interrupts which use the range of
  32. ; interrupts that is reserved by Intel. If a fault is
  33. ; detected, then format the stack for a DPMI fault handler,
  34. ; then vector to the handler whose address is stored in
  35. ; PMFaultVector. If it looks more like an interrupt, then
  36. ; set up the stack for an interrupt handler, jump to the
  37. ; handler whose address is stored in PMIntelVector.
  38. ;
  39. ; Input: none
  40. ; Output: none
  41. assume ds:NOTHING,es:NOTHING,ss:DGROUP
  42. public PMFaultAnalyzer
  43. PMFaultAnalyzer proc near
  44. ;
  45. ; Make sure we are on the right stack. Else, something fishy is going on.
  46. ; Note that stack faults won't do too well here.
  47. ;
  48. push ax
  49. mov ax,ss
  50. cmp ax,SEL_DXDATA or STD_RING
  51. pop ax
  52. je pmfa_stack_passed
  53. jmp pmfa_bad_stack
  54. pmfa_stack_passed:
  55. ;
  56. ; Is the stack pointer pointing at a word error code (minus 2)?
  57. ;
  58. cmp sp,offset DGROUP:Ring0_EH_PEC
  59. je pmfa_fault ; Yes, processor fault.
  60. ;
  61. ; Is it pointing to where it is supposed to be for a hardware or
  62. ; software interrupt?
  63. ;
  64. cmp sp,offset DGROUP:Ring0_EH_EC
  65. je pmfa_20
  66. jmp pmfa_bad_stack
  67. pmfa_20:jmp pmfa_inspect
  68. pmfa_fault:
  69. ;
  70. ; Getting here, we have a known exception with a word error code of some
  71. ; sort on the stack. Perform an outward ring transition, switch to the
  72. ; client stack, then vector through the exception handler vector to the
  73. ; appropriate handler.
  74. ;
  75. push bp
  76. push cx
  77. push bx
  78. push ax
  79. push ds
  80. lea bp,Ring0_EH_SS
  81. mov ax,word ptr [bp]
  82. mov cx,selEHStack
  83. cmp ax,cx
  84. jne pmfa_stack_OK
  85. mov bx,[bp-2]
  86. jmp pmfa_copy_stack
  87. pmfa_stack_OK:
  88. mov bx,npEHStackLimit
  89. pmfa_copy_stack:
  90. mov ds,cx ; DS:BX = user SS:SP
  91. mov cx,13
  92. add bp,2 ; put both halves of ss
  93. pmfa_copy_stack_loop:
  94. dec bx
  95. dec bx
  96. mov ax,word ptr [bp]
  97. mov word ptr [bx],ax
  98. dec bp
  99. dec bp
  100. loop pmfa_copy_stack_loop
  101. ; DS:BX points to stack on entry to PMFaultReflector
  102. ;
  103. ; Build a far return frame on user stack, switch to user stack, and return
  104. ;
  105. lea bp,Ring0_EH_PEC
  106. mov word ptr [bp+6],ds
  107. mov word ptr [bp+4],bx
  108. sub bx,2
  109. mov word ptr ds:[bx],SEL_DXPMCODE OR STD_RING; push cs
  110. sub bx,2
  111. mov ds:[bx],offset DXPMCODE:PMFaultReflector; push ip
  112. lea bp,Ring0_EH_PEC
  113. mov ax,Ring0_EH_CX ; get BP value
  114. sub bx,2
  115. mov ds:[bx],ax ; push bp
  116. mov Ring0_EH_PEC,bx ; sp for lss
  117. mov bx,ds
  118. mov Ring0_EH_EC,bx ; ss for lss
  119. pop ds
  120. pop ax
  121. pop bx
  122. pop cx
  123. .386p
  124. lss sp,[bp] ; switch stack
  125. .286p
  126. pop bp
  127. retf
  128. pmfa_inspect:
  129. ;
  130. ; Stack is set up as for an interrupt or exception without error code.
  131. ; Adjust the stack pointer and put an error code of zero. Then try to
  132. ; determine whether we have an exception or an interrupt. First test
  133. ; is the interrupt number.
  134. ;
  135. push Ring0_EH_EC
  136. mov Ring0_EH_EC,0
  137. cmp Ring0_EH_PEC,offset PMFaultEntryVector + ((7 + 1) * 3)
  138. ja pfma_50
  139. push Ring0_EH_PEC
  140. mov Ring0_EH_PEC,0
  141. jmp pmfa_fault ; Yes, definitely a fault.
  142. pfma_50:
  143. ;
  144. ; At this point, all valid exceptions have been eliminated except for
  145. ; exception 9, coprocessor segment overrun, and exception 16, coprocessor
  146. ; error.
  147. ;
  148. ; **********************************************
  149. ; * Your code to detect these exceptions here. *
  150. ; **********************************************
  151. push bp
  152. push cx
  153. push bx
  154. push ax
  155. push ds ; SP -> Ring0_EH_DS
  156. ;
  157. ; Point to the user's stack.
  158. ;
  159. lea bp,Ring0_EH_SS
  160. mov cx,[bp]
  161. mov ds,cx
  162. mov bx,[bp-2] ; DS:[BX] -> user stack
  163. ;
  164. ; Copy the IRET frame to the user stack.
  165. ;
  166. lea bp,Ring0_EH_Flags
  167. mov cx,6
  168. pmfa_copy_IRET:
  169. mov ax,[bp]
  170. dec bx
  171. dec bx
  172. mov [bx],ax
  173. dec bp
  174. dec bp
  175. loop pmfa_copy_IRET
  176. ;
  177. ; Point BP at vector entry for this (reserved) interrupt.
  178. ;
  179. mov ax,Ring0_EH_PEC ; fetch near return address
  180. sub ax,offset DXPMCODE:PMFaultEntryVector+3
  181. mov cl,3
  182. div cl ; AX = interrupt number
  183. shl ax,2 ; AX = vector entry offset
  184. lea bp,PMIntelVector
  185. add bp,ax ; BP -> interrupt handler address
  186. mov ax,[bp] ; AX = IP of handler
  187. mov cx,[bp+2] ; CX = CS of handler
  188. ;
  189. ; Build a far return frame on user stack, switch to user stack, and return
  190. ;
  191. sub bx,2
  192. mov ds:[bx],cx ; push cs
  193. sub bx,2
  194. mov ds:[bx],ax ; push ip
  195. lea bp,Ring0_EH_PEC
  196. mov ax,Ring0_EH_BP
  197. sub bx,2
  198. mov ds:[bx],ax ; push bp
  199. mov Ring0_EH_PEC,bx ; sp for lss
  200. mov bx,ds
  201. mov Ring0_EH_EC,bx ; ss for lss
  202. pop ds
  203. pop ax
  204. pop bx
  205. pop cx
  206. .386p
  207. lss sp,[bp] ; switch stack
  208. .286p
  209. pop bp
  210. retf ; Out of here.
  211. pmfa_bad_stack:
  212. if DEBUG
  213. mov ax,ss
  214. mov bx,sp
  215. Trace_Out "Fault Handler Aborting with SS:SP = #AX:#BX"
  216. pop ax
  217. sub ax, (offset DXPMCODE:PMFaultEntryVector) + 3
  218. mov bx,3
  219. div bl
  220. Trace_Out "Fault Number #AX"
  221. pop ax
  222. pop bx
  223. pop cx
  224. pop dx
  225. Trace_Out "First four stack words: #AX #BX #CX #DX."
  226. endif
  227. push selDgroupPM
  228. push offset DGROUP:rgwStack
  229. rpushf
  230. push SEL_DXPMCODE or STD_RING
  231. push offset DXPMCODE:pmfr_death
  232. riret
  233. pmfr_death:
  234. mov ax,cs
  235. mov ds,ax
  236. mov dx,offset szRing0FaultMessage
  237. pmdossvc 09h
  238. jmp PMAbort
  239. PMFaultAnalyzer endp
  240. FR_Stack Struc
  241. FR_BP dd ?
  242. FR_AX dd ?
  243. FR_BX dd ?
  244. FR_DS dw ?
  245. FR_ENTRY dd ? ; SS:[SP] points here on entry
  246. ; to PMReservedReflector
  247. FR_Toss dd ? ; DPMI return IP
  248. FR_Ret_IP dd ? ; actual fault handler gets put
  249. FR_Ret_CS dd ? ; here to return to
  250. FR_IP dd ?
  251. FR_CS dd ?
  252. FR_FL dd ?
  253. FR_SP dd ?
  254. FR_SS dd ?
  255. FR_Stack Ends
  256. ;
  257. ; Alternate names so the structure above makes more sense to
  258. ; PMFaultReflector.
  259. ;
  260. FR_Handler_IP equ FR_DS
  261. FR_Handler_CS equ FR_ENTRY
  262. FR_Handler_Ret_IP equ FR_Toss
  263. FR_Handler_Ret_CS equ FR_Ret_IP
  264. FR_Handler_Entry equ FR_Handler_Ret_CS
  265. FR_EC equ FR_Ret_CS
  266. ; ------------------------------------------------------------------
  267. ; PMFaultReflector -- Dispatch a fault to a fault handler installed
  268. ; in PMFaultVector. When the fault handler returns, return
  269. ; to the faulting code, using the addresses placed on the
  270. ; DPMI fault handler stack by the last called fault handler.
  271. ;
  272. ; Input:
  273. ; Entry is by a NEAR call, with an IP within the range
  274. ; of PMFaultEntryVector on the stack. The stack has been
  275. ; set up for use by a DPMI fault handler.
  276. ;
  277. ; Output:
  278. ; Controlled by fault handler.
  279. ;
  280. ; Uses:
  281. ; Controlled by fault handler.
  282. ;
  283. ; Notes:
  284. ; Fault handlers are called on a static stack. This routine
  285. ; is NOT REENTRANT.
  286. ;
  287. public PMFaultReflector
  288. public PMFaultReflectorIRET
  289. PMFaultReflector proc near
  290. assume ss:nothing,ds:nothing,es:nothing
  291. sub sp,6
  292. push bx
  293. push eax
  294. push bp
  295. mov bp,sp
  296. push ds
  297. mov ax,SEL_DXDATA or STD_RING
  298. mov ds,ax
  299. assume ds:dgroup
  300. mov ax,[bp.FR_Handler_Entry]
  301. sub ax,offset DXPMCODE:PMFaultEntryVector+3
  302. mov bl,3
  303. div bl ; AX = interrupt number
  304. shl ax,3 ; AX = offset of fault handler
  305. lea bx,PMFaultVector
  306. add bx,ax ; SS:[BX] -> fault vector entry
  307. mov eax,word ptr ds:[bx]
  308. mov [bp.FR_Handler_IP],eax
  309. mov ax,word ptr ds:[bx+2]
  310. mov [bp.FR_Handler_CS],ax
  311. lea ax,pmfr_cleanup
  312. movzx eax,ax
  313. mov [bp.FR_Handler_Ret_IP],eax
  314. push cs
  315. pop [bp.FR_Handler_Ret_CS]
  316. pop ds
  317. assume ds:nothing
  318. pop bp
  319. pop ax
  320. pop bx
  321. db 066h,0CBh ; This calls the fault handler.
  322. PMFaultReflectorIRETCall:
  323. dd (SEL_RZIRET or STD_RING) shl 10h
  324. pmfr_cleanup:
  325. ;
  326. ; Unwind the fault handler stack. Return to the faulting code.
  327. ; This works by calling a Ring 0 procedure to do the actual IRET.
  328. ; If we do it that way, we can return to the faulting code without
  329. ; actually touching the faulting code's stack.
  330. ;
  331. PMFaultReflectorIRET:
  332. ; BUGBUG Daveh using user stack this way is less robust!!!
  333. .386p
  334. add sp,4 ; pop error code
  335. push bp
  336. mov bp,sp
  337. push ebx
  338. push ds
  339. push eax
  340. mov ax,[bp + 18]
  341. mov ds,ax
  342. mov ebx,[bp + 14] ; ds:bx -> user stack
  343. sub ebx,4
  344. mov eax,[bp + 10]
  345. mov ds:[ebx],eax ; push flags
  346. sub ebx,4
  347. mov eax,[bp + 4]
  348. mov ds:[ebx],eax ; push cs
  349. sub ebx,4
  350. mov eax,[bp + 2]
  351. mov ds:[ebx],eax ; push ip
  352. sub ebx,2
  353. mov ax,[bp]
  354. mov ds:[ebx],ax ; push bp
  355. mov [bp + 8],bx
  356. pop eax
  357. pop ds
  358. pop ebx
  359. pop bp
  360. add sp,6 ; point to ss:sp
  361. mov bp,sp
  362. lss esp,[bp]
  363. .286p
  364. pop bp ; restore bp
  365. riretd
  366. endif
  367. PMFaultReflector endp
  368. ;
  369. ; -------------------------------------------------------
  370. ; PMReservedReflector -- This routine is for reflecting
  371. ; exceptions to a protected mode interrupt handler.
  372. ; The default for exceptions 1, 2, and 3 is to have
  373. ; a near call to this routine placed in the PMFaultVector.
  374. ;
  375. ; This routine strips off the fault handler stack set
  376. ; up by PMFaultAnalyzer, switches to the stack pointed
  377. ; to by the pushed SS and SP values, sets up an IRET
  378. ; frame for use by PMIntrReflector, and jumps to
  379. ; PMIntrReflector. Eventual return is via an IRET
  380. ; from PMIntrReflector.
  381. ;
  382. ; Input:
  383. ; Entry is by a NEAR call, with an IP within the range
  384. ; of PMReservedEntryVector on the stack. The stack has been
  385. ; set up for use by a DPMI fault handler.
  386. ;
  387. ; Output:
  388. ; Switch to stack registers set up by any previous fault
  389. ; handler, jump to PMIntrReflector with an IRET frame set up
  390. ; for direct return to the interrupted code.
  391. ;
  392. ; Errors: none
  393. ;
  394. ; Uses: Modifies SS, SP. Does not return to caller.
  395. ;
  396. assume ds:NOTHING,es:NOTHING,ss:NOTHING
  397. public PMReservedReflector
  398. PMReservedReflector:
  399. push ds
  400. push ebx
  401. push eax
  402. push ebp
  403. mov bp,sp
  404. ;
  405. ; BP now points to a stack frame described by the structure
  406. ; above. This will be copied to a stack frame on the stack pointed to
  407. ; by FR_SS:FR_SS. In most cases, the destination stack is actually
  408. ; the same as the present stack, offset by four bytes. The following
  409. ; block of code is therefore very likely an overlapping copy. Think
  410. ; carefully before modifying how it works.
  411. ;
  412. mov bx,[bp.FR_SS]
  413. mov ds,bx
  414. mov ebx,[bp.FR_SP] ; DS:[BX] -> interrupted code's stack
  415. sub bx, (size FR_Stack) - 8 ; (not copying SP or SS)
  416. ; DS:[BX] -> place to copy our stack frame
  417. mov eax,[bp.FR_FL] ; Push user IRET frame onto the destination
  418. mov [ebx.FR_FL],eax ; stack.
  419. mov eax,[bp.FR_CS]
  420. mov [ebx.FR_CS],eax
  421. mov eax,[bp.FR_IP]
  422. mov [ebx.FR_IP],eax
  423. mov eax,[bp.FR_ENTRY] ; Copy our caller's near return.
  424. mov [ebx.FR_ENTRY],eax
  425. mov ax,[bp.FR_DS] ; Copy saved registers.
  426. mov [ebx.FR_DS],ax
  427. mov eax,[bp.FR_BX]
  428. mov [ebx.FR_BX],eax
  429. mov eax,[bp.FR_AX]
  430. mov [ebx.FR_AX],eax
  431. mov eax,[bp.FR_BP]
  432. mov [ebx.FR_BP],eax
  433. mov ax,ds ; Switch to user stack.
  434. mov ss,ax
  435. mov esp,ebx
  436. mov ebp,esp
  437. mov ax,[ebp.FR_ENTRY] ; AX = offset of caller
  438. sub ax,offset DXPMCODE:PMReservedEntryVector + 3
  439. mov bl,3
  440. div bl ; AX = interrupt number
  441. shl ax,2 ; AX = offset into PMIntelVector
  442. mov ds,SelDgroupPM
  443. assume ds:DGROUP
  444. lea bx,PMIntelVector
  445. add bx,ax ; DS:[BX] -> interrupt handler
  446. mov eax,[bx] ; Place vector entry just below
  447. mov [ebp.FR_Ret_IP],eax ; IRET frame.
  448. mov eax,[bx+4]
  449. mov [ebp.FR_Ret_CS],eax
  450. lea esp,[ebp.FR_BP] ; Point to saved registers.
  451. pop ebp ; Pop 'em.
  452. pop eax
  453. pop ebx
  454. pop ds
  455. add esp,4 ; Fix up stack.
  456. db 066h,0CBh ; jump to interrupt handler via far return
  457. DXPMCODE ends
  458. ; -------------------------------------------------------
  459. subttl Real Mode Interrupt Reflector
  460. page
  461. ; -------------------------------------------------------
  462. ; REAL MODE INTERRUPT REFLECTOR
  463. ; -------------------------------------------------------
  464. DXCODE segment
  465. assume cs:DXCODE
  466. ; -------------------------------------------------------
  467. ; RMIntrEntryVector -- This table contains a vector of
  468. ; near jump instructions to the real mode interrupt
  469. ; reflector. Real mode interrupts that have been hooked
  470. ; by the protected mode application have their vector
  471. ; set to entry the real mode reflector through this table.
  472. public RMIntrEntryVector
  473. RMIntrEntryVector:
  474. rept 256
  475. call RMIntrReflector
  476. endm
  477. ; -------------------------------------------------------
  478. ; RMIntrReflector -- This routine is the entry point for
  479. ; the real mode interrupt reflector. This routine
  480. ; is entered when an interrupt occurs (either software
  481. ; or hardware) that has been hooked by the protected mode
  482. ; application. It switches the processor to protected mode
  483. ; and transfers control to the appropriate interrupt
  484. ; service routine for the interrupt. After the interrupt
  485. ; service routine completes, it switches back to real
  486. ; mode and returns control to the originally interrupted
  487. ; real mode code.
  488. ; Entry to this routine comes from the RMIntrEntryVector,
  489. ; which contains a vector of near call instructions, which
  490. ; all call here. The interrupt number is determined from
  491. ; the return address of the near call from the interrupt
  492. ; entry vector.
  493. ; The address of the protected mode interrupt service routine
  494. ; to execute is determined from the protected mode interrupt
  495. ; descriptor tabel and the interrupt number.
  496. ;
  497. ; Input: none
  498. ; Output: none
  499. ; Errors: none
  500. ; Uses: The segment registers are explicitly preserved by
  501. ; this routine. Other registers are as preserved or
  502. ; modified by the interrutp service routine.
  503. assume ds:NOTHING,es:NOTHING,ss:NOTHING
  504. public RMIntrReflector
  505. RMIntrReflector:
  506. ;
  507. ; On entry, the stack layout is:
  508. ; [6] FLAGS - "
  509. ; [4] CS - "
  510. ; [2] IP - from original interrupt
  511. ; [0] IP - from interrupt entry vector call
  512. ;
  513. FCLI
  514. cld
  515. push ds
  516. IFDEF ROM
  517. SetRMDataSeg
  518. ELSE
  519. mov ds,selDgroup
  520. ENDIF
  521. assume ds:DGROUP
  522. if DEBUG
  523. ;
  524. ; Are we on a DOSX interrupt reflector stack?
  525. ;
  526. push ax
  527. push cx
  528. mov ax,ss
  529. mov cx,ds
  530. cmp ax,cx
  531. pop cx
  532. jne @F
  533. cmp sp,offset bReflStack
  534. jb @F
  535. cmp sp,offset pbReflStack
  536. jnb @F
  537. ;
  538. ; If so, have we overflowed a stacklet?
  539. ;
  540. mov ax,pbReflStack
  541. cmp sp,ax
  542. ja @F
  543. add ax,CB_STKFRAME
  544. cmp sp,ax
  545. jb @F
  546. pop ax
  547. Real_Debug_Out "DOSX:RMIntrReflector--Reflector stack overflow."
  548. push ax
  549. @@:
  550. pop ax
  551. endif ;DEBUG
  552. mov regUserAX,ax ;save user AX for later
  553. push bp ;stack -> BP DS IP IP CS FL
  554. mov bp,sp ; [0] [2] [4] [6] [8] [A]
  555. mov ax,[bp+0Ah] ;get the interrupted routine's flags
  556. and ax,NOT 4100h ;clear the trace flag in case we got
  557. ; an interrupt on an instruction about
  558. ; to be single stepped
  559. mov regUserFL,ax ;and save for later
  560. mov ax,es
  561. xchg ax,[bp+4] ;save ES and get entry vector address
  562. pop bp
  563. ; Some software (like older versions of Smartdrv.sys) may enable A20 on
  564. ; their own, and get very 'suprised' to find it turned off by our PM->RM
  565. ; mode switch. If they used Himem.sys, this wouldn't be necessary, but...
  566. if VCPI
  567. cmp fVCPI,0
  568. jnz @f
  569. endif
  570. push ax ;get/save current A20 state on stack
  571. push bx
  572. xmssvc 7
  573. mov regUserSP,ax ;use regUserSP as a temp var
  574. pop bx
  575. pop ax
  576. @@:
  577. push regUserSP
  578. ; The state that we want to save on the user's stack has been set up.
  579. ; Convert the entry vector return address into an interrupt number.
  580. sub ax,offset RMIntrEntryVector+3
  581. push cx
  582. mov cl,3
  583. div cl
  584. pop cx
  585. if DEBUG
  586. mov PMIntNo,ax
  587. endif
  588. ; Allocate a new stack frame, and then switch to the reflector stack
  589. ; frame.
  590. mov regUserSP,sp ;save entry stack pointer so we can
  591. mov regUSerSS,ss ; switch to our own stack
  592. IFDEF ROM
  593. push ds
  594. pop ss
  595. ELSE
  596. mov ss,selDgroup ;switch to the reflector stack frame
  597. ENDIF
  598. mov sp,pbReflStack
  599. push pbReflStack ;save stack frame ptr on stack
  600. sub pbReflStack,CB_STKFRAME ;adjust pointer to next stack frame
  601. ; We are now running on our own stack, so we can switch into protected mode.
  602. push ax ;save interrupt vector table offset
  603. SwitchToProtectedMode
  604. pop ax
  605. if DEBUG ;--------------------------------------------------------
  606. push 0DEADh ;debugging id & interrupt number
  607. push PMIntNo
  608. cmp fTraceReflect,0
  609. jz @f
  610. push ax
  611. mov ax,PMIntNo
  612. Trace_Out "(rp#AL)",x
  613. pop ax
  614. @@:
  615. ; Perform a too-late-to-save-us-now-but-we-want-to-know check on the
  616. ; reflector stack.
  617. cmp StackGuard,1022h
  618. jz @f
  619. Debug_Out "DOSX:RMIntrReflector--Global reflector stack overflow."
  620. @@:
  621. endif ;DEBUG ---------------------------------------------------------
  622. ; Build an IRET frame on the stack so that the protected mode interrupt service
  623. ; routine will return to us when it is finished.
  624. push regUserSS ;save user stack address on our own stack
  625. push regUserSP ; frame so we can restore it later
  626. push ds
  627. push regUserFL
  628. push cs
  629. push offset rmrf50
  630. ; Build an IRET frame on the stack to use to transfer control to the
  631. ; protected mode ISR
  632. and byte ptr regUserFL+1,not 02h ;use entry flags less the
  633. push 0 ; high half esp
  634. push regUserFL ; interrupt flag (IF)
  635. xchg bx,ax ;interrupt vector offset to BX, preserve BX
  636. cmp bx,CRESERVED ;Interrupt in reserved range?
  637. jc rmrf_reserved
  638. shl bx,3
  639. mov es,selIDT
  640. jmp rmrf_setISR
  641. rmrf_reserved:
  642. shl bx,2
  643. mov es,SelDgroupPM
  644. add bx,offset DGROUP:PMIntelVector
  645. rmrf_setISR:
  646. push dword ptr es:[bx+4] ;push segment of isr
  647. push dword ptr es:[bx] ;push offset of isr
  648. xchg bx,ax
  649. mov ax,regUserAX ;restore entry value of AX
  650. push ds
  651. pop es
  652. ; At this point the interrupt reflector stack looks like this:
  653. ;
  654. ; [18] previous stack frame pointer
  655. ; [16] stack segment of original stack
  656. ; [14] stack pointer of original stack
  657. ; [12] protected mode dos extender data segment
  658. ; [10] dos extender flags
  659. ; [8] segment of return address back to interupt reflector
  660. ; [6] offset of return address back to interrupt reflector
  661. ; [4] user flags as on entry from original interrupt
  662. ; [2] segment of protected mode ISR
  663. ; [0] offset of protected mode ISR
  664. ;
  665. ; Execute the protected mode interrupt service routine
  666. iretd
  667. ; The protected mode ISR will return here after it is finsished.
  668. rmrf50: pop ds
  669. pushf ;save flags as returned by PM Int routine
  670. FCLI ;We have to clear interrupts here, because
  671. cld ; the interrupt routine may have returned
  672. ; with interrupts on and our code that uses
  673. ; static variables must be protected. We
  674. ; turn them off after to pushf instruction so
  675. ; that we can preserve the state of the
  676. ; interrupt flag as returned by the ISR.
  677. mov regUserAX,ax
  678. pop ax
  679. pop regUserSP
  680. pop regUserSS
  681. if DEBUG
  682. add sp,4 ;'pop' off debugging info
  683. endif
  684. pop pbReflStack ;deallocate stack frame(s)
  685. ; Switch back to real mode.
  686. push ax ;preserve AX
  687. SwitchToRealMode
  688. pop ax
  689. ; Switch back to the original stack.
  690. mov ss,regUserSS
  691. mov sp,regUserSP
  692. ; Make sure the A20 line matches whatever state it was when the int occured.
  693. ; This is for the benefit of any software that diddles A20 without using
  694. ; an XMS driver
  695. pop regUserSP ;A20 state at time of interrupt to temp var
  696. if VCPI
  697. cmp fVCPI,0
  698. jnz rmrf75
  699. endif
  700. push ax ;save current ax
  701. mov ax,regUserSP ;ax = A20 state at time of interrupt
  702. or ax,ax ;if it was off, don't sweat it
  703. jz rmrf70
  704. push bx ;save bx (XMS calls destroy bl)
  705. push ax
  706. xmssvc 7 ;ax = current A20 state
  707. pop bx ;bx = old A20 state
  708. cmp ax,bx ;if A20 is still on, don't need to diddle
  709. jz @f
  710. xmssvc 5 ;force A20 back on
  711. inc A20EnableCount ; and remember that we did this
  712. if DEBUG
  713. or fA20,04h
  714. endif
  715. @@:
  716. pop bx
  717. rmrf70:
  718. pop ax
  719. rmrf75:
  720. ; Put the flags returned by the real mode interrupt routine back into
  721. ; the caller's stack so that they will be returned properly.
  722. push bp ;stack -> BP DS ES IP CS FL
  723. mov bp,sp ; [0] [2] [4] [6] [8] [10]
  724. and [bp+10],0300h ;clear all but the interrupt and trace flags
  725. ; in the caller's original flags
  726. or [bp+10],ax ;combine in the flags returned by the
  727. ; interrupt service routine. This will cause
  728. ; us to return to the original routine with
  729. ; interrupts on if they were on when the
  730. ; interrupt occured, or if the ISR returned
  731. ; with them on.
  732. pop bp
  733. ; And return to the original interrupted program.
  734. mov ax,regUserAX
  735. pop ds
  736. pop es
  737. iret
  738. DXCODE ends
  739. WowIntr3216 proc
  740. FCLI
  741. push ebp
  742. mov ebp,esp
  743. mov regUserAX,eax
  744. mov regUserBX,ebx
  745. mov regUserDS,ds
  746. mov regUserES,es
  747. mov regUserFlags,[ebp + 16]
  748. mov ax,SEL_DXDATA OR STD_RING
  749. mov ds,ax
  750. assume ds:dgroup
  751. mov ebx,esp
  752. mov regUserSp,eax
  753. mov ax,ss
  754. mov regUserSs,ax
  755. mov bx,pbReflStack ; get pointer to new frame
  756. sub bpReflStack,CB_STKFRAME
  757. ;
  758. ; put user stack pointer on new stack
  759. ;
  760. sub bx,4
  761. mov [bx],regUserSs
  762. sub bx,4
  763. mov [bx],dword ptr regUserSp
  764. mov ax,[ebp + 4]
  765. ;
  766. ; switch to new stack
  767. ;
  768. push ds
  769. pop ss
  770. movzx esp,bx
  771. ;
  772. ; Save ss:esp for lss esp
  773. ;
  774. push regUserSs
  775. push regUserSp
  776. ;
  777. ; Create an int frame
  778. ;
  779. pushf
  780. push cs
  781. push offset wi30
  782. ;
  783. ; Put handler address on stack
  784. ;
  785. shl ax,3
  786. mov es,selDgroupPM
  787. add bx,offset DGROUP:Intr16Vector
  788. push [bx + 2]
  789. push [bx]
  790. ;
  791. ; Restore Registers
  792. ;
  793. mov eax,regUserAx
  794. mov ebx,regUserBX
  795. mov es,regUserES
  796. mov ds,regUserDS
  797. assume ds:nothing
  798. ;
  799. ; call handler
  800. ;
  801. retf
  802. wi30:
  803. ;
  804. ; handler will return here
  805. ;
  806. ;
  807. ; Switch stacks
  808. ;
  809. mov ebp,esp
  810. lss esp,[ebp]
  811. mov ebp,esp
  812. push eax
  813. push ds
  814. mov ds,SEL_DXDATA OR STD_RING
  815. assume ds:DGROUP
  816. ;
  817. ; Deallocate stack frame
  818. ;
  819. add pbReflStack,CB_STKFRAME
  820. pop eax
  821. pop ds
  822. ;
  823. ; Return flags from int handler
  824. ;
  825. pushf
  826. pop [ebp + 16]
  827. ;
  828. ; Return to interrupted code
  829. ;
  830. pop ebp
  831. riretd
  832. WowIntr3216 endp