windows-nt/Source/XPSP1/NT/base/ntos/init/init.c
2020-09-26 16:20:57 +08:00

3114 lines
88 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1989-1998 Microsoft Corporation
Module Name:
init.c
Abstract:
Main source file of 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 <kddll.h>
#include <setupblk.h>
#include <fsrtl.h>
#include <ntverp.h>
#include "stdlib.h"
#include "stdio.h"
#include <string.h>
#include <safeboot.h>
#include <inbv.h>
#include <hdlsblk.h>
#include <hdlsterm.h>
#include "anim.h"
#include "xip.h"
UNICODE_STRING NtSystemRoot;
PVOID ExPageLockHandle;
VOID
ExpInitializeExecutive(
IN ULONG Number,
IN PLOADER_PARAMETER_BLOCK LoaderBlock
);
NTKERNELAPI
BOOLEAN
ExpRefreshTimeZoneInformation(
IN PLARGE_INTEGER CurrentUniversalTime
);
NTSTATUS
CreateSystemRootLink(
IN PLOADER_PARAMETER_BLOCK LoaderBlock
);
static USHORT
NameToOrdinal (
IN PSZ NameOfEntryPoint,
IN ULONG_PTR DllBase,
IN ULONG NumberOfNames,
IN PULONG NameTableBase,
IN PUSHORT NameOrdinalTableBase
);
NTSTATUS
LookupEntryPoint (
IN PVOID DllBase,
IN PSZ NameOfEntryPoint,
OUT PVOID *AddressOfEntryPoint
);
#if defined(_X86_)
VOID
KiLogMcaErrors (
VOID
);
#endif
PFN_COUNT
ExBurnMemory(
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
IN PFN_COUNT NumberOfPagesToBurn,
IN TYPE_OF_MEMORY MemoryTypeForRemovedPages,
IN PMEMORY_ALLOCATION_DESCRIPTOR NewMemoryDescriptor OPTIONAL
);
VOID
DisplayFilter(
PUCHAR *String
);
#ifdef ALLOC_PRAGMA
//
// The INIT section is not pageable during initialization, so these
// functions can be in INIT rather than in .text.
//
#pragma alloc_text(INIT,ExBurnMemory)
#pragma alloc_text(INIT,ExpInitializeExecutive)
#pragma alloc_text(INIT,Phase1Initialization)
#pragma alloc_text(INIT,CreateSystemRootLink)
#pragma alloc_text(INIT,LookupEntryPoint)
#pragma alloc_text(INIT,NameToOrdinal)
#endif
//
// Define global static data used during initialization.
//
ULONG NtGlobalFlag;
extern PMESSAGE_RESOURCE_BLOCK KiBugCheckMessages;
extern UCHAR CmProcessorMismatch;
ULONG NtMajorVersion;
ULONG NtMinorVersion;
#if DBG
ULONG NtBuildNumber = VER_PRODUCTBUILD | 0xC0000000;
#else
ULONG NtBuildNumber = VER_PRODUCTBUILD | 0xF0000000;
#endif
#if defined(__BUILDMACHINE__)
#if defined(__BUILDDATE__)
#define B2(w,x,y) "" #w "." #x "." #y
#define B1(w,x,y) B2(w, x, y)
#define BUILD_MACHINE_TAG B1(VER_PRODUCTBUILD, __BUILDMACHINE__, __BUILDDATE__)
#else
#define B2(w,x) "" #w "." #x
#define B1(w,x) B2(w,x)
#define BUILD_MACHINE_TAG B1(VER_PRODUCTBUILD, __BUILDMACHINE__)
#endif
#else
#define BUILD_MACHINE_TAG ""
#endif
const CHAR NtBuildLab[] = BUILD_MACHINE_TAG;
ULONG InitializationPhase;
extern BOOLEAN ShowProgressBar;
extern KiServiceLimit;
extern PMESSAGE_RESOURCE_DATA KiBugCodeMessages;
extern ULONG KdpTimeSlipPending;
extern BOOLEAN KdBreakAfterSymbolLoad;
extern CM_SYSTEM_CONTROL_VECTOR CmControlVector[];
ULONG CmNtCSDVersion;
ULONG CmNtCSDReleaseType;
#define SP_RELEASE_TYPE_NONE 0 // No SP string appendage
#define SP_RELEASE_TYPE_INTERNAL 1 // Uses VER_PRODUCTBUILD_QFE in ntverp.h for build value
#define SP_RELEASE_TYPE_RC 2 // Uses VER_PRODUCTRCVERSION in ntverp.h for RC x.x value
#define SP_RELEASE_TYPE_BETA 3 // Uses VER_PRODUCTBETAVERSION in ntverp.h for B' x.x value
ULONG CmBrand;
UNICODE_STRING CmVersionString;
UNICODE_STRING CmCSDVersionString;
ULONG InitSafeBootMode;
BOOLEAN InitIsWinPEMode = FALSE;
ULONG InitWinPEModeType = INIT_WINPEMODE_NONE;
WCHAR NtInitialUserProcessBuffer[128] = L"\\SystemRoot\\System32\\smss.exe";
ULONG NtInitialUserProcessBufferLength =
sizeof(NtInitialUserProcessBuffer) - sizeof(WCHAR);
ULONG NtInitialUserProcessBufferType = REG_SZ;
#if defined(_X86_)
extern ULONG KeNumprocSpecified;
#endif
typedef struct _EXLOCK {
KSPIN_LOCK SpinLock;
KIRQL Irql;
} EXLOCK, *PEXLOCK;
#ifdef ALLOC_PRAGMA
NTSTATUS
ExpInitializeLockRoutine(
PEXLOCK Lock
);
#pragma alloc_text(INIT,ExpInitializeLockRoutine)
#endif
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;
}
#if 0
NTSTATUS
ExpDeleteLockRoutine(
PEXLOCK Lock
)
{
return STATUS_SUCCESS;
}
#endif //0
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("INITDATA")
#endif
ULONG CmNtGlobalFlag = 0;
NLSTABLEINFO InitTableInfo;
ULONG InitNlsTableSize;
PVOID InitNlsTableBase;
PFN_COUNT BBTPagesToReserve;
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("PAGEDATA")
#endif
PVOID InitNlsSectionPointer = NULL;
ULONG InitAnsiCodePageDataOffset = 0;
ULONG InitOemCodePageDataOffset = 0;
ULONG InitUnicodeCaseTableDataOffset = 0;
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg()
#endif
PVOID BBTBuffer;
MEMORY_ALLOCATION_DESCRIPTOR BBTMemoryDescriptor;
#define COLOR_BLACK 0
#define COLOR_BLUE 2
#define COLOR_DARKGRAY 4
#define COLOR_GRAY 9
#define COLOR_WHITE 15
extern BOOLEAN InbvBootDriverInstalled;
VOID
DisplayBootBitmap (
IN BOOLEAN DisplayOnScreen
)
/*++
Routine Description:
Draws the gui boot screen.
Arguments:
DisplayOnScreen - TRUE to dump text to the screen, FALSE otherwise.
Return Value:
None.
Environment:
This routine may be called more than once, and should not be marked INIT.
--*/
{
LARGE_INTEGER DueTime;
static BOOLEAN FirstCall = TRUE;
ROT_BAR_TYPE TempRotBarSelection = RB_UNSPECIFIED;
if (FirstCall == FALSE) {
//
// Disable current animation
//
InbvAcquireLock();
RotBarSelection = RB_UNSPECIFIED;
InbvReleaseLock();
}
ShowProgressBar = FALSE;
if (DisplayOnScreen) {
PUCHAR BitmapTop, BitmapBottom;
if (SharedUserData->NtProductType == NtProductWinNt) {
InbvSetTextColor(COLOR_WHITE);
InbvSolidColorFill(0, 0, 639, 479, 7); // background
InbvSolidColorFill(0, 421, 639, 479, 1); // bottom
BitmapTop = InbvGetResourceAddress(6);
BitmapBottom = InbvGetResourceAddress(7);
} else { // srv
InbvSetTextColor(14);
InbvSolidColorFill(0, 0, 639, 479, 6); // background
InbvSolidColorFill(0, 421, 639, 479, 1); // bottom
BitmapTop = InbvGetResourceAddress(14);
BitmapBottom = InbvGetResourceAddress(15);
}
TempRotBarSelection = RB_UNSPECIFIED;
InbvSetScrollRegion(32, 80, 631, 400);
if (BitmapTop && BitmapBottom) {
InbvBitBlt(BitmapBottom, 0, 419);
InbvBitBlt(BitmapTop, 0, 0);
}
} else {
PUCHAR BarBitmap = NULL;
PUCHAR TextBitmap = NULL;
PUCHAR Bitmap = NULL;
InbvInstallDisplayStringFilter(DisplayFilter);
if (!InbvBootDriverInstalled) {
return;
}
Bitmap = InbvGetResourceAddress(1); // workstation bitmap
if (ExVerifySuite(EmbeddedNT)) { // embd and pro have the same bar, but different text
TextBitmap = InbvGetResourceAddress(12); // embedded edition title text
BarBitmap = InbvGetResourceAddress(8); // pro and embedded editions progress bar
}
else if (SharedUserData->NtProductType == NtProductWinNt) { // home or pro
if (ExVerifySuite(Personal)) { // home
BarBitmap = InbvGetResourceAddress(9); // home edition progress bar
TextBitmap = InbvGetResourceAddress(11); // home edition title text
}
else { // pro
BarBitmap = InbvGetResourceAddress(8); // pro and embedded editions progress bar
switch (CmBrand) {
case 1: // TabletPc
TextBitmap = InbvGetResourceAddress(17);
break;
case 2: // eHome Freestyle
TextBitmap = InbvGetResourceAddress(18);
break;
default: // Professional title text
TextBitmap = InbvGetResourceAddress(10);
}
}
}
else { // srv
BarBitmap = InbvGetResourceAddress(4); // srv edition progress bar
TextBitmap = InbvGetResourceAddress(13); // srv edition title text
}
if (Bitmap) {
TempRotBarSelection = RB_SQUARE_CELLS;
}
//
// Set positions for scrolling bar.
//
if (Bitmap) {
InbvBitBlt(Bitmap, 0, 0);
//if (SharedUserData->NtProductType == NtProductServer) {
if (SharedUserData->NtProductType != NtProductWinNt) {
// make some fixes for server bitmap: remove "XP"
UCHAR sav_copyright[64];
InbvScreenToBufferBlt(sav_copyright, 413, 237, 7, 7, 8);
InbvSolidColorFill(418,230,454,256,0);
InbvBufferToScreenBlt(sav_copyright, 413, 237, 7, 7, 8);
// HACK: in case of "text mode setup" (ExpInTextModeSetup == TRUE)
// we can't determine the SKU so we displaying neutral butmap
// without specific SKU title (e.g. just Windows) and server's progress bar
{
extern BOOLEAN ExpInTextModeSetup; // defined at base\ntos\ex\exinit.c
if (ExpInTextModeSetup) {
TextBitmap = NULL;
}
else {
PUCHAR DotBitmap = InbvGetResourceAddress(16); // srv edition progress bar
InbvBitBlt(DotBitmap, 423, 233);
}
}
}
}
if (TextBitmap) {
InbvBitBlt(TextBitmap, 220, 272);
}
if (BarBitmap) {
InbvBitBlt(BarBitmap, 0, 0);
}
}
InbvAcquireLock();
RotBarSelection = TempRotBarSelection;
InbvRotBarInit();
InbvReleaseLock();
if (FirstCall) {
//
// If we got here, we are showing the boot bitmap.
// Start a timer to support animation.
//
HANDLE ThreadHandle;
PsCreateSystemThread(&ThreadHandle,
0L,
NULL,
NULL,
NULL,
InbvRotateGuiBootDisplay,
NULL);
}
FirstCall = FALSE;
}
VOID
DisplayFilter(
IN OUT PUCHAR *String
)
/*++
Routine Description:
This routine monitors InbvDisplayString output. If it sees something
which needs to be displayed on the screen, it triggers the output screen.
Arguments:
String - Pointer to a string pointer.
Returns:
None.
Notes:
This routine will be called anytime a string is displayed via the
Inbv routines. It cannot be paged!
--*/
{
static const UCHAR EmptyString = 0;
static BOOLEAN NonDotHit = FALSE;
if ((NonDotHit == FALSE) && (strcmp(*String, ".") == 0)) {
*String = (PUCHAR)&EmptyString;
} else {
NonDotHit = TRUE;
InbvInstallDisplayStringFilter((INBV_DISPLAY_STRING_FILTER)NULL);
DisplayBootBitmap(TRUE);
}
}
PFN_COUNT
ExBurnMemory (
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
IN PFN_COUNT NumberOfPagesToBurn,
IN TYPE_OF_MEMORY MemoryTypeForRemovedPages,
IN PMEMORY_ALLOCATION_DESCRIPTOR NewMemoryDescriptor OPTIONAL
)
/*++
Routine Description:
This routine removes memory from the system loader block thus simulating
a machine with less physical memory without having to physically remove it.
Arguments:
LoaderBlock - Supplies a pointer to the loader parameter block.
NumberOfPagesToBurn - Supplies the number of pages to burn.
MemoryTypeForRemovedPages - Supplies the type to mark into the loader block
for the burned pages.
NewMemoryDescriptor - If non-NULL, this supplies a pointer to a memory
block to be used if a split is needed.
Return Value:
Number of pages actually burned.
Environment:
Kernel mode.
--*/
{
PLIST_ENTRY ListHead;
PLIST_ENTRY NextEntry;
PFN_COUNT PagesRemaining;
PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
PagesRemaining = NumberOfPagesToBurn;
//
// Look backwards through physical memory to leave it like
// it otherwise would be. ie: that's the way most people add memory
// modules to their systems.
//
ListHead = &LoaderBlock->MemoryDescriptorListHead;
NextEntry = ListHead->Blink;
do {
MemoryDescriptor = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if ((MemoryDescriptor->MemoryType == LoaderFree ||
MemoryDescriptor->MemoryType == LoaderFirmwareTemporary) &&
MemoryDescriptor->PageCount != 0) {
if (MemoryDescriptor->PageCount > PagesRemaining) {
//
// This block has enough pages.
// Split it into two and mark it as requested.
//
MemoryDescriptor->PageCount = MemoryDescriptor->PageCount -
PagesRemaining;
if (ARGUMENT_PRESENT (NewMemoryDescriptor)) {
NewMemoryDescriptor->BasePage = MemoryDescriptor->BasePage +
MemoryDescriptor->PageCount;
NewMemoryDescriptor->PageCount = PagesRemaining;
NewMemoryDescriptor->MemoryType = MemoryTypeForRemovedPages;
InsertTailList (MemoryDescriptor->ListEntry.Blink,
&NewMemoryDescriptor->ListEntry);
}
PagesRemaining = 0;
break;
}
PagesRemaining -= MemoryDescriptor->PageCount;
MemoryDescriptor->MemoryType = MemoryTypeForRemovedPages;
}
NextEntry = NextEntry->Blink;
} while (NextEntry != ListHead);
return NumberOfPagesToBurn - PagesRemaining;
}
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 initialization is performed in the context of
the kernel start up routine with interrupts disabled. During Phase 1
initialization, the system is fully operational and subcomponents may
do any initialization that is necessary.
Arguments:
Number - Supplies the processor number currently initializing.
LoaderBlock - Supplies a pointer to a loader parameter block.
Return Value:
None.
--*/
{
PFN_COUNT PagesToBurn;
PCHAR Options;
PCHAR MemoryOption;
NTSTATUS Status;
PKLDR_DATA_TABLE_ENTRY DataTableEntry;
PMESSAGE_RESOURCE_ENTRY MessageEntry;
PLIST_ENTRY NextEntry;
ANSI_STRING AnsiString;
STRING NameString;
CHAR Buffer[ 256 ];
ULONG ImageCount;
ULONG i;
ULONG_PTR ResourceIdPath[3];
PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
PMESSAGE_RESOURCE_DATA MessageData;
CHAR VersionBuffer[ 64 ];
PCHAR s;
PCHAR sMajor;
PCHAR sMinor;
PIMAGE_NT_HEADERS NtHeaders;
PLIST_ENTRY NextMd;
PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
//
// Initialize PRCB pool lookaside pointers.
//
ExInitPoolLookasidePointers ();
if (Number == 0) {
//
// Determine whether this is textmode setup and whether this is a
// remote boot client.
//
ExpInTextModeSetup = FALSE;
IoRemoteBootClient = FALSE;
if (LoaderBlock->SetupLoaderBlock != NULL) {
if ((LoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_IS_TEXTMODE) != 0) {
ExpInTextModeSetup = TRUE;
}
if ((LoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_IS_REMOTE_BOOT) != 0) {
IoRemoteBootClient = TRUE;
ASSERT( _memicmp( LoaderBlock->ArcBootDeviceName, "net(0)", 6 ) == 0 );
}
}
#if defined(REMOTE_BOOT)
SharedUserData->SystemFlags = 0;
if (IoRemoteBootClient) {
SharedUserData->SystemFlags |= SYSTEM_FLAG_REMOTE_BOOT_CLIENT;
}
#endif // defined(REMOTE_BOOT)
//
// Indicate that we are in phase 0.
//
InitializationPhase = 0L;
Options = LoaderBlock->LoadOptions;
if (Options != NULL) {
//
// If in BBT mode, remove the requested amount of memory from the
// loader block and use it for BBT purposes instead.
//
_strupr(Options);
MemoryOption = strstr(Options, "PERFMEM");
if (MemoryOption != NULL) {
MemoryOption = strstr (MemoryOption,"=");
if (MemoryOption != NULL) {
PagesToBurn = (PFN_COUNT) atol (MemoryOption + 1);
//
// Convert MB to pages.
//
PagesToBurn *= ((1024 * 1024) / PAGE_SIZE);
if (PagesToBurn != 0) {
PERFINFO_INIT_TRACEFLAGS(Options, MemoryOption);
BBTPagesToReserve = ExBurnMemory (LoaderBlock,
PagesToBurn,
LoaderBBTMemory,
&BBTMemoryDescriptor);
}
}
}
//
// Burn memory - consume the amount of memory
// specified in the OS Load Options. This is used
// for testing reduced memory configurations.
//
MemoryOption = strstr(Options, "BURNMEMORY");
if (MemoryOption != NULL) {
MemoryOption = strstr(MemoryOption,"=");
if (MemoryOption != NULL ) {
PagesToBurn = (PFN_COUNT) atol (MemoryOption + 1);
//
// Convert MB to pages.
//
PagesToBurn *= ((1024 * 1024) / PAGE_SIZE);
if (PagesToBurn != 0) {
ExBurnMemory (LoaderBlock,
PagesToBurn,
LoaderBad,
NULL);
}
}
}
}
//
// Initialize the translation tables using the loader
// loaded tables.
//
InitNlsTableBase = LoaderBlock->NlsData->AnsiCodePageData;
InitAnsiCodePageDataOffset = 0;
InitOemCodePageDataOffset = (ULONG)((PUCHAR)LoaderBlock->NlsData->OemCodePageData - (PUCHAR)LoaderBlock->NlsData->AnsiCodePageData);
InitUnicodeCaseTableDataOffset = (ULONG)((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);
}
//
// Enable interrupts now that the HAL has initialized.
//
#if defined(_X86_)
_enable();
#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;
#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 KLDR_DATA_TABLE_ENTRY for
// ntoskrnl.exe is always the first in the loaded module list.
//
DataTableEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink,
KLDR_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;
}
}
#if !defined(NT_UP)
//
// Verify that the kernel and HAL images are suitable for MP systems.
//
// N.B. Loading of kernel and HAL symbols now occurs in kdinit.
//
ImageCount = 0;
NextEntry = LoaderBlock->LoadOrderListHead.Flink;
while ((NextEntry != &LoaderBlock->LoadOrderListHead) && (ImageCount < 2)) {
DataTableEntry = CONTAINING_RECORD(NextEntry,
KLDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
ImageCount += 1;
if ( !MmVerifyImageIsOkForMpUse(DataTableEntry->DllBase) ) {
KeBugCheckEx(UP_DRIVER_ON_MP_SYSTEM,
(ULONG_PTR)DataTableEntry->DllBase,
0,
0,
0);
}
NextEntry = NextEntry->Flink;
}
#endif // !defined(NT_UP)
//
// Get system control values out of the registry.
//
CmGetSystemControlValues(LoaderBlock->RegistryBase, &CmControlVector[0]);
CmNtGlobalFlag &= FLG_VALID_BITS; // Toss bogus bits.
if (((CmNtCSDVersion & 0xFFFF0000) == 0) &&
( CmNtCSDReleaseType )) {
switch ( CmNtCSDReleaseType ) {
case SP_RELEASE_TYPE_INTERNAL:
CmNtCSDVersion |= VER_PRODUCTBUILD_QFE << 16;
break;
#ifdef VER_PRODUCTBETAVERSION
case SP_RELEASE_TYPE_BETA:
CmNtCSDVersion |= VER_PRODUCTBETAVERSION << 16;
break;
#endif
#ifdef VER_PRODUCTRCVERSION
case SP_RELEASE_TYPE_RC:
CmNtCSDVersion |= VER_PRODUCTRCVERSION << 16;
break;
#endif
default:
break;
}
}
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);
}
//
// Get multinode configuration (if any).
//
KeNumaInitialize();
//
// Initialize memory management and the memory allocation pools.
//
MmInitSystem (0, LoaderBlock);
//
// Scan the loaded module list and load the driver image symbols.
//
ImageCount = 0;
NextEntry = LoaderBlock->LoadOrderListHead.Flink;
while (NextEntry != &LoaderBlock->LoadOrderListHead) {
if (ImageCount >= 2) {
ULONG Count;
WCHAR *Filename;
ULONG Length;
//
// Get the address of the data table entry for the next component.
//
DataTableEntry = CONTAINING_RECORD(NextEntry,
KLDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
//
// Load the symbols via the kernel debugger
// for the next component.
//
if (DataTableEntry->FullDllName.Buffer[0] == L'\\') {
//
// Correct fullname already available
//
Filename = DataTableEntry->FullDllName.Buffer;
Length = DataTableEntry->FullDllName.Length / sizeof(WCHAR);
Count = 0;
do {
Buffer[Count++] = (CHAR)*Filename++;
} while (Count < Length);
Buffer[Count] = 0;
} else {
//
// Assume drivers
//
sprintf (Buffer, "%ws\\System32\\Drivers\\%wZ",
&SharedUserData->NtSystemRoot[2],
&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_PTR)DataTableEntry->DllBase,0,0,0);
}
#endif // NT_UP
}
ImageCount += 1;
NextEntry = NextEntry->Flink;
}
//
// If break after symbol load is specified, then break into the
// debugger.
//
if (KdBreakAfterSymbolLoad != FALSE) {
DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
}
//
// Turn on the headless terminal now, if we are of a sufficiently
// new vintage of loader
//
if (LoaderBlock->Extension->Size >= sizeof (LOADER_PARAMETER_EXTENSION)) {
HeadlessInit(LoaderBlock);
}
//
// These fields are supported for legacy 3rd party 32-bit software
// only. New code should call NtQueryInformationSystem() to get them.
//
#if defined(_WIN64)
SharedUserData->Reserved1 = 0x7ffeffff; // 2gb HighestUserAddress
SharedUserData->Reserved3 = 0x80000000; // 2gb SystemRangeStart
#else
//
// Set the highest user address and the start of the system range in
// the shared memory block.
//
// N.B. This is not a constant value if the target system is an x86
// with 3gb of user virtual address space.
//
SharedUserData->Reserved1 = (ULONG)MM_HIGHEST_USER_ADDRESS;
SharedUserData->Reserved3 = (ULONG)MmSystemRangeStart;
#endif
//
// Snapshot the NLS tables into paged pool and then
// reset the translation tables.
//
// 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);
if (MemoryDescriptor->MemoryType == LoaderNlsData) {
InitNlsTableSize += MemoryDescriptor->PageCount*PAGE_SIZE;
}
NextMd = MemoryDescriptor->ListEntry.Flink;
}
InitNlsTableBase = ExAllocatePoolWithTag (NonPagedPool,
InitNlsTableSize,
' slN');
if (InitNlsTableBase == NULL) {
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 guarantees
// contiguous buffers and the base of all the tables is the ANSI
// code page data.
//
RtlCopyMemory (InitNlsTableBase,
LoaderBlock->NlsData->AnsiCodePageData,
InitNlsTableSize);
RtlInitNlsTables ((PVOID)((PUCHAR)InitNlsTableBase+InitAnsiCodePageDataOffset),
(PVOID)((PUCHAR)InitNlsTableBase+InitOemCodePageDataOffset),
(PVOID)((PUCHAR)InitNlsTableBase+InitUnicodeCaseTableDataOffset),
&InitTableInfo);
RtlResetRtlTranslations (&InitTableInfo);
//
// Determine System version information.
//
DataTableEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink,
KLDR_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 = (USHORT) sprintf( Buffer, VER_PRODUCTBETA_STR );
}
//
// High-order 16-bits of CSDVersion contain RC number or build number. If non-zero
// display it after the Service Pack number.
//
if (CmNtCSDVersion & 0xFFFF0000) {
switch ( CmNtCSDReleaseType ) {
case SP_RELEASE_TYPE_INTERNAL:
s = Buffer + strlen( Buffer );
if (s != Buffer) {
*s++ = ',';
*s++ = ' ';
}
s += sprintf( s,
"v.%u",
(CmNtCSDVersion & 0xFFFF0000) >> 16
);
*s++ = '\0';
break;
#ifdef VER_PRODUCTRCVERSION
case SP_RELEASE_TYPE_RC:
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';
break;
#endif
#ifdef VER_PRODUCTBETAVERSION
case SP_RELEASE_TYPE_BETA:
s = Buffer + strlen( Buffer );
if (s != Buffer) {
*s++ = ',';
*s++ = ' ';
}
RtlInitAnsiString( &AnsiString, "\xDF" );
s += sprintf( s,
"%Z %u",
&AnsiString,
(CmNtCSDVersion & 0xFF000000) >> 24
);
if (CmNtCSDVersion & 0x00FF0000) {
s += sprintf( s, ".%u", (CmNtCSDVersion & 0x00FF0000) >> 16 );
}
*s++ = '\0';
break;
#endif
default:
break;
}
}
RtlInitAnsiString( &AnsiString, Buffer );
RtlAnsiStringToUnicodeString( &CmCSDVersionString, &AnsiString, TRUE );
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 );
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 ));
}
}
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);
}
if (!PpInitSystem()) {
KeBugCheck(PP0_INITIALIZATION_FAILED);
}
//
// Initialize debug system.
//
DbgkInitialize ();
//
// 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(_AMD64_)
SharedUserData->ImageNumberLow = IMAGE_FILE_MACHINE_AMD64;
SharedUserData->ImageNumberHigh = IMAGE_FILE_MACHINE_AMD64;
#elif defined(_X86_)
SharedUserData->ImageNumberLow = IMAGE_FILE_MACHINE_I386;
SharedUserData->ImageNumberHigh = IMAGE_FILE_MACHINE_I386;
#elif defined(_IA64_)
SharedUserData->ImageNumberLow = IMAGE_FILE_MACHINE_IA64;
SharedUserData->ImageNumberHigh = IMAGE_FILE_MACHINE_IA64;
#else
#error "no target architecture"
#endif
}
else {
//
// Initialize the Hardware Architecture Layer (HAL).
//
if (HalInitSystem(InitializationPhase, LoaderBlock) == FALSE) {
KeBugCheck(HAL_INITIALIZATION_FAILED);
}
}
return;
}
VOID
xcpt4 (
VOID
);
VOID
Phase1Initialization(
IN PVOID Context
)
{
PCHAR s;
PLOADER_PARAMETER_BLOCK LoaderBlock;
PETHREAD Thread;
PKPRCB Prcb;
KPRIORITY Priority;
NTSTATUS Status;
UNICODE_STRING SessionManager;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID Address;
PFN_COUNT MemorySize;
SIZE_T 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];
CHAR BootLogBuffer[256]; // must be the same size as DebugBuffer
PWSTR Src, Dst;
BOOLEAN ResetActiveTimeBias;
HANDLE NlsSection;
LARGE_INTEGER SectionSize;
LARGE_INTEGER SectionOffset;
PVOID SectionBase;
PVOID ViewBase;
ULONG CacheViewSize;
SIZE_T CapturedViewSize;
ULONG SavedViewSize;
LONG BootTimeZoneBias;
PKLDR_DATA_TABLE_ENTRY DataTableEntry;
CHAR VersionBuffer[24];
PMESSAGE_RESOURCE_ENTRY MessageEntry;
#ifndef NT_UP
PMESSAGE_RESOURCE_ENTRY MessageEntry1;
#endif
PCHAR MPKernelString;
PCHAR Options;
PCHAR YearOverrideOption, SafeModeOption, BootLogOption;
LONG CurrentYear = 0;
PSTR SafeBoot;
BOOLEAN UseAlternateShell = FALSE;
#if defined(REMOTE_BOOT)
BOOLEAN NetBootRequiresFormat = FALSE;
BOOLEAN NetBootDisconnected = FALSE;
CHAR NetBootHalName[MAX_HAL_NAME_LENGTH + 1];
UNICODE_STRING TmpUnicodeString;
#endif // defined(REMOTE_BOOT)
BOOLEAN NOGUIBOOT;
PVOID Environment;
//
// Initialize the handle for the PAGELK section.
//
ExPageLockHandle = MmLockPagableCodeSection ((PVOID)MmShutdownSystem);
MmUnlockPagableImageSection(ExPageLockHandle);
//
// Set the phase number and raise the priority of current thread to
// a high priority so it will not be preempted during initialization.
//
ResetActiveTimeBias = FALSE;
InitializationPhase = 1;
Thread = PsGetCurrentThread();
Priority = KeSetPriorityThread( &Thread->Tcb,MAXIMUM_PRIORITY - 1 );
LoaderBlock = (PLOADER_PARAMETER_BLOCK)Context;
//
// Put Phase 1 initialization calls here.
//
if (HalInitSystem(InitializationPhase, LoaderBlock) == FALSE) {
KeBugCheck(HAL1_INITIALIZATION_FAILED);
}
//
// Allow the boot video driver to behave differently based on the
// OsLoadOptions.
//
Options = LoaderBlock->LoadOptions ? _strupr(LoaderBlock->LoadOptions) : NULL;
if (Options) {
NOGUIBOOT = (BOOLEAN)(strstr(Options, "NOGUIBOOT") != NULL);
} else {
NOGUIBOOT = FALSE;
}
InbvEnableBootDriver((BOOLEAN)!NOGUIBOOT);
//
// There is now enough functionality for the system Boot Video
// Driver to run.
//
if (InbvDriverInitialize(LoaderBlock, 18)) {
BOOLEAN SOS;
if (NOGUIBOOT) {
//
// If the user specified the noguiboot switch we don't want to
// use the bootvid driver, so release display ownership.
//
InbvNotifyDisplayOwnershipLost(NULL);
}
if (Options) {
SOS = (BOOLEAN)(strstr(Options, "SOS") != NULL);
} else {
SOS = FALSE;
}
if (NOGUIBOOT) {
InbvEnableDisplayString(FALSE);
} else {
InbvEnableDisplayString(SOS);
DisplayBootBitmap(SOS);
}
}
//
// Check whether we are booting into WinPE
//
if (Options) {
if (strstr(Options, "MININT") != NULL) {
InitIsWinPEMode = TRUE;
if (strstr(Options, "INRAM") != NULL) {
InitWinPEModeType |= INIT_WINPEMODE_INRAM;
} else {
InitWinPEModeType |= INIT_WINPEMODE_REGULAR;
}
}
}
//
// Now that the HAL is available and memory management has sized
// memory, display the initial system banner containing the version number.
// Under normal circumstances, this is the first message displayed
// to the user by the OS.
//
DataTableEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink,
KLDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
Status = RtlFindMessage (DataTableEntry->DllBase,
11,
0,
WINDOWS_NT_BANNER,
&MessageEntry);
s = DebugBuffer;
if (CmCSDVersionString.Length != 0) {
s += sprintf( s, ": %wZ", &CmCSDVersionString );
}
*s++ = '\0';
sprintf( VersionBuffer, "%u.%u", NtMajorVersion, NtMinorVersion );
sprintf (s,
NT_SUCCESS(Status) ? MessageEntry->Text :
"MICROSOFT (R) WINDOWS 2000 (TM)\n",
VersionBuffer,
NtBuildNumber & 0xFFFF,
DebugBuffer);
InbvDisplayString(s);
RtlCopyMemory (BootLogBuffer, DebugBuffer, sizeof(DebugBuffer));
//
// Initialize the Power subsystem.
//
if (!PoInitSystem(0)) {
KeBugCheck(INTERNAL_POWER_ERROR);
}
//
// The user may have put a /YEAR=2000 switch on
// the OSLOADOPTIONS line. This allows us to
// enforce a particular year on hardware that
// has a broken clock.
//
if (Options) {
YearOverrideOption = strstr(Options, "YEAR");
if (YearOverrideOption != NULL) {
YearOverrideOption = strstr(YearOverrideOption,"=");
}
if (YearOverrideOption != NULL) {
CurrentYear = atol(YearOverrideOption + 1);
}
}
//
// 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 (ExCmosClockIsSane
&& HalQueryRealTimeClock(&TimeFields)) {
//
// If appropriate, override the year.
//
if (YearOverrideOption) {
TimeFields.Year = (SHORT)CurrentYear;
}
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
);
SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.HighPart;
SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.LowPart;
SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.HighPart;
UniversalTime.QuadPart = CmosTime.QuadPart + ExpTimeZoneBias.QuadPart;
}
KeSetSystemTime(&UniversalTime, &OldTime, FALSE, NULL);
//
// Notify other components that the system time has been set
//
PoNotifySystemTimeSet();
KeBootTime = UniversalTime;
KeBootTimeBias = 0;
}
MPKernelString = "";
#ifndef NT_UP
//
// Enforce processor licensing.
//
if (KeLicensedProcessors) {
if (KeRegisteredProcessors > KeLicensedProcessors) {
KeRegisteredProcessors = KeLicensedProcessors;
}
}
if (Options) {
ULONG NewRegisteredProcessors;
PCHAR NumProcOption;
NumProcOption = strstr(Options, "NUMPROC");
if (NumProcOption != NULL) {
NumProcOption = strstr(NumProcOption,"=");
}
if (NumProcOption != NULL) {
NewRegisteredProcessors = atol(NumProcOption+1);
if (NewRegisteredProcessors < KeRegisteredProcessors) {
KeRegisteredProcessors = NewRegisteredProcessors;
}
#if defined(_X86_)
KeNumprocSpecified = NewRegisteredProcessors;
#endif
}
}
//
// If this is an MP build of the kernel start any other processors now
//
KeStartAllProcessors();
//
// Since starting processors has thrown off the system time, get it again
// from the RTC and set the system time again.
//
if (ExCmosClockIsSane
&& HalQueryRealTimeClock(&TimeFields)) {
if (YearOverrideOption) {
TimeFields.Year = (SHORT)CurrentYear;
}
RtlTimeFieldsToTime(&TimeFields, &CmosTime);
if ( !ExpRealTimeIsUniversal ) {
UniversalTime.QuadPart = CmosTime.QuadPart + ExpTimeZoneBias.QuadPart;
}
KeSetSystemTime(&UniversalTime, &OldTime, TRUE, NULL);
}
//
// Set the affinity of the system process and all of its threads to
// all processors in the host configuration.
//
KeSetAffinityProcess(KeGetCurrentThread()->ApcState.Process,
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
//
// Signify 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
);
MemorySize = 0;
for (Index=0; Index < MmPhysicalMemoryBlock->NumberOfRuns; Index++) {
MemorySize += (PFN_COUNT)MmPhysicalMemoryBlock->Run[Index].PageCount;
}
sprintf (DebugBuffer,
NT_SUCCESS(Status) ? MessageEntry->Text : "%u System Processor [%u MB Memory] %Z\n",
KeNumberProcessors,
(MemorySize + (1 << (20 - PAGE_SHIFT)) - 1) >> (20 - PAGE_SHIFT),
&AnsiDebugString);
InbvDisplayString(DebugBuffer);
InbvUpdateProgressBar(5);
#if defined(REMOTE_BOOT)
//
// Save any information from NetBoot for later.
//
if (IoRemoteBootClient) {
ULONG Flags;
ASSERT(LoaderBlock->SetupLoaderBlock != NULL);
Flags = LoaderBlock->SetupLoaderBlock->Flags;
NetBootDisconnected = (BOOLEAN)((Flags & SETUPBLK_FLAGS_DISCONNECTED) != 0);
NetBootRequiresFormat = (BOOLEAN)((Flags & SETUPBLK_FLAGS_FORMAT_NEEDED) != 0);
memcpy(NetBootHalName,
LoaderBlock->SetupLoaderBlock->NetBootHalName,
sizeof(NetBootHalName));
}
#endif // defined(REMOTE_BOOT)
//
// Initialize OB, EX, KE, and KD.
//
if (!ObInitSystem()) {
KeBugCheck(OBJECT1_INITIALIZATION_FAILED);
}
if (!ExInitSystem()) {
KeBugCheckEx(PHASE1_INITIALIZATION_FAILED,STATUS_UNSUCCESSFUL,0,1,0);
}
if (!KeInitSystem()) {
KeBugCheckEx(PHASE1_INITIALIZATION_FAILED,STATUS_UNSUCCESSFUL,0,2,0);
}
if (!KdInitSystem(InitializationPhase, NULL)) {
KeBugCheckEx(PHASE1_INITIALIZATION_FAILED,STATUS_UNSUCCESSFUL,0,3,0);
}
//
// SE expects directory and executive objects to be available, but
// must be before device drivers are initialized.
//
if (!SeInitSystem()) {
KeBugCheck(SECURITY1_INITIALIZATION_FAILED);
}
InbvUpdateProgressBar(10);
//
// Create the symbolic link to \SystemRoot.
//
Status = CreateSystemRootLink(LoaderBlock);
if ( !NT_SUCCESS(Status) ) {
KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED,Status,0,0,0);
}
if (MmInitSystem(1, LoaderBlock) == 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;
CacheViewSize = SectionSize.LowPart;
SavedViewSize = CacheViewSize;
SectionSize.LowPart = 0;
Status = MmMapViewInSystemCache (InitNlsSectionPointer,
&SectionBase,
&SectionSize,
&CacheViewSize);
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 guarantees
// contiguous buffers and the base of all the tables is the ANSI
// code page data.
//
RtlCopyMemory (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 underutilized 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);
}
RtlCopyMemory (ViewBase, InitNlsTableBase, InitNlsTableSize);
InitNlsTableBase = ViewBase;
//
// Initialize the cache manager.
//
if (!CcInitializeCacheManager()) {
KeBugCheck(CACHE_INITIALIZATION_FAILED);
}
//
// Config management (particularly the registry) gets initialized 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);
}
//
// Initialize the prefetcher after registry is initialized so we can
// query the prefetching parameters.
//
CcPfInitializePrefetcher();
InbvUpdateProgressBar(15);
//
// Compute timezone bias and next cutover date.
//
BootTimeZoneBias = ExpLastTimeZoneBias;
ExpRefreshTimeZoneInformation(&CmosTime);
if (ResetActiveTimeBias) {
ExLocalTimeToSystemTime(&CmosTime,&UniversalTime);
KeBootTime = UniversalTime;
KeBootTimeBias = 0;
KeSetSystemTime(&UniversalTime, &OldTime, FALSE, NULL);
}
else {
//
// Check to see if a timezone switch occurred prior to boot...
//
if (BootTimeZoneBias != ExpLastTimeZoneBias) {
ZwSetSystemTime(NULL,NULL);
}
}
if (!FsRtlInitSystem()) {
KeBugCheck(FILE_INITIALIZATION_FAILED);
}
//
// Initialize the range list package - this must be before PNP
// initialization as PNP uses range lists.
//
RtlInitializeRangeListPackage();
HalReportResourceUsage();
KdDebuggerInitialize1(LoaderBlock);
//
// 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);
}
InbvUpdateProgressBar(20);
//
// 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);
}
//
// Check for the existence of the safeboot option.
//
if (Options) {
SafeBoot = strstr(Options,SAFEBOOT_LOAD_OPTION_A);
} else {
SafeBoot = FALSE;
}
if (SafeBoot) {
//
// Isolate the safeboot option.
//
SafeBoot += strlen(SAFEBOOT_LOAD_OPTION_A);
//
// Set the safeboot mode.
//
if (strncmp(SafeBoot,SAFEBOOT_MINIMAL_STR_A,strlen(SAFEBOOT_MINIMAL_STR_A))==0) {
InitSafeBootMode = SAFEBOOT_MINIMAL;
SafeBoot += strlen(SAFEBOOT_MINIMAL_STR_A);
} else if (strncmp(SafeBoot,SAFEBOOT_NETWORK_STR_A,strlen(SAFEBOOT_NETWORK_STR_A))==0) {
InitSafeBootMode = SAFEBOOT_NETWORK;
SafeBoot += strlen(SAFEBOOT_NETWORK_STR_A);
} else if (strncmp(SafeBoot,SAFEBOOT_DSREPAIR_STR_A,strlen(SAFEBOOT_DSREPAIR_STR_A))==0) {
InitSafeBootMode = SAFEBOOT_DSREPAIR;
SafeBoot += strlen(SAFEBOOT_DSREPAIR_STR_A);
} else {
InitSafeBootMode = 0;
}
if (*SafeBoot && strncmp(SafeBoot,SAFEBOOT_ALTERNATESHELL_STR_A,strlen(SAFEBOOT_ALTERNATESHELL_STR_A))==0) {
UseAlternateShell = TRUE;
}
if (InitSafeBootMode) {
PKLDR_DATA_TABLE_ENTRY DataTableEntry;
PMESSAGE_RESOURCE_ENTRY MessageEntry;
ULONG MsgId = 0;
DataTableEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink,
KLDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
switch (InitSafeBootMode) {
case SAFEBOOT_MINIMAL:
MsgId = BOOTING_IN_SAFEMODE_MINIMAL;
break;
case SAFEBOOT_NETWORK:
MsgId = BOOTING_IN_SAFEMODE_NETWORK;
break;
case SAFEBOOT_DSREPAIR:
MsgId = BOOTING_IN_SAFEMODE_DSREPAIR;
break;
}
Status = RtlFindMessage (DataTableEntry->DllBase, 11, 0, MsgId, &MessageEntry);
if (NT_SUCCESS( Status )) {
InbvDisplayString(MessageEntry->Text);
}
}
}
//
// Check for the existence of the bootlog option.
//
if (Options) {
BootLogOption = strstr(Options, "BOOTLOG");
} else {
BootLogOption = FALSE;
}
if (BootLogOption) {
Status = RtlFindMessage (DataTableEntry->DllBase, 11, 0, BOOTLOG_ENABLED, &MessageEntry);
if (NT_SUCCESS( Status )) {
InbvDisplayString(MessageEntry->Text);
}
IopInitializeBootLogging(LoaderBlock, BootLogBuffer);
}
//
// Now that system time is running, initialize more of the Executive.
//
ExInitSystemPhase2();
InbvUpdateProgressBar(25);
//
// Allow time slip notification changes.
//
KdpTimeSlipPending = 0;
//
// If we are running XIP, we have to initialize XIP before the I/O system calls xipdisk.sys
// This is defined to be nothing on platforms that do not support XIP.
//
XIPInit(LoaderBlock);
//
// Initialize the Io system.
//
// IoInitSystem updates progress bar updates from 25 to 75 %.
//
InbvSetProgressBarSubset(25, 75);
if (!IoInitSystem(LoaderBlock)) {
KeBugCheck(IO1_INITIALIZATION_FAILED);
}
//
// Clear progress bar subset, goes back to absolute mode.
//
InbvSetProgressBarSubset(0, 100);
//
// Set the registry value that indicates we've booted in safeboot mode.
//
if (InitSafeBootMode) {
HANDLE hSafeBoot,hOption;
UNICODE_STRING string;
OBJECT_ATTRIBUTES objectAttributes;
ULONG disposition;
UCHAR Buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + 32];
ULONG length;
PKEY_VALUE_PARTIAL_INFORMATION keyValue;
InitializeObjectAttributes(
&objectAttributes,
&CmRegistryMachineSystemCurrentControlSetControlSafeBoot,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = ZwOpenKey(
&hSafeBoot,
KEY_ALL_ACCESS,
&objectAttributes
);
if (NT_SUCCESS(Status)) {
if (UseAlternateShell) {
RtlInitUnicodeString( &string, L"AlternateShell" );
keyValue = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
RtlZeroMemory(Buffer, sizeof(Buffer));
Status = NtQueryValueKey(
hSafeBoot,
&string,
KeyValuePartialInformation,
keyValue,
sizeof(Buffer),
&length
);
if (!NT_SUCCESS(Status)) {
UseAlternateShell = FALSE;
}
}
RtlInitUnicodeString( &string, L"Option" );
InitializeObjectAttributes(
&objectAttributes,
&string,
OBJ_CASE_INSENSITIVE,
hSafeBoot,
NULL
);
Status = ZwCreateKey(
&hOption,
KEY_ALL_ACCESS,
&objectAttributes,
0,
NULL,
REG_OPTION_VOLATILE,
&disposition
);
NtClose(hSafeBoot);
if (NT_SUCCESS(Status)) {
RtlInitUnicodeString( &string, L"OptionValue" );
Status = NtSetValueKey(
hOption,
&string,
0,
REG_DWORD,
&InitSafeBootMode,
sizeof(ULONG)
);
if (UseAlternateShell) {
RtlInitUnicodeString( &string, L"UseAlternateShell" );
Index = 1;
Status = NtSetValueKey(
hOption,
&string,
0,
REG_DWORD,
&Index,
sizeof(ULONG)
);
}
NtClose(hOption);
}
}
}
//
// Create the Mini NT boot key, to indicate to the user mode
// programs that we are in Mini NT environment.
//
if (InitIsWinPEMode) {
WCHAR KeyName[256] = {0};
HANDLE hControl;
UNICODE_STRING String;
OBJECT_ATTRIBUTES ObjAttrs;
ULONG Disposition;
wcsncpy(KeyName, CmRegistryMachineSystemCurrentControlSet.Buffer,
CmRegistryMachineSystemCurrentControlSet.Length);
wcscat(KeyName, L"\\Control");
RtlInitUnicodeString(&String, KeyName);
InitializeObjectAttributes(
&ObjAttrs,
&String,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = ZwOpenKey(
&hControl,
KEY_ALL_ACCESS,
&ObjAttrs
);
if (NT_SUCCESS(Status)) {
HANDLE hMiniNT;
RtlInitUnicodeString(&String, L"MiniNT");
InitializeObjectAttributes(
&ObjAttrs,
&String,
OBJ_CASE_INSENSITIVE,
hControl,
NULL
);
Status = ZwCreateKey(
&hMiniNT,
KEY_ALL_ACCESS,
&ObjAttrs,
0,
NULL,
REG_OPTION_VOLATILE,
&Disposition
);
if (NT_SUCCESS(Status)) {
ZwClose(hMiniNT);
}
ZwClose(hControl);
}
//
// If we could not create the key, then bug check
// since we can't boot into mini NT anyway.
//
if (!NT_SUCCESS(Status)) {
KeBugCheckEx(PHASE1_INITIALIZATION_FAILED,Status,6,0,0);
}
}
//
// Begin paging the executive if desired.
//
MmInitSystem(2, LoaderBlock);
InbvUpdateProgressBar(80);
#if defined(_X86_)
//
// Initialize Vdm specific stuff
//
// Note: If this fails, Vdms may not be able to run, but it isn't
// necessary to bugcheck the system because of this.
//
KeI386VdmInitialize();
#if !defined(NT_UP)
//
// Now that the error log interface has been initialized, write
// an informational message if it was determined that the
// processors in the system are at differing revision levels.
//
if (CmProcessorMismatch != 0) {
PIO_ERROR_LOG_PACKET ErrLog;
ErrLog = IoAllocateGenericErrorLogEntry(ERROR_LOG_MAXIMUM_SIZE);
if (ErrLog) {
//
// Fill it in and write it out.
//
ErrLog->FinalStatus = STATUS_MP_PROCESSOR_MISMATCH;
ErrLog->ErrorCode = STATUS_MP_PROCESSOR_MISMATCH;
ErrLog->UniqueErrorValue = CmProcessorMismatch;
IoWriteErrorLogEntry(ErrLog);
}
}
#endif // !NT_UP
//
// Also log remembered machine checks, if any.
//
KiLogMcaErrors();
#endif // _X86_
if (!PoInitSystem(1)) {
KeBugCheck(INTERNAL_POWER_ERROR);
}
//
// Okay to call PsInitSystem now that \SystemRoot is defined so it can
// locate NTDLL.DLL and SMSS.EXE.
//
if (PsInitSystem(1, LoaderBlock) == FALSE) {
KeBugCheck(PROCESS1_INITIALIZATION_FAILED);
}
InbvUpdateProgressBar(85);
//
// 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);
}
InbvUpdateProgressBar(90);
//
// Set up process parameters for the Session Manager Subsystem.
//
// NOTE: Remote boot allocates an extra DOS_MAX_PATH_LENGTH number of
// WCHARs in order to hold command line arguments to smss.exe.
//
Size = sizeof( *ProcessParameters ) +
((DOS_MAX_PATH_LENGTH * 6) * 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 = (ULONG)Size;
ProcessParameters->MaximumLength = (ULONG)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;
Environment = NULL;
Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
&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);
}
ProcessParameters->Environment = Environment;
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 );
if (NtInitialUserProcessBufferType != REG_SZ ||
(NtInitialUserProcessBufferLength != (ULONG)-1 &&
(NtInitialUserProcessBufferLength < sizeof(WCHAR) ||
NtInitialUserProcessBufferLength >
sizeof(NtInitialUserProcessBuffer) - sizeof(WCHAR)))) {
KeBugCheckEx(SESSION2_INITIALIZATION_FAILED,
STATUS_INVALID_PARAMETER,
NtInitialUserProcessBufferType,
NtInitialUserProcessBufferLength,
sizeof(NtInitialUserProcessBuffer));
}
// Executable names with spaces don't need to
// be supported so just find the first space and
// assume it terminates the process image name.
Src = NtInitialUserProcessBuffer;
while (*Src && *Src != L' ') {
Src++;
}
ProcessParameters->ImagePathName.Length =
(USHORT)((PUCHAR)Src - (PUCHAR)NtInitialUserProcessBuffer);
RtlCopyMemory(ProcessParameters->ImagePathName.Buffer,
NtInitialUserProcessBuffer,
ProcessParameters->ImagePathName.Length);
ProcessParameters->ImagePathName.Buffer[ProcessParameters->ImagePathName.Length / sizeof(WCHAR)] = UNICODE_NULL;
Dst = (PWSTR)((PCHAR)ProcessParameters->ImagePathName.Buffer +
ProcessParameters->ImagePathName.MaximumLength
);
ProcessParameters->CommandLine.Buffer = Dst;
ProcessParameters->CommandLine.MaximumLength = DOS_MAX_PATH_LENGTH * sizeof( WCHAR );
RtlAppendUnicodeToString(&ProcessParameters->CommandLine,
NtInitialUserProcessBuffer);
#if defined(REMOTE_BOOT)
//
// Pass additional parameters for remote boot clients.
//
if (IoRemoteBootClient && !ExpInTextModeSetup) {
RtlAppendUnicodeToString(&ProcessParameters->CommandLine, L" NETBOOT");
RtlAppendUnicodeToString(&ProcessParameters->CommandLine, L" NETBOOTHAL ");
AnsiDebugString.Length = strlen(NetBootHalName);
AnsiDebugString.MaximumLength = sizeof(NetBootHalName);
AnsiDebugString.Buffer = NetBootHalName;
RtlAnsiStringToUnicodeString(&TmpUnicodeString, &AnsiDebugString, TRUE);
RtlAppendUnicodeStringToString(&ProcessParameters->CommandLine, &TmpUnicodeString);
(RtlFreeStringRoutine)(TmpUnicodeString.Buffer);
if (NetBootDisconnected) {
RtlAppendUnicodeToString(&ProcessParameters->CommandLine, L" NETBOOTDISCONNECTED");
}
if (NetBootRequiresFormat) {
RtlAppendUnicodeToString(&ProcessParameters->CommandLine, L" NETBOOTFORMAT");
}
}
#endif // defined(REMOTE_BOOT)
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
//
// Notify boot prefetcher of boot progress.
//
CcPfBeginBootPhase(PfSessionManagerInitPhase);
SessionManager = ProcessParameters->ImagePathName;
Status = RtlCreateUserProcess(
&SessionManager,
OBJ_CASE_INSENSITIVE,
RtlDeNormalizeProcessParams( ProcessParameters ),
NULL,
NULL,
NULL,
FALSE,
NULL,
NULL,
&ProcessInformation);
if (InbvBootDriverInstalled)
{
FinalizeBootLogo();
}
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);
}
InbvUpdateProgressBar(100);
//
// Turn on debug output so that we can see chkdsk run.
//
InbvEnableDisplayString(TRUE);
//
// 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);
}
//
// Don't need these handles anymore.
//
ZwClose( ProcessInformation.Thread );
ZwClose( ProcessInformation.Process );
//
// Free up memory used to pass arguments to session manager.
//
Size = 0;
Address = 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,
SePublicDefaultUnrestrictedSd );
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,
SePublicDefaultUnrestrictedSd );
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,
SePublicDefaultUnrestrictedSd );
//
// 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
--*/
{
PKLDR_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, KLDR_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_PTR)DllBase,
ExportDirectory->NumberOfNames,
(PULONG)((ULONG_PTR)DllBase + ExportDirectory->AddressOfNames),
(PUSHORT)((ULONG_PTR)DllBase + 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_PTR)DllBase + ExportDirectory->AddressOfFunctions);
*AddressOfEntryPoint = (PVOID)((ULONG_PTR)DllBase + Addr[Ordinal]);
return STATUS_SUCCESS;
}
static USHORT
NameToOrdinal (
IN PSZ NameOfEntryPoint,
IN ULONG_PTR DllBase,
IN ULONG NumberOfNames,
IN PULONG NameTableBase,
IN PUSHORT NameOrdinalTableBase
)
{
ULONG SplitIndex;
LONG CompareResult;
if ( NumberOfNames == 0 ) {
return (USHORT)-1;
}
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);
}