/*++ Copyright (c) 1992 NCR Corporation Module Name: ncrmp.c Abstract: Author: Richard Barton (o-richb) 24-Jan-1992 Environment: Kernel mode only. Revision History: --*/ #include "halp.h" #include "ixkdcom.h" #include "ncr.h" #include "stdio.h" #include "ncrnls.h" #include "ncrcat.h" #include "ncrcatp.h" #include "ncrsus.h" #include "ncrmem.h" UCHAR HalName[] = "NCR 3x series MP HAL"; ADDRESS_USAGE HalpNCRIoSpace = { NULL, CmResourceTypePort, InternalUsage, { 0xF800, 0x100, // IO space reserved for CAT 0xFC00, 0x100, // IO space reserved for VIC 0x97, 0x2, // IO space for 3450 and up CAT SELECT/BASE port 0,0 } }; ULONG NCRDebug = 0x2; // 0x01 - none // 0x02 - stop on memory edits // 0x04 - enable nmi button on 3360 // 0x08 - enable boot on 3550 // 0x10 - disable reprogram of QCC and QABC Asics for cache ownership // 0x20 - Enable LARCs ULONG NCRProcessorsToBringup = 0xFFFF; ULONG NCRExistingProcessorMask = 0x00; ULONG NCRExistingDyadicProcessorMask = 0x00; ULONG NCRExistingQuadProcessorMask = 0x00; ULONG NCRExtendedProcessorMask = 0x00; ULONG NCRExtendedProcessor0Mask = 0x00; ULONG NCRExtendedProcessor1Mask = 0x00; ULONG NCRActiveProcessorMask = 0x00; ULONG NCRActiveProcessorLogicalMask = 0x00; ULONG NCRActiveProcessorCount = 0; ULONG NCRMaxProcessorCount = NCR_MAX_NUMBER_QUAD_PROCESSORS; ULONG LimitMemory = 0; ULONG NCRNeverClaimIRQs = 0xffffffff; // we start out claiming none #if 0 // // BUGBUG - (shielint) This is requested by Ncr. // For now don't let cpus claim any IRQ by setting the flag to -1. // NCR/ATT will revisit this problem after NT4.0 release. // ULONG DefaultNeverClaimIRQs = 1 // lets don't claim the timer interrupt #else ULONG DefaultNeverClaimIRQs = 0xffffffff; // lets don't claim the timer interrupt #endif ULONG NCRMaxIRQsToClaim = 0; ULONG NCRGlobalClaimedIRQs = 0; ULONG NCRLogicalNumberToPhysicalMask[NCR_MAX_NUMBER_PROCESSORS] = {0}; ULONG NCRProcessorIDR[NCR_MAX_NUMBER_PROCESSORS]; ULONG NCRLarcPageMask = 0x1; // only one page by default (4 Meg) #ifdef DBG ULONG NCRProcessorClaimedIRQs[NCR_MAX_NUMBER_PROCESSORS] = {0}; ULONG NCRClaimCount = 0; ULONG NCRStolenCount = 0; ULONG NCRUnclaimCount = 0; #endif ULONG NCRLogicalDyadicProcessorMask = 0x00; ULONG NCRLogicalQuadProcessorMask = 0x00; UCHAR NCRSlotExtended0ToVIC[4] = {0, 5, 2, 7}; UCHAR NCRSlotExtended1ToVIC[4] = {1, 4, 3, 6}; extern ULONG NCRPlatform; ULONG NCRStatusChangeInterruptEnabled = 0; extern ULONG HalpDefaultInterruptAffinity; extern ULONG NCRLarcEnabledPages[]; // LARC size by Voyager slot /* * Struct used to report secondary MC information to the * Registery */ typedef struct _SMC_RESOURCES { CM_FULL_RESOURCE_DESCRIPTOR ConfigurationData; CM_MCA_POS_DATA PosData[10]; } SMC_RESOURCES, *PSMC_RESOURCES; /* * Global variables used for acessing Secondary Microchannel * */ ULONG NCRSegmentIoAddress = 0xffe00000; PUCHAR NCRSegmentIoRegister = NULL; /* * Spin lock used to lock the CAT Bus. HalpAcquireCatBusSpinLock and * HalpReleaseCatBusSpinLock use this lock. */ KSPIN_LOCK HalpCatBusLock; typedef struct { ULONG StartingByte; ULONG Pages; } NCRClickMapEntry; #define ClickMapEntryCount 16 #define NoExtraDescriptors 16 ULONG NCRAddedDescriptorCount; MEMORY_ALLOCATION_DESCRIPTOR NCRAdditionalMemoryDescriptors[NoExtraDescriptors]; PVOID NonbootStartupPhysicalPtr; PUCHAR NonbootStartupVirtualPtr; PUCHAR PageZeroVirtualPtr; VOID NCRVicIPIHandler(VOID); VOID NCRQicIPIHandler(VOID); VOID NCRClockBroadcastHandler(VOID); VOID __cdecl NCRVICErrataHandler1(); VOID __cdecl NCRVICErrataHandler3(); VOID __cdecl NCRVICErrataHandler4(); VOID __cdecl NCRVICErrataHandler5(); VOID __cdecl NCRVICErrataHandler6(); VOID __cdecl NCRVICErrataHandler7(); VOID __cdecl NCRVICErrataHandler15(); VOID __cdecl NCRProfileHandler(); VOID __cdecl NCRSysIntHandler(); VOID __cdecl NCRQicSpuriousHandler(); PUCHAR NCRDeterminePlatform(PBOOLEAN); VOID NCRFixMemory(PLOADER_PARAMETER_BLOCK); VOID NCRLimitMemory(PLOADER_PARAMETER_BLOCK); VOID NCRVerifyMemoryRange (ULONG, ULONG, PLOADER_PARAMETER_BLOCK); //VOID NCRAdjustMemoryDescriptor(PMEMORY_ALLOCATION_DESCRIPTOR, // NCRClickMapEntry *); VOID NCRSetupDiagnosticProcessor(PLOADER_PARAMETER_BLOCK); VOID NCRLockedOr(PULONG, ULONG); VOID NCRParseLoaderOptions (PUCHAR Options); BOOLEAN NCRGetValue (PUCHAR Options, PUCHAR String, PULONG Value); ULONG HalpGetCmosData (ULONG SourceLocation, ULONG SourceAddress, PUCHAR Buffer, ULONG Length); VOID HalpDisableSingleBitErrorDET(); VOID HalpInitializeSMCInterface(); VOID HalpCatReportSMC(); VOID HalEnableStatusChangeInterrupt ( IN ULONG ); BOOLEAN HalpTranslateSMCBusAddress ( IN PVOID BusHandler, IN PVOID RootHandler, IN PHYSICAL_ADDRESS BusAddress, IN OUT PULONG AddressSpace, OUT PPHYSICAL_ADDRESS TranslatedAddress ); ULONG HalpGetMCAInterruptVector ( IN PVOID BusHandler, IN PVOID RootHandler, IN ULONG BusInterruptLevel, IN ULONG BusInterruptVector, OUT PKIRQL Irql, OUT PKAFFINITY Affinity ); ULONG HalpGetSMCAInterruptVector ( IN PVOID BusHandler, IN PVOID RootHandler, IN ULONG BusInterruptLevel, IN ULONG BusInterruptVector, OUT PKIRQL Irql, OUT PKAFFINITY Affinity ); ULONG HalpNCRGetSystemInterruptVector( IN PBUS_HANDLER BusHandler, IN PBUS_HANDLER RootHandler, IN ULONG BusInterruptLevel, IN ULONG BusInterruptVector, OUT PKIRQL Irql, OUT PKAFFINITY Affinity ); HalpGetPosData ( IN PVOID BusHandler, IN PVOID RootHandler, IN ULONG SlotNumber, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length ); NTSTATUS HalpAdjustEisaResourceList ( IN PVOID BusHandler, IN PVOID RootHandler, IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList ); #define HalpAdjustMCAResourceList HalpAdjustEisaResourceList; BOOLEAN HalpInitMP ( IN ULONG Phase, IN PLOADER_PARAMETER_BLOCK LoaderBlock ); VOID HalpMapCR3 ( IN ULONG VirtAddress, IN PVOID PhysicalAddress, IN ULONG Length ); ULONG HalpBuildTiledCR3 ( IN PKPROCESSOR_STATE ProcessorState ); VOID HalpFreeTiledCR3 ( VOID ); VOID HalpInitOtherBuses (VOID); ULONG NCRTranslateCMOSMask(ULONG); ULONG NCRTranslateToCMOSMask(ULONG); VOID NCRFindExtendedProcessors(); VOID NCRMapIpiAddresses(); VOID NCRAdjustDynamicClaims(); #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT,HalpInitMP) #pragma alloc_text(INIT,HalStartNextProcessor) #pragma alloc_text(INIT,HalReportResourceUsage) #pragma alloc_text(INIT,HalReportResourceUsage) #pragma alloc_text(INIT,HalpInitOtherBuses) #pragma alloc_text(INIT,NCRFixMemory) #pragma alloc_text(INIT,NCRLimitMemory) //#pragma alloc_text(INIT,NCRAdjustMemoryDescriptor) #pragma alloc_text(INIT,NCRVerifyMemoryRange) #pragma alloc_text(INIT,NCRSetupDiagnosticProcessor) #pragma alloc_text(INIT,NCRParseLoaderOptions) #pragma alloc_text(INIT,NCRGetValue) #pragma alloc_text(INIT,HalpFreeTiledCR3) #pragma alloc_text(INIT,HalpMapCR3) #pragma alloc_text(INIT,HalpBuildTiledCR3) #pragma alloc_text(INIT,HalpInitializeCatBusDriver) #pragma alloc_text(INIT,HalpDisableSingleBitErrorDET) #pragma alloc_text(INIT,HalpInitializeSUSInterface) #pragma alloc_text(INIT,HalpInitializeSMCInterface) #pragma alloc_text(INIT,HalpCatReportSystemModules) #pragma alloc_text(INIT,HalpCatReportSMC) #endif BOOLEAN HalpInitMP ( IN ULONG Phase, IN PLOADER_PARAMETER_BLOCK LoaderBlock ) /*++ Routine Description: Allows MP initialization from HalInitSystem. Arguments: Same as HalInitSystem Return Value: none. --*/ { PKPCR pPCR; UCHAR Buffer[64]; UCHAR id; PUCHAR PlatformStringPtr; ULONG MyLogicalNumber; ULONG MyLogicalMask; BOOLEAN ConfiguredMp; ULONG trans; CAT_CONTROL cat_control; pPCR = KeGetPcr(); MyLogicalNumber = ((PProcessorPrivateData)pPCR->HalReserved)->MyLogicalNumber; if (Phase == 0) { // // Register NCR machine IO space, so drivers don't try to // use it // HalpRegisterAddressUsage (&HalpNCRIoSpace); NCRParseLoaderOptions (LoaderBlock->LoadOptions); /* * only the boot processor sees phase zero. */ if ((PlatformStringPtr = NCRDeterminePlatform(&ConfiguredMp)) == NULL) { sprintf(Buffer, MSG_UNKOWN_NCR_PLATFORM, NCRPlatform); HalDisplayString(Buffer); /* may not want to continue here, but for now let's go on, assuming a UP machine */ NCRExistingProcessorMask = 0x1; } else { sprintf(Buffer, MSG_NCR_PLATFORM, PlatformStringPtr); HalDisplayString(Buffer); HalpGetCmosData(1, 0x88A, (PUCHAR)&NCRExistingProcessorMask, 4); trans = NCRTranslateCMOSMask(NCRExistingProcessorMask); NCRExtendedProcessorMask = 0x0; DBGMSG(("HalpInitMP: CMOS NCRExistingProcessorMask = 0x%x, translated = 0x%x\n", NCRExistingProcessorMask, trans)); NCRExistingProcessorMask = trans; // additional stuff only if MSBU machine if (NCRPlatform != NCR3360) { KeInitializeSpinLock(&HalpCatBusLock); /* * This is to allow tweeking the memory descriptors. */ NCRFixMemory(LoaderBlock); /* * This is to determine whether we ought to save COM1 * for the diagnostic processors use. */ NCRSetupDiagnosticProcessor(LoaderBlock); } if (NCRPlatform == NCR3360) { id = 1; HalpSetCmosData(1, 0x41E, &id, 1); if (NCRDebug & 0x04) { NCR3360EnableNmiButton(); } } } if (LimitMemory) { NCRLimitMemory (LoaderBlock); } PageZeroVirtualPtr = HalpMapPhysicalMemory(0, 1); if ((NCRExistingProcessorMask ^ NCRActiveProcessorMask) != 0) { /* * there are non-boot processors to bring up... * * allocate some space to put the non-boot processors * startup code. */ NonbootStartupPhysicalPtr = (PVOID)HalpAllocPhysicalMemory(LoaderBlock, (1*1024*1024), 1, FALSE); NonbootStartupVirtualPtr = (PUCHAR)HalpMapPhysicalMemory(NonbootStartupPhysicalPtr, 1); } if (NCRPlatform != NCR3360) { HalpInitializeSUSInterface(); DBGMSG(("HalpInitMP: End of Phase 0, NCRExistingProcessorMask = 0x%x, NCRActiveProcessorMask = 0x%x\n", NCRExistingProcessorMask, NCRActiveProcessorMask)); NCRMapIpiAddresses(); // Map all QIC Ipi address NCRFindIpiAddress(0); // lookup processor 0 Ipi address #ifdef NEVER DBGMSG(("HalpInitMP: Lets break into the debug..\n")); _asm { int 3 } #endif // NEVER } else { NCRExistingDyadicProcessorMask = NCRExistingProcessorMask; } } else { // Phase 1... DBGMSG(("HalpInitMP: Start Phase %d for Proc %d\n", Phase, MyLogicalNumber)); /* * set up idt for cpis */ HalpEnableInterruptHandler ( InternalUsage, // Report as device vector NCR_CPI_VECTOR_BASE + NCR_IPI_LEVEL_CPI, NCR_CPI_VECTOR_BASE + NCR_IPI_LEVEL_CPI, // IDT IPI_LEVEL, // System Irql NCRVicIPIHandler, // ISR LevelSensitive ); NCRSetHandlerAddressToIDT((NCR_QIC_CPI_VECTOR_BASE + NCR_IPI_LEVEL_CPI), NCRQicIPIHandler); /* * put the broadcast clock handler at the * same irql as the clock. that way enabling * the clock enables the broadcast. */ HalpEnableInterruptHandler ( InternalUsage, // Report as device vector NCR_CPI_VECTOR_BASE + NCR_CLOCK_LEVEL_CPI, NCR_CPI_VECTOR_BASE + NCR_CLOCK_LEVEL_CPI, // IDT CLOCK2_LEVEL, // System Irql NCRClockBroadcastHandler, // ISR LevelSensitive ); NCRSetHandlerAddressToIDT((NCR_QIC_CPI_VECTOR_BASE + NCR_CLOCK_LEVEL_CPI), NCRClockBroadcastHandler); KiSetHandlerAddressToIDT(PROFILE_VECTOR, NCRProfileHandler); /* * Set up handlers for sysints */ NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE + NCR_SYSTEM_INTERRUPT), NCRSysIntHandler); HalEnableSystemInterrupt((NCR_CPI_VECTOR_BASE + NCR_SYSTEM_INTERRUPT), (HIGH_LEVEL - (NCR_SYSTEM_INTERRUPT & 0x7)), LevelSensitive); // due to a VIC errata, may get a bad vector (offset // by 8) for a CPI when a sysint or sbe is active. // Only CPIs 0 (NCR_IPI_LEVEL_CPI) and 2 // (NCR_CLOCK_LEVEL_CPI) are currently are used. Thus, // need to handle CPIs 0/2 at CPI vectors 8/10 as // well. Since CPI 10 is not used for anything else, // it can be set identical to CPI 2. However, CPI 8 // is used by sysint. Thus, the handler for CPI 8 // needs to handle this case NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE + NCR_CLOCK_LEVEL_CPI + 8), NCRClockBroadcastHandler); NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE + NCR_SMCA_9), NCRVICErrataHandler1); NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE + NCR_SMCA_9 + 8), NCRVICErrataHandler1); NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE + NCR_SMCA_11_3), NCRVICErrataHandler3); NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE + NCR_SMCA_11_3 + 8), NCRVICErrataHandler3); NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE + NCR_SMCA_12_4), NCRVICErrataHandler4); NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE + NCR_SMCA_12_4 + 8), NCRVICErrataHandler4); NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE + NCR_SMCA_13_5), NCRVICErrataHandler5); NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE + NCR_SMCA_13_5 + 8), NCRVICErrataHandler5); NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE + NCR_SMCA_14_6), NCRVICErrataHandler6); NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE + NCR_SMCA_14_6 + 8), NCRVICErrataHandler6); NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE + NCR_SMCA_15_7), NCRVICErrataHandler7); NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE + NCR_SMCA_15_7 + 8), NCRVICErrataHandler15); // // Lets go ahead an enable the interrupt for single bit/status change. // The following HalEnableSystemInterrupt call will enable the interrupt // that will be serviced by NCRVICErrataHandler15. The reason we enable // interrupt level 7 is because the single bit/status interrupt is on vector // CPI+f and is a level 7 interrupt. // if (NCRPlatform != NCR3360) { // This code was removed since enabled this vector // also enables 0x37. (Microchanel IRQ 7). If there // is a device connected to IRQ 7 which has an interrupt // asserted, it could start sending interrupts as soon // as ncr_single_bit_error is enabled - which is before // the corrisponding driver could be loaded. HalEnableSystemInterrupt((NCR_CPI_VECTOR_BASE + NCR_SMCA_15_7), (HIGH_LEVEL - (NCR_SMCA_15_7 & 0x7)), LevelSensitive); } // // If this is a processor on the Quad board then we need to handle the // Qic Spurious interrupt // MyLogicalMask = 0x1 << MyLogicalNumber; if (MyLogicalMask & NCRLogicalQuadProcessorMask) { NCRSetHandlerAddressToIDT(NCR_QIC_SPURIOUS_VECTOR, NCRQicSpuriousHandler); } if (MyLogicalNumber != 0) { /* * not the boot processor */ HalpInitializeStallExecution((CCHAR)MyLogicalNumber); /* * Allow clock interrupts on all processors */ HalEnableSystemInterrupt(CLOCK_VECTOR, CLOCK2_LEVEL, LevelSensitive); /* * Allow profile interrupt on all processors */ HalEnableSystemInterrupt(PROFILE_VECTOR, PROFILE_LEVEL, LevelSensitive); } NCRLockedOr(&NCRActiveProcessorLogicalMask, ((PProcessorPrivateData)pPCR->HalReserved)->MyLogicalMask); } return(TRUE); } NCRSetHandlerAddressToIDT ( IN ULONG IdtEntry, IN VOID (*Handler)(VOID) ) { HalpRegisterVector (InternalUsage, IdtEntry, IdtEntry, (HIGH_LEVEL - (IdtEntry & 0x7))); KiSetHandlerAddressToIDT (IdtEntry, Handler); } BOOLEAN HalAllProcessorsStarted ( VOID ) { return TRUE; } VOID HalReportResourceUsage ( VOID ) /*++ Routine Description: The registery is now enabled - time to report resources which are used by the HAL. Arguments: Return Value: --*/ { ANSI_STRING AHalName; UNICODE_STRING UHalName; HalInitSystemPhase2 (); RtlInitAnsiString (&AHalName, HalName); RtlAnsiStringToUnicodeString (&UHalName, &AHalName, TRUE); HalpReportResourceUsage ( &UHalName, // descriptive name MicroChannel // NCR's are MCA machines ); RtlFreeUnicodeString (&UHalName); // // Registry is now online, check for any PCI buses to support // HalpInitializePciBus (); if (NCRPlatform != NCR3360) { HalpCatReportSystemModules(); if (NCRSegmentIoRegister != NULL) { HalpCatReportSMC(); } } } VOID NCRFixMemory ( IN PLOADER_PARAMETER_BLOCK LoaderBlock ) /*++ Routine Description: Consult the firmware click map to determine what the memory really looks like. Fix up the memory descriptors as necessary. Note this function only adds memory which is in the clickmap to NTs memory descriptors. Arguments: Pointer to the loader block Return Value: none. --*/ { ULONG BPage, EPage, Temp; PVOID ClickMapPage; NCRClickMapEntry *BaseOfClickMap; NCRClickMapEntry *ClickMapEntryPtr; MEMORY_ALLOCATION_DESCRIPTOR TempDesc; /* * First get the physical address of the firmware's click map. */ HalpGetCmosData(1, 0xA23, (PUCHAR)&BaseOfClickMap, 4); if (BaseOfClickMap == NULL) { #if DBG HalDisplayString("NCRFixMemory: No click map?!\n"); #endif return; } /* * Now get a virtual address for the firmware's click map. */ ClickMapPage = (PVOID)((ULONG)BaseOfClickMap & ~(PAGE_SIZE - 1)); ClickMapPage = HalpMapPhysicalMemory(ClickMapPage, 2); if (ClickMapPage == NULL) { #if DBG HalDisplayString("NCRFixMemory: Can't map in click map?!\n"); #endif return; } ClickMapEntryPtr = (NCRClickMapEntry *)((ULONG)ClickMapPage + ((ULONG)BaseOfClickMap & (PAGE_SIZE - 1))); BaseOfClickMap = ClickMapEntryPtr; /* * Run the firmware's click map and verify NT has some type of * descriptor for all memory in the click map. */ // The hal allocates various memory by just removing it from the memory // map, we can't add that memory back in. // make bogus descriptor for 0-16M TempDesc.MemoryType = -1; TempDesc.BasePage = 0; TempDesc.PageCount = 0x1000; InsertHeadList(&LoaderBlock->MemoryDescriptorListHead, &TempDesc.ListEntry); for (ClickMapEntryPtr = BaseOfClickMap; ((ClickMapEntryPtr < &BaseOfClickMap[ClickMapEntryCount]) && (ClickMapEntryPtr->Pages != 0)); ++ClickMapEntryPtr) { BPage = ClickMapEntryPtr->StartingByte >> PAGE_SHIFT; EPage = BPage + ClickMapEntryPtr->Pages; NCRVerifyMemoryRange (BPage, EPage, LoaderBlock); } RemoveEntryList(&TempDesc.ListEntry); /* * Clear the mapping to the scratchpad. Not all of it is * reinitialized on a warm reset and the data may get corrupted. * We mapped in two pages. */ Temp = (ULONG)MiGetPteAddress(ClickMapPage); *(PULONG)Temp = 0; *((PULONG)Temp+1) = 0; /* * Flush the TLB. */ _asm { mov eax, cr3 mov cr3, eax } } VOID NCRVerifyMemoryRange ( IN ULONG StartPage, IN ULONG EndPage, IN PLOADER_PARAMETER_BLOCK LoaderBlock ) /*++ Routine Description: Ensure there is an NT descriptor for this memory range. Any part of the range which does not have a descriptor is added as available memory. Arguments: Return Value: none. --*/ { ULONG sp, ep; PLIST_ENTRY NextListEntry; PMEMORY_ALLOCATION_DESCRIPTOR Desc; if (StartPage == EndPage) { return ; } for (NextListEntry = LoaderBlock->MemoryDescriptorListHead.Flink; NextListEntry != &LoaderBlock->MemoryDescriptorListHead; NextListEntry = NextListEntry->Flink) { // // Check each descriptor to see if it intersects with the range // in question // Desc = CONTAINING_RECORD(NextListEntry, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry); sp = Desc->BasePage; ep = sp + Desc->PageCount; if (sp < StartPage) { if (ep > StartPage && ep < EndPage) { // bump target area past this descriptor StartPage = ep; } if (ep > EndPage) { // // Target area is contained totally within this // descriptor. This range is fully accounted for. // StartPage = EndPage; } } else { // sp >= StartPage if (sp < EndPage) { if (ep < EndPage) { // // This descriptor is totally within the target area - // check the area on either side of this desctipor // NCRVerifyMemoryRange (StartPage, sp, LoaderBlock); StartPage = ep; } else { // bump begining page of this descriptor EndPage = sp; } } } // // Anything left of target area? // if (StartPage == EndPage) { return ; } } // next descrtiptor // // The range StartPage - EndPage is a missing range from NTs descriptor // list. Add it as available memory. // if (NCRAddedDescriptorCount == NoExtraDescriptors) { return ; } Desc = &NCRAdditionalMemoryDescriptors[NCRAddedDescriptorCount]; NCRAddedDescriptorCount += 1; Desc->MemoryType = MemoryFree; Desc->BasePage = StartPage; Desc->PageCount = EndPage - StartPage; InsertTailList(&LoaderBlock->MemoryDescriptorListHead, &Desc->ListEntry); } #if 0 VOID NCRFixMemory(LoaderBlockPtr) PLOADER_PARAMETER_BLOCK LoaderBlockPtr; /*++ Routine Description: Consult the firmware click map to determine what the memory really looks like. Fix up the memory descriptors as necessary. Note that we may remove memory descriptors due to the clickmap disagreeing. However, we will only add memory descriptors to the end as necessary. Therefore, in theory, it is possible to have unused memory. But not likely. New descriptors may be added due to holes in physical memory caused by memory mapped adapters. This means that firmware is expected to give the loader (via BIOS int 15 function 88) the amount of contiguous extended memory with the lowest addresses. Arguments: Pointer to the loader block Return Value: none. --*/ { ULONG MaxDescriptorPage; ULONG Temp; ULONG StartingPage; PLIST_ENTRY NextListEntry; PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptorPtr; PMEMORY_ALLOCATION_DESCRIPTOR HighestMemoryDescriptor; PMEMORY_ALLOCATION_DESCRIPTOR NextFreeMemoryDescriptor; PVOID ClickMapPage; NCRClickMapEntry *BaseOfClickMap; NCRClickMapEntry *ClickMapEntryPtr; /* * First get the physical address of the firmware's click map. */ HalpGetCmosData(1, 0xA23, (PUCHAR)&BaseOfClickMap, 4); if (BaseOfClickMap == NULL) { #if DBG HalDisplayString("NCRFixMemory: No click map?!\n"); #endif return; } /* * Now get a virtual address for the firmware's click map. */ ClickMapPage = (PVOID)((ULONG)BaseOfClickMap & ~(PAGE_SIZE - 1)); ClickMapPage = HalpMapPhysicalMemory(ClickMapPage, 2); if (ClickMapPage == NULL) { #if DBG HalDisplayString("NCRFixMemory: Can't map in click map?!\n"); #endif return; } ClickMapEntryPtr = (NCRClickMapEntry *)((ULONG)ClickMapPage + ((ULONG)BaseOfClickMap & (PAGE_SIZE - 1))); BaseOfClickMap = ClickMapEntryPtr; /* * the firmware guys say that contiguous memory * will always be coalesced into one clickmap * entry. we "trust but verify." */ for (; ((ClickMapEntryPtr < &BaseOfClickMap[ClickMapEntryCount-1]) && (ClickMapEntryPtr->Pages != 0)); ++ClickMapEntryPtr) { Temp = ClickMapEntryPtr->StartingByte + (ClickMapEntryPtr->Pages << PAGE_SHIFT); while (((ClickMapEntryPtr+1)->Pages != 0) && ((ClickMapEntryPtr+1)->StartingByte <= Temp)) { /* * this should never happen...but if it does * it's easily fixed */ NCRClickMapEntry *NextClickMapEntryPtr; DBGMSG(("NCRFixMemory: Fixing clickmap!?!\n")); NextClickMapEntryPtr = ClickMapEntryPtr + 1; /* * note that this ending byte address is used * to determine whether we iterate again. */ Temp = NextClickMapEntryPtr->StartingByte + (NextClickMapEntryPtr->Pages << PAGE_SHIFT); if (Temp <= ClickMapEntryPtr->StartingByte) { /* * Whoa!!! this ain't so easy to fix. * I'm not interested in sorting right now. */ DbgBreakPoint(); } /* * here again, in theory, if the planets are really * off their courses we could decrease the page * count */ ClickMapEntryPtr->Pages = (Temp - ClickMapEntryPtr->StartingByte) >> PAGE_SHIFT; /* * we just removed an entry...shift all subsequent * entries down */ for (++NextClickMapEntryPtr; (NextClickMapEntryPtr < &BaseOfClickMap[ClickMapEntryCount]); ++NextClickMapEntryPtr) { (NextClickMapEntryPtr-1)->StartingByte = NextClickMapEntryPtr->StartingByte; (NextClickMapEntryPtr-1)->Pages = NextClickMapEntryPtr->Pages; if (NextClickMapEntryPtr->Pages == 0) { /* * we just copied the sentinel */ break; } } } } /* * go through all the memory descriptor entries... */ HighestMemoryDescriptor = NULL; NextListEntry = LoaderBlockPtr->MemoryDescriptorListHead.Flink; while (NextListEntry != &LoaderBlockPtr->MemoryDescriptorListHead) { MemoryDescriptorPtr = CONTAINING_RECORD(NextListEntry, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry); /* * find clickmap entry that contains this memory descriptor */ for (ClickMapEntryPtr = BaseOfClickMap; ((ClickMapEntryPtr < &BaseOfClickMap[ClickMapEntryCount]) && (ClickMapEntryPtr->Pages != 0)); ++ClickMapEntryPtr) { StartingPage = ClickMapEntryPtr->StartingByte >> PAGE_SHIFT; Temp = StartingPage + ClickMapEntryPtr->Pages; MaxDescriptorPage = MemoryDescriptorPtr->BasePage + MemoryDescriptorPtr->PageCount; if ((MemoryDescriptorPtr->BasePage >= StartingPage) && (MemoryDescriptorPtr->BasePage < Temp)) { /* * this memory descriptor starts in this * clickmap entry... */ if (MaxDescriptorPage > Temp) { /* * and goes beyond */ NCRAdjustMemoryDescriptor(MemoryDescriptorPtr, ClickMapEntryPtr); } break; } if ((MaxDescriptorPage > StartingPage) && (MaxDescriptorPage <= Temp)) { /* * this memory descriptor ends in this * clickmap entry... */ if (MemoryDescriptorPtr->BasePage < StartingPage) { /* * but starts before */ NCRAdjustMemoryDescriptor(MemoryDescriptorPtr, ClickMapEntryPtr); } break; } if ((MemoryDescriptorPtr->BasePage < StartingPage) && (MaxDescriptorPage > Temp)) { /* * this memory descriptor is a superset of * this clickmap entry */ NCRAdjustMemoryDescriptor(MemoryDescriptorPtr, ClickMapEntryPtr); break; } } /* * question...it's possible with the adjustments we did above * to have a memory descriptor with zero pages. should we * remove it too? i've seen other memory descriptors with * zero pages. for now we don't remove them. * * Also the ClickMap doesn't contain any memory for regions * between 640-1M, but the memory descriptor may. we leave * those memory descriptors alone. */ if ((ClickMapEntryPtr >= &BaseOfClickMap[ClickMapEntryCount] || ClickMapEntryPtr->Pages == 0) && (MemoryDescriptorPtr->BasePage < 0x9f || MemoryDescriptorPtr->BasePage+MemoryDescriptorPtr->PageCount > 0x100) ) { /* * no part of this memory descriptor was found to be * contained within any clickmap entry...remove it */ NCRAdjustMemoryDescriptor(MemoryDescriptorPtr, NULL); /* * a memory descriptor was removed. it's probably * safest to just start over */ NextListEntry = LoaderBlockPtr->MemoryDescriptorListHead.Flink; continue; } /* * remember the entry for the memory range with the highest * address */ if ((HighestMemoryDescriptor == NULL) || (HighestMemoryDescriptor->BasePage < MemoryDescriptorPtr->BasePage)) { HighestMemoryDescriptor = MemoryDescriptorPtr; } NextListEntry = NextListEntry->Flink; } /* * We depend on NextListEntry being the list head later. */ MaxDescriptorPage = HighestMemoryDescriptor->BasePage + HighestMemoryDescriptor->PageCount; NextFreeMemoryDescriptor = NCRAdditionalMemoryDescriptors; /* * Go through firmware's click map and find the entry that contains * the highest memory descriptor. */ for (ClickMapEntryPtr = BaseOfClickMap; ((ClickMapEntryPtr < &BaseOfClickMap[ClickMapEntryCount]) && (ClickMapEntryPtr->Pages != 0)); ++ClickMapEntryPtr) { StartingPage = ClickMapEntryPtr->StartingByte >> PAGE_SHIFT; Temp = StartingPage + ClickMapEntryPtr->Pages; if (MaxDescriptorPage >= Temp) { continue; } /* * The click map has memory above the highest memory * descriptor. * * We always add a new memory descriptor to the list. */ NextFreeMemoryDescriptor->MemoryType = MemoryFree; NextFreeMemoryDescriptor->BasePage = StartingPage; NextFreeMemoryDescriptor->PageCount = ClickMapEntryPtr->Pages; if (MaxDescriptorPage > NextFreeMemoryDescriptor->BasePage) { /* * another descriptor already contains part of this * clickmap entry...adjust the new descriptor so * that it excludes the already accounted for memory. * note that we should get into this condition * at most once. */ NextFreeMemoryDescriptor->PageCount -= MaxDescriptorPage - NextFreeMemoryDescriptor->BasePage; NextFreeMemoryDescriptor->BasePage = MaxDescriptorPage; } InsertTailList(NextListEntry, &NextFreeMemoryDescriptor->ListEntry); /* * This is the new highest memory descriptor. */ HighestMemoryDescriptor = NextFreeMemoryDescriptor; MaxDescriptorPage = HighestMemoryDescriptor->BasePage + HighestMemoryDescriptor->PageCount; /* * We can never run out since the maximum was * declared. */ ++NextFreeMemoryDescriptor; } /* * Clear the mapping to the scratchpad. Not all of it is * reinitialized on a warm reset and the data may get corrupted. * We mapped in two pages. */ Temp = (ULONG)MiGetPteAddress(ClickMapPage); *(PULONG)Temp = 0; *((PULONG)Temp+1) = 0; /* * Flush the TLB. */ _asm { mov eax, cr3 mov cr3, eax } } VOID NCRAdjustMemoryDescriptor(MemoryDescriptorPtr, ClickMapEntryPtr) PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptorPtr; NCRClickMapEntry *ClickMapEntryPtr; /*++ Routine Description: Make the memory descriptor fit into the clickmap entry Arguments: Pointer to the memory descriptor Pointer to the clickmap entry Return Value: none. --*/ { ULONG Temp; UCHAR Buffer[64]; #if DBG if ((NCRDebug & 0x2) && (MemoryDescriptorPtr->MemoryType != LoaderFree) && (MemoryDescriptorPtr->MemoryType != LoaderLoadedProgram) && (MemoryDescriptorPtr->MemoryType != MemoryFirmwareTemporary) && (MemoryDescriptorPtr->MemoryType != MemoryFirmwarePermanent) && (MemoryDescriptorPtr->MemoryType != LoaderOsloaderStack)) { /* * looks like it's already been allocated to * to something other than available */ DbgBreakPoint(); } #endif sprintf(Buffer, "MD: Type: %d; BasePage: 0x%08X; PageCount: 0x%X\n", MemoryDescriptorPtr->MemoryType, MemoryDescriptorPtr->BasePage, MemoryDescriptorPtr->PageCount); DBGMSG((Buffer)); if (ClickMapEntryPtr == NULL) { /* * remove the entry from the list */ RemoveEntryList(&MemoryDescriptorPtr->ListEntry); return; } sprintf(Buffer, "CM: StartingByte: 0x%08X; Pages: 0x%X\n", ClickMapEntryPtr->StartingByte, ClickMapEntryPtr->Pages); DBGMSG((Buffer)); Temp = ClickMapEntryPtr->StartingByte >> PAGE_SHIFT; if (MemoryDescriptorPtr->BasePage < Temp) { /* * the memory descriptor starts before the clickmap * entry. */ MemoryDescriptorPtr->PageCount -= Temp - MemoryDescriptorPtr->BasePage; MemoryDescriptorPtr->BasePage = Temp; } Temp += ClickMapEntryPtr->Pages; if ((MemoryDescriptorPtr->BasePage + MemoryDescriptorPtr->PageCount) > Temp) { /* * the memory descriptor ends after the clickmap * entry. */ MemoryDescriptorPtr->PageCount = Temp - MemoryDescriptorPtr->BasePage; } } #endif VOID NCRLimitMemory(LoaderBlockPtr) PLOADER_PARAMETER_BLOCK LoaderBlockPtr; /*++ Routine Description: For performance work the machine can be booted to only use some of the memory in the machine with the /MAXMEM setting. Here we will go through the memory list and remove and free memory above the LimitMemory address Arguments: Pointer to the loader block Return Value: none. --*/ { ULONG LimitPage; PLIST_ENTRY NextListEntry; PMEMORY_ALLOCATION_DESCRIPTOR MemDesc; // // Calculate highest page address // LimitPage = LimitMemory * 1024 * 1024 / PAGE_SIZE; // // Walk memory descritpor list looking for any pages above LimitPage // NextListEntry = LoaderBlockPtr->MemoryDescriptorListHead.Flink; while (NextListEntry != &LoaderBlockPtr->MemoryDescriptorListHead) { MemDesc = CONTAINING_RECORD(NextListEntry, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry); NextListEntry = NextListEntry->Flink; if (MemDesc->BasePage + MemDesc->PageCount > LimitPage) { // // For memory descriptor which extends above LimitPage // Either remove the memory descriptor from the system, or // shrink it. // if (MemDesc->MemoryType != MemoryFree) { DBGMSG(("NCRLimitMemory: non free memory region not freed")); continue; } if (MemDesc->BasePage > LimitPage) { RemoveEntryList(&MemDesc->ListEntry); } else { MemDesc->PageCount = MemDesc->BasePage + MemDesc->PageCount - LimitPage; } } } } VOID NCRSetupDiagnosticProcessor(LoaderBlockPtr) PLOADER_PARAMETER_BLOCK LoaderBlockPtr; /*++ Routine Description: Determine whether the diagnostic processor is using COM1. If so, make sure that the serial driver leaves COM1 alone. Note that the interface used will have to be changed to use the registry when the serial driver makes the switch. Arguments: Pointer to the loader block Return Value: none. --*/ { extern PUCHAR KdComPortInUse; UCHAR FirmwareFlags; HalpGetCmosData(1, 0x7803, (PUCHAR)&FirmwareFlags, 1); if ((FirmwareFlags & 0x80) == 0) { /* * Kernel debug not set. */ return; } if (KdComPortInUse == (PUCHAR)COM1_PORT) { /* * The debugger is using COM1. */ return; } HalDisplayString(MSG_DIAG_ENABLED); UNREFERENCED_PARAMETER(LoaderBlockPtr); } VOID NCRParseLoaderOptions (PUCHAR Options) { ULONG l; if (Options == NULL) return; NCRGetValue (Options, "NCRDEBUG", &NCRDebug); NCRGetValue (Options, "MAXMEM", &LimitMemory); if (NCRGetValue (Options, "PROCESSORS", &l)) { if (l >= 1 && l <= NCR_MAX_NUMBER_QUAD_PROCESSORS) NCRMaxProcessorCount = l; } if (NCRGetValue (Options, "NEVERCLAIM", &l)) { DefaultNeverClaimIRQs = l; } if (NCRGetValue (Options, "LARCPAGEMASK", &l)) { NCRLarcPageMask = l; } } BOOLEAN NCRGetValue (PUCHAR Options, PUCHAR String, PULONG Value) { PUCHAR p, s, t; // strstr (Options, String); for (p=Options; *p; p++) { for (s=String, t=p; *t == *s; s++, t++) { if (*s == 0) break; } if (*s == 0) break; } if (*p == 0) { return FALSE; } for (p += strlen (String); *p && (*p < '0' || *p > '9'); p++) ; // atol (p) for (*Value = 0L; *p >= '0' && *p <= '9'; p++) { *Value = *Value * 10 + *p - '0'; } return TRUE; } #define MAX_PT 8 extern StartPx_PMStub(); PVOID MpFreeCR3[MAX_PT]; // remember pool memory to free ULONG HalpBuildTiledCR3 ( IN PKPROCESSOR_STATE ProcessorState ) /*++ Routine Description: When the x86 processor is reset it starts in real-mode. In order to move the processor from real-mode to protected mode with flat addressing the segment which loads CR0 needs to have it's linear address mapped to machine the phyiscal location of the segment for said instruction so the processor can continue to execute the following instruction. This function is called to built such a tiled page directory. In addition, other flat addresses are tiled to match the current running flat address for the new state. Once the processor is in flat mode, we move to a NT tiled page which can then load up the remaining processors state. Arguments: ProcessorState - The state the new processor should start in. Return Value: Physical address of Tiled page directory --*/ { #define GetPdeAddress(va) ((PHARDWARE_PTE)((((((ULONG)(va)) >> 22) & 0x3ff) << 2) + (PUCHAR)MpFreeCR3[0])) #define GetPteAddress(va) ((PHARDWARE_PTE)((((((ULONG)(va)) >> 12) & 0x3ff) << 2) + (PUCHAR)pPageTable)) // bugbug kenr 27mar92 - fix physical memory usage! MpFreeCR3[0] = ExAllocatePool (NonPagedPool, PAGE_SIZE); RtlZeroMemory (MpFreeCR3[0], PAGE_SIZE); // // Map page for real mode stub (one page) // HalpMapCR3 ((ULONG) NonbootStartupPhysicalPtr, NonbootStartupPhysicalPtr, PAGE_SIZE); // // Map page for protect mode stub (one page) // HalpMapCR3 ((ULONG) &StartPx_PMStub, NULL, 0x1000); // // Map page(s) for processors GDT // HalpMapCR3 (ProcessorState->SpecialRegisters.Gdtr.Base, NULL, ProcessorState->SpecialRegisters.Gdtr.Limit); // // Map page(s) for processors IDT // HalpMapCR3 (ProcessorState->SpecialRegisters.Idtr.Base, NULL, ProcessorState->SpecialRegisters.Idtr.Limit); return MmGetPhysicalAddress (MpFreeCR3[0]).LowPart; } VOID HalpMapCR3 ( IN ULONG VirtAddress, IN PVOID PhysicalAddress, IN ULONG Length ) /*++ Routine Description: Called to build a page table entry for the passed page directory. Used to build a tiled page directory with real-mode & flat mode. Arguments: VirtAddress - Current virtual address PhysicalAddress - Optional. Physical address to be mapped to, if passed as a NULL then the physical address of the passed virtual address is assumed. Length - number of bytes to map Return Value: none. --*/ { ULONG i; PHARDWARE_PTE PTE; PVOID pPageTable; PHYSICAL_ADDRESS pPhysicalPage; while (Length) { PTE = GetPdeAddress (VirtAddress); if (!PTE->PageFrameNumber) { pPageTable = ExAllocatePool (NonPagedPool, PAGE_SIZE); RtlZeroMemory (pPageTable, PAGE_SIZE); for (i=0; iPageFrameNumber = (pPhysicalPage.LowPart >> PAGE_SHIFT); PTE->Valid = 1; PTE->Write = 1; } pPhysicalPage.LowPart = PTE->PageFrameNumber << PAGE_SHIFT; pPhysicalPage.HighPart = 0; pPageTable = MmMapIoSpace (pPhysicalPage, PAGE_SIZE, TRUE); PTE = GetPteAddress (VirtAddress); if (!PhysicalAddress) { PhysicalAddress = (PVOID)MmGetPhysicalAddress ((PVOID)VirtAddress).LowPart; } PTE->PageFrameNumber = ((ULONG) PhysicalAddress >> PAGE_SHIFT); PTE->Valid = 1; PTE->Write = 1; MmUnmapIoSpace (pPageTable, PAGE_SIZE); PhysicalAddress = 0; VirtAddress += PAGE_SIZE; if (Length > PAGE_SIZE) { Length -= PAGE_SIZE; } else { Length = 0; } } } VOID HalpFreeTiledCR3 ( VOID ) /*++ Routine Description: Free's any memory allocated when the tiled page directory was built. Arguments: none Return Value: none --*/ { ULONG i; for (i=0; MpFreeCR3[i]; i++) { ExFreePool (MpFreeCR3[i]); MpFreeCR3[i] = 0; } } ULONG HalpNCRGetSystemInterruptVector( IN PBUS_HANDLER BusHandler, IN PBUS_HANDLER RootHandler, IN ULONG BusInterruptLevel, IN ULONG BusInterruptVector, OUT PKIRQL Irql, OUT PKAFFINITY Affinity ) /*++ Routine Description: Arguments: BusInterruptLevel - Supplies the bus specific interrupt level. BusInterruptVector - Supplies the bus specific interrupt vector. Irql - Returns the system request priority. Affinity - Returns the system wide irq affinity. Return Value: Returns the system interrupt vector corresponding to the specified device. --*/ { ULONG SystemVector; UNREFERENCED_PARAMETER( BusHandler ); UNREFERENCED_PARAMETER( RootHandler ); SystemVector = BusInterruptVector + PRIMARY_VECTOR_BASE; if (SystemVector < PRIMARY_VECTOR_BASE || HalpIDTUsage[SystemVector].Flags & IDTOwned ) { // // This is an illegal BusInterruptVector and cannot be connected. // return(0); } *Irql = (KIRQL)(HIGHEST_LEVEL_FOR_8259 - BusInterruptLevel); *Affinity = HalpDefaultInterruptAffinity; ASSERT(HalpDefaultInterruptAffinity); return SystemVector; } VOID HalpInitOtherBuses ( VOID ) { PBUS_HANDLER InternalBus; PBUS_HANDLER McaBus; PBUS_HANDLER Bus; CAT_CONTROL cat_control; UCHAR data; LONG status; if (NCRPlatform != NCR3360) { HalpInitializeCatBusDriver(); HalpDisableSingleBitErrorDET(); HalpInitializeSMCInterface(); NCRFindExtendedProcessors(); if ((NCRDebug & 0x20) == 1) { HalpInitializeLarc(); } // // Turn off cache ownership it NCRDebug bit is set and you only have one Quad board installed // in slot 1 // if ((NCRDebug & 0x10) && (NCRExistingProcessorMask == 0xf)) { DBGMSG(("HalpInitOtherBuses: Changing QCC Asic on Quad\n")); cat_control.Module = QUAD_LL2_A0; cat_control.Asic = QCC0; cat_control.Command = READ_REGISTER; cat_control.NumberOfBytes = 1; cat_control.Address = 0x4; status = HalpCatBusIo(&cat_control,&data); DBGMSG(("HalpInitOtherBuses: QCC0 A0 Nside Config 0 read 0x%x\n", data)); data |= 0x40; cat_control.Module = QUAD_LL2_A0; cat_control.Asic = QCC0; cat_control.Command = WRITE_REGISTER; cat_control.NumberOfBytes = 1; cat_control.Address = 0x4; status = HalpCatBusIo(&cat_control,&data); cat_control.Module = QUAD_LL2_B0; cat_control.Asic = QCC0; cat_control.Command = READ_REGISTER; cat_control.NumberOfBytes = 1; cat_control.Address = 0x4; status = HalpCatBusIo(&cat_control,&data); DBGMSG(("HalpInitOtherBuses: QCC0 B0 Nside Config 0 read 0x%x\n", data)); data |= 0x40; cat_control.Module = QUAD_LL2_B0; cat_control.Asic = QCC0; cat_control.Command = WRITE_REGISTER; cat_control.NumberOfBytes = 1; cat_control.Address = 0x4; status = HalpCatBusIo(&cat_control,&data); cat_control.Module = QUAD_LL2_A0; cat_control.Asic = QCC1; cat_control.Command = READ_REGISTER; cat_control.NumberOfBytes = 1; cat_control.Address = 0x4; status = HalpCatBusIo(&cat_control,&data); DBGMSG(("HalpInitOtherBuses: QCC1 A0 Nside Config 0 read 0x%x\n", data)); data |= 0x40; cat_control.Module = QUAD_LL2_A0; cat_control.Asic = QCC1; cat_control.Command = WRITE_REGISTER; cat_control.NumberOfBytes = 1; cat_control.Address = 0x4; status = HalpCatBusIo(&cat_control,&data); cat_control.Module = QUAD_LL2_B0; cat_control.Asic = QCC1; cat_control.Command = READ_REGISTER; cat_control.NumberOfBytes = 1; cat_control.Address = 0x4; status = HalpCatBusIo(&cat_control,&data); DBGMSG(("HalpInitOtherBuses: QCC1 B0 Nside Config 0 read 0x%x\n", data)); data |= 0x40; cat_control.Module = QUAD_LL2_B0; cat_control.Asic = QCC1; cat_control.Command = WRITE_REGISTER; cat_control.NumberOfBytes = 1; cat_control.Address = 0x4; status = HalpCatBusIo(&cat_control,&data); cat_control.Module = QUAD_BB0; cat_control.Asic = QABC; cat_control.Command = READ_REGISTER; cat_control.NumberOfBytes = 1; cat_control.Address = 0xb; status = HalCatBusIo(&cat_control,&data); DBGMSG(("HalpInitOtherBuses: QABC Nbus Config read 0x%x\n", data)); data |= 0x10; cat_control.Module = QUAD_BB0; cat_control.Asic = QABC; cat_control.Command = WRITE_REGISTER; cat_control.NumberOfBytes = 1; cat_control.Address = 0xb; status = HalCatBusIo(&cat_control,&data); } InternalBus = HalpHandlerForBus( Internal, 0); InternalBus->GetInterruptVector = HalpNCRGetSystemInterruptVector; // // Change MCA bus #0 // McaBus = HalpHandlerForBus( MicroChannel, 0); McaBus->GetInterruptVector = HalpGetMCAInterruptVector; // // Build MCA bus #1 if present // if (NCRSegmentIoRegister != NULL) { Bus = HalpAllocateBusHandler (MicroChannel, Pos, 1, Internal, 0, 0); Bus->GetBusData = HalpGetPosData; Bus->GetInterruptVector = HalpGetSMCAInterruptVector; Bus->TranslateBusAddress = HalpTranslateSMCBusAddress; Bus->AdjustResourceList = HalpAdjustMCAResourceList; } } } VOID HalpDisableSingleBitErrorDET ( ) /*++ Routine Description: Disable Single Bit Error Reporting Arguments: none Return Value: none --*/ { CAT_CONTROL cat_control; UCHAR data; LONG status; // // Disable single bit error interrupt MMC on memory board 0 // cat_control.Module = MEMORY0; cat_control.Asic = MMC1; cat_control.NumberOfBytes = 1; cat_control.Address = MMC1_Config1; cat_control.Command = READ_REGISTER; status = HalpCatBusIo(&cat_control,&data); if (status == CATNOERR) { // // disable reporting via mem_error_int // correction still enabled // data |= MMC1_SBErr_DetectDisable; cat_control.NumberOfBytes = 1; cat_control.Address = MMC1_Config1; cat_control.Command = WRITE_REGISTER; HalpCatBusIo(&cat_control,&data); } // // Disable single bit error interrupt MMC on memory board 1 // cat_control.Module = MEMORY1; cat_control.Asic = MMC1; cat_control.NumberOfBytes = 1; cat_control.Address = MMC1_Config1; cat_control.Command = READ_REGISTER; status = HalpCatBusIo(&cat_control,&data); if (status == CATNOERR) { // // disable reporting via mem_error_int // correction still enabled // data |= MMC1_SBErr_DetectDisable; cat_control.NumberOfBytes = 1; cat_control.Address = MMC1_Config1; cat_control.Command = WRITE_REGISTER; HalpCatBusIo(&cat_control,&data); } } VOID HalpInitializeSMCInterface ( ) /*++ Routine Description: Check for SMC board and it present setup segment register. Arguments: none Return Value: none --*/ { CAT_CONTROL cat_control; UCHAR data; LONG status; PHYSICAL_ADDRESS physical_address; PUCHAR mapped_segment_address; cat_control.Module = SECONDARYMC; cat_control.Asic = CAT_I; cat_control.Command = READ_REGISTER; cat_control.NumberOfBytes = 1; cat_control.Address = 0; status = HalpCatBusIo(&cat_control,&data); if (status != CATNOMOD) { /* * SMC is installed in this unit */ DBGMSG(("HalpInitializeSMCInterface: SMC has been detected...\n")); physical_address.HighPart = 0; physical_address.LowPart = NCRSegmentIoAddress; mapped_segment_address = (PUCHAR) MmMapIoSpace(physical_address, sizeof(UCHAR), FALSE); if (mapped_segment_address != NULL) { NCRSegmentIoRegister = mapped_segment_address; } /*RMU temp fix for arb control register on DMA asic. */ WRITE_PORT_UCHAR((PUCHAR)0x10090, (UCHAR)0x8f); } } VOID HalpCatReportSMC ( ) /*++ Routine Description: Place information about system modules into the registry. Arguments: Return Value: --*/ { PMODULE module; PASIC asic; PWSTR smc_path = L"\\Registry\\Machine\\Hardware\\DESCRIPTION\\System\\MultifunctionAdapter\\1"; UNICODE_STRING unicode_smc; OBJECT_ATTRIBUTES smc_attributes; HANDLE smc_handle; UNICODE_STRING unicode_name; UNICODE_STRING unicode_mca; NTSTATUS status; ULONG tmp; CONFIGURATION_COMPONENT component; ULONG ConfigurationDataLength; SMC_RESOURCES SmcConfig; int i; /* * */ RtlInitUnicodeString(&unicode_smc,smc_path); InitializeObjectAttributes( &smc_attributes, &unicode_smc, OBJ_CASE_INSENSITIVE, NULL, NULL); status = ZwCreateKey(&smc_handle, KEY_READ | KEY_WRITE, &smc_attributes, 0, (PUNICODE_STRING)NULL, REG_OPTION_VOLATILE, NULL); RtlInitUnicodeString(&unicode_name,L"Component Information"); RtlZeroMemory (&component, sizeof(CONFIGURATION_COMPONENT)); component.AffinityMask = 0xffffffff; status = ZwSetValueKey( smc_handle, &unicode_name, 0, REG_BINARY, &component.Flags, FIELD_OFFSET(CONFIGURATION_COMPONENT, ConfigurationDataLength) - FIELD_OFFSET(CONFIGURATION_COMPONENT, Flags) ); RtlInitUnicodeString(&unicode_name,L"Configuration Data"); RtlZeroMemory (&SmcConfig, sizeof(SMC_RESOURCES)); ConfigurationDataLength = sizeof(SMC_RESOURCES); // // Set up InterfaceType and BusNumber for the component. // SmcConfig.ConfigurationData.InterfaceType = MicroChannel; SmcConfig.ConfigurationData.BusNumber = 1; SmcConfig.ConfigurationData.PartialResourceList.Count = 1; SmcConfig.ConfigurationData.PartialResourceList.PartialDescriptors[0].Type = CmResourceTypeDeviceSpecific; SmcConfig.ConfigurationData.PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareUndetermined; SmcConfig.ConfigurationData.PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize = sizeof(CM_MCA_POS_DATA)*10; for (i = 0; i < 8; i++) { HalGetBusData(Pos, 1, i, &SmcConfig.PosData[i], sizeof(CM_MCA_POS_DATA)); } // // Write the newly constructed configuration data to the hardware registry // status = ZwSetValueKey( smc_handle, &unicode_name, 0, REG_FULL_RESOURCE_DESCRIPTOR, &SmcConfig, ConfigurationDataLength ); RtlInitUnicodeString(&unicode_name,L"Identifier"); RtlInitUnicodeString(&unicode_mca,L"MCA"); status = ZwSetValueKey(smc_handle, &unicode_name, 0, REG_SZ, unicode_mca.Buffer, unicode_mca.Length + sizeof(UNICODE_NULL)); status = ZwClose(smc_handle); } VOID HalSetStatusChangeInterruptState( ULONG State ) /*++ Routine Description: This HAL function will enable or disable the revectoring of the Status Change Interrupt to vector 57. Arguments: Return Value: --*/ { if (State) { NCRStatusChangeInterruptEnabled = 0x1; } else { NCRStatusChangeInterruptEnabled = 0x0; } } ULONG NCRTranslateCMOSMask( ULONG CmosMask ) /*++ Routine Description: This function translates the CMOS processor Mask into what we want to use. This function must change for 32 way CMOS format is: each nibble contains all processors 0 in the system where each bit position denotes the processor slot. Therefore a system with one Quad board has a mask of (0x1111), 2 Quad boards has a mask of (0x3333), 3 Quad boards has a mask of (0x7777), and 4 Quad boards has a mask of (0xffff). Our format is: each nibble contains all processors on one Quad board where each bit position denotes the processor on one board. Therefore a system with one Quad board has a mask of (0x000f), 2 Quad boards has a mask of (0x00ff), 3 Quad boards has a mask of (0x0ffff), and 4 Quad boards has a mask of (xffff); Arguments: Return Value: The Processor Mask that the Hal wants to use for bringing up the system. --*/ { ULONG working_mask = CmosMask; ULONG existing_mask = 0x0; int i, j; // loop thru each processor number for (i = 0; i < 4; i++ ) { // loop thru each processor slot for (j = 0; j < 4; j++) { if (working_mask & 0x1) { existing_mask |= ((1 << i) << (j<<2)); } working_mask >>= 1; } } return existing_mask; } ULONG NCRTranslateToCMOSMask( ULONG Mask ) /*++ Routine Description: Do the oppsite of NCRTranslateCMOSMask() Arguments: Return Value: The Processor Mask that CMOS uses. --*/ { ULONG working_mask = Mask; ULONG cmos_mask = 0x0; int i; for (i = 0; i < 4; i++ ) { if (working_mask & 1) { cmos_mask |= (0x1 << i); } if (working_mask & 2) { cmos_mask |= (0x10 << i); } working_mask >>= 4; } return cmos_mask; } VOID NCRFindExtendedProcessors( ) /*++ Routine Description: Loop over the CAT bus and find all extended processors Arguments: Return Value: --*/ { CAT_CONTROL cat_control; UCHAR data; UCHAR qabc_ext; LONG status; UCHAR module; int slot; for(slot = 0; slot < 4; slot++) { switch (slot) { case 0: module = QUAD_BB0; break; case 1: module = QUAD_BB1; break; case 2: module = QUAD_BB2; break; case 3: module = QUAD_BB3; break; } cat_control.Module = module; cat_control.Asic = QABC; cat_control.Command = READ_SUBADDR; cat_control.NumberOfBytes = 1; cat_control.Address = 0x8; status = HalpCatBusIo(&cat_control,&qabc_ext); if (status == CATNOERR) { // NCRExtendedProcessor0Mask |= (qabc_ext & 0xf) << (qabc_ext << 2); NCRExtendedProcessor0Mask |= (qabc_ext & 0xf) << (slot << 2); NCRExtendedProcessor1Mask |= (qabc_ext >> 4) << (slot << 2); } } NCRExtendedProcessorMask = NCRExtendedProcessor0Mask | NCRExtendedProcessor1Mask; DBGMSG(("NCRFindExtendedProcessors: Extended 0 = 0x%x, 1 = 0x%x\n", NCRExtendedProcessor0Mask, NCRExtendedProcessor1Mask)); } VOID NCRAdjustDynamicClaims( ) /*++ Routine Description: Determine how man interrupts a processor should claim. This is called when processors are enabled and with interrups are enabled and disabled Arguments: Return Value: --*/ { ULONG processors = 0; ULONG max_claimable_irqs = 0; ULONG processor; ULONG irq_count; ULONG mask; // // Count the number of processors that can take device interrupts. // for (mask = HalpDefaultInterruptAffinity; mask != 0; mask >>= 1) { if (mask & 0x1) { processors++; } } for (processor = 0; processor < NCRActiveProcessorCount; processor++) { mask = NCRProcessorIDR[processor]; mask |= NCRNeverClaimIRQs; // do not count never claim IRQs irq_count = 0; for (mask = ~mask; (mask != 0); mask >>= 1) { if (mask & 0x1) { irq_count++; } } if (irq_count > max_claimable_irqs) { max_claimable_irqs = irq_count; } } if ((max_claimable_irqs % processors) == 0) { max_claimable_irqs /= processors; } else { max_claimable_irqs /= processors; max_claimable_irqs++; } if (max_claimable_irqs == 0) { max_claimable_irqs = 1; } NCRMaxIRQsToClaim = max_claimable_irqs; } #ifdef DBG VOID NCRConsoleDebug( ULONG MsgNumber, ULONG Data ) { CHAR buffer[256]; switch (MsgNumber) { case 1: sprintf(buffer, "HalInitializeProcessor called for processor %d\n", Data); HalDisplayString(buffer); break; case 2: sprintf(buffer, "HalStartNextProcessor trying to wakeup 0x%x\n", Data); HalDisplayString(buffer); break; case 3: sprintf(buffer, "HalStartNextProcessor Processor is now awake\n", Data); HalDisplayString(buffer); break; } } #endif NTSTATUS HalpGetMcaLog ( OUT PMCA_EXCEPTION Exception, OUT PULONG ReturnedLength ) { return STATUS_NOT_SUPPORTED; } NTSTATUS HalpMcaRegisterDriver( IN PMCA_DRIVER_INFO DriverInfo ) { return STATUS_NOT_SUPPORTED; } ULONG FASTCALL HalSystemVectorDispatchEntry ( IN ULONG Vector, OUT PKINTERRUPT_ROUTINE **FlatDispatch, OUT PKINTERRUPT_ROUTINE *NoConnection ) { return FALSE; }