/* * @implemented */ VOID NTAPI HalHandleNMI(IN PVOID NmiInfo) { UCHAR ucStatus; /* Get the NMI Flag */ ucStatus = READ_PORT_UCHAR((PUCHAR)0x61); /* Display NMI failure string */ HalDisplayString ("\n*** Hardware Malfunction\n\n"); HalDisplayString ("Call your hardware vendor for support\n\n"); /* Check for parity error */ if (ucStatus & 0x80) { /* Display message */ HalDisplayString ("NMI: Parity Check / Memory Parity Error\n"); } /* Check for I/O failure */ if (ucStatus & 0x40) { /* Display message */ HalDisplayString ("NMI: Channel Check / IOCHK\n"); } /* Halt the system */ HalDisplayString("\n*** The system has halted ***\n"); //KeEnterKernelDebugger(); }
BOOLEAN HalHandleNMI( IN PKINTERRUPT Interrupt, IN PVOID ServiceContext ) /*++ Routine Description: This function is called when an EISA NMI occurs. It print the appropriate status information and bugchecks. Arguments: Interrupt - Supplies a pointer to the interrupt object ServiceContext - Bug number to call bugcheck with. Return Value: Returns TRUE. --*/ { UCHAR StatusByte; #ifdef IDLE_PROCESSOR // // Clear interrupt flag // HalpInterruptReceived = 0; #endif StatusByte = READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus); if (StatusByte & 0x80) { HalDisplayString ("NMI: Parity Check / Parity Error\n"); } if (StatusByte & 0x40) { HalDisplayString ("NMI: Channel Check / IOCHK\n"); } // // This is an Sio machine, no extnded nmi information, so just do it. // KeBugCheck(NMI_HARDWARE_FAILURE); return(TRUE); }
VOID HalHandleNMI( IN OUT PVOID NmiInfo ) /*++ Routine Description: Called DURING an NMI. The system will BugCheck when an NMI occurs. This function can return the proper bugcheck code, bugcheck itself, or return success which will cause the system to iret from the nmi. This function is called during an NMI - no system services are available. In addition, you don't want to touch any spinlock which is normally used since we may have been interrupted while owning it, etc, etc... Warnings: Do NOT: Make any system calls Attempt to acquire any spinlock used by any code outside the NMI handler Change the interrupt state. Do not execute any IRET inside this code Passing data to non-NMI code must be done using manual interlocked functions. (xchg instructions). Arguments: NmiInfo - Pointer to NMI information structure (TBD) - NULL means no NMI information structure was passed Return Value: BugCheck code --*/ { // // We can not look at the hardware to determine the source // of the error because reads of many error registers clear // the error and the IMP board is racing with us. // // If support for systems without an IMP board is added, we need // to duplicate all the error reporting of the IMP board here. // HalDisplayString (MSG_HARDWARE_ERROR1); HalDisplayString (MSG_HARDWARE_ERROR2); HalDisplayString ("NMI: The system has detected a fatal NMI\n"); HalDisplayString (MSG_HALT); KeEnterKernelDebugger(); }
VOID R98DebugOutPut( ULONG DebugPrintLevel, // Debug Level PCSZ DebugMessageLed, // For LED strings. shuld be 4Byte. PCSZ DebugMessage, // For DISPLAY or SIO ... ) /*++ Routine Description: Debug print routine. Arguments: Debug print level between 0,and 3, with 3 being the most verbose. Return Value: None. --*/ { va_list ap; char *p,LedNumber; CHAR buffer[128]; if (DebugPrintLevel >= R98DebugLevel) { if (DebugOutput & DBG_LED) { // Message is "1-a-f" for(p=(char *)DebugMessageLed,LedNumber=0; LedNumber<4;p++,LedNumber++) // A002 HalpDisplaySegment(LedNumber,*p); } // sdk/inc/crt/stdarg.h va_start(ap, DebugMessage); // stdlib ?? (sdk/inc/crt/stdio.h) (VOID) vsprintf(buffer, DebugMessage, ap); // if (DebugOutput & DBG_SERIAL) { DbgPrint(buffer); } // Console =Vram Write // if (DebugOutput & DBG_COLOR) { HalDisplayString(buffer); } } va_end(ap); }
void KrnlStop(uint32_t error, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4) { if (in_stop) { /* Its recursive! */ HalShutdown(); } in_stop = 1; HalInitDisplay(); HalDisplaySetAttr(0x4f); HalDisplayClear(); HalDisplayString("An error has occured and Dux has been shutdown to prevent damage.\n\n"); printf("STOP: %x (%x, %x, %x, %x)\n", error, arg1, arg2, arg3, arg4); #ifdef DEBUG HalDisplayString("BREAK\n"); HalBreak(); #else HalShutdown(); #endif }
VOID SerMouDebugPrint( ULONG DebugPrintLevel, PCSZ DebugMessage, ... ) /*++ Routine Description: Debug print routine. Arguments: Debug print level between 0 and 3, with 3 being the most verbose. Return Value: None. --*/ { va_list ap; va_start(ap, DebugMessage); if (DebugPrintLevel <= SerialMouseDebug) { CHAR buffer[128]; (VOID) vsprintf(buffer, DebugMessage, ap); if (DebugOutput & DBG_SERIAL) { DbgPrint(buffer); } if (DebugOutput & DBG_COLOR) { HalDisplayString(buffer); } } va_end(ap); }
void HalpInitNvram(void) { ULONG Size; int Entry; CpuAuxControl = (volatile UCHAR *)SGI_AUX_BASE; Size = VenNvramTable(NvramTable, sizeof(NvramTable)); if(Size) { #ifdef DBG char buf[64]; sprintf(buf, "Nvram table has grown (%d).\n", Size); HalDisplayString(buf); DbgBreakPoint(); #endif return; } RtlZeroMemory (NvramValues, sizeof NvramValues); for (Entry = 0; Entry < NVRAM_ENTRIES; ++Entry) { if (NvramTable[Entry].NvLen == 0) { // DbgPrint ("Nvram has %d entries\n", Entry); break; } NvramTable[Entry].NvValue = &NvramValues[Entry * MAX_ENTRY_LEN]; if (NvramTable[Entry].NvLen <= MAX_ENTRY_LEN) { NvramReadString(NvramTable[Entry].NvAddr, NvramTable[Entry].NvLen, NvramTable[Entry].NvValue); } else { #ifdef DBG DbgPrint ("NvEntry %s too large\n", NvramTable[Entry].NvName); #endif NvramTable[Entry].NvName[0] = 0; } } #ifdef DBG if (Entry >= NVRAM_ENTRIES) DbgPrint("Nvram: too many entries\n"); #endif }
VOID KiDisplayString ( IN ULONG Column, IN ULONG Row, IN PCHAR Buffer ) /*++ Routine Description: This function display a string starting at the specified column and row position on the screen. Arguments: Column - Supplies the starting column of where the string is displayed. Row - Supplies the starting row of where the string is displayed. Bufer - Supplies a pointer to the string that is displayed. Return Value: None. --*/ { // // Position the cursor and display the string. // HalSetDisplayParameters(Column, Row); HalDisplayString(Buffer); return; }
NTSTATUS Cbus2ResolveNMI( IN PVOID NmiInfo ) /*++ Routine Description: This function determines the cause of the NMI so that the user can replace any offending SIMMs. Arguments: NmiInfo - pointer to the NMI information structure Return Value: Returns the byte address which caused the NMI, 0 if indeterminate --*/ { PCSR csr; UCHAR syndrome; UCHAR memsyndrome; UCHAR EccError; ULONG Processor; ULONG InterruptIndication; ULONG FaultIndication; ULONG ErrorType; PMEMCSR memcsr; PMEMORY_CARD pm; ULONG board; UCHAR NmiMessage[80]; PHYSICAL_ADDRESS FaultAddress; BOOLEAN founderror = FALSE; ULONG original_bridge; ULONG BridgeId; ULONG BusNumber; extern ULONG Cbus2BridgeId[]; extern PCSR Cbus2BridgeCSR[]; extern NTSTATUS DefaultHalHandleNMI( IN OUT PVOID); extern VOID CbusClearEISANMI(VOID); if (NMI_BUTTON_PRESSED()) { // // NMI button was pressed, so go to the debugger // _asm { int 3 } // // Clear the NMI in hardware so the system can continue // // assume that bridge 0 needs the clear in this case. // save the original value for restoral after the clear. // repoint our I/O references to the default bus bridge number. // BusNumber =0; BridgeId = Cbus2BridgeId[BusNumber]; csr = Cbus2BridgeCSR[BusNumber]; original_bridge = csr->BusBridgeSelection.csr_register; csr->BusBridgeSelection.csr_register = ((original_bridge & ~MAX_ELEMENT_CSRS) | BridgeId); CbusClearEISANMI(); // // restore our default bridge references to what they // were when we started... // csr->BusBridgeSelection.csr_register = original_bridge; return STATUS_SUCCESS; // ignore this NMI } if (CbusGlobal.nonstdecc) return DefaultHalHandleNMI(NmiInfo); // // All Cbus2 faults will generate an NMI on all the processors. // An EISA NMI will also go to all CPUs. Only directed NMIs // (sent by software) can go to less than all the processors. // // only one processor may proceed beyond this point, // so first get the Cbus HAL's NMI lock. // KiAcquireSpinLock(&Cbus2NMILock); if (Cbus2NMIHandler) { KiReleaseSpinLock(&Cbus2NMILock); // // another processor is handling it, so just spin forever // while (1) ; } Cbus2NMIHandler = 1; KiReleaseSpinLock(&Cbus2NMILock); // // Now display all the CSRs of: // a) all the processors and // b) all the memory boards and // c) all the I/O bridges // // // print out a leading newline so if he's running a checked // build, he'll be able to see the whole line. otherwise, // the kernel debugger CTS/SEND/etc. serial line status will // overwrite the first NMI line from our processor loop below. // HalDisplayString (MSG_NEWLINE); // // first go through the processors. there is no need to disable // ecc to safely take the system down because we will not iret, // (which is needed to re-enable NMI). // for (Processor = 0; Processor < CbusBootedProcessors; Processor++) { csr = CbusCSR[Processor].csr; InterruptIndication = csr->InterruptIndication.LowDword; // // if the interrupt indication is not set, then it's not // a Cbus2 NMI, so it must be something from EISA. we'll // handle EISA NMI detection last. // if ((InterruptIndication & CBUS2_FAULT_DETECTED) == 0) { sprintf(NmiMessage, MSG_NMI_ECC0, Processor); HalDisplayString (NmiMessage); continue; } founderror = TRUE; FaultIndication = (csr->FaultIndication.LowDword & 0xFF); if ((FaultIndication & (CBUS2_BUS_DATA_UNCORRECTABLE | CBUS2_BUS_ADDRESS_UNCORRECTABLE)) == 0) { // // it is a Cbus2 NMI, but we cannot determine the // address. at least display the fault indication // register so we can see what type of error it was. // sprintf(NmiMessage, MSG_NMI_ECC1, Processor, FaultIndication & CbusGlobal.FaultControlMask); HalDisplayString (NmiMessage); continue; } FaultAddress.LowPart = 0; FaultAddress.HighPart = 0; // // EccError contains the quadword index of which quadword // in the cache line is bad. since words in a cacheline // are not always transferred in order, we must print this // value as well as the address of the cacheline. the // transfer order is deterministic based on the specific // addresses, but not all addresses are read in the same order. // EccError = ((UCHAR)csr->EccError.LowDword & 0x03); syndrome = ((UCHAR)csr->EccSyndrome.LowDword & 0xFF); // // check if this memory board generated the ecc error // ErrorType = cbus2_edac_syndrome[syndrome]; ASSERT (ErrorType != NOECCERROR && ErrorType != SINGLEBIT); // // the error is latched in this processor's DPX registers. // now we need to figure out which register is correct, since // the error could have happened in the memory or on the bus. // // // display the values this processor has latched. // FaultAddress.HighPart = csr->EccWriteAddress.LowDword; FaultAddress.LowPart = csr->EccReadAddress.LowDword; sprintf(NmiMessage, MSG_NMI_ECC2, Processor, FaultAddress.HighPart, FaultAddress.LowPart, EccError, FaultIndication & CbusGlobal.FaultControlMask); HalDisplayString (NmiMessage); } // // next go through the memory boards... // pm = CbusMemoryBoards; for (board = 0; board < CbusMemoryBoardIndex; board++, pm++) { memcsr = (PMEMCSR)pm->regmap; if ((memcsr->MemoryFaultStatus.LowDword & CBUS2_MEMORY_FAULT_DETECTED) == 0) { sprintf(NmiMessage, MSG_NMI_ECC3, board); HalDisplayString (NmiMessage); continue; } founderror = TRUE; // // this board contains an error // memsyndrome = ((UCHAR)memcsr->MemoryEccSyndrome.LowDword & 0xFF); ErrorType = cbus2_edac_syndrome[memsyndrome]; ASSERT (ErrorType != NOECCERROR && ErrorType != SINGLEBIT); FaultAddress.HighPart = memcsr->MemoryEccWriteAddress.LowDword; FaultAddress.LowPart = memcsr->MemoryEccReadAddress.LowDword; sprintf(NmiMessage, MSG_NMI_ECC4, board, FaultAddress.HighPart, FaultAddress.LowPart); HalDisplayString (NmiMessage); } // // lastly, go through the I/O bridges... // for (BusNumber = 0; BusNumber < Cbus2BridgesFound; BusNumber++) { csr = Cbus2BridgeCSR[BusNumber]; InterruptIndication = csr->InterruptIndication.LowDword; // // if the interrupt indication is not set, then it's not // a Cbus2 NMI, so it must be something from EISA. we'll // handle EISA NMI detection last. // if ((InterruptIndication & CBUS2_FAULT_DETECTED) == 0) { sprintf(NmiMessage, MSG_NMI_ECC5, BusNumber); HalDisplayString (NmiMessage); continue; } founderror = TRUE; FaultIndication = (csr->FaultIndication.LowDword & 0xFF); if ((FaultIndication & (CBUS2_BUS_DATA_UNCORRECTABLE | CBUS2_BUS_ADDRESS_UNCORRECTABLE)) == 0) { // // it is a Cbus2 NMI, but we cannot determine the // address. at least display the fault indication // register so we can see what type of error it was. // sprintf(NmiMessage, MSG_NMI_ECC6, BusNumber, FaultIndication & CbusGlobal.FaultControlMask); HalDisplayString (NmiMessage); continue; } FaultAddress.LowPart = 0; FaultAddress.HighPart = 0; // // EccError contains the quadword index of which quadword // in the cache line is bad. since words in a cacheline // are not always transferred in order, we must print this // value as well as the address of the cacheline. the // transfer order is deterministic based on the specific // addresses, but not all addresses are read in the same order. // EccError = ((UCHAR)csr->EccError.LowDword & 0x03); syndrome = ((UCHAR)csr->EccSyndrome.LowDword & 0xFF); // // check if this memory board generated the ecc error // ErrorType = cbus2_edac_syndrome[syndrome]; ASSERT (ErrorType != NOECCERROR && ErrorType != SINGLEBIT); // // the error is latched in this processor's DPX registers. // now we need to figure out which register is correct, since // the error could have happened in the memory or on the bus. // // // display the values this processor has latched. // FaultAddress.HighPart = csr->EccWriteAddress.LowDword; FaultAddress.LowPart = csr->EccReadAddress.LowDword; sprintf(NmiMessage, MSG_NMI_ECC7, BusNumber, FaultAddress.HighPart, FaultAddress.LowPart, EccError, FaultIndication & CbusGlobal.FaultControlMask); HalDisplayString (NmiMessage); } if (founderror == TRUE) { // // this call will not return // CbusHardwareFailure (MSG_NMI_ECC8); } // // No errors were found in Cbus RAM, so check for EISA errors // DefaultHalHandleNMI(NmiInfo); }
ULONG NTAPI KdpServiceDispatcher(ULONG Service, PVOID Buffer1, ULONG Buffer1Length) { ULONG Result = 0; switch (Service) { case BREAKPOINT_PRINT: /* DbgPrint */ Result = KdpPrintString(Buffer1, Buffer1Length); break; #if DBG case ' soR': /* ROS-INTERNAL */ { switch ((ULONG_PTR)Buffer1) { case DumpAllThreads: PspDumpThreads(TRUE); break; case DumpUserThreads: PspDumpThreads(FALSE); break; case KdSpare3: MmDumpArmPfnDatabase(FALSE); break; default: break; } break; } #if defined(_M_IX86) && !defined(_WINKD_) // See ke/i386/traphdlr.c /* Register a debug callback */ case 'CsoR': { switch (Buffer1Length) { case ID_Win32PreServiceHook: KeWin32PreServiceHook = Buffer1; break; case ID_Win32PostServiceHook: KeWin32PostServiceHook = Buffer1; break; } break; } #endif /* Special case for stack frame dumps */ case 'DsoR': { KeRosDumpStackFrames((PULONG)Buffer1, Buffer1Length); break; } #if defined(KDBG) /* Register KDBG CLI callback */ case 'RbdK': { Result = KdbRegisterCliCallback(Buffer1, Buffer1Length); break; } #endif /* KDBG */ #endif /* DBG */ default: DPRINT1("Invalid debug service call!\n"); HalDisplayString("Invalid debug service call!\r\n"); break; } return Result; }
VOID KeDumpMachineState ( IN PKPROCESSOR_STATE ProcessorState, IN PCHAR Buffer, IN PULONG BugCheckParameters, IN ULONG NumberOfParameters, IN PKE_BUGCHECK_UNICODE_TO_ANSI UnicodeToAnsiRoutine ) /*++ Routine Description: This function formats and displays the machine state at the time of the to bug check. Arguments: ProcessorState - Supplies a pointer to the processor's state Buffer - Supplies a pointer to a buffer to be used to output machine state information. BugCheckParameters - Supplies additional bugcheck information NumberOfParameters - sizeof BugCheckParameters array UnicodeToAnsiRoutine - Supplies a pointer to a routine to convert Unicode strings to Ansi strings without touching paged translation tables. Return Value: None. --*/ { PLIST_ENTRY ModuleListHead; PLIST_ENTRY Next; ULONG StackAddr; ULONG PossiblePc; ULONG Index, NoLines; ULONG DisplayWidth, DisplayHeight; ULONG CursorColumn, CursorRow; ULONG i, j; PLDR_DATA_TABLE_ENTRY DataTableEntry; PVOID ImageBase; PKPRCB Prcb; UCHAR AnsiBuffer[ 32 ]; ULONG DateStamp; // // Query display parameters. // HalQueryDisplayParameters(&DisplayWidth, &DisplayHeight, &CursorColumn, &CursorRow); // // At this point the context record contains the machine state at the // call to bug check. // // Put out the system version and the title line with the PSR and FSR. // // // Check to see if any BugCheckParameters are valid code addresses. // If so, print them for the user // NoLines = 8; for (i=0; i < NumberOfParameters; i++) { ImageBase = KiPcToFileHeader((PVOID) BugCheckParameters[i], &DataTableEntry); if (ImageBase == NULL) { continue; } sprintf (Buffer, "*** Address %08lx has base at %08lx - %-12.12s\n", BugCheckParameters[i], ImageBase, (*UnicodeToAnsiRoutine)( &DataTableEntry->BaseDllName, AnsiBuffer, sizeof( AnsiBuffer ))); HalDisplayString(Buffer); NoLines++; } Prcb = KeGetCurrentPrcb(); if (Prcb->CpuID) { sprintf(Buffer, "\n\nCPUID:%.12s %x.%x.%x", Prcb->VendorString, Prcb->CpuType, Prcb->CpuStep >> 8, Prcb->CpuStep & 0x0f ); } else {
BOOLEAN HalInitSystem ( IN ULONG Phase, IN PLOADER_PARAMETER_BLOCK LoaderBlock ) /*++ Routine Description: This function initializes the Hardware Architecture Layer (HAL) for a MIPS R3000 or R4000 system. Arguments: Phase - Supplies the initialization phase (zero or one). LoaderBlock - Supplies a pointer to a loader parameter block. Return Value: A value of TRUE is returned is the initialization was successfully complete. Otherwise a value of FALSE is returend. --*/ { PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; PLIST_ENTRY NextMd; PKPRCB Prcb; ULONG BuildType = 0; Prcb = KeGetCurrentPrcb(); if (Phase == 0) { // // Phase 0 initialization. // // Verify that the processor block major version number conform // to the system that is being loaded. // if (Prcb->MajorVersion != PRCB_MAJOR_VERSION) { KeBugCheck(MISMATCHED_HAL); } // // Set the number of process id's and TB entries. // **((PULONG *)(&KeNumberProcessIds)) = 256; **((PULONG *)(&KeNumberTbEntries)) = 48; // // Set the time increment value. // HalpCurrentTimeIncrement = MAXIMUM_INCREMENT; HalpNextTimeIncrement = MAXIMUM_INCREMENT; HalpNextIntervalCount = 0; KeSetTimeIncrement(MAXIMUM_INCREMENT, MINIMUM_INCREMENT); LessThan16Mb = TRUE; SecondaryCachePurgeBaseAddress = NULL; NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; while (NextMd != &LoaderBlock->MemoryDescriptorListHead) { Descriptor = CONTAINING_RECORD( NextMd, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry ); // To purge the secondary cache on an ArcStation I, a valid Firmware Permanent // region must be found that starts on a 512 KB boundry and is at least // 512 KB long. The secondary cache is purged by reading from the appropriate // range of this 512 KB region for the page being purged. if (Descriptor->MemoryType == LoaderFirmwarePermanent && (Descriptor->BasePage % 128)==0 && Descriptor->PageCount>=128) { SecondaryCachePurgeBaseAddress = (PVOID)(KSEG0_BASE | (Descriptor->BasePage*4096)); Descriptor->BasePage+=128; Descriptor->PageCount-=128; } if (Descriptor->BasePage + Descriptor->PageCount > 0x1000) { LessThan16Mb = FALSE; } NextMd = Descriptor->ListEntry.Flink; } if (SecondaryCachePurgeBaseAddress==NULL) { HalDisplayString("ERROR : A valid Firmware Permanent area does not exist\n"); KeBugCheck(PHASE0_INITIALIZATION_FAILED); } // // Determine the size need for map buffers. If this system has // memory with a physical address of greater than // MAXIMUM_PHYSICAL_ADDRESS, then allocate a large chunk; otherwise, // allocate a small chunk. // if (LessThan16Mb) { // // Allocate a small set of map buffers. They are only need for // slave DMA devices. // HalpMapBufferSize = INITIAL_MAP_BUFFER_SMALL_SIZE; } else { // // Allocate a larger set of map buffers. These are used for // slave DMA controllers and Isa cards. // HalpMapBufferSize = INITIAL_MAP_BUFFER_LARGE_SIZE; } HalpMapBufferPhysicalAddress.LowPart = HalpAllocPhysicalMemory (LoaderBlock, MAXIMUM_ISA_PHYSICAL_ADDRESS, HalpMapBufferSize >> PAGE_SHIFT, FALSE); HalpMapBufferPhysicalAddress.HighPart = 0; if (!HalpMapBufferPhysicalAddress.LowPart) { // // There was not a satisfactory block. Clear the allocation. // HalpMapBufferSize = 0; } // // Initialize interrupts. // HalpInitializeInterrupts(); return TRUE; } else { // // Phase 1 initialization. // if (IoSpaceAlreadyMapped == FALSE) {
ULONG DetectMPS( OUT PBOOLEAN IsConfiguredMp ) /*++ Routine Description: This function is called from HalInitializeProcessors to determine if this is an appropriate system to run the MPS hal on. The recommended detection mechanism is: if ( MPS information does not exist ) then System is not MPS compliant. Return false. In MP table: if ( number IO APICs < 1 ) then Not a MPS System - return false if ( # CPUs = 1 ) then Found a Single Processor MPS System else Found a MP MPS System A side effect of this routine is the mapping of the IO UNits and Local unit virtual addresses. Return TRUE Arguments: IsConfiguredMp - TRUE if this machine is a MP instance of the MPS spec, else FALSE. Return Value: 0 - if not a MPS 1 - if MPS */ { UCHAR ApicVersion, i; PUCHAR LocalApic; PPCMPIOAPIC IoEntryPtr; // // Initialize MpInfo table // RtlZeroMemory (&HalpMpInfoTable, sizeof HalpMpInfoTable); // // Set the return Values to the default // *IsConfiguredMp = FALSE; // // See if there is a MP Table // #if 1 if ((PcMpTablePtr = GetPcMpTable()) == NULL) { FAILMSG (rgzNoMpsTable); return(FALSE); } #else //******** //******** HACK! To make down level 1.0 machine work //******** if ((PcMpTablePtr = MPS10_GetPcMpTable()) == NULL) { FAILMSG (rgzNoMpsTable); return(FALSE); } #endif #ifdef SETUP // During setup, if we detected a default MPS configuration, we have // no more checking to do. if (PcMpTablePtr == (struct PcMpTable *) DEFAULT_MPS_INDICATOR) { *IsConfiguredMp = TRUE; return(TRUE); } #endif // SETUP #if DEBUGGING HalpDisplayConfigTable(); #endif // We have a MPS table. Initialize a HAL specific MP information // structure that gets information from the MPS table. HalpInitMpInfo(PcMpTablePtr); // Verify the information in the MPS table as best as we can. if (HalpMpInfoTable.IOApicCount == 0) { // // Someone Has a MP Table and no IO Units -- Weird // We have to assume the BIOS knew what it was doing // when it built the table. so .. // FAILMSG (rgzNoApic); return (FALSE); } // // It's a MPS System. It could be a UP System though. // #ifdef SETUP // // If this is a MPS (MPS) compliant system, but has only 1 processor, // for now we want to install a standard UP kernel and HAL. // if (HalpMpInfoTable.ProcessorCount <= 1) { return FALSE; } #endif if (HalpMpInfoTable.ProcessorCount > 1) { *IsConfiguredMp = TRUE; } HalpMpInfoTable.LocalApicBase = (ULONG) PcMpTablePtr->LocalApicAddress; LocalApic = (PUCHAR) HalpMapPhysicalMemoryWriteThrough( (PVOID) HalpMpInfoTable.LocalApicBase,1); #ifndef SETUP HalpRemapVirtualAddress ( (PVOID) LOCALAPIC, (PVOID) HalpMpInfoTable.LocalApicBase, TRUE ); #endif ApicVersion = (UCHAR) *(LocalApic + LU_VERS_REGISTER); if (ApicVersion > 0x1f) { // // Only known Apics are 82489dx with version 0.x and // Embedded Apics with version 1.x (where x is don't care) // // Return of 0xFF? Can't have an MPS system without a Local Unit. // #ifdef DEBUGGING sprintf(Cbuf, "HALMPS: apic version %x, read from %x\n", ApicVersion, LocalApic + LU_VERS_REGISTER); HalDisplayString(Cbuf); #endif FAILMSG (rgzBadApicVersion); return (FALSE); } #ifdef SETUP // // MP MPS table, and the local APIC ID looked OK. // return TRUE; #endif //SETUP #ifdef DEBUGGING if ((ApicVersion & 0xf0) == 0) { if (HalpMpInfoTable.ApicVersion != APIC_82489DX) HalDisplayString("HAL:Invalid Local Apic version in MP table\n"); else { sprintf(Cbuf, "HAL: DetectMPS: Found 82489DX Local APIC (Ver 0x%x) at 0x%lx\n", ApicVersion, LocalApic); HalDisplayString(Cbuf); } } else { sprintf(Cbuf, "HAL: DetectMPS: Found Embedded Local APIC (Ver 0x%x) at 0x%lx\n", ApicVersion, LocalApic); HalDisplayString(Cbuf); } #endif // DEBUGGING IoEntryPtr = HalpMpInfoTable.IoApicEntryPtr; for(i=0; i < HalpMpInfoTable.IOApicCount; i++, IoEntryPtr++) { if (IoEntryPtr->IoApicFlag & IO_APIC_ENABLED) { // // Verify the existance of the IO Units // HalpMpInfoTable.IoApicPhys[i] = (ULONG) IoEntryPtr->IoApicAddress; HalpMpInfoTable.IoApicBase[i] = (PULONG) HalpMapPhysicalMemoryWriteThrough( (PVOID)(IoEntryPtr->IoApicAddress), 1); // // Verify the existance of the IO Unit // if (!(HalpVerifyIOUnit((PUCHAR)HalpMpInfoTable.IoApicBase[i]))) { FAILMSG (rgzApicNotVerified); return (FALSE); } } } DBGMSG("HAL: DetectMPS: MPS system found - Returning TRUE\n"); return(TRUE); }
BOOLEAN HalHandleNMI( IN PKINTERRUPT Interrupt, IN PVOID ServiceContext ) /*++ Routine Description: This function is called when an EISA NMI occurs. It prints the appropriate status information and bugchecks. Arguments: Interrupt - Supplies a pointer to the interrupt object ServiceContext - Bug number to call bugcheck with. Return Value: Returns TRUE. --*/ { LEGO_SRV_MGMT SmRegister; UCHAR NmiControl, NmiStatus; BOOLEAN GotSerr, GotIochk, GotSmFan, GotSmTemp, GotHalt; NMIcount++; #if DBG if (NMIcount<5) { DbgPrint("II<NMI><"); } if (NMIcount % 100 == 0) { DbgPrint("II<NMI><%08x><", NMIcount); } #endif GotSerr = GotIochk = GotSmFan = GotSmTemp = GotHalt = FALSE; // // Set the Eisa NMI disable bit. We do this to mask further NMI // interrupts while we're servicing this one. // NmiControl = READ_PORT_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable); ((PNMI_ENABLE)(&NmiControl))->NmiDisable = 1; WRITE_PORT_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable, NmiControl); #ifdef DBG DbgPrint("HalHandleNMI: wrote 0x%x to NmiEnable\n", NmiControl); #endif NmiStatus = READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus); if (NmiStatus & 0x80) { GotSerr = TRUE; #ifdef DBG DbgPrint("HalHandleNMI: Parity Check / Parity Error\n"); DbgPrint("HalHandleNMI: NMI Status = 0x%x\n", NmiStatus); #endif HalAcquireDisplayOwnership(NULL); HalDisplayString ("NMI: Parity Check / Parity Error\n"); KeBugCheck(NMI_HARDWARE_FAILURE); return (TRUE); } if (NmiStatus & 0x40) { GotIochk = TRUE; #ifdef DBG DbgPrint("HalHandleNMI: Channel Check / IOCHK\n"); DbgPrint("HalHandleNMI: NMI Status = 0x%x\n", NmiStatus); #endif HalAcquireDisplayOwnership(NULL); HalDisplayString ("NMI: Channel Check / IOCHK\n"); KeBugCheck(NMI_HARDWARE_FAILURE); return (TRUE); } // Read server management register // Events that can be reported as NMI are: // Enclosure temperature too high // CPU Fan failure // // For now, generate a bugcheck. // [wem] Future: perform secondary dispatch to give // driver shot at reporting problem. // SmRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva ); GotSmFan = SmRegister.CpuFanFailureNmi == 1; GotSmTemp = SmRegister.EnclTempFailureNmi == 1; if (GotSmFan || GotSmTemp) { #ifdef DBG DbgPrint("HalHandleNMI: Server management NMI\n"); DbgPrint("HalHandleNMI: NMI Status = 0x%x\n", NmiStatus); DbgPrint("HalHandleNMI: Server Management Status = 0x%x\n", SmRegister); #endif // // If secondary dispatch enabled, do it now. // #if 0 if (HalpLegoDispatchNmi && ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[SM_ERROR_VECTOR])( PCR->InterruptRoutine[SM_ERROR_VECTOR], TrapFrame) ) { return TRUE; } #endif // // Build uncorrectable error frame and // prepare for orderly shutdown // // The delayed shutdown depends on watchdog timer support // A power off cannot be directly done since KeBugChk() turns // off interrupts, so there's no way to get control back. // // WARNING: Pick a delay that allows a dump to complete. // LegoServerMgmtReportFatalError(SmRegister.All); LegoServerMgmtDelayedShutdown(8); // Issue reset in 8 seconds HalAcquireDisplayOwnership(NULL); HalDisplayString ("NMI: Hardware Failure -- "); HalDisplayString ((SmRegister.CpuFanFailureNmi==1) ? "CPU fan failed." : "Enclosure termperature too high."); HalDisplayString ("\nSystem Power Down will be attempted in 8 seconds...\n\n"); KeBugCheck(NMI_HARDWARE_FAILURE); return (TRUE); } // // Halt button was hit. // // [wem] Perform second-level dispatch here too? // if (!GotSerr && !GotIochk && !GotSmFan && !GotSmTemp) { // // If secondary dispatch enabled, do it now. // #if 0 if (HalpLegoDispatchHalt && ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[HALT_BUTTON_VECTOR])( PCR->InterruptRoutine[HALT_BUTTON_VECTOR], TrapFrame) ) { return TRUE; } #endif GotHalt = TRUE; HalDisplayString ("NMI: Halt button pressed.\n"); if (HalpHaltButtonBreak) { DbgBreakPoint(); } return (TRUE); } // // Clear and re-enable SERR# and IOCHK#, then re-enable NMI // #ifdef DBG DbgPrint("HalHandleNMI: Shouldn't get here!\n"); #endif if (GotSerr) { #ifdef DBG DbgPrint("HalHandleNMI: Resetting SERR#; NMI count = %d\n", NMIcount); #endif // // Reset SERR# (and disable it), then re-enable it. // WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus, 0x04); WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus, 0); } if (GotIochk) { #ifdef DBG DbgPrint("HalHandleNMI: Resetting IOCHK#; NMI count = %d\n", NMIcount); #endif // // Reset IOCHK# (and disable it), then re-enable it. // WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus, 0x08); WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus, 0); } if (GotSmFan || GotSmTemp) { // // Reset Server management condition. // // Interrupt must be cleared or the NMI will continue // to occur. // SmRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva ); if (GotSmFan) { SmRegister.CpuFanFailureNmi = 1; } else { SmRegister.EnclTempFailureNmi = 1; } WRITE_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva, SmRegister.All ); } // // Clear the Eisa NMI disable bit. This re-enables NMI interrupts, // now that we're done servicing this one. // NmiControl = READ_PORT_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable); ((PNMI_ENABLE)(&NmiControl))->NmiDisable = 0; WRITE_PORT_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable, NmiControl); #ifdef DBG DbgPrint("HalHandleNMI: wrote 0x%x to NmiEnable\n", NmiControl); #endif return(TRUE); }
VOID HalpCiaReportFatalError( VOID ) /*++ Routine Description: This function reports and interprets a fatal hardware error detected by the CIA chipset. It is assumed that HalGetDisplayOwnership() has been called prior to this function. Arguments: None. Return Value: None. --*/ { UCHAR OutBuffer[ MAX_ERROR_STRING ]; CIA_ERR CiaError; CIA_STAT CiaStat; CIA_SYN CiaSyn; CIA_CONTROL CiaControl; CIA_MEM_ERR0 MemErr0; CIA_MEM_ERR1 MemErr1; CIA_PCI_ERR0 PciErr0; CIA_PCI_ERR1 PciErr1; CIA_PCI_ERR2 PciErr2; CIA_CPU_ERR0 CpuErr0; CIA_CPU_ERR1 CpuErr1; PUNCORRECTABLE_ERROR uncorr = NULL; PCIA_UNCORRECTABLE_FRAME ciauncorr = NULL; PEXTENDED_ERROR PExtErr; // // We will Build the uncorrectable error frame as we read // the registers to report the error to the blue screen. // We generate the extended error frame as we generate // extended messages to print to the screen. // if(PUncorrectableError){ uncorr = (PUNCORRECTABLE_ERROR) &PUncorrectableError->UncorrectableFrame; ciauncorr = (PCIA_UNCORRECTABLE_FRAME) PUncorrectableError->UncorrectableFrame.RawSystemInformation; PExtErr = &PUncorrectableError->UncorrectableFrame.ErrorInformation; } if(uncorr){ uncorr->Flags.ProcessorInformationValid = 1; HalpGetProcessorInfo(&uncorr->ReportingProcessor); } if(ciauncorr) HalpBuildCiaConfigurationFrame(&ciauncorr->Configuration); // // Read the CIA Error register and decode its contents: // CiaError.all = (ULONG)READ_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr ); if(ciauncorr) ciauncorr->CiaErr = CiaError.all ; // // Read the rest of the error registers and then unlock them by // writing to CIA_ERR // CiaStat.all = (ULONG)READ_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaStat ); CiaSyn.all = (ULONG)READ_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaSyn ); MemErr0.all = (ULONG)READ_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->MemErr0 ); MemErr1.all = (ULONG)READ_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->MemErr1 ); PciErr0.all = (ULONG)READ_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr0 ); PciErr1.PciAddress = (ULONG)READ_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr1 ); PciErr2.PciAddress = (ULONG)READ_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr2 ); CpuErr0.all = (ULONG)READ_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CpuErr0 ); CpuErr1.all = (ULONG)READ_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CpuErr1 ); CiaControl.all = READ_CIA_REGISTER( &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCtrl); if(ciauncorr){ ciauncorr->CiaStat = CiaStat.all; ciauncorr->CiaSyn = CiaSyn.all; ciauncorr->MemErr0 = MemErr0.all; ciauncorr->MemErr1 = MemErr1.all; ciauncorr->PciErr0 = PciErr0.all; ciauncorr->PciErr1 = PciErr1.PciAddress; ciauncorr->PciErr2 = (ULONG)READ_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr2 ); ciauncorr->CpuErr0 = CpuErr0.all; ciauncorr->CpuErr1 = CpuErr1.all; ciauncorr->ErrMask = (ULONG)READ_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->ErrMask ); } WRITE_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr, CiaError.all ); sprintf( OutBuffer, "CIA_CTRL : %08x\n", CiaControl.all ); HalDisplayString( OutBuffer ); DbgPrint( OutBuffer ); sprintf( OutBuffer, "CIA_ERR : %08x\n", CiaError.all ); HalDisplayString( OutBuffer ); DbgPrint( OutBuffer ); sprintf( OutBuffer, "CIA_STAT : %08x\n", CiaStat.all ); HalDisplayString( OutBuffer ); DbgPrint( OutBuffer ); sprintf( OutBuffer, "CIA_SYN : %08x\n", CiaSyn.all ); HalDisplayString( OutBuffer ); DbgPrint( OutBuffer ); sprintf( OutBuffer, "PCI_ERR0 : %08x\n", PciErr0.all ); HalDisplayString( OutBuffer ); DbgPrint( OutBuffer ); sprintf( OutBuffer, "PCI_ERR1 : %08x\n", PciErr1.PciAddress ); HalDisplayString( OutBuffer ); DbgPrint( OutBuffer ); sprintf( OutBuffer, "PCI_ERR2 : %08x\n", PciErr2.PciAddress ); HalDisplayString( OutBuffer ); DbgPrint( OutBuffer ); sprintf( OutBuffer, "CPU_ERR0 : %08x\n", CpuErr0.all ); HalDisplayString( OutBuffer ); DbgPrint( OutBuffer ); sprintf( OutBuffer, "CPU_ERR1 : %08x\n", CpuErr1.all ); HalDisplayString( OutBuffer ); DbgPrint( OutBuffer ); sprintf( OutBuffer, "MEM_ERR0 : %08x\n", MemErr0.all ); HalDisplayString( OutBuffer ); DbgPrint( OutBuffer ); sprintf( OutBuffer, "MEM_ERR1 : %08x\n", MemErr1.all ); HalDisplayString( OutBuffer ); DbgPrint( OutBuffer ); // // If no valid error then no interpretation. // if ( CiaError.ErrValid == 0 ){ return; // No CIA error detected } // // Interpret any detected errors: // if ( CiaError.UnCorErr == 1 ){ sprintf( OutBuffer, "CIA Uncorrectable ECC error, Addr=%x%x, Cmd=%x\n", CpuErr1.Addr34_32, // bits 34:32 CpuErr0.Addr, // bits 31:4 CpuErr1.Cmd ); if(uncorr){ uncorr->Flags.ErrorStringValid = 1; strcpy( uncorr->ErrorString, OutBuffer); } } else if ( CiaError.CpuPe == 1 ){ sprintf( OutBuffer, "EV5 bus parity error, Addr=%x%x, Cmd=%x\n", CpuErr1.Addr34_32, // bits 34:32 CpuErr0.Addr, // bits 31:4 CpuErr1.Cmd ); if(uncorr){ uncorr->Flags.ErrorStringValid = 1; strcpy( uncorr->ErrorString, OutBuffer); } } else if ( CiaError.MemNem == 1 ){ sprintf( OutBuffer, "CIA Access to non-existent memory, Source=%s, Addr=%x%x\n", MemErr1.MemPortSrc == 1 ? "DMA" : "CPU", MemErr1.MemPortSrc == 1 ? 0 : MemErr1.Addr33_32, MemErr1.MemPortSrc == 1 ? PciErr1.PciAddress : MemErr0.Addr31_4 ); if(uncorr){ uncorr->Flags.ErrorStringValid = 1; strcpy( uncorr->ErrorString, OutBuffer); } } else if ( CiaError.PciSerr == 1 ){ sprintf( OutBuffer, "PCI bus SERR detected, Cmd=%x, Window=%d, Addr=%x\n", PciErr0.Cmd, PciErr0.Window, PciErr1.PciAddress ); if(uncorr){ uncorr->Flags.ErrorStringValid = 1; strcpy( uncorr->ErrorString, OutBuffer); uncorr->Flags.AddressSpace = IO_SPACE; uncorr->Flags.PhysicalAddressValid = 1; uncorr->PhysicalAddress = PciErr1.PciAddress; uncorr->Flags.ExtendedErrorValid = 1; PExtErr->IoError.Interface = PCIBus; PExtErr->IoError.BusNumber = 0; PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress; } } else if ( CiaError.PciPerr == 1 ){ sprintf( OutBuffer, "PCI bus Data Parity error, Cmd=%x, Window=%d, Addr=%x\n", PciErr0.Cmd, PciErr0.Window, PciErr1.PciAddress ); if(uncorr){ uncorr->Flags.ErrorStringValid = 1; strcpy( uncorr->ErrorString, OutBuffer); uncorr->Flags.AddressSpace = IO_SPACE; uncorr->Flags.PhysicalAddressValid = 1; uncorr->PhysicalAddress = PciErr1.PciAddress; uncorr->Flags.ExtendedErrorValid = 1; PExtErr->IoError.Interface = PCIBus; PExtErr->IoError.BusNumber = 0; PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress; } } else if ( CiaError.PciAddrPe == 1 ){ sprintf( OutBuffer, "Pci bus Address Parity error, Cmd=%x, Window=%x, Addr=%x\n", PciErr0.Cmd, PciErr0.Window, PciErr1.PciAddress ); if(uncorr){ uncorr->Flags.ErrorStringValid = 1; strcpy( uncorr->ErrorString, OutBuffer); uncorr->Flags.AddressSpace = IO_SPACE; uncorr->Flags.PhysicalAddressValid = 1; uncorr->PhysicalAddress = PciErr1.PciAddress; uncorr->Flags.ExtendedErrorValid = 1; PExtErr->IoError.Interface = PCIBus; PExtErr->IoError.BusNumber = 0; PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress; } } else if ( CiaError.RcvdMasAbt == 1 ){ sprintf( OutBuffer, "PCI Master abort occurred, Cmd=%x, Window=%x, Addr=%x\n", PciErr0.Cmd, PciErr0.Window, PciErr1.PciAddress ); if(uncorr){ uncorr->Flags.ErrorStringValid = 1; strcpy( uncorr->ErrorString, OutBuffer); uncorr->Flags.AddressSpace = IO_SPACE; uncorr->Flags.PhysicalAddressValid = 1; uncorr->PhysicalAddress = PciErr1.PciAddress; uncorr->Flags.ExtendedErrorValid = 1; PExtErr->IoError.Interface = PCIBus; PExtErr->IoError.BusNumber = 0; PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress; } } else if ( CiaError.RcvdTarAbt == 1 ){ sprintf( OutBuffer, "PCI Target abort occurred, Cmd=%x, Window=%x, Addr=%x\n", PciErr0.Cmd, PciErr0.Window, PciErr1.PciAddress ); if(uncorr){ uncorr->Flags.ErrorStringValid = 1; strcpy( uncorr->ErrorString, OutBuffer); uncorr->Flags.AddressSpace = IO_SPACE; uncorr->Flags.PhysicalAddressValid = 1; uncorr->PhysicalAddress = PciErr1.PciAddress; uncorr->Flags.ExtendedErrorValid = 1; PExtErr->IoError.Interface = PCIBus; PExtErr->IoError.BusNumber = 0; PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress; } } else if ( CiaError.PaPteInv == 1 ){ sprintf( OutBuffer, "Invalid Scatter/Gather PTE, Cmd=%x, Window=%x, Addr=%x\n", PciErr0.Cmd, PciErr0.Window, PciErr1.PciAddress ); if(uncorr){ uncorr->Flags.ErrorStringValid = 1; strcpy( uncorr->ErrorString, OutBuffer); uncorr->Flags.AddressSpace = IO_SPACE; uncorr->Flags.PhysicalAddressValid = 1; uncorr->PhysicalAddress = PciErr1.PciAddress; uncorr->Flags.ExtendedErrorValid = 1; PExtErr->IoError.Interface = PCIBus; PExtErr->IoError.BusNumber = 0; PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress; } } else if ( CiaError.FromWrtErr == 1 ){ sprintf( OutBuffer, "Write to Flash ROM with FROM_WRT_EN clear" ); if(uncorr){ uncorr->Flags.ErrorStringValid = 1; strcpy( uncorr->ErrorString, OutBuffer); } } else if ( CiaError.IoaTimeout == 1){ sprintf( OutBuffer, "PCI bus I/O timeout occurred, Cmd=%x, Window=%x, Addr=%x\n", PciErr0.Cmd, PciErr0.Window, PciErr1.PciAddress ); if(uncorr){ uncorr->Flags.ErrorStringValid = 1; strcpy( uncorr->ErrorString, OutBuffer); uncorr->Flags.AddressSpace = IO_SPACE; uncorr->Flags.PhysicalAddressValid = 1; uncorr->PhysicalAddress = PciErr1.PciAddress; uncorr->Flags.ExtendedErrorValid = 1; PExtErr->IoError.Interface = PCIBus; PExtErr->IoError.BusNumber = 0; PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress; } } // // Output the detected error message: // HalDisplayString( "\n" ); HalDisplayString( OutBuffer ); #if HALDBG DbgPrint( OutBuffer ); #endif // // Check for lost errors and output message if any occurred: // if ( (CiaError.all & CIA_ERR_LOST_MASK) != 0 ){ HalDisplayString("\nCIA Lost errors were detected\n\n"); } return; // Fatal error detected }
VOID HalpNMIInterrupt( ULONG DumpStatus ) /*++ Routine Description: This routine was called when dump swich was pressed or Fatal NMI occued. We call KeBugCheckEx() in order to Dump. Arguments: DumpStatus: Dump Switch Status 0 Dump Switch was not pressed. 1 Dump Switch was pressed. Return Value: None. --*/ { ULONG NMISource; ULONG MemoryFailed; LARGE_INTEGER InvalidAddressValue; LARGE_INTEGER EccDiagnosticValue; UCHAR Buffer[100]; HalpChangePanicFlag(16, (UCHAR)(0x01 | (4 * DumpStatus)), 0x10); // S014,S018 // // M007,M012 // Check DumpStatus.and Display NMI status. // if (DumpStatus == 1) { HalDisplayString("HAL:Dump Switch Pressed!\n"); } else { HalDisplayString("HAL:NMI occured\n"); } // // Display NMI registers // NMISource = READ_REGISTER_ULONG(&DMA_CONTROL->NmiSource.Long); sprintf(Buffer, "HAL:NmiSource register = %x\n",NMISource); HalDisplayString((UCHAR *)Buffer); MemoryFailed = READ_REGISTER_ULONG( &((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->MemoryFailedAddress.Long); sprintf(Buffer, "HAL:MemoryFailedAddress register = %x\n", MemoryFailed); HalDisplayString((UCHAR *)Buffer); READ_REGISTER_DWORD( (PVOID)&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->InvalidAddress, &InvalidAddressValue); sprintf(Buffer, "HAL:Processor Invalid Address register = %x %x\n", InvalidAddressValue.HighPart,InvalidAddressValue.LowPart); HalDisplayString((UCHAR *)Buffer); READ_REGISTER_DWORD( (PVOID)&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->EccDiagnostic, &EccDiagnosticValue); sprintf(Buffer, "HAL:EccDiagnostic register = %x %x\n", EccDiagnosticValue.HighPart,EccDiagnosticValue.LowPart); HalDisplayString((UCHAR *)Buffer); // // M007,M008 // call KeBugCheckEx() for dump. // KeBugCheckEx(NMI_HARDWARE_FAILURE,DumpStatus,NMISource,0,0); return; }
PVOID NTAPI PciGetAcpiTable(IN ULONG TableCode) { PDESCRIPTION_HEADER Header; PACPI_BIOS_MULTI_NODE AcpiMultiNode; PRSDT Rsdt; PXSDT Xsdt; ULONG EntryCount, TableLength, Offset, CurrentEntry; PVOID TableBuffer, MappedAddress; PHYSICAL_ADDRESS PhysicalAddress; NTSTATUS Status; /* Try to find the RSDT or XSDT */ Status = PciAcpiFindRsdt(&AcpiMultiNode); if (!NT_SUCCESS(Status)) { /* No ACPI on the machine */ DPRINT1("AcpiFindRsdt() Failed!\n"); return NULL; } /* Map the RSDT with the minimum size allowed */ MappedAddress = MmMapIoSpace(AcpiMultiNode->RsdtAddress, sizeof(DESCRIPTION_HEADER), MmNonCached); Header = MappedAddress; if (!Header) return NULL; /* Check how big the table really is and get rid of the temporary header */ TableLength = Header->Length; MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER)); Header = NULL; /* Map its true size */ MappedAddress = MmMapIoSpace(AcpiMultiNode->RsdtAddress, TableLength, MmNonCached); Rsdt = MappedAddress; Xsdt = MappedAddress; ExFreePoolWithTag(AcpiMultiNode, 0); if (!Rsdt) return NULL; /* Validate the table's signature */ if ((Rsdt->Header.Signature != RSDT_SIGNATURE) && (Rsdt->Header.Signature != XSDT_SIGNATURE)) { /* Very bad: crash */ HalDisplayString("RSDT table contains invalid signature\r\n"); MmUnmapIoSpace(Rsdt, TableLength); return NULL; } /* Smallest RSDT/XSDT is one without table entries */ Offset = FIELD_OFFSET(RSDT, Tables); if (Rsdt->Header.Signature == XSDT_SIGNATURE) { /* Figure out total size of table and the offset */ TableLength = Xsdt->Header.Length; if (TableLength < Offset) Offset = Xsdt->Header.Length; /* The entries are each 64-bits, so count them */ EntryCount = (TableLength - Offset) / sizeof(PHYSICAL_ADDRESS); } else { /* Figure out total size of table and the offset */ TableLength = Rsdt->Header.Length; if (TableLength < Offset) Offset = Rsdt->Header.Length; /* The entries are each 32-bits, so count them */ EntryCount = (TableLength - Offset) / sizeof(ULONG); } /* Start at the beginning of the array and loop it */ for (CurrentEntry = 0; CurrentEntry < EntryCount; CurrentEntry++) { /* Are we using the XSDT? */ if (Rsdt->Header.Signature != XSDT_SIGNATURE) { /* Read the 32-bit physical address */ PhysicalAddress.QuadPart = Rsdt->Tables[CurrentEntry]; } else { /* Read the 64-bit physical address */ PhysicalAddress = Xsdt->Tables[CurrentEntry]; } /* Map this table */ Header = MmMapIoSpace(PhysicalAddress, sizeof(DESCRIPTION_HEADER), MmNonCached); if (!Header) break; /* Check if this is the table that's being asked for */ if (Header->Signature == TableCode) { /* Allocate a buffer for it */ TableBuffer = ExAllocatePoolWithTag(PagedPool, Header->Length, PCI_POOL_TAG); if (!TableBuffer) break; /* Copy the table into the buffer */ RtlCopyMemory(TableBuffer, Header, Header->Length); } /* Done with this table, keep going */ MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER)); } if (Header) MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER)); return NULL; }
BOOLEAN HalpCiaMachineCheck( IN PEXCEPTION_RECORD ExceptionRecord, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: This routine is given control when an hard error is acknowledged by the CIA chipset. The routine is given the chance to correct and dismiss the error. Arguments: ExceptionRecord - Supplies a pointer to the exception record generated at the point of the exception. ExceptionFrame - Supplies a pointer to the exception frame generated at the point of the exception. TrapFrame - Supplies a pointer to the trap frame generated at the point of the exception. Return Value: TRUE is returned if the machine check has been handled and dismissed - indicating that execution can continue. FALSE is return otherwise. --*/ { CIA_ERR CiaError; // // Read the CIA error register to determine the source of the // error. // CiaError.all = READ_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr ); #if HALDBG DbgPrint( "Cia Mchk: 0x%x\n", CiaError.all ); #endif //HALDBG // // Check that an error is valid. If it is not this is a pretty // weird fatal condition. // if( CiaError.ErrValid == 0 ){ DbgPrint( "Error reported but error valid = 0, CiaErr = 0x%x\n", CiaError.all ); goto FatalError; } // // Check for any uncorrectable error other than a master abort // on a PCI transaction. Any of these other errors indicate a // fatal condition. // if( (CiaError.UnCorErr == 1) || // Uncorrectable error (CiaError.CpuPe == 1) || // Ev5 bus parity error (CiaError.MemNem == 1) || // Nonexistent memory error (CiaError.PciSerr == 1) || // PCI bus serr detected (CiaError.PciPerr == 1) || // PCI bus perr detected (CiaError.PciAddrPe == 1) || // PCI bus address parity error (CiaError.RcvdTarAbt == 1) || // Pci Target Abort (CiaError.PaPteInv == 1) || // Invalid Pte (CiaError.FromWrtErr == 1) || // Invalid write to flash rom (CiaError.IoaTimeout == 1) || // Io Timeout occurred (CiaError.LostUnCorErr == 1) || // Lost uncorrectable error (CiaError.LostCpuPe == 1) || // Lost Ev5 bus parity error (CiaError.LostMemNem == 1) || // Lost Nonexistent memory error (CiaError.LostPciPerr == 1) || // Lost PCI bus perr detected (CiaError.LostPciAddrPe == 1) || // Lost PCI address parity error (CiaError.LostRcvdMasAbt == 1) || // Lost Pci Master Abort (CiaError.LostRcvdTarAbt == 1) || // Lost Pci Target Abort (CiaError.LostPaPteInv == 1) || // Lost Invalid Pte (CiaError.LostFromWrtErr == 1) || // Lost Invalid write to flash rom (CiaError.LostIoaTimeout == 1) // Lost Io Timeout occurred ){ DbgPrint( "Explicit fatal error, CiaErr = 0x%x\n", CiaError.all ); goto FatalError; } // // Check for a PCI configuration read error. The CIA experiences // a master abort on a read to a non-existent PCI slot. // if( (CiaError.RcvdMasAbt == 1) && (HalpMasterAbortExpected != 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 original faulting instruction must // be a load with v0 as the destination register. Unfortunately, // machine checks are not precise exceptions so we may have exectued // many instructions since the faulting load. For EV5 a pair of // memory barrier instructions following the load will stall the pipe // waiting for load completion before the second memory barrier can // be issued. Therefore, we expect the exception PC to point to either // the load instruction of one of the two memory barriers. We will // assume that if the exception pc is not an mb that instead it // points to the load that machine checked. We must be careful to // not reexectute the load. // ALPHA_INSTRUCTION FaultingInstruction; BOOLEAN PreviousInstruction = FALSE; FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir); if( FaultingInstruction.Memory.Opcode != MEMSPC_OP ){ // // Exception pc does not point to a memory barrier, return // to the instruction after the exception pc. // TrapFrame->Fir += 4; } // // 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 error condition in CIA_ERR. // CiaError.all = 0; CiaError.RcvdMasAbt = 1; CiaError.ErrValid = 1; WRITE_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr, CiaError.all ); return TRUE; } //end if( (CiaError.RcvdMasAbt == 1) && (HalpMasterAbortExpected != 0) ) DbgPrint( "Unexpected master abort\n" ); // // The system is not well and cannot continue reliable execution. // Print some useful messages and return FALSE to indicate that the error // was not handled. // FatalError: DbgPrint( "Handling fatal error\n" ); // // Clear the error condition in the MCES register. // HalpUpdateMces( TRUE, TRUE ); // // Proceed to display the error. // HalAcquireDisplayOwnership(NULL); // // Display the dreaded banner. // HalDisplayString( "\nFatal system hardware error.\n\n" ); HalpCiaReportFatalError(); return( FALSE ); }
VOID KeDumpMachineState ( IN PKPROCESSOR_STATE ProcessorState, IN PCHAR Buffer, IN PULONG BugCheckParameters, IN ULONG NumberOfParameters, IN PKE_BUGCHECK_UNICODE_TO_ANSI UnicodeToAnsiRoutine ) /*++ Routine Description: This function formats and displays the machine state at the time of the to bug check. Arguments: ProcessorState - Supplies a pointer to a processor state record. Buffer - Supplies a pointer to a buffer to be used to output machine state information. BugCheckParameters - Supplies a pointer to an array of additional bug check information. NumberOfParameters - Suppiles the size of the bug check parameters array. UnicodeToAnsiRoutine - Supplies a pointer to a routine to convert Unicode strings to Ansi strings without touching paged translation tables. Return Value: None. --*/ { PCONTEXT ContextRecord; ULONG ControlPc; PLDR_DATA_TABLE_ENTRY DataTableEntry; ULONG DisplayColumn; ULONG DisplayHeight; ULONG DisplayRow; ULONG DisplayWidth; UNICODE_STRING DllName; ULONG EstablisherFrame; PRUNTIME_FUNCTION FunctionEntry; PVOID ImageBase; ULONG Index; BOOLEAN InFunction; ULONG LastStack; PLIST_ENTRY ModuleListHead; PLIST_ENTRY NextEntry; ULONG NextPc; ULONG StackLimit; UCHAR AnsiBuffer[ 32 ]; ULONG DateStamp; // // Call the HAL to force all external interrupts to be disabled // at the interrupt controller. PowerPC optimization does not // do this when raising to high level. // for (Index = 0; Index < MAXIMUM_VECTOR; Index++) { HalDisableSystemInterrupt(Index, HIGH_LEVEL); } // // Query display parameters. // HalQueryDisplayParameters(&DisplayWidth, &DisplayHeight, &DisplayColumn, &DisplayRow); // // Display any addresses that fall within the range of any module in // the loaded module list. // for (Index = 0; Index < NumberOfParameters; Index += 1) { ImageBase = KiPcToFileHeader((PVOID)*BugCheckParameters, &ImageBase, &DataTableEntry); if (ImageBase != NULL) { sprintf(Buffer, "*** %08lX has base at %08lX - %s\n", *BugCheckParameters, ImageBase, (*UnicodeToAnsiRoutine)( &DataTableEntry->BaseDllName, AnsiBuffer, sizeof( AnsiBuffer ))); HalDisplayString(Buffer); } BugCheckParameters += 1; } // // Virtually unwind to the caller of bug check. // ContextRecord = &ProcessorState->ContextFrame; LastStack = ContextRecord->Gpr1; ControlPc = ContextRecord->Lr - 4; NextPc = ControlPc; FunctionEntry = KiLookupFunctionEntry(ControlPc); if (FunctionEntry != NULL) { NextPc = RtlVirtualUnwind(ControlPc, FunctionEntry, ContextRecord, &InFunction, &EstablisherFrame, NULL, 0, 0xffffffff); } // // At this point the context record contains the machine state at the // call to bug check. // // Put out the machine state at the time of the bugcheck. // sprintf(Buffer, "\n Machine State at Call to Bug Check IAR:%08lX MSR:%08lX\n", ContextRecord->Lr, ContextRecord->Msr); HalDisplayString(Buffer); // // Format and output the integer registers. // sprintf(Buffer, " R0:%8lX R1:%8lX R2:%8lX R3:%8lX R4:%8lX R5:%8lX\n", ContextRecord->Gpr0, ContextRecord->Gpr1, ContextRecord->Gpr2, ContextRecord->Gpr3, ContextRecord->Gpr4, ContextRecord->Gpr5); HalDisplayString(Buffer); sprintf(Buffer, " R6:%8lX R7:%8lX R8:%8lX R9:%8lX R10:%8lX R11:%8lX\n", ContextRecord->Gpr6, ContextRecord->Gpr7, ContextRecord->Gpr8, ContextRecord->Gpr9, ContextRecord->Gpr10, ContextRecord->Gpr11); HalDisplayString(Buffer); sprintf(Buffer, "R12:%8lX R13:%8lX R14:%8lX R15:%8lX R16:%8lX R17:%8lX\n", ContextRecord->Gpr12, ContextRecord->Gpr13, ContextRecord->Gpr14, ContextRecord->Gpr15, ContextRecord->Gpr16, ContextRecord->Gpr17); HalDisplayString(Buffer); sprintf(Buffer, "R18:%8lX R19:%8lX R20:%8lX R21:%8lX R22:%8lX R23:%8lX\n", ContextRecord->Gpr18, ContextRecord->Gpr19, ContextRecord->Gpr20, ContextRecord->Gpr21, ContextRecord->Gpr22, ContextRecord->Gpr23); HalDisplayString(Buffer); sprintf(Buffer, "R24:%8lX R25:%8lX R26:%8lX R27:%8lX R28:%8lX R29:%8lX\n", ContextRecord->Gpr24, ContextRecord->Gpr25, ContextRecord->Gpr26, ContextRecord->Gpr27, ContextRecord->Gpr28, ContextRecord->Gpr29); HalDisplayString(Buffer); sprintf(Buffer, "R30:%8lX R31:%8lX CR:%8lX CTR:%8lX XER:%8lX\n", ContextRecord->Gpr30, ContextRecord->Gpr31, ContextRecord->Cr, ContextRecord->Ctr, ContextRecord->Xer); HalDisplayString(Buffer); #if 0 // // I'd much rather see a longer stack trace and skip the floating // point stuff when the system crashes. plj // // // Format and output the floating registers. // DumpFloat = (PULONG)(&ContextRecord->Fpr0); sprintf(Buffer, " F0- F3:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n", *(DumpFloat+1), *DumpFloat, *(DumpFloat+3), *(DumpFloat+2), *(DumpFloat+5), *(DumpFloat+4), *(DumpFloat+7), *(DumpFloat+6)); HalDisplayString(Buffer); DumpFloat = (PULONG)(&ContextRecord->Fpr4); sprintf(Buffer, " F4- F7:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n", *(DumpFloat+1), *DumpFloat, *(DumpFloat+3), *(DumpFloat+2), *(DumpFloat+5), *(DumpFloat+4), *(DumpFloat+7), *(DumpFloat+6)); HalDisplayString(Buffer); DumpFloat = (PULONG)(&ContextRecord->Fpr8); sprintf(Buffer, " F8-F11:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n", *(DumpFloat+1), *DumpFloat, *(DumpFloat+3), *(DumpFloat+2), *(DumpFloat+5), *(DumpFloat+4), *(DumpFloat+7), *(DumpFloat+6)); HalDisplayString(Buffer); DumpFloat = (PULONG)(&ContextRecord->Fpr12); sprintf(Buffer, "F12-F15:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n", *(DumpFloat+1), *DumpFloat, *(DumpFloat+3), *(DumpFloat+2), *(DumpFloat+5), *(DumpFloat+4), *(DumpFloat+7), *(DumpFloat+6)); HalDisplayString(Buffer); DumpFloat = (PULONG)(&ContextRecord->Fpr16); sprintf(Buffer, "F16-F19:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n", *(DumpFloat+1), *DumpFloat, *(DumpFloat+3), *(DumpFloat+2), *(DumpFloat+5), *(DumpFloat+4), *(DumpFloat+7), *(DumpFloat+6)); HalDisplayString(Buffer); DumpFloat = (PULONG)(&ContextRecord->Fpr20); sprintf(Buffer, "F20-F23:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n", *(DumpFloat+1), *DumpFloat, *(DumpFloat+3), *(DumpFloat+2), *(DumpFloat+5), *(DumpFloat+4), *(DumpFloat+7), *(DumpFloat+6)); HalDisplayString(Buffer); DumpFloat = (PULONG)(&ContextRecord->Fpr24); sprintf(Buffer, "F24-F27:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n", *(DumpFloat+1), *DumpFloat, *(DumpFloat+3), *(DumpFloat+2), *(DumpFloat+5), *(DumpFloat+4), *(DumpFloat+7), *(DumpFloat+6)); HalDisplayString(Buffer); DumpFloat = (PULONG)(&ContextRecord->Fpr28); sprintf(Buffer, "F28-F31:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n", *(DumpFloat+1), *DumpFloat, *(DumpFloat+3), *(DumpFloat+2), *(DumpFloat+5), *(DumpFloat+4), *(DumpFloat+7), *(DumpFloat+6)); HalDisplayString(Buffer); DumpFloat = (PULONG)(&ContextRecord->Fpscr); sprintf(Buffer, " FPSCR:%08lX%08lX\n", *(DumpFloat+1), *DumpFloat); HalDisplayString(Buffer); #define STAKWALK 4 #else #define STAKWALK 8 #endif // // Output short stack back trace with base address. // DllName.Length = 0; DllName.Buffer = L""; if (FunctionEntry != NULL) { StackLimit = (ULONG)KeGetCurrentThread()->KernelStack; HalDisplayString("Callee-Sp Return-Ra Dll Base - Name\n"); for (Index = 0; Index < STAKWALK; Index += 1) { ImageBase = KiPcToFileHeader((PVOID)ControlPc, &ImageBase, &DataTableEntry); sprintf(Buffer, " %08lX %08lX : %08lX - %s\n", ContextRecord->Gpr1, NextPc + 4, ImageBase, (*UnicodeToAnsiRoutine)( (ImageBase != NULL) ? &DataTableEntry->BaseDllName : &DllName, AnsiBuffer, sizeof( AnsiBuffer ))); HalDisplayString(Buffer); if ((NextPc != ControlPc) || (ContextRecord->Gpr1 != LastStack)) { ControlPc = NextPc; LastStack = ContextRecord->Gpr1; FunctionEntry = KiLookupFunctionEntry(ControlPc); if ((FunctionEntry != NULL) && (LastStack < StackLimit)) { NextPc = RtlVirtualUnwind(ControlPc, FunctionEntry, ContextRecord, &InFunction, &EstablisherFrame, NULL, 0, 0xffffffff); } else { NextPc = ContextRecord->Lr; } } else { break; } } } // // Output the build number and other useful information. // sprintf(Buffer, "\nIRQL : %d, DPC Active : %s, SYSVER 0x%08x\n", KeGetCurrentIrql(), KeIsExecutingDpc() ? "TRUE" : "FALSE", NtBuildNumber); HalDisplayString(Buffer); // // Output the processor id and the primary cache sizes. // sprintf(Buffer, "Processor Id: %d.%d, Icache: %d, Dcache: %d", PCR->ProcessorVersion, PCR->ProcessorRevision, PCR->FirstLevelIcacheSize, PCR->FirstLevelDcacheSize); HalDisplayString(Buffer); // // If the display width is greater than 80 + 24 (the size of a DLL // name and base address), then display all the modules loaded in // the system. // HalQueryDisplayParameters(&DisplayWidth, &DisplayHeight, &DisplayColumn, &DisplayRow); if (DisplayWidth > (80 + 24)) { HalDisplayString("\n"); if (KeLoaderBlock != NULL) { ModuleListHead = &KeLoaderBlock->LoadOrderListHead; } else { ModuleListHead = &PsLoadedModuleList; } // // Output display headers. // Index = 1; KiDisplayString(80, Index, "Dll Base DateStmp - Name"); NextEntry = ModuleListHead->Flink; if (NextEntry != NULL) { // // Scan the list of loaded modules and display their base // address and name. // while (NextEntry != ModuleListHead) { Index += 1; DataTableEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); if (MmDbgReadCheck(DataTableEntry->DllBase) != NULL) { PIMAGE_NT_HEADERS NtHeaders; NtHeaders = RtlImageNtHeader(DataTableEntry->DllBase); DateStamp = NtHeaders->FileHeader.TimeDateStamp; } else { DateStamp = 0; } sprintf(Buffer, "%08lX %08lx - %s", DataTableEntry->DllBase, DateStamp, (*UnicodeToAnsiRoutine)( &DataTableEntry->BaseDllName, AnsiBuffer, sizeof( AnsiBuffer ))); KiDisplayString(80, Index, Buffer); NextEntry = NextEntry->Flink; if (Index > DisplayHeight) { break; } } } } // // Reset the current display position. // HalSetDisplayParameters(DisplayColumn, DisplayRow); // // The system has crashed, if we are running without the Kernel // debugger attached, attach it now. // KdInitSystem(NULL, FALSE); return; }
VOID HalpBootCpuRestart( VOID ) /*++ Routine Description: This function returns control to the firmware Arcreboot routine. it waits until all other cpu's have beet shut down. this code is executed only on the boot cpu Arguments: None Return Value: Does not return. --*/ { UCHAR DataByte; ULONG cpt; HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode HalDisplayString("\n"); HalpClearVGADisplay(); HalDisplayString("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); HalDisplayString(" ���������������������������������������ͻ\n"); HalDisplayString(" � �\n"); HalDisplayString(" � Restart in Progress �\n"); HalDisplayString(" � �\n"); HalDisplayString(" ���������������������������������������ͼ\n"); cpt = 0; while(*(PULONG)(& (((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->ActiveProcessor[0]) )) { KeStallExecutionProcessor(500000); ++cpt;if (cpt == 20) break; } // // if there are still ssome processors active, we do a reset of the entire machine // if (*(PULONG)(& (((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->ActiveProcessor[0]) )) { #if DBG DbgPrint(" Some processors did not answer . Reset machine started. \n"); #endif if (HalpIsTowerPci) { WRITE_REGISTER_ULONG((PULONG) PCI_TOWER_DCU_CONTROL, DC_SWRESET); }else { WRITE_REGISTER_UCHAR((PUCHAR) PCI_MCR_ADDR, PCI_MCR_SOFTRESET); } } else { #if DBG DbgPrint("Reboot started \n"); #endif } DataByte = READ_REGISTER_UCHAR( &((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl); ((PNMI_EXTENDED_CONTROL) &DataByte)->BusReset = 1; WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl, DataByte ); KeStallExecutionProcessor(10000); ((PNMI_EXTENDED_CONTROL) &DataByte)->BusReset = 0; WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl, DataByte ); ArcReboot(); for (;;) ; }
VOID HalReturnToFirmware( IN FIRMWARE_REENTRY Routine ) /*++ Routine Description: This function returns control to the specified firmware routine. In most cases it generates a soft reset. Arguments: Routine - Supplies a value indicating which firmware routine to invoke. Return Value: Does not return. --*/ { KIRQL OldIrql; UCHAR DataByte; // // Disable Interrupts. // KeRaiseIrql(HIGH_LEVEL, &OldIrql); // // Case on the type of return. // switch (Routine) { case HalHaltRoutine: // // Hang looping. // // power off asked by DCU/IDC (power - fan or ... failure) if (((ULONG)(((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipRoutine) != (ULONG)-1) && (((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipHalInfo == 1)) ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipRoutine( ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipContext ); for (;;) {} case HalPowerDownRoutine: // power off always done by DCU if ((ULONG)(((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipRoutine) != (ULONG)-1) ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipRoutine( ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipContext ); // // PowerOff is done by the SNI machines by writing the Power_Off bit to the machine control register ... // if (HalpIsTowerPci){ WRITE_REGISTER_ULONG((PULONG) PCI_TOWER_DCU_CONTROL, DC_POWEROFF); }else{ WRITE_REGISTER_UCHAR((PUCHAR) PCI_MCR_ADDR, PCI_MCR_POWEROFF); } for (;;) {} // hang looping case HalRestartRoutine: case HalRebootRoutine: case HalInteractiveModeRoutine: // power off asked by DCU/IDC (power - fan or ... failure) if (((ULONG)(((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipRoutine) != (ULONG)-1) && (((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipHalInfo == 1)) ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipRoutine( ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EipContext ); if (HalpIsMulti) { ULONG Mask,i; for (i=0;i<HalpIsMulti;i++) if (((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->ActiveProcessor[PCR->Number]) Mask |= 1<<i; Mask = Mask & ~(PCR->SetMember); #if DBGG DbgPrint("Send message RESTART to maskcpu = %x \n",Mask); #endif HalpRequestIpi(Mask,MPA_RESTART_MESSAGE); // // if this is not the Boot CPU, we call a special Firmware entry to stop it // // // remove this processor from the list of active processors // ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->ActiveProcessor[PCR->Number]=0; if (PCR->Number ) { #if DBGG DbgPrint(" Reinit slave %x \n", ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->reinit_slave); #endif ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->reinit_slave(); } else HalpBootCpuRestart(); } HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode HalDisplayString("\n"); HalpClearVGADisplay(); HalDisplayString("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); HalDisplayString(" ���������������������������������������ͻ\n"); HalDisplayString(" � �\n"); HalDisplayString(" � Restart in Progress �\n"); HalDisplayString(" � �\n"); HalDisplayString(" ���������������������������������������ͼ\n"); DataByte = READ_REGISTER_UCHAR( &((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl); ((PNMI_EXTENDED_CONTROL) &DataByte)->BusReset = 1; WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl, DataByte ); KeStallExecutionProcessor(10000); ((PNMI_EXTENDED_CONTROL) &DataByte)->BusReset = 0; WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl, DataByte ); ArcReboot(); for (;;) ; default: DbgPrint("HalReturnToFirmware invalid argument\n"); KeLowerIrql(OldIrql); DbgBreakPoint(); } }
VOID HalpDisplayLogout21064 ( IN PLOGOUT_FRAME_21064 LogoutFrame ) /*++ Routine Description: This function displays the logout frame for a 21064. Arguments: LogoutFrame - Supplies a pointer to the logout frame generated by the 21064. Return Value: None. --*/ { UCHAR OutBuffer[ MAX_ERROR_STRING ]; // // 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. This is a JENSEN feature. // HalAcquireDisplayOwnership(NULL); // // Display the machine state via the logout frame. // HalDisplayString( "\nFatal system hardware error.\n\n" ); sprintf( OutBuffer, "BIU_STAT : %016Lx BIU_ADDR: %016Lx\n", BIUSTAT_ALL_21064( LogoutFrame->BiuStat ), LogoutFrame->BiuAddr.QuadPart ); HalDisplayString( OutBuffer ); sprintf( OutBuffer, "FILL_ADDR: %016Lx FILL_SYN: %016Lx\n", LogoutFrame->FillAddr.QuadPart, FILLSYNDROME_ALL_21064(LogoutFrame->FillSyndrome) ); HalDisplayString( OutBuffer ); sprintf( OutBuffer, "DC_STAT : %016Lx BC_TAG : %016Lx\n", DCSTAT_ALL_21064(LogoutFrame->DcStat), BCTAG_ALL_21064(LogoutFrame->BcTag) ); HalDisplayString( OutBuffer ); sprintf( OutBuffer, "ICCSR : %016Lx ABOX_CTL: %016Lx EXC_SUM: %016Lx\n", ICCSR_ALL_21064(LogoutFrame->Iccsr), ABOXCTL_ALL_21064(LogoutFrame->AboxCtl), EXCSUM_ALL_21064(LogoutFrame->ExcSum) ); 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 ); // // Print out interpretation of the error. // HalDisplayString( "\n" ); // // Check for tag control parity error. // if( BIUSTAT_TCPERR_21064(LogoutFrame->BiuStat) == 1 ){ sprintf( OutBuffer, "Tag control parity error, Tag control: P: %1x D: %1x S: %1x V: %1x\n", BCTAG_TAGCTLP_21064( LogoutFrame->BcTag ), BCTAG_TAGCTLD_21064( LogoutFrame->BcTag ), BCTAG_TAGCTLS_21064( LogoutFrame->BcTag ), BCTAG_TAGCTLV_21064( LogoutFrame->BcTag ) ); HalDisplayString( OutBuffer ); } // // Check for tag parity error. // if( BIUSTAT_TPERR_21064(LogoutFrame->BiuStat) == 1 ){ sprintf( OutBuffer, "Tag parity error, Tag: 0b%17b Parity: %1x\n", BCTAG_TAG_21064(LogoutFrame->BcTag), BCTAG_TAGP_21064(LogoutFrame->BcTag) ); HalDisplayString( OutBuffer ); } // // Check for hard error. // if( BIUSTAT_HERR_21064(LogoutFrame->BiuStat) == 1 ){ sprintf( OutBuffer, "Hard error acknowledge: BIU CMD: %x PA: %16Lx\n", BIUSTAT_CMD_21064(LogoutFrame->BiuStat), LogoutFrame->BiuAddr.QuadPart ); HalDisplayString( OutBuffer ); } // // Check for soft error. // if( BIUSTAT_SERR_21064(LogoutFrame->BiuStat) == 1 ){ sprintf( OutBuffer, "Soft error acknowledge: BIU CMD: %x PA: %16Lx\n", BIUSTAT_CMD_21064(LogoutFrame->BiuStat), LogoutFrame->BiuAddr.QuadPart ); HalDisplayString( OutBuffer ); } // // Check for fill ECC errors. // if( BIUSTAT_FILLECC_21064(LogoutFrame->BiuStat) == 1 ){ sprintf( OutBuffer, "ECC error: %s\n", (BIUSTAT_FILLIRD_21064(LogoutFrame->BiuStat) ? "Icache Fill" : "Dcache Fill") ); HalDisplayString( OutBuffer ); sprintf( OutBuffer, "PA: %16Lx Quadword: %x Longword0: %x Longword1: %x\n", LogoutFrame->FillAddr.QuadPart, BIUSTAT_FILLQW_21064(LogoutFrame->BiuStat), FILLSYNDROME_LO_21064(LogoutFrame->FillSyndrome), FILLSYNDROME_HI_21064(LogoutFrame->FillSyndrome) ); HalDisplayString( OutBuffer ); } // // Check for fill Parity errors. // if( BIUSTAT_FILLDPERR_21064(LogoutFrame->BiuStat) == 1 ){ sprintf( OutBuffer, "Parity error: %s\n", (BIUSTAT_FILLIRD_21064(LogoutFrame->BiuStat) ? "Icache Fill" : "Dcache Fill") ); HalDisplayString( OutBuffer ); sprintf( OutBuffer, "PA: %16Lx Quadword: %x Longword0: %x Longword1: %x\n", LogoutFrame->FillAddr.QuadPart, BIUSTAT_FILLQW_21064(LogoutFrame->BiuStat), FILLSYNDROME_LO_21064(LogoutFrame->FillSyndrome), FILLSYNDROME_HI_21064(LogoutFrame->FillSyndrome) ); HalDisplayString( OutBuffer ); } // // Check for multiple hard errors. // if( BIUSTAT_FATAL1_21064(LogoutFrame->BiuStat) == 1 ){ HalDisplayString( "Multiple external/tag errors detected.\n" ); } // // Check for multiple fill errors. // if( BIUSTAT_FATAL2_21064(LogoutFrame->BiuStat) == 1 ){ HalDisplayString( "Multiple fill errors detected.\n" ); } // // return to caller // return; }
BOOLEAN NTAPI KdPortInitializeEx( IN PCPPORT PortInformation, IN ULONG ComPortNumber) { NTSTATUS Status; CHAR buffer[80]; #if 0 // Deactivated because never used in fact (was in KdPortInitialize but we use KdPortInitializeEx) /* * Find the port if needed */ SIZE_T i; if (!PortInitialized) { DefaultPort.BaudRate = PortInformation->BaudRate; if (ComPortNumber == 0) { /* * Start enumerating COM ports from the last one to the first one, * and break when we find a valid port. * If we reach the first element of the list, the invalid COM port, * then it means that no valid port was found. */ for (i = sizeof(BaseArray) / sizeof(BaseArray[0]) - 1; i > 0; i--) { if (CpDoesPortExist(UlongToPtr(BaseArray[i]))) { PortInformation->Address = DefaultPort.Address = BaseArray[i]; ComPortNumber = (ULONG)i; break; } } if (ComPortNumber == 0) { sprintf(buffer, "\nKernel Debugger: No COM port found!\n\n"); HalDisplayString(buffer); return FALSE; } } PortInitialized = TRUE; } #endif /* * Initialize the port */ Status = CpInitialize(PortInformation, (ComPortNumber == 0 ? PortInformation->Address : UlongToPtr(BaseArray[ComPortNumber])), (PortInformation->BaudRate == 0 ? DEFAULT_BAUD_RATE : PortInformation->BaudRate)); if (!NT_SUCCESS(Status)) { sprintf(buffer, "\nKernel Debugger: Serial port not found!\n\n"); HalDisplayString(buffer); return FALSE; } else { #ifndef NDEBUG /* Print message to blue screen */ sprintf(buffer, "\nKernel Debugger: Serial port found: COM%ld (Port 0x%lx) BaudRate %ld\n\n", ComPortNumber, PortInformation->Address, PortInformation->BaudRate); HalDisplayString(buffer); #endif /* NDEBUG */ #if 0 /* Set global info */ KdComPortInUse = DefaultPort.Address; #endif return TRUE; } }
NTSTATUS NtDisplayString( IN PUNICODE_STRING String ) /*++ Routine Description: This service calls the HAL to display a string on the console. The caller must have SeTcbPrivilege to display a message. Arguments: String - A pointer to the string that is to be displayed. Return Value: !NT_SUCCESS - The operation failed or the caller did not have appropriate priviledges. --*/ { KPROCESSOR_MODE PreviousMode; UNICODE_STRING CapturedString; PUCHAR StringBuffer = NULL; PUCHAR AnsiStringBuffer = NULL; STRING AnsiString; // // Check to determine if the caller has the privilege to make this // call. // PreviousMode = KeGetPreviousMode(); if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) { return STATUS_PRIVILEGE_NOT_HELD; } try { // // If the previous mode was user, then check the input parameters. // if (PreviousMode != KernelMode) { // // Probe and capture the input unicode string descriptor. // CapturedString = ProbeAndReadUnicodeString(String); // // If the captured string descriptor has a length of zero, then // return success. // if ((CapturedString.Buffer == 0) || (CapturedString.MaximumLength == 0)) { return STATUS_SUCCESS; } // // Probe and capture the input string. // // N.B. Note the length is in bytes. // ProbeForRead( CapturedString.Buffer, CapturedString.MaximumLength, sizeof(UCHAR) ); // // Allocate a non-paged string buffer because the buffer passed to // HalDisplay string must be non-paged. // StringBuffer = ExAllocatePoolWithTag(NonPagedPool, CapturedString.MaximumLength, 'grtS'); if ( !StringBuffer ) { return STATUS_NO_MEMORY; } RtlMoveMemory(StringBuffer, CapturedString.Buffer, CapturedString.MaximumLength); CapturedString.Buffer = (PWSTR)StringBuffer; // // Allocate a string buffer for the ansi string. // AnsiStringBuffer = ExAllocatePoolWithTag(NonPagedPool, CapturedString.MaximumLength, 'grtS'); if (AnsiStringBuffer == NULL) { ExFreePool(StringBuffer); return STATUS_NO_MEMORY; } AnsiString.MaximumLength = CapturedString.MaximumLength; AnsiString.Length = 0; AnsiString.Buffer = AnsiStringBuffer; // // Transform the string to ANSI until the HAL handles unicode. // RtlUnicodeStringToOemString( &AnsiString, &CapturedString, FALSE ); } else { // // Allocate a string buffer for the ansi string. // AnsiStringBuffer = ExAllocatePoolWithTag(NonPagedPool, String->MaximumLength, 'grtS'); if (AnsiStringBuffer == NULL) { return STATUS_NO_MEMORY; } AnsiString.MaximumLength = String->MaximumLength; AnsiString.Length = 0; AnsiString.Buffer = AnsiStringBuffer; // // We were in kernel mode; just transform the original string. // RtlUnicodeStringToOemString( &AnsiString, String, FALSE ); } HalDisplayString( AnsiString.Buffer ); // // Free up the memory we used to store the strings. // if (PreviousMode != KernelMode) { ExFreePool(StringBuffer); } ExFreePool(AnsiStringBuffer); } except(EXCEPTION_EXECUTE_HANDLER) { if (StringBuffer != NULL) { ExFreePool(StringBuffer); } return GetExceptionCode(); } return STATUS_SUCCESS; }
BOOLEAN HalHandleNMI( IN PKINTERRUPT Interrupt, IN PVOID ServiceContext ) /*++ Routine Description: This function is called when an EISA NMI occurs. It prints the appropriate status information and bugchecks. Arguments: Interrupt - Supplies a pointer to the interrupt object ServiceContext - Bug number to call bugcheck with. Return Value: Returns TRUE. --*/ { UCHAR StatusByte; UCHAR EisaPort; ULONG port; ULONG AddressSpace = 1; // 1 = I/O address space BOOLEAN Status; PHYSICAL_ADDRESS BusAddress; PHYSICAL_ADDRESS TranslatedAddress; UCHAR Datum; NMIcount++; // // Set the Eisa NMI disable bit. We do this to mask further NMI // interrupts while we're servicing this one. // Datum = READ_PORT_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable); ((PNMI_ENABLE)(&Datum))->NmiDisable = 1; WRITE_PORT_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable, Datum); #ifdef HALDBG DbgPrint("HalpIntializeNMI: wrote 0x%x to NmiEnable\n\r", Datum); #endif StatusByte = READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus); if (StatusByte & 0x80) { #ifdef HALDBG DbgPrint("HalHandleNMI: Parity Check / Parity Error\n"); DbgPrint("HalHandleNMI: StatusByte = 0x%x\r\n", StatusByte); #else // // jwlfix - For the present, we're commenting out an NMI parity // error bugcheck, until investigation into its causes // yields a better solution. // // HalDisplayString ("NMI: Parity Check / Parity Error\n"); // KeBugCheck(NMI_HARDWARE_FAILURE); // return (TRUE); #endif } Datum = READ_REGISTER_UCHAR((PUCHAR)HalpServerControlQva ); if (((PMIKASA_SRV)(&Datum))->HaltIncoming == 0 || ((PMIKASA_SRV)(&Datum))->TempFail == 1 || ((PMIKASA_SRV)(&Datum))->Fan1Fault == 0 || ((PMIKASA_SRV)(&Datum))->Fan2Fault == 0) { #ifdef HALDBG DbgPrint("HalHandleNMI: Server management NMI\n"); DbgPrint("HalHandleNMI: StatusByte = 0x%x\r\n", StatusByte); DbgPrint("HalHandleNMI: Server Management Byte = 0x%x\r\n", Datum); #else // // jwlfix - All the above conditions are for handling server // management features. Implementing more than simple // dismissal waits upon definition of desired behavior // by platform designers or Microsoft Windows NT // requirements for server behavior. #endif } if (StatusByte & 0x40) { #ifdef HALDBG DbgPrint("HalHandleNMI: Channel Check / IOCHK\n"); DbgPrint("HalHandleNMI: StatusByte = 0x%x\r\n", StatusByte); #else HalDisplayString ("NMI: Channel Check / IOCHK\n"); KeBugCheck(NMI_HARDWARE_FAILURE); return (TRUE); #endif } #if 0 // jwlfix - This code can be added in later, as we have need // for it. It's good to have it here, for when it // might be of use. // // This is an Eisa machine, check for extnded nmi information... // StatusByte = READ_PORT_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl); if (StatusByte & 0x80) { HalDisplayString ("NMI: Fail-safe timer\n"); } if (StatusByte & 0x40) { HalDisplayString ("NMI: Bus Timeout\n"); } if (StatusByte & 0x20) { HalDisplayString ("NMI: Software NMI generated\n"); } // // Look for any Eisa expansion board. See if it asserted NMI. // // jwlfix - The following doesn't work, at this moment; it's // likey the 12-bit shift, which should be a 5-bit // shift on Mikasa. // BusAddress.HighPart = 0; for (EisaPort = 0; EisaPort <= 0xf; EisaPort++) { BusAddress.LowPart = (EisaPort << 12) + 0xC80; Status = HalTranslateBusAddress(Eisa, // InterfaceType 0, // BusNumber BusAddress, &AddressSpace, // 1=I/O address space &TranslatedAddress); // QVA if (Status == FALSE) { UCHAR pbuf[80]; sprintf(pbuf, "Unable to translate bus address %x for EISA slot %d\n", BusAddress.LowPart, EisaPort); HalDisplayString(pbuf); KeBugCheck(NMI_HARDWARE_FAILURE); } port = TranslatedAddress.LowPart; WRITE_PORT_UCHAR ((PUCHAR) port, 0xff); StatusByte = READ_PORT_UCHAR ((PUCHAR) port); if ((StatusByte & 0x80) == 0) { // // Found valid Eisa board, Check to see if its // IOCHKERR is asserted. // StatusByte = READ_PORT_UCHAR ((PUCHAR) port+4); if (StatusByte & 0x2) { EisaNMIMsg[25] = (EisaPort > 9 ? 'A'-10 : '0') + EisaPort; HalDisplayString (EisaNMIMsg); KeBugCheck(NMI_HARDWARE_FAILURE); } } } #ifdef HALDBG // Reset extended NMI interrupts (for debugging purposes only). WRITE_PORT_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl, 0x00); WRITE_PORT_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl, 0x02); #endif #endif #ifdef HALDBG DbgPrint("HalHandleNMI: Resetting PERR#; NMI count = %d\r\n", NMIcount); #endif // // Reset PERR# and disable it. // WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus, 0x04); // // now enable it again. // WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus, 0); // // Clear the Eisa NMI disable bit. This re-enables NMI interrupts, // now that we're done servicing this one. // Datum = READ_PORT_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable); ((PNMI_ENABLE)(&Datum))->NmiDisable = 0; WRITE_PORT_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable, Datum); #ifdef HALDBG DbgPrint("HalpIntializeNMI: wrote 0x%x to NmiEnable\n\r", Datum); #endif return(TRUE); }
BOOLEAN HalpCalibrateStall ( VOID ) /*++ Routine Description: This function calibrates the stall execution HAL service and connects the clock and profile interrupts to the appropriate NT service routines. Arguments: None. Return Value: A value of TRUE is returned if the calibration is successfully completed. Otherwise a value of FALSE is returned. --*/ { ULONG Index; KIRQL OldIrql; // // Use a range of scale factors from 50ns down to 10ns assuming a // five instruction stall loop. // for (Index = 200; Index > 0; Index -= 10) { // // Disable all interrupts and establish calibration parameters. // KeRaiseIrql(HIGH_LEVEL, &OldIrql); // // Set the scale factor, stall count, starting stall count, and // ending stall count values. // PCR->StallScaleFactor = 4000 / (Index * 5); PCR->StallExecutionCount = 0; HalpStallStart = 0; HalpStallEnd = 0; // // Enable interrupts and stall execution. // KeLowerIrql(OldIrql); // // Stall execution for (MAXIMUM_INCREMENT / 10) * 4 us. // KeStallExecutionProcessor((MAXIMUM_INCREMENT / 10) * 4); // // If both the starting and ending stall counts have been captured, // then break out of loop. // if ((HalpStallStart != 0) && (HalpStallEnd != 0)) { break; } } if (Index == 0) { HalDisplayString("������������������������������������������������������������ͻ\n"); HalDisplayString("�WARNING: Cannot compute stall factor �\n"); HalDisplayString("�WARNING: Using default value (250 Mhz) �\n"); HalDisplayString("������������������������������������������������������������ͼ\n"); HalpStallScaleFactor = 0x20; HalpProfileCountRate = 125*1000000; } else { // // Compute the profile interrupt rate. // HalpProfileCountRate = HalpProfileCountRate * ((1000 * 1000 * 10) / MAXIMUM_INCREMENT); // // Compute the stall execution scale factor. // HalpStallScaleFactor = (HalpStallEnd - HalpStallStart + ((MAXIMUM_INCREMENT / 10) - 1)) / (MAXIMUM_INCREMENT / 10); if (HalpStallScaleFactor <= 0) { HalpStallScaleFactor = 1; } } PCR->StallScaleFactor = HalpStallScaleFactor; // // Set the time increment value and connect the real clock interrupt // routine. // PCR->InterruptRoutine[CLOCK2_LEVEL] = (PKINTERRUPT_ROUTINE) HalpClockInterrupt; // // Write the compare register and clear the count register, and // connect the profile interrupt if profiling is done via count/compare interrupt. // HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT); PCR->InterruptRoutine[PROFILE_LEVEL] = (PKINTERRUPT_ROUTINE) HalpProfileInterrupt; return TRUE; }