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.

657 lines
20 KiB

  1. page 78,132
  2. ;*******************************************************************************
  3. ; Copyright (c) Microsoft Corporation 1991
  4. ; All Rights Reserved
  5. ;
  6. ; ke\i386\emxcptn.asm
  7. ;
  8. ; Module to support getting/setting context to and from the R3
  9. ; emulator.
  10. ;
  11. ;Revision History:
  12. ;
  13. ;
  14. ;*******************************************************************************
  15. .386p
  16. _TEXT SEGMENT DWORD PUBLIC 'CODE'
  17. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  18. ;;*******************************************************************************
  19. ;;
  20. ;; Include some more macros and constants.
  21. ;;
  22. ;;*******************************************************************************
  23. ;
  24. NT386 equ 1
  25. include ks386.inc
  26. include em387.inc ; Emulator TEB data layout
  27. include callconv.inc
  28. EXTRNP _KeGetCurrentIrql,0
  29. EXTRNP _KeBugCheck,1
  30. EXTRNP _ExRaiseStatus,1
  31. extrn _Ki387RoundModeTable:dword
  32. subttl _KiEm87StateToNpxFrame
  33. page
  34. ;*** _KiEm87StateToNpxFrames
  35. ;
  36. ; Translates the R3 emulators state to the NpxFrame
  37. ;
  38. ; Returns TRUE if NpxFrame sucessfully completed.
  39. ; else FALSE
  40. ;
  41. ; Warning: This function can only be called at Irql 0 with interrupts
  42. ; enabled. It is intended to be called only to deal with R3 exceptions
  43. ; when the emulator is being used.
  44. ;
  45. ; Revision History:
  46. ;
  47. ;
  48. ;*******************************************************************************
  49. cPublicProc _KiEm87StateToNpxFrame, 1
  50. push ebp
  51. mov ebp, esp
  52. push ebx ; Save C runtime varibles
  53. push edi
  54. push esi
  55. push esp ; Pass current Esp to handler
  56. push offset stnpx_30 ; Set Handler address
  57. push PCR[PcExceptionList] ; Set next pointer
  58. mov PCR[PcExceptionList],esp ; Link us on
  59. if DBG
  60. pushfd ; Sanity check
  61. pop ecx ; make sure interrupts are enabled
  62. test ecx, EFLAGS_INTERRUPT_MASK
  63. jz short stnpx_err
  64. stdCall _KeGetCurrentIrql ; Sanity check
  65. cmp al, DISPATCH_LEVEL ; make sure Irql is below DPC level
  66. jnc short stnpx_err
  67. endif
  68. xor eax, eax ; set FALSE
  69. mov ebx,PCR[PcPrcbData+PbCurrentThread]
  70. mov ebx,[ebx]+ThApcState+AsProcess
  71. cmp dword ptr [ebx]+PrVdmObjects,0 ; is this a vdm process?
  72. jne short stnpx_10 ; Yes, then not supported
  73. mov ebx, PCR[PcTeb] ; R3 Teb
  74. cmp [ebx].Einstall, 0 ; Initialized?
  75. je short stnpx_10 ; No, then don't return NpxFrame
  76. test [ebx].CURErr, Summary ; Completed?
  77. jz short stnpx_10 ; No, then don't return NpxFrame
  78. mov esi, [ebp+8] ; (esi) = NpxFrame
  79. call SaveState
  80. mov eax, 1 ; Return TRUE
  81. stnpx_10:
  82. pop PCR[PcExceptionList] ; Remove our exception handle
  83. add esp, 8 ; clear stack
  84. pop esi
  85. pop edi
  86. pop ebx
  87. pop ebp
  88. stdRET _KiEm87StateToNpxFrame
  89. stnpx_30:
  90. ;
  91. ; WARNING: Here we directly unlink the exception handler from the
  92. ; exception registration chain. NO unwind is performed. We can take
  93. ; this short cut because we know that our handler is a leaf-node.
  94. ;
  95. mov esp, [esp+8] ; (esp)-> ExceptionList
  96. xor eax, eax ; Return FALSE
  97. jmp short stnpx_10
  98. if DBG
  99. stnpx_err:
  100. stdCall _KeBugCheck <IRQL_NOT_LESS_OR_EQUAL>
  101. endif
  102. _KiEm87StateToNpxFrame ENDP
  103. ;*** SaveEnv
  104. ;
  105. ;
  106. ; ARGUMENTS
  107. ;
  108. ; (esi) = NpxFrame
  109. ; (ebx) = PcTeb
  110. ;
  111. ;
  112. ; DESCRIPTION
  113. ;
  114. SaveEnv:
  115. xor ax,ax
  116. mov [esi].reserved1,ax
  117. mov [esi].reserved2,ax
  118. mov [esi].reserved3,ax
  119. mov [esi].reserved4,ax
  120. mov [esi].reserved5,ax
  121. mov ax,[ebx].ControlWord
  122. mov [esi].E32_ControlWord,ax
  123. call GetEMSEGStatusWord
  124. mov [esi].E32_StatusWord,ax
  125. call GetTagWord
  126. mov [esi].E32_TagWord,ax
  127. mov ax,cs
  128. mov [esi].E32_CodeSeg,ax ; NOTE: Not R0 code & stack
  129. mov ax,ss
  130. mov [esi].E32_DataSeg,ax
  131. mov eax,[ebx].PrevCodeOff
  132. mov [esi].E32_CodeOff,eax
  133. mov eax,[ebx].PrevDataOff
  134. mov [esi].E32_DataOff,eax
  135. ret
  136. ;*** SaveState -
  137. ;
  138. ; ARGUMENTS
  139. ; (esi) = where to store environment
  140. ; (ebx) = PcTeb
  141. ;
  142. ; DESCRIPTION
  143. ;
  144. ; REGISTERS
  145. ; Destroys ALL, but EBX
  146. ;
  147. SaveState: ; Enter here for debugger save state
  148. mov dword ptr [esi].FpCr0NpxState, CR0_EM
  149. call SaveEnv
  150. add esi,size Env80x87_32 ;Skip over environment
  151. mov ebp,NumLev ;Save entire stack
  152. mov edi,[ebx].CURstk
  153. ss_loop:
  154. mov eax,[ebx+edi].ExpSgn
  155. call StoreTempReal ;in emstore.asm
  156. add esi,10
  157. mov edi,[ebx].CURstk
  158. ;;; NextStackElem edi,SaveState
  159. cmp edi,INITstk
  160. jae short ss_wrap
  161. add edi,Reg87Len
  162. ss_continue:
  163. mov [ebx].CURstk,edi
  164. dec ebp
  165. jnz short ss_loop
  166. ret
  167. ss_wrap:
  168. mov edi, BEGstk
  169. jmp short ss_continue
  170. ;*** GetTagWord - figures out what the tag word is from the numeric stack
  171. ; and returns the value of the tag word in ax.
  172. ;
  173. ; ARGUMENTS
  174. ; (ebx) = PcTeb
  175. ;
  176. GetTagWord:
  177. push esi
  178. xor eax, eax
  179. mov ecx, NumLev ; get tags for regs. 0, 7 - 1
  180. mov esi, INITstk
  181. GetTagLoop:
  182. mov dh, [ebx+esi].bTag ; The top 2 bits of Tag are the X87 tag bits.
  183. shld ax, dx, 2
  184. sub esi, Reg87Len
  185. loop GetTagLoop
  186. rol ax, 2 ; This moves Tag(0) into the low 2 bits
  187. pop esi
  188. ret
  189. ;*** GetEMSEGStatusWord
  190. ;
  191. ; User status word returned in ax.
  192. ; Uses status word in per-thread data area, otherwise
  193. ; identical to GetStatusWord
  194. ;
  195. ; ARGUMENTS
  196. ; (ebx) = PcTeb
  197. GetEMSEGStatusWord:
  198. mov eax, [ebx].CURstk
  199. sub eax, BEGstk
  200. ;
  201. ; Make sure the 'div' won't overflowed.
  202. ;
  203. cmp eax, Reg87Len * (NumLev + 2)
  204. ja short @f
  205. mov dl,Reg87Len
  206. div dl
  207. inc eax
  208. and eax, 7 ; eax is now the stack number
  209. shl ax, 11
  210. or ax, [ebx].StatusWord ; or in the rest of the status word.
  211. ret
  212. @@:
  213. mov eax, STATUS_INTEGER_OVERFLOW
  214. stdCall _ExRaiseStatus, <eax>
  215. ret ; Should never come here ...
  216. ;*** StoreTempReal
  217. ;
  218. ;
  219. ; ARGUMENTS
  220. ; ??
  221. ; (ebx) = PcTeb
  222. ;
  223. StoreTempReal:
  224. mov edx,[ebx+edi].lManHi
  225. mov edi,[ebx+edi].lManLo
  226. ;mantissa in edx:edi, exponent in high eax, sign in ah bit 7, tag in al
  227. ;memory destination is esi
  228. mov ecx,eax ;get copy of sign and tag
  229. shr ecx,16 ;Bring exponent down
  230. cmp al,bTAG_ZERO
  231. jz short StoreIEEE80 ;Skip bias if zero
  232. add ecx,IexpBias-TexpBias ;Correct bias
  233. cmp al,bTAG_DEN
  234. jz short Denorm80
  235. StoreIEEE80:
  236. and eax,bSign shl 8
  237. or ecx,eax ;Combine sign with exponent
  238. mov [esi],edi
  239. mov [esi+4],edx
  240. mov [esi+8],cx
  241. ret
  242. Denorm80:
  243. ;Must change it to a denormal
  244. dec ecx
  245. neg ecx ;Use as shift count
  246. cmp cl,32 ;Long shift?
  247. jae LongDenorm
  248. shrd edi,edx,cl
  249. shr edx,cl
  250. xor ecx,ecx ;Exponent is zero
  251. jmp short StoreIEEE80
  252. LongDenorm:
  253. ;edi must be zero if we have 32 bits to shift
  254. xchg edx,edi ;32-bit right shift
  255. shr edi,cl ;shift count is modulo-32
  256. xor ecx,ecx ;Exponent is zero
  257. jmp short StoreIEEE80
  258. ;****************************************************
  259. ;****************************************************
  260. ;****************************************************
  261. ;****************************************************
  262. ;*** _KiNpxFrameToEm87State
  263. ;
  264. ; Translates the NpxFrame to the R3 emulators state
  265. ;
  266. ; Returns TRUE if NpxFrame state sucessfully transfered.
  267. ; else FALSE
  268. ;
  269. ; Warning: This function can only be called at Irql 0 with interrupts
  270. ; enabled. It is intended to be called only to deal with R3 exceptions
  271. ; when the emulator is being used.
  272. ;
  273. ; Revision History:
  274. ;
  275. ;
  276. ;*******************************************************************************
  277. cPublicProc _KiNpxFrameToEm87State, 1
  278. push ebp
  279. mov ebp, esp
  280. push ebx ; Save C runtime varibles
  281. push edi
  282. push esi
  283. push esp ; Pass current Esp to handler
  284. push offset npxts_30 ; Set Handler address
  285. push PCR[PcExceptionList] ; Set next pointer
  286. mov PCR[PcExceptionList],esp ; Link us on
  287. if DBG
  288. pushfd ; Sanity check
  289. pop ecx ; make sure interrupts are enabled
  290. test ecx, EFLAGS_INTERRUPT_MASK
  291. jz short npxts_err
  292. stdCall _KeGetCurrentIrql ; Sanity check
  293. cmp al, DISPATCH_LEVEL ; make sure Irql is below DPC level
  294. jnc short npxts_err
  295. endif
  296. xor eax, eax ; set FALSE
  297. mov ebx,PCR[PcPrcbData+PbCurrentThread]
  298. mov ebx,[ebx]+ThApcState+AsProcess
  299. cmp dword ptr [ebx]+PrVdmObjects,0 ; is this a vdm process?
  300. jne short npxts_10 ; Yes, then not supported
  301. mov ebx, PCR[PcTeb] ; R3 Teb
  302. cmp [ebx].Einstall, 0 ; Initialized?
  303. je short npxts_10 ; No, then don't set NpxFrame
  304. mov esi, [ebp+8] ; (esi) = NpxFrame
  305. call StorState
  306. or [ebx].CURErr, Summary ; Set completed
  307. mov eax, 1 ; Return TRUE
  308. npxts_10:
  309. pop PCR[PcExceptionList] ; Remove our exception handle
  310. add esp, 8 ; clear stack
  311. pop esi
  312. pop edi
  313. pop ebx
  314. pop ebp
  315. stdRet _KiNpxFrameToEm87State
  316. npxts_30:
  317. ;
  318. ; WARNING: Here we directly unlink the exception handler from the
  319. ; exception registration chain. NO unwind is performed. We can take
  320. ; this short cut because we know that our handler is a leaf-node.
  321. ;
  322. mov esp, [esp+8] ; (esp)-> ExceptionList
  323. xor eax, eax ; Return FALSE
  324. jmp short npxts_10
  325. ret
  326. if DBG
  327. npxts_err:
  328. stdCall _KeBugCheck <IRQL_NOT_LESS_OR_EQUAL>
  329. endif
  330. _KiNpxFrameToEm87State ENDP
  331. ;*** StorState - emulate FRSTOR [address]
  332. ;
  333. ; ARGUMENTS
  334. ; (esi) = where to get the environment
  335. ; (ebx) = PcTeb
  336. ;
  337. ;
  338. ; DESCRIPTION
  339. ; This routine emulates an 80387 FRSTOR (restore state)
  340. StorState:
  341. ;First we set up the status word so that [CURstk] is initialized.
  342. ;The floating-point registers are stored in logical ST(0) - ST(7) order,
  343. ;not physical register order. We don't do a full load of the environment
  344. ;because we're not ready to use the tag word yet.
  345. mov ax, [esi].E32_StatusWord
  346. call SetEmStatusWord ;Initialize [CURstk]
  347. add esi,size Env80x87_32 ;Skip over environment
  348. ;Load of temp real has one difference from real math chip: it is an invalid
  349. ;operation to load an unsupported format. By ensuring the exception is
  350. ;masked, we will convert unsupported format to Indefinite. Note that the
  351. ;mask and [CURerr] will be completely restored by the FLDENV at the end.
  352. mov [ebx].CWmask,3FH ;Mask off invalid operation exception
  353. mov edi,[ebx].CURstk
  354. mov ebp,NumLev
  355. FrstorLoadLoop:
  356. push esi
  357. call LoadTempReal ;In emload.asm
  358. pop esi
  359. add esi,10 ;Point to next temp real
  360. ;;; NextStackElem edi,Frstor
  361. cmp edi,INITstk
  362. jae short fr_wrap
  363. add edi,Reg87Len
  364. fr_continue:
  365. dec ebp
  366. jnz short FrstorLoadLoop
  367. sub esi,NumLev*10+size Env80x87_32 ;Point to start of env.
  368. ;
  369. ; Stor Enviroment
  370. ; (esi) = where to get enviroment
  371. ; (ebx) = PcTeb
  372. ;
  373. mov ax, [esi].E32_StatusWord
  374. call SetEmStatusWord ; set up status word
  375. mov ax, [esi].E32_ControlWord
  376. call SetControlWord
  377. mov ax, [esi].E32_TagWord
  378. call UseTagWord
  379. mov eax, [esi].E32_CodeOff
  380. mov [ebx].PrevCodeOff, eax
  381. mov eax, [esi].E32_DataOff
  382. mov [ebx].PrevDataOff, eax
  383. ret
  384. fr_wrap:
  385. mov edi, BEGstk
  386. jmp short fr_continue
  387. ;*** SetEmStatusWord -
  388. ;
  389. ; Given user status word in ax, set into emulator.
  390. ; Destroys ebx only.
  391. SetEmStatusWord:
  392. and ax,7F7FH
  393. mov cx,ax
  394. and cx,3FH ; set up CURerr in case user
  395. mov [ebx].CURerr,cl ; wants to force an exception
  396. mov ecx, eax
  397. and ecx, not (7 shl 11) ; remove stack field.
  398. mov [ebx].StatusWord, cx
  399. sub ah, 8 ; adjust for emulator's stack layout
  400. and ah, 7 shl 3
  401. mov al, ah
  402. shr ah, 1
  403. add al, ah ; stack field * 3 * 4
  404. .erre Reg87Len eq 12
  405. and eax, 255 ; eax is now 12*stack number
  406. add eax, BEGstk
  407. mov [ebx].CURstk, eax
  408. ret
  409. SetControlWord:
  410. and ax,0F3FH ; Limit to valid values
  411. mov [ebx].ControlWord, ax ; Store in the emulated control word
  412. not al ;Flip mask bits for fast compare
  413. and al,3FH ;Limit to valid mask bits
  414. mov [ebx].ErrMask,al
  415. and eax,(RoundControl + PrecisionControl) shl 8
  416. .erre RoundControl eq 1100B
  417. .erre PrecisionControl eq 0011B
  418. shr eax,6 ;Put PC and RC in bits 2-5
  419. mov ecx,_Ki387RoundModeTable
  420. mov ecx,[ecx+eax] ;Get correct RoundMode vector
  421. mov [ebx].RoundMode,ecx
  422. mov [ebx].SavedRoundMode,ecx
  423. and eax,RoundControl shl (8-6) ;Mask off precision control
  424. mov ecx,_Ki387RoundModeTable
  425. mov ecx,[ecx+(eax+PC64 shl (8-6))];Get correct RoundMode vector
  426. mov [ebx].TransRound,ecx ;Round mode w/o precision
  427. ret
  428. ;*** UseTagWord - Set up tags using tag word from environment
  429. ;
  430. ; ARGUMENTS
  431. ; ax - should contain the tag word
  432. ;
  433. ; Destroys ax,bx,cx,dx,di
  434. UseTagWord:
  435. ror ax, 2 ; mov Tag(0) into top bits of ax
  436. mov edi,INITstk
  437. mov ecx, NumLev
  438. UseTagLoop:
  439. mov dl,bTAG_EMPTY
  440. cmp ah, 0c0h ;Is register to be tagged Empty?
  441. jae short SetTag ;Yes, go mark it
  442. mov dl,[ebx+edi].bTag ;Get current tag
  443. cmp dl,bTAG_EMPTY ;Is register currently Empty?
  444. je short SetTagNotEmpty ;If so, go figure out tag for it
  445. SetTag:
  446. mov [ebx+edi].bTag,dl
  447. UseTagLoopCheck:
  448. sub edi, Reg87Len
  449. shl eax, 2
  450. loop UseTagLoop
  451. ret
  452. SetTagEmpty:
  453. mov [ebx+edi].bTag, bTAG_EMPTY
  454. jmp short UseTagLoopCheck
  455. SetTagNotEmpty:
  456. ;Register is currently tagged empty, but new tag word says it is not empty.
  457. ;Figure out a new tag for it. The rules are:
  458. ;
  459. ;1. Everything is either normalized or zero--unnormalized formats cannot
  460. ;get in. So if the high half mantissa is zero, the number is zero.
  461. ;
  462. ;2. Although the exponent bias is different, NANs and Infinities are in
  463. ;standard IEEE format - exponent is TexpMax, mantissa indicates NAN vs.
  464. ;infinity (mantissa for infinity is 800..000H).
  465. ;
  466. ;3. Denormals have an exponent less than TexpMin.
  467. ;
  468. ;4. If the low half of the mantissa is zero, it is tagged bTAG_SNGL
  469. ;
  470. ;5. Everything else is bTAG_VALID
  471. cmp [ebx+edi].lManHi, 0
  472. mov dl,bTAG_ZERO ;Try zero first
  473. jz short SetTag ;Is mantissa zero?
  474. mov edx,[ebx+edi].ExpSgn
  475. mov dl,bTAG_DEN
  476. cmp edx,TexpMin shl 16 ;Is it denormal?
  477. jl short SetTag
  478. cmp [ebx+edi].lManLo,0 ;Is low half zero?
  479. .erre bTAG_VALID eq 1
  480. .erre bTAG_SNGL eq 0
  481. setnz dl ;if low half==0 then dl=0 else dl=1
  482. cmp edx,TexpMax shl 16 ;Is it NAN or Infinity?
  483. jl short SetTag ;If not, it's valid
  484. .erre (bTAG_VALID - bTAG_SNGL) shl TAG_SHIFT eq (bTAG_NAN - bTAG_INF)
  485. shl dl,TAG_SHIFT
  486. add dl,bTAG_INF - bTAG_SNGL
  487. ;If the low bits were zero we have just changed bTAG_SNGL to bTAG_INF
  488. ;If the low bits weren't zero, we changed bTAG_VALID to bTAG_NAN
  489. ;See if infinity is really possible: is high half 80..00H?
  490. cmp [ebx+edi].lManHi,1 shl 31 ;Is it infinity?
  491. jz short SetTag ;Store tag for infinity or NAN
  492. mov dl,bTAG_NAN
  493. jmp short SetTag
  494. ;*** LoadTempReal
  495. ;
  496. ;
  497. ;
  498. LoadTempReal:
  499. mov ebx,[esi+4] ;Get high half of mantissa
  500. mov cx,[esi+8] ;Get exponent and sign
  501. mov esi,[esi] ;Get low half of mantissa
  502. mov eax,ecx
  503. and ch,7FH ;Mask off sign bit
  504. shl ecx,16 ;Move exponent to high end
  505. mov ch,ah ;Restore sign
  506. jz short ZeroOrDenorm80
  507. ;Check for unsupported format: unnormals (MSB not set)
  508. or ebx,ebx
  509. jns short Unsupported
  510. sub ecx,(IexpBias-TexpBias) shl 16 ;Correct the bias
  511. cmp ecx,TexpMax shl 16
  512. jge short NANorInf80
  513. SetupTag:
  514. or esi,esi ;Any bits in low half?
  515. .erre bTAG_VALID eq 1
  516. .erre bTAG_SNGL eq 0
  517. setnz cl ;if low half==0 then cl=0 else cl=1
  518. jmp short SaveStack
  519. NANorInf80:
  520. mov cl,bTAG_NAN
  521. cmp ebx,1 shl 31 ;Only 1 bit set means infinity
  522. jnz short SaveStack
  523. or esi,esi
  524. jnz short SaveStack
  525. mov cl,bTAG_INF
  526. jmp short SaveStack
  527. ZeroOrDenorm80:
  528. ;Exponent is zero. Number is either zero or denormalized
  529. or ebx,ebx
  530. jnz short ShortNorm80 ;Are top 32 bits zero?
  531. or esi,esi ;Are low 32 bits zero too?
  532. jnz LongNorm80
  533. mov cl,bTAG_ZERO
  534. jmp short SaveStack
  535. ;This code accepts and works correctly with pseudo-denormals (MSB already set)
  536. LongNorm80:
  537. xchg ebx,esi ;Shift up 32 bits
  538. sub ecx,32 shl 16 ;Correct exponent
  539. ShortNorm80:
  540. add ecx,(TexpBias-IexpBias+1-31) shl 16 ;Fix up bias
  541. bsr edx,ebx ;Scan for MSB
  542. ;Bit number in edx ranges from 0 to 31
  543. mov cl,dl
  544. not cl ;Convert bit number to shift count
  545. shld ebx,esi,cl
  546. shl esi,cl
  547. shl edx,16 ;Move exp. adjustment to high end
  548. add ecx,edx ;Adjust exponent
  549. jmp short SetUpTag
  550. SaveStack:
  551. mov eax, PCR[PcTeb]
  552. mov [eax].CURstk,edi
  553. mov [eax+edi].lManLo,esi
  554. mov [eax+edi].lManHi,ebx
  555. mov [eax+edi].ExpSgn,ecx
  556. mov ebx, eax ; (ebx) = PcTeb
  557. ret
  558. Unsupported:
  559. mov ebx, PCR[PcTeb]
  560. or [ebx].CURerr,Invalid ; (assume it's masked?)
  561. mov [ebx+edi].lManLo,0
  562. mov [ebx+edi].lManHi,0C0000000H
  563. mov [ebx+edi].ExpSgn,TexpMax shl 16 + bSign shl 8 + bTAG_NAN
  564. mov [ebx].CURstk,edi ;Update top of stack
  565. ret
  566. _TEXT ENDS
  567. END