#include <ntoskrnl.h>
#define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
/* GLOBALS ********************************************************************/
POBJECT_TYPE IoDriverObjectType = NULL;
+#define TAG_RTLREGISTRY 'vrqR'
+
extern BOOLEAN ExpInTextModeSetup;
+extern BOOLEAN PnpSystemInit;
+
+USHORT IopGroupIndex;
+PLIST_ENTRY IopGroupTable;
/* PRIVATE FUNCTIONS **********************************************************/
-NTSTATUS STDCALL
+NTSTATUS NTAPI
IopInvalidDeviceRequest(
PDEVICE_OBJECT DeviceObject,
PIRP Irp)
if (DriverObject->DriverSection)
{
/* Unload it */
- //LdrpUnloadImage(DriverObject->DriverSection);
+ MmUnloadSystemImage(DriverObject->DriverSection);
}
/* Check if it has a name */
ExFreePool(DriverObject->DriverName.Buffer);
}
+#if 0 /* See a bit of hack in IopCreateDriver */
/* Check if it has a service key name */
if (DriverObject->DriverExtension->ServiceKeyName.Buffer)
{
/* Free it */
- //ExFreePool(DriverObject->DriverExtension->ServiceKeyName.Buffer);
+ ExFreePool(DriverObject->DriverExtension->ServiceKeyName.Buffer);
}
+#endif
}
NTSTATUS FASTCALL
UNICODE_STRING DriverName;
NTSTATUS Status;
- DPRINT("IopOpenDriverObject(%p '%wZ' %x)\n",
+ DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
DriverObject, ServiceName, FileSystem);
*DriverObject = NULL;
/* Open driver object */
Status = ObReferenceObjectByName(
&DriverName,
- OBJ_OPENIF | OBJ_KERNEL_HANDLE, /* Attributes */
+ OBJ_OPENIF | OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, /* Attributes */
NULL, /* PassedAccessState */
0, /* DesiredAccess */
IoDriverObjectType,
(PVOID*)&Object);
if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Failed to reference driver object, status=0x%08x\n", Status);
return Status;
+ }
*DriverObject = Object;
+ DPRINT("Driver Object: %p\n", Object);
+
return STATUS_SUCCESS;
}
+/*
+ * RETURNS
+ * TRUE if String2 contains String1 as a suffix.
+ */
+BOOLEAN
+NTAPI
+IopSuffixUnicodeString(
+ IN PCUNICODE_STRING String1,
+ IN PCUNICODE_STRING String2)
+{
+ PWCHAR pc1;
+ PWCHAR pc2;
+ ULONG Length;
+
+ if (String2->Length < String1->Length)
+ return FALSE;
+
+ Length = String1->Length / 2;
+ pc1 = String1->Buffer;
+ pc2 = &String2->Buffer[String2->Length / sizeof(WCHAR) - Length];
+
+ if (pc1 && pc2)
+ {
+ while (Length--)
+ {
+ if( *pc1++ != *pc2++ )
+ return FALSE;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
/*
* IopDisplayLoadingMessage
*
VOID
FASTCALL
INIT_FUNCTION
-IopDisplayLoadingMessage(PVOID ServiceName,
- BOOLEAN Unicode)
+IopDisplayLoadingMessage(PUNICODE_STRING ServiceName)
{
CHAR TextBuffer[256];
- PCHAR Extra = ".sys";
+ UNICODE_STRING DotSys = RTL_CONSTANT_STRING(L".SYS");
if (ExpInTextModeSetup) return;
- if (Unicode)
- {
- if (wcsstr(_wcsupr(ServiceName), L".SYS")) Extra = "";
- sprintf(TextBuffer,
- "%s%s%s\\%S%s\n",
- KeLoaderBlock->ArcBootDeviceName,
- KeLoaderBlock->NtBootPathName,
- "System32\\Drivers",
- (PWCHAR)ServiceName,
- Extra);
- }
- else
- {
- if (strstr(_strupr(ServiceName), ".SYS")) Extra = "";
- sprintf(TextBuffer,
- "%s%s%s\\%s%s\n",
- KeLoaderBlock->ArcBootDeviceName,
- KeLoaderBlock->NtBootPathName,
- "System32\\Drivers",
- (PCHAR)ServiceName,
- Extra);
- }
+ if (!KeLoaderBlock) return;
+ RtlUpcaseUnicodeString(ServiceName, ServiceName, FALSE);
+ snprintf(TextBuffer, sizeof(TextBuffer),
+ "%s%sSystem32\\Drivers\\%wZ%s\n",
+ KeLoaderBlock->ArcBootDeviceName,
+ KeLoaderBlock->NtBootPathName,
+ ServiceName,
+ IopSuffixUnicodeString(&DotSys, ServiceName) ? "" : ".SYS");
HalDisplayString(TextBuffer);
}
if (InputImagePath.Length == 0)
{
- ImagePath->Length = (33 * sizeof(WCHAR)) + ServiceName->Length;
- ImagePath->MaximumLength = ImagePath->Length + sizeof(UNICODE_NULL);
+ ImagePath->Length = 0;
+ ImagePath->MaximumLength =
+ (33 * sizeof(WCHAR)) + ServiceName->Length + sizeof(UNICODE_NULL);
ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
if (ImagePath->Buffer == NULL)
return STATUS_NO_MEMORY;
- wcscpy(ImagePath->Buffer, L"\\SystemRoot\\system32\\drivers\\");
- wcscat(ImagePath->Buffer, ServiceName->Buffer);
- wcscat(ImagePath->Buffer, L".sys");
+ RtlAppendUnicodeToString(ImagePath, L"\\SystemRoot\\system32\\drivers\\");
+ RtlAppendUnicodeStringToString(ImagePath, ServiceName);
+ RtlAppendUnicodeToString(ImagePath, L".sys");
} else
if (InputImagePath.Buffer[0] != L'\\')
{
- ImagePath->Length = (12 * sizeof(WCHAR)) + InputImagePath.Length;
- ImagePath->MaximumLength = ImagePath->Length + sizeof(UNICODE_NULL);
+ ImagePath->Length = 0;
+ ImagePath->MaximumLength =
+ 12 * sizeof(WCHAR) + InputImagePath.Length + sizeof(UNICODE_NULL);
ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
if (ImagePath->Buffer == NULL)
return STATUS_NO_MEMORY;
- wcscpy(ImagePath->Buffer, L"\\SystemRoot\\");
- wcscat(ImagePath->Buffer, InputImagePath.Buffer);
- ExFreePool(InputImagePath.Buffer);
+ RtlAppendUnicodeToString(ImagePath, L"\\SystemRoot\\");
+ RtlAppendUnicodeStringToString(ImagePath, &InputImagePath);
+
+ /* Free caller's string */
+ ExFreePoolWithTag(InputImagePath.Buffer, TAG_RTLREGISTRY);
}
return STATUS_SUCCESS;
{
RTL_QUERY_REGISTRY_TABLE QueryTable[3];
ULONG ServiceStart;
- UNICODE_STRING ServiceImagePath;
+ UNICODE_STRING ServiceImagePath, CCSName;
NTSTATUS Status;
+ HANDLE CCSKey, ServiceKey;
+ PVOID BaseAddress;
DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName, ModuleObject);
/* FIXME: This check may be removed once the bug is fixed */
if (ServiceName->Buffer == NULL)
+ {
+ DPRINT1("If you see this, please report to Fireball or hpoussin!\n");
return STATUS_UNSUCCESSFUL;
+ }
+
+ /* Open CurrentControlSet */
+ RtlInitUnicodeString(&CCSName,
+ L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
+ Status = IopOpenRegistryKeyEx(&CCSKey, NULL, &CCSName, KEY_READ);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
+ return Status;
+ }
+
+ /* Open service key */
+ Status = IopOpenRegistryKeyEx(&ServiceKey, CCSKey, ServiceName, KEY_READ);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
+ ZwClose(CCSKey);
+ return Status;
+ }
/*
* Get information about the service.
QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
QueryTable[1].EntryContext = &ServiceImagePath;
- Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
- ServiceName->Buffer, QueryTable, NULL, NULL);
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
+ (PWSTR)ServiceKey, QueryTable, NULL, NULL);
+
+ ZwClose(ServiceKey);
+ ZwClose(CCSKey);
if (!NT_SUCCESS(Status))
{
- DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
+ DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
return Status;
}
else
{
DPRINT("Loading module\n");
- Status = MmLoadSystemImage(&ServiceImagePath, NULL, NULL, 0, (PVOID)ModuleObject, NULL);
+ Status = MmLoadSystemImage(&ServiceImagePath, NULL, NULL, 0, (PVOID)ModuleObject, &BaseAddress);
}
ExFreePool(ServiceImagePath.Buffer);
return Status;
}
-static NTSTATUS
-NTAPI
-IopDriverInitializeEmpty(IN struct _DRIVER_OBJECT *DriverObject, IN PUNICODE_STRING RegistryPath)
-{
- return STATUS_SUCCESS;
-}
-
/*
* IopInitializeDriverModule
*
UNICODE_STRING RegistryKey;
PDRIVER_INITIALIZE DriverEntry;
PDRIVER_OBJECT Driver;
- PDEVICE_OBJECT DeviceObject;
NTSTATUS Status;
DriverEntry = ModuleObject->EntryPoint;
wcscpy(NameBuffer, FILESYSTEM_ROOT_NAME);
else
wcscpy(NameBuffer, DRIVER_ROOT_NAME);
- wcscat(NameBuffer, ServiceName->Buffer);
RtlInitUnicodeString(&DriverName, NameBuffer);
+ DriverName.MaximumLength = sizeof(NameBuffer);
+
+ RtlAppendUnicodeStringToString(&DriverName, ServiceName);
+
DPRINT("Driver name: '%wZ'\n", &DriverName);
- Status = IopCreateDriver(&DriverName, IopDriverInitializeEmpty, &Driver);
}
else
- {
- Status = IopCreateDriver(NULL, IopDriverInitializeEmpty, &Driver);
- }
+ DriverName.Length = 0;
+
+ Status = IopCreateDriver(
+ DriverName.Length > 0 ? &DriverName : NULL,
+ DriverEntry,
+ &RegistryKey,
+ ModuleObject->DllBase,
+ ModuleObject->SizeOfImage,
+ &Driver);
+ RtlFreeUnicodeString(&RegistryKey);
*DriverObject = Driver;
if (!NT_SUCCESS(Status))
return Status;
}
- Driver->HardwareDatabase = &IopHardwareDatabaseKey;
- Driver->DriverStart = ModuleObject->DllBase;
- Driver->DriverSize = ModuleObject->SizeOfImage;
-
- DPRINT("RegistryKey: %wZ\n", &RegistryKey);
- DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry);
-
- Status = DriverEntry(Driver, &RegistryKey);
-
- RtlFreeUnicodeString(&RegistryKey);
-
- if (!NT_SUCCESS(Status))
- {
- ObMakeTemporaryObject(Driver);
- ObDereferenceObject(Driver);
- return Status;
- }
-
/* Set the driver as initialized */
- Driver->Flags |= DRVO_INITIALIZED;
- DeviceObject = Driver->DeviceObject;
- while (DeviceObject)
- {
- /* Set every device as initialized too */
- DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
- DeviceObject = DeviceObject->NextDevice;
- }
+ IopReadyDeviceObjects(Driver);
- IopReinitializeDrivers();
+ if (PnpSystemInit) IopReinitializeDrivers();
return STATUS_SUCCESS;
}
* Internal routine used by IopAttachFilterDrivers.
*/
-NTSTATUS STDCALL
+NTSTATUS NTAPI
IopAttachFilterDriversCallback(
PWSTR ValueName,
ULONG ValueType,
&ServiceName,
FALSE);
if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("IopGetDriverObject() returned status 0x%08x!\n", Status);
continue;
+ }
}
Status = IopInitializeDevice(DeviceNode, DriverObject);
PDEVICE_NODE DeviceNode,
BOOLEAN Lower)
{
- RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
- PWCHAR KeyBuffer;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { NULL, 0, NULL, NULL, 0, NULL, 0 }, };
UNICODE_STRING Class;
WCHAR ClassBuffer[40];
+ UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
+ HANDLE EnumRootKey, SubKey;
NTSTATUS Status;
+ /* Open enumeration root key */
+ Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL,
+ &EnumRoot, KEY_READ);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
+ return Status;
+ }
+
+ /* Open subkey */
+ Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey,
+ &DeviceNode->InstancePath, KEY_READ);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
+ ZwClose(EnumRootKey);
+ return Status;
+ }
+
/*
* First load the device filters
*/
-
QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
if (Lower)
QueryTable[0].Name = L"LowerFilters";
QueryTable[0].Name = L"UpperFilters";
QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
- KeyBuffer = ExAllocatePool(
- PagedPool,
- (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
- wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
- wcscat(KeyBuffer, DeviceNode->InstancePath.Buffer);
-
RtlQueryRegistryValues(
- RTL_REGISTRY_ABSOLUTE,
- KeyBuffer,
+ RTL_REGISTRY_HANDLE,
+ (PWSTR)SubKey,
QueryTable,
DeviceNode,
NULL);
/*
* Now get the class GUID
*/
-
Class.Length = 0;
Class.MaximumLength = 40 * sizeof(WCHAR);
Class.Buffer = ClassBuffer;
QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
Status = RtlQueryRegistryValues(
- RTL_REGISTRY_ABSOLUTE,
- KeyBuffer,
+ RTL_REGISTRY_HANDLE,
+ (PWSTR)SubKey,
QueryTable,
DeviceNode,
NULL);
- ExFreePool(KeyBuffer);
+ /* Close handles */
+ ZwClose(SubKey);
+ ZwClose(EnumRootKey);
/*
* Load the class filter driver
*/
-
if (NT_SUCCESS(Status))
{
+ UNICODE_STRING ControlClass = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
+
+ Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL,
+ &ControlClass, KEY_READ);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
+ return Status;
+ }
+
+ /* Open subkey */
+ Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey,
+ &Class, KEY_READ);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
+ ZwClose(EnumRootKey);
+ return Status;
+ }
+
QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
if (Lower)
QueryTable[0].Name = L"LowerFilters";
QueryTable[0].EntryContext = NULL;
QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
- KeyBuffer = ExAllocatePool(PagedPool, (58 * sizeof(WCHAR)) + Class.Length);
- wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\");
- wcscat(KeyBuffer, ClassBuffer);
-
RtlQueryRegistryValues(
- RTL_REGISTRY_ABSOLUTE,
- KeyBuffer,
+ RTL_REGISTRY_HANDLE,
+ (PWSTR)SubKey,
QueryTable,
DeviceNode,
NULL);
- ExFreePool(KeyBuffer);
+ /* Clean up */
+ ZwClose(SubKey);
+ ZwClose(EnumRootKey);
}
return STATUS_SUCCESS;
OUT PWCHAR *MissingDriver,
OUT PLOAD_IMPORTS *LoadImports);
-extern KSPIN_LOCK PsLoadedModuleSpinLock;
-
//
// Used for images already loaded (boot drivers)
//
LPWSTR FileExtension;
PUNICODE_STRING ModuleName = &LdrEntry->BaseDllName;
UNICODE_STRING ServiceName;
-#if 1 // Disable for FreeLDR 2.5
- UNICODE_STRING ServiceNameWithExtension;
- PLDR_DATA_TABLE_ENTRY ModuleObject;
-#endif
/*
* Display 'Loading XXX...' message
*/
- IopDisplayLoadingMessage(ModuleName->Buffer, TRUE);
+ IopDisplayLoadingMessage(ModuleName);
+ InbvIndicateProgress();
/*
* Generate filename without path (not needed by freeldr)
FileNameWithoutPath++;
}
- /*
- * Load the module.
- */
-#if 1 // Remove for FreeLDR 2.5.
- RtlCreateUnicodeString(&ServiceNameWithExtension, FileNameWithoutPath);
- Status = LdrProcessDriverModule(LdrEntry, &ServiceNameWithExtension, &ModuleObject);
- if (!NT_SUCCESS(Status))
- {
- CPRINT("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
- return Status;
- }
-#endif
-
/*
* Strip the file extension from ServiceName
*/
Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
if (!NT_SUCCESS(Status))
{
- CPRINT("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
+ DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
return(Status);
}
DeviceNode->ServiceName = ServiceName;
if (!NT_SUCCESS(Status))
{
IopFreeDeviceNode(DeviceNode);
- CPRINT("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
return Status;
}
FASTCALL
IopInitializeBootDrivers(VOID)
{
- PLIST_ENTRY ListHead, NextEntry;
+ PLIST_ENTRY ListHead, NextEntry, NextEntry2;
PLDR_DATA_TABLE_ENTRY LdrEntry;
PDEVICE_NODE DeviceNode;
PDRIVER_OBJECT DriverObject;
LDR_DATA_TABLE_ENTRY ModuleObject;
NTSTATUS Status;
+ UNICODE_STRING DriverName;
+ ULONG i, Index;
+ PDRIVER_INFORMATION DriverInfo, DriverInfoTag;
+ HANDLE KeyHandle;
+ PBOOT_DRIVER_LIST_ENTRY BootEntry;
+ DPRINT("IopInitializeBootDrivers()\n");
/* Use IopRootDeviceNode for now */
Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, NULL, &DeviceNode);
ModuleObject.DllBase = NULL;
ModuleObject.SizeOfImage = 0;
ModuleObject.EntryPoint = RawFsDriverEntry;
+ RtlInitUnicodeString(&DriverName, L"RAW");
/* Initialize it */
Status = IopInitializeDriverModule(DeviceNode,
&ModuleObject,
- &DeviceNode->ServiceName,
+ &DriverName,
TRUE,
&DriverObject);
if (!NT_SUCCESS(Status))
return;
}
+ /* Get highest group order index */
+ IopGroupIndex = PpInitGetGroupOrderIndex(NULL);
+ if (IopGroupIndex == 0xFFFF) ASSERT(FALSE);
+
+ /* Allocate the group table */
+ IopGroupTable = ExAllocatePoolWithTag(PagedPool,
+ IopGroupIndex * sizeof(LIST_ENTRY),
+ TAG_IO);
+ if (IopGroupTable == NULL) ASSERT(FALSE);
+
+ /* Initialize the group table lists */
+ for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]);
+
/* Loop the boot modules */
ListHead = &KeLoaderBlock->LoadOrderListHead;
NextEntry = ListHead->Flink;
LdrEntry = CONTAINING_RECORD(NextEntry,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
-
- /*
- * HACK: Make sure we're loading a driver
- * (we should be using BootDriverListHead!)
- */
- if (wcsstr(_wcsupr(LdrEntry->BaseDllName.Buffer), L".SYS"))
+
+ /* Check if the DLL needs to be initialized */
+ if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
{
- /* Make sure we didn't load this driver already */
- if (!(LdrEntry->Flags & LDRP_ENTRY_INSERTED))
+ /* Call its entrypoint */
+ MmCallDllInitialize(LdrEntry, NULL);
+ }
+
+ /* Go to the next driver */
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* Loop the boot drivers */
+ ListHead = &KeLoaderBlock->BootDriverListHead;
+ NextEntry = ListHead->Flink;
+ while (ListHead != NextEntry)
+ {
+ /* Get the entry */
+ BootEntry = CONTAINING_RECORD(NextEntry,
+ BOOT_DRIVER_LIST_ENTRY,
+ Link);
+
+ /* Get the driver loader entry */
+ LdrEntry = BootEntry->LdrEntry;
+
+ /* Allocate our internal accounting structure */
+ DriverInfo = ExAllocatePoolWithTag(PagedPool,
+ sizeof(DRIVER_INFORMATION),
+ TAG_IO);
+ if (DriverInfo)
+ {
+ /* Zero it and initialize it */
+ RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION));
+ InitializeListHead(&DriverInfo->Link);
+ DriverInfo->DataTableEntry = BootEntry;
+
+ /* Open the registry key */
+ Status = IopOpenRegistryKeyEx(&KeyHandle,
+ NULL,
+ &BootEntry->RegistryPath,
+ KEY_READ);
+ if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */
+ ((KeLoaderBlock->SetupLdrBlock) && (KeyHandle = (PVOID)1)))
{
- /* Initialize it */
- IopInitializeBuiltinDriver(LdrEntry);
+ /* Save the handle */
+ DriverInfo->ServiceHandle = KeyHandle;
+
+ /* Get the group oder index */
+ Index = PpInitGetGroupOrderIndex(KeyHandle);
+
+ /* Get the tag position */
+ DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle);
+
+ /* Insert it into the list, at the right place */
+ ASSERT(Index < IopGroupIndex);
+ NextEntry2 = IopGroupTable[Index].Flink;
+ while (NextEntry2 != &IopGroupTable[Index])
+ {
+ /* Get the driver info */
+ DriverInfoTag = CONTAINING_RECORD(NextEntry2,
+ DRIVER_INFORMATION,
+ Link);
+
+ /* Check if we found the right tag position */
+ if (DriverInfoTag->TagPosition > DriverInfo->TagPosition)
+ {
+ /* We're done */
+ break;
+ }
+
+ /* Next entry */
+ NextEntry2 = NextEntry2->Flink;
+ }
+
+ /* Insert us right before the next entry */
+ NextEntry2 = NextEntry2->Blink;
+ InsertHeadList(NextEntry2, &DriverInfo->Link);
}
}
NextEntry = NextEntry->Flink;
}
+ /* Loop each group index */
+ for (i = 0; i < IopGroupIndex; i++)
+ {
+ /* Loop each group table */
+ NextEntry = IopGroupTable[i].Flink;
+ while (NextEntry != &IopGroupTable[i])
+ {
+ /* Get the entry */
+ DriverInfo = CONTAINING_RECORD(NextEntry,
+ DRIVER_INFORMATION,
+ Link);
+
+ /* Get the driver loader entry */
+ LdrEntry = DriverInfo->DataTableEntry->LdrEntry;
+
+ /* Initialize it */
+ IopInitializeBuiltinDriver(LdrEntry);
+
+ /* Next entry */
+ NextEntry = NextEntry->Flink;
+ }
+ }
+
/* In old ROS, the loader list became empty after this point. Simulate. */
InitializeListHead(&KeLoaderBlock->LoadOrderListHead);
}
+VOID
+FASTCALL
+IopInitializeSystemDrivers(VOID)
+{
+ PUNICODE_STRING *DriverList, *SavedList;
+
+ /* No system drivers on the boot cd */
+ if (KeLoaderBlock->SetupLdrBlock) return;
+
+ /* Get the driver list */
+ SavedList = DriverList = CmGetSystemDriverList();
+ ASSERT(DriverList);
+
+ /* Loop it */
+ while (*DriverList)
+ {
+ /* Load the driver */
+ ZwLoadDriver(*DriverList);
+
+ /* Free the entry */
+ RtlFreeUnicodeString(*DriverList);
+ ExFreePool(*DriverList);
+
+ /* Next entry */
+ InbvIndicateProgress();
+ DriverList++;
+ }
+
+ /* Free the list */
+ ExFreePool(SavedList);
+}
+
/*
* IopUnloadDriver
*
* Guard the whole function by SEH.
*/
-NTSTATUS STDCALL
+NTSTATUS NTAPI
IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
{
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
UNICODE_STRING ServiceName;
UNICODE_STRING ObjectName;
PDRIVER_OBJECT DriverObject;
+ PDEVICE_OBJECT DeviceObject;
+ PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
+ LOAD_UNLOAD_PARAMS LoadParams;
NTSTATUS Status;
LPWSTR Start;
+ BOOLEAN SafeToUnload = TRUE;
DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName, UnloadPnpDrivers);
ObjectName.Length = (wcslen(Start) + 8) * sizeof(WCHAR);
ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
ObjectName.Buffer = ExAllocatePool(PagedPool, ObjectName.MaximumLength);
+ if (!ObjectName.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
wcscpy(ObjectName.Buffer, L"\\Driver\\");
- memcpy(ObjectName.Buffer + 8, Start, (ObjectName.Length - 8) * sizeof(WCHAR));
+ memcpy(ObjectName.Buffer + 8, Start, ObjectName.Length - 8 * sizeof(WCHAR));
ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = 0;
/*
* Find the driver object
*/
-
- Status = ObReferenceObjectByName(&ObjectName, 0, 0, 0, IoDriverObjectType,
- KernelMode, 0, (PVOID*)&DriverObject);
+ Status = ObReferenceObjectByName(&ObjectName,
+ 0,
+ 0,
+ 0,
+ IoDriverObjectType,
+ KernelMode,
+ 0,
+ (PVOID*)&DriverObject);
if (!NT_SUCCESS(Status))
{
- DPRINT("Can't locate driver object for %wZ\n", ObjectName);
+ DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
+ ExFreePool(ObjectName.Buffer);
return Status;
}
/*
* Free the buffer for driver object name
*/
-
ExFreePool(ObjectName.Buffer);
+ /* Check that driver is not already unloading */
+ if (DriverObject->Flags & DRVO_UNLOAD_INVOKED)
+ {
+ DPRINT1("Driver deletion pending\n");
+ ObDereferenceObject(DriverObject);
+ return STATUS_DELETE_PENDING;
+ }
+
/*
* Get path of service...
*/
if (!NT_SUCCESS(Status))
{
- DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
+ DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
+ ObDereferenceObject(DriverObject);
return Status;
}
if (!NT_SUCCESS(Status))
{
- DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
+ DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status);
+ ObDereferenceObject(DriverObject);
return Status;
}
* Unload the module and release the references to the device object
*/
- if (DriverObject->DriverUnload)
- (*DriverObject->DriverUnload)(DriverObject);
- ObDereferenceObject(DriverObject);
- ObDereferenceObject(DriverObject);
- MmUnloadSystemImage(DriverObject->DriverSection);
+ /* Call the load/unload routine, depending on current process */
+ if (DriverObject->DriverUnload && DriverObject->DriverSection)
+ {
+ /* Loop through each device object of the driver
+ and set DOE_UNLOAD_PENDING flag */
+ DeviceObject = DriverObject->DeviceObject;
+ while (DeviceObject)
+ {
+ /* Set the unload pending flag for the device */
+ DeviceExtension = IoGetDevObjExtension(DeviceObject);
+ DeviceExtension->ExtensionFlags |= DOE_UNLOAD_PENDING;
- return STATUS_SUCCESS;
+ /* Make sure there are no attached devices or no reference counts */
+ if ((DeviceObject->ReferenceCount) || (DeviceObject->AttachedDevice))
+ {
+ /* Not safe to unload */
+ DPRINT1("Drivers device object is referenced or has attached devices\n");
+
+ SafeToUnload = FALSE;
+ }
+
+ DeviceObject = DeviceObject->NextDevice;
+ }
+
+ /* If not safe to unload, then return success */
+ if (!SafeToUnload)
+ {
+ ObDereferenceObject(DriverObject);
+ return STATUS_SUCCESS;
+ }
+
+ /* Set the unload invoked flag */
+ DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
+
+ if (PsGetCurrentProcess() == PsInitialSystemProcess)
+ {
+ /* Just call right away */
+ (*DriverObject->DriverUnload)(DriverObject);
+ }
+ else
+ {
+ /* Load/Unload must be called from system process */
+
+ /* Prepare parameters block */
+ LoadParams.DriverObject = DriverObject;
+ KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
+
+ ExInitializeWorkItem(&LoadParams.WorkItem,
+ (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
+ (PVOID)&LoadParams);
+
+ /* Queue it */
+ ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
+
+ /* And wait when it completes */
+ KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
+ FALSE, NULL);
+ }
+
+ /* Mark the driver object temporary, so it could be deleted later */
+ ObMakeTemporaryObject(DriverObject);
+
+ /* Dereference it 2 times */
+ ObDereferenceObject(DriverObject);
+ ObDereferenceObject(DriverObject);
+
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ /* Dereference one time (refd inside this function) */
+ ObDereferenceObject(DriverObject);
+
+ /* Return unloading failure */
+ return STATUS_INVALID_DEVICE_REQUEST;
+ }
}
VOID
NTAPI
IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
IN PDRIVER_INITIALIZE InitializationFunction,
+ IN PUNICODE_STRING RegistryPath,
+ IN PVOID DllBase,
+ IN ULONG SizeOfImage,
OUT PDRIVER_OBJECT *pDriverObject)
{
WCHAR NameBuffer[100];
PDRIVER_OBJECT DriverObject;
UNICODE_STRING ServiceKeyName;
HANDLE hDriver;
- ULONG i;
+ ULONG i, RetryCount = 0;
+try_again:
/* First, create a unique name for the driver if we don't have one */
if (!DriverName)
{
/* Create a random name and set up the string*/
- NameLength = swprintf(NameBuffer, L"\\Driver\\%08u", KeTickCount);
+ NameLength = (USHORT)swprintf(NameBuffer,
+ L"\\Driver\\%08u",
+ KeTickCount);
LocalDriverName.Length = NameLength * sizeof(WCHAR);
LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
LocalDriverName.Buffer = NameBuffer;
(PVOID*)&DriverObject);
if (!NT_SUCCESS(Status)) return Status;
+ DPRINT("IopCreateDriver(): created DO %p\n", DriverObject);
+
/* Set up the Object */
RtlZeroMemory(DriverObject, ObjectSize);
DriverObject->Type = IO_TYPE_DRIVER;
DriverObject->Size = sizeof(DRIVER_OBJECT);
- DriverObject->Flags = DRVO_BUILTIN_DRIVER;
+ DriverObject->Flags = DRVO_LEGACY_DRIVER;//DRVO_BUILTIN_DRIVER;
DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
DriverObject->DriverExtension->DriverObject = DriverObject;
DriverObject->DriverInit = InitializationFunction;
&ServiceKeyName,
sizeof(UNICODE_STRING));
- if (!DriverName)
- {
- /* HACK: Something goes wrong in next lines in this case.
- * Just leave to prevent a freeze */
- *pDriverObject = DriverObject;
- return Status;
- }
-
/* Add the Object and get its handle */
Status = ObInsertObject(DriverObject,
NULL,
0,
NULL,
&hDriver);
+
+ /* Eliminate small possibility when this function is called more than
+ once in a row, and KeTickCount doesn't get enough time to change */
+ if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100))
+ {
+ RetryCount++;
+ goto try_again;
+ }
+
if (!NT_SUCCESS(Status)) return Status;
/* Now reference it */
/* Close the extra handle */
ZwClose(hDriver);
+ DriverObject->HardwareDatabase = &IopHardwareDatabaseKey;
+ DriverObject->DriverStart = DllBase;
+ DriverObject->DriverSize = SizeOfImage;
+
/* Finally, call its init function */
- Status = (*InitializationFunction)(DriverObject, NULL);
+ DPRINT("RegistryKey: %wZ\n", RegistryPath);
+ DPRINT("Calling driver entrypoint at %p\n", InitializationFunction);
+ Status = (*InitializationFunction)(DriverObject, RegistryPath);
if (!NT_SUCCESS(Status))
{
/* If it didn't work, then kill the object */
+ DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status);
ObMakeTemporaryObject(DriverObject);
ObDereferenceObject(DriverObject);
}
*pDriverObject = DriverObject;
}
+ /* Loop all Major Functions */
+ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
+ {
+ /*
+ * Make sure the driver didn't set any dispatch entry point to NULL!
+ * Doing so is illegal; drivers shouldn't touch entry points they
+ * do not implement.
+ */
+
+ /* Check if it did so anyway */
+ if (!DriverObject->MajorFunction[i])
+ {
+ /* Print a warning in the debug log */
+ DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%d] to NULL!\n",
+ &DriverObject->DriverName, i);
+
+ /* Fix it up */
+ DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
+ }
+ }
+
/* Return the Status */
return Status;
}
IN PDRIVER_INITIALIZE InitializationFunction)
{
PDRIVER_OBJECT DriverObject;
- return IopCreateDriver(DriverName, InitializationFunction, &DriverObject);
+ return IopCreateDriver(DriverName, InitializationFunction, NULL, 0, 0, &DriverObject);
}
/*
NTAPI
IoDeleteDriver(IN PDRIVER_OBJECT DriverObject)
{
- /* Simply derefence the Object */
+ /* Simply dereference the Object */
ObDereferenceObject(DriverObject);
}
return DriverExtensions + 1;
}
-/*
- * NtLoadDriver
- *
- * Loads a device driver.
- *
- * Parameters
- * DriverServiceName
- * Name of the service to load (registry key).
- *
- * Return Value
- * Status
- *
- * Status
- * implemented
- */
-NTSTATUS STDCALL
-NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
+VOID NTAPI
+IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams)
{
RTL_QUERY_REGISTRY_TABLE QueryTable[3];
UNICODE_STRING ImagePath;
UNICODE_STRING ServiceName;
- UNICODE_STRING CapturedDriverServiceName = {0};
- KPROCESSOR_MODE PreviousMode = {0};
NTSTATUS Status;
ULONG Type;
PDEVICE_NODE DeviceNode;
- PLDR_DATA_TABLE_ENTRY ModuleObject;
PDRIVER_OBJECT DriverObject;
+ PLDR_DATA_TABLE_ENTRY ModuleObject;
+ PVOID BaseAddress;
WCHAR *cur;
- PAGED_CODE();
-
- PreviousMode = KeGetPreviousMode();
-
- /*
- * Check security privileges
- */
-
-/* FIXME: Uncomment when privileges will be correctly implemented. */
-#if 0
- if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
+ /* Check if it's an unload request */
+ if (LoadParams->DriverObject)
{
- DPRINT("Privilege not held\n");
- return STATUS_PRIVILEGE_NOT_HELD;
- }
-#endif
+ (*LoadParams->DriverObject->DriverUnload)(LoadParams->DriverObject);
- Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
- PreviousMode,
- DriverServiceName);
- if (!NT_SUCCESS(Status))
- {
- return Status;
+ /* Return success and signal the event */
+ LoadParams->Status = STATUS_SUCCESS;
+ (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
+ return;
}
- DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
-
RtlInitUnicodeString(&ImagePath, NULL);
/*
* Get the service name from the registry key name.
*/
- ASSERT(CapturedDriverServiceName.Length >= sizeof(WCHAR));
+ ASSERT(LoadParams->ServiceName->Length >= sizeof(WCHAR));
- ServiceName = CapturedDriverServiceName;
- cur = CapturedDriverServiceName.Buffer + (CapturedDriverServiceName.Length / sizeof(WCHAR)) - 1;
- while (CapturedDriverServiceName.Buffer != cur)
+ ServiceName = *LoadParams->ServiceName;
+ cur = LoadParams->ServiceName->Buffer +
+ (LoadParams->ServiceName->Length / sizeof(WCHAR)) - 1;
+ while (LoadParams->ServiceName->Buffer != cur)
{
if(*cur == L'\\')
{
ServiceName.Buffer = cur + 1;
- ServiceName.Length = CapturedDriverServiceName.Length -
+ ServiceName.Length = LoadParams->ServiceName->Length -
(USHORT)((ULONG_PTR)ServiceName.Buffer -
- (ULONG_PTR)CapturedDriverServiceName.Buffer);
+ (ULONG_PTR)LoadParams->ServiceName->Buffer);
break;
}
cur--;
}
+ IopDisplayLoadingMessage(&ServiceName);
+
/*
* Get service type.
*/
QueryTable[1].EntryContext = &ImagePath;
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
- CapturedDriverServiceName.Buffer, QueryTable, NULL, NULL);
+ LoadParams->ServiceName->Buffer, QueryTable, NULL, NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
- ExFreePool(ImagePath.Buffer);
- goto ReleaseCapturedString;
+ if (ImagePath.Buffer)
+ ExFreePool(ImagePath.Buffer);
+ LoadParams->Status = Status;
+ (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
+ return;
}
/*
if (!NT_SUCCESS(Status))
{
DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
- goto ReleaseCapturedString;
+ LoadParams->Status = Status;
+ (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
+ return;
}
DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
if (!NT_SUCCESS(Status))
{
DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
- goto ReleaseCapturedString;
+ LoadParams->Status = Status;
+ (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
+ return;
}
- /*
- * Load the driver module
- */
+ /* Get existing DriverObject pointer (in case the driver has
+ already been loaded and initialized) */
+ Status = IopGetDriverObject(
+ &DriverObject,
+ &ServiceName,
+ (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
+ Type == 8 /* SERVICE_RECOGNIZER_DRIVER */));
- Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, NULL);
if (!NT_SUCCESS(Status))
{
- DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
+ /*
+ * Load the driver module
+ */
+
+ Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress);
+ if (!NT_SUCCESS(Status) && Status != STATUS_IMAGE_ALREADY_LOADED)
+ {
+ DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
+ IopFreeDeviceNode(DeviceNode);
+ LoadParams->Status = Status;
+ (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
+ return;
+ }
+
+ /*
+ * Set a service name for the device node
+ */
+
+ RtlCreateUnicodeString(&DeviceNode->ServiceName, ServiceName.Buffer);
+
+ /*
+ * Initialize the driver module if it's loaded for the first time
+ */
+ if (Status != STATUS_IMAGE_ALREADY_LOADED)
+ {
+ Status = IopInitializeDriverModule(
+ DeviceNode,
+ ModuleObject,
+ &DeviceNode->ServiceName,
+ (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
+ Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
+ &DriverObject);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
+ MmUnloadSystemImage(ModuleObject);
+ IopFreeDeviceNode(DeviceNode);
+ LoadParams->Status = Status;
+ (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
+ return;
+ }
+ }
+
+ /* Store its DriverSection, so that it could be unloaded */
+ DriverObject->DriverSection = ModuleObject;
+
+ /* Initialize and start device */
+ IopInitializeDevice(DeviceNode, DriverObject);
+ Status = IopStartDevice(DeviceNode);
+ }
+ else
+ {
+ DPRINT("DriverObject already exist in ObjectManager\n");
+
+ /* IopGetDriverObject references the DriverObject, so dereference it */
+ ObDereferenceObject(DriverObject);
+
+ /* Free device node since driver loading failed */
IopFreeDeviceNode(DeviceNode);
- goto ReleaseCapturedString;
}
- /*
- * Set a service name for the device node
- */
+ /* Pass status to the caller and signal the event */
+ LoadParams->Status = Status;
+ (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
+}
+
+/*
+ * NtLoadDriver
+ *
+ * Loads a device driver.
+ *
+ * Parameters
+ * DriverServiceName
+ * Name of the service to load (registry key).
+ *
+ * Return Value
+ * Status
+ *
+ * Status
+ * implemented
+ */
+NTSTATUS NTAPI
+NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
+{
+ UNICODE_STRING CapturedDriverServiceName = { 0, 0, NULL };
+ KPROCESSOR_MODE PreviousMode;
+ LOAD_UNLOAD_PARAMS LoadParams;
+ NTSTATUS Status;
+
+ PAGED_CODE();
- RtlCreateUnicodeString(&DeviceNode->ServiceName, ServiceName.Buffer);
+ PreviousMode = KeGetPreviousMode();
- /*
- * Initialize the driver module
+ /*
+ * Check security privileges
*/
- Status = IopInitializeDriverModule(
- DeviceNode,
- ModuleObject,
- &DeviceNode->ServiceName,
- (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
- Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
- &DriverObject);
+ /* FIXME: Uncomment when privileges will be correctly implemented. */
+#if 0
+ if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
+ {
+ DPRINT("Privilege not held\n");
+ return STATUS_PRIVILEGE_NOT_HELD;
+ }
+#endif
- if (!NT_SUCCESS(Status))
- {
- DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
- MmUnloadSystemImage(ModuleObject);
- IopFreeDeviceNode(DeviceNode);
- goto ReleaseCapturedString;
- }
+ Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
+ PreviousMode,
+ DriverServiceName);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
- IopInitializeDevice(DeviceNode, DriverObject);
- Status = IopStartDevice(DeviceNode);
+ DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
-ReleaseCapturedString:
- ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
- PreviousMode);
+ LoadParams.ServiceName = &CapturedDriverServiceName;
+ LoadParams.DriverObject = NULL;
+ KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
- return Status;
+ /* Call the load/unload routine, depending on current process */
+ if (PsGetCurrentProcess() == PsInitialSystemProcess)
+ {
+ /* Just call right away */
+ IopLoadUnloadDriver(&LoadParams);
+ }
+ else
+ {
+ /* Load/Unload must be called from system process */
+ ExInitializeWorkItem(&LoadParams.WorkItem,
+ (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
+ (PVOID)&LoadParams);
+
+ /* Queue it */
+ ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
+
+ /* And wait when it completes */
+ KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
+ FALSE, NULL);
+ }
+
+ ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
+ PreviousMode);
+
+ return LoadParams.Status;
}
/*
* implemented
*/
-NTSTATUS STDCALL
+NTSTATUS NTAPI
NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
{
return IopUnloadDriver(DriverServiceName, FALSE);