287 lines
6.5 KiB
C
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);
|
||
|
}
|
||
|
}
|