summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halx86/i386/ixcmos.asm
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/nthals/halx86/i386/ixcmos.asm
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/nthals/halx86/i386/ixcmos.asm')
-rw-r--r--private/ntos/nthals/halx86/i386/ixcmos.asm1135
1 files changed, 1135 insertions, 0 deletions
diff --git a/private/ntos/nthals/halx86/i386/ixcmos.asm b/private/ntos/nthals/halx86/i386/ixcmos.asm
new file mode 100644
index 000000000..5cc391076
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixcmos.asm
@@ -0,0 +1,1135 @@
+ 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
+
+
+CMOS_STATUS_BUSY EQU 80H ; Time update in progress
+RTC_OFFSET_SECOND EQU 0 ; second field of RTC memory
+RTC_OFFSET_MINUTE EQU 2 ; minute field of RTC memory
+RTC_OFFSET_HOUR EQU 4 ; hour field of RTC memory
+RTC_OFFSET_DAY_OF_WEEK EQU 6 ; day-of-week field of RTC memory
+RTC_OFFSET_DATE_OF_MONTH EQU 7 ; date-of-month field of RTC memory
+RTC_OFFSET_MONTH EQU 8 ; month field of RTC memory
+RTC_OFFSET_YEAR EQU 9 ; year field of RTC memory
+RTC_OFFSET_CENTURY_MCA EQU 37h ; Century field of RTC memory for MCA
+RTC_OFFSET_CENTURY EQU 32h ; Century field of RTC memory
+RTC_OFFSET_CENTURY_DS EQU 148h ; Bank 1, 48. Century field for DS
+BANK1 EQU 100h
+
+;
+; BCD_TO_BIN
+;
+; Description: Convert BCD value to binary
+;
+; Parameter:
+; Input: (AL) = 2 digit BCD number to convert
+; Output: (AX) = Binary equivalent (all in AL)
+;
+; Return: None.
+;
+
+BCD_TO_BIN macro
+
+ xor ah,ah
+ rol ax,4
+ ror al,4
+ aad
+endm
+
+;
+; BIN_TO_BCD
+;
+; Description: Convert binary value to BCD.
+;
+; Parameter:
+; Input: (AL) = binary value to be converted.
+; Output: (AX) = BCD (all in AL)
+;
+; Return: None.
+;
+
+BIN_TO_BCD macro
+
+ aam
+ rol al, 4
+ ror ax, 4
+endm
+
+
+_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.
+;
+
+_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
+
+;++
+;
+; 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 short 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
+
+
+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
+
+ 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
+ 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
+
+ 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
+
+ mov word ptr [edx].TfMilliseconds, 0 ; do not support
+
+ 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
+ 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:
+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
+ 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
+
+
+_TEXT ends
+
+ end