SETUP equ 1 ;** ; ; Machine-specific detection code ; ;-- .386p include hal386.inc include callconv.inc _TEXT SEGMENT DWORD PUBLIC 'CODE' ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING ; ; Thunk functions. ; Equivalent Hal functions which various detection code may use ; ;++ ; ; CMOS space read functions. ; ;-- CMOSAddressPort equ 70H CMOSDataPort equ 71H CMOSExAddressLSBPort equ 74H CMOSExAddressMSBPort equ 75H CMOSExDataPort equ 76H ;++ ; ; VOID ; ReadCMOS( ; ULONG StartingOffset ; ULONG Count ; PUCHAR ReturnValuePtr ; ) ; ; Read CMOS starting at the given offset for the given number of ; bytes putting the bytes read into the buffer pointed to by the ; given address. ; ; Arguments: ; ; StartingOffset : where to start in CMOS ; ; Count : how many bytes to read ; ; ReturnValuePtr : where to put bytes read ; ; Returns: ; None. ; ;-- StartingOffset equ 2*4[ebp] Count equ 3*4[ebp] ReturnValuePtr equ 4*4[ebp] cPublicProc _ReadCMOS,3 push ebp mov ebp, esp push ebx ; caller's reg push edi ; caller's reg mov ebx, StartingOffset mov ecx, Count mov edi, ReturnValuePtr align dword NextByte: cmp bh, 0 jne ExCMOSRead mov al, bl out CMOSAddressPort, al in al, CMOSDataPort mov [edi], al add ebx, 1 add edi, 1 sub ecx, 1 jg NextByte pop edi ; restore caller's reg pop ebx ; restore caller's reg pop ebp stdRET _ReadCmos align dword ExCMOSRead: mov al, bl out CMOSExAddressLSBPort, al mov al, bh out CMOSExAddressMSBPort, al in al, CMOSExDataPort mov [edi], al add ebx, 1 add edi, 1 sub ecx, 1 jg ExCMOSRead pop edi ; restore caller's reg pop ebx ; restore caller's reg pop ebp stdRET _ReadCMOS stdENDP _ReadCMOS ; 486 C step CPU detection code. CR0_ET equ 10h CR0_TS equ 08H CR0_EM equ 04H CR0_MP equ 02H ; ; The following equates define the control bits of EFALGS register ; EFLAGS_AC equ 40000h EFLAGS_ID equ 200000h ; ; 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 ; ; Define the iret frame ; IretFrame struc IretEip dd 0 IretCs dd 0 IretEFlags dd 0 IretFrame ends ;++ ; ; BOOLEAN ; Detect486CStep ( ; IN PBOOLEAN Dummy ; ) ; ; Routine Description: ; ; Returns TRUE if the processor is a 486 C stepping. We detect the CPU ; in order to use a specific HAL. This HAL attempts to work around ; a 486 C stepping bug which the normal HAL tends to aggravate. ; cPublicProc _Detect486CStep,1 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_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 Not486C ; No, then this is a 386 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 Not486C ; Yes, then this >= 586 mov eax, cr0 and eax, NOT (CR0_ET+CR0_MP+CR0_TS+CR0_EM) mov cr0, eax call IsNpxPresent ; Check if cpu has coprocessor support? or ax, ax jz short Is486C ; it is actually 486sx, assume C step call Check486CStepping ; Check for <= C stepping jnc short Not486C ; if nc, it is NOT a C stepping Is486C: mov eax, 1 ; Return TRUE jmp short DetectCpuExit Not486C: xor eax, eax DetectCpuExit: popfd pop ebx mov cr0, ebx pop ebx pop esi pop edi stdRET _Detect486CStep stdENDP _Detect486CStep ;++ ; ; 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 ; ; 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 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 ; IsNpxPresent( ; VOID ; ); ; ; Routine Description: ; ; This routine determines if there is any Numeric coprocessor ; present. ; ; Arguments: ; ; None. ; ; Return: ; ; TRUE - If NPX is present. Else a value of FALSE is returned. ; ;-- public IsNpxPresent IsNpxPresent proc near push ebp ; Save caller's bp 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 mov edx, 1 Inp10: pop eax ; clear scratch value pop ebp ; Restore caller's bp mov eax, edx ret IsNpxPresent endp _TEXT ENDS END