NT4/private/ntos/nthals/halncr/i386/ncrsus.c
2020-09-30 17:12:29 +02:00

679 lines
14 KiB
C

/*++
Copyright (c) 1993 NCR Corporation
Module Name:
ncrsus.c
Abstract:
Provides the interface to the NCR SUS.
Author:
Rick Ulmer (rick.ulmer@columbiasc.ncr.com) 8-Sep-1993
Revision History:
--*/
#include "halp.h"
#include "ncr.h"
#include "ncrcat.h"
#include "ncrsus.h"
#include "ncrarb.h"
PNST_SUS_LOG SUSErrorLogHeader;
PUCHAR SUSErrorLogData;
PUCHAR CurrentSUSErrorEntryPosition;
USHORT CurrentSUSErrorEntryBytesRemaining;
PKERNEL_SUS_MAILBOX SUSMailbox;
PPROCESSOR_BOARD_INFO SUSBoardInfo;
PCPU_INFO SUSCpuInfo;
extern ULONG NCRExistingProcessorMask;
extern ULONG NCRExistingDyadicProcessorMask;
extern ULONG NCRExistingQuadProcessorMask;
ULONG HalpGetCmosData (ULONG SourceLocation, ULONG SourceAddress,
PUCHAR Buffer, ULONG Length);
ULONG HalpSetCmosData (ULONG SourceLocation, ULONG SourceAddress,
PUCHAR Buffer, ULONG Length);
BOOLEAN HalpCheckSUSLogSanity();
VOID HalpWriteCheckSum(
PUCHAR CheckSumStart,
PUCHAR CheckSumEnd,
PUCHAR CheckSumLowByte,
PUCHAR CheckSumHighByte
);
ULONG NCRTranslateCMOSMask(ULONG);
VOID
HalpInitializeSUSInterface (
)
{
PHYSICAL_ADDRESS physical_log_address;
ULONG LowPart;
UCHAR data;
ULONG i;
//
// Get pointers to SUS Error Log
//
SUSErrorLogHeader = NULL;
SUSErrorLogData = NULL;
LowPart = 0;
HalpGetCmosData(1,SUS_LOG_PTR,
(PUCHAR)&LowPart,NST_LOG_PTR_SIZE);
SUSErrorLogHeader = (PNST_SUS_LOG)HalpMapPhysicalMemory(LowPart,
COMPUTE_PAGES_SPANNED(LowPart,sizeof(NST_SUS_LOG)));
if (SUSErrorLogHeader != NULL) {
LowPart += SUSErrorLogHeader->PhysicalLogBegin;
SUSErrorLogData = (PUCHAR)HalpMapPhysicalMemory(LowPart,
COMPUTE_PAGES_SPANNED(LowPart,SUSErrorLogHeader->PhysicalLogEnd));
if (SUSErrorLogData == NULL) {
// MmUnmapIoSpace(SUSErrorLogHeader,sizeof(NST_SUS_LOG));
SUSErrorLogHeader = NULL;
}
}
//
// Make sure SUS error log is OK
//
/*RMU
This is just during debug.......
if (SUSErrorLogHeader) {
SUSErrorLogHeader->FirstUnreadRecord = SUSErrorLogHeader->FirstValidRecord;
SUSErrorLogHeader->UnreadBytesInLog = SUSErrorLogHeader->ValidBytesInLog;
}
*/
if (!HalpCheckSUSLogSanity()) {
DBGMSG(("SUS Error log is corrputed......................\n"));
SUSErrorLogHeader = NULL;
SUSErrorLogData = NULL;
}
/*RMU debug phase */
//
// Get Pointer to SUS/Kernel mailbox
//
LowPart = 0;
HalpGetCmosData(1,SUS_MAILBOX_PTR,
(PUCHAR)&LowPart,4);
SUSMailbox = (PKERNEL_SUS_MAILBOX)HalpMapPhysicalMemory(LowPart,
COMPUTE_PAGES_SPANNED(LowPart,sizeof(KERNEL_SUS_MAILBOX)));
SUSMailbox->OSMailboxVersion = FIRST_PASS_INTERFACE;
SUSMailbox->OSFlags = OS_KNOWS_SYSINT;
//
// Get Pointer to the SUS board info struct.
//
LowPart = (ULONG)SUSMailbox->BoardData;
SUSBoardInfo = (PPROCESSOR_BOARD_INFO)HalpMapPhysicalMemory(LowPart,
COMPUTE_PAGES_SPANNED(LowPart,sizeof(PROCESSOR_BOARD_INFO)));
DBGMSG(("HalpInitializeSUSInterface: SUSMailbox = 0x%x\n", SUSMailbox));
DBGMSG(("HalpInitializeSUSInterface: SUSBoardInfo = 0x%x\n", SUSBoardInfo));
//
// Get Pointer to the SUS cpu info struct.
//
LowPart = (ULONG)SUSMailbox->Cpu_Data;
SUSCpuInfo = (PCPU_INFO)HalpMapPhysicalMemory(LowPart,
COMPUTE_PAGES_SPANNED(LowPart,sizeof(CPU_INFO)));
DBGMSG(("HalpInitializeSUSInterface: SUSCpuInfo = 0x%x\n", SUSCpuInfo));
//
// Now lets go look for all the processor in the system and fill in
// NCRExistingDyadicProcessorMask and NCRExistingQuadProcessorMask
//
for (i = 0; i < SUSCpuInfo->NumberOfCpus; i++ ) {
data = SUSCpuInfo->CpuData[i].CPU_HardwareId;
if ((data & 0xc0) == 0xc0) {
//
// this is a Quad processor
//
// convert the who_am_i into the proper mask
//
// format:
//
// 1100ccss
//
// cc = processor bits
// ss = slot bits
//
NCRExistingQuadProcessorMask |= (1<<((data & 0xf)>>2))<<(((data&3)<<2));
} else {
//
// this is a Dyadic processor
//
NCRExistingDyadicProcessorMask |= NCRTranslateCMOSMask(data);
}
}
DBGMSG(("HalpInitializeSUSInterface: Dyadic Mask = 0x%x, Quad Mask = 0x%x\n",
NCRExistingDyadicProcessorMask, NCRExistingQuadProcessorMask));
//
// Set firmware to perform a cold reset and not take a dump.
//
HalpGetCmosData(1,SUS_RESET_PTR,
(PUCHAR)&data,1);
data |= 0x01;
HalpSetCmosData(1,SUS_RESET_PTR,
(PUCHAR)&data,1);
HalpWriteCheckSum((PUCHAR)SUS_HIGH_AVAIL_XSUM_START,
(PUCHAR)SUS_HIGH_AVAIL_XSUM_END,
(PUCHAR)SUS_HIGH_AVAIL_XSUM_LOW,
(PUCHAR)SUS_HIGH_AVAIL_XSUM_HIGH);
}
VOID
HalpSUSLogError (
)
{
//
// This routine tells SUS to go do FRU analysis. After the FRU
// analysis the system will reboot
//
DBGMSG(("HalpSUSLogError has been called......\n"));
SUSMailbox->OSFlags |= OS_IN_PROGRESS;
SUSMailbox->MailboxOS = SYSINT_HANDSHAKE;
//
// Send interrupt from SP to DP
//
WRITE_PORT_UCHAR((PUCHAR)0xf820,(UCHAR)0x11);
}
BOOLEAN
HalpSUSSwNmi (
)
{
DBGMSG(("HalpSUSSwNmi has been called......\n"));
if (SUSMailbox->MailboxSUS == DUMP_BUTTON_INTERRUPT) {
SUSMailbox->MailboxOS = NO_COMMAND;
SUSMailbox->OSFlags |= OS_IN_PROGRESS;
KeStallExecutionProcessor(1000000); // give DP a chance 1 sec
SUSMailbox->MailboxOS = IGNORE_DUMP_BUTTON;
SUSMailbox->OSFlags &= ~OS_IN_PROGRESS;
while (SUSMailbox->MailboxSUS == DUMP_BUTTON_INTERRUPT) {
KeStallExecutionProcessor(1);
};
return TRUE;
}
return FALSE;
}
BOOLEAN
HalpCheckSUSLogSanity (
)
{
USHORT bytes_in_log;
PSUS_ERROR_RECORD_HEADER SUS_header;
PUCHAR next_write_record;
PUCHAR logical_log_end;
if (SUSErrorLogHeader == NULL) {
return FALSE;
}
next_write_record = ADDRESS_OF(NEXT_WRITE_RECORD);
logical_log_end = ADDRESS_OF(LOGICAL_LOG_END);
if( (FIRST_VALID_RECORD >= PHYS_LOG_END) ||
(FIRST_UNREAD_RECORD > PHYS_LOG_END) ||
(LOGICAL_LOG_END > PHYS_LOG_END) ||
(NEXT_WRITE_RECORD > PHYS_LOG_END) ||
(VALID_BYTES_IN_LOG > PHYS_LOG_END) ||
(UNREAD_BYTES_IN_LOG > PHYS_LOG_END) ||
(UNREAD_BYTES_IN_LOG > VALID_BYTES_IN_LOG) ||
(VALID_BYTES_IN_LOG > LOGICAL_LOG_END) ) {
return FALSE;
}
if (VALID_BYTES_IN_LOG == 0)
return TRUE;
//
// Make sure the VALID_BYTES_IN_LOG is correct and that the log can be
// traversed starting with the FIRST_VALID_RECORD.
//
for (bytes_in_log = 0,
SUS_header = (PSUS_ERROR_RECORD_HEADER)ADDRESS_OF(FIRST_VALID_RECORD);
bytes_in_log < VALID_BYTES_IN_LOG; ) {
if (SUS_header > (PSUS_ERROR_RECORD_HEADER)logical_log_end)
return FALSE;
if ((SUS_header == (PSUS_ERROR_RECORD_HEADER)logical_log_end))
SUS_header = (PSUS_ERROR_RECORD_HEADER)SUSErrorLogData;
if (SUS_header->RecordLength <= 0)
return FALSE;
if ((bytes_in_log += SUS_header->RecordLength) > VALID_BYTES_IN_LOG)
return FALSE;
SUS_header = (PSUS_ERROR_RECORD_HEADER)((ULONG)SUS_header +
(ULONG)SUS_header->RecordLength);
}
if( bytes_in_log != VALID_BYTES_IN_LOG )
return FALSE;
if (UNREAD_BYTES_IN_LOG == 0)
return TRUE;
//
// Make sure the UNREAD_BYTES_IN_LOG is correct and that the log can be
// traversed starting with the FIRST_UNREAD_RECORD.
//
for (bytes_in_log = 0,
SUS_header = (PSUS_ERROR_RECORD_HEADER)ADDRESS_OF(FIRST_UNREAD_RECORD);
bytes_in_log < UNREAD_BYTES_IN_LOG; ) {
if (SUS_header > (PSUS_ERROR_RECORD_HEADER)logical_log_end)
return FALSE;
if ((SUS_header == (PSUS_ERROR_RECORD_HEADER)logical_log_end))
SUS_header = (PSUS_ERROR_RECORD_HEADER)SUSErrorLogData;
if (SUS_header->RecordLength <= 0)
return FALSE;
if ((bytes_in_log += SUS_header->RecordLength) > UNREAD_BYTES_IN_LOG)
return FALSE;
SUS_header = (PSUS_ERROR_RECORD_HEADER)((ULONG)SUS_header +
(ULONG)SUS_header->RecordLength);
}
if( bytes_in_log != UNREAD_BYTES_IN_LOG )
return FALSE;
return TRUE;
}
LONG
HalGetSUSErrorLogEntry (
PUCHAR ErrorEntry
)
{
PSUS_ERROR_RECORD_HEADER SUS_header;
USHORT entry_length;
if ((SUSErrorLogHeader == NULL) || (SUSErrorLogData == NULL)) {
return -1;
}
if (UNREAD_BYTES_IN_LOG) {
SUS_header = (PSUS_ERROR_RECORD_HEADER)ADDRESS_OF(FIRST_UNREAD_RECORD);
entry_length = SUS_header->RecordLength;
if (entry_length > HAL_MAX_SUS_ENTRY_SIZE) {
entry_length = HAL_MAX_SUS_ENTRY_SIZE;
}
RtlMoveMemory(ErrorEntry,SUS_header,entry_length);
UNREAD_BYTES_IN_LOG -= SUS_header->RecordLength;
FIRST_UNREAD_RECORD += SUS_header->RecordLength;
if ((FIRST_UNREAD_RECORD == LOGICAL_LOG_END) &&
(UNREAD_BYTES_IN_LOG)) {
FIRST_UNREAD_RECORD = 0;
}
} else {
entry_length = 0;
}
return entry_length;
}
VOID
HalSetWatchDogPeriod (
ULONG Period
)
{
if (SUSMailbox) {
SUSMailbox->OSFlags |= UPDATING_WDPERIOD;
SUSMailbox->WatchDogPeriod = Period;
SUSMailbox->WatchDogCount = 0;
SUSMailbox->OSFlags &= ~UPDATING_WDPERIOD;
}
}
VOID
HalBumpWatchDogCount (
)
{
if (SUSMailbox) {
SUSMailbox->WatchDogCount++;
}
}
VOID
HalpBeginSUSErrorEntry (
ULONG EntryType,
ULONG EntrySize
)
{
USHORT record_length;
PSUS_ERROR_RECORD_HEADER SUS_header;
USHORT i;
//
// Make sure the log is in a good state.
//
if (!HalpCheckSUSLogSanity()) {
CurrentSUSErrorEntryPosition = NULL;
CurrentSUSErrorEntryBytesRemaining = 0;
return;
}
//
// Make sure the Error Entry is valid
//
if ((EntryType != NST_ErrorType) && (EntryType != ASCII_ErrorType)) {
return;
}
record_length = EntrySize + sizeof(SUS_ERROR_RECORD_HEADER);
//
// increate by 1 for the null terminator
//
record_length++;
//
// is it too big to fit?
//
if (record_length > PHYS_LOG_END)
return;
/* Check for fit before physical end of log */
/*
* if this record will NOT fit within physical end of log,
* it causes a wrap of the error log
* if the log is in a wrapped state, valid records at end of log will
* be lost
* Delete the valid bytes that are at the end of the log
* Point first valid to top of log
* if first unread will be lost in the wrap, unread records at the
* end of the log will be lost
* Delete the unread bytes that are at the end of the log
* Point first unread to top of log
* Set new logical end to where next record was to write
* Set next write record to the top of the log
*/
if ((record_length + NEXT_WRITE_RECORD) > PHYS_LOG_END) {
if (FIRST_VALID_RECORD >= NEXT_WRITE_RECORD) {
VALID_BYTES_IN_LOG -= LOGICAL_LOG_END - FIRST_VALID_RECORD;
FIRST_VALID_RECORD = 0;
}
if (FIRST_UNREAD_RECORD >= NEXT_WRITE_RECORD) {
UNREAD_BYTES_IN_LOG -= LOGICAL_LOG_END - FIRST_UNREAD_RECORD;
FIRST_UNREAD_RECORD = 0;
}
LOGICAL_LOG_END = NEXT_WRITE_RECORD;
NEXT_WRITE_RECORD = 0;
}
/* Check for overwriting currently unread records */
while(UNREAD_BYTES_IN_LOG && (NEXT_WRITE_RECORD <= FIRST_UNREAD_RECORD) &&
((record_length + NEXT_WRITE_RECORD) > FIRST_UNREAD_RECORD)) {
UNREAD_BYTES_IN_LOG -= RECORDLENGTH(ADDRESS_OF(FIRST_UNREAD_RECORD));
FIRST_UNREAD_RECORD += RECORDLENGTH(ADDRESS_OF(FIRST_UNREAD_RECORD));
if (FIRST_UNREAD_RECORD >= LOGICAL_LOG_END) {
FIRST_UNREAD_RECORD = 0;
}
}
/* Check for overwriting currently valid records */
while (VALID_BYTES_IN_LOG && (NEXT_WRITE_RECORD <= FIRST_VALID_RECORD)&&
((record_length + NEXT_WRITE_RECORD) > FIRST_VALID_RECORD)) {
VALID_BYTES_IN_LOG -= RECORDLENGTH(ADDRESS_OF(FIRST_VALID_RECORD));
FIRST_VALID_RECORD += RECORDLENGTH(ADDRESS_OF(FIRST_VALID_RECORD));
if (FIRST_VALID_RECORD >= LOGICAL_LOG_END) {
FIRST_VALID_RECORD = 0;
LOGICAL_LOG_END = VALID_BYTES_IN_LOG;
}
}
UNREAD_BYTES_IN_LOG += record_length;
VALID_BYTES_IN_LOG += record_length;
SUS_header = (PSUS_ERROR_RECORD_HEADER)ADDRESS_OF(NEXT_WRITE_RECORD);
RtlZeroMemory((PVOID)SUS_header, (ULONG)record_length);
SUS_header->RecordType = EntryType;
SUS_header->RecordLength = record_length;
CurrentSUSErrorEntryPosition = (PUCHAR)ADDRESS_OF(NEXT_WRITE_RECORD) +
sizeof(SUS_ERROR_RECORD_HEADER);
CurrentSUSErrorEntryBytesRemaining = EntrySize;
/*
* Adjust all of the offsets to include the new record.
*/
NEXT_WRITE_RECORD += record_length;
if (NEXT_WRITE_RECORD > LOGICAL_LOG_END)
LOGICAL_LOG_END = NEXT_WRITE_RECORD;
}
VOID
HalpWriteToSUSErrorEntry (
PUCHAR EntryData
)
{
USHORT entry_length;
USHORT i;
PUCHAR char_pointer;
if (CurrentSUSErrorEntryBytesRemaining == 0) {
return;
}
entry_length = 0;
char_pointer = EntryData;
while (*char_pointer) {
char_pointer++;
entry_length++;
}
if (entry_length == 0)
return;
if (entry_length > CurrentSUSErrorEntryBytesRemaining) {
entry_length = CurrentSUSErrorEntryBytesRemaining;
}
//
// Copy Entry segment into the Error Log
//
RtlMoveMemory(CurrentSUSErrorEntryPosition,EntryData,entry_length);
CurrentSUSErrorEntryBytesRemaining -= entry_length;
CurrentSUSErrorEntryPosition += entry_length;
}
VOID HalpWriteCheckSum(
PUCHAR CheckSumStart,
PUCHAR CheckSumEnd,
PUCHAR CheckSumLowByte,
PUCHAR CheckSumHighByte
)
{
USHORT check_sum = 0;
USHORT zero_sum;
PUCHAR address;
UCHAR data;
for (address = CheckSumStart; address <= CheckSumEnd; address++) {
HalpGetCmosData(1,(ULONG)address,
(PUCHAR)&data,1);
check_sum = check_sum + data;
}
zero_sum = 0 - check_sum;
HalpSetCmosData(1,SUS_HIGH_AVAIL_XSUM_LOW,
(PUCHAR)&zero_sum,2);
}