You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
973 lines
17 KiB
973 lines
17 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ixcmos.c
|
|
|
|
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.
|
|
|
|
Forrest Foltz (forrestf) 24-Oct-2000
|
|
Ported ixcmos.asm to ixcmos.c
|
|
|
|
--*/
|
|
|
|
#include "halcmn.h"
|
|
|
|
ULONG HalpHardwareLockFlags;
|
|
|
|
//
|
|
// Module-specific types
|
|
//
|
|
|
|
typedef UCHAR (*READ_CMOS_CHAR)(ULONG Address);
|
|
typedef VOID (*WRITE_CMOS_CHAR)(ULONG Address, UCHAR Data);
|
|
|
|
typedef struct _CMOS_BUS_PARAMETERS {
|
|
ULONG MaximumAddress;
|
|
READ_CMOS_CHAR ReadFunction;
|
|
WRITE_CMOS_CHAR WriteFunction;
|
|
} CMOS_BUS_PARAMETERS, *PCMOS_BUS_PARAMETERS;
|
|
|
|
//
|
|
// External data
|
|
//
|
|
|
|
extern KSPIN_LOCK HalpSystemHardwareLock;
|
|
|
|
//
|
|
// Local prototypes
|
|
//
|
|
|
|
UCHAR
|
|
HalpCmosReadByte(
|
|
ULONG Address
|
|
);
|
|
|
|
VOID
|
|
HalpCmosWriteByte(
|
|
ULONG Address,
|
|
UCHAR Data
|
|
);
|
|
|
|
UCHAR
|
|
HalpECmosReadByte(
|
|
ULONG Address
|
|
);
|
|
|
|
VOID
|
|
HalpECmosWriteByte(
|
|
ULONG Address,
|
|
UCHAR Data
|
|
);
|
|
|
|
UCHAR
|
|
HalpGetCmosCenturyByte (
|
|
VOID
|
|
);
|
|
|
|
ULONG
|
|
HalpGetSetCmosData (
|
|
IN ULONG SourceLocation,
|
|
IN ULONG SourceAddress,
|
|
IN PVOID ReturnBuffer,
|
|
IN ULONG ByteCount,
|
|
IN BOOLEAN Write
|
|
);
|
|
|
|
VOID
|
|
HalpSetCmosCenturyByte (
|
|
UCHAR Century
|
|
);
|
|
|
|
//
|
|
// Local data
|
|
//
|
|
|
|
//
|
|
// Describes each of the CMOS types
|
|
//
|
|
|
|
CMOS_BUS_PARAMETERS HalpCmosBusParameterTable[] = {
|
|
{ 0xFF, HalpCmosReadByte, HalpCmosWriteByte },
|
|
{ 0xFFFF, HalpECmosReadByte, HalpECmosWriteByte }
|
|
};
|
|
|
|
//
|
|
// Contains the offset to the CMOS century information
|
|
//
|
|
|
|
ULONG HalpCmosCenturyOffset;
|
|
|
|
//
|
|
// HalpRebootNow is a reboot vector. Set in an MP system to cause any
|
|
// processors that might be looping in HalpAcquireCmosSpinLock to transfer
|
|
// control to the vector in HalpRebootNow.
|
|
//
|
|
|
|
VOID (*HalpRebootNow)(VOID);
|
|
|
|
ULONG
|
|
HalpGetCmosData (
|
|
IN ULONG SourceLocation,
|
|
IN ULONG SourceAddress,
|
|
IN PVOID ReturnBuffer,
|
|
IN ULONG ByteCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
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 transferred
|
|
|
|
ReturnBuffer - address in system memory for data to transfer
|
|
|
|
ByteCount - number of bytes to be read
|
|
|
|
Returns:
|
|
|
|
Number of byte actually read.
|
|
|
|
--*/
|
|
|
|
{
|
|
return HalpGetSetCmosData(SourceLocation,
|
|
SourceAddress,
|
|
ReturnBuffer,
|
|
ByteCount,
|
|
FALSE);
|
|
}
|
|
|
|
ULONG
|
|
HalpSetCmosData (
|
|
IN ULONG SourceLocation,
|
|
IN ULONG SourceAddress,
|
|
IN PVOID ReturnBuffer,
|
|
IN ULONG ByteCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes the requested number of bytes to CMOS/ECMOS.
|
|
|
|
Arguments:
|
|
|
|
SourceLocation - where data is to be written from CMOS or ECMOS
|
|
0 - CMOS, 1 - ECMOS
|
|
|
|
SourceAddress - address in CMOS/ECMOS where data is to be transferred
|
|
|
|
ReturnBuffer - address in system memory for data to transfer
|
|
|
|
ByteCount - number of bytes to be written
|
|
|
|
Returns:
|
|
|
|
Number of byte actually read.
|
|
|
|
--*/
|
|
|
|
{
|
|
return HalpGetSetCmosData(SourceLocation,
|
|
SourceAddress,
|
|
ReturnBuffer,
|
|
ByteCount,
|
|
TRUE);
|
|
}
|
|
|
|
ULONG
|
|
HalpGetSetCmosData (
|
|
IN ULONG SourceLocation,
|
|
IN ULONG RangeStart,
|
|
IN PVOID Buffer,
|
|
IN ULONG ByteCount,
|
|
IN BOOLEAN Write
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
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
|
|
|
|
RangeStart - address in CMOS/ECMOS where data is to be transferred
|
|
|
|
Buffer - address in system memory for data to transfer
|
|
|
|
ByteCount - number of bytes to be transferred
|
|
|
|
Write - Indicates whether the operation is a read or a write
|
|
|
|
Returns:
|
|
|
|
Number of byte actually transferred
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG address;
|
|
PCHAR buffer;
|
|
ULONG last;
|
|
PCMOS_BUS_PARAMETERS cmosParameters;
|
|
|
|
//
|
|
// Validate the "bus type" and get a pointer to the parameters
|
|
// for the corresponding CMOS "bus".
|
|
//
|
|
|
|
if (SourceLocation != 0 && SourceLocation != 1) {
|
|
return 0;
|
|
}
|
|
|
|
cmosParameters = &HalpCmosBusParameterTable[SourceLocation];
|
|
|
|
//
|
|
// Limit the range of bytes to that which the cmos bus can accomodate.
|
|
//
|
|
|
|
address = RangeStart;
|
|
buffer = Buffer;
|
|
|
|
last = address + ByteCount - 1;
|
|
if (last > cmosParameters->MaximumAddress) {
|
|
last = cmosParameters->MaximumAddress;
|
|
}
|
|
|
|
//
|
|
// Take the cmos spin lock, perform the transfer, and release the lock.
|
|
//
|
|
|
|
HalpAcquireCmosSpinLock();
|
|
|
|
while (address <= last) {
|
|
if (Write == FALSE) {
|
|
*buffer = cmosParameters->ReadFunction(address);
|
|
} else {
|
|
cmosParameters->WriteFunction(address,*buffer);
|
|
}
|
|
|
|
address += 1;
|
|
buffer += 1;
|
|
}
|
|
HalpReleaseCmosSpinLock();
|
|
|
|
//
|
|
// Calculate and return the number of bytes trasferred.
|
|
//
|
|
|
|
return last - RangeStart;
|
|
}
|
|
|
|
|
|
UCHAR
|
|
HalpCmosReadByte(
|
|
ULONG Address
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads a single byte from cmos.
|
|
|
|
Arguments:
|
|
|
|
Address - The CMOS address from which to retrieve the byte.
|
|
|
|
Returns:
|
|
|
|
The byte that was read.
|
|
|
|
--*/
|
|
|
|
{
|
|
return CMOS_READ((UCHAR)Address);
|
|
}
|
|
|
|
VOID
|
|
HalpCmosWriteByte(
|
|
ULONG Address,
|
|
UCHAR Data
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes a single byte to cmos.
|
|
|
|
Arguments:
|
|
|
|
Address - The CMOS address at which to write the byte
|
|
|
|
Data - The byte to write
|
|
|
|
Returns:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
|
|
{
|
|
CMOS_WRITE((UCHAR)Address,Data);
|
|
}
|
|
|
|
UCHAR
|
|
HalpECmosReadByte(
|
|
ULONG Address
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads a single byte from extended cmos (ECMOS).
|
|
|
|
Arguments:
|
|
|
|
Address - The CMOS address from which to retrieve the byte.
|
|
|
|
Returns:
|
|
|
|
The byte that was read.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR data;
|
|
|
|
WRITE_PORT_USHORT_PAIR (ECMOS_ADDRESS_PORT_LSB,
|
|
ECMOS_ADDRESS_PORT_MSB,
|
|
(USHORT)Address);
|
|
IO_DELAY();
|
|
|
|
data = READ_PORT_UCHAR(ECMOS_DATA_PORT);
|
|
IO_DELAY();
|
|
|
|
return data;
|
|
}
|
|
|
|
VOID
|
|
HalpECmosWriteByte(
|
|
ULONG Address,
|
|
UCHAR Data
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes a single byte to extended cmos (ECMOS).
|
|
|
|
Arguments:
|
|
|
|
Address - The CMOS address at which to write the byte
|
|
|
|
Data - The byte to write
|
|
|
|
Returns:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
|
|
{
|
|
WRITE_PORT_USHORT_PAIR (ECMOS_ADDRESS_PORT_LSB,
|
|
ECMOS_ADDRESS_PORT_MSB,
|
|
(USHORT)Address);
|
|
IO_DELAY();
|
|
|
|
WRITE_PORT_UCHAR(ECMOS_DATA_PORT,Data);
|
|
IO_DELAY();
|
|
}
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
USHORT year;
|
|
|
|
HalpAcquireCmosSpinLockAndWait();
|
|
|
|
//
|
|
// The RTC is only accurate to within one second. So add a
|
|
// half a second so that we are closer, on average, to the right
|
|
// answer.
|
|
//
|
|
|
|
TimeFields->Milliseconds = 500;
|
|
TimeFields->Second = CMOS_READ_BCD(RTC_OFFSET_SECOND);
|
|
TimeFields->Minute = CMOS_READ_BCD(RTC_OFFSET_MINUTE);
|
|
TimeFields->Hour = CMOS_READ_BCD(RTC_OFFSET_HOUR);
|
|
TimeFields->Weekday = CMOS_READ_BCD(RTC_OFFSET_DAY_OF_WEEK);
|
|
TimeFields->Day = CMOS_READ_BCD(RTC_OFFSET_DATE_OF_MONTH);
|
|
TimeFields->Month = CMOS_READ_BCD(RTC_OFFSET_MONTH);
|
|
|
|
year = BCD_TO_BIN(HalpGetCmosCenturyByte());
|
|
year = year * 100 + CMOS_READ_BCD(RTC_OFFSET_YEAR);
|
|
|
|
if (year >= 1900 && year < 1920) {
|
|
|
|
//
|
|
// Compensate for the century field
|
|
//
|
|
|
|
year += 100;
|
|
}
|
|
|
|
TimeFields->Year = year;
|
|
|
|
HalpReleaseCmosSpinLock();
|
|
}
|
|
|
|
VOID
|
|
HalpWriteCmosTime (
|
|
PTIME_FIELDS TimeFields
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes current time from TIME_FIELDS structure
|
|
to CMOS memory.
|
|
|
|
Arguments:
|
|
|
|
TimeFields - A pointer to the TIME_FIELDS structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG year;
|
|
|
|
HalpAcquireCmosSpinLockAndWait();
|
|
|
|
CMOS_WRITE_BCD(RTC_OFFSET_SECOND,(UCHAR)TimeFields->Second);
|
|
CMOS_WRITE_BCD(RTC_OFFSET_MINUTE,(UCHAR)TimeFields->Minute);
|
|
CMOS_WRITE_BCD(RTC_OFFSET_HOUR,(UCHAR)TimeFields->Hour);
|
|
CMOS_WRITE_BCD(RTC_OFFSET_DAY_OF_WEEK,(UCHAR)TimeFields->Weekday);
|
|
CMOS_WRITE_BCD(RTC_OFFSET_DATE_OF_MONTH,(UCHAR)TimeFields->Day);
|
|
CMOS_WRITE_BCD(RTC_OFFSET_MONTH,(UCHAR)TimeFields->Month);
|
|
|
|
year = TimeFields->Year;
|
|
if (year > 9999) {
|
|
year = 9999;
|
|
}
|
|
|
|
HalpSetCmosCenturyByte(BIN_TO_BCD((UCHAR)(year / 100)));
|
|
CMOS_WRITE_BCD(RTC_OFFSET_YEAR,(UCHAR)(year % 100));
|
|
|
|
HalpReleaseCmosSpinLock();
|
|
}
|
|
|
|
VOID
|
|
HalpAcquireCmosSpinLockAndWait (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine acquires the CMOS spinlock, then waits for the CMOS
|
|
BUSY flag to be clear.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG count;
|
|
ULONG value;
|
|
|
|
//
|
|
// Acquire the cmos spinlock and wait until it is not busy. While
|
|
// waiting, periodically release and re-acquire the spinlock.
|
|
//
|
|
|
|
HalpAcquireCmosSpinLock();
|
|
count = 0;
|
|
while (TRUE) {
|
|
|
|
value = CMOS_READ(CMOS_STATUS_A);
|
|
if ((value & CMOS_STATUS_BUSY) == 0) {
|
|
return;
|
|
}
|
|
|
|
count += 1;
|
|
if (count == 100) {
|
|
|
|
count = 0;
|
|
HalpReleaseCmosSpinLock();
|
|
HalpAcquireCmosSpinLock();
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
HalpReleaseCmosSpinLock (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine acquires the spin lock used to protect access to various
|
|
pieces of hardware.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG flags;
|
|
|
|
flags = HalpHardwareLockFlags;
|
|
#if !defined(NT_UP)
|
|
KeReleaseSpinLockFromDpcLevel(&HalpSystemHardwareLock);
|
|
#endif
|
|
HalpRestoreInterrupts(flags);
|
|
}
|
|
|
|
VOID
|
|
HalpAcquireCmosSpinLock (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine acquires the spin lock used to protect access to various
|
|
pieces of hardware.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN acquired;
|
|
ULONG flags;
|
|
KIRQL oldIrql;
|
|
|
|
#if defined(NT_UP)
|
|
HalpHardwareLockFlags = HalpDisableInterrupts();
|
|
#else
|
|
while (TRUE) {
|
|
|
|
flags = HalpDisableInterrupts();
|
|
acquired = KeTryToAcquireSpinLockAtDpcLevel(&HalpSystemHardwareLock);
|
|
if (acquired != FALSE) {
|
|
break;
|
|
}
|
|
HalpRestoreInterrupts(flags);
|
|
|
|
while (KeTestSpinLock(&HalpSystemHardwareLock) == FALSE) {
|
|
if (HalpRebootNow != NULL) {
|
|
HalpRebootNow();
|
|
}
|
|
PAUSE_PROCESSOR;
|
|
}
|
|
}
|
|
|
|
HalpHardwareLockFlags = flags;
|
|
#endif
|
|
}
|
|
|
|
VOID
|
|
HalpAcquireSystemHardwareSpinLock (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine acquires the spin lock used to protect access to various
|
|
pieces of hardware. It is a synonym of HalpAcquireCmosSpinLock().
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
|
|
{
|
|
HalpAcquireCmosSpinLock();
|
|
}
|
|
|
|
VOID
|
|
HalpReleaseSystemHardwareSpinLock (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine releases the spin lock used to protect access to various
|
|
pieces of hardware. It is a synonym of HalpReleaseCmosSpinLock().
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
|
|
{
|
|
HalpReleaseCmosSpinLock();
|
|
}
|
|
|
|
UCHAR
|
|
HalpGetCmosCenturyByte (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine retrieves the century byte from the CMOS.
|
|
|
|
N.B. The cmos spinlock must be acquired before calling this function.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
The century byte.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR value;
|
|
UCHAR oldStatus;
|
|
UCHAR centuryByte;
|
|
|
|
//
|
|
// Make sure the century offset is initialized
|
|
//
|
|
|
|
ASSERT(HalpCmosCenturyOffset != 0);
|
|
|
|
if ((HalpCmosCenturyOffset & CMOS_BANK_1) != 0) {
|
|
|
|
//
|
|
// Perform a bank 1 read
|
|
//
|
|
|
|
oldStatus = CMOS_READ(CMOS_STATUS_A);
|
|
value = oldStatus | CMOS_STATUS_BANK1;
|
|
CMOS_WRITE(CMOS_STATUS_A,value);
|
|
centuryByte = CMOS_READ((UCHAR)HalpCmosCenturyOffset);
|
|
CMOS_WRITE(CMOS_STATUS_A,oldStatus);
|
|
|
|
} else {
|
|
centuryByte = CMOS_READ((UCHAR)HalpCmosCenturyOffset);
|
|
}
|
|
|
|
return centuryByte;
|
|
}
|
|
|
|
VOID
|
|
HalpSetCmosCenturyByte (
|
|
UCHAR Century
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the century byte in the CMOS.
|
|
|
|
N.B. The cmos spinlock must be acquired before calling this function.
|
|
|
|
Arguments:
|
|
|
|
Century - The century byte to set
|
|
|
|
Returns:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR value;
|
|
UCHAR oldStatus;
|
|
|
|
//
|
|
// Make sure the century offset is initialized
|
|
//
|
|
|
|
ASSERT(HalpCmosCenturyOffset != 0);
|
|
|
|
if ((HalpCmosCenturyOffset & CMOS_BANK_1) != 0) {
|
|
|
|
//
|
|
// Perform a bank 1 write
|
|
//
|
|
|
|
oldStatus = CMOS_READ(CMOS_STATUS_A);
|
|
value = oldStatus | CMOS_STATUS_BANK1;
|
|
CMOS_WRITE(CMOS_STATUS_A,value);
|
|
CMOS_WRITE((UCHAR)HalpCmosCenturyOffset,Century);
|
|
CMOS_WRITE(CMOS_STATUS_A,oldStatus);
|
|
|
|
} else {
|
|
CMOS_WRITE((UCHAR)HalpCmosCenturyOffset,Century);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
HalpFlushTLB (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Flushes the current TLB.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG flags;
|
|
PKPCR pcr;
|
|
PKPRCB prcb;
|
|
ULONG64 cr3;
|
|
ULONG64 cr4;
|
|
ULONG64 oldCr4;
|
|
|
|
flags = HalpDisableInterrupts();
|
|
|
|
cr3 = ReadCR3();
|
|
|
|
pcr = KeGetPcr();
|
|
prcb = pcr->CurrentPrcb;
|
|
|
|
//
|
|
// Note: the original code (ixcmos.asm) had differing behavior based
|
|
// on whether this was CPU 0. That behavior is mimicked here.
|
|
// It would be good to find out why this is done.
|
|
//
|
|
|
|
if (prcb->Number == 0) {
|
|
WriteCR3(cr3);
|
|
} else {
|
|
cr4 = ReadCR4();
|
|
WriteCR4(cr4 & ~CR4_PGE);
|
|
WriteCR3(cr3);
|
|
WriteCR4(cr4);
|
|
}
|
|
|
|
HalpRestoreInterrupts(flags);
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpCpuID (
|
|
IN ULONG Function,
|
|
OUT PULONG Eax,
|
|
OUT PULONG Ebx,
|
|
OUT PULONG Ecx,
|
|
OUT PULONG Edx
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function executes a cpu id and returns the result as found in
|
|
registers eax, ebx, ecx and edx.
|
|
|
|
Arguments:
|
|
|
|
Function - supplies the CPUID function to execute.
|
|
|
|
Eax - supplies a pointer to the storage to contain the contents of eax.
|
|
|
|
Eax - supplies a pointer to the storage to contain the contents of ebx.
|
|
|
|
Eax - supplies a pointer to the storage to contain the contents of ecx.
|
|
|
|
Eax - supplies a pointer to the storage to contain the contents of edx.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
CPU_INFO cpuInfo;
|
|
|
|
KiCpuId (Function,&cpuInfo);
|
|
|
|
*Eax = cpuInfo.Eax;
|
|
*Ebx = cpuInfo.Ebx;
|
|
*Ecx = cpuInfo.Ecx;
|
|
*Edx = cpuInfo.Edx;
|
|
}
|
|
|
|
|
|
UCHAR
|
|
CMOS_READ_BCD (
|
|
UCHAR Address
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function reads a CMOS byte as a two-digit packed BCD value and
|
|
returns its binary representation.
|
|
|
|
Arguments:
|
|
|
|
Address - supplies the CMOS address of the BCD value to retrieve.
|
|
|
|
Return Value:
|
|
|
|
Returns the binary representation of the BCD value residing in CMOS
|
|
at Address.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR value;
|
|
|
|
value = CMOS_READ(Address);
|
|
return BCD_TO_BIN(value);
|
|
}
|
|
|
|
VOID
|
|
CMOS_WRITE_BCD (
|
|
UCHAR Address,
|
|
UCHAR Value
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function writes a CMOS byte as a two-digit packed BCD value.
|
|
|
|
Arguments:
|
|
|
|
Address - supplies the CMOS address of the BCD value to write.
|
|
|
|
Value - supplies the binary representation of the value to write in
|
|
CMOS.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR value;
|
|
|
|
ASSERT(Value <= 99);
|
|
|
|
value = BIN_TO_BCD(Value);
|
|
CMOS_WRITE(Address,value);
|
|
}
|
|
|