Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

397 lines
9.6 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
allproc.c
Abstract:
This module allocates and intializes 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;
PUCHAR pStack;
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 it's own GDT
//
_asm {
sgdt Descriptor.Limit
}
KiCloneDescriptor (&Descriptor,
&ProcessorState.SpecialRegisters.Gdtr);
pGDT = (PKGDTENTRY) ProcessorState.SpecialRegisters.Gdtr.Base;
//
// Give new processor it's own IDT
//
_asm {
sidt Descriptor.Limit
}
KiCloneDescriptor (&Descriptor,
&ProcessorState.SpecialRegisters.Idtr);
//
// Give new processor it's 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)ExAllocatePool(NonPagedPool, DOUBLE_FAULT_STACK_SIZE);
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;
//
// Allocate a kernel stack and ThreadObject for the new processor
//
pStack = (PUCHAR)MmCreateKernelStack (FALSE);
pThreadObject = (PUCHAR)ExAllocatePool (NonPagedPool, sizeof(ETHREAD));
//
// Zero initialize these...
//
RtlZeroMemory ((PVOID) PCRDesc.Base, sizeof (KPCR));
RtlZeroMemory ((PVOID) pThreadObject, sizeof (KTHREAD));
//
// Setup context
// Push varibles 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 processors 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
);
//
// 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
//
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 ((PVOID) pStack, FALSE);
break;
}
//
// Wait for processor to initialize in kernel, then loop for another
//
while (*((volatile ULONG *) &KeLoaderBlock->Prcb) != 0)
{ }
}
//
// Reset and synchronize the performance counters of all processors.
//
NumberProcessors = KeNumberProcessors;
KiIpiGenericCall (
(PKIPI_BROADCAST_WORKER) HalCalibratePerformanceCounter,
(ULONG)(&NumberProcessors)
);
//
// Allow all processor 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 selectors data, and updated 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 GDTs 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) ExAllocatePool (NonPagedPool, Size);
RtlMoveMemory ((PVOID) pDestDescriptor->Base,
(PVOID) pSrcDescriptor->Base, Size);
}
#endif // !NT_UP