windows-nt/Source/XPSP1/NT/base/hals/halx86/i386/ixcmos.asm
2020-09-26 16:20:57 +08:00

1121 lines
26 KiB
NASM

title "Cmos Access Routines"
;++
;
; Module Name:
;
; ixcmos.asm
;
; Abstract:
;
; Procedures necessary to access CMOS/ECMOS information.
;
; Author:
;
; David Risner (o-ncrdr) 20 Apr 1992
;
; Revision History:
;
; Landy Wang (corollary!landy) 04 Dec 1992
; - Move much code from ixclock.asm to here so different HALs
; can reuse the common functionality.
;
;--
.386p
.xlist
include hal386.inc
include callconv.inc ; calling convention macros
include mac386.inc
include i386\ix8259.inc
include i386\ixcmos.inc
.list
EXTRNP _DbgBreakPoint,0,IMPORT
extrn _HalpSystemHardwareLock:DWORD
extrn _HalpBusType:DWORD
extrn _HalpSerialLen:BYTE
extrn _HalpSerialNumber:BYTE
_DATA SEGMENT DWORD PUBLIC 'DATA'
;
; HalpRebootNow is a reboot vector. Set in an MP system, to
; cause any processors which may be looping in HalpAcquireCmosSinLock
; to transfer control to the vector in HalpRebootNow
;
public _HalpRebootNow
_HalpRebootNow dd 0
;
; Holds the value of the eflags register before a cmos spinlock is
; acquired (used in HalpAcquire/ReleaseCmosSpinLock().
;
_HalpHardwareLockFlags dd 0
;
; Holds the offset to CMOS Century information.
;
public _HalpCmosCenturyOffset
_HalpCmosCenturyOffset dd 0
_DATA ends
subttl "HalpGetCmosData"
;++
;
; CMOS space read and write functions.
;
;--
CmosAddressPort equ 70H
CmosDataPort equ 71H
ECmosAddressLsbPort equ 74H
ECmosAddressMsbPort equ 75H
ECmosDataPort equ 76H
INIT SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
ifndef ACPI_HAL
;++
;
; VOID
; HalpInitializeCmos(
; VOID
; )
;
; This routine reads CMOS and initializes globals required for
; CMOS access, such as the location of the century byte.
;
;--
cPublicProc _HalpInitializeCmos,0
push ebx
push esi
push edi
;
; Assume default
;
mov eax, RTC_OFFSET_CENTURY
mov _HalpCmosCenturyOffset, eax
cmp _HalpBusType, MACHINE_TYPE_ISA
jne icm40
;
; If control comes here, this is ISA machine. We need to check if this is
; IBM PS/1 or Pc/ValuePoint machine and use RTC_CENTURY_OFFSET_MCA to get
; Century byte from CMOS.
;
;
; Check if the CMOS 2e and 2f contains memory checksum. On PS/1 machine
; the check should fail.
;
icm20: mov ecx, 2dh ; from 10h to 2dh
mov eax, 0 ; clear ax
mov edx, 0
icm30: mov al, cl
CMOS_READ
add edx, eax
dec ecx
cmp ecx, 0fh
jne short icm30
mov eax, 2eh
CMOS_READ
mov ah, al
mov al, 2fh
CMOS_READ
cmp eax, edx
je short icm50 ; NOT PS/1
mov eax, RTC_OFFSET_CENTURY_MCA
mov _HalpCmosCenturyOffset, eax
jmp icm90
icm40: cmp _HalpBusType, MACHINE_TYPE_MCA
jne short icm50
;
; See if this is a P700 MCA machine
;
in al, 07fh ; get PD700 ID byte
and al, 0F0h ; Mask high nibble
cmp al, 0A0h ; Is the ID Ax?
jz short icm50
cmp al, 090h ; Or an 9X?
jz short icm50 ; Yes, it's a 700
mov eax, RTC_OFFSET_CENTURY_MCA
mov _HalpCmosCenturyOffset, eax
icm50:
if 0
- Selecting BANK1 causes some devices to mess up their month value
- For now, I'm removing this code until this problem can be solved
;
; See if this is a Dallas Semiconductor DS17285 or later
; Switch to BANK 1
;
mov al, 0Ah
CMOS_READ
and al, 7fh ; Don't write UIP
mov ah, al
mov esi, eax ; save it for restore
or ah, 10h ; Set DV0 = 1
mov al, 0Ah ; Write register A
CMOS_WRITE
;
; Check for RTC serial # with matching crc
; (al) = current byte
; (ah) = scratch register
; (bl) = current crc
; (bh) = zero, non-zero, flag
; (ecx) = cmos offset
; (edx) = used by cmos_read macro
; (esi) = saved register 0A
;
mov ecx, 40h
xor ebx, ebx
icm60: mov al, cl
CMOS_READ
mov byte ptr _HalpSerialNumber+2+-40h[ecx], al
or bh, al ; or to check for all zeros
mov ch, 8 ; Bits per byte
icm65: mov ah, bl ; ah = crc
xor ah, al ; xor LSb
shr bl, 1 ; shift crc
shr ah, 1 ; mov LSb to carry
sbb ah, ah ; if carry set 1's else 0's
and ah, (118h shr 1) ; crc polynomial
xor bl, ah ; apply it
shr al, 1 ; next bit
dec ch ;
jnz short icm65 ; if ch non-zero, loop
inc cl ; next cmos location
cmp cl, 48h ; at end?
jne short icm60 ; no, loop
;
; (bh) = zero, non-zero flag
; (bl) = crc
;
mov eax, RTC_OFFSET_CENTURY_DS ; Read century byte
CMOS_READ
BCD_TO_BIN
movzx ecx, ax ; save it
;
; Switch back to BANK 0
;
mov eax, esi
mov al, 0Ah
CMOS_WRITE
;
; Check for valid DS data
;
cmp bh, 0 ; Was data all zeros?
je short icm90
cmp bl, 0 ; was CRC valid?
jnz short icm90
cmp ecx, 19 ; Is century before 19?
jb short icm90
cmp ecx, 20 ; Is century after 20?
ja short icm90
;
; Setup for DS century byte
;
mov byte ptr _HalpSerialNumber+0, 'D'
mov byte ptr _HalpSerialNumber+1, 'S'
mov _HalpSerialLen, 10
mov eax, RTC_OFFSET_CENTURY_DS
mov _HalpCmosCenturyOffset, eax
endif
icm90: pop edi
pop esi
pop ebx
stdRET _HalpInitializeCmos
stdENDP _HalpInitializeCmos
endif
INIT ends
_TEXT SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
;++
;
; ULONG
; HalpGetCmosData(
; IN ULONG SourceLocation
; IN ULONG SourceAddress
; IN ULONG ReturnBuffer
; IN PUCHAR ByteCount
; )
;
; This routine reads the requested number of bytes from CMOS/ECMOS and
; stores the data read into the supplied buffer in system memory. If
; the requested data amount exceeds the allowable extent of the source
; location, the return data is truncated.
;
; Arguments:
;
; SourceLocation : where data is to be read from CMOS or ECMOS
; 0 - CMOS, 1 - ECMOS
;
; SourceAddress : address in CMOS/ECMOS where data is to be read from
;
; ReturnBuffer : address in system memory for return data
;
; ByteCount : number of bytes to be read
;
; Returns:
;
; Number of byte actually read.
;
;--
SourceLocation equ 2*4[ebp]
SourceAddress equ 3*4[ebp]
ReturnBuffer equ 4*4[ebp]
ByteCount equ 5*4[ebp]
cPublicProc _HalpGetCmosData ,4
push ebp
mov ebp, esp
push ebx
push edi
;
; NOTE: The spinlock is needed even in the UP case, because
; the resource is also used in an interrupt handler (profiler).
; If we own the spinlock in this routine, and we service
; the profiler interrupt (which will wait for the spinlock forever),
; then we have a hosed system.
;
stdCall _HalpAcquireCmosSpinLock
xor edx, edx ; initialize return data length
mov ecx, ByteCount
or ecx, ecx ; validate requested byte count
jz HalpGetCmosDataExit ; if no work to do, exit
mov edx, SourceAddress
mov edi, ReturnBuffer
mov eax, SourceLocation ; cmos or extended cmos?
cmp eax, 1
je ECmosReadByte
cmp eax, 0
jne HalpGetCmosDataExit
CmosReadByte:
cmp edx, 0ffH ; validate cmos source address
ja HalpGetCmosDataExit ; if out of range, exit
mov al, dl
out CmosAddressPort, al
in al, CmosDataPort
mov [edi], al
inc edx
inc edi
dec ecx
jnz CmosReadByte
jmp SHORT HalpGetCmosDataExit
ECmosReadByte:
cmp edx,0ffffH ; validate ecmos source address
ja HalpGetCmosDataExit ; if out of range, exit
mov al, dl
out ECmosAddressLsbPort, al
mov al, dh
out ECmosAddressMsbPort, al
in al, ECmosDataPort
mov [edi], al
inc edx
inc edi
dec ecx
jnz ECmosReadByte
HalpGetCmosDataExit:
stdCall _HalpReleaseCmosSpinLock
mov eax, edx ; return bytes read
sub eax, SourceAddress ; subtract the initial offset
pop edi
pop ebx
pop ebp
stdRET _HalpGetCmosData
stdENDP _HalpGetCmosData
;++
;
; VOID
; HalpSetCmosData(
; IN ULONG SourceLocation
; IN ULONG SourceAddress
; IN ULONG ReturnBuffer
; IN PUCHAR ByteCount
; )
;
; This routine writes the requested number of bytes to CMOS/ECMOS
;
; Arguments:
;
; SourceLocation : where data is to be written to CMOS or ECMOS
; 0 - CMOS, 1 - ECMOS
;
; SourceAddress : address in CMOS/ECMOS where data is to write to.
;
; ReturnBuffer : address in system memory for data to write
;
; ByteCount : number of bytes to be write
;
; Returns:
;
; Number of byte actually written.
;
;--
cPublicProc _HalpSetCmosData ,4
push ebp
mov ebp, esp
push ebx
push edi
stdCall _HalpAcquireCmosSpinLock
xor edx, edx ; initialize return data length
mov ecx, ByteCount
or ecx, ecx ; validate requested byte count
jz HalpSetCmosDataExit ; if no work to do, exit
mov edx, SourceAddress
mov edi, ReturnBuffer
mov eax, SourceLocation ; cmos or extended cmos?
cmp eax, 1
je ECmosWriteByte
cmp eax, 0
jne HalpSetCmosDataExit
CmosWriteByte:
cmp edx, 0ffH ; validate cmos source address
ja HalpSetCmosDataExit ; if out of range, exit
mov al, dl
out CmosAddressPort, al
mov al, [edi]
out CmosDataPort, al
inc edx
inc edi
dec ecx
jnz CmosWriteByte
jmp SHORT HalpSetCmosDataExit
ECmosWriteByte:
cmp edx,0ffffH ; validate ecmos source address
ja HalpSetCmosDataExit ; if out of range, exit
mov al, dl
out ECmosAddressLsbPort, al
mov al, dh
out ECmosAddressMsbPort, al
mov al, [edi]
out ECmosDataPort, al
inc edx
inc edi
dec ecx
jnz ECmosWriteByte
HalpSetCmosDataExit:
stdCall _HalpReleaseCmosSpinLock
mov eax, edx ; return bytes written
sub eax, SourceAddress ; subtract the initial offset
pop edi
pop ebx
pop ebp
stdRET _HalpSetCmosData
stdENDP _HalpSetCmosData
page ,132
subttl "Read System Time"
;++
;
; VOID
; HalpReadCmosTime (
; PTIME_FIELDS TimeFields
; )
;
; Routine Description:
;
; This routine reads current time from CMOS memory and stores it
; in the TIME_FIELDS structure passed in by caller.
;
; Arguments:
;
; TimeFields - A pointer to the TIME_FIELDS structure.
;
; Return Value:
;
; None.
;
;--
;
; Parameters:
;
KrctPTimeFields equ [esp+4]
cPublicProc _HalpReadCmosTime ,1
if DBG
krctwait0:
mov ecx, 100
krctwait:
push ecx
else
krctwait:
endif
stdCall _HalpAcquireCmosSpinLock
mov ecx, 100
align 4
krct00: mov al, 0Ah ; Specify register A
CMOS_READ ; (al) = CMOS register A
test al, CMOS_STATUS_BUSY ; Is time update in progress?
jz short krct10 ; if z, no, go read CMOS time
loop short krct00 ; otherwise, try again.
;
; CMOS is still busy. Try again ...
;
stdCall _HalpReleaseCmosSpinLock
if DBG
pop ecx
loop short krctwait
stdCall _DbgBreakPoint
jmp short krctwait0
else
jmp short krctwait
endif
align 4
if DBG
krct10:
pop ecx
else
krct10:
endif
mov edx, KrctPTimeFields ; (edx)-> TIME_FIELDS structure
xor eax, eax ; (eax) = 0
;
; The RTC is only accurate within one second. So
; add a half a second so that we are closer, on average,
; to the right answer.
;
mov word ptr [edx].TfMilliseconds, 500 ; add a half a second
mov al, RTC_OFFSET_SECOND
CMOS_READ ; (al) = second in BCD form
BCD_TO_BIN ; (ax) = second
mov [edx].TfSecond, ax ; set second in TIME_FIELDS
mov al, RTC_OFFSET_MINUTE
CMOS_READ ; (al) = minute in BCD form
BCD_TO_BIN ; (ax) = Minute
mov [edx].TfMinute, ax ; set minute in TIME_FIELDS
mov al, RTC_OFFSET_HOUR
CMOS_READ ; (al) = hour in BCD form
BCD_TO_BIN ; (ax) = Hour
mov [edx].TfHour, ax ; set hour in TIME_FIELDS
mov al, RTC_OFFSET_DAY_OF_WEEK
CMOS_READ ; (al) = day-of-week in BCD form
BCD_TO_BIN ; (ax) = day-of-week
mov [edx].TfWeekday, ax ; set Weekday in TIME_FIELDS
mov al, RTC_OFFSET_DATE_OF_MONTH
CMOS_READ ; (al) = date-of-month in BCD form
BCD_TO_BIN ; (ax) = date_of_month
mov [edx].TfDay, ax ; set day in TIME_FIELDS
mov al, RTC_OFFSET_MONTH
CMOS_READ ; (al) = month in BCD form
BCD_TO_BIN ; (ax) = month
mov [edx].TfMonth, ax ; set month in TIME_FIELDS
mov al, RTC_OFFSET_YEAR
CMOS_READ ; (al) = year in BCD form
BCD_TO_BIN ; (ax) = year
push eax ; save year in stack
push edx ; preserve edx
call _HalpGetCmosCenturyByte ; (al)= century byte in BCD form
BCD_TO_BIN ; (ax) = century
pop edx
mov ah, 100
mul ah ; (ax) = century * 100
pop ecx ; (cx) = year
add ax, cx ; (ax)= year
cmp ax, 1900 ; Is year > 1900
jb short krct40
cmp ax, 1920 ; and < 1920
jae short krct40
add ax, 100 ; Compensate for century field
krct40:
mov [edx].TfYear, ax ; set year in TIME_FIELDS
stdCall _HalpReleaseCmosSpinLock
stdRET _HalpReadCmosTime
stdENDP _HalpReadCmosTime
page ,132
subttl "Write System Time"
;++
;
; VOID
; HalpWriteCmosTime (
; PTIME_FIELDS TimeFields
; )
;
; Routine Description:
;
; This routine writes current time from TIME_FILEDS structure
; to CMOS memory.
;
; Arguments:
;
; TimeFields - A pointer to the TIME_FIELDS structure.
;
; Return Value:
;
; None.
;
;--
;
; Parameters:
;
KrctPTimeFields equ [esp+4]
cPublicProc _HalpWriteCmosTime ,1
if DBG
kwctwait0:
mov ecx, 100
kwctwait:
push ecx
else
kwctwait:
endif
stdCall _HalpAcquireCmosSpinLock
mov ecx, 100
align 4
kwct00: mov al, 0Ah ; Specify register A
CMOS_READ ; (al) = CMOS register A
test al, CMOS_STATUS_BUSY ; Is time update in progress?
jz short kwct10 ; if z, no, go write CMOS time
loop short kwct00 ; otherwise, try again.
;
; CMOS is still busy. Try again ...
;
stdCall _HalpReleaseCmosSpinLock
if DBG
pop ecx
loop short kwctwait
stdCall _DbgBreakPoint
jmp short kwctwait0
else
jmp short kwctwait
endif
align 4
if DBG
kwct10:
pop ecx
else
kwct10:
endif
mov edx, KrctPTimeFields ; (edx)-> TIME_FIELDS structure
mov al, [edx].TfSecond ; Read second in TIME_FIELDS
BIN_TO_BCD
mov ah, al
mov al, RTC_OFFSET_SECOND
CMOS_WRITE
mov al, [edx].TfMinute ; Read minute in TIME_FIELDS
BIN_TO_BCD
mov ah, al
mov al, RTC_OFFSET_MINUTE
CMOS_WRITE
mov al, [edx].TfHour ; Read Hour in TIME_FIELDS
BIN_TO_BCD
mov ah, al
mov al, RTC_OFFSET_HOUR
CMOS_WRITE
mov al, [edx].TfWeekDay ; Read WeekDay in TIME_FIELDS
BIN_TO_BCD
mov ah, al
mov al, RTC_OFFSET_DAY_OF_WEEK
CMOS_WRITE
mov al, [edx].TfDay ; Read day in TIME_FIELDS
BIN_TO_BCD
mov ah, al
mov al, RTC_OFFSET_DATE_OF_MONTH
CMOS_WRITE
mov al, [edx].TfMonth ; Read month in TIME_FIELDS
BIN_TO_BCD
mov ah, al
mov al, RTC_OFFSET_MONTH
CMOS_WRITE
mov ax, [edx].TfYear ; Read Year in TIME_FIELDS
cmp ax, 9999
jbe short kwct15
mov ax, 9999
align 4
kwct15:
mov cl, 100
div cl ; [ax]/[cl]->al=quo, ah=rem
push eax
BIN_TO_BCD
push eax
call _HalpSetCmosCenturyByte
pop eax
mov al, ah ; [al] = Year
BIN_TO_BCD
mov ah, al ; [ah] = year in BCD
mov al, RTC_OFFSET_YEAR
CMOS_WRITE
stdCall _HalpReleaseCmosSpinLock
stdRET _HalpWriteCmosTime
stdENDP _HalpWriteCmosTime
;++
;
; Routine Description:
;
; Acquires a spinlock to access the cmos chip. The cmos chip is
; accessed at different irql levels, so to be safe, we 'cli'.
; We could replace that to raise irql to PROFILE_LEVEL, but that's
; a lot of code.
;
; Arguments:
;
; None
;
; Return Value:
;
; Interrupt is disabled.
; Irql level not affected.
; Flags saved in _HalpHardwareLockFlags.
;--
cPublicProc _HalpAcquireCmosSpinLock ,0
public _HalpAcquireSystemHardwareSpinLock@0
_HalpAcquireSystemHardwareSpinLock@0:
push eax
Arsl10: pushfd
cli
lea eax, _HalpSystemHardwareLock
ACQUIRE_SPINLOCK eax, Arsl20
pop _HalpHardwareLockFlags ; save flags for release S.L.
pop eax
stdRET _HalpAcquireCmosSpinLock
Arsl20: popfd
Arsl30:
YIELD
ifndef NT_UP
cmp _HalpRebootNow, 0
jnz short Arsl50
endif
TEST_SPINLOCK eax, <short Arsl30>
jmp short ARsl10
Arsl50:
ifndef NT_UP
mov eax, _HalpRebootNow
call eax
int 3 ; should not return
endif
stdENDP _HalpAcquireCmosSpinLock
;++
;
; Routine Description:
;
; Release spinlock, and restore flags to the state it was before
; acquiring the spinlock.
;
; Arguments:
;
; None
;
; Return Value:
;
; Interrupts restored to their state before acquiring spinlock.
; Irql level not affected.
;
;--
cPublicProc _HalpReleaseCmosSpinLock ,0
public _HalpReleaseSystemHardwareSpinLock@0
_HalpReleaseSystemHardwareSpinLock@0:
push eax
;
; restore eflags as it was before acquiring spinlock. Put it on
; stack before releasing spinlock (so other cpus cannot overwrite
; it with their own eflags).
;
push _HalpHardwareLockFlags ; old eflags on stack.
lea eax, _HalpSystemHardwareLock
RELEASE_SPINLOCK eax
popfd ; restore eflags.
pop eax
stdRET _HalpReleaseCmosSpinLock
stdENDP _HalpReleaseCmosSpinLock
;++
;
; UCHAR
; HalpGetCmosCenturyByte (
; VOID
; )
;
; Routine Description:
;
; This routine gets Century byte from CMOS.
;
; Arguments:
;
; None
;
; Return Value:
;
; (al) = Century byte in BCD form.
;
;--
cPublicProc _HalpGetCmosCenturyByte, 0
mov eax, _HalpCmosCenturyOffset
if DBG
;
; Make sure the HalpCmosCenturyOffset is initialized
;
cmp eax, 0
jne short @f
int 3
@@:
endif
test eax, BANK1
jnz short rcb50
CMOS_READ ; (al) = century in BCD form
stdRET _HalpGetCmosCenturyByte
rcb50: mov edx, eax
mov al, 0Ah
CMOS_READ
mov dh, al ; save it for restore
or al, 10h ; Set DV0 = 1
mov ah, al
mov al, 0Ah ; Write register A
CMOS_WRITE
mov al, dl ; century offset
CMOS_READ
mov dl, al ; save it
mov ah, dh ; Restore DV0
mov al, 0Ah ; Write register A
CMOS_WRITE
mov al, dl
stdRET _HalpGetCmosCenturyByte
stdENDP _HalpGetCmosCenturyByte
;++
;
; VOID
; HalpSetCmosCenturyByte (
; UCHAR Century
; )
;
; Routine Description:
;
; This routine sets Century byte in CMOS.
;
; Arguments:
;
; Century - Supplies the value for CMOS century byte
;
; Return Value:
;
; None.
;
;--
cPublicProc _HalpSetCmosCenturyByte, 1
mov eax, _HalpCmosCenturyOffset
if DBG
;
; Make sure the HalpCmosCenturyOffset is initialized
;
cmp eax, 0
jne short @f
int 3
@@:
endif
test eax, BANK1
jnz short scb50
mov ah, [esp+4] ; (ah) = Century in BCD form
CMOS_WRITE
stdRET _HalpSetCmosCenturyByte
scb50: mov edx, eax
mov al, 0Ah
CMOS_READ
mov dh, al ; save it for restore
or al, 10h ; Set DV0 = 1
mov ah, al
mov al, 0Ah ; Write register A
CMOS_WRITE
mov ah, [esp+4] ; (ah) = Century in BCD form
mov al, dl ; century offset
CMOS_WRITE
mov ah, dh ; Restore DV0
mov al, 0Ah ; Write register A
CMOS_WRITE
stdRET _HalpSetCmosCenturyByte
stdENDP _HalpSetCmosCenturyByte
;++
;
; VOID
; HalpCpuID (
; 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 _HalpCpuID,5
push ebx
push esi
mov eax, [esp+12]
db 0fh, 0a2h ; 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 _HalpCpuID
stdENDP _HalpCpuID
;++
;
; VOID
; HalpFlushTLB (
; VOID
; );
;
; Routine Description:
;
; Flush the current TLB.
;
; Arguments:
;
; Return Value:
;
;--
cPublicProc _HalpFlushTLB, 0
.586p
pushfd
push ebx
push esi
cli
mov esi, cr3
mov ecx, PCR[PcPrcb]
cmp byte ptr [ecx].PbCpuID, 0
jz short ftb50
mov eax, 1 ; Get feature bits
cpuid ; (note "cpuid" between CR3 reload fixes
; P6 B step errata #11)
test edx, 2000h ; see if 'G' bit is supported
jz short ftb50
mov ecx, cr4 ; 'G' bit is supported, due global flush
mov edx, ecx ; Save orginal cr4
and ecx, not CR4_PGE ; Make sure global bit is disabled
mov cr4, ecx
mov cr3, esi ; flush TLB
mov cr4, edx ; restore cr4
jmp short ftp99
ftb50: mov cr3, esi
ftp99: pop esi
pop ebx
popfd
stdRET _HalpFlushTLB
.486p
stdENDP _HalpFlushTLB
;++
;
; VOID
; HalpYieldProcessor (
; VOID
; );
;
; Routine Description:
;
; Arguments:
;
; None
;
; Return Value:
;
; None
;
;--
cPublicProc _HalpYieldProcessor
YIELD
stdRET _HalpYieldProcessor
stdENDP _HalpYieldProcessor
_TEXT ends
end