NT4/private/ntos/init/init.c

2068 lines
60 KiB
C
Raw Permalink Normal View History

2001-01-01 00:00:00 +01:00
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
init.c
Abstract:
Main source file the NTOS system initialization subcomponent.
Author:
Steve Wood (stevewo) 31-Mar-1989
Revision History:
--*/
#include "ntos.h"
#include "ntimage.h"
#include <zwapi.h>
#include <ntdddisk.h>
#include <fsrtl.h>
#include <ntverp.h>
#include "stdlib.h"
#include "stdio.h"
#include <string.h>
UNICODE_STRING NtSystemRoot;
PVOID ExPageLockHandle;
VOID
ExpInitializeExecutive(
IN ULONG Number,
IN PLOADER_PARAMETER_BLOCK LoaderBlock
);
NTSTATUS
CreateSystemRootLink(
IN PLOADER_PARAMETER_BLOCK LoaderBlock
);
static USHORT
NameToOrdinal (
IN PSZ NameOfEntryPoint,
IN ULONG DllBase,
IN ULONG NumberOfNames,
IN PULONG NameTableBase,
IN PUSHORT NameOrdinalTableBase
);
NTSTATUS
LookupEntryPoint (
IN PVOID DllBase,
IN PSZ NameOfEntryPoint,
OUT PVOID *AddressOfEntryPoint
);
#if i386
VOID
KiRestoreInterrupts (
IN BOOLEAN Restore
);
#endif
VOID
ExBurnMemory(
IN PLOADER_PARAMETER_BLOCK LoaderBlock
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,ExpInitializeExecutive)
#pragma alloc_text(INIT,Phase1Initialization)
#pragma alloc_text(INIT,CreateSystemRootLink)
#pragma alloc_text(INIT,NameToOrdinal)
#pragma alloc_text(INIT,LookupEntryPoint)
#pragma alloc_text(INIT,ExBurnMemory)
#endif
//
// Define global static data used during initialization.
//
ULONG NtGlobalFlag;
extern PMESSAGE_RESOURCE_BLOCK KiBugCheckMessages;
ULONG NtMajorVersion;
ULONG NtMinorVersion;
#if DBG
ULONG NtBuildNumber = VER_PRODUCTBUILD | 0xC0000000;
#else
ULONG NtBuildNumber = VER_PRODUCTBUILD | 0xF0000000;
#endif
ULONG InitializationPhase; // bss 0
extern LIST_ENTRY PsLoadedModuleList;
extern KiServiceLimit;
extern PMESSAGE_RESOURCE_DATA KiBugCodeMessages;
extern CM_SYSTEM_CONTROL_VECTOR CmControlVector[];
ULONG CmNtGlobalFlag;
ULONG CmNtCSDVersion;
UNICODE_STRING CmVersionString;
UNICODE_STRING CmCSDVersionString;
//
// Define working set watch enabled.
//
BOOLEAN PsWatchEnabled = FALSE;
#if i386
typedef struct _EXLOCK {
KSPIN_LOCK SpinLock;
KIRQL Irql;
} EXLOCK, *PEXLOCK;
BOOLEAN
ExpOkayToLockRoutine(
IN PEXLOCK Lock
)
{
return TRUE;
}
NTSTATUS
ExpInitializeLockRoutine(
PEXLOCK Lock
)
{
KeInitializeSpinLock(&Lock->SpinLock);
return STATUS_SUCCESS;
}
NTSTATUS
ExpAcquireLockRoutine(
PEXLOCK Lock
)
{
ExAcquireSpinLock(&Lock->SpinLock,&Lock->Irql);
return STATUS_SUCCESS;
}
NTSTATUS
ExpReleaseLockRoutine(
PEXLOCK Lock
)
{
ExReleaseSpinLock(&Lock->SpinLock,Lock->Irql);
return STATUS_SUCCESS;
}
NTSTATUS
ExpDeleteLockRoutine(
PEXLOCK Lock
)
{
return STATUS_SUCCESS;
}
#endif // i386
NLSTABLEINFO InitTableInfo;
ULONG InitNlsTableSize;
PVOID InitNlsTableBase;
ULONG InitAnsiCodePageDataOffset;
ULONG InitOemCodePageDataOffset;
ULONG InitUnicodeCaseTableDataOffset;
PVOID InitNlsSectionPointer;
VOID
ExBurnMemory(
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
{
PLIST_ENTRY ListHead;
PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
PLIST_ENTRY NextEntry;
PCHAR TypeOfMemory;
PCHAR Options;
PCHAR BurnMemoryOption;
PCHAR NumProcOption;
ULONG BurnMemoryAmount;
ULONG PagesToBurn;
ULONG PagesBurned;
ULONG NewRegisteredProcessors;
#if !defined(NT_UP)
extern ULONG KeRegisteredProcessors;
#endif
if (LoaderBlock->LoadOptions == NULL) {
return;
}
Options = LoaderBlock->LoadOptions;
_strupr(Options);
#if !defined(NT_UP)
NumProcOption = strstr(Options, "NUMPROC");
if (NumProcOption != NULL) {
NumProcOption = strstr(NumProcOption,"=");
}
if (NumProcOption != NULL) {
NewRegisteredProcessors = atol(NumProcOption+1);
if (NewRegisteredProcessors < KeRegisteredProcessors) {
KeRegisteredProcessors = NewRegisteredProcessors;
DbgPrint("INIT: NumProcessors = %d\n",KeRegisteredProcessors);
}
}
#endif
BurnMemoryOption = strstr(Options, "BURNMEMORY");
if (BurnMemoryOption == NULL ) {
return;
}
BurnMemoryOption = strstr(BurnMemoryOption,"=");
if (BurnMemoryOption == NULL ) {
return;
}
BurnMemoryAmount = atol(BurnMemoryOption+1);
PagesToBurn = (BurnMemoryAmount*(1024*1024))/PAGE_SIZE;
DbgPrint("INIT: BurnAmount %dmb -> %d pages\n",BurnMemoryAmount,PagesToBurn);
ListHead = &LoaderBlock->MemoryDescriptorListHead;
NextEntry = ListHead->Flink;
PagesBurned = 0;
do {
MemoryDescriptor = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if (MemoryDescriptor->MemoryType == LoaderFree ||
MemoryDescriptor->MemoryType == LoaderFirmwareTemporary ) {
if ( PagesBurned < PagesToBurn ) {
//
// We still need to chew up some memory
//
if ( MemoryDescriptor->PageCount > (PagesToBurn - PagesBurned) ) {
//
// This block has more than enough pages to satisfy us...
// simply change its page count
//
DbgPrint("INIT: BasePage %5lx PageCount %5d ReducedBy %5d to %5d\n",
MemoryDescriptor->BasePage,
MemoryDescriptor->PageCount,
(PagesToBurn - PagesBurned),
MemoryDescriptor->PageCount - (PagesToBurn - PagesBurned)
);
MemoryDescriptor->PageCount = MemoryDescriptor->PageCount - (PagesToBurn - PagesBurned);
PagesBurned = PagesToBurn;
}
else {
//
// This block is not big enough. Take all of its pages and convert
// it to LoaderBad
//
DbgPrint("INIT: BasePage %5lx PageCount %5d Turned to LoaderBad\n",
MemoryDescriptor->BasePage,
MemoryDescriptor->PageCount
);
PagesBurned += MemoryDescriptor->PageCount;
MemoryDescriptor->MemoryType = LoaderBad;
}
}
else {
return;
}
}
NextEntry = NextEntry->Flink;
} while (NextEntry != ListHead);
}
extern BOOLEAN ExpInTextModeSetup;
VOID
ExpInitializeExecutive(
IN ULONG Number,
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
/*++
Routine Description:
This routine is called from the kernel initialization routine during
bootstrap to initialize the executive and all of its subcomponents.
Each subcomponent is potentially called twice to perform phase 0, and
then phase 1 initialization. During phase 0 initialization, the only
activity that may be performed is the initialization of subcomponent
specific data. Phase 0 initilaization is performed in the context of
the kernel start up routine with initerrupts disabled. During phase 1
initialization, the system is fully operational and subcomponents may
do any initialization that is necessary.
Arguments:
LoaderBlock - Supplies a pointer to a loader parameter block.
Return Value:
None.
--*/
{
NTSTATUS Status;
PLDR_DATA_TABLE_ENTRY DataTableEntry;
PMESSAGE_RESOURCE_ENTRY MessageEntry;
PLIST_ENTRY NextEntry;
ANSI_STRING AnsiString;
STRING NameString;
CHAR Buffer[ 256 ];
CHAR VersionBuffer[ 64 ];
PCHAR s, sMajor, sMinor;
ULONG ImageCount, i;
BOOLEAN IncludeType[LoaderMaximum];
ULONG MemoryAlloc[(sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
sizeof(PHYSICAL_MEMORY_RUN)*MAX_PHYSICAL_MEMORY_FRAGMENTS) /
sizeof(ULONG)];
PPHYSICAL_MEMORY_DESCRIPTOR Memory;
ULONG ResourceIdPath[3];
PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
PIMAGE_NT_HEADERS NtHeaders;
PMESSAGE_RESOURCE_DATA MessageData;
if (Number == 0) {
ExpInTextModeSetup = LoaderBlock->SetupLoaderBlock ? TRUE : FALSE;
InitializationPhase = 0L;
//
// Compute PhysicalMemoryBlock
//
Memory = (PPHYSICAL_MEMORY_DESCRIPTOR)&MemoryAlloc;
Memory->NumberOfRuns = MAX_PHYSICAL_MEMORY_FRAGMENTS;
// include all memory types ...
for (i=0; i < LoaderMaximum; i++) {
IncludeType[i] = TRUE;
}
// ... expect these..
IncludeType[LoaderBad] = FALSE;
IncludeType[LoaderFirmwarePermanent] = FALSE;
IncludeType[LoaderSpecialMemory] = FALSE;
MmInitializeMemoryLimits(LoaderBlock, IncludeType, Memory);
//
// Initialize the translation tables using the loader
// loaded tables
//
InitNlsTableBase = LoaderBlock->NlsData->AnsiCodePageData;
InitAnsiCodePageDataOffset = 0;
InitOemCodePageDataOffset = ((PUCHAR)LoaderBlock->NlsData->OemCodePageData - (PUCHAR)LoaderBlock->NlsData->AnsiCodePageData);
InitUnicodeCaseTableDataOffset = ((PUCHAR)LoaderBlock->NlsData->UnicodeCaseTableData - (PUCHAR)LoaderBlock->NlsData->AnsiCodePageData);
RtlInitNlsTables(
(PVOID)((PUCHAR)InitNlsTableBase+InitAnsiCodePageDataOffset),
(PVOID)((PUCHAR)InitNlsTableBase+InitOemCodePageDataOffset),
(PVOID)((PUCHAR)InitNlsTableBase+InitUnicodeCaseTableDataOffset),
&InitTableInfo
);
RtlResetRtlTranslations(&InitTableInfo);
//
// Initialize the Hardware Architecture Layer (HAL).
//
if (HalInitSystem(InitializationPhase, LoaderBlock) == FALSE) {
KeBugCheck(HAL_INITIALIZATION_FAILED);
}
#if i386
//
// Interrupts can now be enabled
//
KiRestoreInterrupts (TRUE);
#endif
//
// Initialize the crypto exponent... Set to 0 when systems leave ms!
//
#ifdef TEST_BUILD_EXPONENT
#pragma message("WARNING: building kernel with TESTKEY enabled!")
#else
#define TEST_BUILD_EXPONENT 0
#endif
SharedUserData->CryptoExponent = TEST_BUILD_EXPONENT;
#if DBG
NtGlobalFlag |= FLG_ENABLE_CLOSE_EXCEPTIONS |
FLG_ENABLE_KDEBUG_SYMBOL_LOAD |
FLG_IGNORE_DEBUG_PRIV;
#endif
sprintf( Buffer, "C:%s", LoaderBlock->NtBootPathName );
RtlInitString( &AnsiString, Buffer );
Buffer[ --AnsiString.Length ] = '\0';
NtSystemRoot.Buffer = SharedUserData->NtSystemRoot;
NtSystemRoot.MaximumLength = sizeof( SharedUserData->NtSystemRoot ) / sizeof( WCHAR );
NtSystemRoot.Length = 0;
Status = RtlAnsiStringToUnicodeString( &NtSystemRoot,
&AnsiString,
FALSE
);
if (!NT_SUCCESS( Status )) {
KeBugCheck(SESSION3_INITIALIZATION_FAILED);
}
//
// Find the address of BugCheck message block resource and put it
// in KiBugCodeMessages.
//
// WARNING: This code assumes that the LDR_DATA_TABLE_ENTRY for
// ntoskrnl.exe is always the first in the loaded module list.
//
DataTableEntry = CONTAINING_RECORD(
LoaderBlock->LoadOrderListHead.Flink,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
ResourceIdPath[0] = 11;
ResourceIdPath[1] = 1;
ResourceIdPath[2] = 0;
Status = LdrFindResource_U(
DataTableEntry->DllBase,
ResourceIdPath,
3,
(VOID *) &ResourceDataEntry);
if (NT_SUCCESS(Status)) {
Status = LdrAccessResource(
DataTableEntry->DllBase,
ResourceDataEntry,
&MessageData,
NULL);
if (NT_SUCCESS(Status)) {
KiBugCodeMessages = MessageData;
}
}
//
// Scan the loaded module list and load the image symbols via the
// kernel debugger for the system, the HAL, the boot file system, and
// the boot drivers.
//
ImageCount = 0;
NextEntry = LoaderBlock->LoadOrderListHead.Flink;
while (NextEntry != &LoaderBlock->LoadOrderListHead) {
//
// Get the address of the data table entry for the next component.
//
DataTableEntry = CONTAINING_RECORD(NextEntry,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
//
// Load the symbols via the kernel debugger for the next component.
//
sprintf( Buffer, "%ws\\System32\\%s%wZ",
&SharedUserData->NtSystemRoot[2],
ImageCount++ < 2 ? "" : "Drivers\\",
&DataTableEntry->BaseDllName
);
RtlInitString( &NameString, Buffer );
DbgLoadImageSymbols(&NameString, DataTableEntry->DllBase, (ULONG)-1);
#if !defined(NT_UP)
if ( !MmVerifyImageIsOkForMpUse(DataTableEntry->DllBase) ) {
KeBugCheckEx(UP_DRIVER_ON_MP_SYSTEM,(ULONG)DataTableEntry->DllBase,0,0,0);
}
#endif // NT_UP
NextEntry = NextEntry->Flink;
}
} else {
//
// Initialize the Hardware Architecture Layer (HAL).
//
if (HalInitSystem(InitializationPhase, LoaderBlock) == FALSE) {
KeBugCheck(HAL_INITIALIZATION_FAILED);
}
}
if (Number == 0) {
// DbgBreakPoint();
//
// get system control values out of the registry
//
CmGetSystemControlValues(LoaderBlock->RegistryBase, &CmControlVector[0]);
if (CmNtGlobalFlag & ~FLG_VALID_BITS) {
#if DBG
CmNtGlobalFlag = 0x000F4400;
#else
CmNtGlobalFlag = 0x00000000;
#endif
}
#ifdef VER_PRODUCTRCVERSION
if ((CmNtCSDVersion & 0xFFFF0000) == 0) {
CmNtCSDVersion |= VER_PRODUCTRCVERSION << 16;
}
#endif
NtGlobalFlag |= CmNtGlobalFlag;
#if !DBG
if (!(CmNtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD)) {
NtGlobalFlag &= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
}
#endif
//
// Initialize the ExResource package.
//
if (!ExInitSystem()) {
KeBugCheck(PHASE0_INITIALIZATION_FAILED);
}
//
// Initialize memory managment and the memory allocation pools.
//
ExBurnMemory(LoaderBlock);
MmInitSystem(0, LoaderBlock, Memory);
//
// Snapshot the NLS tables into paged pool and then
// reset the translation tables
//
{
PLIST_ENTRY NextMd;
PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
//
//
// Walk through the memory descriptors and size the nls data
//
NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
MemoryDescriptor = CONTAINING_RECORD(NextMd,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
switch (MemoryDescriptor->MemoryType) {
case LoaderNlsData:
InitNlsTableSize += MemoryDescriptor->PageCount*PAGE_SIZE;
break;
default:
break;
}
NextMd = MemoryDescriptor->ListEntry.Flink;
}
InitNlsTableBase = ExAllocatePoolWithTag(NonPagedPool,InitNlsTableSize,' slN');
if ( !InitNlsTableBase ) {
KeBugCheck(PHASE0_INITIALIZATION_FAILED);
}
//
// Copy the NLS data into the dynamic buffer so that we can
// free the buffers allocated by the loader. The loader garuntees
// contiguous buffers and the base of all the tables is the ANSI
// code page data
//
RtlMoveMemory(
InitNlsTableBase,
LoaderBlock->NlsData->AnsiCodePageData,
InitNlsTableSize
);
RtlInitNlsTables(
(PVOID)((PUCHAR)InitNlsTableBase+InitAnsiCodePageDataOffset),
(PVOID)((PUCHAR)InitNlsTableBase+InitOemCodePageDataOffset),
(PVOID)((PUCHAR)InitNlsTableBase+InitUnicodeCaseTableDataOffset),
&InitTableInfo
);
RtlResetRtlTranslations(&InitTableInfo);
}
//
// Now that the HAL is available and memory management has sized
// memory, Display Version number
//
DataTableEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
if (CmNtCSDVersion & 0xFFFF) {
Status = RtlFindMessage (DataTableEntry->DllBase, 11, 0,
WINDOWS_NT_CSD_STRING, &MessageEntry);
if (NT_SUCCESS( Status )) {
RtlInitAnsiString( &AnsiString, MessageEntry->Text );
AnsiString.Length -= 2;
sprintf( Buffer,
"%Z %u%c",
&AnsiString,
(CmNtCSDVersion & 0xFF00) >> 8,
(CmNtCSDVersion & 0xFF) ? 'A' + (CmNtCSDVersion & 0xFF) - 1 : '\0'
);
}
else {
sprintf( Buffer, "CSD %04x", CmNtCSDVersion );
}
}
else {
CmCSDVersionString.MaximumLength = sprintf( Buffer, VER_PRODUCTBETA_STR );
}
//
// High-order 16-bits of CSDVersion contain RC number. If non-zero
// display it after Service Pack number
//
if (CmNtCSDVersion & 0xFFFF0000) {
s = Buffer + strlen( Buffer );
if (s != Buffer) {
*s++ = ',';
*s++ = ' ';
}
Status = RtlFindMessage (DataTableEntry->DllBase, 11, 0,
WINDOWS_NT_RC_STRING, &MessageEntry);
if (NT_SUCCESS(Status)) {
RtlInitAnsiString( &AnsiString, MessageEntry->Text );
AnsiString.Length -= 2;
}
else {
RtlInitAnsiString( &AnsiString, "RC" );
}
s += sprintf( s,
"%Z %u",
&AnsiString,
(CmNtCSDVersion & 0xFF000000) >> 24
);
if (CmNtCSDVersion & 0x00FF0000) {
s += sprintf( s, ".%u", (CmNtCSDVersion & 0x00FF0000) >> 16 );
}
*s++ = '\0';
}
RtlInitAnsiString( &AnsiString, Buffer );
RtlAnsiStringToUnicodeString( &CmCSDVersionString, &AnsiString, TRUE );
Status = RtlFindMessage (DataTableEntry->DllBase, 11, 0,
WINDOWS_NT_BANNER, &MessageEntry);
s = Buffer;
if (CmCSDVersionString.Length != 0) {
s += sprintf( s, ": %wZ", &CmCSDVersionString );
}
*s++ = '\0';
sMajor = strcpy( VersionBuffer, VER_PRODUCTVERSION_STR );
sMinor = strchr( sMajor, '.' );
*sMinor++ = '\0';
NtMajorVersion = atoi( sMajor );
NtMinorVersion = atoi( sMinor );
*--sMinor = '.';
NtHeaders = RtlImageNtHeader( DataTableEntry->DllBase );
if (NtHeaders->OptionalHeader.MajorSubsystemVersion != NtMajorVersion ||
NtHeaders->OptionalHeader.MinorSubsystemVersion != NtMinorVersion
) {
NtMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion;
NtMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion;
}
sprintf( VersionBuffer, "%u.%u", NtMajorVersion, NtMinorVersion );
RtlCreateUnicodeStringFromAsciiz( &CmVersionString, VersionBuffer );
sprintf( s,
NT_SUCCESS(Status) ? MessageEntry->Text : "MICROSOFT (R) WINDOWS NT (TM)\n",
VersionBuffer,
NtBuildNumber & 0xFFFF,
Buffer
);
HalDisplayString(s);
#if i386 && !FPO
if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
PVOID StackTraceDataBase;
ULONG StackTraceDataBaseLength;
NTSTATUS Status;
StackTraceDataBaseLength = 512 * 1024;
switch ( MmQuerySystemSize() ) {
case MmMediumSystem :
StackTraceDataBaseLength = 1024 * 1024;
break;
case MmLargeSystem :
StackTraceDataBaseLength = 2048 * 1024;
break;
}
StackTraceDataBase = ExAllocatePoolWithTag( NonPagedPool,
StackTraceDataBaseLength,'catS'
);
if (StackTraceDataBase != NULL) {
KdPrint(( "INIT: Kernel mode stack back trace enabled with %u KB buffer.\n", StackTraceDataBaseLength / 1024 ));
Status = RtlInitStackTraceDataBaseEx( StackTraceDataBase,
StackTraceDataBaseLength,
StackTraceDataBaseLength,
(PRTL_INITIALIZE_LOCK_ROUTINE) ExpInitializeLockRoutine,
(PRTL_ACQUIRE_LOCK_ROUTINE) ExpAcquireLockRoutine,
(PRTL_RELEASE_LOCK_ROUTINE) ExpReleaseLockRoutine,
(PRTL_OKAY_TO_LOCK_ROUTINE) ExpOkayToLockRoutine
);
} else {
Status = STATUS_NO_MEMORY;
}
if (!NT_SUCCESS( Status )) {
KdPrint(( "INIT: Unable to initialize stack trace data base - Status == %lx\n", Status ));
}
}
#endif // i386 && !FPO
if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING) {
RtlInitializeExceptionLog(MAX_EXCEPTION_LOG);
}
ExInitializeHandleTablePackage();
#if DBG
//
// Allocate and zero the system service count table.
//
KeServiceDescriptorTable[0].Count =
(PULONG)ExAllocatePoolWithTag(NonPagedPool,
KiServiceLimit * sizeof(ULONG),
'llac');
KeServiceDescriptorTableShadow[0].Count = KeServiceDescriptorTable[0].Count;
if (KeServiceDescriptorTable[0].Count != NULL ) {
RtlZeroMemory((PVOID)KeServiceDescriptorTable[0].Count,
KiServiceLimit * sizeof(ULONG));
}
#endif
if (!ObInitSystem()) {
KeBugCheck(OBJECT_INITIALIZATION_FAILED);
}
if (!SeInitSystem()) {
KeBugCheck(SECURITY_INITIALIZATION_FAILED);
}
if (PsInitSystem(0, LoaderBlock) == FALSE) {
KeBugCheck(PROCESS_INITIALIZATION_FAILED);
}
//#ifdef _PNP_POWER_
if (!PpInitSystem()) {
KeBugCheck(PP0_INITIALIZATION_FAILED);
}
//#endif // _PNP_POWER_
//
// Compute the tick count multiplier that is used for computing the
// windows millisecond tick count and copy the resultant value to
// the memory that is shared between user and kernel mode.
//
ExpTickCountMultiplier = ExComputeTickCountMultiplier(KeMaximumIncrement);
SharedUserData->TickCountMultiplier = ExpTickCountMultiplier;
//
// Set the base os version into shared memory
//
SharedUserData->NtMajorVersion = NtMajorVersion;
SharedUserData->NtMinorVersion = NtMinorVersion;
//
// Set the supported image number range used to determine by the
// loader if a particular image can be executed on the host system.
// Eventually this will need to be dynamically computed. Also set
// the architecture specific feature bits.
//
#if defined(_X86_)
SharedUserData->ImageNumberLow = IMAGE_FILE_MACHINE_I386;
SharedUserData->ImageNumberHigh = IMAGE_FILE_MACHINE_I386;
#elif defined(_ALPHA_)
SharedUserData->ImageNumberLow = IMAGE_FILE_MACHINE_ALPHA;
SharedUserData->ImageNumberHigh = IMAGE_FILE_MACHINE_ALPHA;
SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
#elif defined(_MIPS_)
SharedUserData->ImageNumberLow = IMAGE_FILE_MACHINE_R3000;
if (((PCR->ProcessorId >> 8) & 0xff)== 0x09) {
SharedUserData->ImageNumberHigh = IMAGE_FILE_MACHINE_R10000;
} else {
SharedUserData->ImageNumberHigh = IMAGE_FILE_MACHINE_R4000;
}
SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
#elif defined(_PPC_)
SharedUserData->ImageNumberLow = IMAGE_FILE_MACHINE_POWERPC;
SharedUserData->ImageNumberHigh = IMAGE_FILE_MACHINE_POWERPC;
#elif
#error "must define target machine architecture"
#endif
}
}
VOID
Phase1Initialization(
IN PVOID Context
)
{
PLOADER_PARAMETER_BLOCK LoaderBlock;
PETHREAD Thread;
PKPRCB Prcb;
KPRIORITY Priority;
NTSTATUS Status;
UNICODE_STRING SessionManager;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID Address;
ULONG Size;
ULONG Index;
RTL_USER_PROCESS_INFORMATION ProcessInformation;
LARGE_INTEGER UniversalTime;
LARGE_INTEGER CmosTime;
LARGE_INTEGER OldTime;
TIME_FIELDS TimeFields;
UNICODE_STRING UnicodeDebugString;
ANSI_STRING AnsiDebugString;
UNICODE_STRING EnvString, NullString, UnicodeSystemDriveString;
CHAR DebugBuffer[256];
PWSTR Src, Dst;
BOOLEAN ResetActiveTimeBias;
HANDLE NlsSection;
LARGE_INTEGER SectionSize;
LARGE_INTEGER SectionOffset;
PVOID SectionBase;
PVOID ViewBase;
ULONG CapturedViewSize;
ULONG SavedViewSize;
LONG BootTimeZoneBias;
PLDR_DATA_TABLE_ENTRY DataTableEntry;
PMESSAGE_RESOURCE_ENTRY MessageEntry;
#ifndef NT_UP
PMESSAGE_RESOURCE_ENTRY MessageEntry1;
#endif
PCHAR MPKernelString;
//
// Set handle for PAGELK section.
//
ExPageLockHandle = MmLockPagableCodeSection ((PVOID)NtQuerySystemEnvironmentValue);
MmUnlockPagableImageSection(ExPageLockHandle);
//
// Set the phase number and raise the priority of current thread to
// a high priority so it will not be prempted during initialization.
//
ResetActiveTimeBias = FALSE;
InitializationPhase = 1;
Thread = PsGetCurrentThread();
Priority = KeSetPriorityThread( &Thread->Tcb,MAXIMUM_PRIORITY - 1 );
//
// Put phase 1 initialization calls here
//
LoaderBlock = (PLOADER_PARAMETER_BLOCK)Context;
if (HalInitSystem(InitializationPhase, LoaderBlock) == FALSE) {
KeBugCheck(HAL1_INITIALIZATION_FAILED);
}
#ifdef _PNP_POWER_
if (!PoInitSystem(0)) {
KeBugCheck(IO1_INITIALIZATION_FAILED);
}
#endif // _PNP_POWER_
//
// Initialize the system time and set the time the system was booted.
//
// N.B. This cannot be done until after the phase one initialization
// of the HAL Layer.
//
if (HalQueryRealTimeClock(&TimeFields) != FALSE) {
RtlTimeFieldsToTime(&TimeFields, &CmosTime);
UniversalTime = CmosTime;
if ( !ExpRealTimeIsUniversal ) {
//
// If the system stores time in local time. This is converted to
// universal time before going any further
//
// If we have previously set the time through NT, then
// ExpLastTimeZoneBias should contain the timezone bias in effect
// when the clock was set. Otherwise, we will have to resort to
// our next best guess which would be the programmed bias stored in
// the registry
//
if ( ExpLastTimeZoneBias == -1 ) {
ResetActiveTimeBias = TRUE;
ExpLastTimeZoneBias = ExpAltTimeZoneBias;
}
ExpTimeZoneBias.QuadPart = Int32x32To64(
ExpLastTimeZoneBias*60, // Bias in seconds
10000000
);
#ifdef _ALPHA_
SharedUserData->TimeZoneBias = ExpTimeZoneBias.QuadPart;
#else
SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.HighPart;
SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.LowPart;
SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.HighPart;
#endif
UniversalTime.QuadPart = CmosTime.QuadPart + ExpTimeZoneBias.QuadPart;
}
KeSetSystemTime(&UniversalTime, &OldTime, NULL);
KeBootTime = UniversalTime;
}
MPKernelString = "";
DataTableEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
#ifndef NT_UP
//
// If this is an MP build of the kernel start any other processors now
//
//
// enforce the processor licensing stuff
//
if ( KeLicensedProcessors ) {
if ( KeRegisteredProcessors > KeLicensedProcessors ) {
KeRegisteredProcessors = KeLicensedProcessors;
}
}
KeStartAllProcessors();
//
// Set the affinity of the boot processes and initialization thread
// for all processors
//
KeGetCurrentThread()->ApcState.Process->Affinity = KeActiveProcessors;
KeSetAffinityThread (KeGetCurrentThread(), KeActiveProcessors);
Status = RtlFindMessage (DataTableEntry->DllBase, 11, 0,
WINDOWS_NT_MP_STRING, &MessageEntry1);
if (NT_SUCCESS( Status )) {
MPKernelString = MessageEntry1->Text;
}
else {
MPKernelString = "MultiProcessor Kernel\r\n";
}
#endif
//
// Signifiy to the HAL that all processors have been started and any
// post initialization should be performed.
//
if (!HalAllProcessorsStarted()) {
KeBugCheck(HAL1_INITIALIZATION_FAILED);
}
RtlInitAnsiString( &AnsiDebugString, MPKernelString );
if (AnsiDebugString.Length >= 2) {
AnsiDebugString.Length -= 2;
}
//
// Now that the processors have started, display number of processors
// and size of memory.
//
Status = RtlFindMessage( DataTableEntry->DllBase,
11,
0,
KeNumberProcessors > 1 ? WINDOWS_NT_INFO_STRING_PLURAL
: WINDOWS_NT_INFO_STRING,
&MessageEntry
);
Size = 0;
for (Index=0; Index < MmPhysicalMemoryBlock->NumberOfRuns; Index++) {
Size += MmPhysicalMemoryBlock->Run[Index].PageCount;
}
sprintf( DebugBuffer,
NT_SUCCESS(Status) ? MessageEntry->Text : "%u System Processor [%u MB Memory] %Z\n",
KeNumberProcessors,
(Size + (1 << 20 - PAGE_SHIFT) - 1) >> (20 - PAGE_SHIFT),
&AnsiDebugString
);
HalDisplayString(DebugBuffer);
//
// Display the memory configuration of the host system.
//
#if 0
{
CHAR DisplayBuffer[256];
PLIST_ENTRY ListHead;
PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
PLIST_ENTRY NextEntry;
PCHAR TypeOfMemory;
//
// Output display headings and enumerate memory types.
//
HalDisplayString("\nStart End Page Type Of Memory\n Pfn Pfn Count\n\n");
ListHead = &LoaderBlock->MemoryDescriptorListHead;
NextEntry = ListHead->Flink;
do {
MemoryDescriptor = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
//
// Switch on the memory type.
//
switch(MemoryDescriptor->MemoryType) {
case LoaderExceptionBlock:
TypeOfMemory = "Exception block";
break;
case LoaderSystemBlock:
TypeOfMemory = "System block";
break;
case LoaderFree:
TypeOfMemory = "Free memory";
break;
case LoaderBad:
TypeOfMemory = "Bad memory";
break;
case LoaderLoadedProgram:
TypeOfMemory = "Os Loader Program";
break;
case LoaderFirmwareTemporary:
TypeOfMemory = "Firmware temporary";
break;
case LoaderFirmwarePermanent:
TypeOfMemory = "Firmware permanent";
break;
case LoaderOsloaderHeap:
TypeOfMemory = "Os Loader heap";
break;
case LoaderOsloaderStack:
TypeOfMemory = "Os Loader stack";
break;
case LoaderSystemCode:
TypeOfMemory = "Operating system code";
break;
case LoaderHalCode:
TypeOfMemory = "HAL code";
break;
case LoaderBootDriver:
TypeOfMemory = "Boot disk/file system driver";
break;
case LoaderConsoleInDriver:
TypeOfMemory = "Console input driver";
break;
case LoaderConsoleOutDriver:
TypeOfMemory = "Console output driver";
break;
case LoaderStartupDpcStack:
TypeOfMemory = "DPC stack";
break;
case LoaderStartupKernelStack:
TypeOfMemory = "Idle process stack";
break;
case LoaderStartupPanicStack:
TypeOfMemory = "Panic stack";
break;
case LoaderStartupPcrPage:
TypeOfMemory = "PCR Page";
break;
case LoaderStartupPdrPage:
TypeOfMemory = "PDR Pages";
break;
case LoaderRegistryData:
TypeOfMemory = "Registry data";
break;
case LoaderMemoryData:
TypeOfMemory = "Memory data";
break;
case LoaderNlsData:
TypeOfMemory = "Nls data";
break;
case LoaderSpecialMemory:
TypeOfMemory = "Special memory";
break;
default :
TypeOfMemory = "Unknown memory";
break;
}
//
// Display memory descriptor information.
//
sprintf(&DisplayBuffer[0], "%5lx %5lx %5lx %s\n",
MemoryDescriptor->BasePage,
MemoryDescriptor->BasePage + MemoryDescriptor->PageCount - 1,
MemoryDescriptor->PageCount,
TypeOfMemory);
HalDisplayString(&DisplayBuffer[0]);
NextEntry = NextEntry->Flink;
} while (NextEntry != ListHead);
HalDisplayString("\n");
}
#endif
if (!ObInitSystem())
KeBugCheck(OBJECT1_INITIALIZATION_FAILED);
if (!ExInitSystem())
KeBugCheckEx(PHASE1_INITIALIZATION_FAILED,0,0,0,0);
if (!KeInitSystem())
KeBugCheckEx(PHASE1_INITIALIZATION_FAILED,0,0,0,0);
//
// SE expects directory and executive objects to be available, but
// must be before device drivers are initialized.
//
if (!SeInitSystem())
KeBugCheck(SECURITY1_INITIALIZATION_FAILED);
//
// Create the symbolic link to \SystemRoot.
//
Status = CreateSystemRootLink(LoaderBlock);
if ( !NT_SUCCESS(Status) ) {
KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED,Status,0,0,0);
}
if (MmInitSystem(1, (PLOADER_PARAMETER_BLOCK)Context, NULL) == FALSE)
KeBugCheck(MEMORY1_INITIALIZATION_FAILED);
//
// Snapshot the NLS tables into a page file backed section, and then
// reset the translation tables
//
SectionSize.HighPart = 0;
SectionSize.LowPart = InitNlsTableSize;
Status = ZwCreateSection(
&NlsSection,
SECTION_ALL_ACCESS,
NULL,
&SectionSize,
PAGE_READWRITE,
SEC_COMMIT,
NULL
);
if (!NT_SUCCESS(Status)) {
KdPrint(("INIT: Nls Section Creation Failed %x\n",Status));
KeBugCheckEx(PHASE1_INITIALIZATION_FAILED,Status,1,0,0);
}
Status = ObReferenceObjectByHandle(
NlsSection,
SECTION_ALL_ACCESS,
MmSectionObjectType,
KernelMode,
&InitNlsSectionPointer,
NULL
);
ZwClose(NlsSection);
if ( !NT_SUCCESS(Status) ) {
KdPrint(("INIT: Nls Section Reference Failed %x\n",Status));
KeBugCheckEx(PHASE1_INITIALIZATION_FAILED,Status,2,0,0);
}
SectionBase = NULL;
CapturedViewSize = SectionSize.LowPart;
SavedViewSize = CapturedViewSize;
SectionSize.LowPart = 0;
Status = MmMapViewInSystemCache(
InitNlsSectionPointer,
&SectionBase,
&SectionSize,
&CapturedViewSize
);
if ( !NT_SUCCESS(Status) ) {
KdPrint(("INIT: Map In System Cache Failed %x\n",Status));
KeBugCheckEx(PHASE1_INITIALIZATION_FAILED,Status,3,0,0);
}
//
// Copy the NLS data into the dynamic buffer so that we can
// free the buffers allocated by the loader. The loader garuntees
// contiguous buffers and the base of all the tables is the ANSI
// code page data
//
RtlMoveMemory(
SectionBase,
InitNlsTableBase,
InitNlsTableSize
);
//
// Unmap the view to remove all pages from memory. This prevents
// these tables from consuming memory in the system cache while
// the system cache is under utilized during bootup.
//
MmUnmapViewInSystemCache (SectionBase, InitNlsSectionPointer, FALSE);
SectionBase = NULL;
//
// Map it back into the system cache, but now the pages will no
// longer be valid.
//
Status = MmMapViewInSystemCache(
InitNlsSectionPointer,
&SectionBase,
&SectionSize,
&SavedViewSize
);
if ( !NT_SUCCESS(Status) ) {
KdPrint(("INIT: Map In System Cache Failed %x\n",Status));
KeBugCheckEx(PHASE1_INITIALIZATION_FAILED,Status,4,0,0);
}
ExFreePool(InitNlsTableBase);
InitNlsTableBase = SectionBase;
RtlInitNlsTables(
(PVOID)((PUCHAR)InitNlsTableBase+InitAnsiCodePageDataOffset),
(PVOID)((PUCHAR)InitNlsTableBase+InitOemCodePageDataOffset),
(PVOID)((PUCHAR)InitNlsTableBase+InitUnicodeCaseTableDataOffset),
&InitTableInfo
);
RtlResetRtlTranslations(&InitTableInfo);
ViewBase = NULL;
SectionOffset.LowPart = 0;
SectionOffset.HighPart = 0;
CapturedViewSize = 0;
//
// Map the system dll into the user part of the address space
//
Status = MmMapViewOfSection(
InitNlsSectionPointer,
PsGetCurrentProcess(),
&ViewBase,
0L,
0L,
&SectionOffset,
&CapturedViewSize,
ViewShare,
0L,
PAGE_READWRITE
);
if ( !NT_SUCCESS(Status) ) {
KdPrint(("INIT: Map In User Portion Failed %x\n",Status));
KeBugCheckEx(PHASE1_INITIALIZATION_FAILED,Status,5,0,0);
}
RtlMoveMemory(
ViewBase,
InitNlsTableBase,
InitNlsTableSize
);
InitNlsTableBase = ViewBase;
//
// Initialize the cache manager.
//
if (!CcInitializeCacheManager())
KeBugCheck(CACHE_INITIALIZATION_FAILED);
//
// Config management (particularly the registry) gets inited in
// two parts. Part 1 makes \REGISTRY\MACHINE\SYSTEM and
// \REGISTRY\MACHINE\HARDWARE available. These are needed to
// complete IO init.
//
if (!CmInitSystem1(LoaderBlock))
KeBugCheck(CONFIG_INITIALIZATION_FAILED);
//
// Compute timezone bias and next cutover date
//
BootTimeZoneBias = ExpLastTimeZoneBias;
ExRefreshTimeZoneInformation(&CmosTime);
if ( ResetActiveTimeBias ) {
ExLocalTimeToSystemTime(&CmosTime,&UniversalTime);
KeBootTime = UniversalTime;
KeSetSystemTime(&UniversalTime, &OldTime, NULL);
}
else {
//
// check to see if a timezone switch occured prior to boot...
//
if ( BootTimeZoneBias != ExpLastTimeZoneBias ) {
ZwSetSystemTime(NULL,NULL);
}
}
if (!FsRtlInitSystem())
KeBugCheck(FILE_INITIALIZATION_FAILED);
HalReportResourceUsage();
//#ifdef _PNP_POWER_
//
// Perform phase1 initialization of the Plug and Play manager. This
// must be done before the I/O system initializes.
//
if (!PpInitSystem()) {
KeBugCheck(PP1_INITIALIZATION_FAILED);
}
//#endif // _PNP_POWER_
//
// LPC needs to be initialized before the I/O system, since
// some drivers may create system threads that will terminate
// and cause LPC to be called.
//
if (!LpcInitSystem())
KeBugCheck(LPC_INITIALIZATION_FAILED);
//
// Now that the system time is running, initialize more of the
// Executive
//
ExInitSystemPhase2();
if (!IoInitSystem(LoaderBlock))
KeBugCheck(IO1_INITIALIZATION_FAILED);
#if i386
//
// Initialize Vdm specific stuff
//
// Note: If this fails, vdms may not be able to run, but it doesn't
// seem neceesary to bugcheck the system because of this.
//
KeI386VdmInitialize();
#endif
#ifdef _PNP_POWER_
if (!PoInitSystem(1)) {
KeBugCheck(IO1_INITIALIZATION_FAILED);
}
#endif // _PNP_POWER_
//
// Okay to call PsInitSystem now that \SystemRoot is defined so it can
// locate NTDLL.DLL and SMSS.EXE
//
if (PsInitSystem(1, (PLOADER_PARAMETER_BLOCK)Context) == FALSE)
KeBugCheck(PROCESS1_INITIALIZATION_FAILED);
//
// Force KeBugCheck to look at PsLoadedModuleList now that it is
// setup.
//
if (LoaderBlock == KeLoaderBlock) {
KeLoaderBlock = NULL;
}
//
// Free loader block.
//
MmFreeLoaderBlock (LoaderBlock);
LoaderBlock = NULL;
Context = NULL;
//
// Perform Phase 1 Reference Monitor Initialization. This includes
// creating the Reference Monitor Command Server Thread, a permanent
// thread of the System Init process. That thread will create an LPC
// port called the Reference Monitor Command Port through which
// commands sent by the Local Security Authority Subsystem will be
// received. These commands (e.g. Enable Auditing) change the Reference
// Monitor State.
//
if (!SeRmInitPhase1()) {
KeBugCheck(REFMON_INITIALIZATION_FAILED);
}
//
// Set up process parameters for the Session Manager Subsystem
//
Size = sizeof( *ProcessParameters ) +
((DOS_MAX_PATH_LENGTH * 4) * sizeof( WCHAR ));
ProcessParameters = NULL;
Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
(PVOID *)&ProcessParameters,
0,
&Size,
MEM_COMMIT,
PAGE_READWRITE
);
if (!NT_SUCCESS( Status )) {
#if DBG
sprintf(DebugBuffer,
"INIT: Unable to allocate Process Parameters. 0x%lx\n",
Status);
RtlInitAnsiString(&AnsiDebugString, DebugBuffer);
if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeDebugString,
&AnsiDebugString,
TRUE)) == FALSE) {
KeBugCheck(SESSION1_INITIALIZATION_FAILED);
}
ZwDisplayString(&UnicodeDebugString);
#endif // DBG
KeBugCheckEx(SESSION1_INITIALIZATION_FAILED,Status,0,0,0);
}
ProcessParameters->Length = Size;
ProcessParameters->MaximumLength = Size;
//
// Reserve the low 1 MB of address space in the session manager.
// Setup gets started using a replacement for the session manager
// and that process needs to be able to use the vga driver on x86,
// which uses int10 and thus requires the low 1 meg to be reserved
// in the process. The cost is so low that we just do this all the
// time, even when setup isn't running.
//
ProcessParameters->Flags = RTL_USER_PROC_PARAMS_NORMALIZED | RTL_USER_PROC_RESERVE_1MB;
Size = PAGE_SIZE;
Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
(PVOID *)&ProcessParameters->Environment,
0,
&Size,
MEM_COMMIT,
PAGE_READWRITE
);
if (!NT_SUCCESS( Status )) {
#if DBG
sprintf(DebugBuffer,
"INIT: Unable to allocate Process Environment 0x%lx\n",
Status);
RtlInitAnsiString(&AnsiDebugString, DebugBuffer);
if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeDebugString,
&AnsiDebugString,
TRUE)) == FALSE) {
KeBugCheck(SESSION2_INITIALIZATION_FAILED);
}
ZwDisplayString(&UnicodeDebugString);
#endif // DBG
KeBugCheckEx(SESSION2_INITIALIZATION_FAILED,Status,0,0,0);
}
Dst = (PWSTR)(ProcessParameters + 1);
ProcessParameters->CurrentDirectory.DosPath.Buffer = Dst;
ProcessParameters->CurrentDirectory.DosPath.MaximumLength = DOS_MAX_PATH_LENGTH * sizeof( WCHAR );
RtlCopyUnicodeString( &ProcessParameters->CurrentDirectory.DosPath,
&NtSystemRoot
);
Dst = (PWSTR)((PCHAR)ProcessParameters->CurrentDirectory.DosPath.Buffer +
ProcessParameters->CurrentDirectory.DosPath.MaximumLength
);
ProcessParameters->DllPath.Buffer = Dst;
ProcessParameters->DllPath.MaximumLength = DOS_MAX_PATH_LENGTH * sizeof( WCHAR );
RtlCopyUnicodeString( &ProcessParameters->DllPath,
&ProcessParameters->CurrentDirectory.DosPath
);
RtlAppendUnicodeToString( &ProcessParameters->DllPath, L"\\System32" );
Dst = (PWSTR)((PCHAR)ProcessParameters->DllPath.Buffer +
ProcessParameters->DllPath.MaximumLength
);
ProcessParameters->ImagePathName.Buffer = Dst;
ProcessParameters->ImagePathName.MaximumLength = DOS_MAX_PATH_LENGTH * sizeof( WCHAR );
RtlAppendUnicodeToString( &ProcessParameters->ImagePathName,
L"\\SystemRoot\\System32"
);
RtlAppendUnicodeToString( &ProcessParameters->ImagePathName,
L"\\smss.exe"
);
NullString.Buffer = L"";
NullString.Length = sizeof(WCHAR);
NullString.MaximumLength = sizeof(WCHAR);
EnvString.Buffer = ProcessParameters->Environment;
EnvString.Length = 0;
EnvString.MaximumLength = (USHORT)Size;
RtlAppendUnicodeToString( &EnvString, L"Path=" );
RtlAppendUnicodeStringToString( &EnvString, &ProcessParameters->DllPath );
RtlAppendUnicodeStringToString( &EnvString, &NullString );
UnicodeSystemDriveString = NtSystemRoot;
UnicodeSystemDriveString.Length = 2 * sizeof( WCHAR );
RtlAppendUnicodeToString( &EnvString, L"SystemDrive=" );
RtlAppendUnicodeStringToString( &EnvString, &UnicodeSystemDriveString );
RtlAppendUnicodeStringToString( &EnvString, &NullString );
RtlAppendUnicodeToString( &EnvString, L"SystemRoot=" );
RtlAppendUnicodeStringToString( &EnvString, &NtSystemRoot );
RtlAppendUnicodeStringToString( &EnvString, &NullString );
#if 0
KdPrint(( "ProcessParameters at %lx\n", ProcessParameters ));
KdPrint(( " CurDir: %wZ\n", &ProcessParameters->CurrentDirectory.DosPath ));
KdPrint(( " DllPath: %wZ\n", &ProcessParameters->DllPath ));
KdPrint(( " ImageFile: %wZ\n", &ProcessParameters->ImagePathName ));
KdPrint(( " Environ: %lx\n", ProcessParameters->Environment ));
Src = ProcessParameters->Environment;
while (*Src) {
KdPrint(( " %ws\n", Src ));
while (*Src++) ;
}
}
#endif
ProcessParameters->CommandLine = ProcessParameters->ImagePathName;
SessionManager = ProcessParameters->ImagePathName;
Status = RtlCreateUserProcess(
&SessionManager,
OBJ_CASE_INSENSITIVE,
RtlDeNormalizeProcessParams( ProcessParameters ),
NULL,
NULL,
NULL,
FALSE,
NULL,
NULL,
&ProcessInformation
);
if ( !NT_SUCCESS(Status) ) {
#if DBG
sprintf(DebugBuffer,
"INIT: Unable to create Session Manager. 0x%lx\n",
Status);
RtlInitAnsiString(&AnsiDebugString, DebugBuffer);
if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeDebugString,
&AnsiDebugString,
TRUE)) == FALSE) {
KeBugCheck(SESSION3_INITIALIZATION_FAILED);
}
ZwDisplayString(&UnicodeDebugString);
#endif // DBG
KeBugCheckEx(SESSION3_INITIALIZATION_FAILED,Status,0,0,0);
}
Status = ZwResumeThread(ProcessInformation.Thread,NULL);
if ( !NT_SUCCESS(Status) ) {
#if DBG
sprintf(DebugBuffer,
"INIT: Unable to resume Session Manager. 0x%lx\n",
Status);
RtlInitAnsiString(&AnsiDebugString, DebugBuffer);
if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeDebugString,
&AnsiDebugString,
TRUE)) == FALSE) {
KeBugCheck(SESSION4_INITIALIZATION_FAILED);
}
ZwDisplayString(&UnicodeDebugString);
#endif // DBG
KeBugCheckEx(SESSION4_INITIALIZATION_FAILED,Status,0,0,0);
}
//
// Wait five seconds for the session manager to get started or
// terminate. If the wait times out, then the session manager
// is assumed to be healthy and the zero page thread is called.
//
OldTime.QuadPart = Int32x32To64(5, -(10 * 1000 * 1000));
Status = ZwWaitForSingleObject(
ProcessInformation.Process,
FALSE,
&OldTime
);
if (Status == STATUS_SUCCESS) {
#if DBG
sprintf(DebugBuffer, "INIT: Session Manager terminated.\n");
RtlInitAnsiString(&AnsiDebugString, DebugBuffer);
RtlAnsiStringToUnicodeString(&UnicodeDebugString,
&AnsiDebugString,
TRUE);
ZwDisplayString(&UnicodeDebugString);
#endif // DBG
KeBugCheck(SESSION5_INITIALIZATION_FAILED);
} else {
//
// Dont need these handles anymore.
//
ZwClose( ProcessInformation.Thread );
ZwClose( ProcessInformation.Process );
//
// Free up memory used to pass arguments to session manager.
//
Size = 0;
Address = ProcessParameters->Environment;
ZwFreeVirtualMemory( NtCurrentProcess(),
(PVOID *)&Address,
&Size,
MEM_RELEASE
);
Size = 0;
Address = ProcessParameters;
ZwFreeVirtualMemory( NtCurrentProcess(),
(PVOID *)&Address,
&Size,
MEM_RELEASE
);
InitializationPhase += 1;
MmZeroPageThread();
}
}
NTSTATUS
CreateSystemRootLink(
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
{
HANDLE handle;
UNICODE_STRING nameString;
OBJECT_ATTRIBUTES objectAttributes;
STRING linkString;
UNICODE_STRING linkUnicodeString;
NTSTATUS status;
UCHAR deviceNameBuffer[256];
STRING deviceNameString;
UNICODE_STRING deviceNameUnicodeString;
HANDLE linkHandle;
#if DBG
UCHAR debugBuffer[256];
STRING debugString;
UNICODE_STRING debugUnicodeString;
#endif
//
// Create the root directory object for the \ArcName directory.
//
RtlInitUnicodeString( &nameString, L"\\ArcName" );
InitializeObjectAttributes( &objectAttributes,
&nameString,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
NULL,
SePublicDefaultSd );
status = NtCreateDirectoryObject( &handle,
DIRECTORY_ALL_ACCESS,
&objectAttributes );
if (!NT_SUCCESS( status )) {
KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED,status,1,0,0);
return status;
} else {
(VOID) NtClose( handle );
}
//
// Create the root directory object for the \Device directory.
//
RtlInitUnicodeString( &nameString, L"\\Device" );
InitializeObjectAttributes( &objectAttributes,
&nameString,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
NULL,
SePublicDefaultSd );
status = NtCreateDirectoryObject( &handle,
DIRECTORY_ALL_ACCESS,
&objectAttributes );
if (!NT_SUCCESS( status )) {
KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED,status,2,0,0);
return status;
} else {
(VOID) NtClose( handle );
}
//
// Create the symbolic link to the root of the system directory.
//
RtlInitAnsiString( &linkString, INIT_SYSTEMROOT_LINKNAME );
status = RtlAnsiStringToUnicodeString( &linkUnicodeString,
&linkString,
TRUE);
if (!NT_SUCCESS( status )) {
KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED,status,3,0,0);
return status;
}
InitializeObjectAttributes( &objectAttributes,
&linkUnicodeString,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
NULL,
SePublicDefaultSd );
//
// Use ARC device name and system path from loader.
//
sprintf( deviceNameBuffer,
"\\ArcName\\%s%s",
LoaderBlock->ArcBootDeviceName,
LoaderBlock->NtBootPathName);
deviceNameBuffer[strlen(deviceNameBuffer)-1] = '\0';
RtlInitString( &deviceNameString, deviceNameBuffer );
status = RtlAnsiStringToUnicodeString( &deviceNameUnicodeString,
&deviceNameString,
TRUE );
if (!NT_SUCCESS(status)) {
RtlFreeUnicodeString( &linkUnicodeString );
KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED,status,4,0,0);
return status;
}
status = NtCreateSymbolicLinkObject( &linkHandle,
SYMBOLIC_LINK_ALL_ACCESS,
&objectAttributes,
&deviceNameUnicodeString );
RtlFreeUnicodeString( &linkUnicodeString );
RtlFreeUnicodeString( &deviceNameUnicodeString );
if (!NT_SUCCESS(status)) {
KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED,status,5,0,0);
return status;
}
#if DBG
sprintf( debugBuffer, "INIT: %s => %s\n",
INIT_SYSTEMROOT_LINKNAME,
deviceNameBuffer );
RtlInitAnsiString( &debugString, debugBuffer );
status = RtlAnsiStringToUnicodeString( &debugUnicodeString,
&debugString,
TRUE );
if (NT_SUCCESS(status)) {
ZwDisplayString( &debugUnicodeString );
RtlFreeUnicodeString( &debugUnicodeString );
}
#endif // DBG
NtClose( linkHandle );
return STATUS_SUCCESS;
}
#if 0
PVOID
LookupImageBaseByName (
IN PLIST_ENTRY ListHead,
IN PSZ Name
)
/*++
Lookups BaseAddress of ImageName - returned value can be used
to find entry points via LookupEntryPoint
--*/
{
PLDR_DATA_TABLE_ENTRY Entry;
PLIST_ENTRY Next;
PVOID Base;
ANSI_STRING ansiString;
UNICODE_STRING unicodeString;
NTSTATUS status;
Next = ListHead->Flink;
if (!Next) {
return NULL;
}
RtlInitAnsiString(&ansiString, Name);
status = RtlAnsiStringToUnicodeString( &unicodeString, &ansiString, TRUE );
if (!NT_SUCCESS (status)) {
return NULL;
}
Base = NULL;
while (Next != ListHead) {
Entry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
Next = Next->Flink;
if (RtlEqualUnicodeString (&unicodeString, &Entry->BaseDllName, TRUE)) {
Base = Entry->DllBase;
break;
}
}
RtlFreeUnicodeString( &unicodeString );
return Base;
}
#endif
NTSTATUS
LookupEntryPoint (
IN PVOID DllBase,
IN PSZ NameOfEntryPoint,
OUT PVOID *AddressOfEntryPoint
)
/*++
Routine Description:
Returns the address of an entry point given the DllBase and PSZ
name of the entry point in question
--*/
{
PIMAGE_EXPORT_DIRECTORY ExportDirectory;
ULONG ExportSize;
USHORT Ordinal;
PULONG Addr;
CHAR NameBuffer[64];
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)
RtlImageDirectoryEntryToData(
DllBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&ExportSize);
#if DBG
if (!ExportDirectory) {
DbgPrint("LookupENtryPoint: Can't locate system Export Directory\n");
}
#endif
if ( strlen(NameOfEntryPoint) > sizeof(NameBuffer)-2 ) {
return STATUS_INVALID_PARAMETER;
}
strcpy(NameBuffer,NameOfEntryPoint);
Ordinal = NameToOrdinal(
NameBuffer,
(ULONG)DllBase,
ExportDirectory->NumberOfNames,
(PULONG)((ULONG)DllBase + (ULONG)ExportDirectory->AddressOfNames),
(PUSHORT)((ULONG)DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals)
);
//
// If Ordinal is not within the Export Address Table,
// then DLL does not implement function.
//
if ( (ULONG)Ordinal >= ExportDirectory->NumberOfFunctions ) {
return STATUS_PROCEDURE_NOT_FOUND;
}
Addr = (PULONG)((ULONG)DllBase + (ULONG)ExportDirectory->AddressOfFunctions);
*AddressOfEntryPoint = (PVOID)((ULONG)DllBase + Addr[Ordinal]);
return STATUS_SUCCESS;
}
static USHORT
NameToOrdinal (
IN PSZ NameOfEntryPoint,
IN ULONG DllBase,
IN ULONG NumberOfNames,
IN PULONG NameTableBase,
IN PUSHORT NameOrdinalTableBase
)
{
ULONG SplitIndex;
LONG CompareResult;
SplitIndex = NumberOfNames >> 1;
CompareResult = strcmp(NameOfEntryPoint, (PSZ)(DllBase + NameTableBase[SplitIndex]));
if ( CompareResult == 0 ) {
return NameOrdinalTableBase[SplitIndex];
}
if ( NumberOfNames == 1 ) {
return (USHORT)-1;
}
if ( CompareResult < 0 ) {
NumberOfNames = SplitIndex;
} else {
NameTableBase = &NameTableBase[SplitIndex+1];
NameOrdinalTableBase = &NameOrdinalTableBase[SplitIndex+1];
NumberOfNames = NumberOfNames - SplitIndex - 1;
}
return NameToOrdinal(NameOfEntryPoint,DllBase,NumberOfNames,NameTableBase,NameOrdinalTableBase);
}