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.
1237 lines
33 KiB
1237 lines
33 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
initkr.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code to initialize the kernel data structures
|
|
and to initialize the idle thread, its process, and the processor control
|
|
block.
|
|
|
|
Author:
|
|
|
|
Bernard Lint 8-Aug-1996
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
Based on MIPS version (David N. Cutler (davec) 11-Apr-1990)
|
|
--*/
|
|
|
|
#include "ki.h"
|
|
|
|
|
|
//
|
|
// Put all code for kernel initialization in the INIT section. It will be
|
|
// deallocated by memory management when phase 1 initialization is completed.
|
|
//
|
|
|
|
VOID
|
|
KiInitializeProcessorIds(
|
|
IN PKPRCB Prcb
|
|
);
|
|
|
|
ULONG
|
|
KiGetFeatureBits(
|
|
IN PKPRCB Prcb
|
|
);
|
|
|
|
VOID
|
|
FASTCALL
|
|
KiZeroPages (
|
|
IN PVOID PageBase,
|
|
IN SIZE_T NumberOfPages
|
|
);
|
|
|
|
#if defined(ALLOC_PRAGMA)
|
|
|
|
#pragma alloc_text(INIT, KiGetFeatureBits)
|
|
#pragma alloc_text(INIT, KiInitializeProcessorIds)
|
|
#pragma alloc_text(INIT, KiInitializeKernel)
|
|
#pragma alloc_text(INIT, KiInitMachineDependent)
|
|
|
|
#endif
|
|
|
|
KE_ZERO_PAGE_ROUTINE KeZeroPages = KiZeroPages;
|
|
KE_ZERO_PAGE_ROUTINE KeZeroPagesFromIdleThread = KiZeroPages;
|
|
|
|
//
|
|
// KiTbBroadcastLock - This is the spin lock that prevents the other processors
|
|
// from issuing PTC.G (TB purge broadcast) operations.
|
|
//
|
|
|
|
KSPIN_LOCK KiTbBroadcastLock;
|
|
|
|
//
|
|
// KiMasterRidLock - This is the spin lock that prevents the other processors
|
|
// from updating KiMasterRid.
|
|
//
|
|
|
|
KSPIN_LOCK KiMasterRidLock;
|
|
|
|
//
|
|
// KiRegionSwapLock - This is the lock that covers all context swap operations
|
|
//
|
|
|
|
KSPIN_LOCK KiRegionSwapLock;
|
|
|
|
//
|
|
// KiCacheFlushLock - This is the spin lock that ensures cache flush is only
|
|
// done on one processor at a time. (SAL cache flush not yet MP safe).
|
|
//
|
|
|
|
KSPIN_LOCK KiCacheFlushLock;
|
|
|
|
//
|
|
// KiUserSharedDataPage - This holds the page number of UserSharedDataPage for
|
|
// MP boot
|
|
//
|
|
|
|
ULONG_PTR KiUserSharedDataPage;
|
|
|
|
//
|
|
// KiKernelPcrPage - This holds the page number of per-processor PCR page for
|
|
// MP boot
|
|
//
|
|
|
|
ULONG_PTR KiKernelPcrPage = 0i64;
|
|
|
|
//
|
|
// VHPT configuation variables
|
|
//
|
|
|
|
IA64_VM_SUMMARY1 KiIA64VmSummary1;
|
|
IA64_VM_SUMMARY2 KiIA64VmSummary2;
|
|
IA64_PTCE_INFO KiIA64PtceInfo;
|
|
ULONG_PTR KiIA64PtaContents;
|
|
ULONG_PTR KiIA64PtaHpwEnabled = 1;
|
|
ULONG_PTR KiIA64VaSign;
|
|
ULONG_PTR KiIA64VaSignedFill;
|
|
ULONG_PTR KiIA64PtaBase;
|
|
ULONG_PTR KiIA64PtaSign;
|
|
ULONG KiIA64ImpVirtualMsb;
|
|
ULONG KiNumberOfCacheLevels;
|
|
IA64_CACHE_INFO1 KiCacheInfo1[2][CONFIG_INFO_CACHE_LEVELS]; // Pass several levels of cache information
|
|
IA64_CACHE_INFO2 KiCacheInfo2[2][CONFIG_INFO_CACHE_LEVELS]; // One each for instruction and data.
|
|
ULONG_PTR KiIA64RseNumOfPhysRegs;
|
|
ULONG_PTR KiIA64RseNumOfMaxDirty;
|
|
ULONG_PTR KiIA64RseHints;
|
|
extern ULONG KiMaximumRid;
|
|
|
|
//
|
|
// KiExceptionDeferralMode - This holds the mode for the exception deferral
|
|
// policy
|
|
//
|
|
|
|
ULONG KiExceptionDeferralMode;
|
|
|
|
//
|
|
// KiBackingStoreSecurityMode - This holds the security policy for the backing store
|
|
//
|
|
|
|
ULONG KiBackingStoreSecurityMode = 1;
|
|
|
|
//
|
|
// Initial DCR value
|
|
//
|
|
|
|
ULONGLONG KiIA64DCR = DCR_INITIAL;
|
|
|
|
//
|
|
// KiVectorLogMask - bitmap for enable/disable the interruption logging
|
|
//
|
|
|
|
LONGLONG KiVectorLogMask;
|
|
|
|
//
|
|
// KiHistoryBufferLogMask - bitmap for enable/disable the history buffer logging
|
|
//
|
|
|
|
LONGLONG KiHistoryBufferLogMask;
|
|
|
|
//
|
|
// Definition of bits that must be set in user's PSR value
|
|
// N.B. Initial value of bit PSR_DI in UserPsrSetMask is 0.
|
|
//
|
|
|
|
ULONGLONG UserPsrSetMask = PSR_USER_SET;
|
|
|
|
//
|
|
// Ensure all the PSR bits are represented in all the mask once and only once.
|
|
//
|
|
|
|
C_ASSERT((PSR_KERNEL_CLR ^ PSR_KERNEL_SET ^ PSR_KERNEL_CPY) == -1);
|
|
C_ASSERT((PSR_USER_CLR ^ PSR_USER_SET ^ PSR_USER_CPY) == -1);
|
|
|
|
|
|
|
|
ULONG
|
|
KiGetFeatureBits(
|
|
PKPRCB Prcb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the NT Feature Bits supported by the specified
|
|
processor control block.
|
|
|
|
Arguments:
|
|
|
|
Prcb - Supplies a pointer to a processor control block for the specified
|
|
processor.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Comments:
|
|
|
|
This function is called after the initialization of the IA64 processor
|
|
control block ProcessorFeatureBits field and after HalInitializeProcessor().
|
|
|
|
--*/
|
|
|
|
{
|
|
// WARNING: NT system wide feature bits is a 32-bit type.
|
|
ULONG features = (ULONG) Prcb->ProcessorFeatureBits;
|
|
|
|
//
|
|
// Check for Long Branch instruction support.
|
|
//
|
|
|
|
if ( features & 0x1 ) {
|
|
features |= KF_BRL;
|
|
}
|
|
|
|
return features;
|
|
|
|
} // KiGetFeatureBits()
|
|
|
|
|
|
|
|
VOID
|
|
KiInitializeProcessorIds(
|
|
IN PKPRCB Prcb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called early in the initialization of the kernel
|
|
to initialize the processor indentification registers located
|
|
in the processor control block.
|
|
This function is called for each processor and should be called b
|
|
before the HAL is called.
|
|
|
|
Arguments:
|
|
|
|
Prcb - Supplies a pointer to a processor control block for the specified
|
|
processor.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Comments:
|
|
|
|
This function simply deals with IA64 architected CPUID registers.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONGLONG val;
|
|
|
|
// IA64 architected CPUID3: Version information.
|
|
|
|
val = __getReg( CV_IA64_CPUID3 );
|
|
Prcb->ProcessorRevision = (ULONG) ((val >> 8 ) & 0xFF);
|
|
Prcb->ProcessorModel = (ULONG) ((val >> 16) & 0xFF);
|
|
Prcb->ProcessorFamily = (ULONG) ((val >> 24) & 0xFF);
|
|
Prcb->ProcessorArchRev = (ULONG) ((val >> 32) & 0xFF);
|
|
|
|
// IA64 architected CPUID0 & CPUID1: Vendor Information.
|
|
|
|
val = __getReg( CV_IA64_CPUID0 );
|
|
strncpy( (PCHAR) Prcb->ProcessorVendorString , (PCHAR)&val, 8 );
|
|
val = __getReg( CV_IA64_CPUID1 );
|
|
strncpy( (PCHAR)&Prcb->ProcessorVendorString[8], (PCHAR)&val, 8 );
|
|
|
|
// IA64 architected CPUID2: Processor Serial Number.
|
|
|
|
Prcb->ProcessorSerialNumber = __getReg( CV_IA64_CPUID2 );
|
|
|
|
// IA64 architected CPUID4: General Features / Capability bits.
|
|
|
|
Prcb->ProcessorFeatureBits = __getReg( CV_IA64_CPUID4 );
|
|
|
|
if ( (Prcb->ProcessorFamily != 0x7) && (Prcb->ProcessorFamily != 0x1F) ) {
|
|
|
|
//
|
|
// If it is neither Itanium nor Itanium2, ISA transition
|
|
// is disabled
|
|
//
|
|
|
|
UserPsrSetMask |= MASK_IA64(PSR_DI, 1i64);
|
|
}
|
|
return;
|
|
|
|
} // KiInitializeProcessorIds()
|
|
|
|
#if defined(_MERCED_A0_)
|
|
VOID
|
|
KiProcessorWorkAround(
|
|
);
|
|
|
|
VOID
|
|
KiSwitchToLogVector(
|
|
VOID
|
|
);
|
|
|
|
extern BOOLEAN KiIpiTbShootdown;
|
|
|
|
ULONGLONG KiConfigFlag;
|
|
|
|
//
|
|
// Process the boot loader configuration flags.
|
|
//
|
|
|
|
VOID
|
|
KiProcessorConfigFlag(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
{
|
|
PCHAR ConfigFlag;
|
|
ULONG ConfigFlagValue=0;
|
|
ULONGLONG Cpuid3;
|
|
ULONGLONG ItaniumId;
|
|
ULONGLONG PalFeatureSet;
|
|
LONGLONG Status;
|
|
|
|
Cpuid3 = __getReg( CV_IA64_CPUID3 );
|
|
ItaniumId = 0xFFFFFF0000I64 & Cpuid3;
|
|
|
|
ConfigFlag = strstr(LoaderBlock->LoadOptions, "CONFIGFLAG");
|
|
if (ConfigFlag != NULL) {
|
|
|
|
ConfigFlag = strstr(ConfigFlag, "=");
|
|
if (ConfigFlag != NULL) {
|
|
ConfigFlagValue = atol(ConfigFlag+1);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Set the recommened ConfigFlagValue for Itanium, B1/B2
|
|
// if there is no CONFIGFLAG keyword
|
|
//
|
|
|
|
if (ItaniumId == 0x0007000000) {
|
|
|
|
switch (Cpuid3) {
|
|
case 0x0007000004: // Itanium, A stepping
|
|
case 0x0007000104: // Itanium, B0 stepping
|
|
ConfigFlagValue = 0;
|
|
break;
|
|
case 0x0007000204: // Itanium, B1 stepping
|
|
case 0x0007000304: // Itanium, B2 stepping
|
|
ConfigFlagValue = 1054;
|
|
break;
|
|
case 0x0007000404: // Itanium, B3 stepping
|
|
case 0x0007000504: // Itanium, B4 stepping
|
|
ConfigFlagValue = 19070;
|
|
break;
|
|
case 0x0007000604: // Itanium, C0 or later stepping
|
|
ConfigFlagValue = 2943 | (1 << DISABLE_INTERRUPTION_LOG);
|
|
break;
|
|
default:
|
|
ConfigFlagValue = 35711 | (1 << DISABLE_INTERRUPTION_LOG);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Make ptc.g enabled by default
|
|
//
|
|
|
|
ConfigFlagValue = 32 | (1 << DISABLE_INTERRUPTION_LOG);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Save config flag value.
|
|
//
|
|
|
|
KiConfigFlag = ConfigFlagValue;
|
|
|
|
//
|
|
// do the processor MSR workarounds
|
|
//
|
|
|
|
KiProcessorWorkAround(ConfigFlagValue);
|
|
|
|
//
|
|
// Call PAL to disable McKinley 692 workaround to improve
|
|
// performance. Disable should not be done if kernel does a
|
|
// br.ret from kernel to user mode.
|
|
//
|
|
|
|
if (ItaniumId == 0x001F000000) {
|
|
|
|
// Get current feature settings
|
|
|
|
Status = HalCallPal (PAL_PROC_GET_FEATURES, 0, 16, 0,
|
|
NULL, NULL, &PalFeatureSet, NULL);
|
|
|
|
if (Status == PAL_STATUS_SUCCESS) {
|
|
|
|
// Disable workaround: bit 7 = 1
|
|
|
|
PalFeatureSet |= 0x80;
|
|
Status = HalCallPal (PAL_PROC_SET_FEATURES, PalFeatureSet, 16, 0,
|
|
NULL, NULL, NULL, NULL);
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// For Conditional Interrupt Logging
|
|
// switch to shadow IVT depending on ConfigFlag
|
|
//
|
|
|
|
if (ConfigFlagValue & (1 << DISABLE_INTERRUPTION_LOG)) {
|
|
KiVectorLogMask = 0;
|
|
} else {
|
|
|
|
//
|
|
// By default disable logging of:
|
|
// KiAltInstTlbVectorBit 3
|
|
// KiAltDataTlbVectorBit 4
|
|
//
|
|
|
|
KiVectorLogMask = 0xffffffffffffffffI64;
|
|
KiSwitchToLogVector();
|
|
}
|
|
|
|
if (ConfigFlagValue & (1 << ENABLE_HISTORY_BUFFER)) {
|
|
KiHistoryBufferLogMask = 0xffffffffffffffffI64;
|
|
} else {
|
|
KiHistoryBufferLogMask = 0;
|
|
}
|
|
|
|
//
|
|
// check to see if the VHPT walker should be disabled
|
|
//
|
|
|
|
if (ConfigFlagValue & (1 << DISABLE_VHPT_WALKER)) {
|
|
KiIA64PtaHpwEnabled = 0;
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
ULONG
|
|
KiInitializeKernelUnhandledExceptionFilter(
|
|
IN PEXCEPTION_POINTERS ExceptionPointers
|
|
)
|
|
{
|
|
KdPrint(("KE: Unhandled Kernel Mode Exception Pointers = 0x%p\n", ExceptionPointers));
|
|
KdPrint(("Code %x Addr %p\nInfo0 %p Info1 %p Info2 %p\nInfo3 %p Info4 %p Info5 %p\n",
|
|
ExceptionPointers->ExceptionRecord->ExceptionCode,
|
|
(ULONG_PTR)ExceptionPointers->ExceptionRecord->ExceptionAddress,
|
|
ExceptionPointers->ExceptionRecord->ExceptionInformation[0],
|
|
ExceptionPointers->ExceptionRecord->ExceptionInformation[1],
|
|
ExceptionPointers->ExceptionRecord->ExceptionInformation[2],
|
|
ExceptionPointers->ExceptionRecord->ExceptionInformation[3],
|
|
ExceptionPointers->ExceptionRecord->ExceptionInformation[4],
|
|
ExceptionPointers->ExceptionRecord->ExceptionInformation[5]
|
|
));
|
|
|
|
KeBugCheckEx(
|
|
PHASE0_EXCEPTION,
|
|
ExceptionPointers->ExceptionRecord->ExceptionCode,
|
|
(ULONG_PTR)ExceptionPointers->ExceptionRecord->ExceptionAddress,
|
|
ExceptionPointers->ExceptionRecord->ExceptionInformation[0],
|
|
ExceptionPointers->ExceptionRecord->ExceptionInformation[1]
|
|
);
|
|
}
|
|
|
|
|
|
VOID
|
|
KiInitializeKernel (
|
|
IN PKPROCESS Process,
|
|
IN PKTHREAD Thread,
|
|
IN PVOID IdleStack,
|
|
IN PKPRCB Prcb,
|
|
IN CCHAR Number,
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function gains control after the system has been bootstrapped and
|
|
before the system has been initialized. Its function is to initialize
|
|
the kernel data structures, initialize the idle thread and process objects,
|
|
initialize the processor control block, call the executive initialization
|
|
routine, and then return to the system startup routine. This routine is
|
|
also called to initialize the processor specific structures when a new
|
|
processor is brought on line.
|
|
|
|
Arguments:
|
|
|
|
Process - Supplies a pointer to a control object of type process for
|
|
the specified processor.
|
|
|
|
Thread - Supplies a pointer to a dispatcher object of type thread for
|
|
the specified processor.
|
|
|
|
IdleStack - Supplies a pointer the base of the real kernel stack for
|
|
idle thread on the specified processor.
|
|
|
|
Prcb - Supplies a pointer to a processor control block for the specified
|
|
processor.
|
|
|
|
Number - Supplies the number of the processor that is being
|
|
initialized.
|
|
|
|
LoaderBlock - Supplies a pointer to the loader parameter block.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG Index;
|
|
KIRQL OldIrql;
|
|
ULONG_PTR DirectoryTableBase[2];
|
|
PVOID KernelStack;
|
|
USHORT ProcessorRevision;
|
|
|
|
//
|
|
// Perform Processor Identification Registers update.
|
|
//
|
|
// This has to be done before HalInitializeProcessor to offer
|
|
// a possibility for the HAL to look at them.
|
|
//
|
|
|
|
KiInitializeProcessorIds( Prcb );
|
|
|
|
//
|
|
// Perform platform dependent processor initialization.
|
|
//
|
|
|
|
HalInitializeProcessor(Number, LoaderBlock);
|
|
|
|
//
|
|
// Apply processor config flag and workarounds
|
|
//
|
|
|
|
KiProcessorConfigFlag(LoaderBlock);
|
|
|
|
//
|
|
// Save the address of the loader parameter block.
|
|
//
|
|
|
|
KeLoaderBlock = LoaderBlock;
|
|
|
|
//
|
|
// Initialize the processor block.
|
|
//
|
|
|
|
Prcb->MinorVersion = PRCB_MINOR_VERSION;
|
|
Prcb->MajorVersion = PRCB_MAJOR_VERSION;
|
|
Prcb->BuildType = 0;
|
|
|
|
#if DBG
|
|
|
|
Prcb->BuildType |= PRCB_BUILD_DEBUG;
|
|
|
|
#endif
|
|
|
|
#if defined(NT_UP)
|
|
|
|
Prcb->BuildType |= PRCB_BUILD_UNIPROCESSOR;
|
|
|
|
#endif
|
|
|
|
Prcb->CurrentThread = Thread;
|
|
Prcb->NextThread = (PKTHREAD)NULL;
|
|
Prcb->IdleThread = Thread;
|
|
Prcb->Number = Number;
|
|
Prcb->SetMember = AFFINITY_MASK(Number);
|
|
Prcb->PcrPage = LoaderBlock->u.Ia64.PcrPage;
|
|
|
|
//
|
|
// initialize the per processor lock data.
|
|
//
|
|
|
|
KiInitSpinLocks(Prcb, Number);
|
|
|
|
//
|
|
// Initialize the interprocessor communication packet.
|
|
//
|
|
|
|
#if !defined(NT_UP)
|
|
|
|
Prcb->TargetSet = 0;
|
|
Prcb->WorkerRoutine = NULL;
|
|
Prcb->RequestSummary = 0;
|
|
Prcb->IpiFrozen = 0;
|
|
|
|
#endif
|
|
|
|
//
|
|
// Set address of processor block.
|
|
//
|
|
|
|
KiProcessorBlock[Number] = Prcb;
|
|
|
|
//
|
|
// Initialize processors PowerState
|
|
//
|
|
|
|
PoInitializePrcb (Prcb);
|
|
|
|
//
|
|
// Set global processor architecture. Global processor level and
|
|
// revision will be set on a least common denominator basis.
|
|
//
|
|
|
|
KeProcessorArchitecture = PROCESSOR_ARCHITECTURE_IA64;
|
|
ProcessorRevision = (USHORT) ((Prcb->ProcessorModel << 8) |
|
|
Prcb->ProcessorRevision);
|
|
|
|
//
|
|
// Initialize the address of the bus error routines / machine check
|
|
//
|
|
// **** TBD
|
|
|
|
//
|
|
// Initialize the idle thread initial kernel stack and limit address value.
|
|
//
|
|
|
|
PCR->InitialStack = (ULONGLONG)IdleStack;
|
|
PCR->InitialBStore = (ULONGLONG)IdleStack;
|
|
PCR->StackLimit = (ULONGLONG)((ULONG_PTR)IdleStack - KERNEL_STACK_SIZE);
|
|
PCR->BStoreLimit = (ULONGLONG)((ULONG_PTR)IdleStack + KERNEL_BSTORE_SIZE);
|
|
|
|
//
|
|
// Initialize pointers to the SAL event resource structures.
|
|
//
|
|
|
|
PCR->OsMcaResourcePtr = (PSAL_EVENT_RESOURCES) &PCR->OsMcaResource;
|
|
PCR->OsInitResourcePtr = (PSAL_EVENT_RESOURCES) &PCR->OsInitResource;
|
|
|
|
//
|
|
// Initialize all interrupt vectors to transfer control to the unexpected
|
|
// interrupt routine.
|
|
//
|
|
// N.B. This interrupt object is never actually "connected" to an interrupt
|
|
// vector via KeConnectInterrupt. It is initialized and then connected
|
|
// by simply storing the address of the dispatch code in the interrupt
|
|
// vector.
|
|
//
|
|
|
|
if (Number == 0) {
|
|
|
|
//
|
|
// Set default node. Used in non-multinode systems and in
|
|
// multinode systems until the node topology is available.
|
|
//
|
|
|
|
extern KNODE KiNode0;
|
|
|
|
KeNodeBlock[0] = &KiNode0;
|
|
|
|
#if defined(KE_MULTINODE)
|
|
|
|
for (Index = 1; Index < MAXIMUM_CCNUMA_NODES; Index++) {
|
|
|
|
extern KNODE KiNodeInit[];
|
|
|
|
//
|
|
// Set temporary node.
|
|
//
|
|
|
|
KeNodeBlock[Index] = &KiNodeInit[Index];
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Set baseline global processor level and revision.
|
|
//
|
|
|
|
KeProcessorLevel = (USHORT) Prcb->ProcessorFamily;
|
|
KeProcessorRevision = ProcessorRevision;
|
|
|
|
Prcb->ParentNode = KeNodeBlock[0];
|
|
KeNodeBlock[0]->ProcessorMask = Prcb->SetMember;
|
|
|
|
//
|
|
// Initialize system wide FeatureBits with BSP processor feature bits.
|
|
//
|
|
|
|
KeFeatureBits = KiGetFeatureBits( Prcb ) ;
|
|
|
|
//
|
|
// Initialize the Tb Broadcast spinlock.
|
|
//
|
|
|
|
KeInitializeSpinLock(&KiTbBroadcastLock);
|
|
|
|
//
|
|
// Initialize the Master Rid spinlock.
|
|
//
|
|
|
|
KeInitializeSpinLock(&KiMasterRidLock);
|
|
|
|
//
|
|
// Initialize the cache flush spinlock.
|
|
//
|
|
|
|
KeInitializeSpinLock(&KiCacheFlushLock);
|
|
|
|
//
|
|
// Initial the address of the interrupt dispatch routine.
|
|
//
|
|
|
|
KxUnexpectedInterrupt.DispatchAddress = KiUnexpectedInterrupt;
|
|
|
|
//
|
|
// Copy the interrupt dispatch function descriptor into the interrupt
|
|
// object.
|
|
//
|
|
|
|
for (Index = 0; Index < DISPATCH_LENGTH; Index += 1) {
|
|
KxUnexpectedInterrupt.DispatchCode[Index] =
|
|
*(((PULONG)(ULONG_PTR)(KxUnexpectedInterrupt.DispatchAddress))+Index);
|
|
}
|
|
|
|
//
|
|
// Set the default DMA I/O coherency attributes. IA64
|
|
// architecture dictates that the D-Cache is fully coherent.
|
|
//
|
|
|
|
KiDmaIoCoherency = DMA_READ_DCACHE_INVALIDATE | DMA_WRITE_DCACHE_SNOOP;
|
|
|
|
//
|
|
// Set KiSharedUserData for MP boot
|
|
//
|
|
|
|
KiUserSharedDataPage = LoaderBlock->u.Ia64.PcrPage2;
|
|
|
|
//
|
|
// Get implementatoin specific VM info
|
|
//
|
|
|
|
KiIA64VmSummary1 = LoaderBlock->u.Ia64.ProcessorConfigInfo.VmSummaryInfo1;
|
|
KiIA64VmSummary2 = LoaderBlock->u.Ia64.ProcessorConfigInfo.VmSummaryInfo2;
|
|
KiIA64PtceInfo = LoaderBlock->u.Ia64.ProcessorConfigInfo.PtceInfo;
|
|
KiMaximumRid = ((ULONG)1 << KiIA64VmSummary2.RidSize) - 1;
|
|
|
|
//
|
|
// Get implementation specific RSE info
|
|
//
|
|
|
|
KiIA64RseNumOfPhysRegs = LoaderBlock->u.Ia64.ProcessorConfigInfo.NumOfPhysStackedRegs;
|
|
KiIA64RseHints = LoaderBlock->u.Ia64.ProcessorConfigInfo.RseHints;
|
|
|
|
//
|
|
// Initialize the VHPT variables
|
|
//
|
|
|
|
KiIA64ImpVirtualMsb = (ULONG)KiIA64VmSummary2.ImplVaMsb;
|
|
KiIA64VaSign = (ULONGLONG)1 << KiIA64ImpVirtualMsb;
|
|
KiIA64PtaSign = KiIA64VaSign >> (PAGE_SHIFT - PTE_SHIFT);
|
|
KiIA64VaSignedFill =
|
|
(ULONGLONG)((LONGLONG)VRN_MASK >> (60-KiIA64ImpVirtualMsb)) & ~VRN_MASK;
|
|
KiIA64PtaBase =
|
|
(ULONGLONG)((LONGLONG)(VRN_MASK|KiIA64VaSignedFill)
|
|
>> (PAGE_SHIFT - PTE_SHIFT)) & ~VRN_MASK;
|
|
|
|
KiIA64PtaContents =
|
|
KiIA64PtaBase |
|
|
((KiIA64ImpVirtualMsb - PAGE_SHIFT + PTE_SHIFT + 1) << PS_SHIFT) |
|
|
KiIA64PtaHpwEnabled;
|
|
|
|
if (LoaderBlock->u.Ia64.ProcessorConfigInfo.NumberOfCacheLevels > 0) {
|
|
|
|
KeLargestCacheLine = LoaderBlock->u.Ia64.ProcessorConfigInfo.LargestCacheLine;
|
|
KiNumberOfCacheLevels = LoaderBlock->u.Ia64.ProcessorConfigInfo.NumberOfCacheLevels;
|
|
|
|
memcpy(&KiCacheInfo1, &LoaderBlock->u.Ia64.ProcessorConfigInfo.CacheInfo1, sizeof(KiCacheInfo1));
|
|
memcpy(&KiCacheInfo2, &LoaderBlock->u.Ia64.ProcessorConfigInfo.CacheInfo2, sizeof(KiCacheInfo2));
|
|
|
|
}
|
|
|
|
//
|
|
// enable the VHPT
|
|
//
|
|
|
|
__setReg(CV_IA64_ApPTA, KiIA64PtaContents);
|
|
__isrlz();
|
|
|
|
//
|
|
// Set up the NT page base addresses
|
|
//
|
|
|
|
PCR->PteUbase = UADDRESS_BASE | KiIA64PtaBase;
|
|
PCR->PteKbase = KADDRESS_BASE | KiIA64PtaBase;
|
|
PCR->PteSbase = SADDRESS_BASE | KiIA64PtaBase;
|
|
PCR->PdeUbase = PCR->PteUbase | (PCR->PteUbase >> (PTI_SHIFT-PTE_SHIFT));
|
|
PCR->PdeKbase = PCR->PteKbase | (PCR->PteKbase >> (PTI_SHIFT-PTE_SHIFT));
|
|
PCR->PdeSbase = PCR->PteSbase | (PCR->PteSbase >> (PTI_SHIFT-PTE_SHIFT));
|
|
PCR->PdeUtbase = PCR->PteUbase | (PCR->PdeUbase >> (PTI_SHIFT-PTE_SHIFT));
|
|
PCR->PdeKtbase = PCR->PteKbase | (PCR->PdeKbase >> (PTI_SHIFT-PTE_SHIFT));
|
|
PCR->PdeStbase = PCR->PteSbase | (PCR->PdeSbase >> (PTI_SHIFT-PTE_SHIFT));
|
|
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Set global processor level and revision to least common denominator
|
|
//
|
|
|
|
if (KeProcessorLevel > (USHORT) Prcb->ProcessorFamily) {
|
|
KeProcessorLevel = (USHORT) Prcb->ProcessorFamily;
|
|
KeProcessorRevision = ProcessorRevision;
|
|
} else if ((KeProcessorLevel == (USHORT) Prcb->ProcessorFamily) &&
|
|
(KeProcessorRevision > ProcessorRevision)) {
|
|
KeProcessorRevision = ProcessorRevision;
|
|
}
|
|
|
|
//
|
|
// Mask off feature bits that are not supported on all processors.
|
|
//
|
|
|
|
KeFeatureBits &= KiGetFeatureBits( Prcb );
|
|
|
|
}
|
|
|
|
//
|
|
// Initialize the cache sizes in the PCR. We currently assume the sizes are the same
|
|
// on all processors.
|
|
//
|
|
|
|
if (KiNumberOfCacheLevels > 0) {
|
|
|
|
PCR->FirstLevelDcacheSize = (ULONG) KiCacheInfo2[CONFIG_INFO_DCACHE][0].Size;
|
|
PCR->FirstLevelDcacheFillSize = 1UL << KiCacheInfo1[CONFIG_INFO_DCACHE][0].LineSize;
|
|
PCR->FirstLevelIcacheSize = (ULONG) KiCacheInfo2[CONFIG_INFO_ICACHE][0].Size;
|
|
PCR->FirstLevelIcacheFillSize = 1UL << KiCacheInfo1[CONFIG_INFO_ICACHE][0].LineSize;
|
|
|
|
}
|
|
|
|
if (KeLargestCacheLine > 1) {
|
|
|
|
PCR->SecondLevelDcacheSize = (ULONG) KiCacheInfo2[CONFIG_INFO_DCACHE][1].Size;
|
|
PCR->SecondLevelDcacheFillSize = 1UL << KiCacheInfo1[CONFIG_INFO_DCACHE][1].LineSize;
|
|
PCR->SecondLevelIcacheSize = (ULONG) KiCacheInfo2[CONFIG_INFO_ICACHE][1].Size;
|
|
PCR->SecondLevelIcacheFillSize = 1UL << KiCacheInfo1[CONFIG_INFO_ICACHE][1].LineSize;
|
|
|
|
}
|
|
|
|
//
|
|
// Point to UnexpectedInterrupt function pointer
|
|
//
|
|
|
|
for (Index = 0; Index < MAXIMUM_VECTOR; Index += 1) {
|
|
PCR->InterruptRoutine[Index] =
|
|
(PKINTERRUPT_ROUTINE)((ULONG_PTR)&KxUnexpectedInterrupt.DispatchCode);
|
|
}
|
|
|
|
//
|
|
// Initialize the profile count and interval.
|
|
//
|
|
|
|
PCR->ProfileCount = 0;
|
|
PCR->ProfileInterval = 0x200000;
|
|
|
|
//
|
|
// Initialize the passive release, APC, and DPC interrupt vectors.
|
|
//
|
|
|
|
PCR->InterruptRoutine[0] = KiPassiveRelease;
|
|
PCR->InterruptRoutine[APC_VECTOR] = KiApcInterrupt;
|
|
PCR->InterruptRoutine[DISPATCH_VECTOR] = KiDispatchInterrupt;
|
|
|
|
//
|
|
// N.B. Reserve levels, not vectors
|
|
//
|
|
|
|
PCR->ReservedVectors = (1 << PASSIVE_LEVEL) | (1 << APC_LEVEL) | (1 << DISPATCH_LEVEL);
|
|
|
|
//
|
|
// Initialize the set member for the current processor, set IRQL to
|
|
// APC_LEVEL, and set the processor number.
|
|
//
|
|
|
|
KeLowerIrql(APC_LEVEL);
|
|
PCR->SetMember = AFFINITY_MASK(Number);
|
|
PCR->NotMember = ~PCR->SetMember;
|
|
PCR->Number = Number;
|
|
|
|
//
|
|
// Set the initial stall execution scale factor. This value will be
|
|
// recomputed later by the HAL.
|
|
//
|
|
|
|
PCR->StallScaleFactor = 50;
|
|
|
|
//
|
|
// Set address of process object in thread object.
|
|
//
|
|
|
|
Thread->ApcState.Process = Process;
|
|
PCR->Pcb = (PVOID)Process;
|
|
|
|
//
|
|
// Initialize the idle process region id. Session ids are initialized
|
|
// in memory management.
|
|
//
|
|
|
|
Process->ProcessRegion.RegionId = START_PROCESS_RID;
|
|
Process->ProcessRegion.SequenceNumber = START_SEQUENCE;
|
|
|
|
//
|
|
// Set the appropriate member in the active processors set.
|
|
//
|
|
|
|
KeActiveProcessors |= AFFINITY_MASK(Number);
|
|
|
|
//
|
|
// Set the number of processors based on the maximum of the current
|
|
// number of processors and the current processor number.
|
|
//
|
|
|
|
if ((Number + 1) > KeNumberProcessors) {
|
|
KeNumberProcessors = (CCHAR)(Number + 1);
|
|
}
|
|
|
|
//
|
|
// If the initial processor is being initialized, then initialize the
|
|
// per system data structures.
|
|
//
|
|
|
|
if (Number == 0) {
|
|
|
|
Prcb->RestartBlock = NULL;
|
|
|
|
//
|
|
// Initialize the kernel debugger.
|
|
//
|
|
|
|
if (KdInitSystem(0, LoaderBlock) == FALSE) {
|
|
KeBugCheck(PHASE0_INITIALIZATION_FAILED);
|
|
}
|
|
|
|
//
|
|
// Initialize processor block array.
|
|
//
|
|
|
|
for (Index = 1; Index < MAXIMUM_PROCESSORS; Index += 1) {
|
|
KiProcessorBlock[Index] = (PKPRCB)NULL;
|
|
}
|
|
|
|
//
|
|
// Perform architecture independent initialization.
|
|
//
|
|
|
|
KiInitSystem();
|
|
|
|
//
|
|
// Initialize idle thread process object and then set:
|
|
//
|
|
// 1. all the quantum values to the maximum possible.
|
|
// 2. the process in the balance set.
|
|
// 3. the active processor mask to the specified processor.
|
|
//
|
|
|
|
DirectoryTableBase[0] = 0;
|
|
DirectoryTableBase[1] = 0;
|
|
|
|
KeInitializeProcess(Process,
|
|
(KPRIORITY)0,
|
|
(KAFFINITY)(-1),
|
|
&DirectoryTableBase[0],
|
|
FALSE);
|
|
|
|
Process->ThreadQuantum = MAXCHAR;
|
|
|
|
}
|
|
|
|
// Update processor features.
|
|
// This assumes an iVE exists or other ability to emulate the ia32
|
|
// instruction set at the ability of the iVE on Merced (Itanium).
|
|
//
|
|
|
|
SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] = TRUE;
|
|
SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
|
|
SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
|
|
SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] = TRUE;
|
|
|
|
|
|
//
|
|
//
|
|
// Initialize idle thread object and then set:
|
|
//
|
|
// 1. the initial kernel stack to the specified idle stack.
|
|
// 2. the next processor number to the specified processor.
|
|
// 3. the thread priority to the highest possible value.
|
|
// 4. the state of the thread to running.
|
|
// 5. the thread affinity to the specified processor.
|
|
// 6. the specified processor member in the process active processors
|
|
// set.
|
|
//
|
|
|
|
KernelStack = (PVOID)((ULONG_PTR)IdleStack - PAGE_SIZE);
|
|
|
|
KeInitializeThread(Thread,
|
|
KernelStack,
|
|
(PKSYSTEM_ROUTINE)KeBugCheck,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
Process);
|
|
|
|
Thread->InitialStack = IdleStack;
|
|
Thread->InitialBStore = IdleStack;
|
|
Thread->StackBase = IdleStack;
|
|
Thread->StackLimit = (PVOID)((ULONG_PTR)IdleStack - KERNEL_STACK_SIZE);
|
|
Thread->BStoreLimit = (PVOID)((ULONG_PTR)IdleStack + KERNEL_BSTORE_SIZE);
|
|
Thread->NextProcessor = Number;
|
|
Thread->Priority = HIGH_PRIORITY;
|
|
Thread->State = Running;
|
|
Thread->Affinity = AFFINITY_MASK(Number);
|
|
Thread->WaitIrql = DISPATCH_LEVEL;
|
|
|
|
//
|
|
// If the current processor is 0, then set the appropriate bit in the
|
|
// active summary of the idle process.
|
|
//
|
|
|
|
if (Number == 0) {
|
|
Process->ActiveProcessors |= AFFINITY_MASK(Number);
|
|
}
|
|
|
|
//
|
|
// Execute the executive initialization.
|
|
//
|
|
|
|
try {
|
|
|
|
ExpInitializeExecutive(Number, LoaderBlock);
|
|
|
|
} except (KiInitializeKernelUnhandledExceptionFilter(GetExceptionInformation())) {
|
|
// WARNING: this code is unreachable, because
|
|
// WARNING: KiInitializeKernelUnhandledExceptionFilter calls
|
|
// WARNING: KeBugCheckEx!
|
|
// KeBugCheck (PHASE0_EXCEPTION);
|
|
}
|
|
|
|
//
|
|
// check for the exception deferral mode
|
|
//
|
|
|
|
if (KiExceptionDeferralMode != 0) {
|
|
KiIA64DCR = DCR_INITIAL ^ (1 << DCR_DM);
|
|
}
|
|
|
|
//
|
|
// initialize the DCR deferral bits
|
|
//
|
|
|
|
__setReg(CV_IA64_ApDCR, KiIA64DCR);
|
|
|
|
//
|
|
// If KiBackingStoreSecurityMode is non-zero then enable the srubing of the
|
|
// RSE registres in kernel user transisions.
|
|
//
|
|
|
|
if (KiBackingStoreSecurityMode != 0) {
|
|
|
|
KiIA64RseNumOfMaxDirty = KiIA64RseNumOfPhysRegs + ((KiIA64RseNumOfPhysRegs + 62) / 63);
|
|
|
|
} else {
|
|
|
|
//
|
|
// making 0 makes no scrubbing performed on kernel-user transisions
|
|
//
|
|
|
|
KiIA64RseNumOfMaxDirty = 0;
|
|
|
|
}
|
|
|
|
//
|
|
// If the initial processor is being initialized, then compute the
|
|
// timer table reciprocal value and reset the PRCB values for the
|
|
// controllable DPC behavior in order to reflect any registry
|
|
// overrides.
|
|
//
|
|
|
|
if (Number == 0) {
|
|
KiTimeIncrementReciprocal = KiComputeReciprocal((LONG)KeMaximumIncrement,
|
|
&KiTimeIncrementShiftCount);
|
|
|
|
Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
|
|
Prcb->MinimumDpcRate = KiMinimumDpcRate;
|
|
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
|
|
RtlInitializeHistoryTable();
|
|
}
|
|
|
|
//
|
|
// Raise IRQL to dispatch level and set the priority of the idle thread
|
|
// to zero. This will have the effect of immediately causing the phase
|
|
// one initialization thread to get scheduled for execution. The idle
|
|
// thread priority is then set to the lowest realtime priority. This is
|
|
// necessary so that mutexes aquired at DPC level do not cause the active
|
|
// matrix to get corrupted.
|
|
//
|
|
|
|
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
|
KeSetPriorityThread(Thread, (KPRIORITY)0);
|
|
Thread->Priority = LOW_REALTIME_PRIORITY;
|
|
|
|
//
|
|
// Raise IRQL to the highest level.
|
|
//
|
|
|
|
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
|
|
|
#if !defined(NT_UP)
|
|
|
|
//
|
|
// Indicate boot complete on secondary processor
|
|
//
|
|
|
|
LoaderBlock->Prcb = 0;
|
|
|
|
//
|
|
// If the current processor is not 0, then set the appropriate bit in
|
|
// idle summary.
|
|
//
|
|
KiAcquirePrcbLock(Prcb);
|
|
if ((Number != 0) && (Prcb->NextThread == NULL)) {
|
|
KiIdleSummary |= AFFINITY_MASK(Number);
|
|
}
|
|
KiReleasePrcbLock(Prcb);
|
|
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
KiInitMachineDependent (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function performs machine-specific initialization by querying the HAL.
|
|
|
|
N.B. This function is only called during phase1 initialization.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
A value of TRUE is returned if initialization is successful. Otherwise,
|
|
a value of FALSE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
HAL_PLATFORM_INFORMATION PlatformInfo;
|
|
HAL_PROCESSOR_SPEED_INFORMATION ProcessorSpeedInfo;
|
|
NTSTATUS Status;
|
|
BOOLEAN UseFrameBufferCaching;
|
|
ULONG Size;
|
|
|
|
//
|
|
// check to see if we should switch to PTC.G-based TB shootdown
|
|
//
|
|
|
|
Status = HalQuerySystemInformation(HalPlatformInformation,
|
|
sizeof(PlatformInfo),
|
|
&PlatformInfo,
|
|
&Size);
|
|
if (NT_SUCCESS(Status) &&
|
|
(PlatformInfo.PlatformFlags & HAL_PLATFORM_DISABLE_PTCG)) {
|
|
//
|
|
// Will continue not to use PTC.G
|
|
//
|
|
}
|
|
else {
|
|
//
|
|
// Use PTC.G if processor support is there.
|
|
//
|
|
|
|
if (KiConfigFlag & (1 << ENABLE_TB_BROADCAST)) {
|
|
KiIpiTbShootdown = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the HAL indicates write combining is not supported, drop it.
|
|
//
|
|
|
|
Status = HalQuerySystemInformation(HalFrameBufferCachingInformation,
|
|
sizeof(UseFrameBufferCaching),
|
|
&UseFrameBufferCaching,
|
|
&Size);
|
|
|
|
if (NT_SUCCESS(Status) && (UseFrameBufferCaching == FALSE)) {
|
|
|
|
//
|
|
// Hal says don't use.
|
|
//
|
|
|
|
NOTHING;
|
|
}
|
|
else {
|
|
MmEnablePAT ();
|
|
}
|
|
|
|
//
|
|
// Ask HAL for Processor Speed
|
|
//
|
|
|
|
Status = HalQuerySystemInformation(HalProcessorSpeedInformation,
|
|
sizeof(ProcessorSpeedInfo),
|
|
&ProcessorSpeedInfo,
|
|
&Size);
|
|
if (NT_SUCCESS(Status)) {
|
|
PKPRCB Prcb;
|
|
ULONG i;
|
|
|
|
//
|
|
// Put the Processor Speed into the Prcb structure so others
|
|
// can reference it later.
|
|
//
|
|
for (i = 0; i < (ULONG)KeNumberProcessors; i++ ) {
|
|
Prcb = KiProcessorBlock[i];
|
|
Prcb->MHz = (USHORT)ProcessorSpeedInfo.ProcessorSpeed;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|