Windows2000/private/ntos/ke/i386/cyrix.c
2020-09-30 17:12:32 +02:00

287 lines
6.5 KiB
C

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
cyrix.c
Abstract:
Detects and initializes Cryix processors
Author:
Ken Reneris (kenr) 24-Feb-1994
Environment:
Kernel mode only.
--*/
#include "ki.h"
#define Cx486_SLC 0x0
#define Cx486_DLC 0x1
#define Cx486_SLC2 0x2
#define Cx486_DLC2 0x3
#define Cx486_SRx 0x4 // Retail Upgrade Cx486SLC
#define Cx486_DRx 0x5 // Retail Upgrade Cx486DLC
#define Cx486_SRx2 0x6 // Retail Upgrade 2x Cx486SLC
#define Cx486_DRx2 0x7 // Retail Upgrade 2x Cx486DLC
#define Cx486DX 0x1a
#define Cx486DX2 0x1b
#define M1 0x30
#define CCR0 0xC0
#define CCR1 0xC1
#define CCR2 0xC2
#define CCR3 0xC3
#define DIR0 0xFE
#define DIR1 0xFF
// SRx & DRx flags
#define CCR0_NC0 0x01 // No cache 64k @ 1M boundaries
#define CCR0_NC1 0x02 // No cache 640k - 1M
#define CCR0_A20M 0x04 // Enables A20M#
#define CCR0_KEN 0x08 // Enables KEN#
#define CCR0_FLUSH 0x10 // Enables FLUSH#
// DX flags
#define CCR1_NO_LOCK 0x10 // Ignore lock prefixes
ULONG Ke386CyrixId (VOID);
UCHAR ReadCyrixRegister (IN UCHAR Register);
VOID WriteCyrixRegister (IN UCHAR Register, IN UCHAR Value);
VOID Ke386ConfigureCyrixProcessor (VOID);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,Ke386CyrixId)
#pragma alloc_text(PAGELK,Ke386ConfigureCyrixProcessor)
#endif
extern UCHAR CmpCyrixID[];
ULONG
Ke386CyrixId (
VOID
)
/*++
Routine Description:
Detects and returns the Cyrix ID of the processor.
This function only detects Cyrix processors which have internal
cache support.
Arguments:
Configure - If TRUE, causes this function to alter
the Cyrix CCR registers for the optimal NT
performance.
If FALSE, the processors configuration is
not altered.
Return Value:
Cyrix ID of the processor
0 if not a Cyrix processor
--*/
{
ULONG CyrixID;
UCHAR r3, c;
UCHAR flags;
PKPRCB Prcb;
CyrixID = 0;
Prcb = KeGetCurrentPrcb();
if (Prcb->CpuID && strcmp (Prcb->VendorString, CmpCyrixID)) {
// Not a Cyrix processor
return 0;
}
// Test Div instruction to see if the flags
// do not get altered
_asm {
xor eax, eax
sahf ; flags = ah
lahf ; ah = flags
mov flags, ah ; save flags
mov eax, 5
mov ecx, 2
div cl ; 5 / 2 = ?
lahf
sub flags, ah ; flags = orig_flags - new_flags
}
if (flags == 0) {
// See if the Cyrix CCR3 register bit 0x80 can be editted.
r3 = ReadCyrixRegister(CCR3); // Read CCR3
c = r3 ^ 0x80; // flip bit 80
WriteCyrixRegister(CCR3, c); // Write CCR3
ReadCyrixRegister(CCR0); // select new register
c = ReadCyrixRegister(CCR3); // Read new CCR3 value
if (ReadCyrixRegister(CCR3) != r3) {
// Read the Cyrix ID type register
CyrixID = ReadCyrixRegister(DIR0) + 1;
}
WriteCyrixRegister(CCR3, r3); // restore original CCR3 value
}
if (CyrixID > 0x7f) {
// invalid setting
CyrixID = 0;
}
return CyrixID;
}
static UCHAR
ReadCyrixRegister (
IN UCHAR Register
)
/*++
Routine Description:
Reads an internal Cyrix ID register. Note the internal register
space is accessed via I/O addresses which are hooked internally
to the processor.
The caller is responsible for only calling this function on
a Cyrix processor.
Arguments:
Register - Which Cyrix register to read
Return Value:
The registers value
--*/
{
UCHAR Value;
_asm {
mov al, Register
cli
out 22h, al
in al, 23h
sti
mov Value, al
}
return Value;
}
static VOID
WriteCyrixRegister (
IN UCHAR Register,
IN UCHAR Value
)
/*++
Routine Description:
Write an internal Cyrix ID register. Note the internal register
space is accessed via I/O addresses which are hooked internally to the processor.
The caller is responsible for only calling this function on a Cyrix processor.
Arguments:
Register - Which Cyrix register to written
Value - Value to write into the register
Return Value:
The registers value
--*/
{
_asm {
mov al, Register
mov cl, Value
cli
out 22h, al
mov al, cl
out 23h, al
sti
}
}
VOID Ke386ConfigureCyrixProcessor (VOID)
{
UCHAR r0, r1;
ULONG id, rev;
PVOID LockHandle;
PAGED_CODE();
id = Ke386CyrixId();
if (id) {
LockHandle = MmLockPagableCodeSection (&Ke386ConfigureCyrixProcessor);
id = id - 1;
rev = ReadCyrixRegister(DIR1);
if ((id >= 0x20 && id <= 0x27) || ((id & 0xF0) == M1 && rev < 0x17)) {
// These steppings have a write-back cache problem.
// On these chips the L1 w/b cache can be disabled by
// setting only the NW bit.
_asm {
cli
mov eax, cr0
or eax, CR0_NW
mov cr0, eax
sti
}
}
switch (id) {
case Cx486_SRx:
case Cx486_DRx:
case Cx486_SRx2:
case Cx486_DRx2:
// These processors have an internal cache feature
// let's turn it on.
r0 = ReadCyrixRegister(CCR0);
r0 |= CCR0_NC1 | CCR0_FLUSH;
r0 &= ~CCR0_NC0;
WriteCyrixRegister(CCR0, r0);
// Clear Non-Cacheable Region 1
WriteCyrixRegister(0xC4, 0);
WriteCyrixRegister(0xC5, 0);
WriteCyrixRegister(0xC6, 0);
break;
case Cx486DX:
case Cx486DX2:
// Set NO_LOCK flag on these processors according to
// the number of booted processors
r1 = ReadCyrixRegister(CCR1);
r1 |= CCR1_NO_LOCK;
if (KeNumberProcessors > 1) {
r1 &= ~CCR1_NO_LOCK;
}
WriteCyrixRegister(CCR1, r1);
break;
}
MmUnlockPagableImageSection (LockHandle);
}
}