windows-nt/Source/XPSP1/NT/base/boot/lib/i386/detmach.asm

371 lines
9.2 KiB
NASM
Raw Normal View History

2020-09-26 03:20:57 -05:00
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