1113 lines
24 KiB
C
1113 lines
24 KiB
C
|
|
/*++
|
|
|
|
Copyright (c) 2000 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, the processor control
|
|
block, and the processor control region.
|
|
|
|
Author:
|
|
|
|
David N. Cutler (davec) 22-Apr-2000
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
--*/
|
|
|
|
#include "ki.h"
|
|
|
|
//
|
|
// Define default profile IRQL level.
|
|
//
|
|
|
|
KIRQL KiProfileIrql = PROFILE_LEVEL;
|
|
|
|
//
|
|
// Define the process and thread for the initial system process and startup
|
|
// thread.
|
|
//
|
|
|
|
EPROCESS KiInitialProcess;
|
|
ETHREAD KiInitialThread;
|
|
|
|
//
|
|
// Define the interrupt initialization data.
|
|
//
|
|
// Entries in the KiInterruptInitTable[] must be in ascending vector # order.
|
|
//
|
|
|
|
typedef VOID (*KI_INTERRUPT_HANDLER)(VOID);
|
|
|
|
typedef struct _KI_INTINIT_REC {
|
|
UCHAR Vector;
|
|
UCHAR Dpl;
|
|
UCHAR IstIndex;
|
|
KI_INTERRUPT_HANDLER Handler;
|
|
} KI_INTINIT_REC, *PKI_INTINIT_REC;
|
|
|
|
#pragma data_seg("INITDATA")
|
|
|
|
KI_INTINIT_REC KiInterruptInitTable[] = {
|
|
{0, 0, 0, KiDivideErrorFault},
|
|
{1, 0, 0, KiDebugTrapOrFault},
|
|
{2, 0, TSS_IST_PANIC, KiNmiInterrupt},
|
|
{3, 3, 0, KiBreakpointTrap},
|
|
{4, 3, 0, KiOverflowTrap},
|
|
{5, 0, 0, KiBoundFault},
|
|
{6, 0, 0, KiInvalidOpcodeFault},
|
|
{7, 0, 0, KiNpxNotAvailableFault},
|
|
{8, 0, TSS_IST_PANIC, KiDoubleFaultAbort},
|
|
{9, 0, 0, KiNpxSegmentOverrunAbort},
|
|
{10, 0, 0, KiInvalidTssFault},
|
|
{11, 0, 0, KiSegmentNotPresentFault},
|
|
{12, 0, 0, KiStackFault},
|
|
{13, 0, 0, KiGeneralProtectionFault},
|
|
{14, 0, 0, KiPageFault},
|
|
{16, 0, 0, KiFloatingErrorFault},
|
|
{17, 0, 0, KiAlignmentFault},
|
|
{18, 0, TSS_IST_MCA, KiMcheckAbort},
|
|
{19, 0, 0, KiXmmException},
|
|
{31, 0, 0, KiApcInterrupt},
|
|
{45, 3, 0, KiDebugServiceTrap},
|
|
{47, 0, 0, KiDpcInterrupt},
|
|
{0, 0, 0, NULL}
|
|
};
|
|
|
|
#pragma data_seg()
|
|
|
|
//
|
|
// Define macro to initialize an IDT entry.
|
|
//
|
|
// KiInitializeIdtEntry (
|
|
// IN PKIDTENTRY64 Entry,
|
|
// IN PVOID Address,
|
|
// IN USHORT Level
|
|
// )
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Entry - Supplies a pointer to an IDT entry.
|
|
//
|
|
// Address - Supplies the address of the vector routine.
|
|
//
|
|
// Dpl - Descriptor privilege level.
|
|
//
|
|
// Ist - Interrupt stack index.
|
|
//
|
|
|
|
#define KiInitializeIdtEntry(Entry, Address, Level, Index) \
|
|
(Entry)->OffsetLow = (USHORT)((ULONG64)(Address)); \
|
|
(Entry)->Selector = KGDT64_R0_CODE; \
|
|
(Entry)->IstIndex = Index; \
|
|
(Entry)->Type = 0xe; \
|
|
(Entry)->Dpl = (Level); \
|
|
(Entry)->Present = 1; \
|
|
(Entry)->OffsetMiddle = (USHORT)((ULONG64)(Address) >> 16); \
|
|
(Entry)->OffsetHigh = (ULONG)((ULONG64)(Address) >> 32) \
|
|
|
|
//
|
|
// Define forward referenced prototypes.
|
|
//
|
|
|
|
ULONG
|
|
KiFatalFilter (
|
|
IN ULONG Code,
|
|
IN PEXCEPTION_POINTERS Pointers
|
|
);
|
|
|
|
VOID
|
|
KiSetCacheInformation (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
KiSetCpuVendor (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
KiSetFeatureBits (
|
|
IN PKPRCB Prcb
|
|
);
|
|
|
|
VOID
|
|
KiSetProcessorType (
|
|
VOID
|
|
);
|
|
|
|
#pragma alloc_text(INIT, KiFatalFilter)
|
|
#pragma alloc_text(INIT, KiInitializeBootStructures)
|
|
#pragma alloc_text(INIT, KiInitializeKernel)
|
|
#pragma alloc_text(INIT, KiInitMachineDependent)
|
|
#pragma alloc_text(INIT, KiSetCacheInformation)
|
|
#pragma alloc_text(INIT, KiSetCpuVendor)
|
|
#pragma alloc_text(INIT, KiSetFeatureBits)
|
|
#pragma alloc_text(INIT, KiSetProcessorType)
|
|
|
|
VOID
|
|
KiInitializeKernel (
|
|
IN PKPROCESS Process,
|
|
IN PKTHREAD Thread,
|
|
IN PVOID IdleStack,
|
|
IN PKPRCB Prcb,
|
|
IN CCHAR Number,
|
|
PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function gains control after the system has been booted, but before
|
|
the system has been completely initialized. Its function is to initialize
|
|
the kernel data structures, initialize the idle thread and process objects,
|
|
complete the initialization of the processor control block (PRCB) and
|
|
processor control region (PCR), call the executive initialization routine,
|
|
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.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG64 DirectoryTableBase[2];
|
|
ULONG FeatureBits;
|
|
|
|
#if !defined(NT_UP)
|
|
|
|
LONG Index;
|
|
|
|
#endif
|
|
|
|
KIRQL OldIrql;
|
|
PCHAR Options;
|
|
|
|
//
|
|
// Set CPU vendor.
|
|
//
|
|
|
|
KiSetCpuVendor();
|
|
|
|
//
|
|
// Set processor type.
|
|
//
|
|
|
|
KiSetProcessorType();
|
|
|
|
//
|
|
// Set the processor feature bits.
|
|
//
|
|
|
|
KiSetFeatureBits(Prcb);
|
|
FeatureBits = Prcb->FeatureBits;
|
|
|
|
//
|
|
// If this is the boot processor, then enable global pages, set the page
|
|
// attributes table, set machine check enable, set large page enable, and
|
|
// enable debug extensions.
|
|
//
|
|
// N.B. This only happens on the boot processor and at a time when there
|
|
// can be no coherency problem. On subsequent, processors this happens
|
|
// during the transistion into 64-bit mode which is also at a time
|
|
// that there can be no coherency problems.
|
|
//
|
|
|
|
if (Number == 0) {
|
|
|
|
//
|
|
// If any loader options were specified, then upper case the options.
|
|
//
|
|
|
|
Options = LoaderBlock->LoadOptions;
|
|
if (Options != NULL) {
|
|
_strupr(Options);
|
|
}
|
|
|
|
//
|
|
// Flush the entire TB and enable global pages.
|
|
//
|
|
|
|
KeFlushCurrentTb();
|
|
|
|
//
|
|
// Set page attributes table and flush cache.
|
|
//
|
|
|
|
KiSetPageAttributesTable();
|
|
WritebackInvalidate();
|
|
|
|
//
|
|
// If execute protection is specified in the loader options, then
|
|
// turn off no execute protection for memory management.
|
|
//
|
|
// N.B. No execute protection is always enabled during processor
|
|
// initialization.
|
|
//
|
|
|
|
MmPaeMask = 0x8000000000000000UI64;
|
|
MmPaeErrMask = 0x8;
|
|
if ((strstr(Options, "NOEXECUTE") == NULL) &&
|
|
(strstr(Options, "EXECUTE") != NULL)) {
|
|
|
|
MmPaeMask = 0;
|
|
MmPaeErrMask = 0;
|
|
}
|
|
|
|
//
|
|
// Set debugger extension and large page enable.
|
|
//
|
|
|
|
WriteCR4(ReadCR4() | CR4_DE | CR4_PSE);
|
|
|
|
//
|
|
// Flush the entire TB.
|
|
//
|
|
|
|
KeFlushCurrentTb();
|
|
}
|
|
|
|
//
|
|
// set processor cache size information.
|
|
//
|
|
|
|
KiSetCacheInformation();
|
|
|
|
//
|
|
// Initialize power state information.
|
|
//
|
|
|
|
PoInitializePrcb(Prcb);
|
|
|
|
//
|
|
// initialize the per processor lock data.
|
|
//
|
|
|
|
KiInitSpinLocks(Prcb, Number);
|
|
|
|
//
|
|
// If the initial processor is being initialized, then initialize the
|
|
// per system data structures.
|
|
//
|
|
|
|
if (Number == 0) {
|
|
|
|
//
|
|
// Set default node until the node topology is available.
|
|
//
|
|
|
|
KeNodeBlock[0] = &KiNode0;
|
|
|
|
#if !defined(NT_UP)
|
|
|
|
for (Index = 1; Index < MAXIMUM_CCNUMA_NODES; Index += 1) {
|
|
KeNodeBlock[Index] = &KiNodeInit[Index];
|
|
}
|
|
|
|
#endif
|
|
|
|
Prcb->ParentNode = KeNodeBlock[0];
|
|
KeNodeBlock[0]->ProcessorMask = Prcb->SetMember;
|
|
|
|
//
|
|
// Set global architecture and feature information.
|
|
//
|
|
|
|
KeProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
|
|
KeProcessorLevel = (USHORT)Prcb->CpuType;
|
|
KeProcessorRevision = Prcb->CpuStep;
|
|
KeFeatureBits = FeatureBits;
|
|
|
|
//
|
|
// Lower IRQL to APC level.
|
|
//
|
|
|
|
KeLowerIrql(APC_LEVEL);
|
|
|
|
//
|
|
// Initialize kernel internal spinlocks
|
|
//
|
|
|
|
KeInitializeSpinLock(&KiFreezeExecutionLock);
|
|
|
|
//
|
|
// Performance architecture independent initialization.
|
|
//
|
|
|
|
KiInitSystem();
|
|
|
|
//
|
|
// Initialize idle thread process object and then set:
|
|
//
|
|
// 1. the process quantum.
|
|
//
|
|
|
|
DirectoryTableBase[0] = 0;
|
|
DirectoryTableBase[1] = 0;
|
|
KeInitializeProcess(Process,
|
|
(KPRIORITY)0,
|
|
(KAFFINITY)(-1),
|
|
&DirectoryTableBase[0],
|
|
FALSE);
|
|
|
|
Process->ThreadQuantum = MAXCHAR;
|
|
|
|
} else {
|
|
|
|
//
|
|
// If the CPU feature bits are not identical, then bugcheck.
|
|
//
|
|
|
|
if (FeatureBits != KeFeatureBits) {
|
|
KeBugCheckEx(MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED,
|
|
(ULONG64)FeatureBits,
|
|
(ULONG64)KeFeatureBits,
|
|
0,
|
|
0);
|
|
}
|
|
|
|
//
|
|
// Lower IRQL to DISPATCH level.
|
|
//
|
|
|
|
KeLowerIrql(DISPATCH_LEVEL);
|
|
}
|
|
|
|
//
|
|
// Set global processor features.
|
|
//
|
|
|
|
SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
|
|
SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
|
|
SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] = TRUE;
|
|
SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] = TRUE;
|
|
SharedUserData->ProcessorFeatures[PF_PAE_ENABLED] = TRUE;
|
|
SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] = TRUE;
|
|
if (FeatureBits & KF_3DNOW) {
|
|
SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] = TRUE;
|
|
}
|
|
|
|
//
|
|
// Initialize idle thread object and then set:
|
|
//
|
|
// 1. the next processor number to the specified processor.
|
|
// 2. the thread priority to the highest possible value.
|
|
// 3. the state of the thread to running.
|
|
// 4. the thread affinity to the specified processor.
|
|
// 5. the specified member in the process active processors set.
|
|
//
|
|
|
|
KeInitializeThread(Thread,
|
|
(PVOID)((ULONG64)IdleStack),
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
Process);
|
|
|
|
Thread->NextProcessor = Number;
|
|
Thread->Priority = HIGH_PRIORITY;
|
|
Thread->State = Running;
|
|
Thread->Affinity = AFFINITY_MASK(Number);
|
|
Thread->WaitIrql = DISPATCH_LEVEL;
|
|
Process->ActiveProcessors |= AFFINITY_MASK(Number);
|
|
|
|
//
|
|
// Call the executive initialization routine.
|
|
//
|
|
|
|
try {
|
|
ExpInitializeExecutive(Number, LoaderBlock);
|
|
|
|
} except(KiFatalFilter(GetExceptionCode(), GetExceptionInformation())) {
|
|
}
|
|
|
|
//
|
|
// If the initial processor is being initialized, then compute the timer
|
|
// table reciprocal value, reset the PRCB values for the controllable DPC
|
|
// behavior in order to reflect any registry overrides, and initialize the
|
|
// global unwind history table.
|
|
//
|
|
|
|
if (Number == 0) {
|
|
KiTimeIncrementReciprocal = KiComputeReciprocal((LONG)KeMaximumIncrement,
|
|
&KiTimeIncrementShiftCount);
|
|
|
|
Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
|
|
Prcb->MinimumDpcRate = KiMinimumDpcRate;
|
|
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
|
|
RtlInitializeHistoryTable();
|
|
}
|
|
|
|
//
|
|
// Raise IRQL to dispatch level and eet 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 ot the lowest realtime priority.
|
|
//
|
|
|
|
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
|
KeSetPriorityThread(Thread, 0);
|
|
Thread->Priority = LOW_REALTIME_PRIORITY;
|
|
|
|
//
|
|
// Raise IRQL to highest level.
|
|
//
|
|
|
|
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
|
|
|
//
|
|
// If the current processor is a secondary processor and a thread has
|
|
// not been selected for execution, then set the appropriate bit in the
|
|
// idle summary.
|
|
//
|
|
|
|
#if !defined(NT_UP)
|
|
|
|
KiAcquirePrcbLock(Prcb);
|
|
if ((Number != 0) && (Prcb->NextThread == NULL)) {
|
|
KiIdleSummary |= AFFINITY_MASK(Number);
|
|
}
|
|
|
|
KiReleasePrcbLock(Prcb);
|
|
|
|
#endif
|
|
|
|
//
|
|
// Signal that this processor has completed its initialization.
|
|
//
|
|
|
|
LoaderBlock->Prcb = (ULONG64)NULL;
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
KiInitializeBootStructures (
|
|
PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes the boot structures for a processor. It is only
|
|
called by the system start up code. Certain fields in the boot structures
|
|
have already been initialized. In particular:
|
|
|
|
The address and limit of the GDT and IDT in the PCR.
|
|
|
|
The address of the system TSS in the PCR.
|
|
|
|
The processor number in the PCR.
|
|
|
|
The special registers in the PRCB.
|
|
|
|
N.B. All uninitialized fields are zero.
|
|
|
|
Arguments:
|
|
|
|
LoaderBlock - Supplies a pointer to the loader block that has been
|
|
initialized for this processor.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PKIDTENTRY64 IdtBase;
|
|
ULONG Index;
|
|
PKI_INTINIT_REC IntInitRec;
|
|
PKPCR Pcr = KeGetPcr();
|
|
PKPRCB Prcb = KeGetCurrentPrcb();
|
|
UCHAR Number;
|
|
PKTHREAD Thread;
|
|
PKTSS64 TssBase;
|
|
|
|
//
|
|
// Initialize the PCR major and minor version numbers.
|
|
//
|
|
|
|
Pcr->MajorVersion = PCR_MAJOR_VERSION;
|
|
Pcr->MinorVersion = PCR_MINOR_VERSION;
|
|
|
|
//
|
|
// initialize the PRCB major and minor version numbers and build type.
|
|
//
|
|
|
|
Prcb->MajorVersion = PRCB_MAJOR_VERSION;
|
|
Prcb->MinorVersion = PRCB_MINOR_VERSION;
|
|
Prcb->BuildType = 0;
|
|
|
|
#if DBG
|
|
|
|
Prcb->BuildType |= PRCB_BUILD_DEBUG;
|
|
|
|
#endif
|
|
|
|
#if defined(NT_UP)
|
|
|
|
Prcb->BuildType |= PRCB_BUILD_UNIPROCESSOR;
|
|
|
|
#endif
|
|
|
|
//
|
|
// Initialize the PRCR processor number and the PCR and PRCB set member.
|
|
//
|
|
|
|
Number = Pcr->Number;
|
|
Prcb->Number = Number;
|
|
Prcb->SetMember = AFFINITY_MASK(Number);
|
|
Prcb->NotSetMember = ~Prcb->SetMember;
|
|
Pcr->SetMember = Prcb->SetMember;
|
|
|
|
//
|
|
// If this is processor zero, then initialize the address of the system
|
|
// process and initial thread.
|
|
//
|
|
|
|
if (Number == 0) {
|
|
LoaderBlock->Process = (ULONG64)&KiInitialProcess;
|
|
LoaderBlock->Thread = (ULONG64)&KiInitialThread;
|
|
}
|
|
|
|
//
|
|
// Initialize the PRCB scheduling thread address and the thread process
|
|
// address.
|
|
//
|
|
|
|
Thread = (PVOID)LoaderBlock->Thread;
|
|
Prcb->CurrentThread = Thread;
|
|
Prcb->NextThread = NULL;
|
|
Prcb->IdleThread = Thread;
|
|
Thread->ApcState.Process = (PKPROCESS)LoaderBlock->Process;
|
|
InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]);
|
|
|
|
//
|
|
// Initialize the processor block address.
|
|
//
|
|
|
|
KiProcessorBlock[Number] = Prcb;
|
|
|
|
//
|
|
// Initialize the PRCB address of the DPC stack.
|
|
//
|
|
|
|
Prcb->DpcStack = (PVOID)LoaderBlock->KernelStack;
|
|
|
|
//
|
|
// Initialize the PRCB symmetric multithreading member.
|
|
//
|
|
|
|
Prcb->MultiThreadProcessorSet = Prcb->SetMember;
|
|
|
|
//
|
|
// If this is processor zero, initialize the IDT according to the contents
|
|
// of KiInterruptInitTable[]
|
|
//
|
|
|
|
if (Number == 0) {
|
|
|
|
IdtBase = Pcr->IdtBase;
|
|
IntInitRec = KiInterruptInitTable;
|
|
for (Index = 0; Index < MAXIMUM_IDTVECTOR; Index += 1) {
|
|
|
|
//
|
|
// If the vector is found in the initialization table then
|
|
// set up the IDT entry accordingly and advance to the next
|
|
// entry in the initialization table.
|
|
//
|
|
// Otherwise set the IDT to reference the unexpected interrupt
|
|
// handler.
|
|
//
|
|
|
|
if (Index == IntInitRec->Vector) {
|
|
|
|
KiInitializeIdtEntry(&IdtBase[Index],
|
|
IntInitRec->Handler,
|
|
IntInitRec->Dpl,
|
|
IntInitRec->IstIndex);
|
|
IntInitRec += 1;
|
|
|
|
} else {
|
|
|
|
KiInitializeIdtEntry(&IdtBase[Index],
|
|
&KxUnexpectedInterrupt0[Index],
|
|
0,
|
|
0);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Initialize the system TSS I/O Map.
|
|
//
|
|
|
|
TssBase = Pcr->TssBase;
|
|
TssBase->IoMapBase = KiComputeIopmOffset(FALSE);
|
|
|
|
//
|
|
// Initialize the system call MSRs.
|
|
//
|
|
// N.B. CSTAR must be written before LSTAR to work around a bug in the
|
|
// simulator.
|
|
//
|
|
|
|
WriteMSR(MSR_STAR,
|
|
((ULONG64)KGDT64_R0_CODE << 32) | (((ULONG64)KGDT64_R3_CMCODE | RPL_MASK) << 48));
|
|
|
|
WriteMSR(MSR_CSTAR, (ULONG64)&KiSystemCall32);
|
|
WriteMSR(MSR_LSTAR, (ULONG64)&KiSystemCall64);
|
|
WriteMSR(MSR_SYSCALL_MASK, EFLAGS_IF_MASK | EFLAGS_TF_MASK);
|
|
|
|
//
|
|
// Initialize the HAL for this processor.
|
|
//
|
|
|
|
HalInitializeProcessor(Number, LoaderBlock);
|
|
|
|
//
|
|
// 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 = Number + 1;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
ULONG
|
|
KiFatalFilter (
|
|
IN ULONG Code,
|
|
IN PEXCEPTION_POINTERS Pointers
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is executed if an unhandled exception occurs during
|
|
phase 0 initialization. Its function is to bug check the system
|
|
with all the context information still on the stack.
|
|
|
|
Arguments:
|
|
|
|
Code - Supplies the exception code.
|
|
|
|
Pointers - Supplies a pointer to the exception information.
|
|
|
|
Return Value:
|
|
|
|
None - There is no return from this routine even though it appears there
|
|
is.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KeBugCheckEx(PHASE0_EXCEPTION,
|
|
Code,
|
|
(ULONG64)Pointers,
|
|
0,
|
|
0);
|
|
}
|
|
|
|
BOOLEAN
|
|
KiInitMachineDependent (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes machine dependent data structures and hardware.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG Size;
|
|
NTSTATUS Status;
|
|
BOOLEAN UseFrameBufferCaching;
|
|
|
|
//
|
|
// Query the HAL to determine if the write combining can be used for the
|
|
// frame buffer.
|
|
//
|
|
|
|
Status = HalQuerySystemInformation(HalFrameBufferCachingInformation,
|
|
sizeof(BOOLEAN),
|
|
&UseFrameBufferCaching,
|
|
&Size);
|
|
|
|
//
|
|
// If the status is successful and frame buffer caching is disabled,
|
|
// then don't enable write combining.
|
|
//
|
|
|
|
if (!NT_SUCCESS(Status) || (UseFrameBufferCaching != FALSE)) {
|
|
MmEnablePAT();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
KiSetCacheInformation (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sets the current processor cache information in the PCR.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
UCHAR Associativity;
|
|
ULONG CacheSize;
|
|
CPU_INFO CpuInfo;
|
|
ULONG LineSize;
|
|
PKPCR Pcr = KeGetPcr();
|
|
|
|
//
|
|
// Get the CPU L2 cache information.
|
|
//
|
|
|
|
KiCpuId(0x80000006, &CpuInfo);
|
|
|
|
//
|
|
// Get the L2 cache line size.
|
|
//
|
|
|
|
LineSize = CpuInfo.Ecx & 0xff;
|
|
|
|
//
|
|
// Get the L2 cache size.
|
|
//
|
|
|
|
CacheSize = (CpuInfo.Ecx >> 16) << 10;
|
|
|
|
//
|
|
// Compute the L2 cache associativity.
|
|
//
|
|
|
|
switch ((CpuInfo.Ecx >> 12) & 0xf) {
|
|
|
|
//
|
|
// Two way set associative.
|
|
//
|
|
|
|
case 2:
|
|
Associativity = 2;
|
|
break;
|
|
|
|
//
|
|
// Four way set associative.
|
|
//
|
|
|
|
case 4:
|
|
Associativity = 4;
|
|
break;
|
|
|
|
//
|
|
// Six way set associative.
|
|
//
|
|
|
|
case 6:
|
|
Associativity = 6;
|
|
break;
|
|
|
|
//
|
|
// Eight way set associative.
|
|
//
|
|
|
|
case 8:
|
|
Associativity = 8;
|
|
break;
|
|
|
|
//
|
|
// Fully associative.
|
|
//
|
|
|
|
case 255:
|
|
Associativity = 16;
|
|
break;
|
|
|
|
//
|
|
// Direct mapped.
|
|
//
|
|
|
|
default:
|
|
Associativity = 1;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set L2 cache information.
|
|
//
|
|
|
|
Pcr->SecondLevelCacheAssociativity = Associativity;
|
|
Pcr->SecondLevelCacheSize = CacheSize;
|
|
|
|
//
|
|
// If the line size is greater then the current largest line size, then
|
|
// set the new largest line size.
|
|
//
|
|
|
|
if (LineSize > KeLargestCacheLine) {
|
|
KeLargestCacheLine = LineSize;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
KiSetCpuVendor (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the current processor cpu vendor information in the PRCB.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PKPRCB Prcb = KeGetCurrentPrcb();
|
|
CPU_INFO CpuInfo;
|
|
ULONG Temp;
|
|
|
|
//
|
|
// Get the CPU vendor string.
|
|
//
|
|
|
|
KiCpuId(0, &CpuInfo);
|
|
|
|
//
|
|
// Copy vendor string to PRCB.
|
|
//
|
|
|
|
Temp = CpuInfo.Ecx;
|
|
CpuInfo.Ecx = CpuInfo.Edx;
|
|
CpuInfo.Edx = Temp;
|
|
RtlCopyMemory(Prcb->VendorString,
|
|
&CpuInfo.Ebx,
|
|
sizeof(Prcb->VendorString) - 1);
|
|
|
|
Prcb->VendorString[sizeof(Prcb->VendorString) - 1] = '\0';
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
KiSetFeatureBits (
|
|
IN PKPRCB Prcb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the current processor feature bits in the PRCB.
|
|
|
|
Arguments:
|
|
|
|
Prcb - Supplies a pointer to the current processor block.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
CPU_INFO CpuInfo;
|
|
ULONG FeatureBits;
|
|
|
|
//
|
|
// Get CPU feature information.
|
|
//
|
|
|
|
KiCpuId(1, &CpuInfo);
|
|
|
|
//
|
|
// Set the initial APIC ID.
|
|
//
|
|
|
|
Prcb->InitialApicId = (UCHAR)(CpuInfo.Ebx >> 24);
|
|
|
|
//
|
|
// If the required fetures are not present, then bugcheck.
|
|
//
|
|
|
|
if ((CpuInfo.Edx & HF_REQUIRED) != HF_REQUIRED) {
|
|
KeBugCheckEx(UNSUPPORTED_PROCESSOR, CpuInfo.Edx, 0, 0, 0);
|
|
}
|
|
|
|
FeatureBits = KF_REQUIRED;
|
|
if (CpuInfo.Edx & 0x00200000) {
|
|
FeatureBits |= KF_DTS;
|
|
}
|
|
|
|
//
|
|
// Get extended CPU feature information.
|
|
//
|
|
|
|
KiCpuId(0x80000000, &CpuInfo);
|
|
|
|
//
|
|
// Check the extended feature bits.
|
|
//
|
|
|
|
if (CpuInfo.Edx & 0x80000000) {
|
|
FeatureBits |= KF_3DNOW;
|
|
}
|
|
|
|
Prcb->LogicalProcessorsPerPhysicalProcessor = 1;
|
|
Prcb->FeatureBits = FeatureBits;
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
KiSetProcessorType (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sets the current processor family and stepping in the PRCB.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
CPU_INFO CpuInfo;
|
|
PKPRCB Prcb = KeGetCurrentPrcb();
|
|
|
|
//
|
|
// Get cpu feature information.
|
|
//
|
|
|
|
KiCpuId(1, &CpuInfo);
|
|
|
|
//
|
|
// Set processor family and stepping information.
|
|
//
|
|
|
|
Prcb->CpuID = TRUE;
|
|
Prcb->CpuType = (CCHAR)((CpuInfo.Eax >> 8) & 0xf);
|
|
Prcb->CpuStep = (USHORT)(((CpuInfo.Eax << 4) & 0xf00) | (CpuInfo.Eax & 0xf));
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
KeOptimizeProcessorControlState (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function performs no operation on AMD64.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
return;
|
|
}
|