Windows2000/private/ntos/ke/i386/allproc.c
2020-09-30 17:12:32 +02:00

406 lines
9.6 KiB
C

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
allproc.c
Abstract:
This module allocates and initializes kernel resources required
to start a new processor, and passes a complete process_state
structre to the hal to obtain a new processor. This is done
for every processor.
Author:
Ken Reneris (kenr) 22-Jan-92
Environment:
Kernel mode only.
Phase 1 of bootup
Revision History:
--*/
#include "ki.h"
#ifdef NT_UP
VOID
KeStartAllProcessors (
VOID
)
{
// UP Build - this function is a nop
}
#else
extern ULONG KeRegisteredProcessors;
static VOID
KiCloneDescriptor (
IN PKDESCRIPTOR pSrcDescriptorInfo,
IN PKDESCRIPTOR pDestDescriptorInfo
);
static VOID
KiCloneSelector (
IN ULONG SrcSelector,
IN PKGDTENTRY pNGDT,
IN PKDESCRIPTOR pDestDescriptor
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,KeStartAllProcessors)
#pragma alloc_text(INIT,KiCloneDescriptor)
#pragma alloc_text(INIT,KiCloneSelector)
#endif
#if !defined(NT_UP)
ULONG KiBarrierWait = 0;
#endif
VOID
KeStartAllProcessors (
VOID
)
/*++
Routine Description:
Called by p0 during phase 1 of bootup. This function implements
the x86 specific code to contact the hal for each system processor.
Arguments:
Return Value:
All available processors are sent to KiSystemStartup.
--*/
{
KPROCESSOR_STATE ProcessorState;
KDESCRIPTOR Descriptor;
KDESCRIPTOR TSSDesc, DFTSSDesc, NMITSSDesc, PCRDesc;
PKGDTENTRY pGDT;
PVOID pStack;
PVOID pDpcStack;
ULONG DFStack;
PUCHAR pThreadObject;
PULONG pTopOfStack;
ULONG NewProcessorNumber;
BOOLEAN NewProcessor;
PKPROCESS Process;
PKTHREAD Thread;
PKTSS pTSS;
PLIST_ENTRY NextEntry;
LONG NumberProcessors;
// If the registered number of processors is greater than the maximum
// number of processors supported, then only allow the maximum number
// of supported processors.
if (KeRegisteredProcessors > MAXIMUM_PROCESSORS) {
KeRegisteredProcessors = MAXIMUM_PROCESSORS;
}
// Set barrier that will prevent any other processor from entering the
// idle loop until all processors have been started.
KiBarrierWait = 1;
while ((ULONG)KeNumberProcessors < KeRegisteredProcessors) {
// Build up a processor state for new processor
RtlZeroMemory ((PVOID) &ProcessorState, sizeof ProcessorState);
// Give the new processor its own GDT
_asm {
sgdt Descriptor.Limit
}
KiCloneDescriptor (&Descriptor,
&ProcessorState.SpecialRegisters.Gdtr);
pGDT = (PKGDTENTRY) ProcessorState.SpecialRegisters.Gdtr.Base;
// Give new processor its own IDT
_asm {
sidt Descriptor.Limit
}
KiCloneDescriptor (&Descriptor,
&ProcessorState.SpecialRegisters.Idtr);
// Give new processor its own TSS and PCR
KiCloneSelector (KGDT_TSS, pGDT, &TSSDesc);
KiCloneSelector (KGDT_R0_PCR, pGDT, &PCRDesc);
// Allocate double-fault TSS & stack, and NMI TSS
KiCloneSelector (KGDT_DF_TSS, pGDT, &DFTSSDesc);
DFStack = (ULONG)ExAllocatePoolWithTag(NonPagedPool, DOUBLE_FAULT_STACK_SIZE, ' eK');
pTSS = (PKTSS)DFTSSDesc.Base;
pTSS->Esp0 = DFStack + DOUBLE_FAULT_STACK_SIZE;
pTSS->NotUsed2[5] = DFStack + DOUBLE_FAULT_STACK_SIZE;
KiCloneSelector (KGDT_NMI_TSS, pGDT, &NMITSSDesc);
pTSS = (PKTSS)NMITSSDesc.Base;
pTSS->Esp0 = DFStack + DOUBLE_FAULT_STACK_SIZE;
pTSS->NotUsed2[5] = DFStack + DOUBLE_FAULT_STACK_SIZE;
// Set other SpecialRegisters in processor state
_asm {
mov eax, cr0
and eax, NOT (CR0_AM or CR0_WP)
mov ProcessorState.SpecialRegisters.Cr0, eax
mov eax, cr3
mov ProcessorState.SpecialRegisters.Cr3, eax
pushfd
pop ProcessorState.ContextFrame.EFlags
and ProcessorState.ContextFrame.EFlags, NOT EFLAGS_INTERRUPT_MASK
}
ProcessorState.SpecialRegisters.Tr = KGDT_TSS;
pGDT[KGDT_TSS>>3].HighWord.Bytes.Flags1 = 0x89;
#if defined(_X86PAE_)
ProcessorState.SpecialRegisters.Cr4 = CR4_PAE;
#endif
// Allocate a DPC stack, idle thread stack and ThreadObject for
// the new processor.
pStack = MmCreateKernelStack (FALSE);
pDpcStack = MmCreateKernelStack (FALSE);
pThreadObject = (PUCHAR)ExAllocatePoolWithTag (NonPagedPool, sizeof(ETHREAD), ' eK');
// Zero initialize these...
RtlZeroMemory ((PVOID) PCRDesc.Base, sizeof (KPCR));
RtlZeroMemory ((PVOID) pThreadObject, sizeof (KTHREAD));
// Setup context
// Push variables onto new stack
pTopOfStack = (PULONG) pStack;
pTopOfStack[-1] = (ULONG) KeLoaderBlock;
ProcessorState.ContextFrame.Esp = (ULONG) (pTopOfStack-2);
ProcessorState.ContextFrame.Eip = (ULONG) KiSystemStartup;
ProcessorState.ContextFrame.SegCs = KGDT_R0_CODE;
ProcessorState.ContextFrame.SegDs = KGDT_R3_DATA;
ProcessorState.ContextFrame.SegEs = KGDT_R3_DATA;
ProcessorState.ContextFrame.SegFs = KGDT_R0_PCR;
ProcessorState.ContextFrame.SegSs = KGDT_R0_DATA;
// Initialize new processor's PCR & Prcb
NewProcessorNumber = KeNumberProcessors;
KiInitializePcr (
(ULONG) NewProcessorNumber,
(PKPCR) PCRDesc.Base,
(PKIDTENTRY) ProcessorState.SpecialRegisters.Idtr.Base,
(PKGDTENTRY) ProcessorState.SpecialRegisters.Gdtr.Base,
(PKTSS) TSSDesc.Base,
(PKTHREAD) pThreadObject,
(PVOID) pDpcStack
);
// Adjust LoaderBlock so it has the next processors state
KeLoaderBlock->KernelStack = (ULONG) pTopOfStack;
KeLoaderBlock->Thread = (ULONG) pThreadObject;
KeLoaderBlock->Prcb = (ULONG) ((PKPCR) PCRDesc.Base)->Prcb;
// Contact hal to start new processor
NewProcessor = HalStartNextProcessor (KeLoaderBlock, &ProcessorState);
if (!NewProcessor) {
// There wasn't another processor, so free resources and
// break
KiProcessorBlock[NewProcessorNumber] = NULL;
ExFreePool ((PVOID) ProcessorState.SpecialRegisters.Gdtr.Base);
ExFreePool ((PVOID) ProcessorState.SpecialRegisters.Idtr.Base);
ExFreePool ((PVOID) TSSDesc.Base);
ExFreePool ((PVOID) DFTSSDesc.Base);
ExFreePool ((PVOID) NMITSSDesc.Base);
ExFreePool ((PVOID) PCRDesc.Base);
ExFreePool ((PVOID) pThreadObject);
ExFreePool ((PVOID) DFStack);
MmDeleteKernelStack ( pStack, FALSE);
MmDeleteKernelStack ( pDpcStack, FALSE);
break;
}
// Wait for processor to initialize in kernel, then loop for another
while (*((volatile ULONG *) &KeLoaderBlock->Prcb) != 0) {
KeYieldProcessor();
}
}
// Reset and synchronize the performance counters of all processors, by
// applying a null adjustment to the interrupt time
KiAdjustInterruptTime (0);
// Allow all processors that were started to enter the idle loop and
// begin execution.
KiBarrierWait = 0;
}
static VOID
KiCloneSelector (
IN ULONG SrcSelector,
IN PKGDTENTRY pNGDT,
IN PKDESCRIPTOR pDestDescriptor
/*++
Routine Description:
Makes a copy of the current selector's data, and update the new
gdt's linear address to point to the new copy.
Arguments:
SrcSelector - Selector value to clone
pNGDT - New gdt table which is being built
DescDescriptor - descriptor structure to fill in with resulting memory
Return Value:
--*/
)
{
KDESCRIPTOR Descriptor;
PKGDTENTRY pGDT;
ULONG CurrentBase;
ULONG NewBase;
_asm {
sgdt fword ptr [Descriptor.Limit] ; Get GDT's addr
}
pGDT = (PKGDTENTRY) Descriptor.Base;
pGDT += SrcSelector >> 3;
pNGDT += SrcSelector >> 3;
CurrentBase = pGDT->BaseLow | (pGDT->HighWord.Bits.BaseMid << 16) |
(pGDT->HighWord.Bits.BaseHi << 24);
Descriptor.Base = CurrentBase;
Descriptor.Limit = pGDT->LimitLow;
if (pGDT->HighWord.Bits.Granularity & GRAN_PAGE)
Descriptor.Limit = (Descriptor.Limit << PAGE_SHIFT) -1;
KiCloneDescriptor (&Descriptor, pDestDescriptor);
NewBase = pDestDescriptor->Base;
pNGDT->BaseLow = (USHORT) NewBase & 0xffff;
pNGDT->HighWord.Bits.BaseMid = (UCHAR) (NewBase >> 16) & 0xff;
pNGDT->HighWord.Bits.BaseHi = (UCHAR) (NewBase >> 24) & 0xff;
}
static VOID
KiCloneDescriptor (
IN PKDESCRIPTOR pSrcDescriptor,
IN PKDESCRIPTOR pDestDescriptor
)
/*++
Routine Description:
Makes a copy of the specified descriptor, and supplies a return
descriptor for the new copy
Arguments:
pSrcDescriptor - descriptor to clone
pDescDescriptor - the cloned descriptor
Return Value:
--*/
{
ULONG Size;
Size = pSrcDescriptor->Limit + 1;
pDestDescriptor->Limit = (USHORT) Size -1;
pDestDescriptor->Base = (ULONG) ExAllocatePoolWithTag (NonPagedPool, Size, ' eK');
RtlMoveMemory ((PVOID) pDestDescriptor->Base,
(PVOID) pSrcDescriptor->Base, Size);
}
#endif // !NT_UP