|
|
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
|