Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

706 lines
18 KiB

/*++
Copyright (c) 1990 Microsoft Corporation
Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file
contains copyrighted material. Use of this file is restricted
by the provisions of a Motorola Software License Agreement.
Copyright (c) 1996 International Business Machines Corporation
Module Name:
pxmemctl.c
Abstract:
The module initializes any planar registers.
This module also implements machince check parity error handling.
Author:
Jim Wooldridge ([email protected])
Revision History:
Jake Oshins ([email protected])
Support newer Victory machines, (Lightning-2, Thunderbolt)
Peter L Johnston ([email protected]) Handle UNION (aka Doral/Terlingua)
--*/
#include "halp.h"
#include "pxmemctl.h"
#include "pxdakota.h"
#include "pci.h"
#include "pcip.h"
// #include "pxmp.h"
#include "ibmppc.h"
#define BYTE_SWAP(x) ((((x) & 0x000000ff) << 24) | \
(((x) & 0x0000ff00) << 8 ) | \
(((x) & 0x00ff0000) >> 8 ) | \
(((x) & 0xff000000) >> 24))
//
// Device ID/Vendor ID for IBM PCI Host Bridge (in UNION).
//
#define IBMUNIONPCIBRIDGE 0x003a1014
//
// Prototype routines to be discarded at end of phase 1.
//
BOOLEAN
HalpInitPlanar (
VOID
);
BOOLEAN
HalpMapPlanarSpace (
VOID
);
BOOLEAN
HalpMapBusConfigSpace (
VOID
);
BOOLEAN
HalpPhase0MapBusConfigSpace (
VOID
);
VOID
HalpPhase0UnMapBusConfigSpace (
VOID
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,HalpInitPlanar)
#pragma alloc_text(INIT,HalpMapPlanarSpace)
#pragma alloc_text(INIT,HalpMapBusConfigSpace)
#pragma alloc_text(INIT,HalpPhase0MapBusConfigSpace)
#pragma alloc_text(INIT,HalpPhase0UnMapBusConfigSpace)
#endif
//
// Virtual address of UNION System Control Registers (page).
//
PVOID HalpUnionControlRegs;
BOOLEAN
HalpInitPlanar (
VOID
)
{
ULONG pcidata;
static Pass = 0;
if ( Pass++ == 0 ) {
//
// This would be an error,...
//
return TRUE;
}
switch (HalpSystemType) {
case IBM_VICTORY:
// Write NMI status and control register NMISC
WRITE_PORT_UCHAR((PUCHAR)HalpIoControlBase + 0x61, 0x04);
// Write Mode select register PCI-Eisa bridge
WRITE_PORT_UCHAR((PUCHAR)HalpIoControlBase + 0x22, 0x40);
WRITE_PORT_UCHAR((PUCHAR)HalpIoControlBase + 0x23, 0x40);
// Set it so that the memory controller (montana/nevada
// will not cause a machine check when he is the initiator
// of a transaction when a pci parity error takes place
// won't cause a machine check. A server should probably
// do things like parity checking
// on the PCI bus, but there are lots of broken adapters
// out there that don't generate PCI bus parity.
// Read Montana Enable detection register (and surrounding bytes)
HalpPhase0GetPciDataByOffset(0, // primary PCI bus
0, // location of Montana/Nevada
&pcidata,
0xc0,
4);
pcidata &= ~(1 << 5);
// Now write back Montana Enable detection register
HalpPhase0SetPciDataByOffset(0, // primary PCI bus
0, // location of Montana/Nevada
&pcidata,
0xc0,
4);
break;
case IBM_DORAL:
HalpUnionControlRegs = HalpAssignReservedVirtualSpace(
UNION_SYSTEM_CONTROL_REG_BASE >> PAGE_SHIFT,
1);
//
// If the above failed, there's nothing we can do about it now
// anyway.
//
break;
case IBM_TIGER:
//
// CPK? What goes here?
//
break;
}
return TRUE;
}
BOOLEAN
HalpMapPlanarSpace (
VOID
)
/*++
Routine Description:
This routine maps the interrupt acknowledge register for the 8259.
Arguments:
None.
Return Value:
If the initialization is successfully completed, than a value of TRUE
is returned. Otherwise, a value of FALSE is returned.
--*/
{
PHYSICAL_ADDRESS physicalAddress;
//
// Map 8259 interrupt control space.
//
physicalAddress.HighPart = 0;
switch (HalpSystemType) {
case IBM_DORAL:
physicalAddress.LowPart = UNION_INTERRUPT_PHYSICAL_BASE;
break;
case IBM_VICTORY:
case IBM_TIGER:
physicalAddress.LowPart = INTERRUPT_PHYSICAL_BASE;
break;
}
HalpInterruptBase = MmMapIoSpace(physicalAddress,
PAGE_SIZE,
FALSE);
return TRUE;
}
BOOLEAN
HalpMapBusConfigSpace (
VOID
)
/*++
Routine Description:
Access to the PCI Configuration and Data registers has already been
obtained. This routine does nothing.
Arguments:
None.
Return Value:
Returns TRUE.
--*/
{
return TRUE;
}
BOOLEAN
HalpPhase0MapBusConfigSpace (
VOID
)
/*++
Routine Description:
Access to the PCI Configuration and Data registers has already been
obtained. This routine does nothing.
Arguments:
None.
Return Value:
Returns TRUE.
--*/
{
return TRUE;
}
VOID
HalpPhase0UnMapBusConfigSpace (
VOID
)
/*++
Routine Description:
Return the space mapped above. Except we didn't actually map
anything above, so do nothing.
Arguments:
None.
Return Value:
None.
--*/
{
return;
}
VOID
HalpDisplayRegister(
PUCHAR RegHex,
ULONG Bytes
)
/*++
Routine Description:
Displays (via HalDisplayString) a new-line terminated
string of hex digits representing the input value. The
input value is pointed to by the first argument is
from 1 to 4 bytes in length.
Arguments:
RegHex Pointer to the value to be displayed.
Bytes Length of input value in bytes (1-4).
Return Value:
None.
--*/
{
#define DISP_MAX 4
UCHAR RegString[(DISP_MAX * 2) + 2];
UCHAR Num, High, Low;
PUCHAR Byte = &RegString[(DISP_MAX * 2) + 1];
*Byte = '\0';
*--Byte = '\n';
if ( (unsigned)Bytes > DISP_MAX ) {
Bytes = DISP_MAX;
}
while (Bytes--) {
Num = *RegHex++;
High = (Num >> 4) + '0';
Low = (Num & 0xf) + '0';
if ( High > '9' ) {
High += ('A' - '0' - 0xA);
}
if ( Low > '9' ) {
Low += ('A' - '0' - 0xA);
}
*--Byte = Low;
*--Byte = High;
}
HalDisplayString(Byte);
}
VOID
HalpHandleVictoryMemoryError(
VOID
)
{
UCHAR StatusByte;
ULONG ErrorAddress;
//
// Read the error address register first
//
ErrorAddress = READ_PORT_ULONG(HalpErrorAddressRegister);
//
// Check TEA conditions
//
StatusByte = READ_PORT_UCHAR(&((PDAKOTA_CONTROL)
HalpIoControlBase)->MemoryParityErrorStatus);
if (!(StatusByte & 0x01)) {
HalDisplayString("TEA: Memory Parity Error at Address ");
HalpDisplayRegister((PUCHAR)&ErrorAddress, sizeof(ErrorAddress));
}
StatusByte = READ_PORT_UCHAR(&((PDAKOTA_CONTROL)
HalpIoControlBase)->L2CacheErrorStatus);
if (!(StatusByte & 0x01)) {
HalDisplayString ("TEA: L2 Cache Parity Error\n");
}
StatusByte = READ_PORT_UCHAR(&((PDAKOTA_CONTROL)
HalpIoControlBase)->TransferErrorStatus);
if (!(StatusByte & 0x01)) {
HalDisplayString ("TEA: Transfer Error at Address ");
HalpDisplayRegister((PUCHAR)&ErrorAddress, sizeof(ErrorAddress));
}
}
VOID
HalpHandleTigerMemoryError(
VOID
)
{
// CPK: Your turn. (plj).
}
VOID
HalpHandleDoralMemoryError(
VOID
)
{
static ULONG RecursionLevel = 0;
ULONG Status;
ULONG Address;
ULONG PciCsr0;
ULONG PciCsr1;
ULONG PciPlssr0;
ULONG PciPlssr1;
ULONG MemErrorStatus;
ULONG MemErrorAddress;
ULONG OldPciConfigAddress;
ULONG HostBridgePciAddress = 0x80000000;
ULONG PciConfigData;
ULONG PciBridgeFound = 0;
UCHAR Syndrome = 0;
PCHAR PciBusString;
extern KSPIN_LOCK HalpPCIConfigLock;
extern PVOID HalpPciConfigAddr[];
extern PVOID HalpPciConfigData[];
extern UCHAR HalpEpciMin;
switch ( ++RecursionLevel ) {
case 1:
//
// Read the System Error Status Register and try to display
// something reasonable based on what's in there.
//
Status = *(PULONG)((ULONG)HalpUnionControlRegs + UNION_SESR);
Status = BYTE_SWAP(Status);
//
// Before calling HalDisplayString which will interact with
// the PCI bus, try to gather all the pertinent info.
//
PciCsr0 = *((PULONG)HalpPciConfigAddr[0] + UNION_PCI_CSR_OFFSET);
PciCsr1 = *((PULONG)HalpPciConfigAddr[1] + UNION_PCI_CSR_OFFSET);
PciPlssr0 = *((PULONG)HalpPciConfigAddr[0] + UNION_PCI_PLSSR_OFFSET);
PciPlssr1 = *((PULONG)HalpPciConfigAddr[1] + UNION_PCI_PLSSR_OFFSET);
if ( Status & ~(UNION_SEAR_NOT_SET) ) {
//
// Status Error Address Register contains valid data,
// display it also.
//
Address = *(PULONG)((ULONG)HalpUnionControlRegs + UNION_SEAR);
Address = BYTE_SWAP(Address);
} else if ( Status &
(UNION_SESR_PCI32_BUS_MASTER | UNION_SESR_PCI64_BUS_MASTER) ) {
ULONG i = 0;
PciBusString = "on the 32 bit PCI bus.\n";
if ( Status & UNION_SESR_PCI64_BUS_MASTER ) {
i = 1;
PciBusString = "on the 64 bit PCI bus.\n";
}
//
// The error was a PCI error. It is possible we are still
// holding the PCI config access lock, so, unconditionally
// blow it away.
//
// However, we need to access the PCI config space for the
// bridge, so we need the lock but cannot acquire it in the
// usual way, (a) because it may already be locked, and (b)
// KeAcquireSpinLock will change IRQL.
//
// WARNING: Arcane knowledge about what a KSPIN_LOCK really
// is!
//
HalpPCIConfigLock = 0xdeaddead;
__builtin_isync();
//
// Get current value of this bridge's PCI CONFIG ADDRESS
// register.
//
OldPciConfigAddress = *(PULONG)(HalpPciConfigAddr[i]);
__builtin_sync();
//
// Set address for access to the host PCI bridge's config
// space.
//
if ( i != 0 ) {
//
// EPCI Bridge.
//
HostBridgePciAddress |= HalpEpciMin << 16;
}
*(PULONG)(HalpPciConfigAddr[i]) = HostBridgePciAddress;
__builtin_sync();
PciConfigData = *(PULONG)(HalpPciConfigData[i]);
if ( PciConfigData == IBMUNIONPCIBRIDGE ) {
PciBridgeFound = 1;
*(PULONG)(HalpPciConfigAddr[i]) = HostBridgePciAddress + 4;
__builtin_sync();
PciConfigData = *(PULONG)(HalpPciConfigData[i]);
}
//
// Release spin lock.
//
HalpPCIConfigLock = 0;
}
if ( Status & UNION_SESR_CPU_MEMORY_ACCESS ) {
//
// Memory Error. Read the Memory Error Status and
// Memory Error Address registers as well.
//
MemErrorStatus = *(PULONG)
((ULONG)HalpUnionControlRegs + UNION_MESR);
MemErrorStatus = BYTE_SWAP(MemErrorStatus);
MemErrorAddress = *(PULONG)
((ULONG)HalpUnionControlRegs + UNION_MEAR);
MemErrorAddress = BYTE_SWAP(MemErrorAddress);
Syndrome = (UCHAR)(MemErrorStatus & 0xff);
}
HalDisplayString("Machine Check : System Error Status = 0x");
HalpDisplayRegister((PUCHAR)&Status, sizeof(Status));
if ( Status & ~(UNION_SEAR_NOT_SET) ) {
HalDisplayString(" System Error Address = 0x");
HalpDisplayRegister((PUCHAR)&Address, sizeof(Address));
}
//
// The following strangness is just in case it is possible
// for more than one bit to be set.
//
if ( Status & UNION_SESR_CHECKSTOP ) {
HalDisplayString("UNION initiated checkstop.\n");
}
if ( Status & UNION_SESR_FLASH_WRITE ) {
HalDisplayString("FLASH Write Error. A write to flash\n");
HalDisplayString("memory was attempted but is not enabled.\n");
}
if ( Status & UNION_SESR_IGMC_ACCESS ) {
HalDisplayString("Access performed to IGMC when not enabled.\n");
}
if ( Status & UNION_SESR_DISABLED_ADDRESS ) {
HalDisplayString("Access performed to system I/O\n");
HalDisplayString("address space that is not enabled.\n");
}
if ( Status & UNION_SESR_T1_ACCESS ) {
HalDisplayString(
"T = 1 Access Error, a T = 1 PIO cycle was detected.\n");
}
if ( Status & UNION_SESR_ADDRESS_BUS_PARITY ) {
HalDisplayString("Address bus parity error.\n");
}
if ( Status & UNION_SESR_DATA_BUS_PARITY ) {
HalDisplayString("Data bus parity error.\n");
}
if ( Status & UNION_SESR_NO_L2_HIT_ACCESS ) {
HalDisplayString(
"L2_HIT_signal not active after AACK_; Addressing error.\n");
}
if ( Status & UNION_SESR_CPU_TO_PCI_ACCESS ) {
HalDisplayString(
"An error occurred on PCI bus while processing a load/store request.\n");
}
if ( Status &
(UNION_SESR_PCI32_BUS_MASTER | UNION_SESR_PCI64_BUS_MASTER) ) {
HalDisplayString(
"An error occurred during a PCI master initiated operation\n");
HalDisplayString(PciBusString);
HalDisplayString("Last PCI Configuration Address = 0x");
HalpDisplayRegister((PUCHAR)&OldPciConfigAddress,
sizeof(OldPciConfigAddress));
if ( PciBridgeFound ) {
HalDisplayString("PCI Bridge Status/Command = 0x");
HalpDisplayRegister((PUCHAR)&PciConfigData,
sizeof(PciConfigData));
}
}
if ( PciCsr0 ) {
HalDisplayString("Channel Status [32 bit bus] = 0x");
HalpDisplayRegister((PUCHAR)&PciCsr0, sizeof(PciCsr0));
}
if ( PciPlssr0 ) {
HalDisplayString("Processor Load/Store Status [32 bit bus] = 0x");
HalpDisplayRegister((PUCHAR)&PciPlssr0, sizeof(PciPlssr0));
}
if ( PciCsr1 ) {
HalDisplayString("Channel Status [64 bit bus] = 0x");
HalpDisplayRegister((PUCHAR)&PciCsr1, sizeof(PciCsr1));
}
if ( PciPlssr1 ) {
HalDisplayString("Processor Load/Store Status [32 bit bus] = 0x");
HalpDisplayRegister((PUCHAR)&PciPlssr1, sizeof(PciPlssr1));
}
if ( Status & UNION_SESR_XFERDATA ) {
HalDisplayString(
"An error occured during an operation in the memory\n");
HalDisplayString("controller's XferData unit.\n");
}
if ( Status & UNION_SESR_DATA_BUS_TIMEOUT ) {
//
// N.B. This error cannot be detected except via JTAG logic
// as UNION will checkstop rather than machine check in this
// case. This error indicates that the 60x bus did not
// respond in 8ms.
//
HalDisplayString("Data bus timeout.\n");
}
if ( Status & UNION_SESR_CPU_MEMORY_ACCESS ) {
HalDisplayString(
"An error occurred during a memory access by the CPU.\n");
HalDisplayString("Memory Error Status Register = 0x");
HalpDisplayRegister((PUCHAR)&MemErrorStatus,
sizeof(MemErrorStatus));
HalDisplayString("Memory Error Address Register = 0x");
HalpDisplayRegister((PUCHAR)&MemErrorAddress,
sizeof(MemErrorAddress));
if ( MemErrorStatus & UNION_MESR_DOUBLE_BIT ) {
HalDisplayString(
"bit 0 - A double bit memory error was detected.\n");
HalDisplayString(
" Syndrome bits = 0x");
HalpDisplayRegister(&Syndrome, sizeof(UCHAR));
}
if ( MemErrorStatus & UNION_MESR_SINGLE_BIT ) {
HalDisplayString(
"bit 1 - A single bit memory error was detected/corrected.\n");
if ( !(MemErrorStatus & UNION_MESR_SINGLE_BIT) ) {
HalDisplayString(
" Syndrome bits = 0x");
HalpDisplayRegister(&Syndrome, sizeof(UCHAR));
} else {
HalDisplayString(
" Error Address and Syndrome are for the Double bit error only.\n");
}
}
if ( MemErrorStatus & UNION_MESR_OVERLAPPED_MEM_EXT ) {
HalDisplayString(
"bit 3 - An access to an address that is mapped in two different memory\n");
HalDisplayString(
" extents was detected. This is a System Software error.\n");
}
}
break;
case 2:
HalDisplayString(
"Machine Check while trying to report Machine Check\n");
default:
//
// If we get here we took a second machine check while processing
// the first. Just hang.
//
for (;;);
}
}
VOID
HalpHandleMemoryError(
VOID
)
{
switch (HalpSystemType) {
case IBM_VICTORY:
HalpHandleVictoryMemoryError();
return;
case IBM_DORAL:
HalpHandleDoralMemoryError();
return;
case IBM_TIGER:
HalpHandleTigerMemoryError();
return;
}
return;
}