1154 lines
31 KiB
C
1154 lines
31 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1994 Digital Equipment Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
lca4err.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements error handling (machine checks and error
|
|||
|
interrupts) for machines based on the DECchip 21066
|
|||
|
microprocessor.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Joe Notarangelo 8-Feb-1994
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode only.
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "halp.h"
|
|||
|
#include "axp21066.h"
|
|||
|
#include "lca4.h"
|
|||
|
#include "stdio.h"
|
|||
|
|
|||
|
//
|
|||
|
// Declare the extern variable UncorrectableError declared in
|
|||
|
// inithal.c.
|
|||
|
//
|
|||
|
extern PERROR_FRAME PUncorrectableError;
|
|||
|
|
|||
|
//
|
|||
|
// MAX_RETRYABLE_ERRORS is the number of times to retry machine checks before
|
|||
|
// just giving up.
|
|||
|
//
|
|||
|
|
|||
|
#define MAX_RETRYABLE_ERRORS 32
|
|||
|
|
|||
|
//
|
|||
|
//jnfix - temporary counts
|
|||
|
//
|
|||
|
|
|||
|
ULONG CorrectableErrors = 0;
|
|||
|
ULONG RetryableErrors = 0;
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HalpDisplayLogout21066 (
|
|||
|
IN ESR_21066 Esr,
|
|||
|
IN IOC_STAT0_21066 IoStat0,
|
|||
|
IN PLOGOUT_FRAME_21066 LogoutFrame
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
HalpClearMachineCheck(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
ULONG
|
|||
|
HalpBankError(
|
|||
|
ULONG PhysicalAddress,
|
|||
|
PLOGOUT_FRAME_21066 LogoutFrame
|
|||
|
);
|
|||
|
|
|||
|
//jnfix - should be exported from platform-specific
|
|||
|
ULONG
|
|||
|
HalpSimmError(
|
|||
|
ULONG PhysicalAddress,
|
|||
|
PLOGOUT_FRAME_21066 LogoutFrame
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HalpClearAllErrors(
|
|||
|
IN BOOLEAN SignalMemoryCorrectables
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine clears all of the error bits in the LCA4 memory
|
|||
|
controller and I/O controller.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SignalMemoryCorrectables - Supplies a boolean value which specifies
|
|||
|
if correctable error reporting should be
|
|||
|
enabled in the memory controller.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
ESR_21066 ErrorStatus;
|
|||
|
IOC_STAT0_21066 IoStat0;
|
|||
|
|
|||
|
//
|
|||
|
// The error status bits of the ESR are all write one to clear.
|
|||
|
// Clear the value and then set all of the error bits. Then set
|
|||
|
// correctable enable according to specified input.
|
|||
|
//
|
|||
|
|
|||
|
ErrorStatus.all.QuadPart = (ULONGLONG)0;
|
|||
|
|
|||
|
ErrorStatus.Eav = 1;
|
|||
|
ErrorStatus.Cee = 1;
|
|||
|
ErrorStatus.Uee = 1;
|
|||
|
ErrorStatus.Cte = 1;
|
|||
|
ErrorStatus.Mse = 1;
|
|||
|
ErrorStatus.Mhe = 1;
|
|||
|
ErrorStatus.Nxm = 1;
|
|||
|
|
|||
|
if( SignalMemoryCorrectables == TRUE ){
|
|||
|
ErrorStatus.Ice = 0;
|
|||
|
} else {
|
|||
|
ErrorStatus.Ice = 1;
|
|||
|
}
|
|||
|
|
|||
|
WRITE_MEMC_REGISTER( &((PLCA4_MEMC_CSRS)(0))->ErrorStatus,
|
|||
|
ErrorStatus.all.QuadPart );
|
|||
|
|
|||
|
//
|
|||
|
// The ERR and LOST bits of the IO_STAT0 are write one to clear.
|
|||
|
//
|
|||
|
|
|||
|
IoStat0.all.QuadPart = (ULONGLONG)0;
|
|||
|
|
|||
|
IoStat0.Err = 1;
|
|||
|
IoStat0.Lost = 1;
|
|||
|
|
|||
|
WRITE_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0,
|
|||
|
IoStat0.all.QuadPart );
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
HalpBuildLCAUncorrectableErrorFrame(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
PPROCESSOR_LCA_UNCORRECTABLE LcaUncorrerr = NULL;
|
|||
|
PEXTENDED_ERROR PExtErr;
|
|||
|
EAR_21066 Ear;
|
|||
|
|
|||
|
if(PUncorrectableError){
|
|||
|
LcaUncorrerr = (PPROCESSOR_LCA_UNCORRECTABLE)
|
|||
|
PUncorrectableError->UncorrectableFrame.RawProcessorInformation;
|
|||
|
|
|||
|
//
|
|||
|
// first fill in some generic processor Information.
|
|||
|
// For the Current (Reporting) Processor.
|
|||
|
//
|
|||
|
HalpGetProcessorInfo(
|
|||
|
&PUncorrectableError->UncorrectableFrame.ReportingProcessor);
|
|||
|
PUncorrectableError->
|
|||
|
UncorrectableFrame.Flags.ProcessorInformationValid = 1;
|
|||
|
|
|||
|
|
|||
|
PExtErr = &PUncorrectableError->UncorrectableFrame.ErrorInformation;
|
|||
|
}
|
|||
|
|
|||
|
if(LcaUncorrerr) {
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
|||
|
sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
|
|||
|
"Uncorrectable Error From "
|
|||
|
"LCA4 Detected");
|
|||
|
LcaUncorrerr->IocStat0 = (ULONGLONG)
|
|||
|
READ_IOC_REGISTER(&((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0);
|
|||
|
|
|||
|
LcaUncorrerr->IocStat1 = (ULONGLONG)
|
|||
|
READ_IOC_REGISTER(&((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat1);
|
|||
|
|
|||
|
LcaUncorrerr->Esr = (ULONGLONG)
|
|||
|
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->ErrorStatus);
|
|||
|
|
|||
|
Ear.all.QuadPart = LcaUncorrerr->Ear = (ULONGLONG)
|
|||
|
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->ErrorAddress);
|
|||
|
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.PhysicalAddressValid = 1;
|
|||
|
PUncorrectableError->UncorrectableFrame.PhysicalAddress =
|
|||
|
Ear.ErrorAddress;
|
|||
|
|
|||
|
LcaUncorrerr->BankConfig0 =
|
|||
|
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankConfiguration0);
|
|||
|
|
|||
|
LcaUncorrerr->BankConfig1 =
|
|||
|
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankConfiguration1);
|
|||
|
|
|||
|
LcaUncorrerr->BankConfig2 =
|
|||
|
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankConfiguration2);
|
|||
|
|
|||
|
LcaUncorrerr->BankConfig3 =
|
|||
|
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankConfiguration3);
|
|||
|
|
|||
|
LcaUncorrerr->BankMask0 =
|
|||
|
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankMask0);
|
|||
|
|
|||
|
LcaUncorrerr->BankMask1 =
|
|||
|
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankMask1);
|
|||
|
|
|||
|
LcaUncorrerr->BankMask2 =
|
|||
|
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankMask2);
|
|||
|
|
|||
|
LcaUncorrerr->BankMask3 =
|
|||
|
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankMask3);
|
|||
|
|
|||
|
LcaUncorrerr->Car =
|
|||
|
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->CacheControl);
|
|||
|
|
|||
|
LcaUncorrerr->Gtr =
|
|||
|
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->GlobalTiming);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HalMachineCheck (
|
|||
|
IN PEXCEPTION_RECORD ExceptionRecord,
|
|||
|
IN PKEXCEPTION_FRAME ExceptionFrame,
|
|||
|
IN PKTRAP_FRAME TrapFrame
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function fields machine checks for 21066-based machines.
|
|||
|
|
|||
|
The following errors may be the cause of the machine check:
|
|||
|
|
|||
|
(a) Uncorrectable Dcache error
|
|||
|
(b) Uncorrectable Load from Memory Controller
|
|||
|
(c) Uncorrectable Load from I/O Controller
|
|||
|
(d) Non-existent device in PCI Configuration Space (I/O Controller)
|
|||
|
(e) Retryable Icache parity error
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ExceptionRecord - Supplies a pointer to the exception record for the
|
|||
|
machine check. Included in the exception information
|
|||
|
is the pointer to the logout frame.
|
|||
|
|
|||
|
ExceptionFrame - Supplies a pointer to the kernel exception frame.
|
|||
|
|
|||
|
TrapFrame - Supplies a pointer to the kernel trap frame.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A value of TRUE is returned if the machine check has been
|
|||
|
handled by the HAL. If it has been handled then execution may
|
|||
|
resume at the faulting address. Otherwise, a value of FALSE
|
|||
|
is returned.
|
|||
|
|
|||
|
N.B. - When a fatal error is recognized this routine does not
|
|||
|
return at all.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PMCHK_STATUS MachineCheckStatus;
|
|||
|
ESR_21066 ErrorStatus;
|
|||
|
IOC_STAT0_21066 IoStat0;
|
|||
|
PPROCESSOR_LCA_UNCORRECTABLE LcaUncorrerr = NULL;
|
|||
|
|
|||
|
MachineCheckStatus =
|
|||
|
(PMCHK_STATUS)&ExceptionRecord->ExceptionInformation[0];
|
|||
|
|
|||
|
//
|
|||
|
// Print an error message if a correctable machine check is signalled.
|
|||
|
// Correctable machine checks are not possible on the 21066.
|
|||
|
//
|
|||
|
|
|||
|
if( MachineCheckStatus->Correctable == 1 ){
|
|||
|
|
|||
|
#if DBG
|
|||
|
|
|||
|
DbgPrint( "Illegal correctable error for LCA4\n" );
|
|||
|
|
|||
|
#endif //DBG
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the machine check is retryable then log the error and
|
|||
|
// and restart the operation.
|
|||
|
//
|
|||
|
|
|||
|
if( MachineCheckStatus->Retryable == 1 ){
|
|||
|
|
|||
|
//
|
|||
|
// jnfix Log the error, interface undefined.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Increment the number of retryable machine checks.
|
|||
|
//
|
|||
|
|
|||
|
RetryableErrors += 1;
|
|||
|
|
|||
|
|
|||
|
#if (DBG) || (HALDBG)
|
|||
|
|
|||
|
DbgPrint( "HAL Retryable Errors = %d\n", RetryableErrors );
|
|||
|
// if( (RetryableErrors % 32) == 0 ){
|
|||
|
// DbgPrint( "HAL Retryable Errors = %d\n", RetryableErrors );
|
|||
|
// }
|
|||
|
|
|||
|
#endif //DBG || HALDBG
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// We'll retry MAX_RETRYABLE_ERRORS times and then give up. We
|
|||
|
// do this to avoid infinite retry loops.
|
|||
|
//
|
|||
|
|
|||
|
if( RetryableErrors > MAX_RETRYABLE_ERRORS ){
|
|||
|
|
|||
|
//
|
|||
|
// Acknowledge receipt of the retryable machine check.
|
|||
|
//
|
|||
|
DbgPrint("Got too many Retryable Errors errors\n");
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Clear the machine check in the MCES register.
|
|||
|
//
|
|||
|
|
|||
|
HalpClearMachineCheck();
|
|||
|
|
|||
|
//
|
|||
|
// Attempt to retry the operation.
|
|||
|
//
|
|||
|
|
|||
|
return TRUE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The machine check is uncorrectable according to the processor.
|
|||
|
// Read the error registers in the Memory and I/O Controller.
|
|||
|
// If the operation was a read to PCI configuration space and no
|
|||
|
// device is the error then we will fix up the operation and continue,
|
|||
|
// otherwise the machine has taken a fatal error.
|
|||
|
//
|
|||
|
|
|||
|
//jnfix - code here to check for dcache parity error?
|
|||
|
|
|||
|
|
|||
|
ErrorStatus.all.QuadPart =
|
|||
|
READ_MEMC_REGISTER(
|
|||
|
&((PLCA4_MEMC_CSRS)(0))->ErrorStatus );
|
|||
|
|
|||
|
IoStat0.all.QuadPart =
|
|||
|
READ_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0 );
|
|||
|
|
|||
|
//
|
|||
|
// If any of the following errors are indicated in the memory controller
|
|||
|
// then process a fatal error:
|
|||
|
// Uncorrectable Error
|
|||
|
// Cache Tag Error
|
|||
|
// Multiple Hard Errors
|
|||
|
// Non-existent Memory
|
|||
|
//
|
|||
|
|
|||
|
if( (ErrorStatus.Uee == 1) ||
|
|||
|
(ErrorStatus.Cte == 1) ||
|
|||
|
(ErrorStatus.Mhe == 1) ||
|
|||
|
(ErrorStatus.Nxm == 1) ){
|
|||
|
|
|||
|
goto FatalError;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check for a PCI configuration read error. An error is a
|
|||
|
// candidate if the I/O controller has signalled an error, there
|
|||
|
// are no lost errors and the error was a no device error on the PCI.
|
|||
|
//
|
|||
|
|
|||
|
if( (IoStat0.Err == 1) && (IoStat0.Code == IocErrorNoDevice) &&
|
|||
|
(IoStat0.Lost == 0) ){
|
|||
|
|
|||
|
//
|
|||
|
// So far, the error looks like a PCI configuration space read
|
|||
|
// that accessed a device that does not exist. In order to fix
|
|||
|
// this up we expect that the faulting instruction or the instruction
|
|||
|
// previous to the faulting instruction must be a load with v0 as
|
|||
|
// the destination register. If this condition is met then simply
|
|||
|
// update v0 in the register set and return. However, be careful
|
|||
|
// not to re-execute the load.
|
|||
|
//
|
|||
|
// jnfix - add condition to check if Rb contains the superpage
|
|||
|
// address for config space?
|
|||
|
|
|||
|
ALPHA_INSTRUCTION FaultingInstruction;
|
|||
|
BOOLEAN PreviousInstruction = FALSE;
|
|||
|
|
|||
|
FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir);
|
|||
|
if( (FaultingInstruction.Memory.Ra != V0_REG) ||
|
|||
|
(FaultingInstruction.Memory.Opcode != LDL_OP) ){
|
|||
|
|
|||
|
//
|
|||
|
// Faulting instruction did not match, try the previous
|
|||
|
// instruction.
|
|||
|
//
|
|||
|
|
|||
|
PreviousInstruction = TRUE;
|
|||
|
|
|||
|
FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir - 4);
|
|||
|
if( (FaultingInstruction.Memory.Ra != V0_REG) ||
|
|||
|
(FaultingInstruction.Memory.Opcode != LDL_OP) ){
|
|||
|
|
|||
|
//
|
|||
|
// No match, we can't fix this up.
|
|||
|
//
|
|||
|
|
|||
|
goto FatalError;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The error has matched all of our conditions. Fix it up by
|
|||
|
// writing the value 0xffffffff into the destination of the load.
|
|||
|
//
|
|||
|
|
|||
|
TrapFrame->IntV0 = (ULONGLONG)0xffffffffffffffff;
|
|||
|
|
|||
|
//
|
|||
|
// Clear the machine check condition in the processor.
|
|||
|
//
|
|||
|
|
|||
|
HalpClearMachineCheck();
|
|||
|
|
|||
|
//
|
|||
|
// Clear the error condition in the io controller.
|
|||
|
// The Err bit is write one to clear.
|
|||
|
//
|
|||
|
|
|||
|
IoStat0.all.QuadPart = (ULONGLONG)0;
|
|||
|
IoStat0.Err = 1;
|
|||
|
WRITE_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0,
|
|||
|
IoStat0.all.QuadPart );
|
|||
|
|
|||
|
//
|
|||
|
// If the faulting instruction was the load the restart execution
|
|||
|
// at the instruction after the load.
|
|||
|
//
|
|||
|
|
|||
|
if( PreviousInstruction == FALSE ){
|
|||
|
TrapFrame->Fir += 4;
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
|
|||
|
} //end if (IoStat0.Err == 1) && (IoStat0.Code == IocErrorNoDevice) ){
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// The system is not well and cannot continue reliable execution.
|
|||
|
// Print some useful messages and shutdown the machine.
|
|||
|
//
|
|||
|
|
|||
|
FatalError:
|
|||
|
|
|||
|
HalpBuildLCAUncorrectableErrorFrame();
|
|||
|
|
|||
|
if(PUncorrectableError){
|
|||
|
LcaUncorrerr = (PPROCESSOR_LCA_UNCORRECTABLE)
|
|||
|
PUncorrectableError->UncorrectableFrame.RawProcessorInformation;
|
|||
|
|
|||
|
LcaUncorrerr->AboxCtl = (ULONGLONG)
|
|||
|
((PLOGOUT_FRAME_21066)
|
|||
|
(ExceptionRecord->ExceptionInformation[1] ))->AboxCtl.all.QuadPart;
|
|||
|
|
|||
|
LcaUncorrerr->CStat = (ULONGLONG)
|
|||
|
((PLOGOUT_FRAME_21066)
|
|||
|
(ExceptionRecord->ExceptionInformation[1] ))->DcStat.all.QuadPart;
|
|||
|
|
|||
|
LcaUncorrerr->MmCsr = (ULONGLONG)
|
|||
|
((PLOGOUT_FRAME_21066)
|
|||
|
(ExceptionRecord->ExceptionInformation[1] ))->MmCsr.all.QuadPart;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Display the logout frame.
|
|||
|
//
|
|||
|
|
|||
|
HalpDisplayLogout21066(
|
|||
|
ErrorStatus,
|
|||
|
IoStat0,
|
|||
|
(PLOGOUT_FRAME_21066)(ExceptionRecord->ExceptionInformation[1]) );
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
// Bugcheck to dump the rest of the machine state, this will help
|
|||
|
// if the machine check is software-related.
|
|||
|
//
|
|||
|
|
|||
|
KeBugCheckEx( DATA_BUS_ERROR,
|
|||
|
(ULONG)MachineCheckStatus->Correctable,
|
|||
|
(ULONG)MachineCheckStatus->Retryable,
|
|||
|
0,
|
|||
|
(ULONG)PUncorrectableError );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
HalpClearMachineCheck(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Clear the machine check which is currently pending. Clearing the
|
|||
|
pending machine check bit will allow us to take machine checks in
|
|||
|
the future without detecting a double machine check condition.
|
|||
|
The machine check pending bit must be cleared in the MCES register
|
|||
|
within the PALcode.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
MCES MachineCheckSummary;
|
|||
|
|
|||
|
MachineCheckSummary.MachineCheck = 1;
|
|||
|
MachineCheckSummary.SystemCorrectable = 0;
|
|||
|
MachineCheckSummary.ProcessorCorrectable = 0;
|
|||
|
MachineCheckSummary.DisableProcessorCorrectable = 0;
|
|||
|
MachineCheckSummary.DisableSystemCorrectable = 0;
|
|||
|
MachineCheckSummary.DisableMachineChecks = 0;
|
|||
|
|
|||
|
HalpWriteMces( MachineCheckSummary );
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#define MAX_ERROR_STRING 100
|
|||
|
|
|||
|
VOID
|
|||
|
HalpDisplayLogout21066 (
|
|||
|
IN ESR_21066 Esr,
|
|||
|
IN IOC_STAT0_21066 IoStat0,
|
|||
|
IN PLOGOUT_FRAME_21066 LogoutFrame
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function displays the logout frame for a 21066.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Esr - Supplies the value of the memory controller error status register.
|
|||
|
|
|||
|
IoStat0 - Supplies the value of the i/o controller status register 0.
|
|||
|
|
|||
|
LogoutFrame - Supplies a pointer to the logout frame generated
|
|||
|
by the 21066.
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UCHAR OutBuffer[ MAX_ERROR_STRING ];
|
|||
|
EAR_21066 Ear;
|
|||
|
CAR_21066 Car;
|
|||
|
IOC_STAT1_21066 IoStat1;
|
|||
|
ULONG Index;
|
|||
|
PKPRCB Prcb;
|
|||
|
extern HalpLogicalToPhysicalProcessor[HAL_MAXIMUM_PROCESSOR+1];
|
|||
|
PCHAR parityErrString = NULL;
|
|||
|
PEXTENDED_ERROR exterr;
|
|||
|
|
|||
|
|
|||
|
if(PUncorrectableError) {
|
|||
|
exterr = &PUncorrectableError->UncorrectableFrame.ErrorInformation;
|
|||
|
parityErrString = PUncorrectableError->UncorrectableFrame.ErrorString;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Capture other useful registers, EAR, CAR, and IO_STAT1.
|
|||
|
//
|
|||
|
|
|||
|
Ear.all.QuadPart =
|
|||
|
READ_MEMC_REGISTER(
|
|||
|
&((PLCA4_MEMC_CSRS)(0))->ErrorAddress );
|
|||
|
|
|||
|
Car.all.QuadPart =
|
|||
|
READ_MEMC_REGISTER(
|
|||
|
&((PLCA4_MEMC_CSRS)(0))->CacheControl );
|
|||
|
|
|||
|
IoStat1.all.QuadPart =
|
|||
|
READ_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat1);
|
|||
|
|
|||
|
//
|
|||
|
// Acquire ownership of the display. This is done here in case we take
|
|||
|
// a machine check before the display has been taken away from the HAL.
|
|||
|
// When the HAL begins displaying strings after it has lost the
|
|||
|
// display ownership then the HAL will be careful not to scroll information
|
|||
|
// off of the screen.
|
|||
|
//
|
|||
|
|
|||
|
HalAcquireDisplayOwnership(NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Display the machine state via the logout frame.
|
|||
|
//
|
|||
|
|
|||
|
HalDisplayString( "\nFatal system hardware error.\n\n" );
|
|||
|
|
|||
|
|
|||
|
sprintf( OutBuffer, "MEMC_ESR: %16Lx MEMC_EAR: %16Lx CAR: %16Lx\n",
|
|||
|
Esr.all.QuadPart,
|
|||
|
Ear.all.QuadPart,
|
|||
|
Car.all.QuadPart );
|
|||
|
|
|||
|
HalDisplayString( OutBuffer );
|
|||
|
|
|||
|
sprintf( OutBuffer, "IO_STAT0: %16Lx IO_STAT1: %16Lx\n",
|
|||
|
IoStat0.all.QuadPart,
|
|||
|
IoStat1.all.QuadPart );
|
|||
|
|
|||
|
HalDisplayString( OutBuffer );
|
|||
|
|
|||
|
sprintf( OutBuffer, "ICCSR : %016Lx ABOX_CTL: %016Lx DC_STAT: %016Lx\n",
|
|||
|
ICCSR_ALL_21064(LogoutFrame->Iccsr),
|
|||
|
ABOXCTL_ALL_21064(LogoutFrame->AboxCtl),
|
|||
|
DCSTAT_ALL_21064(LogoutFrame->DcStat) );
|
|||
|
|
|||
|
HalDisplayString( OutBuffer );
|
|||
|
|
|||
|
sprintf( OutBuffer, "EXC_ADDR : %016Lx VA : %016Lx MM_CSR : %016Lx\n",
|
|||
|
LogoutFrame->ExcAddr.QuadPart,
|
|||
|
LogoutFrame->Va.QuadPart,
|
|||
|
MMCSR_ALL_21064(LogoutFrame->MmCsr) );
|
|||
|
|
|||
|
HalDisplayString( OutBuffer );
|
|||
|
|
|||
|
sprintf( OutBuffer, "HIRR : %016Lx HIER : %016Lx PS : %016Lx\n",
|
|||
|
IRR_ALL_21064(LogoutFrame->Hirr),
|
|||
|
IER_ALL_21064(LogoutFrame->Hier),
|
|||
|
PS_ALL_21064(LogoutFrame->Ps) );
|
|||
|
|
|||
|
HalDisplayString( OutBuffer );
|
|||
|
|
|||
|
sprintf( OutBuffer, "PAL_BASE : %016Lx \n",
|
|||
|
LogoutFrame->PalBase.QuadPart );
|
|||
|
|
|||
|
HalDisplayString( OutBuffer );
|
|||
|
|
|||
|
sprintf( OutBuffer, "Waiting 15 seconds...\n");
|
|||
|
HalDisplayString( OutBuffer );
|
|||
|
|
|||
|
for( Index=0; Index<1500; Index++)
|
|||
|
KeStallExecutionProcessor( 10000 ); // ~15 second delay
|
|||
|
|
|||
|
//
|
|||
|
// Print out interpretation of the error.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// First print the processor on which we saw the error
|
|||
|
//
|
|||
|
|
|||
|
Prcb = PCR->Prcb;
|
|||
|
sprintf( OutBuffer, "Error on processor number: %d\n",
|
|||
|
HalpLogicalToPhysicalProcessor[Prcb->Number] );
|
|||
|
HalDisplayString( OutBuffer );
|
|||
|
|
|||
|
//
|
|||
|
// If we got a Data Cache Parity Error print a message on screen.
|
|||
|
//
|
|||
|
|
|||
|
if( DCSTAT_DCPARITY_ERROR_21064(LogoutFrame->DcStat) ){
|
|||
|
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
|
|||
|
MEMORY_SPACE;
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.
|
|||
|
MemoryErrorSource = PROCESSOR_CACHE;
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.
|
|||
|
ExtendedErrorValid = 1;
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
|||
|
sprintf( parityErrString,
|
|||
|
"Data Cache Parity Error.\n");
|
|||
|
HalpGetProcessorInfo(&exterr->CacheError.ProcessorInfo);
|
|||
|
|
|||
|
sprintf( OutBuffer, "Data Cache Parity Error.\n" );
|
|||
|
HalDisplayString( OutBuffer );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check for uncorrectable error.
|
|||
|
//
|
|||
|
|
|||
|
if( Esr.Uee == 1 ){
|
|||
|
|
|||
|
if( Esr.Sor == 0 ){
|
|||
|
|
|||
|
//
|
|||
|
// Uncorrectable error from cache.
|
|||
|
//
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
|
|||
|
MEMORY_SPACE;
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.
|
|||
|
MemoryErrorSource = PROCESSOR_CACHE;
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.
|
|||
|
ExtendedErrorValid = 1;
|
|||
|
HalpGetProcessorInfo(&exterr->CacheError.ProcessorInfo);
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
|||
|
|
|||
|
sprintf( parityErrString,
|
|||
|
"Uncorrectable error from cache on %s, Tag: 0x%x\n",
|
|||
|
Esr.Wre ? "write" : "read",
|
|||
|
Car.Tag );
|
|||
|
HalDisplayString( parityErrString );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Uncorrectable error from memory.
|
|||
|
//
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
|
|||
|
MEMORY_SPACE;
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.
|
|||
|
MemoryErrorSource = SYSTEM_MEMORY;
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.
|
|||
|
ExtendedErrorValid = 1;
|
|||
|
HalpGetProcessorInfo(&exterr->MemoryError.ProcessorInfo);
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
|||
|
|
|||
|
sprintf( parityErrString,
|
|||
|
"Uncorrectable error from memory on %s\n",
|
|||
|
Esr.Wre ? "write" : "read" );
|
|||
|
HalDisplayString( parityErrString );
|
|||
|
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.
|
|||
|
PhysicalAddressValid = 1;
|
|||
|
PUncorrectableError->UncorrectableFrame.PhysicalAddress =
|
|||
|
Ear.ErrorAddress;
|
|||
|
|
|||
|
exterr->MemoryError.Flags.MemorySimmValid = 1;
|
|||
|
exterr->MemoryError.MemorySimm =
|
|||
|
HalpSimmError( Ear.ErrorAddress, LogoutFrame );
|
|||
|
|
|||
|
sprintf( OutBuffer,
|
|||
|
"Physical Address: 0x%x, Bank: %d, SIMM: %d\n",
|
|||
|
Ear.ErrorAddress,
|
|||
|
HalpBankError( Ear.ErrorAddress, LogoutFrame ),
|
|||
|
HalpSimmError( Ear.ErrorAddress, LogoutFrame ) );
|
|||
|
HalDisplayString( OutBuffer );
|
|||
|
|
|||
|
} //end if( Esr.Sor == 0 )
|
|||
|
|
|||
|
} //end if( Esr.Uee == 1 )
|
|||
|
|
|||
|
//
|
|||
|
// Check for cache tag errors.
|
|||
|
//
|
|||
|
|
|||
|
if( Esr.Cte == 1 ){
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
|
|||
|
MEMORY_SPACE;
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.
|
|||
|
MemoryErrorSource = PROCESSOR_CACHE;
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.
|
|||
|
ExtendedErrorValid = 1;
|
|||
|
HalpGetProcessorInfo(&exterr->CacheError.ProcessorInfo);
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
|||
|
|
|||
|
|
|||
|
sprintf( parityErrString,
|
|||
|
"Cache Tag Error, Tag: 0x%x, Hit: %d\n",
|
|||
|
Car.Tag, Car.Hit );
|
|||
|
HalDisplayString( parityErrString );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check for non-existent memory error.
|
|||
|
//
|
|||
|
|
|||
|
if( Esr.Nxm == 1 ){
|
|||
|
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
|
|||
|
MEMORY_SPACE;
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.
|
|||
|
MemoryErrorSource = SYSTEM_MEMORY;
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.
|
|||
|
ExtendedErrorValid = 1;
|
|||
|
HalpGetProcessorInfo(&exterr->MemoryError.ProcessorInfo);
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
|||
|
|
|||
|
sprintf( parityErrString,
|
|||
|
"Non-existent memory accessed\n" );
|
|||
|
sprintf( OutBuffer,
|
|||
|
"Non-existent memory accessed, Physical Address: 0x%x.\n",
|
|||
|
Ear.ErrorAddress );
|
|||
|
HalDisplayString( OutBuffer );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check for multiple hard errors.
|
|||
|
//
|
|||
|
|
|||
|
if( Esr.Mhe == 1 ){
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
|
|||
|
MEMORY_SPACE;
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.
|
|||
|
MemoryErrorSource = SYSTEM_MEMORY;
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.
|
|||
|
ExtendedErrorValid = 1;
|
|||
|
HalpGetProcessorInfo(&exterr->MemoryError.ProcessorInfo);
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
|||
|
|
|||
|
sprintf( parityErrString,
|
|||
|
"Multiple hard errors detected\n" );
|
|||
|
|
|||
|
sprintf( OutBuffer,
|
|||
|
"Multiple hard errors detected.\n" );
|
|||
|
HalDisplayString( OutBuffer );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If an I/O Error was pending print the interpretation.
|
|||
|
//
|
|||
|
|
|||
|
if( IoStat0.Err == 1 ){
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
|
|||
|
IO_SPACE;
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.
|
|||
|
ExtendedErrorValid = 1;
|
|||
|
exterr->IoError.Interface = PCIBus;
|
|||
|
exterr->IoError.BusNumber = 0;
|
|||
|
exterr->IoError.BusAddress.QuadPart = IoStat1.Address;
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.PhysicalAddressValid =
|
|||
|
1;
|
|||
|
PUncorrectableError->UncorrectableFrame.PhysicalAddress =
|
|||
|
IoStat1.Address;
|
|||
|
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
|||
|
|
|||
|
|
|||
|
switch( IoStat0.Code ){
|
|||
|
|
|||
|
//
|
|||
|
// Retry Limit.
|
|||
|
//
|
|||
|
|
|||
|
case IocErrorRetryLimit:
|
|||
|
sprintf(parityErrString,
|
|||
|
"Retry Limit Error, PCI Cmd 0x%x\n",
|
|||
|
IoStat0.Cmd );
|
|||
|
|
|||
|
sprintf( OutBuffer,
|
|||
|
"Retry Limit Error, PCI Address 0x%x PCI Cmd 0x%x\n",
|
|||
|
IoStat1.Address,
|
|||
|
IoStat0.Cmd );
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// No device error.
|
|||
|
//
|
|||
|
|
|||
|
case IocErrorNoDevice:
|
|||
|
sprintf(parityErrString,
|
|||
|
"No Device Error, PCI Cmd 0x%x\n",
|
|||
|
IoStat0.Cmd );
|
|||
|
|
|||
|
|
|||
|
sprintf( OutBuffer,
|
|||
|
"No Device Error, PCI Address 0x%x PCI Cmd 0x%x\n",
|
|||
|
IoStat1.Address,
|
|||
|
IoStat0.Cmd );
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Bad data parity.
|
|||
|
//
|
|||
|
|
|||
|
case IocErrorBadDataParity:
|
|||
|
sprintf(parityErrString,
|
|||
|
"Bad Data Parity Error, PCI Cmd 0x%x\n",
|
|||
|
IoStat0.Cmd );
|
|||
|
|
|||
|
|
|||
|
sprintf( OutBuffer,
|
|||
|
"Bad Data Parity Error, PCI Address 0x%x PCI Cmd 0x%x\n",
|
|||
|
IoStat1.Address,
|
|||
|
IoStat0.Cmd );
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Target abort.
|
|||
|
//
|
|||
|
|
|||
|
case IocErrorTargetAbort:
|
|||
|
sprintf(parityErrString,
|
|||
|
"Target Abort, PCI Cmd 0x%x\n",
|
|||
|
IoStat0.Cmd );
|
|||
|
|
|||
|
|
|||
|
sprintf( OutBuffer,
|
|||
|
"Target Abort, PCI Address 0x%x PCI Cmd 0x%x\n",
|
|||
|
IoStat1.Address,
|
|||
|
IoStat0.Cmd );
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Bad address parity.
|
|||
|
//
|
|||
|
|
|||
|
case IocErrorBadAddressParity:
|
|||
|
sprintf(parityErrString,
|
|||
|
"Bad Address Parity, PCI Cmd 0x%x\n",
|
|||
|
IoStat0.Cmd );
|
|||
|
|
|||
|
|
|||
|
sprintf( OutBuffer,
|
|||
|
"Bad Address Parity, PCI Address 0x%x PCI Cmd 0x%x\n",
|
|||
|
IoStat1.Address,
|
|||
|
IoStat0.Cmd );
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Page Table Read Error.
|
|||
|
//
|
|||
|
|
|||
|
case IocErrorPageTableReadError:
|
|||
|
sprintf(parityErrString,
|
|||
|
"Page Table Read Error, PCI Cmd 0x%x\n",
|
|||
|
IoStat0.Cmd );
|
|||
|
|
|||
|
|
|||
|
sprintf( OutBuffer,
|
|||
|
"Page Table Read Error, PCI Pfn 0x%x PCI Cmd 0x%x\n",
|
|||
|
IoStat0.PageNumber,
|
|||
|
IoStat0.Cmd );
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Invalid page.
|
|||
|
//
|
|||
|
|
|||
|
case IocErrorInvalidPage:
|
|||
|
sprintf(parityErrString,
|
|||
|
"Invalid Page Error, PCI Cmd 0x%x\n",
|
|||
|
IoStat0.Cmd );
|
|||
|
|
|||
|
|
|||
|
sprintf( OutBuffer,
|
|||
|
"Invalid Page Error, PCI Pfn 0x%x PCI Cmd 0x%x\n",
|
|||
|
IoStat0.PageNumber,
|
|||
|
IoStat0.Cmd );
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Data error.
|
|||
|
//
|
|||
|
|
|||
|
case IocErrorDataError:
|
|||
|
|
|||
|
sprintf(parityErrString,
|
|||
|
"Data Error, PCI Cmd 0x%x\n",
|
|||
|
IoStat0.Cmd );
|
|||
|
|
|||
|
sprintf( OutBuffer,
|
|||
|
"Data Error, PCI Address 0x%x PCI Cmd 0x%x\n",
|
|||
|
IoStat1.Address,
|
|||
|
IoStat0.Cmd );
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Unrecognized error code.
|
|||
|
//
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
sprintf(parityErrString,
|
|||
|
"Unrecognized I/O Error.\n" );
|
|||
|
|
|||
|
sprintf( OutBuffer, "Unrecognized I/O Error.\n" );
|
|||
|
break;
|
|||
|
|
|||
|
} //end switch (IoStat0.Code)
|
|||
|
|
|||
|
HalDisplayString( OutBuffer );
|
|||
|
|
|||
|
if( IoStat0.Lost == 1 ){
|
|||
|
sprintf(parityErrString,
|
|||
|
"Additional I/O errors were lost.\n" );
|
|||
|
|
|||
|
HalDisplayString( "Additional I/O errors were lost.\n" );
|
|||
|
}
|
|||
|
|
|||
|
} //end if( IoStat0.Err == 1 )
|
|||
|
|
|||
|
//
|
|||
|
// return to caller
|
|||
|
//
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ULONG
|
|||
|
HalpBankError(
|
|||
|
ULONG PhysicalAddress,
|
|||
|
PLOGOUT_FRAME_21066 LogoutFrame
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Return the bank of memory that the physical address fails within.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
PhysicalAddress - Supplies the physical address to locate.
|
|||
|
|
|||
|
LogoutFrame - Supplies a pointer to the logout frame that contains the
|
|||
|
bank configuration information.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns the number of the bank that contains the physical address.
|
|||
|
Returns 0xffffffff if the physical address is not contained within any of
|
|||
|
the banks.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
ULONG Bank;
|
|||
|
|
|||
|
for( Bank=0; Bank < MEMORY_BANKS_21066; Bank++ ){
|
|||
|
|
|||
|
//
|
|||
|
// If the bank is valid and the physical address is within the
|
|||
|
// bank then we have found the correct bank.
|
|||
|
//
|
|||
|
|
|||
|
if( (LogoutFrame->BankConfig[Bank].Bav == 1) &&
|
|||
|
((PhysicalAddress >> 20) &
|
|||
|
(~LogoutFrame->BankMask[Bank].BankAddressMask)) ==
|
|||
|
LogoutFrame->BankConfig[Bank].BankBase ){
|
|||
|
|
|||
|
return Bank;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Did not find a bank which contains physical address.
|
|||
|
//
|
|||
|
|
|||
|
return (0xffffffff);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//jnfix - this should be move to platform-specific
|
|||
|
//jnfix - and made real depending upon how memory is configured
|
|||
|
//jnfix - this current code is a simple guess which provides a model
|
|||
|
|
|||
|
ULONG
|
|||
|
HalpSimmError(
|
|||
|
ULONG PhysicalAddress,
|
|||
|
PLOGOUT_FRAME_21066 LogoutFrame
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Return the SIMM number that the physical address fails within.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
PhysicalAddress - Supplies the physical address to locate.
|
|||
|
|
|||
|
LogoutFrame - Supplies a pointer to the logout frame that contains the
|
|||
|
bank configuration information.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns the number of the SIMM that contains the physical address.
|
|||
|
Returns 0xffffffffif the physical address is not contained within any of
|
|||
|
the SIMMs.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG Bank;
|
|||
|
ULONG Simm;
|
|||
|
|
|||
|
for( Bank=0; Bank < MEMORY_BANKS_21066; Bank++ ){
|
|||
|
|
|||
|
//
|
|||
|
// If the bank is valid and the physical address is within the
|
|||
|
// bank then we have found the correct bank.
|
|||
|
//
|
|||
|
|
|||
|
if( (LogoutFrame->BankConfig[Bank].Bav == 1) &&
|
|||
|
((PhysicalAddress >> 20) &
|
|||
|
(~LogoutFrame->BankMask[Bank].BankAddressMask)) ==
|
|||
|
LogoutFrame->BankConfig[Bank].BankBase ){
|
|||
|
|
|||
|
//
|
|||
|
// Assume that each bank contains 2 SIMMs and that they are
|
|||
|
// numbered 0..N. We need to determine which SIMM within the
|
|||
|
// bank. We will guess that the SIMMs are 32-bits wide and
|
|||
|
// that the low 32-bits are in the low SIMM while the high
|
|||
|
// 32-bits are in the high SIMM. So addresses 0..3 are low
|
|||
|
// and 4..7 are high.
|
|||
|
//
|
|||
|
|
|||
|
Simm = Bank * 2;
|
|||
|
if( PhysicalAddress & 4 ) Simm += 1;
|
|||
|
return Simm;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Did not find a bank which contains physical address.
|
|||
|
//
|
|||
|
|
|||
|
return (0xffffffff);
|
|||
|
|
|||
|
}
|