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.

1088 lines
48 KiB

  1. PAGE 60,150
  2. ;***************************************************************************
  3. ;* INT2.ASM
  4. ;*
  5. ;* Assembly code support routines used for the TOOLHELP.DLL interrupt
  6. ;* trapping API
  7. ;*
  8. ;***************************************************************************
  9. INCLUDE TOOLPRIV.INC
  10. INCLUDE WINDOWS.INC
  11. include vint.inc
  12. .286p
  13. ;** Symbols
  14. I_EXCEPTION EQU 0
  15. I_INTERRUPT EQU 1
  16. MAX_INTERRUPT EQU 7
  17. GIVE_WDEB386 EQU 8000h
  18. BAD_STACK_FLAG EQU 8000h
  19. MIN_STACK_ALLOWED EQU 128
  20. ;** Local types
  21. INT_INFO STRUC
  22. ii_wNumber DW ? ;INT nn
  23. ii_wType DW ? ;I_EXCEPTION or I_INTERRUPT
  24. ii_dwChain DD ?
  25. ii_wHandler DW ? ;Note that this is CS relative
  26. INT_INFO ENDS
  27. ;** Data
  28. sBegin DATA
  29. IntInfo LABEL BYTE
  30. public IntInfo
  31. UD_Info DW 6 ;Undefined opcode
  32. DW I_EXCEPTION ;This should be DPMI-hooked
  33. DD 0 ;Chain address (will be initialized)
  34. DW OFFSET _TEXT:UD_Handler
  35. Div0_Info DW 0 ;Divide by zero
  36. DW I_EXCEPTION ;Hook with DPMI
  37. DW OFFSET _TEXT:Div0_Handler
  38. DW 0
  39. DW OFFSET _TEXT:Div0_Handler
  40. Int1_Info DW 1 ;Single step + debug register
  41. DW I_INTERRUPT ;Hook with DOS
  42. DD 0 ;Chain address
  43. DW OFFSET _TEXT:Int1_Handler
  44. Int3_Info DW 3 ;Software debug int
  45. DW I_INTERRUPT ;Hook with DOS
  46. DD 0 ;Chain address
  47. DW OFFSET _TEXT:Int3_Handler
  48. GP_Info DW 13 ;GP Fault
  49. DW I_EXCEPTION ;This should be DPMI-hooked
  50. ;** This entry is a special case entry for the Win30 std mode
  51. ;* handler. This is a separate entry point into the
  52. ;** interrupt handler routine
  53. DW OFFSET _TEXT:GP_StdModeHandler
  54. DW 0
  55. DW OFFSET _TEXT:GP_Handler
  56. SF_Info DW 12 ;Stack fault
  57. DW I_EXCEPTION ;This should be DPMI-hooked
  58. ;** This entry is a special case entry for the Win30 std mode
  59. ;* handler. This is a separate entry point into the
  60. ;** interrupt handler routine
  61. DW OFFSET _TEXT:SF_StdModeHandler
  62. DW 0
  63. DW OFFSET _TEXT:SF_Handler
  64. PF_Info DW 14 ;Page fault
  65. DW I_EXCEPTION ;This should be DPMI-hooked
  66. ;** This entry is a special case entry for the Win30 std mode
  67. ;* handler. This is a separate entry point into the
  68. ;** interrupt handler routine
  69. DW OFFSET _TEXT:PF_StdModeHandler
  70. DW 0
  71. DW OFFSET _TEXT:PF_Handler
  72. CASRq_Info DW 256 ;CtlAltSysRq (fake interrupt)
  73. DW I_INTERRUPT ;Hook with DOS
  74. DD 0 ;Chain address
  75. DW OFFSET _TEXT:CASRq_Handler
  76. ;** The following data is used to see if GDI wants the
  77. ;** Div0 we have trapped
  78. lpGDIFlag DD 0
  79. hGDI DW 0
  80. szGDI DB 'GDI', 0
  81. public lpGDIFlag, hGDI
  82. ;** Points to a KERNEL routine to see if it wants the
  83. ;** GP fault first
  84. lpfnPV DD 0 ;Call to see if PV GP fault
  85. public lpfnPV
  86. ;** Globals used for DPMI emulation
  87. lpOldHandler DD 0 ;Previous DPMI exception handler
  88. lpChainCSIP DD 0 ;Next exception handler on chain
  89. wException DW 0
  90. public lpOldHandler, lpChainCSIP
  91. externW wCASRqFlag ;Set when an CASRq INT3 has been set
  92. externD dwCASRqCSIP ;Holds the CS:IP of the CASRq INT3
  93. sEnd
  94. ;** Imports
  95. externNP TerminateApp
  96. externNP HelperHandleToSel
  97. externNP HelperVerifySeg
  98. externFP AllocCStoDSAlias
  99. externFP FreeSelector
  100. externFP GetModuleHandle
  101. externFP GetProcAddress
  102. externFP GlobalEntryHandle
  103. externFP _wsprintf
  104. externFP OutputDebugString
  105. externA __WinFlags
  106. ;** Functions
  107. sBegin CODE
  108. assumes CS,CODE
  109. assumes DS,DATA
  110. ;** Interrupt trapping API
  111. ; InterruptInit
  112. ; Hooks all necessary interrupts and exceptions to allow an API
  113. ; for app-level interrupt hooks.
  114. cProc InterruptInit, <NEAR,PUBLIC>, <si,di>
  115. cBegin
  116. ;** Loop through all possible handlers
  117. mov cx,MAX_INTERRUPT ;Number of ints to hook
  118. lea si,IntInfo ;Get the address of the array
  119. DII_HandlerLoop:
  120. push cx ;Save loop counter
  121. cmp [si].ii_wNumber,256 ;Fake exception?
  122. jae DII_Continue ;Yes, don't hook anything!
  123. cmp [si].ii_wType,I_EXCEPTION ;Exception?
  124. jnz DII_Interrupt ;Nope, hook as interrupt
  125. ;** Do a special case for 3.0 Std Mode
  126. test wTHFlags,TH_WIN30STDMODE ;Are we in Win30 std mode?
  127. jz DII_NotStdMode ;No.
  128. mov ax,WORD PTR [si].ii_dwChain ;Get the secondary handler
  129. mov [si].ii_wHandler,ax ;Make sure we use it instead!
  130. DII_NotStdMode:
  131. ;** Hook as an exception (DPMI)
  132. mov ax,0202h ;Get exception handler - DPMI
  133. mov bl,BYTE PTR [si].ii_wNumber ;Interrupt number
  134. int 31h ;Call DPMI
  135. mov WORD PTR [si].ii_dwChain,dx ;Save the old offset
  136. mov WORD PTR [si].ii_dwChain + 2,cx ;Save the old selector
  137. mov ax,0203h ;Set exception handler - DPMI
  138. mov bl,BYTE PTR [si].ii_wNumber ;Interrupt number
  139. mov dx,[si].ii_wHandler ;Address of exception handler
  140. mov cx,cs ;Selector value of handler
  141. int 31h ;Call DPMI
  142. jmp SHORT DII_Continue
  143. ;** Hook as an interrupt (DOS)
  144. DII_Interrupt:
  145. mov ah,35h ;Get interrrupt handler - DOS
  146. mov al,BYTE PTR [si].ii_wNumber ;Interrupt number
  147. int 21h ;Call DOS
  148. mov WORD PTR [si].ii_dwChain,bx ;Save the old offset
  149. mov WORD PTR [si].ii_dwChain + 2,es ;Save the old selector
  150. mov ah,25h ;Set interrupt handler - DOS
  151. mov al,BYTE PTR [si].ii_wNumber ;Interrupt number
  152. mov dx,[si].ii_wHandler ;Address of exception handler
  153. push ds ;Save static DS for later
  154. push cs ;DS = CS
  155. pop ds
  156. int 21h ;Call DOS
  157. pop ds ;Get segment back
  158. ;** Prepare for next in table
  159. DII_Continue:
  160. add si,SIZE INT_INFO ;Bump to next entry
  161. pop cx ;Get loop counter back
  162. loop DII_HandlerLoop ;Loop back
  163. ;** Prepare the linked list
  164. mov npIntHead,0 ;Put a NULL in the list head
  165. ;** Get information so we can check the GDI flag
  166. lea ax,szGDI ;Get the string
  167. cCall GetModuleHandle, <ds,ax> ;Get GDI's module handle
  168. cCall HelperHandleToSel, <ax> ;Convert the owner to a selector
  169. mov hGDI,ax ;Save it for later
  170. cCall GetProcAddress, <ax,0,355> ;The flag is ordinal 355
  171. mov WORD PTR lpGDIFlag[0],ax ;Save it for later
  172. mov WORD PTR lpGDIFlag[2],dx
  173. DII_End:
  174. ;** Return TRUE
  175. mov ax,1
  176. cEnd
  177. ; InterruptUnInit
  178. ; Unhooks all interrupts and exceptions hooked by DebugInterruptUnInit.
  179. cProc InterruptUnInit, <NEAR,PUBLIC>, <si,di>
  180. cBegin
  181. ;** Loop through all possible handlers
  182. mov cx,MAX_INTERRUPT ;Number of ints to hook
  183. lea si,IntInfo ;Get the address of the array
  184. DIU_HandlerLoop:
  185. push cx ;Save loop counter
  186. cmp [si].ii_wNumber,256 ;Fake exception?
  187. jae DIU_Continue ;Yes, don't unhook anything!
  188. cmp [si].ii_wType,I_EXCEPTION ;Exception?
  189. jnz DIU_Interrupt ;Nope, hook as interrupt
  190. ;** Unhook exception (DPMI)
  191. mov ax,0203h ;Set exception handler - DPMI
  192. mov bl,BYTE PTR [si].ii_wNumber ;Interrupt number
  193. mov dx,WORD PTR [si].ii_dwChain ;Put back the old offset
  194. mov cx,WORD PTR [si].ii_dwChain + 2 ;Put back the old selector
  195. int 31h ;Call DPMI
  196. jmp SHORT DIU_Continue
  197. ;** Unhook interrupt (DOS)
  198. DIU_Interrupt:
  199. mov ah,35h ;Get interrrupt handler - DOS
  200. mov al,BYTE PTR [si].ii_wNumber ;Interrupt number
  201. int 21h ;Call DOS
  202. mov ah,25h ;Set interrupt handler - DOS
  203. mov al,BYTE PTR [si].ii_wNumber ;Interrupt number
  204. mov dx,WORD PTR [si].ii_dwChain ;Put back the old offset
  205. push ds
  206. mov ds,WORD PTR [si].ii_dwChain + 2 ;Put back the old selector
  207. int 21h ;Call DOS
  208. pop ds
  209. ;** Prepare for next in table
  210. DIU_Continue:
  211. add si,SIZE INT_INFO ;Bump to next entry
  212. pop cx ;Get loop counter back
  213. loop DIU_HandlerLoop ;Loop back
  214. ;** Prepare the linked list
  215. mov npIntHead,0 ;Put a NULL in the list head
  216. DIU_End:
  217. cEnd
  218. InterruptEntry MACRO Name, wBytes
  219. labelFP Name ;;Start at this address
  220. PUBLIC Name
  221. sub sp,wBytes ;;Leave room on stack for return val
  222. push bx ;;Save for the info pointer
  223. ENDM
  224. InterruptJump MACRO pInfo
  225. mov bx,OFFSET pInfo ;;Point to interrupt info
  226. jmp DIH_Main
  227. ENDM
  228. ; InterruptHandler
  229. ; This routine is used to handle interrupts as they come in. This
  230. ; routine has multiple entry points; a seperate one for each int/
  231. ; exception trapped. Because interrupts and exceptions have
  232. ; different stack frames, they are handled by two different code
  233. ; sections.
  234. cProc InterruptHandler, <FAR,PUBLIC>
  235. cBegin NOGEN
  236. ;** All interrupt entry points here
  237. InterruptEntry GP_Handler, 14 ;Normal GP fault
  238. InterruptJump GP_Info
  239. InterruptEntry GP_StdModeHandler, 12 ;3.0 Std mode GP fault
  240. InterruptJump GP_Info
  241. InterruptEntry SF_Handler, 14 ;Normal Stack Fault
  242. InterruptJump SF_Info
  243. InterruptEntry SF_StdModeHandler, 12 ;3.0 Std mode Stack Fault
  244. InterruptJump SF_Info
  245. InterruptEntry PF_Handler, 14 ;Page fault
  246. InterruptJump PF_Info
  247. InterruptEntry PF_StdModeHandler, 10 ;3.0 Std mode Page fault
  248. InterruptJump PF_Info
  249. InterruptEntry UD_Handler, 14 ;Undefined opcode
  250. InterruptJump UD_Info
  251. InterruptEntry Int1_Handler, 14 ;Int 1
  252. InterruptJump Int1_Info
  253. InterruptEntry Int3_Handler, 14 ;Int 3
  254. InterruptJump Int3_Info
  255. InterruptEntry CASRq_Handler, 14 ;Ctrl-Alt-SysRq (not really an int)
  256. InterruptJump CASRq_Info
  257. ;** The divide by zero case has to include checking to make sure
  258. ;** that this isn't GDI's divide by zero.
  259. InterruptEntry Div0_Handler, 14
  260. ;** Check to see if GDI wants this Div0
  261. push ds ;Save some registers
  262. push es
  263. mov bx,_DATA ;Point to our data
  264. mov ds,bx ; with DS
  265. mov bx,WORD PTR lpGDIFlag[0];Get the low word
  266. push bx
  267. or bx,WORD PTR lpGDIFlag[2];Do we have a flag to look at?
  268. pop bx
  269. jz DIH_NoFlag ;No. Do this the hard way
  270. ;** Since we have a pointer to GDI's flag to look at, use it
  271. mov es,WORD PTR lpGDIFlag[2];Get the seg value
  272. cmp WORD PTR es:[bx],0 ;The flag is nonzero if GDI wants it
  273. je DIH_NormalDiv0 ;GDI doesn't want it
  274. ;** GDI wants the Div0 so chain to it
  275. DIH_ChainToGDI:
  276. pop es ;Restore registers
  277. pop ds ; (Doesn't trash flags)
  278. push bp ;Make the same stack frame for compat
  279. mov bp,sp
  280. pusha ;Save all registers
  281. push ds
  282. push es
  283. mov ax,_DATA ;Get the data segment
  284. mov ds,ax ;Point with DS
  285. mov bx,OFFSET Div0_Info ;This fault's info
  286. jmp DIH_DPMIChainOn ;Chain on (ignore the int)
  287. DIH_NormalDiv0:
  288. pop es ;Restore registers
  289. pop ds
  290. InterruptJump Div0_Info
  291. ;** We didn't get a GDI flag (only present in 3.1) so instead, we
  292. ;* check the owner of the CS where the fault occurred. If
  293. ;** the owner is GDI, we ignore the Div0.
  294. DIH_NoFlag:
  295. push bp ;Make a stack frame
  296. mov bp,sp
  297. sub sp,SIZE GLOBALENTRY ;Make room for a structure
  298. Global EQU [bp - SIZE GLOBALENTRY] ;Point to our structure
  299. pusha ;Save all registers
  300. mov WORD PTR Global.ge_dwSize[0],SIZE GLOBALENTRY ;Size of struct
  301. mov WORD PTR Global.ge_dwSize[2],0
  302. lea bx,Global ;Point to the structure
  303. test wTHFlags,TH_WIN30STDMODE ;3.0 std mode?
  304. jnz DIH_Div0_StdMode ;Yes
  305. mov ax,[bp + 1ah + 4] ;Get the CS value (4 is extra BP,BX
  306. jmp SHORT @F ; pushed by InterruptEntry macro)
  307. DIH_Div0_StdMode:
  308. mov ax,[bp + 14h + 4] ;Get the CS value
  309. @@: cCall GlobalEntryHandle, <ss,bx,ax> ;Get info about the CS
  310. or ax,ax ;Did the call succeed?
  311. jne @F ;Yes, go on
  312. popa ;No, clear stack frame and do normal
  313. mov sp,bp
  314. pop bp
  315. jmp DIH_NormalDiv0 ;Jump to normal processing
  316. @@: mov ax,Global.ge_hOwner ;Get the owner
  317. cCall HelperHandleToSel, <ax> ;Make it a selector
  318. cmp hGDI,ax ;Is this owned by GDI?
  319. popa ;Restore the registers
  320. mov sp,bp ;Clear stack frame
  321. pop bp
  322. je DIH_ChainToGDI ;Yes, so give the interrupt to it
  323. jmp DIH_NormalDiv0 ;No, do normal stuff
  324. ;** We now have to first find the item on the block to see if we
  325. ;** want to handle the interrupt.
  326. PubLabel CommonInterruptEntry
  327. DIH_Main:
  328. push bp ;Make a stack frame
  329. mov bp,sp
  330. pusha ;Save all registers
  331. push ds
  332. push es
  333. ;** We check first to see if this was a GP fault received from the
  334. ;* parameter validation code. If it was, we just chain on
  335. ;* just as if we don't find any handlers.
  336. ;**
  337. mov ax,_DATA ;Get our data segment
  338. mov ds,ax
  339. FSTI ;Must have interrupts on
  340. cmp bx,OFFSET GP_Info ;GP Fault?
  341. jnz DIH_NotPVGPFault ;No.
  342. mov cx,WORD PTR lpfnPV[0] ;Get the low word
  343. or cx,WORD PTR lpfnPV[2] ;Param Validation stuff present?
  344. jz DIH_NotPVGPFault ;No, skip this
  345. ;** Check to see if the parameter validation code wants the fault
  346. push ds
  347. push bx
  348. push [bp + 1Ah] ;Push faulting CS:IP
  349. push [bp + 18h]
  350. call [lpfnPV] ;Call it
  351. pop bx
  352. pop ds
  353. or ax,ax ;Non-zero means this was PV fault
  354. je DIH_NotPVGPFault ;Not a PV GP fault
  355. ;** It is a parameter validation fault so ignore it
  356. jmp DIH_DPMIChainOn ;Chain the fault on--we don't want it
  357. ;** We check here to see if the INT3 we received is from the CASRq
  358. ;* handler. If it was, we have to replace the INT3 with the
  359. ;* previous byte and tell the user this was actually a CASRq
  360. ;** event (not an INT3).
  361. PubLabel DIH_NotPVGPFault
  362. cmp bx,OFFSET Int3_Info ;INT3?
  363. jnz DIH_NotCASRq ;Nope, ignore all this
  364. cmp wCASRqFlag,0 ;Was this because of CASRq?
  365. je DIH_NotCASRq ;No.
  366. mov ax,[bp + 12h] ;INT3 is an IRET frame. Get bkpt IP
  367. dec ax ;Breaks AFTER instruction
  368. cmp WORD PTR dwCASRqCSIP[0],ax ;Is this the right CASRq address?
  369. jne DIH_NotCASRq ;Nope
  370. mov dx,[bp + 14h] ;Get the breakpoint CS
  371. cmp WORD PTR dwCASRqCSIP[2],dx ;Is this correct?
  372. jne DIH_NotCASRq ;Nope
  373. push ax ;Save the IP value
  374. cCall AllocCStoDSAlias, <dx> ;Get a data alias to the CS
  375. mov es,ax ;Point with ES
  376. pop si ;Restore the IP value
  377. mov [bp + 12h],si ;Back to instr where INT3 was
  378. mov al,BYTE PTR wCASRqFlag ;Get the saved byte
  379. mov es:[si],al ;Put it back in the code
  380. mov wCASRqFlag,0 ;Clear the flag
  381. cCall FreeSelector, <es> ;Get rid of the alias
  382. mov bx,OFFSET CASRq_Info ;Point to the CASRq information
  383. ;** See if we have at least one handler. We should always have one.
  384. PubLabel DIH_NotCASRq
  385. mov si,npIntHead ;Get the list start
  386. or si,si ;Are there any routines hooked?
  387. jnz DIH_Found ;There should ALWAYS be at least one
  388. ; routine hooked (otherwise, the
  389. ; interrupt hooks should have
  390. ; already been removed)
  391. ;** Return the stack to its prior state and chain on.
  392. ;* We only get here in an erroneous state. We keep the code in
  393. ;* to avoid GP faulting if things get wierd.
  394. ;* The stack looks like this:
  395. ;* ------------
  396. ;* | ES |
  397. ;* | DS |
  398. ;* | PUSHA |
  399. ;* BP-->| Old BP | [BP + 00h]
  400. ;* | BX | [BP + 02h]
  401. ;* | Empty | [BP + 04h]
  402. ;* | Empty | [BP + 06h]
  403. ;* | Empty | [BP + 08h]
  404. ;* | Empty | [BP + 0Ah]
  405. ;* | Empty | [BP + 0Ch]
  406. ;* |Our Ret IP| [BP + 0Eh]
  407. ;* |Our Ret CS| [BP + 10h]
  408. ;* |Original |
  409. ;* | Frame |
  410. ;* | .... |
  411. ;* ------------
  412. ;**
  413. PubLabel DIH_DPMIChainOn
  414. mov ax,WORD PTR [bx].ii_dwChain ;Get the LOWORD
  415. mov [bp + 0eh],ax ;Put into the frame we created
  416. mov ax,WORD PTR [bx].ii_dwChain + 2 ;Get the HIWORD
  417. mov [bp + 10h],ax ;Put into the frame
  418. pop es ;Clear the stack
  419. pop ds
  420. popa
  421. pop bp
  422. pop bx
  423. add sp,10 ;Clear extra space
  424. retf ;This uses our own "return" frame
  425. ; to chain on
  426. ;** Since we found the entry, we have to call the user callback.
  427. ;* Because we must be reentrant at this state, we have to make
  428. ;* sure that we're safe. To do so, we must do different
  429. ;** actions for DPMI and for DOS frames.
  430. PubLabel DIH_Found
  431. cmp [bx].ii_wType,I_EXCEPTION ;DPMI Exception frame?
  432. je @F
  433. jmp DIH_SkipDPMI ;No. Skip DPMI processing
  434. @@:
  435. ;** If we are in Win3.0 Std Mode, the DPMI frame was broken. It
  436. ;* simply left the normal IRET frame on the stack *AND* the
  437. ;** error code.
  438. test wTHFlags,TH_Win30StdMode ;3.0 Std mode?
  439. jz @F
  440. jmp DIH_SkipDPMI ;Yes
  441. @@:
  442. ;** Tell DPMI that the exception is over. Before we do this,
  443. ;* however, save information we'll need later on the user stack.
  444. ;* The stack currently looks like this:
  445. ;* ------------
  446. ;* | ES |
  447. ;* | DS |
  448. ;* | PUSHA |
  449. ;* BP-->| Old BP | [BP + 00h]
  450. ;* | BX | [BP + 02h]
  451. ;* | Empty | [BP + 04h]
  452. ;* | Empty | [BP + 06h]
  453. ;* | Empty | [BP + 08h]
  454. ;* | Empty | [BP + 0Ah]
  455. ;* | Empty | [BP + 0Ch]
  456. ;* | Empty | [BP + 0Eh]
  457. ;* | Empty | [BP + 10h]
  458. ;* | Ret IP | [BP + 12h] <-
  459. ;* | Ret CS | [BP + 14h] |
  460. ;* |Error Code| [BP + 16h] | Pushed by DPMI
  461. ;* | IP | [BP + 18h] |
  462. ;* | CS | [BP + 1Ah] | (Locked stack)
  463. ;* | Flags | [BP + 1Ch] |
  464. ;* | SP | [BP + 1Eh] |
  465. ;* | SS | [BP + 20h] <-
  466. ;* ------------
  467. ;*
  468. ;* Before returning to DPMI, however, we want to create a
  469. ;* stack frame on the user's stack that we will be returning
  470. ;* to so we can preserve information in a reentrant fashion.
  471. ;* The user's stack will appear like this:
  472. ;* ------------
  473. ;* BP---->| Old BP | [BP + 00h]
  474. ;* | BX | [BP + 02h]
  475. ;* |Our Ret IP| [BP + 04h]
  476. ;* |Our Ret CS| [BP + 06h]
  477. ;* | Ret IP | [BP + 08h]
  478. ;* | Ret CS | [BP + 0Ah]
  479. ;* | AX | [BP + 0Ch]
  480. ;* |Exception#| [BP + 0Eh]
  481. ;* | Handle | [BP + 10h]
  482. ;* | IP | [BP + 12h]
  483. ;* | CS | [BP + 14h]
  484. ;* | Flags | [BP + 16h]
  485. ;* ------------
  486. ;**
  487. PubLabel DIH_Exception
  488. ;** Check to see if we're already on the faulting stack. If we are,
  489. ;** we want to shift everything up on this stack so that we
  490. ;** have room for the TOOLHELP user frame
  491. mov ax,ss ;Get the current SS
  492. cmp ax,WORD PTR ss:[bp + 20h] ;Is it the same as the user frame?
  493. jne DIH_EnoughRoomOnStack ;No, ignore all of this
  494. ;** Move everything up by copy everything that's on stack now to
  495. ;** above where SP starts at. This actually uses too much
  496. ;** stack, but it's safe and easy.
  497. push bp ;We use BP to do copy
  498. lea bp,[bp + 20h] ;Point to lowest WORD to copy
  499. mov ax,sp ;Point to position to copy to
  500. dec ax
  501. dec ax
  502. DIH_CopyLoop:
  503. push WORD PTR [bp] ;Copy a WORD
  504. dec bp ;Point to next WORD to copy
  505. dec bp
  506. cmp bp,ax ;Done yet?
  507. jne DIH_CopyLoop ;No
  508. pop bp ;Yes, compute new BP value
  509. sub bp,56 ;Point BP to right place
  510. ;** Put stuff on DPMI's stack
  511. PubLabel DIH_EnoughRoomOnStack
  512. mov di,[bp + 1Eh] ;Get the old SP value
  513. mov cx,[bp + 20h] ; and the SS value
  514. cmp di,MIN_STACK_ALLOWED ;Are we going to stack fault?
  515. jb DIH_BadStack ;Yes, so swich
  516. mov ax,__WinFlags ;Make sure we have a 386 or higher
  517. test ax,WF_CPU286
  518. jnz DIH_SkipBigCheck ;No need to check big bit
  519. .386p
  520. push eax ;Make sure we don't trash EAX
  521. lar eax,ecx ;Get the access rights DWORD
  522. test eax,00400000h ;Check the BIG bit
  523. pop eax
  524. jnz DIH_BadStack ;Don't use this stack if BIG
  525. .286p
  526. DIH_SkipBigCheck:
  527. mov ax,di ;Get the stack pointer
  528. add ax,2 ;Point just beyond
  529. cCall HelperVerifySeg, <cx,ax> ;Is this seg OK?
  530. or ax,ax ;Check for success
  531. jz DIH_BadStack ;Stack is bogus, don't change to it
  532. PubLabel DIH_StackOK
  533. sub di,20 ;Reserve space for the user frame
  534. mov ds,cx ;Get stack value in DS
  535. mov dx,[bp + 1Ah] ;Get the old CS value
  536. mov cx,[bp + 18h] ;Get the old IP value
  537. mov ax,[bp + 1Ch] ;Get the old flags
  538. mov [bp + 1Eh],di ;Save as new SP value
  539. sub di,4 ;Make DI equal to what BP will be
  540. mov [bp + 1Ah],cs ;Prepare to IRET to ourself
  541. mov [bp + 18h],OFFSET _TEXT:DIH_DPMIRestart
  542. ;** Save some things on the user's stack before returning
  543. mov [di + 16h],ax ;Save the flags
  544. mov [di + 14h],dx ;Save the old CS value
  545. mov [di + 12h],cx ;Save the old IP value
  546. mov [di + 0Eh],bx ;INT_INFO pointer to new stack
  547. mov [di + 10h],si ;Handle to new stack
  548. ;** Clear the Trace and Ints Enabled flags
  549. and [bp + 1Ch],NOT 0100h ;Clear TF. We don't want to trace here
  550. pop es ;Clear the DPMI stack
  551. pop ds
  552. popa
  553. pop bp
  554. pop bx
  555. add sp,14 ;Clear extra allocated space
  556. retf
  557. ;** The user stack is bad, so we want to stay on the fault handler
  558. ;** stack. In order to do this, we have to build a frame for
  559. ;** the callback directly on the fault handler stack.
  560. ;** We build the frame here and jump to it.
  561. ;** ------------
  562. ;** | ES |
  563. ;** | DS |
  564. ;** | PUSHA |
  565. ;** BP-->| Old BP | [BP + 00h]
  566. ;** | BX | [BP + 02h]
  567. ;** | Empty | [BP + 04h]
  568. ;** |Our Ret IP| [BP + 06h] ; Client callback addr
  569. ;** |Our Ret CS| [BP + 08h]
  570. ;** | Ret IP | [BP + 0Ah] ; TOOLHELP restart addr
  571. ;** | Ret CS | [BP + 0Ch]
  572. ;** | AX | [BP + 0Eh] ; Saved AX for MPI
  573. ;** |Exception#| [BP + 10h] ; Exception number
  574. ;** | Handle | [BP + 12h] ; TOOLHELP handle
  575. ;** | IP | [BP + 14h] ; IRET frame of fault
  576. ;** | CS | [BP + 16h]
  577. ;** | Flags | [BP + 18h]
  578. ;** | SP | [BP + 1Ah] ; Faulting SS:SP
  579. ;** | SS | [BP + 1Ch]
  580. ;** | Ret IP | [BP + 1Eh] ; DPMI return address
  581. ;** | Ret CS | [BP + 20h]
  582. ;** ------------
  583. PubLabel DIH_BadStack
  584. mov dx,[bp + 12h] ;DPMI return CS:IP
  585. mov cx,[bp + 14h] ; stored in CX:DX
  586. mov ax,[bp + 18h] ;Faulting IP
  587. mov [bp + 14h],ax
  588. mov ax,[bp + 1Ah] ;Faulting CS
  589. mov [bp + 16h],ax
  590. mov ax,[bp + 1Ch] ;Flags
  591. mov [bp + 18h],ax
  592. mov ax,[bp + 1Eh] ;Faulting SP
  593. mov [bp + 1Ah],ax
  594. mov ax,[bp + 20h] ;Faulting SS
  595. mov [bp + 1Ch],ax
  596. mov [bp + 1Eh],dx ;DPMI ret IP
  597. mov [bp + 20h],cx ;DPMI ret CS
  598. mov [bp + 12h],si ;Point to INTERRUPT struct
  599. mov ax,[bx].ii_wNumber ;Get the interrupt number
  600. or ax,BAD_STACK_FLAG ;Flag the client that stack is bad
  601. mov [bp + 10h],ax
  602. mov ax,[bp - 02h] ;Get the AX value from the PUSHA frame
  603. mov [bp + 0Eh],ax
  604. mov [bp + 0Ch],cs ;Point to callback return address
  605. mov [bp + 0Ah],OFFSET _TEXT:DIH_CallbackRestart
  606. mov ax,WORD PTR [si].i_lpfn ;Point to the user callback OFFSET
  607. mov [bp + 06h],ax
  608. mov ax,WORD PTR [si].i_lpfn + 2 ;Point to callback segment
  609. mov [bp + 08h],ax
  610. pop es ;Clear the stack
  611. pop ds
  612. popa
  613. pop bp
  614. pop bx
  615. add sp,2
  616. retf ;Jump to the user callback
  617. ;** At this point, DPMI IRETs back to us instead of to the faulting
  618. ;** app. We have to now create a stack frame identical to the
  619. ;** frame used by interrupt-style hooks. Note that we have
  620. ;** already allocated the frame space (but not initialized it)
  621. ;** before returning to DPMI.
  622. ;** It will look like this:
  623. ;** ------------
  624. ;** | ES | [BP - 14h]
  625. ;** | DS | [BP - 12h]
  626. ;** | DI | [BP - 10h]
  627. ;** | SI | [BP - 0Eh]
  628. ;** | BP | [BP - 0Ch]
  629. ;** | SP | [BP - 0Ah]
  630. ;** | BX | [BP - 08h]
  631. ;** | DX | [BP - 06h]
  632. ;** | CX | [BP - 04h]
  633. ;** | AX | [BP - 02h]
  634. ;** BP---->| Old BP | [BP + 00h]
  635. ;** | BX | [BP + 02h]
  636. ;** |Our Ret IP| [BP + 04h]
  637. ;** |Our Ret CS| [BP + 06h]
  638. ;** | Ret IP | [BP + 08h]
  639. ;** | Ret CS | [BP + 0Ah]
  640. ;** | AX | [BP + 0Ch]
  641. ;** |Exception#| [BP + 0Eh]
  642. ;** | Handle | [BP + 10h]
  643. ;** | IP | [BP + 12h]
  644. ;** | CS | [BP + 14h]
  645. ;** | Flags | [BP + 16h]
  646. ;** ------------
  647. ;**
  648. PubLabel DIH_DPMIRestart
  649. push bx ;Save this register we're using
  650. push bp ;Make a stack frame
  651. mov bp,sp
  652. pusha ;Save all the registers
  653. push ds
  654. push es
  655. mov bx,[bp + 0Eh] ;Get the INT_INFO pointer back
  656. mov si,[bp + 10h] ;Get the INTERRUPT structure back
  657. mov ax,_DATA ;Get our data segment
  658. mov ds,ax
  659. ;** We can now proceed with joint processing as we've matched the
  660. ;** DOS interrupt frame
  661. PubLabel DIH_SkipDPMI
  662. ;** Build our return frame and jump to the user callback
  663. mov [bp + 10h],si ;Point to INTERRUPT struct
  664. mov ax,[bx].ii_wNumber ;Get the interrupt number
  665. mov [bp + 0Eh],ax ;Put on frame
  666. mov ax,[bp - 02h] ;Get the AX value from the PUSHA frame
  667. mov [bp + 0Ch],ax ;Put on frame
  668. mov [bp + 0Ah],cs ;Point to callback return address
  669. mov [bp + 08h],OFFSET _TEXT:DIH_CallbackRestart
  670. mov ax,WORD PTR [si].i_lpfn ;Point to the user callback OFFSET
  671. mov [bp + 04h],ax
  672. mov ax,WORD PTR [si].i_lpfn + 2 ;Point to callback segment
  673. mov [bp + 06h],ax
  674. pop es ;Clear the stack
  675. pop ds
  676. popa
  677. pop bp
  678. pop bx
  679. retf ;Jump to the user callback
  680. ;** When the callback returns, we have to know how to call the
  681. ;* next matching callback or to chain on the interrupt list.
  682. ;* We have to do a raft of special stuff if this was an
  683. ;* exception so that the chained on handlers think it was
  684. ;** DPMI that called them.
  685. PubLabel DIH_CallbackRestart
  686. sub sp,8 ;Leave room for ret addresses
  687. push bx ;For compat. with the above code
  688. push bp ;Make the same stack frame
  689. mov bp,sp
  690. pusha
  691. push ds
  692. push es
  693. ;** Get the next matching item on the list
  694. mov ax,_DATA ;Get our data segment
  695. mov ds,ax
  696. mov ax,[bp + 0Ch] ;Get the saved AX value
  697. mov [bp - 02h],ax ;Put in PUSHA frame
  698. mov si,[bp + 10h] ;Get the last handle used
  699. or si,si ;If NULL, app has messed with it
  700. jz DIH_NukeIt ;Nuke the app--it did a no-no
  701. mov si,[si].i_pNext ;Get the next item in the list
  702. or si,si ;End of the line?
  703. jz DIH_NextNotFound ;Yes, chain on
  704. mov ax,[bp + 0Eh] ;Get the exception number
  705. cCall InterruptInfo ;Get the INT_INFO structure
  706. or ax,ax ;If NULL return, user messed with #
  707. jz DIH_NukeIt ; so nuke it
  708. mov bx,ax ;Point with BX
  709. jmp DIH_SkipDPMI ;Process this one
  710. ;** If we don't find a match, we pass on to previous handler
  711. PubLabel DIH_NextNotFound
  712. mov ax,[bp + 0Eh] ;Get the exception number
  713. and ax,7fffh ;Clear the new stack bit
  714. cCall InterruptInfo ;Find the INT_INFO structure
  715. or ax,ax ;If the user messed with it,
  716. jz DIH_NukeIt ; nuke the app.
  717. mov si,ax ;Get the pointer in AX
  718. test wTHFlags,TH_Win30StdMode ;3.0 Std mode?
  719. jnz DIH_30StdChainOn ;Always do normal chain on in 3.0sm
  720. cmp [si].ii_wType,I_INTERRUPT ;Was this an interrupt?
  721. je DIH_ChainOn ;Yes, do normal chain on
  722. jmp DIH_EmulateDPMI ;No, do the DPMI chain on
  723. PubLabel DIH_NukeIt
  724. push [bp + 16h] ;Copy the IRET frame for KERNEL
  725. push [bp + 14h]
  726. push [bp + 12h]
  727. push 0 ;Nuke current task
  728. push UAE_BOX OR GIVE_WDEB386 ;UAE box + give to wdeb
  729. push cs ;Simulate a far jump
  730. call NEAR PTR TerminateApp ;Nuke the app
  731. ;** We only get here if WDEB386 is installed. We tell it to set
  732. ;* a breakpoint, then restart the app, in effect giving
  733. ;* control to WDEB386. Unfortunately, at this point, all
  734. ;** fault handlers for this task have been removed
  735. add sp,6 ;Clear fake IRET frame
  736. mov cx,[bp + 14h] ;Faulting CS
  737. mov bx,[bp + 12h] ;Faulting IP
  738. mov ax, 40h ;16 bit forced go command
  739. int 41h ;Call debugger
  740. pop es ;Restore registers and clear stack
  741. pop ds
  742. popa
  743. pop bp
  744. pop bx
  745. add sp,14 ;Clear extra words
  746. ; all that remains is IRET frame
  747. iret ;WDEB386 will get control
  748. PubLabel DIH_NukeApp
  749. push 0 ;Nuke current task
  750. push UAE_BOX ;Draw the UAE box
  751. push cs ;Simulate a far jump
  752. call NEAR PTR TerminateApp ;Nuke the app
  753. int 1 ;Should never return
  754. jmp SHORT DIH_ChainOn
  755. ;** In 3.0 standard mode we have to put an error code on the stack
  756. ;** if it's a GP fault or. If not, we just chain on normally
  757. PubLabel DIH_30StdChainOn
  758. cmp si,OFFSET GP_Info ;Is this a GP fault?
  759. jne DIH_ChainOn ;No, handle normally
  760. mov ax,WORD PTR [si].ii_dwChain ;Get the LOWORD
  761. mov dx,WORD PTR [si].ii_dwChain + 2 ;Get HIWORD
  762. mov bx,ax ;Save the LOWORD
  763. or ax,dx ;Is there a chain on address?
  764. jz DIH_NoChainAddr ;No, just restart the instruction
  765. mov [bp + 0Ch],bx ;Put on stack so we can retf to it
  766. mov [bp + 0Eh],dx
  767. mov WORD PTR [bp + 10h],0 ;Zero the error code
  768. pop es ;Restore registers and clear stack
  769. pop ds
  770. popa
  771. pop bp
  772. pop bx
  773. add sp,8 ;Clear extra words
  774. retf
  775. PubLabel DIH_ChainOn
  776. mov ax,WORD PTR [si].ii_dwChain ;Get the LOWORD
  777. mov dx,WORD PTR [si].ii_dwChain + 2 ;Get HIWORD
  778. mov bx,ax ;Save the LOWORD
  779. or ax,dx ;Is there a chain on address?
  780. jz DIH_NoChainAddr ;No, just restart the instruction
  781. mov [bp + 0Eh],bx ;Put on stack so we can retf to it
  782. mov [bp + 10h],dx
  783. pop es ;Restore registers and clear stack
  784. pop ds
  785. popa
  786. pop bp
  787. pop bx
  788. add sp,10 ;Clear extra words
  789. retf
  790. ;** No chain on address was recorded so just restart the instruction
  791. PubLabel DIH_NoChainAddr
  792. pop es
  793. pop ds
  794. popa
  795. pop bp
  796. pop bx
  797. add sp,14 ;Clear all extra words
  798. iret ; and restart instruction
  799. ;** Chain on a DPMI-style exception:
  800. ;**
  801. ;** The goal here is to make a fault frame that appears that DPMI
  802. ;** has passed the next exception handler the interrupt. We
  803. ;** have only two important cases here:
  804. ;** 1) We have already told DPMI the int was finished.
  805. ;** 2) We have not told DPMI the int was finished and
  806. ;** have not switched off the fault handler stack
  807. ;** We handle the cases differently:
  808. ;** -If we have already told DPMI that the fault was handled,
  809. ;** we have to make a new fault so that the next handler can see
  810. ;** the frame. This can be best accomplished by restarting the
  811. ;** faulting instruction. This will cause the same fault to
  812. ;** happen and will make the same frame.
  813. ;** -In the case of us still being on the fh stack, we have to
  814. ;** rebuild the frame and chain on.
  815. ;** The stack we're given looks like this:
  816. ;** ------------
  817. ;** | ES | [BP - 14h]
  818. ;** | DS | [BP - 12h]
  819. ;** | DI | [BP - 10h]
  820. ;** | SI | [BP - 0Eh]
  821. ;** | BP | [BP - 0Ch]
  822. ;** | SP | [BP - 0Ah]
  823. ;** | BX | [BP - 08h]
  824. ;** | DX | [BP - 06h]
  825. ;** | CX | [BP - 04h]
  826. ;** | AX | [BP - 02h]
  827. ;** BP---->| Old BP | [BP + 00h]
  828. ;** | BX | [BP + 02h]
  829. ;** |Our Ret IP| [BP + 04h]
  830. ;** |Our Ret CS| [BP + 06h]
  831. ;** | Ret IP | [BP + 08h]
  832. ;** | Ret CS | [BP + 0Ah]
  833. ;** | AX | [BP + 0Ch]
  834. ;** |Exception#| [BP + 0Eh]
  835. ;** | Handle | [BP + 10h]
  836. ;** | IP | [BP + 12h]
  837. ;** | CS | [BP + 14h]
  838. ;** | Flags | [BP + 16h]
  839. ;** | SP | [BP + 18h] ;Only here if on fh stack
  840. ;** | SS | [BP + 1Ah]
  841. ;** | Ret IP | [BP + 1Ch] ;DPMI return address
  842. ;** | Ret CS | [BP + 1Eh]
  843. ;** ------------
  844. PubLabel DIH_EmulateDPMI
  845. mov ax,[bp + 0Eh] ;Get the exception number
  846. test ax,BAD_STACK_FLAG ;Still on fh stack?
  847. jnz DIH_RebuildDPMIFrame ;Yes, rebuild the frame
  848. ;** Rehook the exception so we're sure to get it first
  849. push si ;Preserve handle
  850. mov bx,ax ;Fault number in bx
  851. mov wException,bx ;Save as a static also
  852. mov ax,0202h ;Get exception handler - DPMI
  853. int 31h ;Call DPMI
  854. mov WORD PTR lpOldHandler[0],dx ;Save the old exception handler
  855. mov WORD PTR lpOldHandler[2],cx
  856. mov ax,0203h ;Set exception handler - DPMI
  857. mov dx,OFFSET DIH_EmDPMIRestart
  858. mov cx,cs ;Selector value of handler
  859. int 31h ;Call DPMI
  860. pop si
  861. ;** Save the address of the next exception handler
  862. mov ax,WORD PTR [si].ii_dwChain[0] ;Address to chain fault to
  863. mov WORD PTR lpChainCSIP[0],ax
  864. mov ax,WORD PTR [si].ii_dwChain[2]
  865. mov WORD PTR lpChainCSIP[2],ax
  866. ;** Restart the instruction. This will fault and jump to our
  867. ;** newly-established handler at DIH_EmDPMIRestart
  868. pop es
  869. pop ds
  870. popa
  871. pop bp
  872. pop bx
  873. add sp,14 ;Clear all extra words
  874. iret ; and restart instruction
  875. ;** Now we're on the fault handler stack with a DPMI frame. Throw
  876. ;** it to the next handler on the chain
  877. PubLabel DIH_EmDPMIRestart
  878. sub sp,4 ;Enough room for a RETF frame
  879. push bp
  880. mov bp,sp
  881. pusha
  882. push ds
  883. push es
  884. mov ax,_DATA ;Point to TOOLHELP's DS
  885. mov ds,ax
  886. ;** Restore the exception handler
  887. mov ax,0203h ;Set exception handler - DPMI
  888. mov bx,wException ;Get exception number
  889. mov dx,WORD PTR lpOldHandler[0] ;Get the exception handler address
  890. mov cx,WORD PTR lpOldHandler[2]
  891. int 31h ;Call DPMI
  892. ;** Put the chain address on the stack so we can return to it
  893. mov ax,WORD PTR lpChainCSIP[0] ;Get chain address
  894. mov [bp + 02h],ax
  895. mov ax,WORD PTR lpChainCSIP[2]
  896. mov [bp + 04h],ax
  897. ;** Restore registers and jump to the handler
  898. pop es
  899. pop ds
  900. popa
  901. pop bp
  902. retf
  903. ;** Since we are already on the fault handler stack, there is no
  904. ;** need to fault again. All we have to do here is recreate the
  905. ;** DPMI fault stack as if the fault had just occurred. It would
  906. ;** be nice to clear the exception and then make it fault again,
  907. ;** but since we only get here in potentially stack-faulting
  908. ;** conditions, we cannot do this. We just build a reasonable
  909. ;** facsimile of the frame and chain on. This frame should
  910. ;** look as follows when we're done:
  911. ;** ------------
  912. ;** | ES | [BP - 14h]
  913. ;** | DS | [BP - 12h]
  914. ;** | DI | [BP - 10h]
  915. ;** | SI | [BP - 0Eh]
  916. ;** | BP | [BP - 0Ch]
  917. ;** | SP | [BP - 0Ah]
  918. ;** | BX | [BP - 08h]
  919. ;** | DX | [BP - 06h]
  920. ;** | CX | [BP - 04h]
  921. ;** | AX | [BP - 02h]
  922. ;** BP---->| Old BP | [BP + 00h]
  923. ;** | BX | [BP + 02h]
  924. ;** | Empty | [BP + 04h]
  925. ;** | Empty | [BP + 06h]
  926. ;** | Empty | [BP + 08h]
  927. ;** | Empty | [BP + 0Ah]
  928. ;** | Chain IP | [BP + 0Ch]
  929. ;** | Chain CS | [BP + 0Eh]
  930. ;** | Ret IP | [BP + 10h]
  931. ;** | Ret CS | [BP + 12h]
  932. ;** |Error Code| [BP + 14h] ;Always return zero
  933. ;** | IP | [BP + 16h]
  934. ;** | CS | [BP + 18h] ;Only here if on fh stack
  935. ;** | Flags | [BP + 1Ah]
  936. ;** | SP | [BP + 1Ch] ;DPMI return address
  937. ;** | SS | [BP + 1Eh]
  938. ;** ------------
  939. PubLabel DIH_RebuildDPMIFrame
  940. mov dx,[bp + 1Ch] ;DPMI return CS:IP
  941. mov cx,[bp + 1Eh] ; stored in CX:DX
  942. mov ax,[bp + 1Ah] ;Faulting SS
  943. mov [bp + 1Eh],ax
  944. mov ax,[bp + 18h] ;Faulting SP
  945. mov [bp + 1Ch],ax
  946. mov ax,[bp + 16h] ;Flags
  947. mov [bp + 1Ah],ax
  948. mov ax,[bp + 14h] ;Faulting CS
  949. mov [bp + 18h],ax
  950. mov ax,[bp + 12h] ;Faulting IP
  951. mov [bp + 16h],ax
  952. xor ax,ax ;Error code
  953. mov [bp + 14h],ax
  954. mov [bp + 12h],cx ;DPMI ret CS
  955. mov [bp + 10h],dx ;DPMI ret IP
  956. mov ax,WORD PTR [si].ii_dwChain[2] ;Address to chain fault to
  957. mov [bp + 0Eh],ax
  958. mov ax,WORD PTR [si].ii_dwChain[0]
  959. mov [bp + 0Ch],ax
  960. pop es
  961. pop ds
  962. popa
  963. pop bp
  964. pop bx
  965. add sp,8 ;Clear all extra words
  966. retf
  967. cEnd NOGEN
  968. ;** Helper functions
  969. ; InterruptInfo
  970. ; Gets a pointer to the INT_INFO structure given the interrupt
  971. ; number. Accepts the int number in AX and returns the pointer in AX.
  972. ; Preserves all other registers
  973. cProc InterruptInfo, <NEAR,PUBLIC>, <si,cx>
  974. cBegin
  975. ;** Loop through all possible handlers
  976. mov cx,MAX_INTERRUPT + 1 ;Number of ints to hook
  977. lea si,IntInfo ;Get the address of the array
  978. ;** Is this a match?
  979. II_HandlerLoop:
  980. cmp [si].ii_wNumber,ax ;Match?
  981. jz II_End ;Yes, return the pointer
  982. ;** Prepare for next in table
  983. II_Continue:
  984. add si,SIZE INT_INFO ;Bump to next entry
  985. loop II_HandlerLoop ;Loop back
  986. xor si,si ;Return NULL for not found
  987. II_End:
  988. mov ax,si ;Get return value
  989. cEnd
  990. sEnd
  991. END