|
|
/*++
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.
Revision History:
--*/
#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 );
static UCHAR ReadCyrixRegister ( IN UCHAR Register );
static 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 CHAR 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 ((PCHAR)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 register's 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;
PAGED_CODE();
id = Ke386CyrixId(); if (id) {
ASSERT(ExPageLockHandle); MmLockPagableSectionByHandle(ExPageLockHandle);
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 (ExPageLockHandle); } }
|