mirror of https://github.com/lianthony/NT4.0
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.
5005 lines
165 KiB
5005 lines
165 KiB
/*++
|
|
|
|
Copyright (c) 1989-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ioinit.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code to initialize the I/O system.
|
|
|
|
Author:
|
|
|
|
Darryl E. Havens (darrylh) April 27, 1989
|
|
|
|
Environment:
|
|
|
|
Kernel mode, system initialization code
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "iop.h"
|
|
|
|
//
|
|
// Define the default number of I/O stack locations a large IRP should
|
|
// have if not specified by the registry.
|
|
//
|
|
|
|
#define DEFAULT_LARGE_IRP_LOCATIONS 4;
|
|
|
|
|
|
//
|
|
// Define the type for driver group name entries in the group list so that
|
|
// load order dependencies can be tracked.
|
|
//
|
|
|
|
typedef struct _TREE_ENTRY {
|
|
struct _TREE_ENTRY *Left;
|
|
struct _TREE_ENTRY *Right;
|
|
struct _TREE_ENTRY *Sibling;
|
|
ULONG DriversThisType;
|
|
ULONG DriversLoaded;
|
|
UNICODE_STRING GroupName;
|
|
} TREE_ENTRY, *PTREE_ENTRY;
|
|
|
|
|
|
PTREE_ENTRY IopGroupListHead;
|
|
|
|
//
|
|
// Define a macro for initializing drivers.
|
|
//
|
|
|
|
//#if _PNP_POWER_
|
|
#define InitializeDriverObject( Object ) { \
|
|
ULONG i; \
|
|
RtlZeroMemory( Object, \
|
|
sizeof( DRIVER_OBJECT ) + sizeof ( DRIVER_EXTENSION )); \
|
|
Object->DriverExtension = (PDRIVER_EXTENSION) (Object + 1); \
|
|
Object->DriverExtension->DriverObject = Object; \
|
|
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) \
|
|
Object->MajorFunction[i] = IopInvalidDeviceRequest; \
|
|
Object->Type = IO_TYPE_DRIVER; \
|
|
Object->Size = sizeof( DRIVER_OBJECT ); \
|
|
}
|
|
//#else
|
|
#if 0
|
|
#define InitializeDriverObject( DriverObject ) { \
|
|
ULONG i; \
|
|
RtlZeroMemory( DriverObject, sizeof( DRIVER_OBJECT ) ); \
|
|
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) \
|
|
DriverObject->MajorFunction[i] = IopInvalidDeviceRequest; \
|
|
DriverObject->Type = IO_TYPE_DRIVER; \
|
|
DriverObject->Size = sizeof( DRIVER_OBJECT ); \
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Define external procedures not in common header files
|
|
//
|
|
|
|
VOID
|
|
IopInitializeData(
|
|
VOID
|
|
);
|
|
|
|
NTSTATUS
|
|
RawInitialize(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
//
|
|
// Define the local procedures
|
|
//
|
|
|
|
BOOLEAN
|
|
IopCheckDependencies(
|
|
IN HANDLE KeyHandle
|
|
);
|
|
|
|
VOID
|
|
IopCreateArcNames(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
);
|
|
|
|
BOOLEAN
|
|
IopCreateObjectTypes(
|
|
VOID
|
|
);
|
|
|
|
PTREE_ENTRY
|
|
IopCreateEntry(
|
|
IN PUNICODE_STRING GroupName
|
|
);
|
|
|
|
BOOLEAN
|
|
IopCreateRootDirectories(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
IopFreeGroupTree(
|
|
IN PTREE_ENTRY TreeEntry
|
|
);
|
|
|
|
NTSTATUS
|
|
IopInitializeAttributesAndCreateObject(
|
|
IN PUNICODE_STRING ObjectName,
|
|
IN OUT POBJECT_ATTRIBUTES ObjectAttributes,
|
|
OUT PDRIVER_OBJECT *DriverObject
|
|
);
|
|
|
|
BOOLEAN
|
|
IopInitializeBootDrivers(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
|
OUT PDRIVER_OBJECT *PreviousDriver
|
|
);
|
|
|
|
BOOLEAN
|
|
IopInitializeBuiltinDriver(
|
|
IN PUNICODE_STRING DriverName,
|
|
IN PUNICODE_STRING RegistryPath,
|
|
IN PDRIVER_INITIALIZE DriverInitializeRoutine
|
|
);
|
|
|
|
BOOLEAN
|
|
IopInitializeDumpDrivers(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
);
|
|
|
|
BOOLEAN
|
|
IopInitializeSingleBootDriver(
|
|
IN HANDLE KeyHandle,
|
|
IN PBOOT_DRIVER_LIST_ENTRY BootDriver,
|
|
OUT PUNICODE_STRING DriverName OPTIONAL
|
|
);
|
|
|
|
BOOLEAN
|
|
IopInitializeSystemDrivers(
|
|
VOID
|
|
);
|
|
|
|
PTREE_ENTRY
|
|
IopLookupGroupName(
|
|
IN PUNICODE_STRING GroupName,
|
|
IN BOOLEAN Insert
|
|
);
|
|
|
|
BOOLEAN
|
|
IopMarkBootPartition(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
);
|
|
|
|
BOOLEAN
|
|
IopReassignSystemRoot(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
|
OUT PSTRING NtDeviceName
|
|
);
|
|
|
|
VOID
|
|
IopRevertModuleList(
|
|
IN ULONG ListCount
|
|
);
|
|
|
|
VOID
|
|
IopStoreSystemPartitionInformation(
|
|
IN PUNICODE_STRING NtSystemPartitionDeviceName,
|
|
IN OUT PUNICODE_STRING OsLoaderPathName
|
|
);
|
|
|
|
#ifdef _PNP_POWER_
|
|
|
|
VOID
|
|
IopVerifyBuiltInBuses(
|
|
VOID
|
|
);
|
|
|
|
NTSTATUS
|
|
IopRegisterNewBusInstance (
|
|
PBUS_HANDLER BusHandler
|
|
);
|
|
|
|
VOID
|
|
PiGetBusDescription(
|
|
INTERFACE_TYPE InterfaceType,
|
|
WCHAR BusName[MAX_BUS_NAME]
|
|
);
|
|
|
|
#endif // _PNP_POWER_
|
|
|
|
//
|
|
// The following allows the I/O system's initialization routines to be
|
|
// paged out of memory.
|
|
//
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT,IoInitSystem)
|
|
#pragma alloc_text(INIT,IopCheckDependencies)
|
|
#pragma alloc_text(INIT,IopCreateArcNames)
|
|
#pragma alloc_text(INIT,IopCreateEntry)
|
|
#pragma alloc_text(INIT,IopCreateObjectTypes)
|
|
#pragma alloc_text(INIT,IopCreateRootDirectories)
|
|
#pragma alloc_text(INIT,IopFreeGroupTree)
|
|
#pragma alloc_text(INIT,IopInitializeAttributesAndCreateObject)
|
|
#pragma alloc_text(INIT,IopInitializeBootDrivers)
|
|
#pragma alloc_text(INIT,IopInitializeDumpDrivers)
|
|
#pragma alloc_text(INIT,IopInitializeBuiltinDriver)
|
|
#pragma alloc_text(INIT,IopInitializeSingleBootDriver)
|
|
#pragma alloc_text(INIT,IopInitializeSystemDrivers)
|
|
#pragma alloc_text(INIT,IopLookupGroupName)
|
|
#pragma alloc_text(INIT,IopMarkBootPartition)
|
|
#pragma alloc_text(INIT,IopReassignSystemRoot)
|
|
#pragma alloc_text(INIT,IopRevertModuleList)
|
|
#pragma alloc_text(INIT,IopStoreSystemPartitionInformation)
|
|
|
|
#ifdef _PNP_POWER_
|
|
#pragma alloc_text(INIT,IopVerifyBuiltInBuses)
|
|
#pragma alloc_text(INIT,IopRegisterNewBusInstance)
|
|
#endif // _PNP_POWER_
|
|
|
|
#endif
|
|
|
|
|
|
BOOLEAN
|
|
IoInitSystem(
|
|
PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the I/O system.
|
|
|
|
Arguments:
|
|
|
|
LoaderBlock - Supplies a pointer to the loader parameter block that was
|
|
created by the OS Loader.
|
|
|
|
Return Value:
|
|
|
|
The function value is a BOOLEAN indicating whether or not the I/O system
|
|
was successfully initialized.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDRIVER_OBJECT driverObject;
|
|
PDRIVER_OBJECT *nextDriverObject;
|
|
STRING ntDeviceName;
|
|
UCHAR deviceNameBuffer[256];
|
|
ULONG packetSize;
|
|
ULONG numberOfPackets;
|
|
ULONG poolSize;
|
|
PLIST_ENTRY entry;
|
|
PREINIT_PACKET reinitEntry;
|
|
LARGE_INTEGER deltaTime;
|
|
MM_SYSTEMSIZE systemSize;
|
|
USHORT largeIrpZoneSize;
|
|
USHORT smallIrpZoneSize;
|
|
USHORT mdlZoneSize;
|
|
ULONG oldNtGlobalFlag;
|
|
NTSTATUS status;
|
|
ANSI_STRING AnsiString;
|
|
|
|
ASSERT( IopQueryOperationLength[FileMaximumInformation] == 0xff );
|
|
ASSERT( IopSetOperationLength[FileMaximumInformation] == 0xff );
|
|
ASSERT( IopQueryOperationAccess[FileMaximumInformation] == 0xffffffff );
|
|
ASSERT( IopSetOperationAccess[FileMaximumInformation] == 0xffffffff );
|
|
|
|
ASSERT( IopQueryFsOperationLength[FileFsMaximumInformation] == 0xff );
|
|
ASSERT( IopSetFsOperationLength[FileFsMaximumInformation] == 0xff );
|
|
ASSERT( IopQueryFsOperationAccess[FileFsMaximumInformation] == 0xffffffff );
|
|
ASSERT( IopSetFsOperationAccess[FileFsMaximumInformation] == 0xffffffff );
|
|
|
|
//#if _PNP_POWER_
|
|
status = IopInitializePlugPlayServices(LoaderBlock);
|
|
if (!NT_SUCCESS(status)) {
|
|
return FALSE;
|
|
}
|
|
//#endif
|
|
|
|
//
|
|
// Initialize the I/O database resource, lock, and the file system and
|
|
// network file system queue headers. Also allocate the cancel spin
|
|
// lock.
|
|
//
|
|
|
|
ntDeviceName.Buffer = deviceNameBuffer;
|
|
ntDeviceName.MaximumLength = sizeof(deviceNameBuffer);
|
|
ntDeviceName.Length = 0;
|
|
|
|
ExInitializeResource( &IopDatabaseResource );
|
|
KeInitializeSpinLock( &IopDatabaseLock );
|
|
InitializeListHead( &IopDiskFileSystemQueueHead );
|
|
InitializeListHead( &IopCdRomFileSystemQueueHead );
|
|
InitializeListHead( &IopTapeFileSystemQueueHead );
|
|
InitializeListHead( &IopNetworkFileSystemQueueHead );
|
|
InitializeListHead( &IopDriverReinitializeQueueHead );
|
|
InitializeListHead( &IopNotifyShutdownQueueHead );
|
|
InitializeListHead( &IopFsNotifyChangeQueueHead );
|
|
KeInitializeSpinLock( &IopCancelSpinLock );
|
|
KeInitializeSpinLock( &IopVpbSpinLock );
|
|
KeInitializeSpinLock( &IoStatisticsLock );
|
|
|
|
//
|
|
// Initialize the large I/O Request Packet (IRP) lookaside list head and the
|
|
// mutex which guards the list.
|
|
//
|
|
|
|
if (!IopLargeIrpStackLocations) {
|
|
IopLargeIrpStackLocations = DEFAULT_LARGE_IRP_LOCATIONS;
|
|
}
|
|
|
|
systemSize = MmQuerySystemSize();
|
|
|
|
switch ( systemSize ) {
|
|
|
|
case MmSmallSystem :
|
|
smallIrpZoneSize = 6;
|
|
largeIrpZoneSize = 8;
|
|
mdlZoneSize = 16;
|
|
break;
|
|
|
|
case MmMediumSystem :
|
|
smallIrpZoneSize = 24;
|
|
largeIrpZoneSize = 32;
|
|
mdlZoneSize = 90;
|
|
break;
|
|
|
|
case MmLargeSystem :
|
|
if (MmIsThisAnNtAsSystem()) {
|
|
smallIrpZoneSize = 96;
|
|
largeIrpZoneSize = 128;
|
|
mdlZoneSize = 256;
|
|
|
|
} else {
|
|
smallIrpZoneSize = 32;
|
|
largeIrpZoneSize = 64;
|
|
mdlZoneSize = 128;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Initialize the large IRP lookaside list.
|
|
//
|
|
|
|
packetSize = (ULONG) (sizeof( IRP ) + (IopLargeIrpStackLocations * sizeof( IO_STACK_LOCATION )));
|
|
ExInitializeNPagedLookasideList( &IopLargeIrpLookasideList,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
packetSize,
|
|
'lprI',
|
|
largeIrpZoneSize );
|
|
|
|
//
|
|
// Initialize the small IRP lookaside list.
|
|
//
|
|
|
|
packetSize = (ULONG) (sizeof( IRP ) + sizeof( IO_STACK_LOCATION ));
|
|
ExInitializeNPagedLookasideList( &IopSmallIrpLookasideList,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
packetSize,
|
|
'sprI',
|
|
smallIrpZoneSize );
|
|
|
|
//
|
|
// Initialize the MDL lookaside list.
|
|
//
|
|
|
|
packetSize = (ULONG) (sizeof( MDL ) + (IOP_FIXED_SIZE_MDL_PFNS * sizeof( ULONG )));
|
|
ExInitializeNPagedLookasideList( &IopMdlLookasideList,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
packetSize,
|
|
' ldM',
|
|
mdlZoneSize );
|
|
|
|
//
|
|
// Initialize the I/O completion spin lock.
|
|
//
|
|
|
|
KeInitializeSpinLock( &IopCompletionLock );
|
|
|
|
//
|
|
// Initalize the error log spin locks and log list.
|
|
//
|
|
|
|
KeInitializeSpinLock( &IopErrorLogLock );
|
|
KeInitializeSpinLock( &IopErrorLogAllocationLock );
|
|
InitializeListHead( &IopErrorLogListHead );
|
|
|
|
//
|
|
// Initialize the registry access semaphore.
|
|
//
|
|
|
|
KeInitializeSemaphore( &IopRegistrySemaphore, 1, 1 );
|
|
|
|
//
|
|
// Initialize the timer database and start the timer DPC routine firing
|
|
// so that drivers can use it during initialization.
|
|
//
|
|
|
|
deltaTime.QuadPart = - 10 * 1000 * 1000;
|
|
|
|
KeInitializeSpinLock( &IopTimerLock );
|
|
InitializeListHead( &IopTimerQueueHead );
|
|
KeInitializeDpc( &IopTimerDpc, IopTimerDispatch, NULL );
|
|
KeInitializeTimerEx( &IopTimer, SynchronizationTimer );
|
|
(VOID) KeSetTimerEx( &IopTimer, deltaTime, 1000, &IopTimerDpc );
|
|
|
|
//
|
|
// Initialize the IopHardError structure used for informational pop-ups.
|
|
//
|
|
|
|
ExInitializeWorkItem( &IopHardError.ExWorkItem,
|
|
IopHardErrorThread,
|
|
NULL );
|
|
|
|
InitializeListHead( &IopHardError.WorkQueue );
|
|
|
|
KeInitializeSpinLock( &IopHardError.WorkQueueSpinLock );
|
|
|
|
KeInitializeSemaphore( &IopHardError.WorkQueueSemaphore,
|
|
0,
|
|
MAXLONG );
|
|
|
|
IopHardError.ThreadStarted = FALSE;
|
|
|
|
IopCurrentHardError = NULL;
|
|
|
|
//
|
|
// Create all of the objects for the I/O system.
|
|
//
|
|
|
|
if (!IopCreateObjectTypes()) {
|
|
#if DBG
|
|
DbgPrint( "IOINIT: IopCreateObjectTypes failed\n" );
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Create the root directories for the I/O system.
|
|
//
|
|
|
|
if (!IopCreateRootDirectories()) {
|
|
#if DBG
|
|
DbgPrint( "IOINIT: IopCreateRootDirectories failed\n" );
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Initialize the resource map
|
|
//
|
|
|
|
IopInitializeResourceMap (LoaderBlock);
|
|
|
|
//
|
|
// Initialize the drivers loaded by the boot loader (OSLOADER)
|
|
//
|
|
|
|
nextDriverObject = &driverObject;
|
|
if (!IopInitializeBootDrivers( LoaderBlock,
|
|
nextDriverObject )) {
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Initializing boot drivers failed\n" );
|
|
#endif // DBG
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Save the current value of the NT Global Flags and enable kernel debugger
|
|
// symbol loading while drivers are being loaded so that systems can be
|
|
// debugged regardless of whether they are free or checked builds.
|
|
//
|
|
|
|
oldNtGlobalFlag = NtGlobalFlag;
|
|
|
|
if (!(NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD)) {
|
|
NtGlobalFlag |= FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
|
|
}
|
|
|
|
status = PsLocateSystemDll();
|
|
if (!NT_SUCCESS( status )) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Initialize the device drivers for the system.
|
|
//
|
|
|
|
if (!IopInitializeSystemDrivers()) {
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Initializing system drivers failed\n" );
|
|
#endif // DBG
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Free the memory allocated to contain the group dependency list.
|
|
//
|
|
|
|
if (IopGroupListHead) {
|
|
IopFreeGroupTree( IopGroupListHead );
|
|
}
|
|
|
|
//
|
|
// Walk the list of drivers that have requested that they be called again
|
|
// for reinitialization purposes.
|
|
//
|
|
|
|
while (entry = ExInterlockedRemoveHeadList( &IopDriverReinitializeQueueHead, &IopDatabaseLock )) {
|
|
reinitEntry = CONTAINING_RECORD( entry, REINIT_PACKET, ListEntry );
|
|
//#if _PNP_POWER_
|
|
reinitEntry->DriverObject->DriverExtension->Count++;
|
|
reinitEntry->DriverReinitializationRoutine( reinitEntry->DriverObject,
|
|
reinitEntry->Context,
|
|
reinitEntry->DriverObject->DriverExtension->Count );
|
|
//#else
|
|
#if 0
|
|
reinitEntry->DriverObject->Count++;
|
|
reinitEntry->DriverReinitializationRoutine( reinitEntry->DriverObject,
|
|
reinitEntry->Context,
|
|
reinitEntry->DriverObject->Count );
|
|
#endif // _PNP_POWER_
|
|
ExFreePool( reinitEntry );
|
|
}
|
|
|
|
//
|
|
// Reassign \SystemRoot to NT device name path.
|
|
//
|
|
|
|
if (!IopReassignSystemRoot( LoaderBlock, &ntDeviceName )) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Protect the system partition of an ARC system if necessary
|
|
//
|
|
|
|
if (!IopProtectSystemPartition( LoaderBlock )) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Assign DOS drive letters to disks and cdroms and define \SystemRoot.
|
|
//
|
|
|
|
AnsiString.MaximumLength = NtSystemRoot.MaximumLength / sizeof( WCHAR );
|
|
AnsiString.Length = 0;
|
|
AnsiString.Buffer = (RtlAllocateStringRoutine)( AnsiString.MaximumLength );
|
|
status = RtlUnicodeStringToAnsiString( &AnsiString,
|
|
&NtSystemRoot,
|
|
FALSE
|
|
);
|
|
if (!NT_SUCCESS( status )) {
|
|
DbgPrint( "IOINIT: UnicodeToAnsi( %wZ ) failed - %x\n", &NtSystemRoot, status );
|
|
return(FALSE);
|
|
}
|
|
|
|
IoAssignDriveLetters( LoaderBlock,
|
|
&ntDeviceName,
|
|
AnsiString.Buffer,
|
|
&AnsiString );
|
|
|
|
status = RtlAnsiStringToUnicodeString( &NtSystemRoot,
|
|
&AnsiString,
|
|
FALSE
|
|
);
|
|
if (!NT_SUCCESS( status )) {
|
|
DbgPrint( "IOINIT: AnsiToUnicode( %Z ) failed - %x\n", &AnsiString, status );
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Also restore the NT Global Flags to their original state.
|
|
//
|
|
|
|
NtGlobalFlag = oldNtGlobalFlag;
|
|
|
|
|
|
//
|
|
// Indicate that the I/O system successfully initialized itself.
|
|
//
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
IopCheckDependencies(
|
|
IN HANDLE KeyHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gets the "DependOnGroup" field for the specified key node
|
|
and determines whether any driver in the group(s) that this entry is
|
|
dependent on has successfully loaded.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Supplies a handle to the key representing the driver in
|
|
question.
|
|
|
|
Return Value:
|
|
|
|
The function value is TRUE if the driver should be loaded, otherwise
|
|
FALSE
|
|
|
|
--*/
|
|
|
|
{
|
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|
UNICODE_STRING groupName;
|
|
BOOLEAN load;
|
|
ULONG length;
|
|
PWSTR source;
|
|
PTREE_ENTRY treeEntry;
|
|
|
|
//
|
|
// Attempt to obtain the "DependOnGroup" key for the specified driver
|
|
// entry. If one does not exist, then simply mark this driver as being
|
|
// one to attempt to load. If it does exist, then check to see whether
|
|
// or not any driver in the groups that it is dependent on has loaded
|
|
// and allow it to load.
|
|
//
|
|
|
|
if (!NT_SUCCESS( IopGetRegistryValue( KeyHandle, L"DependOnGroup", &keyValueInformation ))) {
|
|
return TRUE;
|
|
}
|
|
|
|
length = keyValueInformation->DataLength;
|
|
|
|
source = (PWSTR) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset);
|
|
load = TRUE;
|
|
|
|
while (length) {
|
|
RtlInitUnicodeString( &groupName, source );
|
|
groupName.Length = groupName.MaximumLength;
|
|
treeEntry = IopLookupGroupName( &groupName, FALSE );
|
|
if (treeEntry) {
|
|
if (!treeEntry->DriversLoaded) {
|
|
load = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
length -= groupName.MaximumLength;
|
|
source = (PWSTR) ((PUCHAR) source + groupName.MaximumLength);
|
|
}
|
|
|
|
ExFreePool( keyValueInformation );
|
|
return load;
|
|
}
|
|
|
|
VOID
|
|
IopCreateArcNames(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The loader block contains a table of disk signatures and corresponding
|
|
ARC names. Each device that the loader can access will appear in the
|
|
table. This routine opens each disk device in the system, reads the
|
|
signature and compares it to the table. For each match, it creates a
|
|
symbolic link between the nt device name and the ARC name.
|
|
|
|
The checksum value provided by the loader is the ULONG sum of all
|
|
elements in the checksum, inverted, plus 1:
|
|
checksum = ~sum + 1;
|
|
This way the sum of all of the elements can be calculated here and
|
|
added to the checksum in the loader block. If the result is zero, then
|
|
there is a match.
|
|
|
|
Arguments:
|
|
|
|
LoaderBlock - Supplies a pointer to the loader parameter block that was
|
|
created by the OS Loader.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
STRING arcBootDeviceString;
|
|
UCHAR deviceNameBuffer[64];
|
|
STRING deviceNameString;
|
|
UNICODE_STRING deviceNameUnicodeString;
|
|
PDEVICE_OBJECT deviceObject;
|
|
UCHAR arcNameBuffer[64];
|
|
STRING arcNameString;
|
|
UNICODE_STRING arcNameUnicodeString;
|
|
PFILE_OBJECT fileObject;
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
DISK_GEOMETRY diskGeometry;
|
|
PDRIVE_LAYOUT_INFORMATION driveLayout;
|
|
PLIST_ENTRY listEntry;
|
|
PARC_DISK_SIGNATURE diskBlock;
|
|
ULONG diskNumber;
|
|
ULONG partitionNumber;
|
|
PCHAR arcName;
|
|
PULONG buffer;
|
|
PIRP irp;
|
|
KEVENT event;
|
|
LARGE_INTEGER offset;
|
|
ULONG checkSum;
|
|
ULONG i;
|
|
PVOID tmpPtr;
|
|
BOOLEAN singleBiosDiskFound;
|
|
BOOLEAN bootDiskFound = FALSE;
|
|
PARC_DISK_INFORMATION arcInformation = LoaderBlock->ArcDiskInformation;
|
|
ULONG totalDriverDisksFound = IoGetConfigurationInformation()->DiskCount;
|
|
STRING arcSystemDeviceString;
|
|
STRING osLoaderPathString;
|
|
UNICODE_STRING osLoaderPathUnicodeString;
|
|
|
|
//
|
|
// If a single bios disk was found if there is only a
|
|
// single entry on the disk signature list.
|
|
//
|
|
|
|
singleBiosDiskFound = (arcInformation->DiskSignatures.Flink->Flink ==
|
|
&arcInformation->DiskSignatures) ? (TRUE) : (FALSE);
|
|
|
|
//
|
|
// Get ARC boot device name from loader block.
|
|
//
|
|
|
|
RtlInitAnsiString( &arcBootDeviceString,
|
|
LoaderBlock->ArcBootDeviceName );
|
|
|
|
//
|
|
// Get ARC system device name from loader block.
|
|
//
|
|
|
|
RtlInitAnsiString( &arcSystemDeviceString,
|
|
LoaderBlock->ArcHalDeviceName );
|
|
|
|
//
|
|
// For each disk in the system do the following:
|
|
// 1. open the device
|
|
// 2. get its geometry
|
|
// 3. read the MBR
|
|
// 4. determine ARC name via disk signature and checksum
|
|
// 5. construct ARC name.
|
|
//
|
|
|
|
for (diskNumber = 0;
|
|
diskNumber < totalDriverDisksFound;
|
|
diskNumber++) {
|
|
|
|
//
|
|
// Construct the NT name for a disk and obtain a reference.
|
|
//
|
|
|
|
sprintf( deviceNameBuffer,
|
|
"\\Device\\Harddisk%d\\Partition0",
|
|
diskNumber );
|
|
RtlInitAnsiString( &deviceNameString, deviceNameBuffer );
|
|
status = RtlAnsiStringToUnicodeString( &deviceNameUnicodeString,
|
|
&deviceNameString,
|
|
TRUE );
|
|
if (!NT_SUCCESS( status )) {
|
|
continue;
|
|
}
|
|
|
|
status = IoGetDeviceObjectPointer( &deviceNameUnicodeString,
|
|
FILE_READ_ATTRIBUTES,
|
|
&fileObject,
|
|
&deviceObject );
|
|
RtlFreeUnicodeString( &deviceNameUnicodeString );
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Create IRP for get drive geometry device control.
|
|
//
|
|
|
|
irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|
deviceObject,
|
|
NULL,
|
|
0,
|
|
&diskGeometry,
|
|
sizeof(DISK_GEOMETRY),
|
|
FALSE,
|
|
&event,
|
|
&ioStatusBlock );
|
|
if (!irp) {
|
|
ObDereferenceObject( fileObject );
|
|
continue;
|
|
}
|
|
|
|
KeInitializeEvent( &event,
|
|
NotificationEvent,
|
|
FALSE );
|
|
status = IoCallDriver( deviceObject,
|
|
irp );
|
|
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject( &event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL );
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
ObDereferenceObject( fileObject );
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Get partition information for this disk.
|
|
//
|
|
|
|
status = IoReadPartitionTable( deviceObject,
|
|
diskGeometry.BytesPerSector,
|
|
TRUE,
|
|
&driveLayout );
|
|
|
|
ObDereferenceObject( fileObject );
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Make sure sector size is at least 512 bytes.
|
|
//
|
|
|
|
if (diskGeometry.BytesPerSector < 512) {
|
|
diskGeometry.BytesPerSector = 512;
|
|
}
|
|
|
|
//
|
|
// Check to see if EZ Drive is out there on this disk. If
|
|
// it is then zero out the signature in the drive layout since
|
|
// this will never be written by anyone AND change to offset to
|
|
// actually read sector 1 rather than 0 cause that's what the
|
|
// loader actually did.
|
|
//
|
|
|
|
offset.QuadPart = 0;
|
|
HalExamineMBR( deviceObject,
|
|
diskGeometry.BytesPerSector,
|
|
(ULONG)0x55,
|
|
&tmpPtr );
|
|
|
|
if (tmpPtr) {
|
|
|
|
offset.QuadPart = diskGeometry.BytesPerSector;
|
|
ExFreePool(tmpPtr);
|
|
#ifdef _X86_
|
|
} else if (KeI386MachineType & MACHINE_TYPE_PC_9800_COMPATIBLE) {
|
|
|
|
//
|
|
// PC 9800 compatible machines do not have a standard
|
|
// MBR format and use a different sector for checksuming.
|
|
//
|
|
|
|
offset.QuadPart = 512;
|
|
#endif //_X86_
|
|
}
|
|
|
|
//
|
|
// Allocate buffer for sector read and construct the read request.
|
|
//
|
|
|
|
buffer = ExAllocatePool( NonPagedPoolCacheAlignedMustS,
|
|
diskGeometry.BytesPerSector );
|
|
|
|
if (buffer) {
|
|
irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
|
|
deviceObject,
|
|
buffer,
|
|
diskGeometry.BytesPerSector,
|
|
&offset,
|
|
&event,
|
|
&ioStatusBlock );
|
|
|
|
if (!irp) {
|
|
ExFreePool(driveLayout);
|
|
ExFreePool(buffer);
|
|
continue;
|
|
}
|
|
} else {
|
|
ExFreePool(driveLayout);
|
|
continue;
|
|
}
|
|
KeInitializeEvent( &event,
|
|
NotificationEvent,
|
|
FALSE );
|
|
status = IoCallDriver( deviceObject,
|
|
irp );
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject( &event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL );
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
ExFreePool(driveLayout);
|
|
ExFreePool(buffer);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Calculate MBR sector checksum. Only 512 bytes are used.
|
|
//
|
|
|
|
checkSum = 0;
|
|
for (i = 0; i < 128; i++) {
|
|
checkSum += buffer[i];
|
|
}
|
|
|
|
//
|
|
// For each ARC disk information record in the loader block
|
|
// match the disk signature and checksum to determine its ARC
|
|
// name and construct the NT ARC names symbolic links.
|
|
//
|
|
|
|
for (listEntry = arcInformation->DiskSignatures.Flink;
|
|
listEntry != &arcInformation->DiskSignatures;
|
|
listEntry = listEntry->Flink) {
|
|
|
|
//
|
|
// Get next record and compare disk signatures.
|
|
//
|
|
|
|
diskBlock = CONTAINING_RECORD( listEntry,
|
|
ARC_DISK_SIGNATURE,
|
|
ListEntry );
|
|
|
|
//
|
|
// Compare disk signatures.
|
|
//
|
|
// Or if there is only a single disk drive from
|
|
// both the bios and driver viewpoints then
|
|
// assign an arc name to that drive.
|
|
//
|
|
|
|
if ((singleBiosDiskFound && (totalDriverDisksFound == 1)) ||
|
|
(diskBlock->Signature == driveLayout->Signature &&
|
|
!(diskBlock->CheckSum + checkSum) &&
|
|
diskBlock->ValidPartitionTable)) {
|
|
|
|
//
|
|
// Create unicode device name for physical disk.
|
|
//
|
|
|
|
sprintf( deviceNameBuffer,
|
|
"\\Device\\Harddisk%d\\Partition0",
|
|
diskNumber );
|
|
RtlInitAnsiString( &deviceNameString, deviceNameBuffer );
|
|
status = RtlAnsiStringToUnicodeString( &deviceNameUnicodeString,
|
|
&deviceNameString,
|
|
TRUE );
|
|
if (!NT_SUCCESS( status )) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Create unicode ARC name for this partition.
|
|
//
|
|
|
|
arcName = diskBlock->ArcName;
|
|
sprintf( arcNameBuffer,
|
|
"\\ArcName\\%s",
|
|
arcName );
|
|
RtlInitAnsiString( &arcNameString, arcNameBuffer );
|
|
status = RtlAnsiStringToUnicodeString( &arcNameUnicodeString,
|
|
&arcNameString,
|
|
TRUE );
|
|
if (!NT_SUCCESS( status )) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Create symbolic link between NT device name and ARC name.
|
|
//
|
|
|
|
IoCreateSymbolicLink( &arcNameUnicodeString,
|
|
&deviceNameUnicodeString );
|
|
RtlFreeUnicodeString( &arcNameUnicodeString );
|
|
RtlFreeUnicodeString( &deviceNameUnicodeString );
|
|
|
|
//
|
|
// Create an ARC name for every partition on this disk.
|
|
//
|
|
|
|
for (partitionNumber = 0;
|
|
partitionNumber < driveLayout->PartitionCount;
|
|
partitionNumber++) {
|
|
|
|
//
|
|
// Create unicode NT device name.
|
|
//
|
|
|
|
sprintf( deviceNameBuffer,
|
|
"\\Device\\Harddisk%d\\Partition%d",
|
|
diskNumber,
|
|
partitionNumber+1 );
|
|
RtlInitAnsiString( &deviceNameString, deviceNameBuffer );
|
|
status = RtlAnsiStringToUnicodeString( &deviceNameUnicodeString,
|
|
&deviceNameString,
|
|
TRUE );
|
|
if (!NT_SUCCESS( status )) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Create unicode ARC name for this partition and
|
|
// check to see if this is the boot disk.
|
|
//
|
|
|
|
sprintf( arcNameBuffer,
|
|
"%spartition(%d)",
|
|
arcName,
|
|
partitionNumber+1 );
|
|
RtlInitAnsiString( &arcNameString, arcNameBuffer );
|
|
if (RtlEqualString( &arcNameString,
|
|
&arcBootDeviceString,
|
|
TRUE )) {
|
|
bootDiskFound = TRUE;
|
|
}
|
|
|
|
//
|
|
// See if this is the system partition.
|
|
//
|
|
if (RtlEqualString( &arcNameString,
|
|
&arcSystemDeviceString,
|
|
TRUE )) {
|
|
//
|
|
// We've found the system partition--store it away in the registry
|
|
// to later be transferred to a application-friendly location.
|
|
//
|
|
RtlInitAnsiString( &osLoaderPathString, LoaderBlock->NtHalPathName );
|
|
status = RtlAnsiStringToUnicodeString( &osLoaderPathUnicodeString,
|
|
&osLoaderPathString,
|
|
TRUE );
|
|
|
|
#if DBG
|
|
if (!NT_SUCCESS( status )) {
|
|
DbgPrint("IopCreateArcNames: couldn't allocate unicode string for OsLoader path - %x\n", status);
|
|
}
|
|
#endif // DBG
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
IopStoreSystemPartitionInformation( &deviceNameUnicodeString,
|
|
&osLoaderPathUnicodeString );
|
|
|
|
RtlFreeUnicodeString( &osLoaderPathUnicodeString );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add the NT ARC namespace prefix to the ARC name constructed.
|
|
//
|
|
|
|
sprintf( arcNameBuffer,
|
|
"\\ArcName\\%spartition(%d)",
|
|
arcName,
|
|
partitionNumber+1 );
|
|
RtlInitAnsiString( &arcNameString, arcNameBuffer );
|
|
status = RtlAnsiStringToUnicodeString( &arcNameUnicodeString,
|
|
&arcNameString,
|
|
TRUE );
|
|
if (!NT_SUCCESS( status )) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Create symbolic link between NT device name and ARC name.
|
|
//
|
|
|
|
IoCreateSymbolicLink( &arcNameUnicodeString,
|
|
&deviceNameUnicodeString );
|
|
RtlFreeUnicodeString( &arcNameUnicodeString );
|
|
RtlFreeUnicodeString( &deviceNameUnicodeString );
|
|
}
|
|
|
|
} else {
|
|
|
|
#if DBG
|
|
//
|
|
// Check key indicators to see if this condition may be
|
|
// caused by a viral infection.
|
|
//
|
|
|
|
if (diskBlock->Signature == driveLayout->Signature &&
|
|
(diskBlock->CheckSum + checkSum) != 0 &&
|
|
diskBlock->ValidPartitionTable) {
|
|
DbgPrint("IopCreateArcNames: Virus or duplicate disk signatures\n");
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
ExFreePool( driveLayout );
|
|
ExFreePool( buffer );
|
|
}
|
|
|
|
if (!bootDiskFound) {
|
|
|
|
//
|
|
// Locate the disk block that represents the boot device.
|
|
//
|
|
|
|
diskBlock = NULL;
|
|
for (listEntry = arcInformation->DiskSignatures.Flink;
|
|
listEntry != &arcInformation->DiskSignatures;
|
|
listEntry = listEntry->Flink) {
|
|
|
|
diskBlock = CONTAINING_RECORD( listEntry,
|
|
ARC_DISK_SIGNATURE,
|
|
ListEntry );
|
|
if (strcmp( diskBlock->ArcName, LoaderBlock->ArcBootDeviceName ) == 0) {
|
|
break;
|
|
}
|
|
diskBlock = NULL;
|
|
}
|
|
|
|
if (diskBlock) {
|
|
|
|
//
|
|
// This could be a CdRom boot. Search all of the NT CdRoms
|
|
// to locate a checksum match on the diskBlock found. If
|
|
// there is a match, assign the ARC name to the CdRom.
|
|
//
|
|
|
|
irp = NULL;
|
|
buffer = ExAllocatePool( NonPagedPoolCacheAlignedMustS,
|
|
2048 );
|
|
if (buffer) {
|
|
|
|
//
|
|
// Construct the NT names for CdRoms and search each one
|
|
// for a checksum match. If found, create the ARC Name
|
|
// symbolic link.
|
|
//
|
|
|
|
for (diskNumber = 0; TRUE; diskNumber++) {
|
|
|
|
sprintf( deviceNameBuffer,
|
|
"\\Device\\CdRom%d",
|
|
diskNumber );
|
|
RtlInitAnsiString( &deviceNameString, deviceNameBuffer );
|
|
status = RtlAnsiStringToUnicodeString( &deviceNameUnicodeString,
|
|
&deviceNameString,
|
|
TRUE );
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
status = IoGetDeviceObjectPointer( &deviceNameUnicodeString,
|
|
FILE_READ_ATTRIBUTES,
|
|
&fileObject,
|
|
&deviceObject );
|
|
if (!NT_SUCCESS( status )) {
|
|
|
|
//
|
|
// All CdRoms have been processed.
|
|
//
|
|
|
|
RtlFreeUnicodeString( &deviceNameUnicodeString );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Read the block for the checksum calculation.
|
|
//
|
|
|
|
offset.QuadPart = 0x8000;
|
|
irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
|
|
deviceObject,
|
|
buffer,
|
|
2048,
|
|
&offset,
|
|
&event,
|
|
&ioStatusBlock );
|
|
checkSum = 0;
|
|
if (irp) {
|
|
KeInitializeEvent( &event,
|
|
NotificationEvent,
|
|
FALSE );
|
|
status = IoCallDriver( deviceObject,
|
|
irp );
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject( &event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL );
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
//
|
|
// Calculate MBR sector checksum.
|
|
// 2048 bytes are used.
|
|
//
|
|
|
|
for (i = 0; i < 2048 / sizeof(ULONG) ; i++) {
|
|
checkSum += buffer[i];
|
|
}
|
|
}
|
|
}
|
|
ObDereferenceObject( fileObject );
|
|
|
|
if (!(diskBlock->CheckSum + checkSum)) {
|
|
|
|
//
|
|
// This is the boot CdRom. Create the symlink for
|
|
// the ARC name from the loader block.
|
|
//
|
|
|
|
sprintf( arcNameBuffer,
|
|
"\\ArcName\\%s",
|
|
LoaderBlock->ArcBootDeviceName );
|
|
RtlInitAnsiString( &arcNameString, arcNameBuffer );
|
|
status = RtlAnsiStringToUnicodeString( &arcNameUnicodeString,
|
|
&arcNameString,
|
|
TRUE );
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
IoCreateSymbolicLink( &arcNameUnicodeString,
|
|
&deviceNameUnicodeString );
|
|
RtlFreeUnicodeString( &arcNameUnicodeString );
|
|
}
|
|
RtlFreeUnicodeString( &deviceNameUnicodeString );
|
|
break;
|
|
}
|
|
RtlFreeUnicodeString( &deviceNameUnicodeString );
|
|
}
|
|
}
|
|
ExFreePool(buffer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
GENERIC_MAPPING IopFileMapping = {
|
|
STANDARD_RIGHTS_READ |
|
|
FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE,
|
|
STANDARD_RIGHTS_WRITE |
|
|
FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE,
|
|
STANDARD_RIGHTS_EXECUTE |
|
|
SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_EXECUTE,
|
|
FILE_ALL_ACCESS
|
|
};
|
|
|
|
GENERIC_MAPPING IopCompletionMapping = {
|
|
STANDARD_RIGHTS_READ |
|
|
IO_COMPLETION_QUERY_STATE,
|
|
STANDARD_RIGHTS_WRITE |
|
|
IO_COMPLETION_MODIFY_STATE,
|
|
STANDARD_RIGHTS_EXECUTE |
|
|
SYNCHRONIZE,
|
|
IO_COMPLETION_ALL_ACCESS
|
|
};
|
|
|
|
BOOLEAN
|
|
IopCreateObjectTypes(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates the object types used by the I/O system and its
|
|
components. The object types created are:
|
|
|
|
Adapter
|
|
Controller
|
|
Device
|
|
Driver
|
|
File
|
|
I/O Completion
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
The function value is a BOOLEAN indicating whether or not the object
|
|
types were successfully created.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
OBJECT_TYPE_INITIALIZER objectTypeInitializer;
|
|
UNICODE_STRING nameString;
|
|
|
|
#if DBG
|
|
IopCreateFileEventId = RtlCreateEventId( NULL,
|
|
0,
|
|
"CreateFile",
|
|
9,
|
|
RTL_EVENT_PUNICODE_STRING_PARAM, "FileName", 0,
|
|
RTL_EVENT_FLAGS_PARAM, "", 13,
|
|
GENERIC_READ, "GenericRead",
|
|
GENERIC_WRITE, "GenericWrite",
|
|
GENERIC_EXECUTE, "GenericExecute",
|
|
GENERIC_ALL, "GenericAll",
|
|
FILE_READ_DATA, "Read",
|
|
FILE_WRITE_DATA, "Write",
|
|
FILE_APPEND_DATA, "Append",
|
|
FILE_EXECUTE, "Execute",
|
|
FILE_READ_EA, "ReadEa",
|
|
FILE_WRITE_EA, "WriteEa",
|
|
FILE_DELETE_CHILD, "DeleteChild",
|
|
FILE_READ_ATTRIBUTES, "ReadAttributes",
|
|
FILE_WRITE_ATTRIBUTES, "WriteAttributes",
|
|
RTL_EVENT_FLAGS_PARAM, "", 3,
|
|
FILE_SHARE_READ, "ShareRead",
|
|
FILE_SHARE_WRITE, "ShareWrite",
|
|
FILE_SHARE_DELETE, "ShareDelete",
|
|
RTL_EVENT_ENUM_PARAM, "", 5,
|
|
FILE_SUPERSEDE, "Supersede",
|
|
FILE_OPEN, "Open",
|
|
FILE_CREATE, "Create",
|
|
FILE_OPEN_IF, "OpenIf",
|
|
FILE_OVERWRITE, "Overwrite",
|
|
RTL_EVENT_FLAGS_PARAM, "", 14,
|
|
FILE_DIRECTORY_FILE, "OpenDirectory",
|
|
FILE_WRITE_THROUGH, "WriteThrough",
|
|
FILE_SEQUENTIAL_ONLY, "Sequential",
|
|
FILE_NO_INTERMEDIATE_BUFFERING, "NoBuffering",
|
|
FILE_SYNCHRONOUS_IO_ALERT, "Synchronous",
|
|
FILE_SYNCHRONOUS_IO_NONALERT, "SynchronousNoAlert",
|
|
FILE_NON_DIRECTORY_FILE, "OpenNonDirectory",
|
|
FILE_CREATE_TREE_CONNECTION, "CreateTreeConnect",
|
|
FILE_COMPLETE_IF_OPLOCKED, "CompleteIfOpLocked",
|
|
FILE_NO_EA_KNOWLEDGE, "NoEas",
|
|
FILE_RANDOM_ACCESS, "Random",
|
|
FILE_DELETE_ON_CLOSE, "DeleteOnClose",
|
|
FILE_OPEN_BY_FILE_ID, "OpenById",
|
|
FILE_OPEN_FOR_BACKUP_INTENT, "BackupIntent",
|
|
RTL_EVENT_ENUM_PARAM, "", 2,
|
|
CreateFileTypeNamedPipe, "NamedPiped",
|
|
CreateFileTypeMailslot, "MailSlot",
|
|
RTL_EVENT_ULONG_PARAM, "Handle", 0,
|
|
RTL_EVENT_STATUS_PARAM, "", 0,
|
|
RTL_EVENT_ENUM_PARAM, "", 6,
|
|
FILE_SUPERSEDED, "Superseded",
|
|
FILE_OPENED, "Opened",
|
|
FILE_CREATED, "Created",
|
|
FILE_OVERWRITTEN, "Truncated",
|
|
FILE_EXISTS, "Exists",
|
|
FILE_DOES_NOT_EXIST, "DoesNotExist"
|
|
);
|
|
|
|
IopReadFileEventId = RtlCreateEventId( NULL,
|
|
0,
|
|
"ReadFile",
|
|
6,
|
|
RTL_EVENT_ULONG_PARAM, "Handle", 0,
|
|
RTL_EVENT_ULONG_PARAM, "Buffer", 0,
|
|
RTL_EVENT_ULONG_PARAM, "Length", 0,
|
|
RTL_EVENT_STATUS_PARAM, "Io", 0,
|
|
RTL_EVENT_ULONG_PARAM, "IoLength", 0,
|
|
RTL_EVENT_STATUS_PARAM, "", 0
|
|
);
|
|
|
|
IopWriteFileEventId = RtlCreateEventId( NULL,
|
|
0,
|
|
"WriteFile",
|
|
6,
|
|
RTL_EVENT_ULONG_PARAM, "Handle", 0,
|
|
RTL_EVENT_ULONG_PARAM, "Buffer", 0,
|
|
RTL_EVENT_ULONG_PARAM, "Length", 0,
|
|
RTL_EVENT_STATUS_PARAM, "Io", 0,
|
|
RTL_EVENT_ULONG_PARAM, "IoLength", 0,
|
|
RTL_EVENT_STATUS_PARAM, "", 0
|
|
);
|
|
IopCloseFileEventId = RtlCreateEventId( NULL,
|
|
0,
|
|
"CloseFile",
|
|
2,
|
|
RTL_EVENT_ULONG_PARAM, "Handle", 0,
|
|
RTL_EVENT_STATUS_PARAM, "", 0
|
|
);
|
|
#endif // DBG
|
|
|
|
//
|
|
// Initialize the common fields of the Object Type Initializer record
|
|
//
|
|
|
|
RtlZeroMemory( &objectTypeInitializer, sizeof( objectTypeInitializer ) );
|
|
objectTypeInitializer.Length = sizeof( objectTypeInitializer );
|
|
objectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
|
|
objectTypeInitializer.GenericMapping = IopFileMapping;
|
|
objectTypeInitializer.PoolType = NonPagedPool;
|
|
objectTypeInitializer.ValidAccessMask = FILE_ALL_ACCESS;
|
|
objectTypeInitializer.UseDefaultObject = TRUE;
|
|
|
|
|
|
//
|
|
// Create the object type for adapter objects.
|
|
//
|
|
|
|
RtlInitUnicodeString( &nameString, L"Adapter" );
|
|
// objectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( struct _ADAPTER_OBJECT );
|
|
if (!NT_SUCCESS( ObCreateObjectType( &nameString,
|
|
&objectTypeInitializer,
|
|
(PSECURITY_DESCRIPTOR) NULL,
|
|
&IoAdapterObjectType ))) {
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef _PNP_POWER_
|
|
//
|
|
// Create the object type for device helper objects.
|
|
//
|
|
|
|
RtlInitUnicodeString( &nameString, L"DeviceHandler" );
|
|
if (!NT_SUCCESS( ObCreateObjectType( &nameString,
|
|
&objectTypeInitializer,
|
|
(PSECURITY_DESCRIPTOR) NULL,
|
|
&IoDeviceHandlerObjectType ))) {
|
|
return FALSE;
|
|
}
|
|
IoDeviceHandlerObjectSize = sizeof(DEVICE_HANDLER_OBJECT);
|
|
|
|
#endif
|
|
|
|
//
|
|
// Create the object type for controller objects.
|
|
//
|
|
|
|
RtlInitUnicodeString( &nameString, L"Controller" );
|
|
objectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( CONTROLLER_OBJECT );
|
|
if (!NT_SUCCESS( ObCreateObjectType( &nameString,
|
|
&objectTypeInitializer,
|
|
(PSECURITY_DESCRIPTOR) NULL,
|
|
&IoControllerObjectType ))) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Create the object type for device objects.
|
|
//
|
|
|
|
RtlInitUnicodeString( &nameString, L"Device" );
|
|
objectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( DEVICE_OBJECT );
|
|
objectTypeInitializer.ParseProcedure = IopParseDevice;
|
|
#ifdef _PNP_POWER_
|
|
objectTypeInitializer.DeleteProcedure = IopDeleteDevice;
|
|
#endif // _PNP_POWER_
|
|
objectTypeInitializer.SecurityProcedure = IopGetSetSecurityObject;
|
|
objectTypeInitializer.QueryNameProcedure = (OB_QUERYNAME_METHOD)NULL;
|
|
if (!NT_SUCCESS( ObCreateObjectType( &nameString,
|
|
&objectTypeInitializer,
|
|
(PSECURITY_DESCRIPTOR) NULL,
|
|
&IoDeviceObjectType ))) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Create the object type for driver objects.
|
|
//
|
|
|
|
RtlInitUnicodeString( &nameString, L"Driver" );
|
|
objectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( DRIVER_OBJECT );
|
|
objectTypeInitializer.ParseProcedure = (OB_PARSE_METHOD) NULL;
|
|
objectTypeInitializer.DeleteProcedure = IopDeleteDriver;
|
|
objectTypeInitializer.SecurityProcedure = (OB_SECURITY_METHOD) NULL;
|
|
objectTypeInitializer.QueryNameProcedure = (OB_QUERYNAME_METHOD)NULL;
|
|
if (!NT_SUCCESS( ObCreateObjectType( &nameString,
|
|
&objectTypeInitializer,
|
|
(PSECURITY_DESCRIPTOR) NULL,
|
|
&IoDriverObjectType ))) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Create the object type for I/O completion objects.
|
|
//
|
|
|
|
RtlInitUnicodeString( &nameString, L"IoCompletion" );
|
|
objectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( KQUEUE );
|
|
objectTypeInitializer.InvalidAttributes = OBJ_PERMANENT | OBJ_OPENLINK;
|
|
objectTypeInitializer.GenericMapping = IopCompletionMapping;
|
|
objectTypeInitializer.ValidAccessMask = IO_COMPLETION_ALL_ACCESS;
|
|
objectTypeInitializer.DeleteProcedure = IopDeleteIoCompletion;
|
|
if (!NT_SUCCESS( ObCreateObjectType( &nameString,
|
|
&objectTypeInitializer,
|
|
(PSECURITY_DESCRIPTOR) NULL,
|
|
&IoCompletionObjectType ))) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Create the object type for file objects.
|
|
//
|
|
|
|
RtlInitUnicodeString( &nameString, L"File" );
|
|
objectTypeInitializer.DefaultPagedPoolCharge = IO_FILE_OBJECT_PAGED_POOL_CHARGE;
|
|
objectTypeInitializer.DefaultNonPagedPoolCharge = IO_FILE_OBJECT_NON_PAGED_POOL_CHARGE +
|
|
sizeof( FILE_OBJECT );
|
|
objectTypeInitializer.InvalidAttributes = OBJ_PERMANENT | OBJ_EXCLUSIVE | OBJ_OPENLINK;
|
|
objectTypeInitializer.GenericMapping = IopFileMapping;
|
|
objectTypeInitializer.ValidAccessMask = FILE_ALL_ACCESS;
|
|
objectTypeInitializer.MaintainHandleCount = TRUE;
|
|
objectTypeInitializer.CloseProcedure = IopCloseFile;
|
|
objectTypeInitializer.DeleteProcedure = IopDeleteFile;
|
|
objectTypeInitializer.ParseProcedure = IopParseFile;
|
|
objectTypeInitializer.SecurityProcedure = IopGetSetSecurityObject;
|
|
objectTypeInitializer.QueryNameProcedure = IopQueryName;
|
|
objectTypeInitializer.UseDefaultObject = FALSE;
|
|
|
|
if (!NT_SUCCESS( ObCreateObjectType( &nameString,
|
|
&objectTypeInitializer,
|
|
(PSECURITY_DESCRIPTOR) NULL,
|
|
&IoFileObjectType ))) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PTREE_ENTRY
|
|
IopCreateEntry(
|
|
IN PUNICODE_STRING GroupName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates an entry for the specified group name suitable for
|
|
being inserted into the group name tree.
|
|
|
|
Arguments:
|
|
|
|
GroupName - Specifies the name of the group for the entry.
|
|
|
|
Return Value:
|
|
|
|
The function value is a pointer to the created entry.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PTREE_ENTRY treeEntry;
|
|
|
|
//
|
|
// Allocate and initialize an entry suitable for placing into the group
|
|
// name tree.
|
|
//
|
|
|
|
treeEntry = ExAllocatePool( PagedPool,
|
|
sizeof( TREE_ENTRY ) + GroupName->Length );
|
|
if (!treeEntry) {
|
|
ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
|
|
}
|
|
|
|
RtlZeroMemory( treeEntry, sizeof( TREE_ENTRY ) );
|
|
treeEntry->GroupName.Length = GroupName->Length;
|
|
treeEntry->GroupName.MaximumLength = GroupName->Length;
|
|
treeEntry->GroupName.Buffer = (PWCHAR) (treeEntry + 1);
|
|
RtlCopyMemory( treeEntry->GroupName.Buffer,
|
|
GroupName->Buffer,
|
|
GroupName->Length );
|
|
|
|
return treeEntry;
|
|
}
|
|
|
|
BOOLEAN
|
|
IopCreateRootDirectories(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to create the object manager directory objects
|
|
to contain the various device and file system driver objects.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
The function value is a BOOLEAN indicating whether or not the directory
|
|
objects were successfully created.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE handle;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
UNICODE_STRING nameString;
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// Create the root directory object for the \Driver directory.
|
|
//
|
|
|
|
RtlInitUnicodeString( &nameString, L"\\Driver" );
|
|
InitializeObjectAttributes( &objectAttributes,
|
|
&nameString,
|
|
OBJ_PERMANENT,
|
|
(HANDLE) NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL );
|
|
|
|
status = NtCreateDirectoryObject( &handle,
|
|
DIRECTORY_ALL_ACCESS,
|
|
&objectAttributes );
|
|
if (!NT_SUCCESS( status )) {
|
|
return FALSE;
|
|
} else {
|
|
(VOID) NtClose( handle );
|
|
}
|
|
|
|
//
|
|
// Create the root directory object for the \FileSystem directory.
|
|
//
|
|
|
|
RtlInitUnicodeString( &nameString, L"\\FileSystem" );
|
|
|
|
status = NtCreateDirectoryObject( &handle,
|
|
DIRECTORY_ALL_ACCESS,
|
|
&objectAttributes );
|
|
if (!NT_SUCCESS( status )) {
|
|
return FALSE;
|
|
} else {
|
|
(VOID) NtClose( handle );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
IopFreeGroupTree(
|
|
PTREE_ENTRY TreeEntry
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to free a node from the group dependency tree.
|
|
It is invoked the first time with the root of the tree, and thereafter
|
|
recursively to walk the tree and remove the nodes.
|
|
|
|
Arguments:
|
|
|
|
TreeEntry - Supplies a pointer to the node to be freed.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Simply walk the tree in ascending order from the bottom up and free
|
|
// each node along the way.
|
|
//
|
|
|
|
if (TreeEntry->Left) {
|
|
IopFreeGroupTree( TreeEntry->Left );
|
|
}
|
|
|
|
if (TreeEntry->Sibling) {
|
|
IopFreeGroupTree( TreeEntry->Sibling );
|
|
}
|
|
|
|
if (TreeEntry->Right) {
|
|
IopFreeGroupTree( TreeEntry->Right );
|
|
}
|
|
|
|
//
|
|
// All of the children and siblings for this node have been freed, so
|
|
// now free this node as well.
|
|
//
|
|
|
|
ExFreePool( TreeEntry );
|
|
}
|
|
|
|
NTSTATUS
|
|
IopInitializeAttributesAndCreateObject(
|
|
IN PUNICODE_STRING ObjectName,
|
|
IN OUT POBJECT_ATTRIBUTES ObjectAttributes,
|
|
OUT PDRIVER_OBJECT *DriverObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to initialize a set of object attributes and
|
|
to create a driver object.
|
|
|
|
Arguments:
|
|
|
|
ObjectName - Supplies the name of the driver object.
|
|
|
|
ObjectAttributes - Supplies a pointer to the object attributes structure
|
|
to be initialized.
|
|
|
|
DriverObject - Supplies a variable to receive a pointer to the resultant
|
|
created driver object.
|
|
|
|
Return Value:
|
|
|
|
The function value is the final status of the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// Simply initialize the object attributes and create the driver object.
|
|
//
|
|
|
|
InitializeObjectAttributes( ObjectAttributes,
|
|
ObjectName,
|
|
OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
|
|
(HANDLE) NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL );
|
|
|
|
status = ObCreateObject( KeGetPreviousMode(),
|
|
IoDriverObjectType,
|
|
ObjectAttributes,
|
|
KernelMode,
|
|
(PVOID) NULL,
|
|
//#if _PNP_POWER_
|
|
(ULONG) (sizeof( DRIVER_OBJECT ) + sizeof ( DRIVER_EXTENSION )),
|
|
//#else
|
|
#if 0
|
|
(ULONG) sizeof( DRIVER_OBJECT ),
|
|
#endif
|
|
0,
|
|
0,
|
|
(PVOID *)DriverObject );
|
|
return status;
|
|
}
|
|
|
|
#ifdef _PNP_POWER_
|
|
|
|
BOOLEAN
|
|
IopInitializeSingleBootDriver(
|
|
IN HANDLE KeyHandle,
|
|
IN PBOOT_DRIVER_LIST_ENTRY BootDriver,
|
|
OUT PUNICODE_STRING DriverName OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to initialize a single boot driver.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Supplies a handle to the driver's key in the Services list.
|
|
|
|
BootDriver - Supplies a pointer to the driver's node in the loader's
|
|
boot driver list.
|
|
|
|
DriverName - Optionally receives the driver name used for this driver object.
|
|
(NOTE: If this argument is specified, then it is the caller's
|
|
responsibility to free the memory allocated for the string buffer.)
|
|
|
|
Return Value:
|
|
|
|
The function value is a BOOLEAN indicating whether or not the boot driver
|
|
was successfully initialized.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING completeName;
|
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|
UNICODE_STRING groupName;
|
|
PTREE_ENTRY treeEntry;
|
|
PLDR_DATA_TABLE_ENTRY driverEntry;
|
|
BOOLEAN success = FALSE;
|
|
|
|
//
|
|
// See if this driver has an ObjectName value. If so, this value
|
|
// overrides the default ("\Driver" or "\FileSystem").
|
|
//
|
|
status = IopGetDriverNameFromKeyNode(KeyHandle,
|
|
&completeName
|
|
);
|
|
if(!NT_SUCCESS(status)) {
|
|
|
|
#if DBG
|
|
DbgPrint("IOINIT: Could not get driver name for %wZ\n",
|
|
&BootDriver->RegistryPath
|
|
);
|
|
#endif // DBG
|
|
|
|
} else {
|
|
|
|
status = IopGetRegistryValue(KeyHandle,
|
|
REGSTR_VALUE_GROUP,
|
|
&keyValueInformation
|
|
);
|
|
if(NT_SUCCESS(status)) {
|
|
if((keyValueInformation->Type == REG_SZ) &&
|
|
keyValueInformation->DataLength) {
|
|
groupName.MaximumLength = groupName.Length = (USHORT)keyValueInformation->DataLength;
|
|
groupName.Buffer = (PWCHAR)KEY_VALUE_DATA(keyValueInformation);
|
|
treeEntry = IopLookupGroupName(&groupName, TRUE);
|
|
} else {
|
|
treeEntry = (PTREE_ENTRY)NULL;
|
|
}
|
|
ExFreePool(keyValueInformation);
|
|
} else {
|
|
treeEntry = (PTREE_ENTRY)NULL;
|
|
}
|
|
|
|
driverEntry = BootDriver->LdrEntry;
|
|
|
|
if(IopCheckDependencies(KeyHandle) &&
|
|
IopInitializeBuiltinDriver(&completeName,
|
|
&BootDriver->RegistryPath,
|
|
(PDRIVER_INITIALIZE)driverEntry->EntryPoint )) {
|
|
|
|
success = TRUE;
|
|
if(treeEntry) {
|
|
treeEntry->DriversLoaded++;
|
|
}
|
|
} else {
|
|
PLIST_ENTRY NextEntry;
|
|
PLDR_DATA_TABLE_ENTRY DataTableEntry;
|
|
|
|
NextEntry = PsLoadedModuleList.Flink;
|
|
while(NextEntry != &PsLoadedModuleList) {
|
|
DataTableEntry = CONTAINING_RECORD(NextEntry,
|
|
LDR_DATA_TABLE_ENTRY,
|
|
InLoadOrderLinks);
|
|
if(RtlEqualString((PSTRING)&driverEntry->BaseDllName,
|
|
(PSTRING)&DataTableEntry->BaseDllName,
|
|
TRUE)) {
|
|
|
|
driverEntry->Flags |= LDRP_FAILED_BUILTIN_LOAD;
|
|
DataTableEntry->Flags |= LDRP_FAILED_BUILTIN_LOAD;
|
|
break;
|
|
}
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
}
|
|
|
|
if(success && ARGUMENT_PRESENT(DriverName)) {
|
|
*DriverName = completeName;
|
|
} else {
|
|
ExFreePool(completeName.Buffer);
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
#endif // _PNP_POWER_
|
|
|
|
BOOLEAN
|
|
IopInitializeBootDrivers(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
|
OUT PDRIVER_OBJECT *PreviousDriver
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to initialize the boot drivers that were loaded
|
|
by the OS Loader. The list of drivers is provided as part of the loader
|
|
parameter block.
|
|
|
|
** _PNP_POWER_ Only **
|
|
Two passes are made over the loader parameter block. In the first pass,
|
|
all HAL bus extenders are loaded. This is an iterative process, where
|
|
the initialization of one bus extender may materialize other buses--perhaps
|
|
for extenders that have already initialized. Also during this pass, all
|
|
enumerable devices are found and registered in HKLM\System\Enum.
|
|
|
|
In the second pass, all other boot drivers are loaded. Since Plug and Play
|
|
device enumeration was done as part of the first pass, all PnP information
|
|
is available to drivers initialized in the second pass.
|
|
|
|
Arguments:
|
|
|
|
LoaderBlock - Supplies a pointer to the loader parameter block, created
|
|
by the OS Loader.
|
|
|
|
Previous Driver - Supplies a variable to receive the address of the
|
|
driver object chain created by initializing the drivers.
|
|
|
|
Return Value:
|
|
|
|
The function value is a BOOLEAN indicating whether or not the boot
|
|
drivers were successfully initialized.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING completeName;
|
|
#if 0
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
#endif
|
|
UNICODE_STRING rawFsName;
|
|
NTSTATUS status;
|
|
PLIST_ENTRY nextEntry;
|
|
PBOOT_DRIVER_LIST_ENTRY bootDriver;
|
|
HANDLE keyHandle;
|
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|
#ifdef _PNP_POWER_
|
|
ULONG bootInitPass, serviceInstanceCount, i;
|
|
BOOLEAN isBusExtender, success;
|
|
PPLUGPLAY_BUS_ENUMERATOR busEnumerator;
|
|
HANDLE serviceEnumHandle;
|
|
UNICODE_STRING serviceEnumName;
|
|
PHAL_BUS_INFORMATION oldBusInformation;
|
|
ULONG oldBusCount;
|
|
PLIST_ENTRY nextBusInstance;
|
|
HANDLE driverHandle;
|
|
PDRIVER_OBJECT driverObject;
|
|
#else
|
|
PLDR_DATA_TABLE_ENTRY driverEntry;
|
|
UNICODE_STRING groupName;
|
|
PTREE_ENTRY treeEntry;
|
|
#endif // _PNP_POWER_
|
|
|
|
UNREFERENCED_PARAMETER( PreviousDriver );
|
|
|
|
//
|
|
// Initialize the built-in RAW file system driver.
|
|
//
|
|
|
|
RtlInitUnicodeString( &rawFsName, L"\\FileSystem\\RAW" );
|
|
RtlInitUnicodeString( &completeName, L"" );
|
|
if (!IopInitializeBuiltinDriver( &rawFsName,
|
|
&completeName,
|
|
RawInitialize )) {
|
|
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Failed to initialize RAW filsystem \n" );
|
|
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef _PNP_POWER_
|
|
//
|
|
// For the bus/device enumeration, we must acquire exclusive (write) access to
|
|
// resources for the PnP device portions of the registry, as well as to
|
|
// the PnP bus list.
|
|
//
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceExclusive(&PpBusResource, TRUE);
|
|
ExAcquireResourceExclusive(&PpRegistryDeviceResource, TRUE);
|
|
|
|
//
|
|
// Make two passes through the list of boot drivers--first enumerating/loading
|
|
// all bus extenders, and then loading all other boot drivers.
|
|
//
|
|
success = TRUE;
|
|
for(bootInitPass = 0; bootInitPass < 2; bootInitPass++) {
|
|
//
|
|
// Traverse the list of boot drivers, looking for appropriate drivers
|
|
// for this initialization pass.
|
|
//
|
|
for(nextEntry = LoaderBlock->BootDriverListHead.Flink;
|
|
nextEntry != &LoaderBlock->BootDriverListHead;
|
|
nextEntry = nextEntry->Flink) {
|
|
|
|
bootDriver = CONTAINING_RECORD(nextEntry,
|
|
BOOT_DRIVER_LIST_ENTRY,
|
|
Link
|
|
);
|
|
//
|
|
// Open the driver's registry key.
|
|
//
|
|
status = IopOpenRegistryKey(&keyHandle,
|
|
NULL,
|
|
&bootDriver->RegistryPath,
|
|
KEY_READ,
|
|
FALSE
|
|
);
|
|
if(!NT_SUCCESS(status)) {
|
|
//
|
|
// Something is quite wrong. The driver must have a key in the
|
|
// registry, or the OS Loader wouldn't have loaded it in the first
|
|
// first place. Skip this driver and keep going.
|
|
//
|
|
#if DBG
|
|
DbgPrint("IOINIT: IopInitializeBootDrivers couldn't open registry\n");
|
|
DbgPrint(" key for %wZ. Cannot initialize driver.\n",
|
|
&bootDriver->RegistryPath );
|
|
#endif // DBG
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Find out whether this driver is a bus extender.
|
|
//
|
|
isBusExtender = FALSE;
|
|
status = IopGetRegistryValue(keyHandle,
|
|
REGSTR_VALUE_PLUGPLAY_SERVICE_TYPE,
|
|
&keyValueInformation
|
|
);
|
|
if(NT_SUCCESS(status)) {
|
|
if((keyValueInformation->Type == REG_DWORD) &&
|
|
(keyValueInformation->DataLength >= sizeof(ULONG))) {
|
|
|
|
isBusExtender = (PlugPlayServiceBusExtender ==
|
|
(PLUGPLAY_SERVICE_TYPE)(*(PULONG)KEY_VALUE_DATA(keyValueInformation)));
|
|
}
|
|
ExFreePool(keyValueInformation);
|
|
}
|
|
|
|
if(isBusExtender) {
|
|
if(bootInitPass != 0) {
|
|
//
|
|
// All bus extenders are initialized in the first pass.
|
|
//
|
|
goto BootDriverInitCleanup;
|
|
}
|
|
//
|
|
// Find this bus extender in our bus enumerator list. Determine
|
|
// whether we need to initialize this bus extender now.
|
|
//
|
|
if(!(busEnumerator = PiBusEnumeratorFromRegistryPath(&bootDriver->RegistryPath))) {
|
|
#if DBG
|
|
DbgPrint("IOINIT: IopInitializeBootDrivers couldn't find the bus\n");
|
|
DbgPrint(" enumerator %wZ. Cannot initialize driver.\n",
|
|
&bootDriver->RegistryPath
|
|
);
|
|
#endif // DBG
|
|
success = FALSE;
|
|
goto BootDriverInitCleanup;
|
|
|
|
}
|
|
|
|
//
|
|
// Initialize the bus extender.
|
|
//
|
|
if(!IopInitializeSingleBootDriver(keyHandle, bootDriver, &completeName)) {
|
|
#if DBG
|
|
DbgPrint("IOINIT: IopInitializeBootDrivers couldn't initialize bus\n");
|
|
DbgPrint(" extender %wZ.\n", &bootDriver->FilePath);
|
|
#endif // DBG
|
|
//
|
|
// This bus extender failed to initialize. This will be reflected by
|
|
// the absence of a driver object pointer in its DriverObject field.
|
|
// If the bus enumerator specified any Plug&Play IDs for buses it
|
|
// controlled, then we will leave it in our bus list, so that if
|
|
// enumeration turns up a bus of this type, we will be able to match it
|
|
// up with its corresponding extender, and then inform the user that
|
|
// there is a problem with the bus driver for the newly found bus.
|
|
//
|
|
if(!busEnumerator->PlugPlayIDCount) {
|
|
//
|
|
// There's no need to keep this around, so remove from the bus
|
|
// extender list, and free its memory.
|
|
//
|
|
RemoveEntryList(&(busEnumerator->BusEnumeratorListEntry));
|
|
ExFreePool(busEnumerator->ServiceName.Buffer);
|
|
ExFreePool(busEnumerator);
|
|
}
|
|
goto BootDriverInitCleanup;
|
|
}
|
|
#if 1
|
|
busEnumerator->DriverName = completeName;
|
|
#else
|
|
//
|
|
// The bus extender initialized successfully. Store away a pointer to its
|
|
// driver object, so that we can call the driver's 'add device instance'
|
|
// routine when we enumerate buses that this driver should control. We also
|
|
// need this pointer, so that we can call the driver's bus detection routine
|
|
// (if supplied) after we've found all enumerable buses.
|
|
//
|
|
// Note that it is OK for us to be storing away a pointer to the device object
|
|
// (even though in general this is a big no-no, since the driver unload is
|
|
// allowed/disallowed based on opened device objects, regardless of the driver
|
|
// object's refcount). In this case, though, these are boot devices and can't
|
|
// be unloaded anyway. Even if they weren't, it is acceptable to store away
|
|
// a driver object pointer to a bus extender, because these drivers should never
|
|
// supply an unload entry point.
|
|
//
|
|
// First, open the driver object.
|
|
//
|
|
InitializeObjectAttributes(&objectAttributes,
|
|
&completeName,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
status = ObOpenObjectByName(&objectAttributes,
|
|
IoDriverObjectType,
|
|
KernelMode,
|
|
NULL,
|
|
FILE_READ_ATTRIBUTES,
|
|
NULL,
|
|
&driverHandle
|
|
);
|
|
ExFreePool(completeName.Buffer);
|
|
if(NT_SUCCESS(status)) {
|
|
//
|
|
// Now reference the driver object.
|
|
//
|
|
status = ObReferenceObjectByHandle(driverHandle,
|
|
0,
|
|
IoDriverObjectType,
|
|
KernelMode,
|
|
&driverObject,
|
|
NULL
|
|
);
|
|
NtClose(driverHandle);
|
|
}
|
|
|
|
if(!NT_SUCCESS(status)) {
|
|
//
|
|
// Treat this case just as if the driver had failed to initialize. Again,
|
|
// we will keep the bus extender node in our list only if it specifies
|
|
// Plug & Play IDs which we may need for later reference.
|
|
//
|
|
#if DBG
|
|
DbgPrint("IOINIT: IopInitializeBootDrivers couldn't retrieve driver object\n");
|
|
DbgPrint(" for %wZ (status %x).\n", &bootDriver->RegistryPath, status);
|
|
#endif // DBG
|
|
if(!busEnumerator->PlugPlayIDCount) {
|
|
//
|
|
// There's no need to keep this around, so remove from the bus
|
|
// extender list, and free its memory.
|
|
//
|
|
RemoveEntryList(&(busEnumerator->BusEnumeratorListEntry));
|
|
ExFreePool(busEnumerator->ServiceName.Buffer);
|
|
ExFreePool(busEnumerator);
|
|
}
|
|
goto BootDriverInitCleanup;
|
|
}
|
|
|
|
busEnumerator->DriverObject = driverObject;
|
|
#endif // 1
|
|
} else { // this driver is not a bus extender
|
|
|
|
if(bootInitPass != 1) {
|
|
//
|
|
// All non-bus extender drivers are initialized in the second pass.
|
|
//
|
|
goto BootDriverInitCleanup;
|
|
}
|
|
//
|
|
// Initialize the driver (ignore failures).
|
|
//
|
|
IopInitializeSingleBootDriver(keyHandle, bootDriver, NULL);
|
|
}
|
|
|
|
BootDriverInitCleanup:
|
|
|
|
NtClose(keyHandle);
|
|
|
|
if(!success) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(bootInitPass == 0) {
|
|
//
|
|
// We have now initialized all bus extender drivers. We must now check
|
|
// each built-in bus instance that we previously registered, to see
|
|
// whether that bus instance is still being controlled by the built-in
|
|
// bus extender. It is likely that one or more of these BIB's have been
|
|
// 'taken over' by an installable bus extender during its initialization.
|
|
// This capability allows the continued use of old, non-PnP HALs, where
|
|
// PnP functionality is gained through the addition of one or more bus
|
|
// extenders.
|
|
//
|
|
IopVerifyBuiltInBuses();
|
|
|
|
//
|
|
// Release the PnP resources we previously acquired.
|
|
//
|
|
ExReleaseResource(&PpRegistryDeviceResource);
|
|
ExReleaseResource(&PpBusResource);
|
|
KeLeaveCriticalRegion();
|
|
|
|
//
|
|
// Now that we've initialized all bus extenders, we can perform a full
|
|
// enumeration of the system, so that all enumerable devices will be
|
|
// available for the rest of the boot drivers during the next pass.
|
|
//
|
|
status = PpPerformFullEnumeration(TRUE);
|
|
#if DBG
|
|
if(!NT_SUCCESS(status)) {
|
|
DbgPrint("IOINIT: PpPerformFullEnumeration failed (status %x).\n", status);
|
|
}
|
|
#endif // DBG
|
|
|
|
}
|
|
|
|
if(!success) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
#else
|
|
//
|
|
// BUGBUG (lonnym): for _PNP_POWER_, much of the code inside the following loop
|
|
// has been moved to the IopInitializeSingleBootDriver routine. Great care must
|
|
// be taken to ensure that changes made here are also made there (and vice versa).
|
|
//
|
|
|
|
//
|
|
// Walk the list of boot drivers and initialize each.
|
|
//
|
|
|
|
nextEntry = LoaderBlock->BootDriverListHead.Flink;
|
|
|
|
while (nextEntry != &LoaderBlock->BootDriverListHead) {
|
|
|
|
//
|
|
// Initialize the next boot driver in the list.
|
|
//
|
|
|
|
bootDriver = CONTAINING_RECORD( nextEntry,
|
|
BOOT_DRIVER_LIST_ENTRY,
|
|
Link );
|
|
driverEntry = bootDriver->LdrEntry;
|
|
|
|
//
|
|
// Open the driver's registry key to find out if this is a
|
|
// filesystem or a driver.
|
|
//
|
|
|
|
status = IopOpenRegistryKey( &keyHandle,
|
|
(HANDLE) NULL,
|
|
&bootDriver->RegistryPath,
|
|
KEY_READ,
|
|
FALSE );
|
|
if (!NT_SUCCESS( status )) {
|
|
|
|
//
|
|
// Something is quite wrong. The driver must have a key in the
|
|
// registry, or the OS Loader wouldn't have loaded it in the first
|
|
// first place. Skip this driver and keep going.
|
|
//
|
|
#if DBG
|
|
DbgPrint( "IOINIT: IopInitializeBootDrivers couldn't open registry\n" );
|
|
DbgPrint( " key for %wZ. Cannot initialize driver.\n",
|
|
&bootDriver->RegistryPath );
|
|
#endif // DBG
|
|
|
|
nextEntry = nextEntry->Flink;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// See if this driver has an ObjectName value. If so, this value
|
|
// overrides the default ("\Driver" or "\FileSystem").
|
|
//
|
|
|
|
status = IopGetDriverNameFromKeyNode( keyHandle,
|
|
&completeName );
|
|
if (!NT_SUCCESS( status )) {
|
|
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Could not get driver name for %wZ\n",
|
|
&bootDriver->RegistryPath );
|
|
#endif // DBG
|
|
|
|
} else {
|
|
|
|
status = IopGetRegistryValue( keyHandle,
|
|
L"Group",
|
|
&keyValueInformation );
|
|
if (NT_SUCCESS( status )) {
|
|
if (keyValueInformation->DataLength) {
|
|
groupName.Length = (USHORT) keyValueInformation->DataLength;
|
|
groupName.MaximumLength = groupName.Length;
|
|
groupName.Buffer = (PWSTR) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset);
|
|
treeEntry = IopLookupGroupName( &groupName, TRUE );
|
|
} else {
|
|
treeEntry = (PTREE_ENTRY) NULL;
|
|
}
|
|
ExFreePool( keyValueInformation );
|
|
} else {
|
|
treeEntry = (PTREE_ENTRY) NULL;
|
|
}
|
|
|
|
if (IopCheckDependencies( keyHandle ) &&
|
|
IopInitializeBuiltinDriver( &completeName,
|
|
&bootDriver->RegistryPath,
|
|
(PDRIVER_INITIALIZE) driverEntry->EntryPoint )) {
|
|
if (treeEntry) {
|
|
treeEntry->DriversLoaded++;
|
|
}
|
|
} else {
|
|
PLIST_ENTRY NextEntry;
|
|
PLDR_DATA_TABLE_ENTRY DataTableEntry;
|
|
|
|
NextEntry = PsLoadedModuleList.Flink;
|
|
while (NextEntry != &PsLoadedModuleList) {
|
|
DataTableEntry = CONTAINING_RECORD(NextEntry,
|
|
LDR_DATA_TABLE_ENTRY,
|
|
InLoadOrderLinks);
|
|
if (RtlEqualString((PSTRING)&driverEntry->BaseDllName,
|
|
(PSTRING)&DataTableEntry->BaseDllName,
|
|
TRUE
|
|
)) {
|
|
driverEntry->Flags |= LDRP_FAILED_BUILTIN_LOAD;
|
|
DataTableEntry->Flags |= LDRP_FAILED_BUILTIN_LOAD;
|
|
break;
|
|
}
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
}
|
|
|
|
ExFreePool( completeName.Buffer );
|
|
}
|
|
|
|
NtClose( keyHandle );
|
|
|
|
nextEntry = nextEntry->Flink;
|
|
}
|
|
|
|
#endif // _PNP_POWER_
|
|
|
|
//
|
|
// Link NT device names to ARC names now that all of the boot drivers
|
|
// have intialized.
|
|
//
|
|
|
|
IopCreateArcNames( LoaderBlock );
|
|
|
|
//
|
|
// Find and mark the boot partition device object so that if a subsequent
|
|
// access or mount of the device during initialization occurs, an more
|
|
// bugcheck can be produced that helps the user understand why the system
|
|
// is failing to boot and run properly. This occurs when either one of the
|
|
// device drivers or the file system fails to load, or when the file system
|
|
// cannot mount the device for some other reason.
|
|
//
|
|
|
|
if (!IopMarkBootPartition( LoaderBlock )) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Initialize the drivers necessary to dump all of physical memory to the
|
|
// disk if the system is configured to do so.
|
|
//
|
|
|
|
return IopInitializeDumpDrivers( LoaderBlock );
|
|
}
|
|
|
|
BOOLEAN
|
|
IopInitializeBuiltinDriver(
|
|
IN PUNICODE_STRING DriverName,
|
|
IN PUNICODE_STRING RegistryPath,
|
|
IN PDRIVER_INITIALIZE DriverInitializeRoutine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to initialize a built-in driver.
|
|
|
|
Arguments:
|
|
|
|
DriverName - Specifies the name to be used in creating the driver object.
|
|
|
|
RegistryPath - Specifies the path to be used by the driver to get to
|
|
the registry.
|
|
|
|
DriverInitializeRoutine - Specifies the initialization entry point of
|
|
the built-in driver.
|
|
|
|
Return Value:
|
|
|
|
The function value is a BOOLEAN indicating whether or not the built-in
|
|
driver successfully initialized.
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE handle;
|
|
PDRIVER_OBJECT driverObject;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
PWSTR buffer;
|
|
NTSTATUS status;
|
|
//#if _PNP_POWER_
|
|
HANDLE serviceHandle;
|
|
PWSTR pserviceName;
|
|
USHORT serviceNameLength;
|
|
PDRIVER_EXTENSION driverExtension;
|
|
//#endif
|
|
#if DBG
|
|
LARGE_INTEGER stime, etime;
|
|
ULONG dtime;
|
|
#endif
|
|
|
|
//
|
|
// Begin by creating the driver object.
|
|
//
|
|
|
|
status = IopInitializeAttributesAndCreateObject( DriverName,
|
|
&objectAttributes,
|
|
&driverObject );
|
|
if (!NT_SUCCESS( status )) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Initialize the driver object.
|
|
//
|
|
|
|
InitializeDriverObject( driverObject );
|
|
driverObject->DriverInit = DriverInitializeRoutine;
|
|
|
|
//
|
|
// Insert the driver object into the object table.
|
|
//
|
|
|
|
status = ObInsertObject( driverObject,
|
|
NULL,
|
|
FILE_READ_DATA,
|
|
0,
|
|
(PVOID *) NULL,
|
|
&handle );
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Save the name of the driver so that it can be easily located by functions
|
|
// such as error logging.
|
|
//
|
|
|
|
buffer = ExAllocatePool( PagedPool, DriverName->MaximumLength + 2 );
|
|
|
|
if (buffer) {
|
|
driverObject->DriverName.Buffer = buffer;
|
|
driverObject->DriverName.MaximumLength = DriverName->MaximumLength;
|
|
driverObject->DriverName.Length = DriverName->Length;
|
|
|
|
RtlCopyMemory( driverObject->DriverName.Buffer,
|
|
DriverName->Buffer,
|
|
DriverName->MaximumLength );
|
|
buffer[DriverName->Length >> 1] = (WCHAR) '\0';
|
|
}
|
|
|
|
//#if _PNP_POWER_
|
|
|
|
//
|
|
// Save the name of the service key so that it can be easily located by PnP
|
|
// mamager.
|
|
//
|
|
|
|
driverExtension = driverObject->DriverExtension;
|
|
if (RegistryPath && RegistryPath->Length != 0) {
|
|
pserviceName = RegistryPath->Buffer + RegistryPath->Length / sizeof (WCHAR) - 1;
|
|
if (*pserviceName == OBJ_NAME_PATH_SEPARATOR) {
|
|
pserviceName--;
|
|
}
|
|
serviceNameLength = 0;
|
|
while (pserviceName != RegistryPath->Buffer) {
|
|
if (*pserviceName == OBJ_NAME_PATH_SEPARATOR) {
|
|
pserviceName++;
|
|
break;
|
|
} else {
|
|
serviceNameLength += sizeof(WCHAR);
|
|
pserviceName--;
|
|
}
|
|
}
|
|
if (pserviceName == RegistryPath->Buffer) {
|
|
serviceNameLength += sizeof(WCHAR);
|
|
}
|
|
buffer = ExAllocatePool( NonPagedPool, serviceNameLength + sizeof(UNICODE_NULL) );
|
|
|
|
if (buffer) {
|
|
driverExtension->ServiceKeyName.Buffer = buffer;
|
|
driverExtension->ServiceKeyName.MaximumLength = serviceNameLength + sizeof(UNICODE_NULL);
|
|
driverExtension->ServiceKeyName.Length = serviceNameLength;
|
|
|
|
RtlCopyMemory( driverExtension->ServiceKeyName.Buffer,
|
|
pserviceName,
|
|
serviceNameLength );
|
|
buffer[driverExtension->ServiceKeyName.Length >> 1] = UNICODE_NULL;
|
|
} else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
driverExtension->ServiceKeyName.Buffer = NULL;
|
|
driverExtension->ServiceKeyName.Length = 0;
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Prepare driver initialization
|
|
//
|
|
|
|
status = IopOpenRegistryKey(&serviceHandle,
|
|
NULL,
|
|
RegistryPath,
|
|
KEY_ALL_ACCESS,
|
|
FALSE
|
|
);
|
|
if (NT_SUCCESS(status)) {
|
|
status = IopPrepareDriverLoading(&driverExtension->ServiceKeyName, serviceHandle);
|
|
NtClose(serviceHandle);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto exit;
|
|
}
|
|
} else {
|
|
goto exit;
|
|
}
|
|
} else {
|
|
driverExtension->ServiceKeyName.Buffer = NULL;
|
|
driverExtension->ServiceKeyName.MaximumLength = 0;
|
|
driverExtension->ServiceKeyName.Length = 0;
|
|
}
|
|
//#endif
|
|
|
|
//
|
|
// Load the Registry information in the appropriate fields of the device
|
|
// object.
|
|
//
|
|
|
|
driverObject->HardwareDatabase = &CmRegistryMachineHardwareDescriptionSystemName;
|
|
|
|
#if DBG
|
|
KeQuerySystemTime (&stime);
|
|
#endif
|
|
|
|
//
|
|
// Now invoke the driver's initialization routine to initialize itself.
|
|
//
|
|
|
|
status = driverObject->DriverInit( driverObject, RegistryPath );
|
|
|
|
#if DBG
|
|
|
|
//
|
|
// If DriverInit took longer than 5 seconds or the driver did not load,
|
|
// print a message.
|
|
//
|
|
|
|
KeQuerySystemTime (&etime);
|
|
dtime = (ULONG) ((etime.QuadPart - stime.QuadPart) / 1000000);
|
|
|
|
if (dtime > 50 || !NT_SUCCESS( status )) {
|
|
if (dtime < 10) {
|
|
DbgPrint( "IOINIT: Built-in driver %wZ failed to initialize - %lX\n",
|
|
DriverName, status );
|
|
|
|
} else {
|
|
DbgPrint( "IOINIT: Built-in driver %wZ took %d.%ds to ",
|
|
DriverName, dtime/10, dtime%10 );
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
DbgPrint ("initialize\n");
|
|
} else {
|
|
DbgPrint ("fail initialization - %lX\n", status);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
exit:
|
|
NtClose( handle );
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
IopReadyDeviceObjects( driverObject );
|
|
return TRUE;
|
|
} else {
|
|
if (status != STATUS_PLUGPLAY_NO_DEVICE) {
|
|
|
|
//
|
|
// if STATUS_PLUGPLAY_NO_DEVICE, the driver was disable by hardware profile.
|
|
//
|
|
|
|
IopDriverLoadingFailed(NULL, &driverObject->DriverExtension->ServiceKeyName);
|
|
}
|
|
ObMakeTemporaryObject( driverObject );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
IopInitializeDumpDrivers(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to load and initialize any drivers that are
|
|
required to dump memory to the boot device's paging file, if the system
|
|
is configured to do so.
|
|
|
|
Arguments:
|
|
|
|
LoaderBlock - System boot loader parameter block.
|
|
|
|
Return Value:
|
|
|
|
The final function value is TRUE if everything worked, else FALSE.
|
|
--*/
|
|
|
|
{
|
|
HANDLE keyHandle;
|
|
HANDLE crashHandle;
|
|
HANDLE deviceHandle;
|
|
UNICODE_STRING keyName;
|
|
NTSTATUS status;
|
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
ULONG dumpControl;
|
|
ULONG handleValue;
|
|
BOOLEAN scsiDump;
|
|
ULONG autoReboot;
|
|
PVOID scratch;
|
|
PCHAR partitionName;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
PFILE_OBJECT fileObject;
|
|
PDEVICE_OBJECT deviceObject;
|
|
PIRP irp;
|
|
KEVENT event;
|
|
DUMP_POINTERS dumpPointers;
|
|
PDUMP_CONTROL_BLOCK dcb;
|
|
ULONG savedModuleCount;
|
|
ULONG dcbSize;
|
|
PLIST_ENTRY nextEntry;
|
|
UNICODE_STRING driverName;
|
|
PLDR_DATA_TABLE_ENTRY loaderEntry;
|
|
PLDR_DATA_TABLE_ENTRY imageHandle;
|
|
PUCHAR imageBaseAddress;
|
|
PWCHAR buffer;
|
|
ANSI_STRING ansiString;
|
|
PMINIPORT_NODE mpNode;
|
|
UNICODE_STRING tmpName;
|
|
LARGE_INTEGER page;
|
|
PARTITION_INFORMATION partitionInfo;
|
|
SCSI_ADDRESS scsiAddress;
|
|
PMAPPED_ADDRESS addresses;
|
|
PHYSICAL_ADDRESS paTemp;
|
|
|
|
//
|
|
// Begin by opening the path to the control for dumping memory. Note
|
|
// that if it does not exist, then no dumps will occur.
|
|
//
|
|
|
|
RtlInitUnicodeString( &keyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control" );
|
|
status = IopOpenRegistryKey( &keyHandle,
|
|
(HANDLE) NULL,
|
|
&keyName,
|
|
KEY_READ,
|
|
FALSE );
|
|
if (!NT_SUCCESS( status )) {
|
|
return TRUE;
|
|
}
|
|
|
|
RtlInitUnicodeString( &keyName, L"CrashControl" );
|
|
status = IopOpenRegistryKey( &crashHandle,
|
|
keyHandle,
|
|
&keyName,
|
|
KEY_READ,
|
|
FALSE );
|
|
NtClose( keyHandle );
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Now get the value of the crash control to determine whether or not
|
|
// dumping is enabled.
|
|
//
|
|
|
|
dumpControl = 0;
|
|
|
|
status = IopGetRegistryValue( crashHandle,
|
|
L"CrashDumpEnabled",
|
|
&keyValueInformation );
|
|
if (NT_SUCCESS( status )) {
|
|
if (keyValueInformation->DataLength) {
|
|
handleValue = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset));
|
|
ExFreePool( keyValueInformation);
|
|
if (handleValue) {
|
|
dumpControl |= DCB_DUMP_ENABLED;
|
|
}
|
|
}
|
|
}
|
|
|
|
status = IopGetRegistryValue( crashHandle,
|
|
L"LogEvent",
|
|
&keyValueInformation );
|
|
if (NT_SUCCESS( status )) {
|
|
if (keyValueInformation->DataLength) {
|
|
handleValue = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset));
|
|
ExFreePool( keyValueInformation);
|
|
if (handleValue) {
|
|
dumpControl |= DCB_SUMMARY_ENABLED;
|
|
}
|
|
}
|
|
}
|
|
|
|
status = IopGetRegistryValue( crashHandle,
|
|
L"SendAlert",
|
|
&keyValueInformation );
|
|
if (NT_SUCCESS( status )) {
|
|
if (keyValueInformation->DataLength) {
|
|
handleValue = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset));
|
|
ExFreePool( keyValueInformation);
|
|
if (handleValue) {
|
|
dumpControl |= DCB_SUMMARY_ENABLED;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now determine whether or not automatic reboot is enabled.
|
|
//
|
|
|
|
autoReboot = 0;
|
|
|
|
status = IopGetRegistryValue( crashHandle,
|
|
L"AutoReboot",
|
|
&keyValueInformation );
|
|
NtClose( crashHandle );
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
if (keyValueInformation->DataLength) {
|
|
autoReboot = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset));
|
|
}
|
|
ExFreePool( keyValueInformation );
|
|
}
|
|
|
|
//
|
|
// If we aren't auto rebooting or crashing then return now.
|
|
//
|
|
|
|
if (!dumpControl && !autoReboot) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
//
|
|
// Memory crash dumps are enabled. Begin by determining whether or not
|
|
// the boot device is an internal "AT" type disk drive or a SCSI disk
|
|
// drive.
|
|
//
|
|
|
|
//
|
|
// It actually turns out that simply looking for the string 'scsi' in the
|
|
// name is not good enough, since it is possible that the device being
|
|
// booted from is on a SCSI adapter that was gotten to via the BIOS. This
|
|
// only happens if the system was initially installed by triple-booting,
|
|
// but since it is so popular, it is handled here.
|
|
//
|
|
// The device itself is opened so that IOCTLs can be given to it. This
|
|
// allows the SCSI get address IOCTL to be issued to determine whether or
|
|
// not this really is a SCSI device.
|
|
//
|
|
|
|
//
|
|
// We only need to go through this work if we are going to take the dump.
|
|
//
|
|
|
|
if (dumpControl) {
|
|
|
|
//
|
|
// Note that this allocation MUST MUST MUST be kept in sync with the
|
|
// allocation in diskdump. No point in creating a defined symbol
|
|
// since there aren't any shared files.
|
|
//
|
|
scratch = ExAllocatePoolWithTag( NonPagedPool, 8*PAGE_SIZE, 'pmuD' );
|
|
|
|
strcpy( (PCHAR) scratch, "\\ArcName\\" );
|
|
partitionName = (PCHAR) scratch + strlen( (PCHAR) scratch );
|
|
strcpy( partitionName, LoaderBlock->ArcBootDeviceName );
|
|
|
|
RtlInitAnsiString( &ansiString, (PCHAR) scratch );
|
|
RtlAnsiStringToUnicodeString( &tmpName, &ansiString, TRUE );
|
|
|
|
InitializeObjectAttributes( &objectAttributes,
|
|
&tmpName,
|
|
0,
|
|
(HANDLE) NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL );
|
|
status = NtOpenFile( &deviceHandle,
|
|
FILE_READ_DATA | SYNCHRONIZE,
|
|
&objectAttributes,
|
|
&ioStatus,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_NON_DIRECTORY_FILE );
|
|
RtlFreeUnicodeString( &tmpName );
|
|
if (!NT_SUCCESS( status )) {
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Could not open boot device partition, %s\n",
|
|
(PCHAR) scratch );
|
|
#endif // DBG
|
|
ExFreePool( scratch );
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Check to see whether or not the system was booted from a SCSI device.
|
|
//
|
|
|
|
status = NtDeviceIoControlFile( deviceHandle,
|
|
(HANDLE) NULL,
|
|
(PIO_APC_ROUTINE) NULL,
|
|
(PVOID) NULL,
|
|
&ioStatus,
|
|
IOCTL_SCSI_GET_ADDRESS,
|
|
(PVOID) NULL,
|
|
0,
|
|
&scsiAddress,
|
|
sizeof( SCSI_ADDRESS ) );
|
|
if (status == STATUS_PENDING) {
|
|
(VOID) NtWaitForSingleObject( deviceHandle,
|
|
FALSE,
|
|
(PLARGE_INTEGER) NULL );
|
|
status = ioStatus.Status;
|
|
}
|
|
|
|
scsiDump = (BOOLEAN) (NT_SUCCESS( status ));
|
|
|
|
}
|
|
|
|
//
|
|
// Allocate and initialize the structures necessary to describe and control
|
|
// the post-bugcheck code.
|
|
//
|
|
|
|
dcbSize = sizeof( DUMP_CONTROL_BLOCK ) + sizeof( MINIPORT_NODE );
|
|
dcb = ExAllocatePoolWithTag( NonPagedPool, dcbSize, 'pmuD' );
|
|
if (!dcb) {
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Not enough pool to allocate DCB\n" );
|
|
#endif // DBG
|
|
NtClose( deviceHandle );
|
|
ExFreePool( scratch );
|
|
return FALSE;
|
|
}
|
|
|
|
RtlZeroMemory( dcb, dcbSize );
|
|
dcb->Type = IO_TYPE_DCB;
|
|
dcb->Size = (USHORT) dcbSize;
|
|
dcb->Flags = autoReboot ? DCB_AUTO_REBOOT : 0;
|
|
dcb->NumberProcessors = KeNumberProcessors;
|
|
dcb->ProcessorArchitecture = KeProcessorArchitecture;
|
|
dcb->MemoryDescriptor = MmPhysicalMemoryBlock;
|
|
dcb->MemoryDescriptorChecksum = IopChecksum( MmPhysicalMemoryBlock,
|
|
sizeof( PHYSICAL_MEMORY_DESCRIPTOR ) - sizeof( PHYSICAL_MEMORY_RUN ) +
|
|
(MmPhysicalMemoryBlock->NumberOfRuns * sizeof( PHYSICAL_MEMORY_RUN )) );
|
|
dcb->LoadedModuleList = &PsLoadedModuleList;
|
|
InitializeListHead( &dcb->MiniportQueue );
|
|
dcb->MinorVersion = (USHORT) NtBuildNumber;
|
|
dcb->MajorVersion = (USHORT) ((NtBuildNumber >> 28) & 0xfffffff);
|
|
|
|
//
|
|
// Get pointers to localized text we will need during dump.
|
|
//
|
|
|
|
if (!KeGetBugMessageText( BUGCODE_PSS_CRASH_INIT, &dcb->PssInitMsg ) ||
|
|
!KeGetBugMessageText( BUGCODE_PSS_CRASH_PROGRESS, &dcb->PssProgressMsg ) ||
|
|
!KeGetBugMessageText( BUGCODE_PSS_CRASH_DONE, &dcb->PssDoneMsg )
|
|
) {
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Could not find PSS messages for crash dump.\n",
|
|
(PCHAR) scratch );
|
|
#endif // DBG
|
|
ExFreePool( dcb );
|
|
ExFreePool( scratch );
|
|
return FALSE;
|
|
}
|
|
|
|
if (dumpControl) {
|
|
|
|
//
|
|
// Determine the disk signature for the device from which the system was
|
|
// booted and get the partition offset.
|
|
//
|
|
|
|
status = NtDeviceIoControlFile( deviceHandle,
|
|
(HANDLE) NULL,
|
|
(PIO_APC_ROUTINE) NULL,
|
|
(PVOID) NULL,
|
|
&ioStatus,
|
|
IOCTL_DISK_GET_PARTITION_INFO,
|
|
(PVOID) NULL,
|
|
0,
|
|
&partitionInfo,
|
|
sizeof( PARTITION_INFORMATION ) );
|
|
if (status == STATUS_PENDING) {
|
|
(VOID) NtWaitForSingleObject( deviceHandle,
|
|
FALSE,
|
|
(PLARGE_INTEGER) NULL );
|
|
status = ioStatus.Status;
|
|
}
|
|
|
|
NtClose( deviceHandle );
|
|
|
|
dcb->PartitionOffset = partitionInfo.StartingOffset;
|
|
|
|
//
|
|
// Determine the name of the device itself to get the disk's signature.
|
|
//
|
|
|
|
partitionName = strstr( (PCHAR) scratch, "partition(" );
|
|
*partitionName = '\0';
|
|
|
|
RtlInitAnsiString( &ansiString, (PCHAR) scratch );
|
|
RtlAnsiStringToUnicodeString( &tmpName, &ansiString, TRUE );
|
|
|
|
InitializeObjectAttributes( &objectAttributes,
|
|
&tmpName,
|
|
0,
|
|
(HANDLE) NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL );
|
|
status = NtOpenFile( &deviceHandle,
|
|
FILE_READ_DATA | SYNCHRONIZE,
|
|
&objectAttributes,
|
|
&ioStatus,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_NON_DIRECTORY_FILE );
|
|
|
|
RtlFreeUnicodeString( &tmpName );
|
|
if (!NT_SUCCESS( status )) {
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Could not open boot device partition 0, %s\n",
|
|
(PCHAR) scratch );
|
|
#endif // DBG
|
|
ExFreePool( dcb );
|
|
ExFreePool( scratch );
|
|
return TRUE;
|
|
}
|
|
|
|
status = NtDeviceIoControlFile( deviceHandle,
|
|
(HANDLE) NULL,
|
|
(PIO_APC_ROUTINE) NULL,
|
|
(PVOID) NULL,
|
|
&ioStatus,
|
|
IOCTL_DISK_GET_DRIVE_LAYOUT,
|
|
(PVOID) NULL,
|
|
0,
|
|
scratch,
|
|
PAGE_SIZE );
|
|
if (status == STATUS_PENDING) {
|
|
(VOID) NtWaitForSingleObject( deviceHandle,
|
|
FALSE,
|
|
(PLARGE_INTEGER) NULL );
|
|
status = ioStatus.Status;
|
|
}
|
|
|
|
dcb->DiskSignature = ((PDRIVE_LAYOUT_INFORMATION) scratch)->Signature;
|
|
|
|
//
|
|
// Get the adapter object and base mapping registers for the disk from
|
|
// the disk driver. These will be used to call the HAL once the system
|
|
// system has crashed, since it is not possible at that point to recreate
|
|
// them from scratch.
|
|
//
|
|
|
|
(VOID) ObReferenceObjectByHandle( deviceHandle,
|
|
0,
|
|
IoFileObjectType,
|
|
KernelMode,
|
|
(PVOID *) &fileObject,
|
|
NULL );
|
|
|
|
deviceObject = IoGetRelatedDeviceObject( fileObject );
|
|
|
|
KeInitializeEvent( &event, NotificationEvent, FALSE );
|
|
|
|
irp = IoBuildDeviceIoControlRequest( IOCTL_SCSI_GET_DUMP_POINTERS,
|
|
deviceObject,
|
|
(PVOID) NULL,
|
|
0,
|
|
&dumpPointers,
|
|
sizeof( DUMP_POINTERS ),
|
|
FALSE,
|
|
&event,
|
|
&ioStatus );
|
|
|
|
status = IoCallDriver( deviceObject, irp );
|
|
|
|
if (status == STATUS_PENDING) {
|
|
(VOID) KeWaitForSingleObject( &event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
(PLARGE_INTEGER) NULL );
|
|
status = ioStatus.Status;
|
|
}
|
|
|
|
ObDereferenceObject( fileObject );
|
|
NtClose( deviceHandle );
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Could not get dump pointers; error = %x\n",
|
|
status );
|
|
#endif // DBG
|
|
ExFreePool( dcb );
|
|
ExFreePool( scratch );
|
|
return TRUE;
|
|
}
|
|
|
|
dcb->AdapterObject = dumpPointers.AdapterObject;
|
|
dcb->MappedRegisterBase = dumpPointers.MappedRegisterBase;
|
|
dcb->PortConfiguration = dumpPointers.PortConfiguration;
|
|
|
|
//
|
|
//
|
|
// Scan the list of mapped registers and get both a count of the entries
|
|
// and produce a checksum.
|
|
//
|
|
|
|
addresses = * (PMAPPED_ADDRESS *) dcb->MappedRegisterBase;
|
|
|
|
while (addresses) {
|
|
dcb->MappedAddressCount++;
|
|
dcb->MappedAddressChecksum += IopChecksum( addresses, sizeof( MAPPED_ADDRESS ) );
|
|
addresses = addresses->NextMappedAddress;
|
|
}
|
|
|
|
//
|
|
// Scan the list of loaded modules in the system and change their names
|
|
// so that they do not appear to exist for the purpose of lookups. This
|
|
// will guarantee that no boot drivers accidentally resolve their names
|
|
// to components loaded at this point.
|
|
//
|
|
|
|
nextEntry = PsLoadedModuleList.Flink;
|
|
savedModuleCount = 0;
|
|
while (nextEntry != &PsLoadedModuleList) {
|
|
loaderEntry = CONTAINING_RECORD( nextEntry,
|
|
LDR_DATA_TABLE_ENTRY,
|
|
InLoadOrderLinks );
|
|
if (savedModuleCount >= 2) {
|
|
loaderEntry->BaseDllName.MaximumLength = loaderEntry->BaseDllName.Length;
|
|
loaderEntry->BaseDllName.Length = 0;
|
|
}
|
|
savedModuleCount++;
|
|
nextEntry = nextEntry->Flink;
|
|
}
|
|
|
|
//
|
|
// Load the boot disk and port driver to be used by the various
|
|
// miniports for writing memory to the disk.
|
|
//
|
|
|
|
RtlInitUnicodeString( &driverName, L"\\SystemRoot\\System32\\Drivers\\diskdump.sys" );
|
|
status = MmLoadSystemImage( &driverName,
|
|
&imageHandle,
|
|
&imageBaseAddress );
|
|
if (!NT_SUCCESS( status )) {
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Could not load diskdump.sys driver; error = %x\n", status );
|
|
#endif // DBG
|
|
IopRevertModuleList( savedModuleCount );
|
|
ExFreePool( dcb );
|
|
ExFreePool( scratch );
|
|
return TRUE;
|
|
}
|
|
|
|
dcb->DiskDumpDriver = imageHandle;
|
|
RtlInitUnicodeString( &tmpName, L"scsiport.sys" );
|
|
RtlCopyUnicodeString( &imageHandle->BaseDllName, &tmpName );
|
|
dcb->DiskDumpChecksum = IopChecksum( imageHandle->DllBase,
|
|
imageHandle->SizeOfImage );
|
|
|
|
//
|
|
// The disk and port dump driver has been loaded. Load the appropriate
|
|
// miniport driver as well so that the boot device can be accessed.
|
|
//
|
|
|
|
buffer = ExAllocatePoolWithTag( NonPagedPool, 256, 'pmuD' );
|
|
driverName.Length = 0;
|
|
driverName.Buffer = buffer;
|
|
driverName.MaximumLength = 256;
|
|
|
|
mpNode = (PMINIPORT_NODE) (dcb + 1);
|
|
|
|
//
|
|
// Determine whether or not the system booted from SCSI. If so, determine
|
|
// the name of the miniport driver that is driving the system disk and
|
|
// load a private copy.
|
|
//
|
|
|
|
if (scsiDump) {
|
|
|
|
PFILE_OBJECT fileObject;
|
|
PDRIVER_OBJECT driverObject;
|
|
PWCHAR mpName;
|
|
PWCHAR nameOffset;
|
|
|
|
//
|
|
// The system was booted from SCSI. Get the name of the appropriate
|
|
// miniport driver and load it.
|
|
//
|
|
|
|
sprintf( (PCHAR) buffer, "\\Device\\ScsiPort%d", scsiAddress.PortNumber );
|
|
RtlInitAnsiString( &ansiString, (PCHAR) buffer );
|
|
RtlAnsiStringToUnicodeString( &tmpName, &ansiString, TRUE );
|
|
|
|
InitializeObjectAttributes( &objectAttributes,
|
|
&tmpName,
|
|
0,
|
|
(HANDLE) NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL );
|
|
status = NtOpenFile( &deviceHandle,
|
|
FILE_READ_ATTRIBUTES,
|
|
&objectAttributes,
|
|
&ioStatus,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_NON_DIRECTORY_FILE );
|
|
RtlFreeUnicodeString( &tmpName );
|
|
if (!NT_SUCCESS( status )) {
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Could not open SCSI port %d, error = %x\n", scsiAddress.PortNumber, status );
|
|
#endif // DBG
|
|
ExFreePool( buffer );
|
|
ExFreePool( dcb );
|
|
IopRevertModuleList( savedModuleCount );
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Convert the file handle into a pointer to the device object, and
|
|
// get the name of the driver from its driver object.
|
|
//
|
|
|
|
ObReferenceObjectByHandle( deviceHandle,
|
|
0,
|
|
IoFileObjectType,
|
|
KernelMode,
|
|
(PVOID *) &fileObject,
|
|
NULL );
|
|
driverObject = fileObject->DeviceObject->DriverObject;
|
|
ObDereferenceObject( fileObject );
|
|
NtClose( deviceHandle );
|
|
|
|
//
|
|
// Loop through the name of the driver looking for the end of the name,
|
|
// which is the name of the miniport image.
|
|
//
|
|
|
|
mpName = driverObject->DriverName.Buffer;
|
|
while ( nameOffset = wcsstr( mpName, L"\\" )) {
|
|
mpName = ++nameOffset;
|
|
}
|
|
|
|
RtlAppendUnicodeToString( &driverName, L"\\SystemRoot\\System32\\Drivers\\" );
|
|
RtlAppendUnicodeToString( &driverName, mpName );
|
|
RtlAppendUnicodeToString( &driverName, L".sys" );
|
|
|
|
status = MmLoadSystemImage( &driverName,
|
|
&imageHandle,
|
|
&imageBaseAddress );
|
|
if (!NT_SUCCESS( status )) {
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Could not load miniport driver %wZ\n", &driverName );
|
|
#endif // DBG
|
|
} else {
|
|
|
|
//
|
|
// The crash dump miniport driver was successfully loaded.
|
|
// Place the miniport node entry on the list and
|
|
// initialize it.
|
|
//
|
|
|
|
InsertTailList( &dcb->MiniportQueue, &mpNode->ListEntry );
|
|
mpNode->DriverEntry = imageHandle;
|
|
mpNode->DriverChecksum = IopChecksum( imageHandle->DllBase,
|
|
imageHandle->SizeOfImage );
|
|
dcb->Flags |= dumpControl;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// The system was not booted from a SCSI device. For this case, simply
|
|
// load the general 'AT disk' miniport driver.
|
|
//
|
|
|
|
RtlAppendUnicodeToString( &driverName, L"\\SystemRoot\\System32\\Drivers\\atapi.sys" );
|
|
|
|
status = MmLoadSystemImage( &driverName,
|
|
&imageHandle,
|
|
&imageBaseAddress );
|
|
if (!NT_SUCCESS( status )) {
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Could not load dump driver ATAPI.SYS\n" );
|
|
#endif // DBG
|
|
} else {
|
|
|
|
//
|
|
// The crash dump miniport driver was successfully loaded. Place
|
|
// the miniport node entry on the list and initialize it.
|
|
//
|
|
|
|
InsertTailList( &dcb->MiniportQueue, &mpNode->ListEntry );
|
|
mpNode->DriverEntry = imageHandle;
|
|
mpNode->DriverChecksum = IopChecksum( imageHandle->DllBase,
|
|
imageHandle->SizeOfImage );
|
|
dcb->Flags |= dumpControl;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free the driver name buffer and restore the system's loaded module list.
|
|
//
|
|
|
|
ExFreePool( buffer );
|
|
IopRevertModuleList( savedModuleCount );
|
|
|
|
//
|
|
// If everything worked, then allocate the various buffer to be used by
|
|
// the crash dump code, etc.
|
|
//
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
//
|
|
// If there is an adapter object then call the common buffer routine
|
|
// to allocate the memory. Otherwise we can just call some "normal"
|
|
// memory allocation routines.
|
|
//
|
|
|
|
if (dcb->AdapterObject) {
|
|
|
|
dcb->NonCachedBufferVa1 = HalAllocateCommonBuffer(
|
|
dcb->AdapterObject,
|
|
0x2000,
|
|
&dcb->NonCachedBufferPa1,
|
|
FALSE
|
|
);
|
|
|
|
if (!dcb->NonCachedBufferVa1) {
|
|
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Could not allocate 8k noncached buffer\n" );
|
|
#endif // DBG
|
|
ExFreePool( dcb );
|
|
dcb = NULL;
|
|
|
|
} else {
|
|
|
|
dcb->NonCachedBufferVa2 = HalAllocateCommonBuffer(
|
|
dcb->AdapterObject,
|
|
0x2000,
|
|
&dcb->NonCachedBufferPa2,
|
|
FALSE
|
|
);
|
|
|
|
if (!dcb->NonCachedBufferVa2) {
|
|
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Could not allocate 8k noncached buffer\n" );
|
|
#endif // DBG
|
|
ExFreePool( dcb );
|
|
dcb = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Allocate the various buffers to be used by the crash dump code.
|
|
//
|
|
|
|
paTemp.QuadPart = 0x1000000 - 1;
|
|
dcb->NonCachedBufferVa1 =
|
|
MmAllocateContiguousMemory( 0x2000,
|
|
paTemp );
|
|
|
|
if (!dcb->NonCachedBufferVa1) {
|
|
|
|
dcb->NonCachedBufferVa1 =
|
|
MmAllocateNonCachedMemory( 0x2000 );
|
|
}
|
|
|
|
if (!dcb->NonCachedBufferVa1) {
|
|
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Could not allocate 8k noncached buffer\n" );
|
|
#endif // DBG
|
|
ExFreePool( dcb );
|
|
dcb = NULL;
|
|
|
|
} else {
|
|
|
|
paTemp.QuadPart = 0x1000000 - 1;
|
|
dcb->NonCachedBufferVa2 =
|
|
MmAllocateContiguousMemory( 0x2000,
|
|
paTemp );
|
|
|
|
if (!dcb->NonCachedBufferVa2) {
|
|
|
|
dcb->NonCachedBufferVa2 =
|
|
MmAllocateNonCachedMemory( 0x2000 );
|
|
}
|
|
|
|
if (!dcb->NonCachedBufferVa2) {
|
|
|
|
#if DBG
|
|
DbgPrint( "IOINIT: Could not allocate 8k noncached buffer\n" );
|
|
#endif // DBG
|
|
ExFreePool( dcb );
|
|
dcb = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dcb) {
|
|
|
|
//
|
|
// If we still have a dcb that meant we could allocate our buffers.
|
|
//
|
|
// Get the physical addresses that correspond to the virtual addresses
|
|
// of the buffers.
|
|
//
|
|
|
|
dcb->NonCachedBufferPa1 = MmGetPhysicalAddress(dcb->NonCachedBufferVa1);
|
|
dcb->NonCachedBufferPa2 = MmGetPhysicalAddress(dcb->NonCachedBufferVa2);
|
|
|
|
dcb->HeaderPage = ExAllocatePoolWithTag( NonPagedPool, PAGE_SIZE, 'pmuD' );
|
|
page = MmGetPhysicalAddress( dcb->HeaderPage );
|
|
page.QuadPart >>= PAGE_SHIFT;
|
|
dcb->HeaderPfn = page.LowPart;
|
|
dcb->Buffer = scratch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Generate the checksum for the entire dump control block structure
|
|
// itself.
|
|
//
|
|
|
|
IopDumpControlBlock = dcb;
|
|
if (dcb) {
|
|
IopDumpControlBlockChecksum = IopChecksum( dcb, dcbSize );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
IopInitializeSystemDrivers(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to load and initialize all of the drivers that
|
|
are supposed to be loaded during Phase 1 initialization of the I/O
|
|
system. This is accomplished by calling the Configuration Manager to
|
|
get a NULL-terminated array of handles to the open keys for each driver
|
|
that is to be loaded, and then loading and initializing the driver.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
The function value is a BOOLEAN indicating whether or not the drivers
|
|
were successfully loaded and initialized.
|
|
|
|
--*/
|
|
|
|
{
|
|
PHANDLE driverList;
|
|
PHANDLE savedList;
|
|
NTSTATUS status;
|
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|
UNICODE_STRING groupName;
|
|
PTREE_ENTRY treeEntry;
|
|
|
|
//
|
|
// Get the list of drivers that are to be loaded during this phase of
|
|
// system initialization, and invoke each driver in turn. Ensure that
|
|
// the list really exists, otherwise get out now.
|
|
//
|
|
|
|
if (!(driverList = CmGetSystemDriverList())) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Walk the entire list, loading each of the drivers, until there are
|
|
// no more drivers in the list.
|
|
//
|
|
|
|
for (savedList = driverList; *driverList; driverList++) {
|
|
status = IopGetRegistryValue( *driverList,
|
|
L"Group",
|
|
&keyValueInformation );
|
|
if (NT_SUCCESS( status )) {
|
|
if (keyValueInformation->DataLength) {
|
|
groupName.Length = (USHORT) keyValueInformation->DataLength;
|
|
groupName.MaximumLength = groupName.Length;
|
|
groupName.Buffer = (PWSTR) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset);
|
|
treeEntry = IopLookupGroupName( &groupName, TRUE );
|
|
} else {
|
|
treeEntry = (PTREE_ENTRY) NULL;
|
|
}
|
|
ExFreePool( keyValueInformation );
|
|
} else {
|
|
treeEntry = (PTREE_ENTRY) NULL;
|
|
}
|
|
|
|
if (IopCheckDependencies( *driverList )) {
|
|
if (NT_SUCCESS( IopLoadDriver( *driverList ) )) {
|
|
if (treeEntry) {
|
|
treeEntry->DriversLoaded++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Finally, free the pool that was allocated for the list and return
|
|
// an indicator the load operation worked.
|
|
//
|
|
|
|
ExFreePool( (PVOID) savedList );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PTREE_ENTRY
|
|
IopLookupGroupName(
|
|
IN PUNICODE_STRING GroupName,
|
|
IN BOOLEAN Insert
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine looks up a group entry in the group load tree and either
|
|
returns a pointer to it, or optionally creates the entry and inserts
|
|
it into the tree.
|
|
|
|
Arguments:
|
|
|
|
GroupName - The name of the group to look up, or insert.
|
|
|
|
Insert - Indicates whether or not an entry is to be created and inserted
|
|
into the tree if the name does not already exist.
|
|
|
|
Return Value:
|
|
|
|
The function value is a pointer to the entry for the specified group
|
|
name, or NULL.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTREE_ENTRY treeEntry;
|
|
PTREE_ENTRY previousEntry;
|
|
|
|
//
|
|
// Begin by determining whether or not there are any entries in the tree
|
|
// whatsoever. If not, and it is OK to insert, then insert this entry
|
|
// into the tree.
|
|
//
|
|
|
|
if (!IopGroupListHead) {
|
|
if (!Insert) {
|
|
return (PTREE_ENTRY) NULL;
|
|
} else {
|
|
IopGroupListHead = IopCreateEntry( GroupName );
|
|
return IopGroupListHead;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The tree is not empty, so actually attempt to do a lookup.
|
|
//
|
|
|
|
treeEntry = IopGroupListHead;
|
|
|
|
for (;;) {
|
|
if (GroupName->Length < treeEntry->GroupName.Length) {
|
|
if (treeEntry->Left) {
|
|
treeEntry = treeEntry->Left;
|
|
} else {
|
|
if (!Insert) {
|
|
return (PTREE_ENTRY) NULL;
|
|
} else {
|
|
treeEntry->Left = IopCreateEntry( GroupName );
|
|
return treeEntry->Left;
|
|
}
|
|
|
|
}
|
|
} else if (GroupName->Length > treeEntry->GroupName.Length) {
|
|
if (treeEntry->Right) {
|
|
treeEntry = treeEntry->Right;
|
|
} else {
|
|
if (!Insert) {
|
|
return (PTREE_ENTRY) NULL;
|
|
} else {
|
|
treeEntry->Right = IopCreateEntry( GroupName );
|
|
return treeEntry->Right;
|
|
}
|
|
}
|
|
} else {
|
|
if (!RtlEqualUnicodeString( GroupName, &treeEntry->GroupName, TRUE )) {
|
|
previousEntry = treeEntry;
|
|
while (treeEntry->Sibling) {
|
|
treeEntry = treeEntry->Sibling;
|
|
if (RtlEqualUnicodeString( GroupName, &treeEntry->GroupName, TRUE )) {
|
|
return treeEntry;
|
|
}
|
|
previousEntry = previousEntry->Sibling;
|
|
}
|
|
if (!Insert) {
|
|
return (PTREE_ENTRY) NULL;
|
|
} else {
|
|
previousEntry->Sibling = IopCreateEntry( GroupName );
|
|
return previousEntry->Sibling;
|
|
}
|
|
} else {
|
|
return treeEntry;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
IopMarkBootPartition(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to locate and mark the boot partition device object
|
|
as a boot device so that subsequent operations can fail more cleanly and
|
|
with a better explanation of why the system failed to boot and run properly.
|
|
|
|
Arguments:
|
|
|
|
LoaderBlock - Supplies a pointer to the loader parameter block created
|
|
by the OS Loader during the boot process. This structure contains
|
|
the various system partition and boot device names and paths.
|
|
|
|
Return Value:
|
|
|
|
The function value is TRUE if everything worked, otherwise FALSE.
|
|
|
|
Notes:
|
|
|
|
If the boot partition device object cannot be found, then the system will
|
|
bugcheck.
|
|
|
|
--*/
|
|
|
|
{
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
STRING deviceNameString;
|
|
UCHAR deviceNameBuffer[256];
|
|
UNICODE_STRING deviceNameUnicodeString;
|
|
NTSTATUS status;
|
|
HANDLE fileHandle;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
PFILE_OBJECT fileObject;
|
|
CHAR ArcNameFmt[12];
|
|
|
|
ArcNameFmt[0] = '\\';
|
|
ArcNameFmt[1] = 'A';
|
|
ArcNameFmt[2] = 'r';
|
|
ArcNameFmt[3] = 'c';
|
|
ArcNameFmt[4] = 'N';
|
|
ArcNameFmt[5] = 'a';
|
|
ArcNameFmt[6] = 'm';
|
|
ArcNameFmt[7] = 'e';
|
|
ArcNameFmt[8] = '\\';
|
|
ArcNameFmt[9] = '%';
|
|
ArcNameFmt[10] = 's';
|
|
ArcNameFmt[11] = '\0';
|
|
//
|
|
// Open the ARC boot device object. The boot device driver should have
|
|
// created the object.
|
|
//
|
|
|
|
sprintf( deviceNameBuffer,
|
|
ArcNameFmt,
|
|
LoaderBlock->ArcBootDeviceName );
|
|
|
|
RtlInitAnsiString( &deviceNameString, deviceNameBuffer );
|
|
|
|
status = RtlAnsiStringToUnicodeString( &deviceNameUnicodeString,
|
|
&deviceNameString,
|
|
TRUE );
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
return FALSE;
|
|
}
|
|
|
|
InitializeObjectAttributes( &objectAttributes,
|
|
&deviceNameUnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL );
|
|
|
|
status = ZwOpenFile( &fileHandle,
|
|
FILE_READ_ATTRIBUTES,
|
|
&objectAttributes,
|
|
&ioStatus,
|
|
0,
|
|
FILE_NON_DIRECTORY_FILE );
|
|
if (!NT_SUCCESS( status )) {
|
|
KeBugCheckEx( INACCESSIBLE_BOOT_DEVICE,
|
|
(ULONG) &deviceNameUnicodeString,
|
|
status,
|
|
0,
|
|
0 );
|
|
}
|
|
|
|
RtlFreeUnicodeString( &deviceNameUnicodeString );
|
|
|
|
//
|
|
// Convert the file handle into a pointer to the device object itself.
|
|
//
|
|
|
|
status = ObReferenceObjectByHandle( fileHandle,
|
|
0,
|
|
IoFileObjectType,
|
|
KernelMode,
|
|
(PVOID *) &fileObject,
|
|
NULL );
|
|
if (!NT_SUCCESS( status )) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Mark the device object represented by the file object.
|
|
//
|
|
|
|
fileObject->DeviceObject->Flags |= DO_SYSTEM_BOOT_PARTITION;
|
|
|
|
//
|
|
// Finally, close the handle and dereference the file object.
|
|
//
|
|
|
|
NtClose( fileHandle );
|
|
ObDereferenceObject( fileObject );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
IopReassignSystemRoot(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
|
OUT PSTRING NtDeviceName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to reassign \SystemRoot from being an ARC path
|
|
name to its NT path name equivalent. This is done by looking up the
|
|
ARC device name as a symbolic link and determining which NT device object
|
|
is referred to by it. The link is then replaced with the new name.
|
|
|
|
Arguments:
|
|
|
|
LoaderBlock - Supplies a pointer to the loader parameter block created
|
|
by the OS Loader during the boot process. This structure contains
|
|
the various system partition and boot device names and paths.
|
|
|
|
NtDeviceName - Specifies a pointer to a STRING to receive the NT name of
|
|
the device from which the system was booted.
|
|
|
|
Return Value:
|
|
|
|
The function value is a BOOLEAN indicating whether or not the ARC name
|
|
was resolved to an NT name.
|
|
|
|
--*/
|
|
|
|
{
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
NTSTATUS status;
|
|
UCHAR deviceNameBuffer[256];
|
|
WCHAR arcNameUnicodeBuffer[64];
|
|
UCHAR arcNameStringBuffer[256];
|
|
STRING deviceNameString;
|
|
STRING arcNameString;
|
|
STRING linkString;
|
|
UNICODE_STRING linkUnicodeString;
|
|
UNICODE_STRING deviceNameUnicodeString;
|
|
UNICODE_STRING arcNameUnicodeString;
|
|
HANDLE linkHandle;
|
|
|
|
#if DBG
|
|
|
|
UCHAR debugBuffer[256];
|
|
STRING debugString;
|
|
UNICODE_STRING debugUnicodeString;
|
|
|
|
#endif
|
|
CHAR ArcNameFmt[12];
|
|
|
|
ArcNameFmt[0] = '\\';
|
|
ArcNameFmt[1] = 'A';
|
|
ArcNameFmt[2] = 'r';
|
|
ArcNameFmt[3] = 'c';
|
|
ArcNameFmt[4] = 'N';
|
|
ArcNameFmt[5] = 'a';
|
|
ArcNameFmt[6] = 'm';
|
|
ArcNameFmt[7] = 'e';
|
|
ArcNameFmt[8] = '\\';
|
|
ArcNameFmt[9] = '%';
|
|
ArcNameFmt[10] = 's';
|
|
ArcNameFmt[11] = '\0';
|
|
|
|
//
|
|
// Open the ARC boot device symbolic link object. The boot device
|
|
// driver should have created the object.
|
|
//
|
|
|
|
sprintf( deviceNameBuffer,
|
|
ArcNameFmt,
|
|
LoaderBlock->ArcBootDeviceName );
|
|
|
|
RtlInitAnsiString( &deviceNameString, deviceNameBuffer );
|
|
|
|
status = RtlAnsiStringToUnicodeString( &deviceNameUnicodeString,
|
|
&deviceNameString,
|
|
TRUE );
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
return FALSE;
|
|
}
|
|
|
|
InitializeObjectAttributes( &objectAttributes,
|
|
&deviceNameUnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL );
|
|
|
|
status = NtOpenSymbolicLinkObject( &linkHandle,
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
&objectAttributes );
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
|
|
#if DBG
|
|
|
|
sprintf( debugBuffer, "IOINIT: unable to resolve %s, Status == %X\n",
|
|
deviceNameBuffer,
|
|
status );
|
|
|
|
RtlInitAnsiString( &debugString, debugBuffer );
|
|
|
|
status = RtlAnsiStringToUnicodeString( &debugUnicodeString,
|
|
&debugString,
|
|
TRUE );
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
ZwDisplayString( &debugUnicodeString );
|
|
RtlFreeUnicodeString( &debugUnicodeString );
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
RtlFreeUnicodeString( &deviceNameUnicodeString );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Get handle to \SystemRoot symbolic link.
|
|
//
|
|
|
|
arcNameUnicodeString.Buffer = arcNameUnicodeBuffer;
|
|
arcNameUnicodeString.Length = 0;
|
|
arcNameUnicodeString.MaximumLength = sizeof( arcNameUnicodeBuffer );
|
|
|
|
status = NtQuerySymbolicLinkObject( linkHandle,
|
|
&arcNameUnicodeString,
|
|
NULL );
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
return FALSE;
|
|
}
|
|
|
|
arcNameString.Buffer = arcNameStringBuffer;
|
|
arcNameString.Length = 0;
|
|
arcNameString.MaximumLength = sizeof( arcNameStringBuffer );
|
|
|
|
status = RtlUnicodeStringToAnsiString( &arcNameString,
|
|
&arcNameUnicodeString,
|
|
FALSE );
|
|
|
|
arcNameStringBuffer[arcNameString.Length] = '\0';
|
|
|
|
NtClose( linkHandle );
|
|
RtlFreeUnicodeString( &deviceNameUnicodeString );
|
|
|
|
RtlInitAnsiString( &linkString, INIT_SYSTEMROOT_LINKNAME );
|
|
|
|
status = RtlAnsiStringToUnicodeString( &linkUnicodeString,
|
|
&linkString,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
return FALSE;
|
|
}
|
|
|
|
InitializeObjectAttributes( &objectAttributes,
|
|
&linkUnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL );
|
|
|
|
status = NtOpenSymbolicLinkObject( &linkHandle,
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
&objectAttributes );
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
return FALSE;
|
|
}
|
|
|
|
NtMakeTemporaryObject( linkHandle );
|
|
NtClose( linkHandle );
|
|
|
|
sprintf( deviceNameBuffer,
|
|
"%Z%s",
|
|
&arcNameString,
|
|
LoaderBlock->NtBootPathName );
|
|
|
|
//
|
|
// Get NT device name for \SystemRoot assignment.
|
|
//
|
|
|
|
RtlCopyString( NtDeviceName, &arcNameString );
|
|
|
|
deviceNameBuffer[strlen(deviceNameBuffer)-1] = '\0';
|
|
|
|
RtlInitAnsiString(&deviceNameString, deviceNameBuffer);
|
|
|
|
InitializeObjectAttributes( &objectAttributes,
|
|
&linkUnicodeString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
|
|
NULL,
|
|
NULL );
|
|
|
|
status = RtlAnsiStringToUnicodeString( &arcNameUnicodeString,
|
|
&deviceNameString,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
return FALSE;
|
|
}
|
|
|
|
status = NtCreateSymbolicLinkObject( &linkHandle,
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
&objectAttributes,
|
|
&arcNameUnicodeString );
|
|
|
|
RtlFreeUnicodeString( &arcNameUnicodeString );
|
|
RtlFreeUnicodeString( &linkUnicodeString );
|
|
NtClose( linkHandle );
|
|
|
|
#if DBG
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
sprintf( debugBuffer,
|
|
"INIT: Reassigned %s => %s\n",
|
|
INIT_SYSTEMROOT_LINKNAME,
|
|
deviceNameBuffer );
|
|
|
|
} else {
|
|
|
|
sprintf( debugBuffer,
|
|
"INIT: unable to create %s => %s, Status == %X\n",
|
|
INIT_SYSTEMROOT_LINKNAME,
|
|
deviceNameBuffer,
|
|
status );
|
|
}
|
|
|
|
RtlInitAnsiString( &debugString, debugBuffer );
|
|
|
|
status = RtlAnsiStringToUnicodeString( &debugUnicodeString,
|
|
&debugString,
|
|
TRUE );
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
ZwDisplayString( &debugUnicodeString );
|
|
RtlFreeUnicodeString( &debugUnicodeString );
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
IopRevertModuleList(
|
|
IN ULONG ListCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to revert the system's loaded module list to its
|
|
form before attempt to load dump drivers.
|
|
|
|
Arguments:
|
|
|
|
ListCount - The number of loaded modules to fixup (and keep).
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIST_ENTRY nextEntry;
|
|
PLDR_DATA_TABLE_ENTRY loaderEntry;
|
|
|
|
//
|
|
// Scan the loaded module list and revert the base DLL names of all of
|
|
// the modules.
|
|
//
|
|
|
|
nextEntry = PsLoadedModuleList.Flink;
|
|
while (ListCount--) {
|
|
loaderEntry = CONTAINING_RECORD( nextEntry,
|
|
LDR_DATA_TABLE_ENTRY,
|
|
InLoadOrderLinks );
|
|
loaderEntry->BaseDllName.Length = loaderEntry->BaseDllName.MaximumLength;
|
|
if (ListCount) {
|
|
nextEntry = nextEntry->Flink;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now remove all of the remaining entries from the list, if any.
|
|
//
|
|
|
|
while (loaderEntry->InLoadOrderLinks.Flink != &PsLoadedModuleList) {
|
|
RemoveHeadList( &loaderEntry->InLoadOrderLinks );
|
|
}
|
|
}
|
|
|
|
#ifdef _PNP_POWER_
|
|
VOID
|
|
IopVerifyBuiltInBuses(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks each bus instance as reported for the HalQuerySystemInformation
|
|
class, HalInstalledBusInformation. Its purpose is to determine whether control for
|
|
a built-in bus (BIB) has been taken over by an installed bus extender. If this is
|
|
the case, then the bus list and registry structures are updated accordingly.
|
|
|
|
The caller must have acquired both the bus list AND PnP registry resources for
|
|
exclusive (write) access.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PHAL_BUS_INFORMATION BusInfoList;
|
|
ULONG BusInfoCount, i, TmpDwordValue, ServiceInstanceOrdinal;
|
|
PWCHAR p, BufferEnd, StringStart;
|
|
PDRIVER_OBJECT DriverObject;
|
|
PLUGPLAY_BUS_INSTANCE BusInstToFind;
|
|
PPLUGPLAY_BUS_ENUMERATOR BusEnumeratorNode, CurBusEnumeratorNode;
|
|
PPLUGPLAY_BUS_INSTANCE_FULL_DESCRIPTOR BusInstanceNode;
|
|
PLIST_ENTRY CurBusListEntry;
|
|
BOOLEAN NewBusExtenderFound, DevicePathFound;
|
|
HANDLE SystemEnumHandle, DevInstHandle, ServiceEnumHandle;
|
|
UNICODE_STRING TempUnicodeString;
|
|
PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
|
|
WCHAR UnicodeBuffer[20];
|
|
PFILE_OBJECT FileObject;
|
|
PBUS_HANDLER BusHandler = NULL;
|
|
|
|
//
|
|
// First, retrieve the list of installed bus instances.
|
|
//
|
|
Status = PiGetInstalledBusInformation(&BusInfoList,
|
|
&BusInfoCount
|
|
);
|
|
if(!NT_SUCCESS(Status)) {
|
|
//
|
|
// Couldn't get info on installed buses--output a debug message and return.
|
|
//
|
|
#if DBG
|
|
DbgPrint("IopVerifyBuiltInBuses: Couldn't get list of installed buses.\n");
|
|
#endif // DBG
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Open the HKLM\System\CurrentControlSet\Enum key, to be used as a base handle
|
|
// for opening device instance keys, should any modifications be required later.
|
|
//
|
|
Status = IopOpenRegistryKey(&SystemEnumHandle,
|
|
NULL,
|
|
&CmRegistryMachineSystemCurrentControlSetEnumName,
|
|
KEY_ALL_ACCESS,
|
|
FALSE
|
|
);
|
|
if(!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("IopVerifyBuiltInBuses: couldn't open HKLM\\System\\Enum key.\n");
|
|
#endif // DBG
|
|
|
|
goto PrepareForReturn;
|
|
}
|
|
|
|
for(i = 0; i < BusInfoCount; i++) {
|
|
|
|
if (BusHandler) {
|
|
HalDereferenceBusHandler (BusHandler);
|
|
}
|
|
|
|
//
|
|
// Examine this bus instance to see whether it's still being controlled by
|
|
// the built-in bus extender for which we originally registered it.
|
|
//
|
|
|
|
BusHandler = HalReferenceHandlerForBus (BusInfoList[i].BusType,
|
|
BusInfoList[i].BusNumber
|
|
);
|
|
|
|
if (BusHandler == NULL) {
|
|
continue;
|
|
} else {
|
|
if (BusHandler->DeviceObject == NULL) {
|
|
|
|
//
|
|
// Nothing to be done for such a bus instance--continue with next one.
|
|
//
|
|
|
|
continue;
|
|
}
|
|
}
|
|
#if 0
|
|
//
|
|
// Retrieve the corresponding driver object for this bus instance.
|
|
//
|
|
DriverObject = BusInfoList[i].DeviceObject->DriverObject;
|
|
#endif
|
|
//
|
|
// Now find the corresponding bus instance node
|
|
//
|
|
BusInstToFind.BusNumber = BusInfoList[i].BusNumber;
|
|
BusInstToFind.BusType.BusClass = SystemBus;
|
|
BusInstToFind.BusType.SystemBusType = BusInfoList[i].BusType;
|
|
|
|
Status = PiFindBusInstanceNode(&BusInstToFind,
|
|
NULL,
|
|
&BusEnumeratorNode,
|
|
&BusInstanceNode
|
|
);
|
|
if(!NT_SUCCESS(Status)) {
|
|
#if 1
|
|
//
|
|
// We couldn't find this bus instance in our list. Apparently a bus extender
|
|
// registered the bus instance in its DriverEntry. We need to add this bus
|
|
// instance to the appropriate bus enumerator.
|
|
//
|
|
|
|
Status = IopRegisterNewBusInstance(BusHandler);
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("IopVerifyBuiltInBuses: add new bus instance failed:\n");
|
|
DbgPrint(" BusType = %x, BusNumber = %u.\n",
|
|
(ULONG)BusInfoList[i].BusType,
|
|
BusInfoList[i].BusNumber
|
|
);
|
|
}
|
|
#endif // DBG
|
|
|
|
#else
|
|
//
|
|
// We couldn't find this bus instance in our list. Apparently, one of
|
|
// the installable bus extenders isn't playing by the rules (i.e., they're
|
|
// going out and grabbing non-BIB buses at init time. For now, just output
|
|
// a debug message, and continue on.
|
|
//
|
|
#if DBG
|
|
DbgPrint("IopVerifyBuiltInBuses: non-registered bus instance found:\n");
|
|
DbgPrint(" BusType = %x, BusNumber = %u.\n",
|
|
(ULONG)BusInfoList[i].BusType,
|
|
BusInfoList[i].BusNumber
|
|
);
|
|
#endif // DBG
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
#if 1
|
|
//
|
|
// See if the driver object for the bus instance matches the bus enumerator's
|
|
// driver object to which it's currently attached.
|
|
//
|
|
|
|
if (BusEnumeratorNode->DriverName.Length != 0) {
|
|
|
|
//
|
|
// If EnumeratorNode does not have DriverName, it is a built-in bus enumerator
|
|
// and its bus instance has been taken over by some bus extender. Otherwise,
|
|
// the device object of the bus instance should be NULL.
|
|
//
|
|
|
|
DriverObject = IopReferenceDriverObjectByName (&BusEnumeratorNode->DriverName);
|
|
if (DriverObject == NULL) {
|
|
#if DBG
|
|
DbgPrint("IopVerifyBuiltInBuses: Couldn't reference bus enumerator's driver object by name %wZ\n",
|
|
BusEnumeratorNode->DriverName.Buffer);
|
|
#endif // DBG
|
|
//
|
|
// Can not reference the driver object by name. The bus extender
|
|
// must have been unloaded.
|
|
// If the bus enumerator specified any Plug&Play IDs for buses it
|
|
// controlled, then we will leave it in our bus list, so that if
|
|
// enumeration turns up a bus of this type, we will be able to match it
|
|
// up with its corresponding extender, and then inform the user that
|
|
// there is a problem with the bus driver for the newly found bus.
|
|
//
|
|
|
|
if (!BusEnumeratorNode->PlugPlayIDCount) {
|
|
//
|
|
// There's no need to keep this around, so remove from the bus
|
|
// extender list, and free its memory.
|
|
//
|
|
RemoveEntryList(&(BusEnumeratorNode->BusEnumeratorListEntry));
|
|
ExFreePool(BusEnumeratorNode->ServiceName.Buffer);
|
|
RtlFreeUnicodeString(&BusEnumeratorNode->DriverName);
|
|
ExFreePool(BusEnumeratorNode);
|
|
}
|
|
|
|
continue;
|
|
} else {
|
|
if (DriverObject == BusHandler->DeviceObject->DriverObject) {
|
|
|
|
//
|
|
// The Driver object of the bus instance matches the bus enumerator's
|
|
// driver object to which it's currently attached.
|
|
//
|
|
|
|
ObDereferenceObject (DriverObject);
|
|
continue;
|
|
}
|
|
}
|
|
ObDereferenceObject (DriverObject);
|
|
}
|
|
#else
|
|
//
|
|
// See if the driver object for the bus instance matches the bus enumerator's
|
|
// driver object to which it's currently attached.
|
|
//
|
|
if(BusEnumeratorNode->DriverObject == DriverObject) {
|
|
//
|
|
// Then all's well, and we can continue on with the next bus instance.
|
|
//
|
|
continue;
|
|
}
|
|
#endif // 1
|
|
|
|
//
|
|
// An installable bus extender has taken control away from the built-in
|
|
// bus extender for this bus instance. Search through our bus enumerator
|
|
// list, looking for the new controlling driver object.
|
|
//
|
|
NewBusExtenderFound = FALSE;
|
|
|
|
for(CurBusListEntry = PpBusListHead.Flink;
|
|
CurBusListEntry != &PpBusListHead;
|
|
CurBusListEntry = CurBusListEntry->Flink) {
|
|
|
|
CurBusEnumeratorNode = CONTAINING_RECORD(CurBusListEntry,
|
|
PLUGPLAY_BUS_ENUMERATOR,
|
|
BusEnumeratorListEntry
|
|
);
|
|
#if 1
|
|
if (RtlEqualUnicodeString(&BusHandler->DeviceObject->DriverObject->DriverExtension->ServiceKeyName,
|
|
&CurBusEnumeratorNode->ServiceName, TRUE )) {
|
|
#else
|
|
if(CurBusEnumeratorNode->DriverObject == DriverObject) {
|
|
#endif
|
|
//
|
|
// We've found the new controlling bus extender for this
|
|
// bus instance.
|
|
//
|
|
NewBusExtenderFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!NewBusExtenderFound) {
|
|
//
|
|
// We can't find out who took control of this bus instance, so
|
|
// just output a debug message and continue with next bus instance.
|
|
//
|
|
#if DBG
|
|
DbgPrint("IopVerifyBuiltInBuses: could not locate new owner of bus\n");
|
|
DbgPrint(" instance %wZ\n",
|
|
&(BusInstanceNode->DeviceInstancePath)
|
|
);
|
|
#endif // DBG
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Open this device instance key, so that we can modify the information
|
|
// that has changed.
|
|
//
|
|
Status = IopOpenRegistryKey(&DevInstHandle,
|
|
SystemEnumHandle,
|
|
&(BusInstanceNode->DeviceInstancePath),
|
|
KEY_ALL_ACCESS,
|
|
FALSE
|
|
);
|
|
if(!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("IopVerifyBuiltInBuses: couldn't open device instance key\n");
|
|
DbgPrint(" %wZ for modification.\n",
|
|
&(BusInstanceNode->DeviceInstancePath)
|
|
);
|
|
#endif // DBG
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// See if the associated configuration space is different now that the new
|
|
// bus extender has control (unlikely). If so, write out a new
|
|
// BusDataType value entry.
|
|
//
|
|
if(BusInstanceNode->AssociatedConfigurationSpace != BusInfoList[i].ConfigurationType) {
|
|
#if DBG
|
|
DbgPrint("IopVerifyBuiltInBuses: ConfigurationType for bus instance %wZ\n",
|
|
&(BusInstanceNode->DeviceInstancePath)
|
|
);
|
|
DbgPrint(" changed from %x to %x.\n",
|
|
BusInstanceNode->AssociatedConfigurationSpace,
|
|
BusInfoList[i].ConfigurationType
|
|
);
|
|
#endif // DBG
|
|
|
|
BusInstanceNode->AssociatedConfigurationSpace = BusInfoList[i].ConfigurationType;
|
|
|
|
TmpDwordValue = (ULONG)(BusInfoList[i].ConfigurationType);
|
|
PiWstrToUnicodeString(&TempUnicodeString, REGSTR_VALUE_BUSDATATYPE);
|
|
ZwSetValueKey(DevInstHandle,
|
|
&TempUnicodeString,
|
|
TITLE_INDEX_VALUE,
|
|
REG_DWORD,
|
|
&TmpDwordValue,
|
|
sizeof(TmpDwordValue)
|
|
);
|
|
}
|
|
|
|
//
|
|
// Write the name of the new controlling service for this bus instance to the
|
|
// registry.
|
|
//
|
|
PiWstrToUnicodeString(&TempUnicodeString, REGSTR_VALUE_SERVICE);
|
|
Status = ZwSetValueKey(DevInstHandle,
|
|
&TempUnicodeString,
|
|
TITLE_INDEX_VALUE,
|
|
REG_SZ,
|
|
CurBusEnumeratorNode->ServiceName.Buffer,
|
|
CurBusEnumeratorNode->ServiceName.MaximumLength
|
|
);
|
|
if(!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("IopVerifyBuiltInBuses: couldn't write service name to registry.\n");
|
|
#endif // DBG
|
|
goto ContinueWithNextBus0;
|
|
}
|
|
|
|
//
|
|
// Now, register this device instance, creating a service instance value entry
|
|
// in the controlling service's volatile Enum subkey.
|
|
//
|
|
// Open up the service's Enum subkey.
|
|
//
|
|
Status = IopOpenServiceEnumKeys(&(CurBusEnumeratorNode->ServiceName),
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&ServiceEnumHandle,
|
|
TRUE
|
|
);
|
|
if(!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("IopVerifyBuiltInBuses: couldn't open Enum subkey for service:\n");
|
|
DbgPrint(" %wZ\n",
|
|
&(CurBusEnumeratorNode->ServiceName)
|
|
);
|
|
#endif // DBG
|
|
|
|
//
|
|
// Clean up what we've done, so we don't have dangling registry references.
|
|
//
|
|
PiWstrToUnicodeString(&TempUnicodeString, REGSTR_VALUE_SERVICE);
|
|
ZwDeleteValueKey(DevInstHandle, &TempUnicodeString);
|
|
goto ContinueWithNextBus0;
|
|
}
|
|
|
|
//
|
|
// Retrieve the next available service instance ordinal.
|
|
//
|
|
ServiceInstanceOrdinal = 0;
|
|
Status = IopGetRegistryValue(ServiceEnumHandle,
|
|
REGSTR_VALUE_COUNT,
|
|
&KeyValueInformation
|
|
);
|
|
if(NT_SUCCESS(Status)) {
|
|
if((KeyValueInformation->Type == REG_DWORD) &&
|
|
(KeyValueInformation->DataLength >= sizeof(ULONG))) {
|
|
|
|
ServiceInstanceOrdinal = *(PULONG)KEY_VALUE_DATA(KeyValueInformation);
|
|
}
|
|
ExFreePool(KeyValueInformation);
|
|
}
|
|
|
|
BusInstanceNode->ServiceInstanceOrdinal = ServiceInstanceOrdinal;
|
|
|
|
//
|
|
// Add a new service instance entry to the service's Enum list.
|
|
//
|
|
PiUlongToUnicodeString(&TempUnicodeString,
|
|
UnicodeBuffer,
|
|
sizeof(UnicodeBuffer),
|
|
ServiceInstanceOrdinal
|
|
);
|
|
Status = ZwSetValueKey(ServiceEnumHandle,
|
|
&TempUnicodeString,
|
|
TITLE_INDEX_VALUE,
|
|
REG_SZ,
|
|
BusInstanceNode->DeviceInstancePath.Buffer,
|
|
BusInstanceNode->DeviceInstancePath.MaximumLength
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
//
|
|
// Now we can increment the instance count, and save it back.
|
|
//
|
|
ServiceInstanceOrdinal++;
|
|
PiWstrToUnicodeString(&TempUnicodeString, REGSTR_VALUE_COUNT);
|
|
Status = ZwSetValueKey(ServiceEnumHandle,
|
|
&TempUnicodeString,
|
|
TITLE_INDEX_VALUE,
|
|
REG_DWORD,
|
|
&ServiceInstanceOrdinal,
|
|
sizeof(ServiceInstanceOrdinal)
|
|
);
|
|
}
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
//
|
|
// Clean up what we've done, so we don't have dangling registry references.
|
|
//
|
|
PiWstrToUnicodeString(&TempUnicodeString, REGSTR_VALUE_SERVICE);
|
|
ZwDeleteValueKey(DevInstHandle, &TempUnicodeString);
|
|
BusInstanceNode->ServiceInstanceOrdinal = PLUGPLAY_NO_INSTANCE;
|
|
goto ContinueWithNextBus1;
|
|
}
|
|
|
|
//
|
|
// The bus extender controlling this bus instance created a device object for it.
|
|
// We will now find the corresponding NT device path under the service's Enum key,
|
|
// and move it to its correct location in the NtDevicePaths value entry of the
|
|
// device instance key.
|
|
//
|
|
Status = IopGetRegistryValue(ServiceEnumHandle,
|
|
REGSTR_VALUE_NTDEVICEPATHS,
|
|
&KeyValueInformation
|
|
);
|
|
if(NT_SUCCESS(Status)) {
|
|
if((KeyValueInformation->Type == REG_MULTI_SZ) &&
|
|
(KeyValueInformation->DataLength > sizeof(WCHAR))) {
|
|
//
|
|
// Examine each NT device path in this list, and see if its corresponding
|
|
// device object is the same as the device object for this bus instance.
|
|
//
|
|
StringStart = p = (PWCHAR)KEY_VALUE_DATA(KeyValueInformation);
|
|
BufferEnd = (PWCHAR)((PUCHAR)p + KeyValueInformation->DataLength);
|
|
while(p < BufferEnd) {
|
|
if(!*p) {
|
|
if(TmpDwordValue = (PUCHAR)p - (PUCHAR)StringStart) {
|
|
|
|
TempUnicodeString.MaximumLength =
|
|
(TempUnicodeString.Length = (USHORT)TmpDwordValue)
|
|
+ sizeof(UNICODE_NULL);
|
|
TempUnicodeString.Buffer = StringStart;
|
|
|
|
//
|
|
// We have an NT device path, now retrieve the corresponding
|
|
// device object.
|
|
//
|
|
Status = PiGetDeviceObjectFilePointer(&TempUnicodeString,
|
|
&FileObject
|
|
);
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
if(FileObject->DeviceObject == BusHandler->DeviceObject) {
|
|
//
|
|
// Then we've found the device path for this device object.
|
|
//
|
|
DevicePathFound = TRUE;
|
|
|
|
//
|
|
// Add this device path to the NtDevicePaths value
|
|
// entry under the device instance key.
|
|
//
|
|
Status = IopAppendStringToValueKey(DevInstHandle,
|
|
REGSTR_VALUE_NT_PHYSICAL_DEVICE_PATHS,
|
|
&TempUnicodeString,
|
|
TRUE
|
|
);
|
|
if(NT_SUCCESS(Status)) {
|
|
//
|
|
// We successfully added the path to the device
|
|
// instance key, so now remove it from the service's
|
|
// Enum key.
|
|
//
|
|
IopRemoveStringFromValueKey(ServiceEnumHandle,
|
|
REGSTR_VALUE_NTDEVICEPATHS,
|
|
&TempUnicodeString
|
|
);
|
|
}
|
|
} else {
|
|
DevicePathFound = FALSE;
|
|
}
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
if(DevicePathFound) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
StringStart = p + 1;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
p++;
|
|
}
|
|
}
|
|
ExFreePool(KeyValueInformation);
|
|
}
|
|
|
|
//
|
|
// All the registry modifications are complete. Now remove the bus instance
|
|
// node from its old bus enumerator list, and insert it into the new bus
|
|
// enumerator list.
|
|
//
|
|
RemoveEntryList(&(BusInstanceNode->BusInstanceListEntry));
|
|
InsertTailList(&(CurBusEnumeratorNode->BusInstanceListEntry),
|
|
&(BusInstanceNode->BusInstanceListEntry)
|
|
);
|
|
|
|
ContinueWithNextBus1:
|
|
|
|
ZwClose(ServiceEnumHandle);
|
|
|
|
ContinueWithNextBus0:
|
|
|
|
ZwClose(DevInstHandle);
|
|
}
|
|
|
|
if (BusHandler) {
|
|
HalDereferenceBusHandler(BusHandler);
|
|
}
|
|
|
|
ZwClose(SystemEnumHandle);
|
|
|
|
PrepareForReturn:
|
|
|
|
ExFreePool(BusInfoList);
|
|
}
|
|
|
|
NTSTATUS
|
|
IopRegisterNewBusInstance(
|
|
PBUS_HANDLER BusHandler
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds the bus instance specified by BusHandler to the appropriate enumberator
|
|
in our global enumberator list.
|
|
|
|
The caller must have acquired both the bus list AND PnP registry resources for
|
|
exclusive (write) access.
|
|
|
|
Arguments:
|
|
|
|
BusHandler - Supplies a Bushandler to specified the new bus instance to be registered.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIST_ENTRY currentPnPBusListEntry, currentPnPBusInstance;
|
|
PPLUGPLAY_BUS_ENUMERATOR curBusEnumerator;
|
|
PPLUGPLAY_BUS_INSTANCE_FULL_DESCRIPTOR curBusInstNode, newBusInstanceNode;
|
|
PUNICODE_STRING serviceName;
|
|
UNICODE_STRING deviceInstancePath;
|
|
BOOLEAN found = FALSE;
|
|
ULONG count, i;
|
|
NTSTATUS status;
|
|
HANDLE serviceHandle, devInstKeyHandle;
|
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|
PWCHAR p, bufferEnd, stringStart;
|
|
ULONG stringLength;
|
|
UNICODE_STRING devicePathString;
|
|
PFILE_OBJECT fileObject;
|
|
|
|
serviceName = &BusHandler->DeviceObject->DriverObject->DriverExtension->ServiceKeyName;
|
|
|
|
//
|
|
// Search our enumerator list to find the enumerator for the new bus instance.
|
|
//
|
|
|
|
for (currentPnPBusListEntry = PpBusListHead.Flink;
|
|
currentPnPBusListEntry != &PpBusListHead;
|
|
currentPnPBusListEntry = currentPnPBusListEntry->Flink) {
|
|
|
|
curBusEnumerator = CONTAINING_RECORD(currentPnPBusListEntry,
|
|
PLUGPLAY_BUS_ENUMERATOR,
|
|
BusEnumeratorListEntry
|
|
);
|
|
if (RtlEqualUnicodeString(serviceName, &curBusEnumerator->ServiceName, TRUE)) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
//
|
|
// Search the device instance path and device instance ordinal for the bus
|
|
//
|
|
|
|
status = IoQueryDeviceEnumInfo(serviceName, &count);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
status = IopOpenServiceEnumKeys (
|
|
serviceName,
|
|
KEY_READ,
|
|
&serviceHandle,
|
|
NULL,
|
|
FALSE
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
//
|
|
// Open the subkey specified by ServiceName\Enum instance number under
|
|
// System\Enum subtree.
|
|
//
|
|
|
|
status = IopServiceInstanceToDeviceInstance (serviceHandle,
|
|
NULL,
|
|
i,
|
|
NULL,
|
|
&devInstKeyHandle,
|
|
KEY_READ
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
ZwClose(serviceHandle);
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Retrieve the NT physical device path(s) from the device instance key (this should've been
|
|
// placed here by the bus extender's calling IoRegisterDevicePath).
|
|
//
|
|
|
|
status = IopGetRegistryValue(devInstKeyHandle,
|
|
REGSTR_VALUE_NT_PHYSICAL_DEVICE_PATHS,
|
|
&keyValueInformation
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
ZwClose(serviceHandle);
|
|
ZwClose (devInstKeyHandle);
|
|
return status;
|
|
} else if((keyValueInformation->Type != REG_MULTI_SZ) ||
|
|
(keyValueInformation->DataLength <= sizeof(WCHAR))) {
|
|
ExFreePool(keyValueInformation);
|
|
ZwClose(serviceHandle);
|
|
ZwClose (devInstKeyHandle);
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
//
|
|
// For each device path in this list, retrieve the corresponding device object,
|
|
// and search for it in the list of installed buses.
|
|
//
|
|
|
|
found = FALSE;
|
|
stringStart = p = (PWCHAR)KEY_VALUE_DATA(keyValueInformation);
|
|
bufferEnd = (PWCHAR)((PUCHAR)p + keyValueInformation->DataLength);
|
|
while (p < bufferEnd) {
|
|
if (!*p) {
|
|
if (stringLength = (PUCHAR)p - (PUCHAR)stringStart) {
|
|
|
|
devicePathString.MaximumLength =
|
|
(devicePathString.Length = (USHORT)stringLength)
|
|
+ sizeof(UNICODE_NULL);
|
|
devicePathString.Buffer = stringStart;
|
|
|
|
//
|
|
// We have an NT device path, now retrieve the corresponding
|
|
// file object (from which we can get the device object).
|
|
//
|
|
|
|
status = PiGetDeviceObjectFilePointer(&devicePathString,
|
|
&fileObject
|
|
);
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Now, compare this device object pointer with bus handler's
|
|
// device object.
|
|
//
|
|
|
|
if (fileObject->DeviceObject == BusHandler->DeviceObject) {
|
|
|
|
//
|
|
// Then we've found the device instance for the specified bus.
|
|
//
|
|
|
|
found = TRUE;
|
|
}
|
|
ObDereferenceObject(fileObject);
|
|
if (found) {
|
|
break;
|
|
}
|
|
}
|
|
stringStart = p + 1;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
p++;
|
|
}
|
|
ExFreePool(keyValueInformation);
|
|
ZwClose(devInstKeyHandle);
|
|
if (found) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
ZwClose(serviceHandle);
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
status = IopServiceInstanceToDeviceInstance (
|
|
serviceHandle,
|
|
NULL,
|
|
i,
|
|
&deviceInstancePath,
|
|
NULL,
|
|
KEY_READ
|
|
);
|
|
ZwClose(serviceHandle);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Now, create a new PLUGPLAY_BUS_INSTANCE_FULL_DESCRIPTOR for this bus instance,
|
|
// and add it to the bus enumerator's bus list.
|
|
//
|
|
|
|
newBusInstanceNode = ExAllocatePool(PagedPool,
|
|
sizeof(PLUGPLAY_BUS_INSTANCE_FULL_DESCRIPTOR)
|
|
);
|
|
if (!newBusInstanceNode) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if(!IopConcatenateUnicodeStrings(&(newBusInstanceNode->DeviceInstancePath),
|
|
&deviceInstancePath,
|
|
NULL)) {
|
|
|
|
ExFreePool(newBusInstanceNode);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
newBusInstanceNode->RootBus = TRUE;
|
|
newBusInstanceNode->Processed = FALSE;
|
|
newBusInstanceNode->ServiceInstanceOrdinal = i;
|
|
newBusInstanceNode->AssociatedConfigurationSpace = BusHandler->ConfigurationType;
|
|
newBusInstanceNode->BusInstanceInformation.BusNumber = BusHandler->BusNumber;
|
|
newBusInstanceNode->BusInstanceInformation.BusType.BusClass = SystemBus;
|
|
newBusInstanceNode->BusInstanceInformation.BusType.SystemBusType = BusHandler->InterfaceType;
|
|
PiGetBusDescription(BusHandler->InterfaceType,
|
|
newBusInstanceNode->BusInstanceInformation.BusName
|
|
);
|
|
|
|
//
|
|
// Finally, insert this node at the end of the bus enumerator's list.
|
|
//
|
|
|
|
InsertTailList(&(curBusEnumerator->BusInstanceListEntry),
|
|
&(newBusInstanceNode->BusInstanceListEntry)
|
|
);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
#endif // _PNP_POWER_
|
|
|
|
VOID
|
|
IopStoreSystemPartitionInformation(
|
|
IN PUNICODE_STRING NtSystemPartitionDeviceName,
|
|
IN OUT PUNICODE_STRING OsLoaderPathName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes two values to the registry (under HKLM\SYSTEM\Setup)--one
|
|
containing the NT device name of the system partition and the other containing
|
|
the path to the OS loader. These values will later be migrated into a
|
|
Win95-compatible registry location (NT path converted to DOS path), so that
|
|
installation programs (including our own setup) have a rock-solid way of knowing
|
|
what the system partition is, on both ARC and x86.
|
|
|
|
ERRORS ENCOUNTERED IN THIS ROUTINE ARE NOT CONSIDERED FATAL.
|
|
|
|
Arguments:
|
|
|
|
NtSystemPartitionDeviceName - supplies the NT device name of the system partition.
|
|
|
|
OsLoaderPathName - supplies the path (on the partition specified in the 1st parameter)
|
|
where the OS loader is located. Upon return, this path will have had its trailing
|
|
backslash removed (if present, and path isn't root).
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE systemHandle, setupHandle;
|
|
UNICODE_STRING nameString;
|
|
//
|
|
// Declare a unicode buffer big enough to contain the longest string we'll be using.
|
|
// (ANSI string in 'sizeof()' below on purpose--we want the number of chars here.)
|
|
//
|
|
WCHAR nameBuffer[sizeof("SystemPartition")];
|
|
|
|
//
|
|
// Both UNICODE_STRING buffers should be NULL-terminated.
|
|
//
|
|
|
|
ASSERT( NtSystemPartitionDeviceName->MaximumLength >= NtSystemPartitionDeviceName->Length + sizeof(WCHAR) );
|
|
ASSERT( NtSystemPartitionDeviceName->Buffer[NtSystemPartitionDeviceName->Length / sizeof(WCHAR)] == L'\0' );
|
|
|
|
ASSERT( OsLoaderPathName->MaximumLength >= OsLoaderPathName->Length + sizeof(WCHAR) );
|
|
ASSERT( OsLoaderPathName->Buffer[OsLoaderPathName->Length / sizeof(WCHAR)] == L'\0' );
|
|
|
|
//
|
|
// Open HKLM\SYSTEM key.
|
|
//
|
|
|
|
status = IopOpenRegistryKey(&systemHandle,
|
|
NULL,
|
|
&CmRegistryMachineSystemName,
|
|
KEY_ALL_ACCESS,
|
|
FALSE
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
#if DBG
|
|
DbgPrint("IopStoreSystemPartitionInformation: couldn't open \\REGISTRY\\MACHINE\\SYSTEM - %x\n", status);
|
|
#endif // DBG
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Now open/create the setup subkey.
|
|
//
|
|
|
|
ASSERT( sizeof(L"Setup") <= sizeof(nameBuffer) );
|
|
|
|
nameBuffer[0] = L'S';
|
|
nameBuffer[1] = L'e';
|
|
nameBuffer[2] = L't';
|
|
nameBuffer[3] = L'u';
|
|
nameBuffer[4] = L'p';
|
|
nameBuffer[5] = L'\0';
|
|
|
|
nameString.MaximumLength = sizeof(L"Setup");
|
|
nameString.Length = sizeof(L"Setup") - sizeof(WCHAR);
|
|
nameString.Buffer = nameBuffer;
|
|
|
|
status = IopOpenRegistryKeyPersist(&setupHandle,
|
|
systemHandle,
|
|
&nameString,
|
|
KEY_ALL_ACCESS,
|
|
TRUE,
|
|
NULL
|
|
);
|
|
|
|
NtClose(systemHandle); // Don't need the handle to the HKLM\System key anymore.
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
#if DBG
|
|
DbgPrint("IopStoreSystemPartitionInformation: couldn't open Setup subkey - %x\n", status);
|
|
#endif // DBG
|
|
return;
|
|
}
|
|
|
|
ASSERT( sizeof(L"SystemPartition") <= sizeof(nameBuffer) );
|
|
|
|
nameBuffer[0] = L'S';
|
|
nameBuffer[1] = L'y';
|
|
nameBuffer[2] = L's';
|
|
nameBuffer[3] = L't';
|
|
nameBuffer[4] = L'e';
|
|
nameBuffer[5] = L'm';
|
|
nameBuffer[6] = L'P';
|
|
nameBuffer[7] = L'a';
|
|
nameBuffer[8] = L'r';
|
|
nameBuffer[9] = L't';
|
|
nameBuffer[10] = L'i';
|
|
nameBuffer[11] = L't';
|
|
nameBuffer[12] = L'i';
|
|
nameBuffer[13] = L'o';
|
|
nameBuffer[14] = L'n';
|
|
nameBuffer[15] = L'\0';
|
|
|
|
nameString.MaximumLength = sizeof(L"SystemPartition");
|
|
nameString.Length = sizeof(L"SystemPartition") - sizeof(WCHAR);
|
|
|
|
status = NtSetValueKey(setupHandle,
|
|
&nameString,
|
|
TITLE_INDEX_VALUE,
|
|
REG_SZ,
|
|
NtSystemPartitionDeviceName->Buffer,
|
|
NtSystemPartitionDeviceName->Length + sizeof(WCHAR)
|
|
);
|
|
#if DBG
|
|
if (!NT_SUCCESS(status)) {
|
|
DbgPrint("IopStoreSystemPartitionInformation: couldn't write SystemPartition value - %x\n", status);
|
|
}
|
|
#endif // DBG
|
|
|
|
ASSERT( sizeof(L"OsLoaderPath") <= sizeof(nameBuffer) );
|
|
|
|
nameBuffer[0] = L'O';
|
|
nameBuffer[1] = L's';
|
|
nameBuffer[2] = L'L';
|
|
nameBuffer[3] = L'o';
|
|
nameBuffer[4] = L'a';
|
|
nameBuffer[5] = L'd';
|
|
nameBuffer[6] = L'e';
|
|
nameBuffer[7] = L'r';
|
|
nameBuffer[8] = L'P';
|
|
nameBuffer[9] = L'a';
|
|
nameBuffer[10] = L't';
|
|
nameBuffer[11] = L'h';
|
|
nameBuffer[12] = L'\0';
|
|
|
|
nameString.MaximumLength = sizeof(L"OsLoaderPath");
|
|
nameString.Length = sizeof(L"OsLoaderPath") - sizeof(WCHAR);
|
|
|
|
//
|
|
// Strip off the trailing backslash from the path (unless, of course, the path is a
|
|
// single backslash).
|
|
//
|
|
|
|
if ((OsLoaderPathName->Length > sizeof(WCHAR)) &&
|
|
(*(PWCHAR)((PCHAR)OsLoaderPathName->Buffer + OsLoaderPathName->Length - sizeof(WCHAR)) == L'\\')) {
|
|
|
|
OsLoaderPathName->Length -= sizeof(WCHAR);
|
|
*(PWCHAR)((PCHAR)OsLoaderPathName->Buffer + OsLoaderPathName->Length) = L'\0';
|
|
}
|
|
|
|
status = NtSetValueKey(setupHandle,
|
|
&nameString,
|
|
TITLE_INDEX_VALUE,
|
|
REG_SZ,
|
|
OsLoaderPathName->Buffer,
|
|
OsLoaderPathName->Length + sizeof(WCHAR)
|
|
);
|
|
#if DBG
|
|
if (!NT_SUCCESS(status)) {
|
|
DbgPrint("IopStoreSystemPartitionInformation: couldn't write OsLoaderPath value - %x\n", status);
|
|
}
|
|
#endif // DBG
|
|
|
|
NtClose(setupHandle);
|
|
}
|
|
|