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.

1118 lines
27 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
  24. ;
  25. ; Revision History:
  26. ;
  27. ;--
  28. .xlist
  29. include i386\cpu.inc
  30. include ks386.inc
  31. include callconv.inc
  32. include mac386.inc
  33. .list
  34. ;
  35. ; constant for i386 32-bit multiplication test
  36. ;
  37. MULTIPLIER equ 00000081h
  38. MULTIPLICAND equ 0417a000h
  39. RESULT_HIGH equ 00000002h
  40. RESULT_LOW equ 0fe7a000h
  41. ;
  42. ; Constants for Floating Point test
  43. ;
  44. REALLONG_LOW equ 00000000
  45. REALLONG_HIGH equ 3FE00000h
  46. PSEUDO_DENORMAL_LOW equ 00000000h
  47. PSEUDO_DENORMAL_MID equ 80000000h
  48. PSEUDO_DENORMAL_HIGH equ 0000h
  49. .586p
  50. INIT SEGMENT DWORD PUBLIC 'CODE'
  51. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  52. ;++
  53. ;
  54. ; USHORT
  55. ; KiSetProcessorType (
  56. ; VOID
  57. ; )
  58. ;
  59. ; Routine Description:
  60. ;
  61. ; This function determines type of processor (80486, 80386),
  62. ; and it's corrisponding stepping. The results are saved in
  63. ; the current processor's PRCB.
  64. ;
  65. ; Arguments:
  66. ;
  67. ; None.
  68. ;
  69. ; Return Value:
  70. ;
  71. ; Prcb->CpuType
  72. ; 3, 4, 5, ... 3 = 386, 4 = 486, etc..
  73. ;
  74. ; Prcb->CpuStep is encoded as follows:
  75. ; lower byte as stepping #
  76. ; upper byte as stepping letter (0=a, 1=b, 2=c, ...)
  77. ;
  78. ; (ax) = x86h or 0 if unrecongnized processor.
  79. ;
  80. ;--
  81. cPublicProc _KiSetProcessorType,0
  82. mov byte ptr fs:PcPrcbData.PbCpuID, 0
  83. push edi
  84. push esi
  85. push ebx ; Save C registers
  86. mov eax, cr0
  87. push eax
  88. pushfd ; save Cr0 & flags
  89. pop ebx ; Get flags into eax
  90. push ebx ; Save original flags
  91. mov ecx, ebx
  92. xor ecx, EFLAGS_ID ; flip ID bit
  93. push ecx
  94. popfd ; load it into flags
  95. pushfd ; re-save flags
  96. pop ecx ; get flags into eax
  97. cmp ebx, ecx ; did bit stay flipped?
  98. jne short cpu_has_cpuid ; Yes, go use CPUID
  99. cpuid_unsupported:
  100. pop ebx ; Get flags into eax
  101. push ebx ; Save original flags
  102. mov ecx, ebx
  103. xor ecx, EFLAGS_AC ; flip AC bit
  104. push ecx
  105. popfd ; load it into flags
  106. pushfd ; re-save flags
  107. pop ecx ; get flags into eax
  108. cmp ebx, ecx ; did bit stay flipped?
  109. je short cpu_is_386 ; No, then this is a 386
  110. cpu_is_486:
  111. mov byte ptr fs:PcPrcbData.PbCpuType, 4h ; Save CPU Type
  112. call Get486Stepping
  113. jmp cpu_save_stepping
  114. cpu_is_386:
  115. mov byte ptr fs:PcPrcbData.PbCpuType, 3h ; Save CPU Type
  116. call Get386Stepping
  117. jmp cpu_save_stepping
  118. cpu_has_cpuid:
  119. or ebx, EFLAGS_ID
  120. push ebx
  121. popfd ; Make sure ID bit is set
  122. mov ecx, fs:PcIdt ; Address of IDT
  123. push dword ptr [ecx+30h] ; Save Trap06 handler incase
  124. push dword ptr [ecx+34h] ; the CPUID instruction faults
  125. mov eax, offset CpuIdTrap6Handler
  126. mov word ptr [ecx+30h], ax ; Set LowWord
  127. shr eax, 16
  128. mov word ptr [ecx+36h], ax ; Set HighWord
  129. mov eax, 0 ; argument to CPUID
  130. cpuid ; Uses eax, ebx, ecx, edx
  131. mov ecx, fs:PcIdt ; Address of IDT
  132. pop dword ptr [ecx+34h] ; restore trap6 handler
  133. pop dword ptr [ecx+30h]
  134. cmp eax, 1 ; make sure level 1 is supported
  135. jc short cpuid_unsupported ; no, then punt
  136. ; Get the family and stepping (cpuid fn=1). If processor family
  137. ; is less than 0xf, the format returned is as below:
  138. ; 3 2 1
  139. ; 10987654321098765432109876543210
  140. ; --------------------------------
  141. ; ppffffmmmmssss
  142. ; where
  143. ; pp = Processor Type
  144. ; ffff = Family
  145. ; mmmm = Model
  146. ; ssss = Stepping
  147. ;
  148. ; This is transformed and saved in the PRCB as
  149. ;
  150. ; PRCB->CpuStep = 0000mmmm0000ssss v v
  151. ; ->CpuID = 00000001 | | v
  152. ; ->CpuType = 0000ffff | | | v
  153. ; | | | |
  154. ; ie the dword that contains all this looks like 0M0S010F
  155. ;
  156. ; If the processor family is 0xf or greater, the format returned is:
  157. ; 3 2 1
  158. ; 10987654321098765432109876543210
  159. ; --------------------------------
  160. ; RRRRFFFFFFFFMMMMRRppffffmmmmssss
  161. ; where
  162. ; pp = Processor Type
  163. ; ffff = Family
  164. ; mmmm = Model
  165. ; ssss = Stepping
  166. ; MMMM = Extended Model
  167. ; FFFFFFFF = Extended Family
  168. ; RRRR, RR = Reserved
  169. ; This is transformed and saved in the PRCB as
  170. ;
  171. ; PRCB->CpuStep = EEEEEEEE0000ssss v v
  172. ; ->CpuID = 00000001 | | v
  173. ; ->CpuType = XXXXXXXX | | | v
  174. ; | | | |
  175. ; ie the dword that contains all this looks like EE0S01XX
  176. ;
  177. ; where
  178. ; EEEEEEEE = ((MMMM) << 4)8 bits + (mmmm)zero extended 8 bits
  179. ; XXXXXXXX = (FFFFFFFF) + (ffff)zero extended 8 bits
  180. ; The value for Extended Family cannot go beyond F0H inorder to support
  181. ; a maximum value of FFH for the final Family value(XXXXXXXX).
  182. ; The maximum value of Extended Model is FH and the maximum value for
  183. ; the final Model value(EEEEEEEE) is FFH
  184. mov eax, 1 ; get the family and stepping
  185. cpuid
  186. mov ebx, eax
  187. mov edx, eax
  188. and edx, 0F00h ; get the Family
  189. cmp edx, 0F00h ; (edx) = 00000000000000000000ffff00000000
  190. jne short cpu_not_extended ; Family less than F
  191. mov ah, al ; (eax) = RRRRFFFFFFFFMMMMmmmmssssmmmmssss
  192. shr eax, 4 ; (eax) = 0000RRRRFFFFFFFFMMMMmmmmssssmmmm
  193. mov al, bl ; (eax) = 0000RRRRFFFFFFFFMMMMmmmmmmmmssss
  194. and eax, 0FF0Fh ; (eax) = 0000000000000000EEEEEEEE0000ssss
  195. and ebx, 0FF00000h ; (ebx) = 0000FFFFFFFF00000000000000000000
  196. shr ebx, 12 ; (ebx) = 0000000000000000FFFFFFFF00000000
  197. add ebx, edx ; (ebx) = 0000000000000000XXXXXXXX00000000
  198. jmp short cpu_save_signature
  199. cpu_not_extended:
  200. and eax, 0F0h ; (eax) = Model
  201. shl eax, 4
  202. mov al, bl
  203. and eax, 0F0Fh ; (eax) = Model[15:8] | Step[7:0]
  204. and ebx, 0F00h ; (bh) = CpuType
  205. cpu_save_signature:
  206. mov byte ptr fs:PcPrcbData.PbCpuID, 1 ; Has ID support
  207. mov byte ptr fs:PcPrcbData.PbCpuType, bh ; Save CPU Type
  208. cpu_save_stepping:
  209. mov word ptr fs:PcPrcbData.PbCpuStep, ax ; Save CPU Stepping
  210. popfd ; Restore flags
  211. pop eax
  212. mov cr0, eax
  213. pop ebx
  214. pop esi
  215. pop edi
  216. stdRET _KiSetProcessorType
  217. cpuid_trap:
  218. mov ecx, fs:PcIdt ; Address of IDT
  219. pop dword ptr [ecx+34h] ; restore trap6 handler
  220. pop dword ptr [ecx+30h]
  221. jmp cpuid_unsupported ; Go get processor information
  222. stdENDP _KiSetProcessorType
  223. ;++
  224. ;
  225. ; BOOLEAN
  226. ; CpuIdTrap6 (
  227. ; VOID
  228. ; )
  229. ;
  230. ; Routine Description:
  231. ;
  232. ; Temporary int 6 handler - assumes the cause of the exception was the
  233. ; attempted CPUID instruction.
  234. ;
  235. ; Arguments:
  236. ;
  237. ; None.
  238. ;
  239. ; Return Value:
  240. ;
  241. ; none.
  242. ;
  243. ;--
  244. CpuIdTrap6Handler proc
  245. mov [esp].IretEip,offset cpuid_trap
  246. iretd
  247. CpuIdTrap6Handler endp
  248. ;++
  249. ;
  250. ; USHORT
  251. ; Get386Stepping (
  252. ; VOID
  253. ; )
  254. ;
  255. ; Routine Description:
  256. ;
  257. ; This function determines cpu stepping for i386 CPU stepping.
  258. ;
  259. ; Arguments:
  260. ;
  261. ; None.
  262. ;
  263. ; Return Value:
  264. ;
  265. ; [ax] - Cpu stepping.
  266. ; 0 = A, 1 = B, 2 = C, ...
  267. ;
  268. ;--
  269. public Get386Stepping
  270. Get386Stepping proc
  271. call MultiplyTest ; Perform mutiplication test
  272. jnc short G3s00 ; if nc, muttest is ok
  273. mov ax, 0
  274. ret
  275. G3s00:
  276. call Check386B0 ; Check for B0 stepping
  277. jnc short G3s05 ; if nc, it's B1/later
  278. mov ax, 100h ; It is B0/earlier stepping
  279. ret
  280. G3s05:
  281. call Check386D1 ; Check for D1 stepping
  282. jc short G3s10 ; if c, it is NOT D1
  283. mov ax, 301h ; It is D1/later stepping
  284. ret
  285. G3s10:
  286. mov ax, 101h ; assume it is B1 stepping
  287. ret
  288. Get386Stepping endp
  289. ;++
  290. ;
  291. ; USHORT
  292. ; Get486Stepping (
  293. ; VOID
  294. ; )
  295. ;
  296. ; Routine Description:
  297. ;
  298. ; This function determines cpu stepping for i486 CPU type.
  299. ;
  300. ; Arguments:
  301. ;
  302. ; None.
  303. ;
  304. ; Return Value:
  305. ;
  306. ; [ax] - Cpu stepping. For example, [ax] = D0h for D0 stepping.
  307. ;
  308. ;--
  309. public Get486Stepping
  310. Get486Stepping proc
  311. call Check486AStepping ; Check for A stepping
  312. jnc short G4s00 ; if nc, it is NOT A stepping
  313. mov ax, 0 ; set to A stepping
  314. ret
  315. G4s00: call Check486BStepping ; Check for B stepping
  316. jnc short G4s10 ; if nc, it is NOT a B stepping
  317. mov ax, 100h ; set to B stepping
  318. ret
  319. ;
  320. ; Before we test for 486 C/D step, we need to make sure NPX is present.
  321. ; Because the test uses FP instruction to do the detection.
  322. ;
  323. G4s10:
  324. call _KiIsNpxPresent ; Check if cpu has coprocessor support?
  325. or ax, ax
  326. jz short G4s15 ; it is actually 486sx
  327. call Check486CStepping ; Check for C stepping
  328. jnc short G4s20 ; if nc, it is NOT a C stepping
  329. G4s15:
  330. mov ax, 200h ; set to C stepping
  331. ret
  332. G4s20: mov ax, 300h ; Set to D stepping
  333. ret
  334. Get486Stepping endp
  335. ;++
  336. ;
  337. ; BOOLEAN
  338. ; Check486AStepping (
  339. ; VOID
  340. ; )
  341. ;
  342. ; Routine Description:
  343. ;
  344. ; This routine checks for 486 A Stepping.
  345. ;
  346. ; It takes advantage of the fact that on the A-step of the i486
  347. ; processor, the ET bit in CR0 could be set or cleared by software,
  348. ; but was not used by the hardware. On B or C -step, ET bit in CR0
  349. ; is now hardwired to a "1" to force usage of the 386 math coprocessor
  350. ; protocol.
  351. ;
  352. ; Arguments:
  353. ;
  354. ; None.
  355. ;
  356. ; Return Value:
  357. ;
  358. ; Carry Flag clear if B or later stepping.
  359. ; Carry Flag set if A or earlier stepping.
  360. ;
  361. ;--
  362. public Check486AStepping
  363. Check486AStepping proc near
  364. mov eax, cr0 ; reset ET bit in cr0
  365. and eax, NOT CR0_ET
  366. mov cr0, eax
  367. mov eax, cr0 ; get cr0 back
  368. test eax, CR0_ET ; if ET bit still set?
  369. jnz short cas10 ; if nz, yes, still set, it's NOT A step
  370. stc
  371. ret
  372. cas10: clc
  373. ret
  374. Check486AStepping endp
  375. ;++
  376. ;
  377. ; BOOLEAN
  378. ; Check486BStepping (
  379. ; VOID
  380. ; )
  381. ;
  382. ; Routine Description:
  383. ;
  384. ; This routine checks for 486 B Stepping.
  385. ;
  386. ; On the i486 processor, the "mov to/from DR4/5" instructions were
  387. ; aliased to "mov to/from DR6/7" instructions. However, the i486
  388. ; B or earlier steps generate an Invalid opcode exception when DR4/5
  389. ; are used with "mov to/from special register" instruction.
  390. ;
  391. ; Arguments:
  392. ;
  393. ; None.
  394. ;
  395. ; Return Value:
  396. ;
  397. ; Carry Flag clear if C or later stepping.
  398. ; Carry Flag set if B stepping.
  399. ;
  400. ;--
  401. public Check486BStepping
  402. Check486BStepping proc
  403. push ebx
  404. mov ebx, fs:PcIdt ; Address of IDT
  405. push dword ptr [ebx+30h]
  406. push dword ptr [ebx+34h] ; Save Trap06 handler
  407. mov eax, offset Temporary486Int6
  408. mov word ptr [ebx+30h], ax ; Set LowWord
  409. shr eax, 16
  410. mov word ptr [ebx+36h], ax ; Set HighWord
  411. c4bs50: db 0fh, 21h, 0e0h ; mov eax, DR4
  412. nop
  413. nop
  414. nop
  415. nop
  416. nop
  417. clc ; it is C step
  418. jmp short c4bs70
  419. c4bs60: stc ; it's B step
  420. c4bs70: pop dword ptr [ebx+34h] ; restore old int 6 vector
  421. pop dword ptr [ebx+30h]
  422. pop ebx
  423. ret
  424. ret
  425. Check486BStepping endp
  426. ;++
  427. ;
  428. ; BOOLEAN
  429. ; Temporary486Int6 (
  430. ; VOID
  431. ; )
  432. ;
  433. ; Routine Description:
  434. ;
  435. ; Temporary int 6 handler - assumes the cause of the exception was the
  436. ; attempted execution of an mov to/from DR4/5 instruction.
  437. ;
  438. ; Arguments:
  439. ;
  440. ; None.
  441. ;
  442. ; Return Value:
  443. ;
  444. ; none.
  445. ;
  446. ;--
  447. Temporary486Int6 proc
  448. mov [esp].IretEIp,offset c4bs60 ; set EIP to stc instruction
  449. iretd
  450. Temporary486Int6 endp
  451. ;++
  452. ;
  453. ; BOOLEAN
  454. ; Check486CStepping (
  455. ; VOID
  456. ; )
  457. ;
  458. ; Routine Description:
  459. ;
  460. ; This routine checks for 486 C Stepping.
  461. ;
  462. ; This routine takes advantage of the fact that FSCALE produces
  463. ; wrong result with Denormal or Pseudo-denormal operand on 486
  464. ; C and earlier steps.
  465. ;
  466. ; If the value contained in ST(1), second location in the floating
  467. ; point stack, is between 1 and 11, and the value in ST, top of the
  468. ; floating point stack, is either a pseudo-denormal number or a
  469. ; denormal number with the underflow exception unmasked, the FSCALE
  470. ; instruction produces an incorrect result.
  471. ;
  472. ; Arguments:
  473. ;
  474. ; None.
  475. ;
  476. ; Return Value:
  477. ;
  478. ; Carry Flag clear if D or later stepping.
  479. ; Carry Flag set if C stepping.
  480. ;
  481. ;--
  482. FpControl equ [ebp - 2]
  483. RealLongSt1 equ [ebp - 10]
  484. PseudoDenormal equ [ebp - 20]
  485. FscaleResult equ [ebp - 30]
  486. public Check486CStepping
  487. Check486CStepping proc
  488. push ebp
  489. mov ebp, esp
  490. sub esp, 30 ; Allocate space for temp real variables
  491. mov eax, cr0 ; Don't trap while doing math
  492. and eax, NOT (CR0_ET+CR0_MP+CR0_TS+CR0_EM)
  493. mov cr0, eax
  494. ;
  495. ; Initialize the local FP variables to predefined values.
  496. ; RealLongSt1 = 1.0 * (2 ** -1) = 0.5 in normalized double precision FP form
  497. ; PseudoDenormal = a unsupported format by IEEE.
  498. ; Sign bit = 0
  499. ; Exponent = 000000000000000B
  500. ; Significand = 100000...0B
  501. ; FscaleResult = The result of FSCALE instruction. Depending on 486 step,
  502. ; the value will be different:
  503. ; Under C and earlier steps, 486 returns the original value
  504. ; in ST as the result. The correct returned value should be
  505. ; original significand and an exponent of 0...01.
  506. ;
  507. mov dword ptr RealLongSt1, REALLONG_LOW
  508. mov dword ptr RealLongSt1 + 4, REALLONG_HIGH
  509. mov dword ptr PseudoDenormal, PSEUDO_DENORMAL_LOW
  510. mov dword ptr PseudoDenormal + 4, PSEUDO_DENORMAL_MID
  511. mov word ptr PseudoDenormal + 8, PSEUDO_DENORMAL_HIGH
  512. .387
  513. fnstcw FpControl ; Get FP control word
  514. fwait
  515. or word ptr FpControl, 0FFh ; Mask all the FP exceptions
  516. fldcw FpControl ; Set FP control
  517. fld qword ptr RealLongSt1 ; 0 < ST(1) = RealLongSt1 < 1
  518. fld tbyte ptr PseudoDenormal; Denormalized operand. Note, i486
  519. ; won't report denormal exception
  520. ; on 'FLD' instruction.
  521. ; ST(0) = Extended Denormalized operand
  522. fscale ; try to trigger 486Cx errata
  523. fstp tbyte ptr FscaleResult ; Store ST(0) in FscaleResult
  524. cmp word ptr FscaleResult + 8, PSEUDO_DENORMAL_HIGH
  525. ; Is Exponent changed?
  526. jz short c4ds00 ; if z, no, it is C step
  527. clc
  528. jmp short c4ds10
  529. c4ds00: stc
  530. c4ds10: mov esp, ebp
  531. pop ebp
  532. ret
  533. Check486CStepping endp
  534. ;++
  535. ;
  536. ; BOOLEAN
  537. ; Check386B0 (
  538. ; VOID
  539. ; )
  540. ;
  541. ; Routine Description:
  542. ;
  543. ; This routine checks for 386 B0 or earlier stepping.
  544. ;
  545. ; It takes advantage of the fact that the bit INSERT and
  546. ; EXTRACT instructions that existed in B0 and earlier versions of the
  547. ; 386 were removed in the B1 stepping. When executed on the B1, INSERT
  548. ; and EXTRACT cause an int 6 (invalid opcode) exception. This routine
  549. ; can therefore discriminate between B1/later 386s and B0/earlier 386s.
  550. ; It is intended to be used in sequence with other checks to determine
  551. ; processor stepping by exercising specific bugs found in specific
  552. ; steppings of the 386.
  553. ;
  554. ; Arguments:
  555. ;
  556. ; None.
  557. ;
  558. ; Return Value:
  559. ;
  560. ; Carry Flag clear if B1 or later stepping
  561. ; Carry Flag set if B0 or prior
  562. ;
  563. ;--
  564. Check386B0 proc
  565. push ebx
  566. mov ebx, fs:PcIdt ; Address of IDT
  567. push dword ptr [ebx+30h]
  568. push dword ptr [ebx+34h] ; Save Trap06 handler
  569. mov eax, offset TemporaryInt6
  570. mov word ptr [ebx+30h], ax ; Set LowWord
  571. shr eax, 16
  572. mov word ptr [ebx+36h], ax ; Set HighWord
  573. ;
  574. ; Attempt execution of Extract Bit String instruction. Execution on
  575. ; B0 or earlier with length (CL) = 0 will return 0 into the destination
  576. ; (CX in this case). Execution on B1 or later will fail either due to
  577. ; taking the invalid opcode trap, or if the opcode is valid, we don't
  578. ; expect CX will be zeroed by any new instruction supported by newer
  579. ; steppings. The dummy int 6 handler will clears the Carry Flag and
  580. ; returns execution to the appropriate label. If the instruction
  581. ; actually executes, CX will *probably* remain unchanged in any new
  582. ; stepping that uses the opcode for something else. The nops are meant
  583. ; to handle newer steppings with an unknown instruction length.
  584. ;
  585. xor eax,eax
  586. mov edx,eax
  587. mov ecx,0ff00h ; Extract length (CL) == 0, (CX) != 0
  588. b1c50: db 0fh, 0a6h, 0cah ; xbts cx,dx,ax,cl
  589. nop
  590. nop
  591. nop
  592. nop
  593. nop
  594. stc ; assume B0
  595. jecxz short b1c70 ; jmp if B0
  596. b1c60: clc
  597. b1c70: pop dword ptr [ebx+34h] ; restore old int 6 vector
  598. pop dword ptr [ebx+30h]
  599. pop ebx
  600. ret
  601. Check386B0 endp
  602. ;++
  603. ;
  604. ; BOOLEAN
  605. ; TemporaryInt6 (
  606. ; VOID
  607. ; )
  608. ;
  609. ; Routine Description:
  610. ;
  611. ; Temporary int 6 handler - assumes the cause of the exception was the
  612. ; attempted execution of an XTBS instruction.
  613. ;
  614. ; Arguments:
  615. ;
  616. ; None.
  617. ;
  618. ; Return Value:
  619. ;
  620. ; none.
  621. ;
  622. ;--
  623. TemporaryInt6 proc
  624. mov [esp].IretEip,offset b1c60 ; set IP to clc instruction
  625. iretd
  626. TemporaryInt6 endp
  627. ;++
  628. ;
  629. ; BOOLEAN
  630. ; Check386D1 (
  631. ; VOID
  632. ; )
  633. ;
  634. ; Routine Description:
  635. ;
  636. ; This routine checks for 386 D1 Stepping.
  637. ;
  638. ; It takes advantage of the fact that on pre-D1 386, if a REPeated
  639. ; MOVS instruction is executed when single-stepping is enabled,
  640. ; a single step trap is taken every TWO moves steps, but should
  641. ; occuu each move step.
  642. ;
  643. ; NOTE: This routine cannot distinguish between a D0 stepping and a D1
  644. ; stepping. If a need arises to make this distinction, this routine
  645. ; will need modification. D0 steppings will be recognized as D1.
  646. ;
  647. ; Arguments:
  648. ;
  649. ; None.
  650. ;
  651. ; Return Value:
  652. ;
  653. ; Carry Flag clear if D1 or later stepping
  654. ; Carry Flag set if B1 or prior
  655. ;
  656. ;--
  657. Check386D1 proc
  658. push ebx
  659. mov ebx, fs:PcIdt ; Address of IDT
  660. push dword ptr [ebx+08h]
  661. push dword ptr [ebx+0ch] ; Save Trap01 handler
  662. mov eax, offset TemporaryInt1
  663. mov word ptr [ebx+08h], ax ; Set LowWord
  664. shr eax, 16
  665. mov word ptr [ebx+0eh], ax ; Set HighWord
  666. ;
  667. ; Attempt execution of rep movsb instruction with the Trace Flag set.
  668. ; Execution on B1 or earlier with length (CX) > 1 will trace over two
  669. ; iterations before accepting the trace trap. Execution on D1 or later
  670. ; will accept the trace trap after a single iteration. The dummy int 1
  671. ; handler will return execution to the instruction following the movsb
  672. ; instruction. Examination of (CX) will reveal the stepping.
  673. ;
  674. sub esp,4 ; make room for target of movsb
  675. mov esi, offset TemporaryInt1 ; (ds:esi) -> some present data
  676. mov edi,esp
  677. mov ecx,2 ; 2 iterations
  678. pushfd
  679. or dword ptr [esp], EFLAGS_TF
  680. popfd ; cause a single step trap
  681. rep movsb
  682. d1c60: add esp,4 ; clean off stack
  683. pop dword ptr [ebx+0ch] ; restore old int 1 vector
  684. pop dword ptr [ebx+08h]
  685. stc ; assume B1
  686. jecxz short d1cx ; jmp if <= B1
  687. clc ; else clear carry to indicate >= D1
  688. d1cx:
  689. pop ebx
  690. ret
  691. Check386D1 endp
  692. ;++
  693. ;
  694. ; BOOLEAN
  695. ; TemporaryInt1 (
  696. ; VOID
  697. ; )
  698. ;
  699. ; Routine Description:
  700. ;
  701. ; Temporary int 1 handler - assumes the cause of the exception was
  702. ; trace trap at the above rep movs instruction.
  703. ;
  704. ; Arguments:
  705. ;
  706. ; (esp)->eip of trapped instruction
  707. ; cs of trapped instruction
  708. ; eflags of trapped instruction
  709. ;
  710. ;--
  711. TemporaryInt1 proc
  712. and [esp].IretEFlags,not EFLAGS_TF ; clear caller's Trace Flag
  713. mov [esp].IretEip,offset d1c60 ; set IP to next instruction
  714. iretd
  715. TemporaryInt1 endp
  716. ;++
  717. ;
  718. ; BOOLEAN
  719. ; MultiplyTest (
  720. ; VOID
  721. ; )
  722. ;
  723. ; Routine Description:
  724. ;
  725. ; This routine checks the 386 32-bit multiply instruction.
  726. ; The reason for this check is because some of the i386 fail to
  727. ; perform this instruction.
  728. ;
  729. ; Arguments:
  730. ;
  731. ; None.
  732. ;
  733. ; Return Value:
  734. ;
  735. ; Carry Flag clear on success
  736. ; Carry Flag set on failure
  737. ;
  738. ;--
  739. ;
  740. MultiplyTest proc
  741. xor cx,cx ; 64K times is a nice round number
  742. mlt00: push cx
  743. call Multiply ; does this chip's multiply work?
  744. pop cx
  745. jc short mltx ; if c, No, exit
  746. loop mlt00 ; if nc, YEs, loop to try again
  747. clc
  748. mltx:
  749. ret
  750. MultiplyTest endp
  751. ;++
  752. ;
  753. ; BOOLEAN
  754. ; Multiply (
  755. ; VOID
  756. ; )
  757. ;
  758. ; Routine Description:
  759. ;
  760. ; This routine performs 32-bit multiplication test which is known to
  761. ; fail on bad 386s.
  762. ;
  763. ; Note, the supplied pattern values must be used for consistent results.
  764. ;
  765. ; Arguments:
  766. ;
  767. ; None.
  768. ;
  769. ; Return Value:
  770. ;
  771. ; Carry Flag clear on success.
  772. ; Carry Flag set on failure.
  773. ;
  774. ;--
  775. Multiply proc
  776. mov ecx, MULTIPLIER
  777. mov eax, MULTIPLICAND
  778. mul ecx
  779. cmp edx, RESULT_HIGH ; Q: high order answer OK ?
  780. stc ; assume failure
  781. jnz short mlpx ; N: exit with error
  782. cmp eax, RESULT_LOW ; Q: low order answer OK ?
  783. stc ; assume failure
  784. jnz short mlpx ; N: exit with error
  785. clc ; indicate success
  786. mlpx:
  787. ret
  788. Multiply endp
  789. ;++
  790. ;
  791. ; BOOLEAN
  792. ; KiIsNpxPresent(
  793. ; VOID
  794. ; );
  795. ;
  796. ; Routine Description:
  797. ;
  798. ; This routine determines if there is any Numeric coprocessor
  799. ; present.
  800. ;
  801. ; Note that we do NOT determine its type (287, 387).
  802. ; This code is extracted from Intel book.
  803. ;
  804. ; Arguments:
  805. ;
  806. ; None.
  807. ;
  808. ; Return:
  809. ;
  810. ; TRUE - If NPX is present. Else a value of FALSE is returned.
  811. ; Sets CR0 NPX bits accordingly.
  812. ;
  813. ;--
  814. cPublicProc _KiIsNpxPresent,0
  815. push ebp ; Save caller's bp
  816. mov eax, cr0
  817. and eax, NOT (CR0_ET+CR0_MP+CR0_TS+CR0_EM)
  818. mov cr0, eax
  819. xor edx, edx
  820. .287
  821. fninit ; Initialize NPX
  822. mov ecx, 5A5A5A5Ah ; Put non-zero value
  823. push ecx ; into the memory we are going to use
  824. mov ebp, esp
  825. fnstsw word ptr [ebp] ; Retrieve status - must use non-wait
  826. cmp byte ptr [ebp], 0 ; All bits cleared by fninit?
  827. jne Inp10
  828. or eax, CR0_ET
  829. mov edx, 1
  830. cmp fs:PcPrcbData.PbCpuType, 3h
  831. jbe Inp10
  832. or eax, CR0_NE
  833. Inp10:
  834. or eax, CR0_EM+CR0_TS ; During Kernel Initialization set
  835. ; the EM bit
  836. mov cr0, eax
  837. pop eax ; clear scratch value
  838. pop ebp ; Restore caller's bp
  839. mov eax, edx
  840. stdRet _KiIsNpxPresent
  841. stdENDP _KiIsNpxPresent
  842. ;++
  843. ;
  844. ; VOID
  845. ; CPUID (
  846. ; ULONG InEax,
  847. ; PULONG OutEax,
  848. ; PULONG OutEbx,
  849. ; PULONG OutEcx,
  850. ; PULONG OutEdx
  851. ; );
  852. ;
  853. ; Routine Description:
  854. ;
  855. ; Executes the CPUID instruction and returns the registers from it
  856. ;
  857. ; Only available at INIT time
  858. ;
  859. ; Arguments:
  860. ;
  861. ; Return Value:
  862. ;
  863. ;--
  864. cPublicProc _CPUID,5
  865. push ebx
  866. push esi
  867. mov eax, [esp+12]
  868. cpuid
  869. mov esi, [esp+16] ; return EAX
  870. mov [esi], eax
  871. mov esi, [esp+20] ; return EBX
  872. mov [esi], ebx
  873. mov esi, [esp+24] ; return ECX
  874. mov [esi], ecx
  875. mov esi, [esp+28] ; return EDX
  876. mov [esi], edx
  877. pop esi
  878. pop ebx
  879. stdRET _CPUID
  880. stdENDP _CPUID
  881. ;++
  882. ;
  883. ; LONGLONG
  884. ; RDTSC (
  885. ; VOID
  886. ; );
  887. ;
  888. ; Routine Description:
  889. ;
  890. ; Arguments:
  891. ;
  892. ; Return Value:
  893. ;
  894. ;--
  895. cPublicProc _RDTSC
  896. rdtsc
  897. stdRET _RDTSC
  898. stdENDP _RDTSC
  899. INIT ENDS
  900. _TEXT SEGMENT DWORD PUBLIC 'CODE' ; Put IdleLoop in text section
  901. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  902. ;++
  903. ;
  904. ; ULONGLONG
  905. ; FASTCALL
  906. ; RDMSR (
  907. ; IN ULONG MsrRegister
  908. ; );
  909. ;
  910. ; Routine Description:
  911. ;
  912. ; Arguments:
  913. ;
  914. ; Return Value:
  915. ;
  916. ;--
  917. cPublicFastCall RDMSR, 1
  918. rdmsr
  919. fstRET RDMSR
  920. fstENDP RDMSR
  921. ;++
  922. ;
  923. ; VOID
  924. ; WRMSR (
  925. ; IN ULONG MsrRegister
  926. ; IN LONGLONG MsrValue
  927. ; );
  928. ;
  929. ; Routine Description:
  930. ;
  931. ; Arguments:
  932. ;
  933. ; Return Value:
  934. ;
  935. ;--
  936. cPublicProc _WRMSR, 3
  937. mov ecx, [esp+4]
  938. mov eax, [esp+8]
  939. mov edx, [esp+12]
  940. wrmsr
  941. stdRET _WRMSR
  942. stdENDP _WRMSR
  943. ;++
  944. ;
  945. ; VOID
  946. ; KeYieldProcessor (
  947. ; VOID
  948. ; );
  949. ;
  950. ; Routine Description:
  951. ;
  952. ; Yields a thread of the processor
  953. ;
  954. ; Arguments:
  955. ;
  956. ; Return Value:
  957. ;
  958. ;--
  959. cPublicProc _KeYieldProcessor
  960. YIELD
  961. stdRET _KeYieldProcessor
  962. stdENDP _KeYieldProcessor
  963. _TEXT ENDS
  964. END