371 lines
9.2 KiB
NASM
371 lines
9.2 KiB
NASM
SETUP equ 1
|
||
|
||
;**
|
||
;
|
||
; Machine-specific detection code
|
||
;
|
||
;--
|
||
|
||
.386p
|
||
|
||
include hal386.inc
|
||
include callconv.inc
|
||
|
||
;
|
||
; Include SystemPro detection code
|
||
;
|
||
SYSTEMPRO equ 1
|
||
include halsp\i386\spdetect.asm
|
||
|
||
|
||
_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
|