mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2443 lines
71 KiB
2443 lines
71 KiB
/*++
|
|
|
|
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; i<MAX_PT; i++) {
|
|
if (!MpFreeCR3[i]) {
|
|
MpFreeCR3[i] = pPageTable;
|
|
break;
|
|
}
|
|
}
|
|
ASSERT (i<MAX_PT);
|
|
|
|
pPhysicalPage = MmGetPhysicalAddress (pPageTable);
|
|
PTE->PageFrameNumber = (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;
|
|
}
|