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.

1887 lines
50 KiB

  1. title "Vdm Instuction Emulation"
  2. ;++
  3. ;
  4. ; Copyright (c) 1989 Microsoft Corporation
  5. ;
  6. ; Module Name:
  7. ;
  8. ; emv86.asm
  9. ;
  10. ; Abstract:
  11. ;
  12. ; This module contains the routines for emulating instructions and
  13. ; faults from v86 mode.
  14. ;
  15. ; Author:
  16. ;
  17. ; sudeep bharati (sudeepb) 16-Nov-1992
  18. ;
  19. ; Environment:
  20. ;
  21. ; Kernel mode only.
  22. ;
  23. ; Notes:
  24. ;
  25. ;
  26. ; Revision History:
  27. ;
  28. ;--
  29. .386p
  30. .xlist
  31. include ks386.inc
  32. include i386\kimacro.inc
  33. include mac386.inc
  34. include i386\mi.inc
  35. include callconv.inc
  36. include ..\..\vdm\i386\vdm.inc
  37. include vdmtib.inc
  38. .list
  39. extrn VdmOpcode0f:proc
  40. extrn _DbgPrint:proc
  41. extrn _KeI386VdmIoplAllowed:dword
  42. extrn _KeI386VirtualIntExtensions:dword
  43. EXTRNP _Ki386VdmDispatchIo,5
  44. EXTRNP _Ki386VdmDispatchStringIo,8
  45. EXTRNP _KiDispatchException,5
  46. EXTRNP _Ki386VdmReflectException,1
  47. EXTRNP _VdmEndExecution,2
  48. EXTRNP _VdmDispatchBop,1
  49. EXTRNP _VdmPrinterStatus,3
  50. EXTRNP _VdmPrinterWriteData, 3
  51. EXTRNP _VdmDispatchInterrupts,2
  52. EXTRNP _KeBugCheck,1
  53. EXTRNP _VdmSkipNpxInstruction,4
  54. EXTRNP _VdmFetchBop1,1
  55. ifdef VDMDBG
  56. EXTRNP _VdmTraceEvent,4
  57. endif
  58. extrn _ExVdmOpcodeDispatchCounts:dword
  59. extrn OpcodeIndex:byte
  60. extrn _VdmUserCr0MapIn:byte
  61. extrn _MmUserProbeAddress:DWORD
  62. page ,132
  63. ifdef VDMDBG
  64. %out Debugging version
  65. endif
  66. ; Force assume into place
  67. _PAGE SEGMENT DWORD PUBLIC 'CODE'
  68. ASSUME DS:NOTHING, ES:NOTHING, SS:NOTHING, FS:NOTHING, GS:NOTHING
  69. _PAGE ENDS
  70. _TEXT$00 SEGMENT DWORD PUBLIC 'CODE'
  71. ASSUME DS:NOTHING, ES:NOTHING, SS:NOTHING, FS:NOTHING, GS:NOTHING
  72. _TEXT$00 ENDS
  73. PAGEDATA SEGMENT DWORD PUBLIC 'DATA'
  74. ;
  75. ; Instruction emulation emulates the following instructions.
  76. ; The emulation affects the noted user mode registers.
  77. ;
  78. ;
  79. ; In V86 mode, the following instruction are emulated in the kernel
  80. ;
  81. ; Registers (E)Flags (E)SP SS CS
  82. ; PUSHF X X
  83. ; POPF X X
  84. ; INTnn X X X
  85. ; INTO X X X
  86. ; IRET X X X
  87. ; CLI X
  88. ; STI X
  89. ;
  90. ;
  91. ; INSB
  92. ; INSW
  93. ; OUTSB
  94. ; OUTSW
  95. ; INBimm
  96. ; INWimm
  97. ; OUTBimm
  98. ; OUTWimm
  99. ; INB
  100. ; INW
  101. ; OUTB
  102. ; OUTW
  103. ;
  104. ; WARNING What do we do about 32 bit io instructions??
  105. ; OpcodeDispatchV86 - table of routines used to emulate instructions
  106. ; in v86 mode.
  107. public OpcodeDispatchV86
  108. dtBEGIN OpcodeDispatchV86,OpcodeInvalidV86
  109. dtS VDM_INDEX_0F , Opcode0FV86
  110. dtS VDM_INDEX_ESPrefix , OpcodeESPrefixV86
  111. dtS VDM_INDEX_CSPrefix , OpcodeCSPrefixV86
  112. dtS VDM_INDEX_SSPrefix , OpcodeSSPrefixV86
  113. dtS VDM_INDEX_DSPrefix , OpcodeDSPrefixV86
  114. dtS VDM_INDEX_FSPrefix , OpcodeFSPrefixV86
  115. dtS VDM_INDEX_GSPrefix , OpcodeGSPrefixV86
  116. dtS VDM_INDEX_OPER32Prefix , OpcodeOPER32PrefixV86
  117. dtS VDM_INDEX_ADDR32Prefix , OpcodeADDR32PrefixV86
  118. dtS VDM_INDEX_INSB , OpcodeINSBV86
  119. dtS VDM_INDEX_INSW , OpcodeINSWV86
  120. dtS VDM_INDEX_OUTSB , OpcodeOUTSBV86
  121. dtS VDM_INDEX_OUTSW , OpcodeOUTSWV86
  122. dtS VDM_INDEX_PUSHF , OpcodePUSHFV86
  123. dtS VDM_INDEX_POPF , OpcodePOPFV86
  124. dtS VDM_INDEX_INTnn , OpcodeINTnnV86
  125. dtS VDM_INDEX_INTO , OpcodeINTOV86
  126. dtS VDM_INDEX_IRET , OpcodeIRETV86
  127. dts VDM_INDEX_NPX , OpcodeNPXV86
  128. dtS VDM_INDEX_INBimm , OpcodeINBimmV86
  129. dtS VDM_INDEX_INWimm , OpcodeINWimmV86
  130. dtS VDM_INDEX_OUTBimm , OpcodeOUTBimmV86
  131. dtS VDM_INDEX_OUTWimm , OpcodeOUTWimmV86
  132. dtS VDM_INDEX_INB , OpcodeINBV86
  133. dtS VDM_INDEX_INW , OpcodeINWV86
  134. dtS VDM_INDEX_OUTB , OpcodeOUTBV86
  135. dtS VDM_INDEX_OUTW , OpcodeOUTWV86
  136. dtS VDM_INDEX_LOCKPrefix , OpcodeLOCKPrefixV86
  137. dtS VDM_INDEX_REPNEPrefix , OpcodeREPNEPrefixV86
  138. dtS VDM_INDEX_REPPrefix , OpcodeREPPrefixV86
  139. dtS VDM_INDEX_CLI , OpcodeCLIV86
  140. dtS VDM_INDEX_STI , OpcodeSTIV86
  141. dtS VDM_INDEX_HLT , OpcodeHLTV86
  142. dtEND MAX_VDM_INDEX
  143. PAGEDATA ENDS
  144. _PAGE SEGMENT DWORD USE32 PUBLIC 'CODE'
  145. ASSUME DS:NOTHING, ES:NOTHING, SS:FLAT, FS:NOTHING, GS:NOTHING
  146. page ,132
  147. subttl "Overide Prefix Macro"
  148. ;++
  149. ;
  150. ; Routine Description:
  151. ;
  152. ; This macro generates the code for handling override prefixes
  153. ; The routine name generated is OpcodeXXXXPrefix, where XXXX is
  154. ; the name used in the macro invocation. The code will set the
  155. ; PREFIX_XXXX bit in the Prefix flags.
  156. ;
  157. ; Arguments
  158. ; name = name of prefix
  159. ; esi = address of reg info
  160. ; edx = opcode
  161. ;
  162. ; Returns
  163. ; user mode Eip advanced
  164. ; eax advanced
  165. ; edx contains next byte of opcode
  166. ;
  167. ; NOTE: This routine exits by dispatching through the table again.
  168. ;--
  169. opPrefix macro name
  170. public Opcode&name&PrefixV86
  171. Opcode&name&PrefixV86 proc
  172. or ebx,PREFIX_&name
  173. ifdef VDMDBG
  174. _DATA segment
  175. Msg&name&Prefix db 'NTVDM: Encountered override prefix &name& %lx at '
  176. db 'address %lx', 0ah, 0dh, 0
  177. _DATA ends
  178. push [ebp].TsEip
  179. push [ebp].TsSegCs
  180. push offset FLAT:Msg&name&Prefix
  181. call _DbgPrint
  182. add esp,12
  183. endif
  184. jmp OpcodeGenericPrefixV86 ; dispatch to next handler
  185. Opcode&name&PrefixV86 endp
  186. endm
  187. irp prefix, <ES, CS, SS, DS, FS, GS, OPER32, ADDR32, LOCK, REPNE, REP>
  188. opPrefix prefix
  189. endm
  190. page ,132
  191. subttl "Instruction Emulation Dispatcher for V86"
  192. ;++
  193. ;
  194. ; Routine Description:
  195. ;
  196. ; This routine dispatches to the opcode specific emulation routine,
  197. ; based on the first byte of the opcode. Two byte opcodes, and prefixes
  198. ; result in another level of dispatching, from the handling routine.
  199. ; This code is called at APC_LEVEL to prevent modifications to the
  200. ; trap frame from NtSetContextThread.
  201. ;
  202. ; Arguments:
  203. ;
  204. ; [esp+4] = pointer to trap frame
  205. ;
  206. ; Returns:
  207. ;
  208. ; EAX = 0 failure
  209. ; 1 success
  210. cPublicProc _Ki386DispatchOpcodeV86,1
  211. push ebp
  212. mov ebp, [esp+8]
  213. movzx esi,word ptr [ebp].TsSegCs
  214. shl esi,4
  215. and dword ptr [ebp].TsEip, 0FFFFH
  216. and dword ptr [ebp].TsHardwareEsp, 0FFFFH
  217. add esi,[ebp].TsEip
  218. ;
  219. ; Probe and fetch the first byte from the instruction stream.
  220. ; Since we should be at APC_LEVEL here the trap frame can't be
  221. ; modified by the set context code. We don't have to capture.
  222. ;
  223. stdCall _VdmFetchBop1, <esi>
  224. movzx edx, OpcodeIndex[eax] ;get opcode index
  225. mov edi,1
  226. xor ebx,ebx
  227. ; All handler routines will get the following on entry
  228. ; ebx -> prefix flags
  229. ; ebp -> trap frame
  230. ; cl -> byte at the faulting address
  231. ; interrupts enabled and Irql at APC level
  232. ; esi -> address of faulting instruction
  233. ; edi -> instruction length count
  234. ; All handler routines return
  235. ; EAX = 0 for failure
  236. ; EAX = 1 for success
  237. if DEVL
  238. inc _ExVdmOpcodeDispatchCounts[edx * type _ExVdmOpcodeDispatchCounts]
  239. endif
  240. ifdef VDMDBG
  241. pushad
  242. stdCall _VdmTraceEvent, <VDMTR_KERNEL_OP_V86,ecx,0,ebp>
  243. popad
  244. endif
  245. call dword ptr OpcodeDispatchV86[edx * type OpcodeDispatchV86]
  246. pop ebp
  247. stdRet _Ki386DispatchOpcodeV86
  248. stdENDP _Ki386DispatchOpcodeV86
  249. page ,132
  250. subttl "Invalid Opcode Handler"
  251. ;++
  252. ;
  253. ; Routine Description:
  254. ;
  255. ; This routine emulates an invalid opcode. It prints the invalid
  256. ; opcode message, and causes a GP fault to be reflected to the
  257. ; debuger
  258. ;
  259. ; Arguments:
  260. ; EBX -> prefix flags
  261. ; EBP -> trap frame
  262. ; CL -> byte at the faulting address
  263. ; interrupts disabled
  264. ; ESI -> address of faulting instruction
  265. ; EDI -> instruction length count
  266. ;
  267. ; Returns:
  268. ; EAX = 0 for failure
  269. ; EAX = 1 for success
  270. ;
  271. ; All registers can be trashed except ebp/esp.
  272. ;
  273. public OpcodeInvalidV86
  274. OpcodeInvalidV86 proc
  275. xor eax,eax ; ret fail
  276. ret
  277. OpcodeInvalidV86 endp
  278. page ,132
  279. subttl "Generic Prefix Handler"
  280. ;++
  281. ;
  282. ; Routine Description:
  283. ;
  284. ; This routine handles the generic portion of all of the prefixes,
  285. ; and dispatches the next byte of the opcode.
  286. ;
  287. ; Arguments:
  288. ;
  289. ; EBX -> prefix flags
  290. ; EBP -> trap frame
  291. ; CL -> byte at the faulting address
  292. ; interrupts disabled
  293. ; ESI -> address of faulting instruction
  294. ; EDI -> instruction length count
  295. ;
  296. ; Returns:
  297. ; EAX = 0 for failure
  298. ; EAX = 1 for success
  299. ;
  300. ; All registers can be trashed except ebp/esp.
  301. ;
  302. public OpcodeGenericPrefixV86
  303. OpcodeGenericPrefixV86 proc
  304. inc esi
  305. inc edi
  306. movzx ecx, byte ptr [esi]
  307. movzx edx, OpcodeIndex[ecx] ;get opcode index
  308. if DEVL
  309. inc _ExVdmOpcodeDispatchCounts[edx * type _ExVdmOpcodeDispatchCounts]
  310. endif
  311. jmp OpcodeDispatchV86[edx * type OpcodeDispatchV86]
  312. OpcodeGenericPrefixV86 endp
  313. page ,132
  314. subttl "Byte string in Opcode Handler"
  315. ;++
  316. ;
  317. ; Routine Description:
  318. ;
  319. ; This routine emulates an INSB opcode. Currently, it prints
  320. ; a message, and ignores the instruction.
  321. ;
  322. ; Arguments:
  323. ; EBX -> prefix flags
  324. ; EBP -> trap frame
  325. ; CL -> byte at the faulting address
  326. ; interrupts disabled
  327. ; ESI -> address of faulting instruction
  328. ; EDI -> instruction length count
  329. ;
  330. ; Returns:
  331. ; EAX = 0 for failure
  332. ; EAX = 1 for success
  333. ;
  334. ; All registers can be trashed except ebp/esp.
  335. ;
  336. ; WARNING size override? ds override?
  337. public OpcodeINSBV86
  338. OpcodeINSBV86 proc
  339. push ebp ; trap frame
  340. push edi ; size of insb
  341. movzx eax,word ptr [ebp].TsV86Es
  342. shl eax,16
  343. movzx ecx,word ptr [ebp].TsEdi
  344. or eax,ecx
  345. push eax ; address
  346. mov eax,1
  347. xor ecx, ecx
  348. test ebx,PREFIX_REP ; prefixREP
  349. jz oisb20
  350. mov ecx, 1
  351. movzx eax,word ptr [ebp].TsEcx
  352. oisb20:
  353. push eax ; number of io ops
  354. push TRUE ; read op
  355. push ecx ; REP prefix ?
  356. push 1 ; byte op
  357. movzx eax,word ptr [ebp].TsEdx
  358. push eax ; port number
  359. ; Ki386VdmDispatchStringIo enables interrupts
  360. IFDEF STD_CALL
  361. call _Ki386VdmDispatchStringIo@32 ; use retval
  362. ELSE
  363. call _Ki386VdmDispatchStringIo ; use retval
  364. add esp,24
  365. ENDIF
  366. ret
  367. OpcodeINSBV86 endp
  368. page ,132
  369. subttl "Word String In Opcode Handler"
  370. ;++
  371. ;
  372. ; Routine Description:
  373. ;
  374. ; This routine emulates an INSW opcode. Currently, it prints
  375. ; a message, and ignores the instruction.
  376. ;
  377. ; Arguments:
  378. ;
  379. ; EBX -> prefix flags
  380. ; EBP -> trap frame
  381. ; CL -> byte at the faulting address
  382. ; interrupts disabled
  383. ; ESI -> address of faulting instruction
  384. ; EDI -> instruction length count
  385. ;
  386. ; Returns:
  387. ; EAX = 0 for failure
  388. ; EAX = 1 for success
  389. ;
  390. ; All registers can be trashed except ebp/esp.
  391. ;
  392. public OpcodeINSWV86
  393. OpcodeINSWV86 proc
  394. push ebp ; trap frame
  395. push edi ; size of insw
  396. movzx eax,word ptr [ebp].TsV86Es
  397. shl eax,16
  398. movzx ecx,word ptr [ebp].TsEdi
  399. or eax,ecx
  400. push eax ; address
  401. mov eax,1
  402. xor ecx, ecx
  403. test ebx,PREFIX_REP ; prefixREP
  404. jz oisw20
  405. mov ecx, 1
  406. movzx eax,word ptr [ebp].TsEcx
  407. oisw20:
  408. push eax ; number of io ops
  409. push TRUE ; read op
  410. push ecx ; REP prefix ?
  411. push 2 ; word op
  412. movzx eax,word ptr [ebp].TsEdx
  413. push eax ; port number
  414. ; Ki386VdmDispatchStringIo enables interrupts
  415. IFDEF STD_CALL
  416. call _Ki386VdmDispatchStringIo@32 ; use retval
  417. ELSE
  418. call _Ki386VdmDispatchStringIo ; use retval
  419. add esp,24
  420. ENDIF
  421. ret
  422. OpcodeINSWV86 endp
  423. page ,132
  424. subttl "Byte String Out Opcode Handler"
  425. ;++
  426. ;
  427. ; Routine Description:
  428. ;
  429. ; This routine emulates an OUTSB opcode. Currently, it prints
  430. ; a message, and ignores the instruction.
  431. ;
  432. ; Arguments:
  433. ;
  434. ; EBX -> prefix flags
  435. ; EBP -> trap frame
  436. ; CL -> byte at the faulting address
  437. ; interrupts disabled
  438. ; ESI -> address of faulting instruction
  439. ; EDI -> instruction length count
  440. ;
  441. ; Returns:
  442. ; EAX = 0 for failure
  443. ; EAX = 1 for success
  444. ;
  445. ; All registers can be trashed except ebp/esp.
  446. ;
  447. public OpcodeOUTSBV86
  448. OpcodeOUTSBV86 proc
  449. push ebp ; trap frame
  450. push edi ; size of outsb
  451. movzx eax,word ptr [ebp].TsV86Ds
  452. shl eax,16
  453. movzx ecx,word ptr [ebp].TsEsi
  454. or eax,ecx
  455. push eax ; address
  456. mov eax,1
  457. xor ecx, ecx
  458. test ebx,PREFIX_REP ; prefixREP
  459. jz oosb20
  460. mov ecx, 1
  461. movzx eax,word ptr [ebp].TsEcx
  462. oosb20:
  463. push eax ; number of io ops
  464. push FALSE ; write op
  465. push ecx ; REP prefix ?
  466. push 1 ; byte op
  467. movzx eax,word ptr [ebp].TsEdx
  468. push eax ; port number
  469. ; Ki386VdmDispatchStringIo enables interrupts
  470. IFDEF STD_CALL
  471. call _Ki386VdmDispatchStringIo@32 ; use retval
  472. ELSE
  473. call _Ki386VdmDispatchStringIo ; use retval
  474. add esp,24
  475. ENDIF
  476. ret
  477. OpcodeOUTSBV86 endp
  478. page ,132
  479. subttl "Word String Out Opcode Handler"
  480. ;++
  481. ;
  482. ; Routine Description:
  483. ;
  484. ; This routine emulates an OUTSW opcode. Currently, it prints
  485. ; a message, and ignores the instruction
  486. ;
  487. ; Arguments:
  488. ;
  489. ; EBX -> prefix flags
  490. ; EBP -> trap frame
  491. ; CL -> byte at the faulting address
  492. ; interrupts disabled
  493. ; ESI -> address of faulting instruction
  494. ; EDI -> instruction length count
  495. ;
  496. ; Returns:
  497. ; EAX = 0 for failure
  498. ; EAX = 1 for success
  499. ;
  500. ; All registers can be trashed except ebp/esp.
  501. ;
  502. public OpcodeOUTSWV86
  503. OpcodeOUTSWV86 proc
  504. push ebp ; trap frame
  505. push edi ; size of outsw
  506. movzx eax,word ptr [ebp].TsV86Ds
  507. shl eax,16
  508. movzx ecx,word ptr [ebp].TsEsi
  509. or eax,ecx
  510. push eax ; address
  511. mov eax,1
  512. xor ecx, ecx
  513. test ebx,PREFIX_REP ; prefixREP
  514. jz oosw20
  515. mov ecx, 1
  516. movzx eax,word ptr [ebp].TsEcx
  517. oosw20:
  518. push eax ; number of io ops
  519. push FALSE ; write op
  520. push ecx ; REP prefix ?
  521. push 2 ; word op
  522. movzx eax,word ptr [ebp].TsEdx
  523. push eax ; port number
  524. ; Ki386VdmDispatchStringIo enables interrupts
  525. IFDEF STD_CALL
  526. call _Ki386VdmDispatchStringIo@32 ; use retval
  527. ELSE
  528. call _Ki386VdmDispatchStringIo ; use retval
  529. add esp,24
  530. ENDIF
  531. ret
  532. OpcodeOUTSWV86 endp
  533. page ,132
  534. subttl "PUSHF Opcode Handler"
  535. ;++
  536. ;
  537. ; Routine Description:
  538. ;
  539. ; This routine emulates an PUSHF opcode. Currently, it prints
  540. ; a message, and simulates the instruction.
  541. ;
  542. ; Get SS
  543. ; shift left 4
  544. ; get SP
  545. ; subtract 2
  546. ; get flags
  547. ; put in virtual interrupt flag
  548. ; put on stack
  549. ; update sp
  550. ;
  551. ; Arguments:
  552. ; EBX -> prefix flags
  553. ; EBP -> trap frame
  554. ; CL -> byte at the faulting address
  555. ; interrupts disabled
  556. ; ESI -> address of faulting instruction
  557. ; EDI -> instruction length count
  558. ;
  559. ; Returns:
  560. ; EAX = 0 for failure
  561. ; EAX = 1 for success
  562. ;
  563. ; All registers can be trashed except ebp/esp.
  564. ;
  565. public OpcodePUSHFV86
  566. OpcodePUSHFV86 proc
  567. test _KeI386VirtualIntExtensions, dword ptr V86_VIRTUAL_INT_EXTENSIONS
  568. jz short puf00
  569. mov eax,dword ptr [ebp].TsEFlags
  570. lea ecx,ds:FIXED_NTVDMSTATE_LINEAR
  571. or dword ptr [ecx], VDM_VIRTUAL_INTERRUPTS
  572. test eax, EFLAGS_VIF ; Is vif on
  573. jnz short puf03
  574. and dword ptr [ecx], NOT VDM_VIRTUAL_INTERRUPTS
  575. and eax, NOT EFLAGS_INTERRUPT_MASK
  576. jmp short puf03
  577. puf00:
  578. lea eax,ds:FIXED_NTVDMSTATE_LINEAR
  579. mov edx,dword ptr [ebp].TsEFlags
  580. mov eax, dword ptr [eax] ; get virtual int flag
  581. and edx,NOT EFLAGS_INTERRUPT_MASK
  582. and eax,VDM_VIRTUAL_INTERRUPTS OR VDM_VIRTUAL_AC OR VDM_VIRTUAL_NT
  583. or eax,edx
  584. or eax,EFLAGS_IOPL_MASK
  585. puf03:
  586. movzx ecx,word ptr [ebp].TsHardwareSegSS
  587. movzx edx,word ptr [ebp].TsHardwareEsp
  588. shl ecx,4
  589. sub dx,2
  590. test ebx,PREFIX_OPER32 ; check operand size
  591. jnz puf10
  592. mov [ecx + edx],ax
  593. puf05:
  594. mov word ptr [ebp].TsHardwareEsp,dx ; update client esp
  595. add dword ptr [ebp].TsEip,edi
  596. mov eax, ds:FIXED_NTVDMSTATE_LINEAR
  597. test eax, VDM_VIRTUAL_INTERRUPTS
  598. jz short @f
  599. test eax, VDM_INTERRUPT_PENDING
  600. jz short @f
  601. call VdmDispatchIntAck
  602. @@:
  603. mov eax,1
  604. ret
  605. puf10: sub dx,2
  606. mov [ecx + edx],eax
  607. jmp puf05
  608. OpcodePUSHFV86 endp
  609. page ,132
  610. subttl "POPF Opcode Handler"
  611. ;++
  612. ;
  613. ; Routine Description:
  614. ;
  615. ; This routine emulates an POPF opcode. Currently, it prints
  616. ; a message, and returns to the monitor.
  617. ;
  618. ; Arguments:
  619. ; EBX -> prefix flags
  620. ; EBP -> trap frame
  621. ; CL -> byte at the faulting address
  622. ; interrupts disabled
  623. ; ESI -> address of faulting instruction
  624. ; EDI -> instruction length count
  625. ;
  626. ; Returns:
  627. ; EAX = 0 for failure
  628. ; EAX = 1 for success
  629. ;
  630. ; All registers can be trashed except ebp/esp.
  631. ;
  632. public OpcodePOPFV86
  633. OpcodePOPFV86 proc
  634. lea eax,ds:FIXED_NTVDMSTATE_LINEAR ; get pointer to VDM State
  635. mov ecx,[ebp].TsHardwareSegSS
  636. movzx edx,word ptr [ebp].TsHardwareEsp
  637. shl ecx,4
  638. mov ecx,[ecx + edx] ; get flags from stack => ecx
  639. add edx,4
  640. test ebx,PREFIX_OPER32 ; check operand size
  641. jnz pof10
  642. and ecx,0ffffh ; only lower 16 bit for 16bit code
  643. sub edx,2
  644. pof10:
  645. mov [ebp].TsHardwareEsp,edx
  646. and ecx, NOT EFLAGS_IOPL_MASK
  647. mov ebx,ecx ; [ebx]=[ecx]=user EFLAGS - IOPL
  648. and ebx, NOT EFLAGS_NT_MASK ; [ebx]=user eflags - iopl - NT
  649. and ecx, (EFLAGS_INTERRUPT_MASK OR EFLAGS_ALIGN_CHECK OR EFLAGS_NT_MASK)
  650. ; [ecx]=IF + AC + NT of User eflgs
  651. ; [ebx]=User eflgs - IOPL - NT
  652. test _KeI386VirtualIntExtensions, dword ptr V86_VIRTUAL_INT_EXTENSIONS
  653. jz short pof15
  654. and ebx, NOT (EFLAGS_VIP + EFLAGS_VIF)
  655. ; [ebx]=UserFlg -IOPL - NT - VIP - VIF
  656. test ebx, EFLAGS_INTERRUPT_MASK
  657. jz short @f
  658. or ebx, EFLAGS_VIF ; [ebx]=UserFlg-IOPL-NT-VIP+VIF
  659. @@:
  660. or ebx, (EFLAGS_INTERRUPT_MASK OR EFLAGS_V86_MASK) ;[ebx]=UserFlg-IOPL-NT-VIP+VIF+IF
  661. and dword ptr [ebp].TsEFlags, EFLAGS_VIP
  662. or [ebp].TsEFlags,ebx
  663. jmp short pof20
  664. pof15:
  665. or ebx, (EFLAGS_INTERRUPT_MASK OR EFLAGS_V86_MASK)
  666. mov [ebp].TsEFlags, ebx
  667. pof20:
  668. MPLOCK and [eax],NOT (EFLAGS_INTERRUPT_MASK OR EFLAGS_ALIGN_CHECK OR EFLAGS_NT_MASK)
  669. MPLOCK or [eax],ecx
  670. add dword ptr [ebp].TsEip,edi
  671. mov eax,dword ptr [eax]
  672. test eax,VDM_INTERRUPT_PENDING
  673. jz pof25
  674. test eax,VDM_VIRTUAL_INTERRUPTS
  675. jz pof25
  676. call VdmDispatchIntAck
  677. pof25:
  678. mov eax,1 ; handled
  679. ret
  680. OpcodePOPFV86 endp
  681. page ,132
  682. subttl "INTnn Opcode Handler"
  683. ;++
  684. ;
  685. ; Routine Description:
  686. ;
  687. ; This routine emulates an INTnn opcode. It retrieves the handler
  688. ; from the IVT, pushes the current cs:ip and flags on the stack,
  689. ; and dispatches to the handler.
  690. ;
  691. ; Arguments:
  692. ; EBX -> prefix flags
  693. ; EBP -> trap frame
  694. ; CL -> byte at the faulting address
  695. ; interrupts disabled
  696. ; ESI -> address of faulting instruction
  697. ; EDI -> instruction length count
  698. ;
  699. ; Returns:
  700. ; EAX = 0 for failure
  701. ; EAX = 1 for success
  702. ;
  703. ; All registers can be trashed except ebp/esp.
  704. ;
  705. public OpcodeINTnnV86
  706. OpcodeINTnnV86 proc
  707. ;
  708. ; Int nn in v86 mode always disables interrupts
  709. ;
  710. mov edx,[ebp].TsEflags
  711. ;
  712. ; If KeI386VdmIoplAllowed is true, direct IF manipulation is allowed
  713. ;
  714. test _KeI386VdmIoplAllowed,1
  715. jz oinnv10
  716. mov eax,edx ; save original flags
  717. and edx,NOT EFLAGS_INTERRUPT_MASK
  718. jmp oinnv20
  719. ;
  720. ; Else, IF and some other flags bits are virtualized
  721. ;
  722. oinnv10:
  723. lea eax,ds:FIXED_NTVDMSTATE_LINEAR ; get pointer to VDM State
  724. mov ecx,dword ptr [eax] ;[ecx]=vdmstate
  725. MPLOCK and [eax],NOT VDM_VIRTUAL_INTERRUPTS
  726. mov eax, edx
  727. and eax, NOT EFLAGS_INTERRUPT_MASK
  728. .errnz (EFLAGS_INTERRUPT_MASK - VDM_VIRTUAL_INTERRUPTS)
  729. and ecx, VDM_VIRTUAL_INTERRUPTS OR VDM_VIRTUAL_AC
  730. ; [edx]=eflags
  731. ; [eax]=eflgs-if
  732. ; [ecx]=IF + AC of vdmstate
  733. test _KeI386VirtualIntExtensions, dword ptr V86_VIRTUAL_INT_EXTENSIONS
  734. jz oinnv15
  735. ;
  736. ;VIF extension is enabled, we should migrate EFLAGS_VIF instead of
  737. ;VDM_VIRTUAL_INTERRUPT to the iret frame eflags IF.
  738. ;When VIF extension is enabled, RI_BIT_MASK is turned on. This in turn,
  739. ;redirects the FCLI/FSTI macro to execute cli/sti directly instead
  740. ;of simulation. Without this, we might disable v86 mode interrupt
  741. ;without the applications knowing it.
  742. ;
  743. and ecx, VDM_VIRTUAL_AC ;keep VDM_VIRTUAL_AC only
  744. or eax, ecx ;[eax]=eflags + ac -if
  745. mov ecx, edx
  746. and ecx, EFLAGS_VIF
  747. .errnz ((EFLAGS_VIF SHR 10) - EFLAGS_INTERRUPT_MASK)
  748. ror ecx, 10 ;VIF -> IF
  749. oinnv15:
  750. or eax, ecx ;[eax]=eflags +ac +if
  751. oinnv20:
  752. and edx,NOT (EFLAGS_NT_MASK OR EFLAGS_TF_MASK OR EFLAGS_VIF)
  753. mov [ebp].TsEflags,edx
  754. or eax, EFLAGS_IOPL_MASK
  755. movzx ecx,word ptr [ebp].TsHardwareSegSS
  756. shl ecx,4
  757. movzx edx,word ptr [ebp].TsHardwareEsp ; ecx+edx is user stack
  758. sub dx,2
  759. mov word ptr [ecx+edx],ax ; push flags
  760. mov ax,word ptr [ebp].TsSegCS
  761. sub dx,2
  762. mov word ptr [ecx+edx],ax ; push cs
  763. movzx eax,word ptr [ebp].TsEip
  764. add eax, edi
  765. inc eax
  766. sub dx,2
  767. mov word ptr [ecx+edx],ax ; push ip
  768. mov [ebp].TsHardwareEsp,dx ; update sp on trap frame
  769. inc esi
  770. movzx ecx,byte ptr [esi] ; ecx is int#
  771. ;
  772. ; Check if this is a v86 interrupt which must be reflected to a PM handler
  773. ;
  774. call oinnvuserrefs ; do user refs under a try/except block
  775. or eax, eax
  776. je oinnv30
  777. ;
  778. ; Encode interrupt number in cs
  779. ;
  780. mov eax,ebx
  781. shr eax,16 ; bop cs
  782. sub eax,ecx ; new cs
  783. shl ecx,4
  784. add ebx,ecx ; new ip
  785. jmp oinnv40
  786. oinnv30:
  787. ;
  788. ; Not hooked, just pick up new vector from RM IVT
  789. ;
  790. mov ebx,[ecx*4]
  791. mov eax,ebx
  792. shr eax,16 ; new cs
  793. oinnv40:
  794. mov word ptr [ebp].TsEip,bx
  795. mov [ebp].TsSegCs,ax ; cs:ip on trap frame is updated
  796. mov eax,1
  797. ret
  798. OpcodeINTnnV86 endp
  799. oinnvuserrefs proc
  800. push ebp
  801. push esp ; Pass current Esp to handler
  802. push offset oinnvuserrefs_fault ; Set Handler address
  803. push PCR[PcExceptionList] ; Set next pointer
  804. mov PCR[PcExceptionList],esp ; Link us on
  805. mov eax,PCR[PcTeb]
  806. mov eax,[eax].TeVdm ; get pointer to VdmTib
  807. cmp eax, _MmUserProbeAddress ; Probe the TeVdm
  808. jae @f
  809. mov ebx,[eax].VtInterruptTable ;
  810. cmp ebx, 0 ; there is no interrupt table
  811. je @f ; so, don't reflect it.
  812. lea ebx,[ebx + ecx*8]
  813. cmp ebx, _MmUserProbeAddress ; Probe the TeVdm
  814. jae @f
  815. test [ebx].ViFlags, VDM_INT_HOOKED ; need to reflect to PM?
  816. jz @f
  817. lea ebx,[eax].VtDpmiInfo ; point to DpmiInfo
  818. mov ebx,[ebx].VpDosxRmReflector ; bop to reflect to PM
  819. mov eax, 1
  820. pop PCR[PcExceptionList] ; Remove our exception handle
  821. add esp, 8 ; clear stack
  822. pop ebp
  823. ret
  824. @@:
  825. oinnvuserrefs_fault_resume:
  826. pop PCR[PcExceptionList] ; Remove our exception handle
  827. add esp, 8 ; clear stack
  828. pop ebp
  829. xor eax, eax
  830. ret
  831. oinnvuserrefs_fault:
  832. ;
  833. ; WARNING: Here we directly unlink the exception handler from the
  834. ; exception registration chain. NO unwind is performed. We can take
  835. ; this short cut because we know that our handler is a leaf-node.
  836. ;
  837. mov esp, [esp+8] ; (esp)-> ExceptionList
  838. jmp oinnvuserrefs_fault_resume
  839. oinnvuserrefs endp
  840. page ,132
  841. subttl "INTO Opcode Handler"
  842. ;++
  843. ;
  844. ; Routine Description:
  845. ;
  846. ; This routine emulates an INTO opcode. Currently, it prints
  847. ; a message, and reflects a GP fault to the debugger.
  848. ;
  849. ; Arguments:
  850. ; EBX -> prefix flags
  851. ; EBP -> trap frame
  852. ; CL -> byte at the faulting address
  853. ; interrupts disabled
  854. ; ESI -> address of faulting instruction
  855. ; EDI -> instruction length count
  856. ;
  857. ; Returns:
  858. ; EAX = 0 for failure
  859. ; EAX = 1 for success
  860. ;
  861. ; All registers can be trashed except ebp/esp.
  862. ;
  863. public OpcodeINTOV86
  864. OpcodeINTOV86 proc
  865. xor eax,eax ; ret fail
  866. ret
  867. OpcodeINTOV86 endp
  868. page ,132
  869. subttl "IRET Opcode Handler"
  870. ;++
  871. ;
  872. ; Routine Description:
  873. ;
  874. ; This routine emulates an IRET opcode. It retrieves the flags,
  875. ; and new instruction pointer from the stack and puts them into
  876. ; the user context.
  877. ;
  878. ;
  879. ; Arguments:
  880. ; EBX -> prefix flags
  881. ; EBP -> trap frame
  882. ; CL -> byte at the faulting address
  883. ; interrupts disabled
  884. ; ESI -> address of faulting instruction
  885. ; EDI -> instruction length count
  886. ;
  887. ; Returns:
  888. ; EAX = 0 for failure
  889. ; EAX = 1 for success
  890. ;
  891. ; All registers can be trashed except ebp/esp.
  892. ;
  893. ;
  894. public OpcodeIRETV86
  895. OpcodeIRETV86 proc
  896. lea eax,ds:FIXED_NTVDMSTATE_LINEAR
  897. movzx ecx,word ptr [ebp].TsHardwareSegSS
  898. movzx edx,word ptr [ebp].TsHardwareEsp ; ebx+edx is user stack
  899. shl ecx,4
  900. add ecx,edx
  901. test ebx,PREFIX_OPER32
  902. jnz irt50 ; normally not
  903. movzx edi,word ptr [ecx] ; get ip value
  904. mov [ebp].TsEip,edi
  905. movzx esi,word ptr [ecx+2] ; get cs value
  906. mov [ebp].TsSegCs,esi
  907. add edx,6
  908. mov [ebp].TsHardwareEsp,edx ; update sp on trap frame
  909. movzx ebx,word ptr [ecx+4] ; get flag value
  910. irt10: ; [ebx]=UserFlgs
  911. and ebx, NOT (EFLAGS_IOPL_MASK OR EFLAGS_NT_MASK OR EFLAGS_VIP OR EFLAGS_VIF)
  912. mov ecx,ebx ; [ecx]=[ebx]=UserFlgs - IOPL - NT - VIP - VIF
  913. test _KeI386VirtualIntExtensions, dword ptr V86_VIRTUAL_INT_EXTENSIONS
  914. jz short irt15
  915. or ebx, EFLAGS_VIF
  916. test ebx, EFLAGS_INTERRUPT_MASK
  917. jnz irt15
  918. and ebx, NOT EFLAGS_VIF
  919. ; [ebx] = UserFlgs - IOPL - NT - VIP
  920. irt15:
  921. or ebx, (EFLAGS_V86_MASK OR EFLAGS_INTERRUPT_MASK)
  922. and dword ptr [ebp].TsEFlags, EFLAGS_VIP
  923. or [ebp].TsEFlags, ebx ; update flags n trap frame
  924. and ecx, EFLAGS_INTERRUPT_MASK
  925. MPLOCK and [eax],NOT VDM_VIRTUAL_INTERRUPTS
  926. MPLOCK or [eax],ecx
  927. mov ebx,[eax]
  928. ; at this point esi is the cs and edi is the ip where v86 mode
  929. ; will return. Now we will check if this returning instruction
  930. ; is a bop. if so we will directly dispatch the bop from here
  931. ; saving a full round trip. This will be really helpful to
  932. ; com apps.
  933. shl esi,4
  934. add esi,edi
  935. cmp esi, _MmUserProbeAddress ; Probe 32 bit value
  936. jbe @f
  937. mov esi, _MmUserProbeAddress
  938. @@: mov ax, word ptr [esi]
  939. cmp ax, 0c4c4h
  940. je irtbop
  941. test ebx,VDM_INTERRUPT_PENDING
  942. jz short irt25
  943. test ebx,VDM_VIRTUAL_INTERRUPTS
  944. jz short irt25
  945. call VdmDispatchIntAck ; VdmDispatchIntAck enables interrupts
  946. irt25:
  947. mov eax,1 ; handled
  948. ret
  949. ; ireting to a bop
  950. irtbop:
  951. stdCall _VdmDispatchBop, <ebp>
  952. jmp short irt25
  953. irt50:
  954. mov edi, [ecx] ; get ip value
  955. mov [ebp].TsEip,edi
  956. movzx esi,word ptr [ecx+4] ; get cs value
  957. mov [ebp].TsSegCs,esi
  958. add edx,12
  959. mov [ebp].TsHardwareEsp,edx ; update sp on trap frame
  960. mov ebx, [ecx+8] ; get flag value
  961. jmp irt10 ; rejoin the common path
  962. OpcodeIRETV86 endp
  963. page ,132
  964. subttl "In Byte Immediate Opcode Handler"
  965. ;++
  966. ;
  967. ; Routine Description:
  968. ;
  969. ; This routine emulates an in byte immediate opcode. Currently, it
  970. ; prints a message, and ignores the instruction.
  971. ;
  972. ; Arguments:
  973. ; EBX -> prefix flags
  974. ; EBP -> trap frame
  975. ; CL -> byte at the faulting address
  976. ; interrupts disabled
  977. ; ESI -> address of faulting instruction
  978. ; EDI -> instruction length count
  979. ;
  980. ; Returns:
  981. ; EAX = 0 for failure
  982. ; EAX = 1 for success
  983. ;
  984. ; All registers can be trashed except ebp/esp.
  985. ;
  986. public OpcodeINBimmV86
  987. OpcodeINBimmV86 proc
  988. inc esi
  989. inc edi
  990. movzx ecx,byte ptr [esi]
  991. ; Ki386VdmDispatchIo enables interrupts
  992. stdCall _Ki386VdmDispatchIo, <ecx, 1, TRUE, edi, ebp>
  993. ret
  994. OpcodeINBimmV86 endp
  995. page ,132
  996. subttl "Word In Immediate Opcode Handler"
  997. ;++
  998. ;
  999. ; Routine Description:
  1000. ;
  1001. ; This routine emulates an in word immediate opcode. Currently, it
  1002. ; prints a message, and ignores the instruction.
  1003. ;
  1004. ; Arguments:
  1005. ; EAX -> pointer to vdm state in DOS arena
  1006. ; EBX -> prefix flags
  1007. ; EBP -> trap frame
  1008. ; CL -> byte at the faulting address
  1009. ; interrupts disabled
  1010. ; ESI -> address of faulting instruction
  1011. ; EDI -> instruction length count
  1012. ;
  1013. ; Returns:
  1014. ; EAX = 0 for failure
  1015. ; EAX = 1 for success
  1016. ;
  1017. ; All registers can be trashed except ebp/esp.
  1018. ;
  1019. public OpcodeINWimmV86
  1020. OpcodeINWimmV86 proc
  1021. inc esi
  1022. inc edi
  1023. movzx ecx,byte ptr [esi]
  1024. ; edi - instruction size
  1025. ; TRUE - read op
  1026. ; 2 - word op
  1027. ; ecx - port number
  1028. ; Ki386VdmDispatchIo enables interrupts
  1029. stdCall _Ki386VdmDispatchIo, <ecx, 2, TRUE, edi, ebp>
  1030. ret
  1031. OpcodeINWimmV86 endp
  1032. page ,132
  1033. subttl "Out Byte Immediate Opcode Handler"
  1034. ;++
  1035. ;
  1036. ; Routine Description:
  1037. ;
  1038. ; This routine emulates an invalid opcode. Currently, it prints
  1039. ; a message, and ignores the instruction.
  1040. ;
  1041. ; Arguments:
  1042. ; EAX -> pointer to vdm state in DOS arena
  1043. ; EBX -> prefix flags
  1044. ; EBP -> trap frame
  1045. ; CL -> byte at the faulting address
  1046. ; interrupts disabled
  1047. ; ESI -> address of faulting instruction
  1048. ; EDI -> instruction length count
  1049. ;
  1050. ; Returns:
  1051. ; EAX = 0 for failure
  1052. ; EAX = 1 for success
  1053. ;
  1054. ; All registers can be trashed except ebp/esp.
  1055. ;
  1056. public OpcodeOUTBimmV86
  1057. OpcodeOUTBimmV86 proc
  1058. inc edi
  1059. inc esi
  1060. movzx ecx,byte ptr [esi]
  1061. ; edi - instruction size
  1062. ; FALSE - write op
  1063. ; 1 - byte op
  1064. ; ecx - port #
  1065. ; Ki386VdmDispatchIo enables interrupts
  1066. stdCall _Ki386VdmDispatchIo, <ecx, 1, FALSE, edi, ebp>
  1067. ret
  1068. OpcodeOUTBimmV86 endp
  1069. page ,132
  1070. subttl "Out Word Immediate Opcode Handler"
  1071. ;++
  1072. ;
  1073. ; Routine Description:
  1074. ;
  1075. ; This routine emulates an out word immediate opcode. Currently,
  1076. ; it prints a message, and ignores the instruction.
  1077. ;
  1078. ; Arguments:
  1079. ; EAX -> pointer to vdm state in DOS arena
  1080. ; EBX -> prefix flags
  1081. ; EBP -> trap frame
  1082. ; CL -> byte at the faulting address
  1083. ; interrupts disabled
  1084. ; ESI -> address of faulting instruction
  1085. ; EDI -> instruction length count
  1086. ;
  1087. ; Returns:
  1088. ; EAX = 0 for failure
  1089. ; EAX = 1 for success
  1090. ;
  1091. ; All registers can be trashed except ebp/esp.
  1092. ;
  1093. ;
  1094. public OpcodeOUTWimmV86
  1095. OpcodeOUTWimmV86 proc
  1096. inc esi
  1097. inc edi
  1098. movzx ecx,byte ptr [esi]
  1099. ; edi - instruction size
  1100. ; FALSE - write op
  1101. ; 2 - word op
  1102. ; ecx - port number
  1103. ; Ki386VdmDispatchIo enables interrupts
  1104. stdCall _Ki386VdmDispatchIo, <ecx, 2, FALSE, edi, ebp>
  1105. ret
  1106. OpcodeOUTWimmV86 endp
  1107. page ,132
  1108. subttl "INB Opcode Handler"
  1109. ;++
  1110. ;
  1111. ; Routine Description:
  1112. ;
  1113. ; This routine emulates an INB opcode. Currently, it prints
  1114. ; a message, and ignores the instruction.
  1115. ;
  1116. ; Arguments:
  1117. ; EAX -> pointer to vdm state in DOS arena
  1118. ; EBX -> prefix flags
  1119. ; EBP -> trap frame
  1120. ; CL -> byte at the faulting address
  1121. ; interrupts disabled
  1122. ; ESI -> address of faulting instruction
  1123. ; EDI -> instruction length count
  1124. ;
  1125. ; Returns:
  1126. ; EAX = 0 for failure
  1127. ; EAX = 1 for success
  1128. ;
  1129. ; All registers can be trashed except ebp/esp.
  1130. ;
  1131. public OpcodeINBV86
  1132. OpcodeINBV86 proc
  1133. movzx ebx,word ptr [ebp].TsEdx
  1134. ; edi - instruction size
  1135. ; TRUE - read op
  1136. ; 1 - byte op
  1137. ; ebx - port number
  1138. cmp ebx, 3bdh
  1139. jz oib_prt1
  1140. cmp ebx, 379h
  1141. jz oib_prt1
  1142. cmp ebx, 279h
  1143. jz oib_prt1
  1144. oib_reflect:
  1145. ; Ki386VdmDispatchIo enables interrupts
  1146. stdCall _Ki386VdmDispatchIo, <ebx, 1, TRUE, edi, ebp>
  1147. ret
  1148. oib_prt1:
  1149. ; call printer status routine with port number, size, trap frame
  1150. stdCall _VdmPrinterStatus, <ebx, edi, ebp>
  1151. or al,al
  1152. jz short oib_reflect
  1153. ret
  1154. OpcodeINBV86 endp
  1155. page ,132
  1156. subttl "INW Opcode Handler"
  1157. ;++
  1158. ;
  1159. ; Routine Description:
  1160. ;
  1161. ; This routine emulates an INW opcode. Currently, it prints
  1162. ; a message, and ignores the instruction.
  1163. ;
  1164. ; Arguments:
  1165. ; EAX -> pointer to vdm state in DOS arena
  1166. ; EBX -> prefix flags
  1167. ; EBP -> trap frame
  1168. ; CL -> byte at the faulting address
  1169. ; interrupts disabled
  1170. ; ESI -> address of faulting instruction
  1171. ; EDI -> instruction length count
  1172. ;
  1173. ; Returns:
  1174. ; EAX = 0 for failure
  1175. ; EAX = 1 for success
  1176. ;
  1177. ; All registers can be trashed except ebp/esp.
  1178. ;
  1179. ;
  1180. public OpcodeINWV86
  1181. OpcodeINWV86 proc
  1182. movzx ebx,word ptr [ebp].TsEdx
  1183. ; edi - instruction size
  1184. ; TRUE - read operation
  1185. ; 2 - word op
  1186. ; ebx - port number
  1187. ; Ki386VdmDispatchIo enables interrupts
  1188. stdCall _Ki386VdmDispatchIo, <ebx, 2, TRUE, edi, ebp>
  1189. ret
  1190. OpcodeINWV86 endp
  1191. page ,132
  1192. subttl "OUTB Opcode Handler"
  1193. ;++
  1194. ;
  1195. ; Routine Description:
  1196. ;
  1197. ; This routine emulates an OUTB opcode. Currently, it prints
  1198. ; a message, and ignores the instruction.
  1199. ;
  1200. ; Arguments:
  1201. ; EAX -> pointer to vdm state in DOS arena
  1202. ; EBX -> prefix flags
  1203. ; EBP -> trap frame
  1204. ; CL -> byte at the faulting address
  1205. ; interrupts disabled
  1206. ; ESI -> address of faulting instruction
  1207. ; EDI -> instruction length count
  1208. ;
  1209. ; Returns:
  1210. ; EAX = 0 for failure
  1211. ; EAX = 1 for success
  1212. ;
  1213. ; All registers can be trashed except ebp/esp.
  1214. ;
  1215. ;
  1216. public OpcodeOUTBV86
  1217. OpcodeOUTBV86 proc
  1218. movzx ebx,word ptr [ebp].TsEdx
  1219. cmp ebx, 3bch
  1220. jz oob_prt1
  1221. cmp ebx, 378h
  1222. jz oob_prt1
  1223. cmp ebx, 278h
  1224. jz oob_prt1
  1225. oob_reflect:
  1226. ; edi - instruction size
  1227. ; FALSE - write op
  1228. ; 1 - byte op
  1229. ; ebx - port number
  1230. ; Ki386VdmDispatchIo enables interrupts
  1231. stdCall _Ki386VdmDispatchIo, <ebx, 1, FALSE, edi, ebp>
  1232. ret
  1233. oob_prt1:
  1234. ; call printer write data routine with port number, size, trap frame
  1235. stdCall _VdmPrinterWriteData, <ebx, edi, ebp>
  1236. or al,al
  1237. jz short oob_reflect
  1238. ;al already has TRUE
  1239. ret
  1240. OpcodeOUTBV86 endp
  1241. page ,132
  1242. subttl "OUTW Opcode Handler"
  1243. ;++
  1244. ;
  1245. ; Routine Description:
  1246. ;
  1247. ; This routine emulates an OUTW opcode. Currently, it prints
  1248. ; a message, and ignores the instruction.
  1249. ;
  1250. ; Arguments:
  1251. ; EAX -> pointer to vdm state in DOS arena
  1252. ; EBX -> prefix flags
  1253. ; EBP -> trap frame
  1254. ; CL -> byte at the faulting address
  1255. ; interrupts disabled
  1256. ; ESI -> address of faulting instruction
  1257. ; EDI -> instruction length count
  1258. ;
  1259. ; Returns:
  1260. ; EAX = 0 for failure
  1261. ; EAX = 1 for success
  1262. ;
  1263. ; All registers can be trashed except ebp/esp.
  1264. ;
  1265. ;
  1266. public OpcodeOUTWV86
  1267. OpcodeOUTWV86 proc
  1268. movzx ebx,word ptr [ebp].TsEdx
  1269. ; edi - instruction size
  1270. ; FALSE - write op
  1271. ; 2 - word op
  1272. ; ebx - port #
  1273. ; Ki386VdmDispatchIo enables interrupts
  1274. stdCall _Ki386VdmDispatchIo, <ebx, 2, FALSE, edi, ebp>
  1275. ret
  1276. OpcodeOUTWV86 endp
  1277. page ,132
  1278. subttl "CLI Opcode Handler"
  1279. ;++
  1280. ;
  1281. ; Routine Description:
  1282. ;
  1283. ; This routine emulates an CLI opcode. Currently, it prints
  1284. ; a message, and clears the virtual interrupt flag in the VdmTeb.
  1285. ;
  1286. ; Arguments:
  1287. ; EAX -> pointer to vdm state in DOS arena
  1288. ; EBX -> prefix flags
  1289. ; EBP -> trap frame
  1290. ; CL -> byte at the faulting address
  1291. ; interrupts disabled
  1292. ; ESI -> address of faulting instruction
  1293. ; EDI -> instruction length count
  1294. ;
  1295. ; Returns:
  1296. ; EAX = 0 for failure
  1297. ; EAX = 1 for success
  1298. ;
  1299. ; All registers can be trashed except ebp/esp.
  1300. ;
  1301. ;
  1302. public OpcodeCLIV86
  1303. OpcodeCLIV86 proc
  1304. lea eax,ds:FIXED_NTVDMSTATE_LINEAR
  1305. test _KeI386VirtualIntExtensions, dword ptr V86_VIRTUAL_INT_EXTENSIONS
  1306. jz short oc50
  1307. mov edx, [ebp].TsEFlags ; redundant code. Just in case
  1308. mov eax,dword ptr [eax]
  1309. and edx, EFLAGS_VIF + EFLAGS_VIP
  1310. cmp edx, EFLAGS_VIF + EFLAGS_VIP
  1311. jnz short oc50
  1312. test eax,VDM_INTERRUPT_PENDING
  1313. jz short oc50
  1314. call VdmDispatchIntAck
  1315. mov eax,1
  1316. ret
  1317. oc50:
  1318. MPLOCK and dword ptr [eax],NOT VDM_VIRTUAL_INTERRUPTS
  1319. add dword ptr [ebp].TsEip,edi
  1320. mov eax,1
  1321. ret
  1322. OpcodeCLIV86 endp
  1323. page ,132
  1324. subttl "STI Opcode Handler"
  1325. ;++
  1326. ;
  1327. ; Routine Description:
  1328. ;
  1329. ; This routine emulates an STI opcode. Currently, it prints
  1330. ; a message, and sets the virtual interrupt flag in the VDM teb.
  1331. ;
  1332. ; Arguments:
  1333. ; EAX -> pointer to vdm state in DOS arena
  1334. ; EBX -> prefix flags
  1335. ; EBP -> trap frame
  1336. ; CL -> byte at the faulting address
  1337. ; interrupts disabled
  1338. ; ESI -> address of faulting instruction
  1339. ; EDI -> instruction length count
  1340. ;
  1341. ; Returns:
  1342. ; EAX = 0 for failure
  1343. ; EAX = 1 for success
  1344. ;
  1345. ; All registers can be trashed except ebp/esp.
  1346. ;
  1347. ;
  1348. public OpcodeSTIV86
  1349. OpcodeSTIV86 proc
  1350. lea eax,ds:FIXED_NTVDMSTATE_LINEAR ; get pointer to VDM State
  1351. test _KeI386VirtualIntExtensions, dword ptr V86_VIRTUAL_INT_EXTENSIONS
  1352. jz short os10
  1353. or [ebp].TsEFlags, dword ptr EFLAGS_VIF
  1354. os10: MPLOCK or dword ptr [eax],EFLAGS_INTERRUPT_MASK
  1355. os20: add dword ptr [ebp].TsEip,edi
  1356. mov eax,dword ptr [eax]
  1357. test eax,VDM_INTERRUPT_PENDING
  1358. jz short os30
  1359. call VdmDispatchIntAck
  1360. os30: mov eax,1
  1361. ret
  1362. OpcodeSTIV86 endp
  1363. ;
  1364. ; If we get here, we have executed an NPX instruction in user mode
  1365. ; with the emulator installed. If the EM bit was not set in CR0, the
  1366. ; app really wanted to execute the instruction for detection purposes.
  1367. ; In this case, we need to clear the TS bit, and restart the instruction.
  1368. ; Otherwise we need to reflect the exception
  1369. ;
  1370. ;
  1371. ; Reginfo structure
  1372. ;
  1373. public Opcode0FV86
  1374. Opcode0FV86 proc
  1375. RI equ [ebp - REGINFOSIZE]
  1376. push ebp
  1377. mov ebp,esp
  1378. sub esp,REGINFOSIZE
  1379. push esi
  1380. push edi
  1381. ; Initialize RegInfo
  1382. do10: mov esi,[ebp]
  1383. ; initialize rest of the trap from which was'nt initialized for
  1384. ; v86 mode
  1385. mov eax, [esi].TsV86Es
  1386. mov [esi].TsSegEs,eax
  1387. mov eax, [esi].TsV86Ds
  1388. mov [esi].TsSegDs,eax
  1389. mov eax, [esi].TsV86Fs
  1390. mov [esi].TsSegFs,eax
  1391. mov eax, [esi].TsV86Gs
  1392. mov [esi].TsSegGs,eax
  1393. mov RI.RiTrapFrame,esi
  1394. mov eax,[esi].TsHardwareSegSs
  1395. mov RI.RiSegSs,eax
  1396. mov eax,[esi].TsHardwareEsp
  1397. mov RI.RiEsp,eax
  1398. mov eax,[esi].TsEFlags
  1399. mov RI.RiEFlags,eax
  1400. mov eax,[esi].TsSegCs
  1401. mov RI.RiSegCs,eax
  1402. mov eax,[esi].TsEip
  1403. dec edi
  1404. add eax,edi ; for prefixes
  1405. mov RI.RiEip,eax
  1406. mov RI.RiPrefixFlags,ebx
  1407. lea esi,RI
  1408. CsToLinearV86
  1409. call VdmOpcode0f ; enables interrupts
  1410. test eax,0FFFFh
  1411. jz do20
  1412. mov edi,RI.RiTrapFrame
  1413. mov eax,RI.RiEip ; advance eip
  1414. mov [edi].TsEip,eax
  1415. do19: mov eax,1
  1416. do20:
  1417. pop edi
  1418. pop esi
  1419. mov esp,ebp
  1420. pop ebp
  1421. ret
  1422. Opcode0FV86 endp
  1423. ;++
  1424. ;
  1425. ; Routine Description: VdmDispatchIntAck
  1426. ; pushes stack arguments for VdmDispatchInterrupts
  1427. ; and invokes VdmDispatchInterrupts
  1428. ;
  1429. ; Expects VDM_INTERRUPT_PENDING, and VDM_VIRTUAL_INTERRUPTS
  1430. ;
  1431. ; Arguments:
  1432. ; EBP -> trap frame
  1433. ;
  1434. ; Returns:
  1435. ; nothing
  1436. ;
  1437. ;
  1438. public VdmDispatchIntAck
  1439. VdmDispatchIntAck proc
  1440. push ebp
  1441. push esp ; Pass current Esp to handler
  1442. push offset diafault ; Set Handler address
  1443. push PCR[PcExceptionList] ; Set next pointer
  1444. mov PCR[PcExceptionList],esp ; Link us on
  1445. test ds:FIXED_NTVDMSTATE_LINEAR, VDM_INT_HARDWARE ; check interrupt int
  1446. mov eax,PCR[PcTeb]
  1447. mov eax,[eax].TeVdm ; get pointer to VdmTib
  1448. jz short dia20
  1449. cmp eax, _MmUserProbeAddress ; check if user address
  1450. jae short dia10 ; if ae, then not user address
  1451. pop PCR[PcExceptionList] ; Remove our exception handle
  1452. add esp, 8 ; clear stack
  1453. pop ebp
  1454. ;
  1455. ; dispatch hardware int directly from kernel
  1456. ;
  1457. stdCall _VdmDispatchInterrupts, <ebp, eax> ; TrapFrame, VdmTib
  1458. ret
  1459. dia10:
  1460. pop PCR[PcExceptionList] ; Remove our exception handle
  1461. add esp, 8 ; clear stack
  1462. pop ebp
  1463. ret
  1464. ;
  1465. ; Switch to monitor context to dispatch timer int
  1466. ;
  1467. dia20:
  1468. cmp eax, _MmUserProbeAddress ; check if user address
  1469. jae dia10 ; if ae, then not user address
  1470. mov dword ptr [eax].VtEIEvent,VdmIntAck ;
  1471. mov dword ptr [eax].VtEIInstSize,0
  1472. mov dword ptr [eax].VtEiIntAckInfo,0
  1473. pop PCR[PcExceptionList] ; Remove our exception handle
  1474. add esp, 8 ; clear stack
  1475. pop ebp
  1476. stdCall _VdmEndExecution, <ebp, eax> ; TrapFrame, VdmTib
  1477. ret
  1478. diafault:
  1479. ;
  1480. ; WARNING: Here we directly unlink the exception handler from the
  1481. ; exception registration chain. NO unwind is performed. We can take
  1482. ; this short cut because we know that our handler is a leaf-node.
  1483. ;
  1484. mov esp, [esp+8] ; (esp)-> ExceptionList
  1485. pop PCR[PcExceptionList] ; Remove our exception handle
  1486. add esp, 8 ; clear stack
  1487. pop ebp
  1488. ret
  1489. VdmDispatchIntAck endp
  1490. public vdmDebugPoint
  1491. vdmDebugPoint proc
  1492. ret
  1493. vdmDebugPoint endp
  1494. page ,132
  1495. subttl "HLT Opcode Handler"
  1496. ;++
  1497. ;
  1498. ; Routine Description:
  1499. ;
  1500. ; This routine emulates an HLT opcode. If the halt instruction is
  1501. ; followed by the magic number (to be found in a crackerjack box),
  1502. ; we use the hlt + magic number as a prefix, and emulate the following
  1503. ; instruction. This allows code running in segmented protected mode to
  1504. ; access the virtual interrupt flag.
  1505. ;
  1506. ; Arguments:
  1507. ; EAX -> pointer to vdm state in DOS arena
  1508. ; EBX -> prefix flags
  1509. ; EBP -> trap frame
  1510. ; CL -> byte at the faulting address
  1511. ; interrupts disabled
  1512. ; ESI -> address of faulting instruction
  1513. ; EDI -> instruction length count
  1514. ;
  1515. ; Returns:
  1516. ; EAX = 0 for failure
  1517. ; EAX = 1 for success
  1518. ;
  1519. ; All registers can be trashed except ebp/esp.
  1520. ;
  1521. public OpcodeHLTV86
  1522. OpcodeHLTV86 proc
  1523. add dword ptr [ebp].TsEip,edi
  1524. mov eax,1
  1525. ret
  1526. OpcodeHLTV86 endp
  1527. _PAGE ends
  1528. _TEXT$00 SEGMENT DWORD PUBLIC 'CODE'
  1529. ASSUME DS:NOTHING, ES:NOTHING, SS:NOTHING, FS:NOTHING, GS:NOTHING
  1530. subttl "NPX Opcode Handler"
  1531. ;++
  1532. ;
  1533. ; Routine Description:
  1534. ;
  1535. ; This routine emulates all NPX opcodes, when the system
  1536. ; has the R3 emulator installed and the c86 apps takes a
  1537. ; trap07.
  1538. ;
  1539. ; Arguments:
  1540. ; EBX -> prefix flags
  1541. ; EBP -> trap frame
  1542. ; CL -> byte at the faulting address
  1543. ; ESI -> address of faulting instruction
  1544. ; EDI -> instruction length count
  1545. ;
  1546. ; Returns:
  1547. ; EAX = 0 for failure
  1548. ; EAX = 1 for success
  1549. ;
  1550. ; All registers can be trashed except ebp/esp.
  1551. ; moved from emv86.asm as it must be non-pagable
  1552. public OpcodeNPXV86
  1553. OpcodeNPXV86 proc
  1554. mov edx, PCR[PcInitialStack]
  1555. mov edx, [edx].FpCr0NpxState
  1556. test edx, CR0_EM ; Does app want NPX traps?
  1557. jnz short onp40
  1558. ; MP bit can never be set while the EM bit is cleared, so we know
  1559. ; the faulting instruction is not an FWAIT
  1560. onp30: and ebx, PREFIX_ADDR32
  1561. stdCall _VdmSkipNpxInstruction, <ebp, ebx, esi, edi>
  1562. or al, al ; was it handled?
  1563. jnz short onp60 ; no, go raise exception to app
  1564. onp40: stdCall _Ki386VdmReflectException, <7> ; trap #
  1565. onp60: mov eax,1
  1566. ret
  1567. OpcodeNPXV86 endp
  1568. ;++ KiVdmSetUserCR0
  1569. ;
  1570. ; eax
  1571. ;
  1572. public KiVdmSetUserCR0
  1573. KiVdmSetUserCR0 proc
  1574. and eax, CR0_MP OR CR0_EM ; Sanitize parameter
  1575. shr eax, 1
  1576. movzx eax, _VdmUserCr0MapIn[eax]
  1577. push esp ; Pass current Esp to handler
  1578. push offset scr_fault ; Set Handler address
  1579. push PCR[PcExceptionList] ; Set next pointer
  1580. mov PCR[PcExceptionList],esp ; Link us on
  1581. mov edx,PCR[PcTeb]
  1582. mov edx,[edx].TeVdm ; get pointer to VdmTib
  1583. cmp edx, _MmUserProbeAddress ; probe the pointer
  1584. jbe @f
  1585. mov edx, _MmUserProbeAddress ; make us AV
  1586. @@: mov [edx].VtVdmContext.CsFloatSave.FpCtxtCr0NpxState, eax
  1587. scr10: pop PCR[PcExceptionList] ; Remove our exception handle
  1588. add esp, 8 ; clear stack
  1589. mov edx, PCR[PcInitialStack] ; Get fp save area
  1590. mov ebx, PCR[PcPrcbData + PbCurrentThread] ; (ebx) = current thread
  1591. scr20: cli ; sync with context swap
  1592. and [edx].FpCr0NpxState, NOT (CR0_MP+CR0_EM+CR0_PE)
  1593. or [edx].FpCr0NpxState,eax ; set fp save area bits
  1594. mov eax,cr0
  1595. and eax, NOT (CR0_MP+CR0_EM+CR0_TS) ; turn off bits we will change
  1596. or al, [ebx].ThNpxState ; set scheduler bits
  1597. or eax,[edx].FpCr0NpxState ; set user's bits
  1598. mov cr0,eax
  1599. sti
  1600. ret
  1601. scr_fault:
  1602. ;
  1603. ; WARNING: Here we directly unlink the exception handler from the
  1604. ; exception registration chain. NO unwind is performed. We can take
  1605. ; this short cut because we know that our handler is a leaf-node.
  1606. ;
  1607. mov esp, [esp+8] ; (esp)-> ExceptionList
  1608. jmp short scr10
  1609. KiVdmSetUserCR0 endp
  1610. _TEXT$00 ENDS
  1611. end