You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3150 lines
91 KiB
3150 lines
91 KiB
/*++
|
|
|
|
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;
|
|
|
|
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
|
|
KiInitializeInterruptTimers(
|
|
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
|
|
);
|
|
|
|
NTSTATUS
|
|
RtlInitializeStackTraceDataBase(
|
|
IN PVOID CommitBase,
|
|
IN SIZE_T CommitSize,
|
|
IN SIZE_T ReserveSize
|
|
);
|
|
|
|
BOOLEAN
|
|
ExpIsLoaderValid(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
);
|
|
|
|
#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)
|
|
#pragma alloc_text(INIT,ExpIsLoaderValid)
|
|
#endif
|
|
|
|
//
|
|
// Define global static data used during initialization.
|
|
//
|
|
|
|
ULONG NtGlobalFlag;
|
|
extern PMESSAGE_RESOURCE_BLOCK KiBugCheckMessages;
|
|
|
|
extern UCHAR CmProcessorMismatch;
|
|
|
|
const ULONG NtMajorVersion = VER_PRODUCTMAJORVERSION;
|
|
const ULONG NtMinorVersion = VER_PRODUCTMINORVERSION;
|
|
|
|
#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 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;
|
|
PUCHAR LogoBitmap = 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
|
|
LogoBitmap = InbvGetResourceAddress(13); // srv edition logo and title
|
|
}
|
|
|
|
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) {
|
|
|
|
extern BOOLEAN ExpInTextModeSetup; // defined at base\ntos\ex\exinit.c
|
|
|
|
// Tweak the logo to make it neutral (e.g. 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 bitmap
|
|
// without specific SKU title (e.g. just Windows) and server's progress bar
|
|
|
|
if (ExpInTextModeSetup) {
|
|
TextBitmap = NULL;
|
|
}
|
|
else {
|
|
// Overwrite the XP logo with .NET logo
|
|
if (LogoBitmap) {
|
|
InbvBitBlt(LogoBitmap, 180, 121);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
|
|
BOOLEAN
|
|
ExpIsLoaderValid(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
{
|
|
ULONG majorVersion;
|
|
ULONG minorVersion;
|
|
CHAR versionBuffer[64];
|
|
PCHAR major;
|
|
PCHAR minor;
|
|
ULONG minSize;
|
|
|
|
//
|
|
// Make sure that we got loaded by a matching or newer loader.
|
|
// First do a size check to make sure we can even read the version fields.
|
|
//
|
|
minSize = FIELD_OFFSET(LOADER_PARAMETER_EXTENSION, MinorVersion) + RTL_FIELD_SIZE(LOADER_PARAMETER_EXTENSION, MinorVersion);
|
|
if (LoaderBlock->Extension->Size >= minSize) {
|
|
|
|
//
|
|
// Safe to do the version check.
|
|
//
|
|
major = strcpy(versionBuffer, VER_PRODUCTVERSION_STR);
|
|
minor = strchr(major, '.');
|
|
majorVersion = atoi(major);
|
|
if( minor != NULL ) {
|
|
|
|
*minor++ = '\0';
|
|
minorVersion = atoi(minor);
|
|
} else {
|
|
|
|
minorVersion = 0;
|
|
}
|
|
|
|
//
|
|
// Check the version.
|
|
//
|
|
if (LoaderBlock->Extension->MajorVersion > majorVersion ||
|
|
(LoaderBlock->Extension->MajorVersion == majorVersion &&
|
|
LoaderBlock->Extension->MinorVersion >= minorVersion)) {
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
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 ];
|
|
BOOLEAN BufferSizeOk;
|
|
ULONG ImageCount;
|
|
ULONG i;
|
|
ULONG_PTR ResourceIdPath[3];
|
|
PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
|
|
PMESSAGE_RESOURCE_DATA MessageData;
|
|
CHAR VersionBuffer[ 64 ];
|
|
PCHAR s;
|
|
PLIST_ENTRY NextMd;
|
|
PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
|
|
|
|
if (!ExpIsLoaderValid(LoaderBlock)) {
|
|
|
|
KeBugCheckEx(MISMATCHED_HAL,
|
|
3,
|
|
LoaderBlock->Extension->Size,
|
|
LoaderBlock->Extension->MajorVersion,
|
|
LoaderBlock->Extension->MinorVersion
|
|
);
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
|
|
#if defined(_APIC_TPR_)
|
|
|
|
HalpIRQLToTPR = LoaderBlock->Extension->HalpIRQLToTPR;
|
|
HalpVectorToIRQL = LoaderBlock->Extension->HalpVectorToIRQL;
|
|
|
|
#endif
|
|
|
|
//
|
|
// Enable interrupts now that the HAL has initialized.
|
|
//
|
|
|
|
#if defined(_X86_)
|
|
|
|
_enable();
|
|
|
|
#endif
|
|
|
|
//
|
|
// Set the interrupt time forward so the Win32 tick count will wrap
|
|
// within one hour to make rollover errors show up in fewer than 49.7
|
|
// days.
|
|
//
|
|
|
|
#if DBG
|
|
|
|
KeAdjustInterruptTime((LONGLONG)(MAXULONG - (60 * 60 * 1000)) * 10 * 1000);
|
|
|
|
#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 );
|
|
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.
|
|
|
|
#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);
|
|
}
|
|
|
|
//
|
|
// 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) {
|
|
|
|
BufferSizeOk = TRUE;
|
|
|
|
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);
|
|
if (sizeof(Buffer) < Length + sizeof(ANSI_NULL)) {
|
|
//
|
|
// DllName too long.
|
|
//
|
|
BufferSizeOk = FALSE;
|
|
} else {
|
|
Count = 0;
|
|
do {
|
|
Buffer[Count++] = (CHAR)*Filename++;
|
|
} while (Count < Length);
|
|
|
|
Buffer[Count] = 0;
|
|
}
|
|
} else {
|
|
//
|
|
// Assume drivers
|
|
//
|
|
if (sizeof(Buffer) < 18 + NtSystemRoot.Length / sizeof(WCHAR) - 2
|
|
+ DataTableEntry->BaseDllName.Length / sizeof(WCHAR)
|
|
+ sizeof(ANSI_NULL)) {
|
|
//
|
|
// ignore the driver entry, it must have been corrupt.
|
|
//
|
|
BufferSizeOk = FALSE;
|
|
|
|
} else {
|
|
|
|
sprintf (Buffer, "%ws\\System32\\Drivers\\%wZ",
|
|
&SharedUserData->NtSystemRoot[2],
|
|
&DataTableEntry->BaseDllName);
|
|
}
|
|
}
|
|
if (BufferSizeOk) {
|
|
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. If non-zero
|
|
// display it after the 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 );
|
|
Status = RtlAnsiStringToUnicodeString( &CmCSDVersionString, &AnsiString, TRUE );
|
|
if (!NT_SUCCESS (Status)) {
|
|
KeBugCheckEx(PHASE0_INITIALIZATION_FAILED,Status,0,0,0);
|
|
}
|
|
|
|
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 = RtlInitializeStackTraceDataBase (StackTraceDataBase,
|
|
StackTraceDataBaseLength,
|
|
StackTraceDataBaseLength);
|
|
} 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;
|
|
BOOLEAN SOS;
|
|
PVOID Environment;
|
|
|
|
//
|
|
// The following is a dummy reference to an inline function to force a
|
|
// reference to the function so it won't get discard before it can be
|
|
// exported.
|
|
//
|
|
|
|
KeAreApcsDisabled();
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
InbvDriverInitialize(LoaderBlock, 18);
|
|
|
|
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 );
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
sprintf (s,
|
|
MessageEntry->Text,
|
|
VersionBuffer,
|
|
NtBuildNumber & 0xFFFF,
|
|
DebugBuffer);
|
|
} else {
|
|
//
|
|
// Could not find the WINDOWS_NT_BANNER message.
|
|
//
|
|
sprintf (s, "MICROSOFT (R) WINDOWS (TM)\n");
|
|
}
|
|
|
|
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
|
|
|
|
#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;
|
|
Status = RtlAnsiStringToUnicodeString(&TmpUnicodeString, &AnsiDebugString, TRUE);
|
|
if (!NT_SUCCESS (Status)) {
|
|
KeBugCheckEx(SESSION2_INITIALIZATION_FAILED,Status,1,0,0);
|
|
}
|
|
|
|
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);
|
|
Status = RtlAnsiStringToUnicodeString(&UnicodeDebugString,
|
|
&AnsiDebugString,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS (Status)) {
|
|
KeBugCheckEx(SESSION4_INITIALIZATION_FAILED,Status,1,0,0);
|
|
}
|
|
|
|
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;
|
|
|
|
#if defined(_X86_)
|
|
|
|
KiInitializeInterruptTimers();
|
|
|
|
#endif
|
|
|
|
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);
|
|
|
|
}
|