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.

553 lines
17 KiB

  1. subttl emf386.asm - 32 bit Emulator Interrupt Handler
  2. page
  3. ;***
  4. ;emf386.asm - 32 bit Emulator Interrupt Handler
  5. ;
  6. ; IBM/Microsoft Confidential
  7. ;
  8. ; Copyright (c) IBM Corporation 1987, 1989
  9. ; Copyright (c) Microsoft Corporation 1987, 1989
  10. ;
  11. ; All Rights Reserved
  12. ;
  13. ;Purpose:
  14. ; 32 bit Emulator Interrupt Handler
  15. ;
  16. ;Revision History: (also see emulator.hst)
  17. ;
  18. ; 1/21/92 JWM Minor modifications for DOSX32 emulator
  19. ; 8/23/91 TP Reduce to only two decoding steps
  20. ;
  21. ;*******************************************************************************
  22. ;*********************************************************************;
  23. ; ;
  24. ; Main Entry Point and Address Calculation Procedure ;
  25. ; ;
  26. ; 80386 version ;
  27. ; ;
  28. ;*********************************************************************;
  29. ;
  30. ; This routine fetches the 8087 instruction, calculates memory address
  31. ; if necessary into ES:ESI and calls a routine to emulate the instruction.
  32. ; Most of the dispatching is done through tables. (see comments in CONST)
  33. ;
  34. ; The instruction dispatching is designed to favor the 386 addressing modes
  35. ifdef _DOS32EXT ; JWM
  36. public __astart
  37. __astart:
  38. mov eax, 1
  39. ret
  40. public _Ms32KrnlHandler
  41. _Ms32KrnlHandler:
  42. endif
  43. ifdef NT386
  44. ;
  45. ; NPXEmulatorTable is a table read by the Windows/NT kernel in
  46. ; order to support the R3 emulator
  47. ;
  48. public _NPXEMULATORTABLE
  49. _NPXEMULATORTABLE label dword
  50. dd offset NpxNpHandler ; Address of Ring3 Trap7 handler
  51. dd offset tRoundMode ; Address of rounding vector table
  52. endif
  53. public NPXNPHandler
  54. NPXNPHandler:
  55. ifdef DEBUG
  56. int 3
  57. endif
  58. cld ; clear direction flag forever
  59. ifdef NT386
  60. ;-- bryanwi - 16Oct91 - Hack FP fix, not pointing IDT:7 at this
  61. ; routine for 16bit code is the right thing to do.
  62. ;
  63. ; Check to see if we are running on flat SS. If so, assume things
  64. ; are OK and proceed. (If a 16bit app loads the flat SS and then
  65. ; does an FP instruction, they're hosed, no skin off our nose.)
  66. ;
  67. ; If SS not what we expect, then either (a) a flat apps is *very*
  68. ; confused, or (b) a 16 bit app has hit an FP instuction. In either
  69. ; case, this emulator is not going to work. Therefore, raise an exception.
  70. ;
  71. push ax ; use form that will word with any SS
  72. mov ax,ss
  73. or ax,RPL_MASK
  74. cmp ax,(KGDT_R3_DATA OR RPL_MASK)
  75. pop ax
  76. jz OK_Segment ; Segments are OK, proceed normally.
  77. jmp Around
  78. _DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
  79. align 4
  80. EmerStk db 1024 dup (?) ; *** SaveContext is assumed to be
  81. SaveContext db size ContextFrameLength dup (?) ; *** at the top of the EmerStk by
  82. SaveException db size ExceptionRecordLength dup (?) ; *** the function @ 13f:0
  83. _DATA ENDS
  84. Around:
  85. ;
  86. ; Trap occured in 16bit code, get to flat environment and raise exception
  87. ;
  88. push eax ; save EAX on old stack
  89. mov ax, ds
  90. push eax ; Save DS on old stack
  91. mov ax,(KGDT_R3_DATA OR RPL_MASK)
  92. mov ds,ax
  93. ASSUME DS:FLAT
  94. pop dword ptr [SaveContext.CsSegDs] ; remove ds from old stack
  95. pop dword ptr [SaveContext.CsEax] ; remove eax from old stack
  96. pop dword ptr [SaveContext.CsEip] ; copy eip from old stack
  97. pop dword ptr [SaveContext.CsSegCs] ; copy cs from old stack
  98. pop dword ptr [SaveContext.CsEflags] ; copy eflag from old stack
  99. push dword ptr [SaveContext.CsEFlags] ; restore eflag to old stack
  100. push dword ptr [SaveContext.CsSegCs] ; restore cs to old stack
  101. push dword ptr [SaveContext.CsEip] ; restore eip to old stack
  102. mov dword ptr [SaveContext.CsEsp], esp
  103. ;
  104. ; Build rest of context frame
  105. ;
  106. mov dword ptr [SaveContext.CsContextFlags],CONTEXT_CONTROL OR CONTEXT_SEGMENTS OR CONTEXT_INTEGER
  107. mov dword ptr [SaveContext.CsEbx], ebx
  108. mov dword ptr [SaveContext.CsEcx], ecx
  109. mov dword ptr [SaveContext.CsEdx], edx
  110. mov dword ptr [SaveContext.CsEsi], esi
  111. mov dword ptr [SaveContext.CsEdi], edi
  112. mov dword ptr [SaveContext.CsEbp], ebp
  113. mov dword ptr [SaveContext.CsSegEs], es
  114. mov dword ptr [SaveContext.CsSegFs], fs
  115. mov dword ptr [SaveContext.CsSegGs], gs
  116. mov dword ptr [SaveContext.CsSegSs], ss
  117. mov ss,ax ; Switch to new stack
  118. mov esp,(OFFSET FLAT:EmerStk) + 1024
  119. ASSUME SS:FLAT
  120. ;
  121. ; ss: flat, esp -> EmerStk
  122. ;
  123. mov ax,KGDT_R3_TEB OR RPL_MASK
  124. mov fs, ax
  125. mov ecx, fs:[TbVdm]
  126. or ecx, ecx
  127. jne short DoVdmFault
  128. mov ecx, offset SaveContext ; (ecx) -> context record
  129. mov edx, offset SaveException ; (edx) -> exception record
  130. mov dword ptr [edx.ErExceptionCode],STATUS_ILLEGAL_FLOAT_CONTEXT
  131. mov dword ptr [edx.ErExceptionFlags],0
  132. mov dword ptr [edx.ErExceptionRecord],0
  133. mov ebx, [ecx.CsEip]
  134. mov [edx.ErExceptionAddress],ebx
  135. mov [edx.ErNumberParameters],0
  136. ;
  137. ; ZwRaiseException(edx=ExceptionRecord, ecx=ContextRecord, TRUE=FirstChance)
  138. ;
  139. stdCall _ZwRaiseException, <edx, ecx, 1>
  140. ;
  141. ; If we come back HERE, things are hosed. We cannot bugcheck because
  142. ; we are in user space, so int-3 and loop forever instead.
  143. ;
  144. Forever:
  145. int 3
  146. jmp short Forever
  147. DoVdmFault:
  148. ;
  149. ; Does the VDM want the fault, or should the instruction be skipped
  150. ;
  151. test ds:[ecx].VtVdmContext.CsFloatSave.FpCr0NpxState, CR0_EM
  152. jz short SkipNpxInstruction
  153. add dword ptr [SaveContext.CsEsp], 12 ; remove from old stack
  154. ; jump to the dos extender NPX exception handler
  155. ; jmp far ptr 013fh:0
  156. db 0eah
  157. dd 0
  158. dw 013fh
  159. SkipNpxInstruction:
  160. mov ax,(KGDT_R3_DATA OR RPL_MASK)
  161. mov es,ax
  162. stdCall _NpxNpSkipInstruction, <offset SaveContext>
  163. mov ebx, dword ptr [SaveContext.CsEbx]
  164. mov ecx, dword ptr [SaveContext.CsEcx]
  165. mov edx, dword ptr [SaveContext.CsEdx]
  166. mov edi, dword ptr [SaveContext.CsEdi]
  167. mov esi, dword ptr [SaveContext.CsEsi]
  168. mov ebp, dword ptr [SaveContext.CsEbp]
  169. mov gs, dword ptr [SaveContext.CsSegGs]
  170. mov fs, dword ptr [SaveContext.CsSegFs]
  171. mov es, dword ptr [SaveContext.CsSegEs]
  172. mov eax, dword ptr [SaveContext.CsEsp]
  173. mov ss, dword ptr [SaveContext.CsSegSs] ; switch to original stack
  174. mov esp, eax
  175. add esp, 12 ; remove eflag, cs, eip
  176. push dword ptr [SaveContext.CsEflags]
  177. push dword ptr [SaveContext.CsSegCs]
  178. push dword ptr [SaveContext.CsEip]
  179. mov eax, dword ptr [SaveContext.CsEax]
  180. mov ds, dword ptr [SaveContext.CsSegDs]
  181. iretd ; restore eflag, cs, eip
  182. OK_Segment:
  183. endif
  184. push ds ; save segment registers
  185. GetEmData ds
  186. push EMSEG:[LongStatusWord] ;In case we're saving status
  187. push EMSEG:[PrevCodeOff] ;In case we save environment
  188. ;Save registers in order of their index number
  189. push edi
  190. push esi
  191. push ebp
  192. push esp
  193. add dword ptr [esp],regFlg-regESP ; adjust to original esp
  194. push ebx
  195. push edx
  196. push ecx
  197. push eax
  198. cmp EMSEG:[Einstall], 0 ; Make sure emulator is initialized.
  199. je InstalEm
  200. EmInstalled:
  201. mov edi,[esp].regEIP ;edi = 387 instruction address
  202. movzx edx, word ptr cseg:[edi] ;dx = esc and opcode
  203. ; Check for unmasked errors
  204. mov al, EMSEG:[CURerr] ; fetch errors
  205. and al, EMSEG:[ErrMask]
  206. jnz short PossibleException
  207. ; UNDONE: rip test for FWAIT in final version
  208. cmp dl, 9bh ;FWAIT?
  209. je sawFWAIT
  210. NoException:
  211. Execute387inst:
  212. ;Enter here if look-ahead found another 387 instruction
  213. mov EMSEG:[PrevCodeOff],edi
  214. mov EMSEG:[CurErrCond],0 ;clear error and cond. codes, show busy
  215. add edi, 2 ; point past opcode
  216. ;CONSIDER: remove the two instruction below and muck with EA386Tab
  217. ;CONSIDER: to optimize for mem ops instead of reg ops.
  218. add dh,40h ; No effective address?
  219. jc NoEffectiveAddress0 ; yes, go do instruction
  220. rol dh,2 ; rotate MOD field next to r/m field
  221. mov bl,dh
  222. and ebx,1FH ; Mask to MOD and r/m fields
  223. MemModeDispatch: ;Label for debugging
  224. jmp EA386Tab[4*ebx]
  225. InstalEm:
  226. call EmulatorInit
  227. mov edi,DefaultControlWord ; Default mode to start in
  228. mov eax, edi
  229. call SetControlWord ; Set it
  230. mov EMSEG:[LongControlWord], edi ; reset reserved bits
  231. jmp EmInstalled
  232. ; ************************
  233. ;
  234. ; We are about to execute a new FP instruction and there is an
  235. ; unmasked expcetion. Check to see if the new FP instruction is
  236. ; a "no wait" instruction. If so, let it proceede; otherwise, raise
  237. ; the exception.
  238. ;
  239. PossibleException:
  240. cmp edx, 0E3DBh ; if fninit, no exception
  241. je short NoException
  242. cmp edx, 0E2DBh ; if fnclex, no exception
  243. je short NoException
  244. cmp edx, 0E0DFh ; if "fnstsw ax", no exception
  245. je short NoException
  246. cmp dl, 0D9h ; possible encoding for fnstenv or fnstcw?
  247. je short pe20 ; yes, check mod r/m
  248. cmp dl, 0DDh ; possible encoding for fnsave or fnstsw?
  249. jne short pe30
  250. pe20: mov bl, dh ; bl = op2
  251. shr bl, 3
  252. and bl, 7 ; bl = mod r/m
  253. cmp bl, 6 ; is it a 6 or 7?
  254. jnc short NoException ; yes, no exception
  255. pe30:
  256. jmp CommonExceptions ; unmasked exception is pending, raise it
  257. ; ************************
  258. ; 386 address modes
  259. ; SIB does not handle SS overrides for ebp
  260. SIB macro modval
  261. local SIBindex,SIBbase
  262. movzx ebx,byte ptr cseg:[edi] ; ebx = SIB field
  263. inc edi ; bump past SIB field
  264. mov eax,ebx
  265. and al,7 ; mask down to base register
  266. if modval eq 0
  267. cmp al,5 ; base = ebp
  268. jne short SIBbase ; yes - get base register value
  269. mov eax,cseg:[edi] ; eax = disp32
  270. add edi,4 ; bump past displacement
  271. jmp SIBindex ; Added to support bbt,
  272. ; replacing SKIP 3,SIBindex
  273. endif
  274. SIBbase:
  275. mov eax,[esp+4*eax] ; eax = base register value
  276. SIBindex:
  277. mov [esp].regESP,0 ; no esp indexing allowed
  278. mov cl,bl
  279. shr cl,6 ; cl = scale factor
  280. and bl,7 shl 3 ; ebx = 8 * index register
  281. shr bl,1
  282. mov esi,[esp+1*ebx] ; esi = index register value
  283. shl esi,cl ; esi = scaled index register value
  284. add esi,eax ; esi = SIB address value
  285. endm
  286. ALIGN 4
  287. SIB00:
  288. SIB 00 ; decode SIB field
  289. jmp CommonMemory
  290. ALIGN 4
  291. SIB01:
  292. SIB 01 ; decode SIB field
  293. movsx eax,byte ptr cseg:[edi]
  294. inc edi
  295. add esi,eax
  296. jmp short CommonMemory
  297. ALIGN 4
  298. SIB10:
  299. SIB 10 ; decode SIB field
  300. mov eax,cseg:[edi]
  301. add edi,4
  302. add esi,eax
  303. jmp short CommonMemory
  304. ; 386 single register addressing
  305. ALIGN 4
  306. Exx00:
  307. and bl,7 shl 2 ; mask off mod bits
  308. mov esi,[esp+1*ebx]
  309. jmp short CommonMemory
  310. ALIGN 4
  311. Exx01:
  312. and bl,7 shl 2 ; mask off mod bits
  313. mov esi,[esp+1*ebx]
  314. movsx eax,byte ptr cseg:[edi]
  315. inc edi
  316. add esi,eax
  317. jmp short CommonMemory
  318. ALIGN 4
  319. Exx10:
  320. and bl,7 shl 2 ; mask off mod bits
  321. mov esi,[esp+1*ebx]
  322. add esi,cseg:[edi]
  323. add edi,4
  324. jmp short CommonMemory
  325. ; 386 direct addressing
  326. ALIGN 4
  327. Direct386:
  328. mov esi,cseg:[edi]
  329. add edi,4
  330. CommonMemory:
  331. MOV [esp].regEIP,edi ; final return offset
  332. ; At this point ESI = memory address, dx = |Op|r/m|MOD|escape|MF|Arith|
  333. ; Current format of opcode and address mode bytes (after rol dh,2)
  334. ;
  335. ; 7 6 5 4 3 2 1 0
  336. ; |1 1 0 1 1| op1 | dl
  337. ;
  338. ; 7 6 5 4 3 2 1 0
  339. ; | op2 | r/m |mod| dh
  340. ;
  341. ;op1 and op2 fields together make the FP opcode
  342. rol dx,5 ; dl = | op1 | op2 |? ?|
  343. and edx,0FCH ;Keep only op1 & op2 bits
  344. push offset EMLFINISH
  345. mov edi,EMSEG:[CURstk]
  346. MemOpDisp: ;Debugging label
  347. ;edi = [CURstk]
  348. jmp tOpMemDisp[edx]
  349. ALIGN 4
  350. NoEffectiveAddress0:
  351. rol dh,2
  352. NoEffectiveAddress: ; Either Register op or Miscellaneous
  353. mov [esp].regEIP,edi ; final return offset
  354. ;Current format of opcode and address mode bytes (after rol dh,2)
  355. ;
  356. ; 7 6 5 4 3 2 1 0
  357. ; |1 1 0 1 1| op1 | dl
  358. ;
  359. ; 7 6 5 4 3 2 1 0
  360. ; | op2 | r/m |mod| dh
  361. ;
  362. ;op1 and op2 fields together make the FP opcode
  363. mov al,dh ;Save r/m bits (contains reg. no.)
  364. rol dx,5 ; dl = | op1 | op2 |? ?|
  365. and edx,0FCH ;Keep only op1 & op2 bits
  366. push offset EMLFINISH
  367. and eax,7 shl 2 ;Mask to register number * 4
  368. mov edi,EMSEG:[CURstk]
  369. lea esi,[2*eax+eax] ;Register no. * 12
  370. add esi,edi
  371. cmp esi,ENDstk ;Run past end?
  372. jae RegWrap
  373. RegOpDisp: ;Debugging label
  374. ;eax = r/m bits * 4
  375. ;esi = FP register address
  376. ;edi = [CURstk]
  377. jmp tOpRegDisp[edx]
  378. ALIGN 4
  379. RegWrap:
  380. sub esi,ENDstk - BEGstk ;Wrap around JWM
  381. RegOpDispWrap: ;Debugging label
  382. jmp tOpRegDisp[edx]
  383. SawFwait:
  384. inc edi ; bump past FWAIT
  385. mov [esp].regEIP,edi ; final return offset
  386. mov EMSEG:[CURErr],0 ; clear current error and cond. codes
  387. ; return from routine; restore registers and return
  388. align 4
  389. EMLFINISH:
  390. ; check for errors
  391. mov al, EMSEG:[CURerr] ; fetch errors
  392. or al, EMSEG:[SWerr]
  393. mov EMSEG:[SWerr],al ; set errors in sticky error flag
  394. and al,EMSEG:[ErrMask]
  395. jnz CommonExceptions
  396. ifdef TRACENPX
  397. jmp CommonExceptions
  398. endif
  399. if DBG eq 0
  400. ;
  401. ; On a free build, look ahead to next instruction
  402. ;
  403. ;09BH is FWAIT - just skip it
  404. ;0D8H - 0DFH is 387 instruction, emulate it
  405. mov edi,[esp].regEIP ;edi = 387 instruction address
  406. mov dx,cseg:[edi]
  407. cmp dl,09BH ;FWAIT?
  408. jz short SawFwait
  409. sub dl,0D8H
  410. cmp dl,8
  411. jb ReExecute
  412. endif
  413. mov ebx,[esp].[OldLongStatus]
  414. and ebx,LongSavedFlags ;preserve condition codes, error flags
  415. or EMSEG:[LongStatusWord],ebx ;merge saved status word, condition codes
  416. pop eax
  417. pop ecx
  418. pop edx
  419. pop ebx
  420. add esp,4 ; toss esp value
  421. pop ebp
  422. pop esi
  423. pop edi
  424. add esp,8 ;toss old PrevCodeOff and StatusWord
  425. mov EMSEG:[CURerr],Summary ;Indicate we are not busy
  426. pop ds
  427. error_return ; common exit sequence
  428. ReExecute:
  429. mov eax,EMSEG:[LongStatusWord]
  430. mov ebx,[esp].[OldLongStatus]
  431. and ebx,LongSavedFlags ;preserve condition codes, error flags
  432. or eax,ebx ;merge saved status word, condition codes
  433. mov [esp].OldLongStatus,eax
  434. mov eax,EMSEG:[PrevCodeOff]
  435. mov [esp].OldCodeOff,eax
  436. lea eax,[esp+regFlg+4] ;must restore "saved" esp
  437. mov [esp].RegEsp,eax
  438. jmp Execute387inst