Leaked source code of windows server 2003
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.

910 lines
23 KiB

  1. title "Processor type and stepping detection"
  2. ;++
  3. ;
  4. ; Copyright (c) 1989 Microsoft Corporation
  5. ;
  6. ; Module Name:
  7. ;
  8. ; cpu.asm
  9. ;
  10. ; Abstract:
  11. ;
  12. ; This module implements the assembley code necessary to determine
  13. ; cpu type and stepping information.
  14. ;
  15. ; Author:
  16. ;
  17. ; Shie-Lin Tzong (shielint) 28-Oct-1991.
  18. ; Some of the code is extracted from Cruiser (mainly,
  19. ; the code to determine 386 stepping.)
  20. ;
  21. ; Environment:
  22. ;
  23. ; 80x86 Real Mode.
  24. ;
  25. ; Revision History:
  26. ;
  27. ;
  28. ;--
  29. .xlist
  30. include cpu.inc
  31. .list
  32. ;
  33. ; constant for i386 32-bit multiplication test
  34. ;
  35. MULTIPLIER equ 00000081h
  36. MULTIPLICAND equ 0417a000h
  37. RESULT_HIGH equ 00000002h
  38. RESULT_LOW equ 0fe7a000h
  39. ;
  40. ; Constants for Floating Point test
  41. ;
  42. REALLONG_LOW equ 00000000
  43. REALLONG_HIGH equ 3FE00000h
  44. PSEUDO_DENORMAL_LOW equ 00000000h
  45. PSEUDO_DENORMAL_MID equ 80000000h
  46. PSEUDO_DENORMAL_HIGH equ 0000h
  47. .386p
  48. _TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
  49. ASSUME CS: _TEXT, DS:NOTHING, SS:NOTHING
  50. ;++
  51. ;
  52. ; USHORT
  53. ; HwGetProcessorType (
  54. ; VOID
  55. ; )
  56. ;
  57. ; Routine Description:
  58. ;
  59. ; This function determines type of processor (80486, 80386, 80286,
  60. ; and even 8086/8088). it relies on Intel-approved code that takes
  61. ; advantage of the documented behavior of the high nibble of the flag
  62. ; word in the REAL MODE of the various processors.
  63. ;
  64. ; For completeness, the code also checks for 8088/8086. But, it won't
  65. ; work.
  66. ;
  67. ; Arguments:
  68. ;
  69. ; None.
  70. ;
  71. ; Return Value:
  72. ;
  73. ; (ax) = x86h or 0 if unrecongnized processor.
  74. ;
  75. ;--
  76. .8086
  77. public _HwGetProcessorType
  78. _HwGetProcessorType proc near
  79. pushf ; save entry flags
  80. ;
  81. ; The MSB (bit 15) is always a one on the 8086 and 8088 and a zero on
  82. ; the 286, 386 and 486.
  83. ;
  84. pushf
  85. pop ax
  86. and ax, NOT 08000h ; clear bit 15 of flags
  87. push ax
  88. popf ; try to put that in the flags
  89. pushf
  90. pop ax ; look at what really went into flags
  91. test ax,08000h ; Was high bit set ?
  92. jnz short x_86 ; if nz, still set, goto x_86
  93. ;
  94. ; Bit 14 (NT flag) and bits 13/12 (IOPL bit field) are always zero on
  95. ; the 286, but can be set on the 386 and 486.
  96. ;
  97. or ax,07000h ; Try to set the NT/IOPL bits
  98. push ax
  99. popf ; Put in to the flags
  100. sti ; (for VDMM/IOPL0)
  101. pushf
  102. pop ax ; look at actual flags
  103. test ax,07000h ; Any high bits set ?
  104. jz short x_286 ; if z, no, goto x_286
  105. .386p
  106. ;
  107. ; The Alignment Check bit in flag can be set on 486 and is always zero
  108. ; on 386.
  109. ;
  110. mov eax,cr0 ; test for 486 processor
  111. push eax ; save CR0 value
  112. and eax,not CR0_AM ; disable alignment check
  113. mov cr0,eax
  114. db ADDRESS_OVERRIDE
  115. pushfd ; save original EFLAGS
  116. db ADDRESS_OVERRIDE
  117. pushfd ; try to set alignment check
  118. or dword ptr [esp],EFLAGS_AC ; bit in EFLAGS
  119. db ADDRESS_OVERRIDE
  120. popfd
  121. db ADDRESS_OVERRIDE
  122. pushfd ; copy new flags into ECX
  123. pop ecx ; [ecx] = new flags word
  124. db ADDRESS_OVERRIDE
  125. popfd ; restore original EFLAGS
  126. pop eax ; restore original CR0 value
  127. mov cr0,eax
  128. and ecx, EFLAGS_AC ; did AC bit get set?
  129. jz short x_386 ; if z, no, goto x_386
  130. mov eax, 4h ; if nz, we have a 486 processor
  131. .286p
  132. jmp short hpt99
  133. x_286:
  134. mov ax, 2h ; Return 286 processor type.
  135. jmp short hpt99
  136. x_86:
  137. mov ax, 0h ; Return 86h for 8088/8086 CPU type.
  138. jmp short hpt99
  139. x_386:
  140. mov ax, 3h ; Return 386 processor type.
  141. hpt99:
  142. popf ; restore flags
  143. ret
  144. _HwGetProcessorType endp
  145. IFDEF ALLOW_386
  146. .386p
  147. ;++
  148. ;
  149. ; USHORT
  150. ; HwGetCpuStepping (
  151. ; UHSORT CpuType
  152. ; )
  153. ;
  154. ; Routine Description:
  155. ;
  156. ; This function determines cpu stepping for the specified CPU type.
  157. ;
  158. ; Currently, this routine only determine stepping for 386 and 486.
  159. ;
  160. ; Arguments:
  161. ;
  162. ; CpuType - The Cpu type which its stepping information will be returned.
  163. ; The input value MUST be either 386 or 486.
  164. ;
  165. ; Return Value:
  166. ;
  167. ; [ax] - Cpu stepping. For example, [ax] = D0h for D0 stepping.
  168. ;
  169. ;--
  170. if 0
  171. HgcsCpuType equ [esp + 2]
  172. public _HwGetCpuStepping
  173. _HwGetCpuStepping proc
  174. mov ax, HgcsCpuType ; [ax] = CpuType
  175. cmp ax, 3h ; Is cpu = 386?
  176. jz short Hgcs00 ; if z, yes, go Hgcs00
  177. call Get486Stepping ; else, check for 486 stepping
  178. jmp short Hgcs90 ; [ax] = Stepping information
  179. Hgcs00:
  180. call _Get386Stepping ; [ax] = Stepping information
  181. Hgcs90:
  182. ret
  183. _HwGetCpuStepping endp
  184. endif
  185. ;++
  186. ;
  187. ; USHORT
  188. ; _Get386Stepping (
  189. ; VOID
  190. ; )
  191. ;
  192. ; Routine Description:
  193. ;
  194. ; This function determines cpu stepping for i386 CPU stepping.
  195. ;
  196. ; Arguments:
  197. ;
  198. ; None.
  199. ;
  200. ; Return Value:
  201. ;
  202. ; [ax] - Cpu stepping. For example, [ax] = D0h for D0 stepping.
  203. ; [ax] = 0 means bad CPU and stepping is not important.
  204. ;
  205. ;--
  206. public _Get386Stepping
  207. _Get386Stepping proc
  208. call MultiplyTest ; Perform mutiplication test
  209. jnc short G3s00 ; if nc, muttest is ok
  210. mov ax, 0
  211. ret
  212. G3s00:
  213. call Check386B0 ; Check for B0 stepping
  214. jnc short G3s05 ; if nc, it's B1/later
  215. mov ax, 0B0h ; It is B0/earlier stepping
  216. ret
  217. G3s05:
  218. call Check386D1 ; Check for D1 stepping
  219. jc short G3s10 ; if c, it is NOT D1
  220. mov ax, 0D1h ; It is D1/later stepping
  221. ret
  222. G3s10:
  223. mov ax, 0B1h ; assume it is B1 stepping
  224. ret
  225. _Get386Stepping endp
  226. if 0
  227. ;++
  228. ;
  229. ; USHORT
  230. ; Get486Stepping (
  231. ; VOID
  232. ; )
  233. ;
  234. ; Routine Description:
  235. ;
  236. ; This function determines cpu stepping for i486 CPU type.
  237. ;
  238. ; Arguments:
  239. ;
  240. ; None.
  241. ;
  242. ; Return Value:
  243. ;
  244. ; [ax] - Cpu stepping. For example, [ax] = D0h for D0 stepping.
  245. ;
  246. ;--
  247. public Get486Stepping
  248. Get486Stepping proc
  249. call Check486AStepping ; Check for A stepping
  250. jnc short G4s00 ; if nc, it is NOT A stepping
  251. mov ax, 0A0h ; set to A stepping
  252. ret
  253. G4s00: call Check486BStepping ; Check for B stepping
  254. jnc short G4s10 ; if nc, it is NOT a B stepping
  255. mov ax, 0B0h ; set to B stepping
  256. ret
  257. ;
  258. ; Before we test for 486 C/D step, we need to make sure NPX is present.
  259. ; Because the test uses FP instruction to do the detection.
  260. ;
  261. G4s10: call _IsNpxPresent ; Check if cpu has coprocessor support?
  262. cmp ax, 0
  263. jz short G4s15 ; it is actually 486sx
  264. call Check486CStepping ; Check for C stepping
  265. jnc short G4s20 ; if nc, it is NOT a C stepping
  266. G4s15:
  267. mov ax, 0C0h ; set to C stepping
  268. ret
  269. G4s20: mov ax, 0D0h ; Set to D stepping
  270. ret
  271. Get486Stepping endp
  272. ;++
  273. ;
  274. ; BOOLEAN
  275. ; Check486AStepping (
  276. ; VOID
  277. ; )
  278. ;
  279. ; Routine Description:
  280. ;
  281. ; This routine checks for 486 A Stepping.
  282. ;
  283. ; It takes advantage of the fact that on the A-step of the i486
  284. ; processor, the ET bit in CR0 could be set or cleared by software,
  285. ; but was not used by the hardware. On B or C -step, ET bit in CR0
  286. ; is now hardwired to a "1" to force usage of the 386 math coprocessor
  287. ; protocol.
  288. ;
  289. ; Arguments:
  290. ;
  291. ; None.
  292. ;
  293. ; Return Value:
  294. ;
  295. ; Carry Flag clear if B or later stepping.
  296. ; Carry Flag set if A or earlier stepping.
  297. ;
  298. ;--
  299. public Check486AStepping
  300. Check486AStepping proc near
  301. .386p
  302. mov eax, cr0 ; reset ET bit in cr0
  303. and eax, NOT CR0_ET
  304. mov cr0, eax
  305. mov eax, cr0 ; get cr0 back
  306. test eax, CR0_ET ; if ET bit still set?
  307. jnz short cas10 ; if nz, yes, still set, it's NOT A step
  308. stc
  309. ret
  310. cas10: clc
  311. ret
  312. ret
  313. Check486AStepping endp
  314. ;++
  315. ;
  316. ; BOOLEAN
  317. ; Check486BStepping (
  318. ; VOID
  319. ; )
  320. ;
  321. ; Routine Description:
  322. ;
  323. ; This routine checks for 486 B Stepping.
  324. ;
  325. ; On the i486 processor, the "mov to/from DR4/5" instructions were
  326. ; aliased to "mov to/from DR6/7" instructions. However, the i486
  327. ; B or earlier steps generate an Invalid opcode exception when DR4/5
  328. ; are used with "mov to/from special register" instruction.
  329. ;
  330. ; Arguments:
  331. ;
  332. ; None.
  333. ;
  334. ; Return Value:
  335. ;
  336. ; Carry Flag clear if C or later stepping.
  337. ; Carry Flag set if B stepping.
  338. ;
  339. ;--
  340. public Check486BStepping
  341. Check486BStepping proc
  342. push ds
  343. push bx
  344. xor ax,ax
  345. mov ds,ax ; (DS) = 0 (real mode IDT)
  346. mov bx,6*4
  347. push dword ptr [bx] ; save old int 6 vector
  348. mov word ptr [bx].VectorOffset,offset Temporary486Int6
  349. mov [bx].VectorSegment,cs ; set vector to new int 6 handler
  350. c4bs50: db 0fh, 21h, 0e0h ; mov eax, DR4
  351. nop
  352. nop
  353. nop
  354. nop
  355. nop
  356. clc ; it is C step
  357. jmp short c4bs70
  358. c4bs60: stc ; it's B step
  359. c4bs70: pop dword ptr [bx] ; restore old int 6 vector
  360. pop bx
  361. pop ds
  362. ret
  363. ret
  364. Check486BStepping endp
  365. ;++
  366. ;
  367. ; BOOLEAN
  368. ; Temporary486Int6 (
  369. ; VOID
  370. ; )
  371. ;
  372. ; Routine Description:
  373. ;
  374. ; Temporary int 6 handler - assumes the cause of the exception was the
  375. ; attempted execution of an mov to/from DR4/5 instruction.
  376. ;
  377. ; Arguments:
  378. ;
  379. ; None.
  380. ;
  381. ; Return Value:
  382. ;
  383. ; none.
  384. ;
  385. ;--
  386. Temporary486Int6 proc
  387. mov word ptr [esp].IretIp,offset c4bs60 ; set IP to stc instruction
  388. iret
  389. Temporary486Int6 endp
  390. ;++
  391. ;
  392. ; BOOLEAN
  393. ; Check486CStepping (
  394. ; VOID
  395. ; )
  396. ;
  397. ; Routine Description:
  398. ;
  399. ; This routine checks for 486 C Stepping.
  400. ;
  401. ; This routine takes advantage of the fact that FSCALE produces
  402. ; wrong result with Denormal or Pseudo-denormal operand on 486
  403. ; C and earlier steps.
  404. ;
  405. ; If the value contained in ST(1), second location in the floating
  406. ; point stack, is between 1 and 11, and the value in ST, top of the
  407. ; floating point stack, is either a pseudo-denormal number or a
  408. ; denormal number with the underflow exception unmasked, the FSCALE
  409. ; instruction produces an incorrect result.
  410. ;
  411. ; Arguments:
  412. ;
  413. ; None.
  414. ;
  415. ; Return Value:
  416. ;
  417. ; Carry Flag clear if D or later stepping.
  418. ; Carry Flag set if C stepping.
  419. ;
  420. ;--
  421. FpControl equ [ebp - 2]
  422. RealLongSt1 equ [ebp - 10]
  423. PseudoDenormal equ [ebp - 20]
  424. FscaleResult equ [ebp - 30]
  425. public Check486CStepping
  426. Check486CStepping proc
  427. push ebp
  428. mov ebp, esp
  429. sub esp, 30 ; Allocate space for temp real variables
  430. ;
  431. ; Initialize the local FP variables to predefined values.
  432. ; RealLongSt1 = 1.0 * (2 ** -1) = 0.5 in normalized double precision FP form
  433. ; PseudoDenormal = a unsupported format by IEEE.
  434. ; Sign bit = 0
  435. ; Exponent = 000000000000000B
  436. ; Significand = 100000...0B
  437. ; FscaleResult = The result of FSCALE instruction. Depending on 486 step,
  438. ; the value will be different:
  439. ; Under C and earlier steps, 486 returns the original value
  440. ; in ST as the result. The correct returned value should be
  441. ; original significand and an exponent of 0...01.
  442. ;
  443. mov dword ptr RealLongSt1, REALLONG_LOW
  444. mov dword ptr RealLongSt1 + 4, REALLONG_HIGH
  445. mov dword ptr PseudoDenormal, PSEUDO_DENORMAL_LOW
  446. mov dword ptr PseudoDenormal + 4, PSEUDO_DENORMAL_MID
  447. mov word ptr PseudoDenormal + 8, PSEUDO_DENORMAL_HIGH
  448. .387
  449. fnstcw FpControl ; Get FP control word
  450. or word ptr FpControl, 0FFh ; Mask all the FP exceptions
  451. fldcw FpControl ; Set FP control
  452. fld qword ptr RealLongSt1 ; 0 < ST(1) = RealLongSt1 < 1
  453. fld tbyte ptr PseudoDenormal; Denormalized operand. Note, i486
  454. ; won't report denormal exception
  455. ; on 'FLD' instruction.
  456. ; ST(0) = Extended Denormalized operand
  457. fscale ; try to trigger 486Cx errata
  458. fstp tbyte ptr FscaleResult ; Store ST(0) in FscaleResult
  459. cmp word ptr FscaleResult + 8, PSEUDO_DENORMAL_HIGH
  460. ; Is Exponent changed?
  461. jz short c4ds00 ; if z, no, it is C step
  462. clc
  463. jmp short c4ds10
  464. c4ds00: stc
  465. c4ds10: mov esp, ebp
  466. pop ebp
  467. ret
  468. Check486CStepping endp
  469. endif
  470. ;++
  471. ;
  472. ; BOOLEAN
  473. ; Check386B0 (
  474. ; VOID
  475. ; )
  476. ;
  477. ; Routine Description:
  478. ;
  479. ; This routine checks for 386 B0 or earlier stepping.
  480. ;
  481. ; It takes advantage of the fact that the bit INSERT and
  482. ; EXTRACT instructions that existed in B0 and earlier versions of the
  483. ; 386 were removed in the B1 stepping. When executed on the B1, INSERT
  484. ; and EXTRACT cause an int 6 (invalid opcode) exception. This routine
  485. ; can therefore discriminate between B1/later 386s and B0/earlier 386s.
  486. ; It is intended to be used in sequence with other checks to determine
  487. ; processor stepping by exercising specific bugs found in specific
  488. ; steppings of the 386.
  489. ;
  490. ; Arguments:
  491. ;
  492. ; None.
  493. ;
  494. ; Return Value:
  495. ;
  496. ; Carry Flag clear if B1 or later stepping
  497. ; Carry Flag set if B0 or prior
  498. ;
  499. ;--
  500. ASSUME ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
  501. Check386B0 proc
  502. push ds
  503. push bx
  504. xor ax,ax
  505. mov ds,ax ; (DS) = 0 (real mode IDT)
  506. mov bx,6*4
  507. push dword ptr [bx] ; save old int 6 vector
  508. mov word ptr [bx].VectorOffset,offset TemporaryInt6
  509. mov [bx].VectorSegment,cs ; set vector to new int 6 handler
  510. ;
  511. ; Attempt execution of Extract Bit String instruction. Execution on
  512. ; B0 or earlier with length (CL) = 0 will return 0 into the destination
  513. ; (CX in this case). Execution on B1 or later will fail either due to
  514. ; taking the invalid opcode trap, or if the opcode is valid, we don't
  515. ; expect CX will be zeroed by any new instruction supported by newer
  516. ; steppings. The dummy int 6 handler will clears the Carry Flag and
  517. ; returns execution to the appropriate label. If the instruction
  518. ; actually executes, CX will *probably* remain unchanged in any new
  519. ; stepping that uses the opcode for something else. The nops are meant
  520. ; to handle newer steppings with an unknown instruction length.
  521. ;
  522. xor ax,ax
  523. mov dx,ax
  524. mov cx,0ff00h ; Extract length (CL) == 0, (CX) != 0
  525. b1c50: db 0fh, 0a6h, 0cah ; xbts cx,dx,ax,cl
  526. nop
  527. nop
  528. nop
  529. nop
  530. nop
  531. stc ; assume B0
  532. jcxz short b1c70 ; jmp if B0
  533. b1c60: clc
  534. b1c70: pop dword ptr [bx] ; restore old int 6 vector
  535. pop bx
  536. pop ds
  537. ret
  538. Check386B0 endp
  539. ;++
  540. ;
  541. ; BOOLEAN
  542. ; TemporaryInt6 (
  543. ; VOID
  544. ; )
  545. ;
  546. ; Routine Description:
  547. ;
  548. ; Temporary int 6 handler - assumes the cause of the exception was the
  549. ; attempted execution of an XTBS instruction.
  550. ;
  551. ; Arguments:
  552. ;
  553. ; None.
  554. ;
  555. ; Return Value:
  556. ;
  557. ; none.
  558. ;
  559. ;--
  560. TemporaryInt6 proc
  561. mov word ptr [esp].IretIp,offset b1c60 ; set IP to clc instruction
  562. iret
  563. TemporaryInt6 endp
  564. ;++
  565. ;
  566. ; BOOLEAN
  567. ; Check386D1 (
  568. ; VOID
  569. ; )
  570. ;
  571. ; Routine Description:
  572. ;
  573. ; This routine checks for 386 D1 Stepping.
  574. ;
  575. ; It takes advantage of the fact that on pre-D1 386, if a REPeated
  576. ; MOVS instruction is executed when single-stepping is enabled,
  577. ; a single step trap is taken every TWO moves steps, but should
  578. ; occuu each move step.
  579. ;
  580. ; NOTE: This routine cannot distinguish between a D0 stepping and a D1
  581. ; stepping. If a need arises to make this distinction, this routine
  582. ; will need modification. D0 steppings will be recognized as D1.
  583. ;
  584. ; Arguments:
  585. ;
  586. ; None.
  587. ;
  588. ; Return Value:
  589. ;
  590. ; Carry Flag clear if D1 or later stepping
  591. ; Carry Flag set if B1 or prior
  592. ;
  593. ;--
  594. assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
  595. Check386D1 proc
  596. push ds
  597. push bx
  598. xor ax,ax
  599. mov ds,ax ; (DS) = 0 (real mode IDT)
  600. mov bx,1*4
  601. push dword ptr [bx] ; save old int 1 vector
  602. mov word ptr [bx].VectorOffset,offset TemporaryInt1
  603. mov word ptr [bx].VectorSegment,cs ; set vector to new int 1 handler
  604. ;
  605. ; Attempt execution of rep movsb instruction with the Trace Flag set.
  606. ; Execution on B1 or earlier with length (CX) > 1 will trace over two
  607. ; iterations before accepting the trace trap. Execution on D1 or later
  608. ; will accept the trace trap after a single iteration. The dummy int 1
  609. ; handler will return execution to the instruction following the movsb
  610. ; instruction. Examination of (CX) will reveal the stepping.
  611. ;
  612. sub sp,4 ; make room for target of movsb
  613. xor si,si ; (ds:si) = 0:0
  614. push ss ; (es:di) = ss:sp-4
  615. pop es
  616. mov di,sp
  617. mov cx,2 ; 2 iterations
  618. pushf
  619. or word ptr [esp], EFLAGS_TF
  620. popf ; cause a single step trap
  621. rep movsb
  622. d1c60: add sp,4 ; clean off stack
  623. pop dword ptr [bx] ; restore old int 1 vector
  624. stc ; assume B1
  625. jcxz short d1cx ; jmp if <= B1
  626. clc ; else clear carry to indicate >= D1
  627. d1cx:
  628. pop bx
  629. pop ds
  630. ret
  631. Check386D1 endp
  632. ;++
  633. ;
  634. ; BOOLEAN
  635. ; TemporaryInt1 (
  636. ; VOID
  637. ; )
  638. ;
  639. ; Routine Description:
  640. ;
  641. ; Temporary int 1 handler - assumes the cause of the exception was
  642. ; trace trap at the above rep movs instruction.
  643. ;
  644. ; Arguments:
  645. ;
  646. ; (esp)->eip of trapped instruction
  647. ; cs of trapped instruction
  648. ; eflags of trapped instruction
  649. ;
  650. ;--
  651. TemporaryInt1 proc
  652. and word ptr [esp].IretFlags,not EFLAGS_TF ; clear caller's Trace Flag
  653. mov word ptr [esp].IretIp,offset d1c60 ; set IP to next instruction
  654. iret
  655. TemporaryInt1 endp
  656. ;++
  657. ;
  658. ; BOOLEAN
  659. ; MultiplyTest (
  660. ; VOID
  661. ; )
  662. ;
  663. ; Routine Description:
  664. ;
  665. ; This routine checks the 386 32-bit multiply instruction.
  666. ; The reason for this check is because some of the i386 fail to
  667. ; perform this instruction.
  668. ;
  669. ; Arguments:
  670. ;
  671. ; None.
  672. ;
  673. ; Return Value:
  674. ;
  675. ; Carry Flag clear on success
  676. ; Carry Flag set on failure
  677. ;
  678. ;--
  679. ;
  680. assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
  681. MultiplyTest proc
  682. xor cx,cx ; 64K times is a nice round number
  683. mlt00: push cx
  684. call Multiply ; does this chip's multiply work?
  685. pop cx
  686. jc short mltx ; if c, No, exit
  687. loop mlt00 ; if nc, YEs, loop to try again
  688. clc
  689. mltx:
  690. ret
  691. MultiplyTest endp
  692. ;++
  693. ;
  694. ; BOOLEAN
  695. ; Multiply (
  696. ; VOID
  697. ; )
  698. ;
  699. ; Routine Description:
  700. ;
  701. ; This routine performs 32-bit multiplication test which is known to
  702. ; fail on bad 386s.
  703. ;
  704. ; Note, the supplied pattern values must be used for consistent results.
  705. ;
  706. ; Arguments:
  707. ;
  708. ; None.
  709. ;
  710. ; Return Value:
  711. ;
  712. ; Carry Flag clear on success.
  713. ; Carry Flag set on failure.
  714. ;
  715. ;--
  716. Multiply proc
  717. mov ecx, MULTIPLIER
  718. mov eax, MULTIPLICAND
  719. mul ecx
  720. cmp edx, RESULT_HIGH ; Q: high order answer OK ?
  721. stc ; assume failure
  722. jnz short mlpx ; N: exit with error
  723. cmp eax, RESULT_LOW ; Q: low order answer OK ?
  724. stc ; assume failure
  725. jnz short mlpx ; N: exit with error
  726. clc ; indicate success
  727. mlpx:
  728. ret
  729. Multiply endp
  730. ;++
  731. ;
  732. ; BOOLEAN
  733. ; IsNpxPresent(
  734. ; VOID
  735. ; );
  736. ;
  737. ; Routine Description:
  738. ;
  739. ; This routine determines if there is any Numeric coprocessor
  740. ; present. If yes, the ET bit in CR0 will be set; otherwise
  741. ; it will be reset.
  742. ;
  743. ; Note that we do NOT determine its type (287, 387).
  744. ; This code is extracted from Intel book.
  745. ;
  746. ; Arguments:
  747. ;
  748. ; None.
  749. ;
  750. ; Return:
  751. ;
  752. ; TRUE - If NPX is present. Else a value of FALSE is returned.
  753. ;
  754. ;--
  755. if 0
  756. public _IsNpxPresent
  757. _IsNpxPresent proc near
  758. push bp ; Save caller's bp
  759. .386p
  760. mov eax, cr0
  761. and eax, NOT CR0_ET ; Assume no NPX
  762. mov edx, 0
  763. .287
  764. fninit ; Initialize NPX
  765. mov cx, 5A5Ah ; Put non-zero value
  766. push cx ; into the memory we are going to use
  767. mov bp, sp
  768. fnstsw word ptr [bp] ; Retrieve status - must use non-wait
  769. cmp byte ptr [bp], 0 ; All bits cleared by fninit?
  770. jne Inp10
  771. or eax, CR0_ET
  772. mov edx, 1
  773. Inp10:
  774. mov cr0, eax
  775. pop ax ; clear scratch value
  776. pop bp ; Restore caller's bp
  777. mov eax, edx
  778. ret
  779. _IsNpxPresent endp
  780. endif
  781. ENDIF ; def ALLOW_386
  782. _TEXT ENDS
  783. END