windows-nt/Source/XPSP1/NT/base/ntos/ke/i386/cpu.asm
2020-09-26 16:20:57 +08:00

1119 lines
27 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

title "Processor type and stepping detection"
;++
;
; Copyright (c) 1989 Microsoft Corporation
;
; Module Name:
;
; cpu.asm
;
; Abstract:
;
; This module implements the assembley code necessary to determine
; cpu type and stepping information.
;
; Author:
;
; Shie-Lin Tzong (shielint) 28-Oct-1991.
; Some of the code is extracted from Cruiser (mainly,
; the code to determine 386 stepping.)
;
; Environment:
;
; 80x86
;
; Revision History:
;
;--
.xlist
include i386\cpu.inc
include ks386.inc
include callconv.inc
include mac386.inc
.list
;
; constant for i386 32-bit multiplication test
;
MULTIPLIER equ 00000081h
MULTIPLICAND equ 0417a000h
RESULT_HIGH equ 00000002h
RESULT_LOW equ 0fe7a000h
;
; Constants for Floating Point test
;
REALLONG_LOW equ 00000000
REALLONG_HIGH equ 3FE00000h
PSEUDO_DENORMAL_LOW equ 00000000h
PSEUDO_DENORMAL_MID equ 80000000h
PSEUDO_DENORMAL_HIGH equ 0000h
.586p
INIT SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
;++
;
; USHORT
; KiSetProcessorType (
; VOID
; )
;
; Routine Description:
;
; This function determines type of processor (80486, 80386),
; and it's corrisponding stepping. The results are saved in
; the current processor's PRCB.
;
; Arguments:
;
; None.
;
; Return Value:
;
; Prcb->CpuType
; 3, 4, 5, ... 3 = 386, 4 = 486, etc..
;
; Prcb->CpuStep is encoded as follows:
; lower byte as stepping #
; upper byte as stepping letter (0=a, 1=b, 2=c, ...)
;
; (ax) = x86h or 0 if unrecongnized processor.
;
;--
cPublicProc _KiSetProcessorType,0
mov byte ptr fs:PcPrcbData.PbCpuID, 0
push edi
push esi
push ebx ; Save C registers
mov eax, cr0
push eax
pushfd ; save Cr0 & flags
pop ebx ; Get flags into eax
push ebx ; Save original flags
mov ecx, ebx
xor ecx, EFLAGS_ID ; flip ID bit
push ecx
popfd ; load it into flags
pushfd ; re-save flags
pop ecx ; get flags into eax
cmp ebx, ecx ; did bit stay flipped?
jne short cpu_has_cpuid ; Yes, go use CPUID
cpuid_unsupported:
pop ebx ; Get flags into eax
push ebx ; Save original flags
mov ecx, ebx
xor ecx, EFLAGS_AC ; flip AC bit
push ecx
popfd ; load it into flags
pushfd ; re-save flags
pop ecx ; get flags into eax
cmp ebx, ecx ; did bit stay flipped?
je short cpu_is_386 ; No, then this is a 386
cpu_is_486:
mov byte ptr fs:PcPrcbData.PbCpuType, 4h ; Save CPU Type
call Get486Stepping
jmp cpu_save_stepping
cpu_is_386:
mov byte ptr fs:PcPrcbData.PbCpuType, 3h ; Save CPU Type
call Get386Stepping
jmp cpu_save_stepping
cpu_has_cpuid:
or ebx, EFLAGS_ID
push ebx
popfd ; Make sure ID bit is set
mov ecx, fs:PcIdt ; Address of IDT
push dword ptr [ecx+30h] ; Save Trap06 handler incase
push dword ptr [ecx+34h] ; the CPUID instruction faults
mov eax, offset CpuIdTrap6Handler
mov word ptr [ecx+30h], ax ; Set LowWord
shr eax, 16
mov word ptr [ecx+36h], ax ; Set HighWord
mov eax, 0 ; argument to CPUID
cpuid ; Uses eax, ebx, ecx, edx
mov ecx, fs:PcIdt ; Address of IDT
pop dword ptr [ecx+34h] ; restore trap6 handler
pop dword ptr [ecx+30h]
cmp eax, 1 ; make sure level 1 is supported
jc short cpuid_unsupported ; no, then punt
; Get the family and stepping (cpuid fn=1). If processor family
; is less than 0xf, the format returned is as below:
; 3 2 1
; 10987654321098765432109876543210
; --------------------------------
; ppffffmmmmssss
; where
; pp = Processor Type
; ffff = Family
; mmmm = Model
; ssss = Stepping
;
; This is transformed and saved in the PRCB as
;
; PRCB->CpuStep = 0000mmmm0000ssss v v
; ->CpuID = 00000001 | | v
; ->CpuType = 0000ffff | | | v
; | | | |
; ie the dword that contains all this looks like 0M0S010F
;
; If the processor family is 0xf or greater, the format returned is:
; 3 2 1
; 10987654321098765432109876543210
; --------------------------------
; RRRRFFFFFFFFMMMMRRppffffmmmmssss
; where
; pp = Processor Type
; ffff = Family
; mmmm = Model
; ssss = Stepping
; MMMM = Extended Model
; FFFFFFFF = Extended Family
; RRRR, RR = Reserved
; This is transformed and saved in the PRCB as
;
; PRCB->CpuStep = EEEEEEEE0000ssss v v
; ->CpuID = 00000001 | | v
; ->CpuType = XXXXXXXX | | | v
; | | | |
; ie the dword that contains all this looks like EE0S01XX
;
; where
; EEEEEEEE = ((MMMM) << 4)8 bits + (mmmm)zero extended 8 bits
; XXXXXXXX = (FFFFFFFF) + (ffff)zero extended 8 bits
; The value for Extended Family cannot go beyond F0H inorder to support
; a maximum value of FFH for the final Family value(XXXXXXXX).
; The maximum value of Extended Model is FH and the maximum value for
; the final Model value(EEEEEEEE) is FFH
mov eax, 1 ; get the family and stepping
cpuid
mov ebx, eax
mov edx, eax
and edx, 0F00h ; get the Family
cmp edx, 0F00h ; (edx) = 00000000000000000000ffff00000000
jne short cpu_not_extended ; Family less than F
mov ah, al ; (eax) = RRRRFFFFFFFFMMMMmmmmssssmmmmssss
shr eax, 4 ; (eax) = 0000RRRRFFFFFFFFMMMMmmmmssssmmmm
mov al, bl ; (eax) = 0000RRRRFFFFFFFFMMMMmmmmmmmmssss
and eax, 0FF0Fh ; (eax) = 0000000000000000EEEEEEEE0000ssss
and ebx, 0FF00000h ; (ebx) = 0000FFFFFFFF00000000000000000000
shr ebx, 12 ; (ebx) = 0000000000000000FFFFFFFF00000000
add ebx, edx ; (ebx) = 0000000000000000XXXXXXXX00000000
jmp short cpu_save_signature
cpu_not_extended:
and eax, 0F0h ; (eax) = Model
shl eax, 4
mov al, bl
and eax, 0F0Fh ; (eax) = Model[15:8] | Step[7:0]
and ebx, 0F00h ; (bh) = CpuType
cpu_save_signature:
mov byte ptr fs:PcPrcbData.PbCpuID, 1 ; Has ID support
mov byte ptr fs:PcPrcbData.PbCpuType, bh ; Save CPU Type
cpu_save_stepping:
mov word ptr fs:PcPrcbData.PbCpuStep, ax ; Save CPU Stepping
popfd ; Restore flags
pop eax
mov cr0, eax
pop ebx
pop esi
pop edi
stdRET _KiSetProcessorType
cpuid_trap:
mov ecx, fs:PcIdt ; Address of IDT
pop dword ptr [ecx+34h] ; restore trap6 handler
pop dword ptr [ecx+30h]
jmp cpuid_unsupported ; Go get processor information
stdENDP _KiSetProcessorType
;++
;
; BOOLEAN
; CpuIdTrap6 (
; VOID
; )
;
; Routine Description:
;
; Temporary int 6 handler - assumes the cause of the exception was the
; attempted CPUID instruction.
;
; Arguments:
;
; None.
;
; Return Value:
;
; none.
;
;--
CpuIdTrap6Handler proc
mov [esp].IretEip,offset cpuid_trap
iretd
CpuIdTrap6Handler endp
;++
;
; USHORT
; Get386Stepping (
; VOID
; )
;
; Routine Description:
;
; This function determines cpu stepping for i386 CPU stepping.
;
; Arguments:
;
; None.
;
; Return Value:
;
; [ax] - Cpu stepping.
; 0 = A, 1 = B, 2 = C, ...
;
;--
public Get386Stepping
Get386Stepping proc
call MultiplyTest ; Perform mutiplication test
jnc short G3s00 ; if nc, muttest is ok
mov ax, 0
ret
G3s00:
call Check386B0 ; Check for B0 stepping
jnc short G3s05 ; if nc, it's B1/later
mov ax, 100h ; It is B0/earlier stepping
ret
G3s05:
call Check386D1 ; Check for D1 stepping
jc short G3s10 ; if c, it is NOT D1
mov ax, 301h ; It is D1/later stepping
ret
G3s10:
mov ax, 101h ; assume it is B1 stepping
ret
Get386Stepping endp
;++
;
; USHORT
; Get486Stepping (
; VOID
; )
;
; Routine Description:
;
; This function determines cpu stepping for i486 CPU type.
;
; Arguments:
;
; None.
;
; Return Value:
;
; [ax] - Cpu stepping. For example, [ax] = D0h for D0 stepping.
;
;--
public Get486Stepping
Get486Stepping proc
call Check486AStepping ; Check for A stepping
jnc short G4s00 ; if nc, it is NOT A stepping
mov ax, 0 ; set to A stepping
ret
G4s00: call Check486BStepping ; Check for B stepping
jnc short G4s10 ; if nc, it is NOT a B stepping
mov ax, 100h ; set to B stepping
ret
;
; Before we test for 486 C/D step, we need to make sure NPX is present.
; Because the test uses FP instruction to do the detection.
;
G4s10:
call _KiIsNpxPresent ; Check if cpu has coprocessor support?
or ax, ax
jz short G4s15 ; it is actually 486sx
call Check486CStepping ; Check for C stepping
jnc short G4s20 ; if nc, it is NOT a C stepping
G4s15:
mov ax, 200h ; set to C stepping
ret
G4s20: mov ax, 300h ; Set to D stepping
ret
Get486Stepping endp
;++
;
; BOOLEAN
; Check486AStepping (
; VOID
; )
;
; Routine Description:
;
; This routine checks for 486 A Stepping.
;
; It takes advantage of the fact that on the A-step of the i486
; processor, the ET bit in CR0 could be set or cleared by software,
; but was not used by the hardware. On B or C -step, ET bit in CR0
; is now hardwired to a "1" to force usage of the 386 math coprocessor
; protocol.
;
; Arguments:
;
; None.
;
; Return Value:
;
; Carry Flag clear if B or later stepping.
; Carry Flag set if A or earlier stepping.
;
;--
public Check486AStepping
Check486AStepping proc near
mov eax, cr0 ; reset ET bit in cr0
and eax, NOT CR0_ET
mov cr0, eax
mov eax, cr0 ; get cr0 back
test eax, CR0_ET ; if ET bit still set?
jnz short cas10 ; if nz, yes, still set, it's NOT A step
stc
ret
cas10: clc
ret
Check486AStepping endp
;++
;
; BOOLEAN
; Check486BStepping (
; VOID
; )
;
; Routine Description:
;
; This routine checks for 486 B Stepping.
;
; On the i486 processor, the "mov to/from DR4/5" instructions were
; aliased to "mov to/from DR6/7" instructions. However, the i486
; B or earlier steps generate an Invalid opcode exception when DR4/5
; are used with "mov to/from special register" instruction.
;
; Arguments:
;
; None.
;
; Return Value:
;
; Carry Flag clear if C or later stepping.
; Carry Flag set if B stepping.
;
;--
public Check486BStepping
Check486BStepping proc
push ebx
mov ebx, fs:PcIdt ; Address of IDT
push dword ptr [ebx+30h]
push dword ptr [ebx+34h] ; Save Trap06 handler
mov eax, offset Temporary486Int6
mov word ptr [ebx+30h], ax ; Set LowWord
shr eax, 16
mov word ptr [ebx+36h], ax ; Set HighWord
c4bs50: db 0fh, 21h, 0e0h ; mov eax, DR4
nop
nop
nop
nop
nop
clc ; it is C step
jmp short c4bs70
c4bs60: stc ; it's B step
c4bs70: pop dword ptr [ebx+34h] ; restore old int 6 vector
pop dword ptr [ebx+30h]
pop ebx
ret
ret
Check486BStepping endp
;++
;
; BOOLEAN
; Temporary486Int6 (
; VOID
; )
;
; Routine Description:
;
; Temporary int 6 handler - assumes the cause of the exception was the
; attempted execution of an mov to/from DR4/5 instruction.
;
; Arguments:
;
; None.
;
; Return Value:
;
; none.
;
;--
Temporary486Int6 proc
mov [esp].IretEIp,offset c4bs60 ; set EIP to stc instruction
iretd
Temporary486Int6 endp
;++
;
; BOOLEAN
; Check486CStepping (
; VOID
; )
;
; Routine Description:
;
; This routine checks for 486 C Stepping.
;
; This routine takes advantage of the fact that FSCALE produces
; wrong result with Denormal or Pseudo-denormal operand on 486
; C and earlier steps.
;
; If the value contained in ST(1), second location in the floating
; point stack, is between 1 and 11, and the value in ST, top of the
; floating point stack, is either a pseudo-denormal number or a
; denormal number with the underflow exception unmasked, the FSCALE
; instruction produces an incorrect result.
;
; Arguments:
;
; None.
;
; Return Value:
;
; Carry Flag clear if D or later stepping.
; Carry Flag set if C stepping.
;
;--
FpControl equ [ebp - 2]
RealLongSt1 equ [ebp - 10]
PseudoDenormal equ [ebp - 20]
FscaleResult equ [ebp - 30]
public Check486CStepping
Check486CStepping proc
push ebp
mov ebp, esp
sub esp, 30 ; Allocate space for temp real variables
mov eax, cr0 ; Don't trap while doing math
and eax, NOT (CR0_ET+CR0_MP+CR0_TS+CR0_EM)
mov cr0, eax
;
; Initialize the local FP variables to predefined values.
; RealLongSt1 = 1.0 * (2 ** -1) = 0.5 in normalized double precision FP form
; PseudoDenormal = a unsupported format by IEEE.
; Sign bit = 0
; Exponent = 000000000000000B
; Significand = 100000...0B
; FscaleResult = The result of FSCALE instruction. Depending on 486 step,
; the value will be different:
; Under C and earlier steps, 486 returns the original value
; in ST as the result. The correct returned value should be
; original significand and an exponent of 0...01.
;
mov dword ptr RealLongSt1, REALLONG_LOW
mov dword ptr RealLongSt1 + 4, REALLONG_HIGH
mov dword ptr PseudoDenormal, PSEUDO_DENORMAL_LOW
mov dword ptr PseudoDenormal + 4, PSEUDO_DENORMAL_MID
mov word ptr PseudoDenormal + 8, PSEUDO_DENORMAL_HIGH
.387
fnstcw FpControl ; Get FP control word
fwait
or word ptr FpControl, 0FFh ; Mask all the FP exceptions
fldcw FpControl ; Set FP control
fld qword ptr RealLongSt1 ; 0 < ST(1) = RealLongSt1 < 1
fld tbyte ptr PseudoDenormal; Denormalized operand. Note, i486
; won't report denormal exception
; on 'FLD' instruction.
; ST(0) = Extended Denormalized operand
fscale ; try to trigger 486Cx errata
fstp tbyte ptr FscaleResult ; Store ST(0) in FscaleResult
cmp word ptr FscaleResult + 8, PSEUDO_DENORMAL_HIGH
; Is Exponent changed?
jz short c4ds00 ; if z, no, it is C step
clc
jmp short c4ds10
c4ds00: stc
c4ds10: mov esp, ebp
pop ebp
ret
Check486CStepping endp
;++
;
; BOOLEAN
; Check386B0 (
; VOID
; )
;
; Routine Description:
;
; This routine checks for 386 B0 or earlier stepping.
;
; It takes advantage of the fact that the bit INSERT and
; EXTRACT instructions that existed in B0 and earlier versions of the
; 386 were removed in the B1 stepping. When executed on the B1, INSERT
; and EXTRACT cause an int 6 (invalid opcode) exception. This routine
; can therefore discriminate between B1/later 386s and B0/earlier 386s.
; It is intended to be used in sequence with other checks to determine
; processor stepping by exercising specific bugs found in specific
; steppings of the 386.
;
; Arguments:
;
; None.
;
; Return Value:
;
; Carry Flag clear if B1 or later stepping
; Carry Flag set if B0 or prior
;
;--
Check386B0 proc
push ebx
mov ebx, fs:PcIdt ; Address of IDT
push dword ptr [ebx+30h]
push dword ptr [ebx+34h] ; Save Trap06 handler
mov eax, offset TemporaryInt6
mov word ptr [ebx+30h], ax ; Set LowWord
shr eax, 16
mov word ptr [ebx+36h], ax ; Set HighWord
;
; Attempt execution of Extract Bit String instruction. Execution on
; B0 or earlier with length (CL) = 0 will return 0 into the destination
; (CX in this case). Execution on B1 or later will fail either due to
; taking the invalid opcode trap, or if the opcode is valid, we don't
; expect CX will be zeroed by any new instruction supported by newer
; steppings. The dummy int 6 handler will clears the Carry Flag and
; returns execution to the appropriate label. If the instruction
; actually executes, CX will *probably* remain unchanged in any new
; stepping that uses the opcode for something else. The nops are meant
; to handle newer steppings with an unknown instruction length.
;
xor eax,eax
mov edx,eax
mov ecx,0ff00h ; Extract length (CL) == 0, (CX) != 0
b1c50: db 0fh, 0a6h, 0cah ; xbts cx,dx,ax,cl
nop
nop
nop
nop
nop
stc ; assume B0
jecxz short b1c70 ; jmp if B0
b1c60: clc
b1c70: pop dword ptr [ebx+34h] ; restore old int 6 vector
pop dword ptr [ebx+30h]
pop ebx
ret
Check386B0 endp
;++
;
; BOOLEAN
; TemporaryInt6 (
; VOID
; )
;
; Routine Description:
;
; Temporary int 6 handler - assumes the cause of the exception was the
; attempted execution of an XTBS instruction.
;
; Arguments:
;
; None.
;
; Return Value:
;
; none.
;
;--
TemporaryInt6 proc
mov [esp].IretEip,offset b1c60 ; set IP to clc instruction
iretd
TemporaryInt6 endp
;++
;
; BOOLEAN
; Check386D1 (
; VOID
; )
;
; Routine Description:
;
; This routine checks for 386 D1 Stepping.
;
; It takes advantage of the fact that on pre-D1 386, if a REPeated
; MOVS instruction is executed when single-stepping is enabled,
; a single step trap is taken every TWO moves steps, but should
; occuu each move step.
;
; NOTE: This routine cannot distinguish between a D0 stepping and a D1
; stepping. If a need arises to make this distinction, this routine
; will need modification. D0 steppings will be recognized as D1.
;
; Arguments:
;
; None.
;
; Return Value:
;
; Carry Flag clear if D1 or later stepping
; Carry Flag set if B1 or prior
;
;--
Check386D1 proc
push ebx
mov ebx, fs:PcIdt ; Address of IDT
push dword ptr [ebx+08h]
push dword ptr [ebx+0ch] ; Save Trap01 handler
mov eax, offset TemporaryInt1
mov word ptr [ebx+08h], ax ; Set LowWord
shr eax, 16
mov word ptr [ebx+0eh], ax ; Set HighWord
;
; Attempt execution of rep movsb instruction with the Trace Flag set.
; Execution on B1 or earlier with length (CX) > 1 will trace over two
; iterations before accepting the trace trap. Execution on D1 or later
; will accept the trace trap after a single iteration. The dummy int 1
; handler will return execution to the instruction following the movsb
; instruction. Examination of (CX) will reveal the stepping.
;
sub esp,4 ; make room for target of movsb
mov esi, offset TemporaryInt1 ; (ds:esi) -> some present data
mov edi,esp
mov ecx,2 ; 2 iterations
pushfd
or dword ptr [esp], EFLAGS_TF
popfd ; cause a single step trap
rep movsb
d1c60: add esp,4 ; clean off stack
pop dword ptr [ebx+0ch] ; restore old int 1 vector
pop dword ptr [ebx+08h]
stc ; assume B1
jecxz short d1cx ; jmp if <= B1
clc ; else clear carry to indicate >= D1
d1cx:
pop ebx
ret
Check386D1 endp
;++
;
; BOOLEAN
; TemporaryInt1 (
; VOID
; )
;
; Routine Description:
;
; Temporary int 1 handler - assumes the cause of the exception was
; trace trap at the above rep movs instruction.
;
; Arguments:
;
; (esp)->eip of trapped instruction
; cs of trapped instruction
; eflags of trapped instruction
;
;--
TemporaryInt1 proc
and [esp].IretEFlags,not EFLAGS_TF ; clear caller's Trace Flag
mov [esp].IretEip,offset d1c60 ; set IP to next instruction
iretd
TemporaryInt1 endp
;++
;
; BOOLEAN
; MultiplyTest (
; VOID
; )
;
; Routine Description:
;
; This routine checks the 386 32-bit multiply instruction.
; The reason for this check is because some of the i386 fail to
; perform this instruction.
;
; Arguments:
;
; None.
;
; Return Value:
;
; Carry Flag clear on success
; Carry Flag set on failure
;
;--
;
MultiplyTest proc
xor cx,cx ; 64K times is a nice round number
mlt00: push cx
call Multiply ; does this chip's multiply work?
pop cx
jc short mltx ; if c, No, exit
loop mlt00 ; if nc, YEs, loop to try again
clc
mltx:
ret
MultiplyTest endp
;++
;
; BOOLEAN
; Multiply (
; VOID
; )
;
; Routine Description:
;
; This routine performs 32-bit multiplication test which is known to
; fail on bad 386s.
;
; Note, the supplied pattern values must be used for consistent results.
;
; Arguments:
;
; None.
;
; Return Value:
;
; Carry Flag clear on success.
; Carry Flag set on failure.
;
;--
Multiply proc
mov ecx, MULTIPLIER
mov eax, MULTIPLICAND
mul ecx
cmp edx, RESULT_HIGH ; Q: high order answer OK ?
stc ; assume failure
jnz short mlpx ; N: exit with error
cmp eax, RESULT_LOW ; Q: low order answer OK ?
stc ; assume failure
jnz short mlpx ; N: exit with error
clc ; indicate success
mlpx:
ret
Multiply endp
;++
;
; BOOLEAN
; KiIsNpxPresent(
; VOID
; );
;
; Routine Description:
;
; This routine determines if there is any Numeric coprocessor
; present.
;
; Note that we do NOT determine its type (287, 387).
; This code is extracted from Intel book.
;
; Arguments:
;
; None.
;
; Return:
;
; TRUE - If NPX is present. Else a value of FALSE is returned.
; Sets CR0 NPX bits accordingly.
;
;--
cPublicProc _KiIsNpxPresent,0
push ebp ; Save caller's bp
mov eax, cr0
and eax, NOT (CR0_ET+CR0_MP+CR0_TS+CR0_EM)
mov cr0, eax
xor edx, edx
.287
fninit ; Initialize NPX
mov ecx, 5A5A5A5Ah ; Put non-zero value
push ecx ; into the memory we are going to use
mov ebp, esp
fnstsw word ptr [ebp] ; Retrieve status - must use non-wait
cmp byte ptr [ebp], 0 ; All bits cleared by fninit?
jne Inp10
or eax, CR0_ET
mov edx, 1
cmp fs:PcPrcbData.PbCpuType, 3h
jbe Inp10
or eax, CR0_NE
Inp10:
or eax, CR0_EM+CR0_TS ; During Kernel Initialization set
; the EM bit
mov cr0, eax
pop eax ; clear scratch value
pop ebp ; Restore caller's bp
mov eax, edx
stdRet _KiIsNpxPresent
stdENDP _KiIsNpxPresent
;++
;
; VOID
; CPUID (
; ULONG InEax,
; PULONG OutEax,
; PULONG OutEbx,
; PULONG OutEcx,
; PULONG OutEdx
; );
;
; Routine Description:
;
; Executes the CPUID instruction and returns the registers from it
;
; Only available at INIT time
;
; Arguments:
;
; Return Value:
;
;--
cPublicProc _CPUID,5
push ebx
push esi
mov eax, [esp+12]
cpuid
mov esi, [esp+16] ; return EAX
mov [esi], eax
mov esi, [esp+20] ; return EBX
mov [esi], ebx
mov esi, [esp+24] ; return ECX
mov [esi], ecx
mov esi, [esp+28] ; return EDX
mov [esi], edx
pop esi
pop ebx
stdRET _CPUID
stdENDP _CPUID
;++
;
; LONGLONG
; RDTSC (
; VOID
; );
;
; Routine Description:
;
; Arguments:
;
; Return Value:
;
;--
cPublicProc _RDTSC
rdtsc
stdRET _RDTSC
stdENDP _RDTSC
INIT ENDS
_TEXT SEGMENT DWORD PUBLIC 'CODE' ; Put IdleLoop in text section
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
;++
;
; ULONGLONG
; FASTCALL
; RDMSR (
; IN ULONG MsrRegister
; );
;
; Routine Description:
;
; Arguments:
;
; Return Value:
;
;--
cPublicFastCall RDMSR, 1
rdmsr
fstRET RDMSR
fstENDP RDMSR
;++
;
; VOID
; WRMSR (
; IN ULONG MsrRegister
; IN LONGLONG MsrValue
; );
;
; Routine Description:
;
; Arguments:
;
; Return Value:
;
;--
cPublicProc _WRMSR, 3
mov ecx, [esp+4]
mov eax, [esp+8]
mov edx, [esp+12]
wrmsr
stdRET _WRMSR
stdENDP _WRMSR
;++
;
; VOID
; KeYieldProcessor (
; VOID
; );
;
; Routine Description:
;
; Yields a thread of the processor
;
; Arguments:
;
; Return Value:
;
;--
cPublicProc _KeYieldProcessor
YIELD
stdRET _KeYieldProcessor
stdENDP _KeYieldProcessor
_TEXT ENDS
END