1c2c66affSColin Finck /* 2c2c66affSColin Finck * PROJECT: ReactOS Kernel 3c2c66affSColin Finck * LICENSE: GPL - See COPYING in the top level directory 4c2c66affSColin Finck * FILE: ntoskrnl/io/iomgr/driver.c 5c2c66affSColin Finck * PURPOSE: Driver Object Management 6c2c66affSColin Finck * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7c2c66affSColin Finck * Filip Navara (navaraf@reactos.org) 8c2c66affSColin Finck * Herv� Poussineau (hpoussin@reactos.org) 9c2c66affSColin Finck */ 10c2c66affSColin Finck 11c2c66affSColin Finck /* INCLUDES *******************************************************************/ 12c2c66affSColin Finck 13c2c66affSColin Finck #include <ntoskrnl.h> 14c2c66affSColin Finck #define NDEBUG 15c2c66affSColin Finck #include <debug.h> 16c2c66affSColin Finck 17c2c66affSColin Finck /* GLOBALS ********************************************************************/ 18c2c66affSColin Finck 19c2c66affSColin Finck ERESOURCE IopDriverLoadResource; 20c2c66affSColin Finck 21c2c66affSColin Finck LIST_ENTRY DriverReinitListHead; 22c2c66affSColin Finck KSPIN_LOCK DriverReinitListLock; 23c2c66affSColin Finck PLIST_ENTRY DriverReinitTailEntry; 24c2c66affSColin Finck 25c2c66affSColin Finck PLIST_ENTRY DriverBootReinitTailEntry; 26c2c66affSColin Finck LIST_ENTRY DriverBootReinitListHead; 27c2c66affSColin Finck KSPIN_LOCK DriverBootReinitListLock; 28c2c66affSColin Finck 29c2c66affSColin Finck UNICODE_STRING IopHardwareDatabaseKey = 30c2c66affSColin Finck RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM"); 314c95339dSVictor Perevertkin static const WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"; 32c2c66affSColin Finck 33c2c66affSColin Finck POBJECT_TYPE IoDriverObjectType = NULL; 34c2c66affSColin Finck 35c2c66affSColin Finck #define TAG_RTLREGISTRY 'vrqR' 36c2c66affSColin Finck 37c2c66affSColin Finck extern BOOLEAN ExpInTextModeSetup; 38c2c66affSColin Finck extern BOOLEAN PnpSystemInit; 392839c850SVictor Perevertkin extern BOOLEAN PnPBootDriversLoaded; 402839c850SVictor Perevertkin extern KEVENT PiEnumerationFinished; 41c2c66affSColin Finck 42c2c66affSColin Finck USHORT IopGroupIndex; 43c2c66affSColin Finck PLIST_ENTRY IopGroupTable; 44c2c66affSColin Finck 45a6a3aa0fSVictor Perevertkin /* TYPES *********************************************************************/ 46a6a3aa0fSVictor Perevertkin 47a6a3aa0fSVictor Perevertkin // Parameters packet for Load/Unload work item's context 48a6a3aa0fSVictor Perevertkin typedef struct _LOAD_UNLOAD_PARAMS 49a6a3aa0fSVictor Perevertkin { 50a6a3aa0fSVictor Perevertkin NTSTATUS Status; 514c95339dSVictor Perevertkin PUNICODE_STRING RegistryPath; 52a6a3aa0fSVictor Perevertkin WORK_QUEUE_ITEM WorkItem; 53a6a3aa0fSVictor Perevertkin KEVENT Event; 54a6a3aa0fSVictor Perevertkin PDRIVER_OBJECT DriverObject; 55a6a3aa0fSVictor Perevertkin BOOLEAN SetEvent; 56a6a3aa0fSVictor Perevertkin } LOAD_UNLOAD_PARAMS, *PLOAD_UNLOAD_PARAMS; 57a6a3aa0fSVictor Perevertkin 58a6a3aa0fSVictor Perevertkin NTSTATUS 59a6a3aa0fSVictor Perevertkin IopDoLoadUnloadDriver( 604c95339dSVictor Perevertkin _In_opt_ PUNICODE_STRING RegistryPath, 61a6a3aa0fSVictor Perevertkin _Inout_ PDRIVER_OBJECT *DriverObject); 62a6a3aa0fSVictor Perevertkin 63c2c66affSColin Finck /* PRIVATE FUNCTIONS **********************************************************/ 64c2c66affSColin Finck 65c2c66affSColin Finck NTSTATUS 66c2c66affSColin Finck NTAPI 67c2c66affSColin Finck IopInvalidDeviceRequest( 68c2c66affSColin Finck PDEVICE_OBJECT DeviceObject, 69c2c66affSColin Finck PIRP Irp) 70c2c66affSColin Finck { 71c2c66affSColin Finck Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; 72c2c66affSColin Finck Irp->IoStatus.Information = 0; 73c2c66affSColin Finck IoCompleteRequest(Irp, IO_NO_INCREMENT); 74c2c66affSColin Finck return STATUS_INVALID_DEVICE_REQUEST; 75c2c66affSColin Finck } 76c2c66affSColin Finck 77c2c66affSColin Finck VOID 78c2c66affSColin Finck NTAPI 79c2c66affSColin Finck IopDeleteDriver(IN PVOID ObjectBody) 80c2c66affSColin Finck { 81c2c66affSColin Finck PDRIVER_OBJECT DriverObject = ObjectBody; 82c2c66affSColin Finck PIO_CLIENT_EXTENSION DriverExtension, NextDriverExtension; 83c2c66affSColin Finck PAGED_CODE(); 84c2c66affSColin Finck 85c2c66affSColin Finck DPRINT1("Deleting driver object '%wZ'\n", &DriverObject->DriverName); 86c2c66affSColin Finck 87c2c66affSColin Finck /* There must be no device objects remaining at this point */ 88c2c66affSColin Finck ASSERT(!DriverObject->DeviceObject); 89c2c66affSColin Finck 90c2c66affSColin Finck /* Get the extension and loop them */ 91c2c66affSColin Finck DriverExtension = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension; 92c2c66affSColin Finck while (DriverExtension) 93c2c66affSColin Finck { 94c2c66affSColin Finck /* Get the next one */ 95c2c66affSColin Finck NextDriverExtension = DriverExtension->NextExtension; 96c2c66affSColin Finck ExFreePoolWithTag(DriverExtension, TAG_DRIVER_EXTENSION); 97c2c66affSColin Finck 98c2c66affSColin Finck /* Move on */ 99c2c66affSColin Finck DriverExtension = NextDriverExtension; 100c2c66affSColin Finck } 101c2c66affSColin Finck 102c2c66affSColin Finck /* Check if the driver image is still loaded */ 103c2c66affSColin Finck if (DriverObject->DriverSection) 104c2c66affSColin Finck { 105c2c66affSColin Finck /* Unload it */ 106c2c66affSColin Finck MmUnloadSystemImage(DriverObject->DriverSection); 107c2c66affSColin Finck } 108c2c66affSColin Finck 109c2c66affSColin Finck /* Check if it has a name */ 110c2c66affSColin Finck if (DriverObject->DriverName.Buffer) 111c2c66affSColin Finck { 112c2c66affSColin Finck /* Free it */ 113c2c66affSColin Finck ExFreePool(DriverObject->DriverName.Buffer); 114c2c66affSColin Finck } 115c2c66affSColin Finck 116c2c66affSColin Finck /* Check if it has a service key name */ 117c2c66affSColin Finck if (DriverObject->DriverExtension->ServiceKeyName.Buffer) 118c2c66affSColin Finck { 119c2c66affSColin Finck /* Free it */ 120c2c66affSColin Finck ExFreePool(DriverObject->DriverExtension->ServiceKeyName.Buffer); 121c2c66affSColin Finck } 122c2c66affSColin Finck } 123c2c66affSColin Finck 124c2c66affSColin Finck NTSTATUS 125c4c0585fSVictor Perevertkin IopGetDriverNames( 126c4c0585fSVictor Perevertkin _In_ HANDLE ServiceHandle, 127c4c0585fSVictor Perevertkin _Out_ PUNICODE_STRING DriverName, 128c4c0585fSVictor Perevertkin _Out_opt_ PUNICODE_STRING ServiceName) 129c2c66affSColin Finck { 130c4c0585fSVictor Perevertkin UNICODE_STRING driverName = {.Buffer = NULL}, serviceName; 131c4c0585fSVictor Perevertkin PKEY_VALUE_FULL_INFORMATION kvInfo; 132c4c0585fSVictor Perevertkin NTSTATUS status; 133c2c66affSColin Finck 134c4c0585fSVictor Perevertkin PAGED_CODE(); 135c2c66affSColin Finck 136a82ff90bSHermès Bélusca-Maïto /* 1. Check the "ObjectName" field in the driver's registry key (it has priority) */ 137c4c0585fSVictor Perevertkin status = IopGetRegistryValue(ServiceHandle, L"ObjectName", &kvInfo); 138c4c0585fSVictor Perevertkin if (NT_SUCCESS(status)) 139c4c0585fSVictor Perevertkin { 140a82ff90bSHermès Bélusca-Maïto /* We've got the ObjectName, use it as the driver name */ 141c4c0585fSVictor Perevertkin if (kvInfo->Type != REG_SZ || kvInfo->DataLength == 0) 142c4c0585fSVictor Perevertkin { 143c4c0585fSVictor Perevertkin ExFreePool(kvInfo); 144c4c0585fSVictor Perevertkin return STATUS_ILL_FORMED_SERVICE_ENTRY; 145c4c0585fSVictor Perevertkin } 146c2c66affSColin Finck 1470d28f271SHermès Bélusca-Maïto driverName.Length = kvInfo->DataLength - sizeof(UNICODE_NULL); 148a82ff90bSHermès Bélusca-Maïto driverName.MaximumLength = kvInfo->DataLength; 149c4c0585fSVictor Perevertkin driverName.Buffer = ExAllocatePoolWithTag(NonPagedPool, driverName.MaximumLength, TAG_IO); 150c4c0585fSVictor Perevertkin if (!driverName.Buffer) 151c4c0585fSVictor Perevertkin { 152c4c0585fSVictor Perevertkin ExFreePool(kvInfo); 153c4c0585fSVictor Perevertkin return STATUS_INSUFFICIENT_RESOURCES; 154c4c0585fSVictor Perevertkin } 155c2c66affSColin Finck 156c4c0585fSVictor Perevertkin RtlMoveMemory(driverName.Buffer, 157c4c0585fSVictor Perevertkin (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset), 158c4c0585fSVictor Perevertkin driverName.Length); 1590d28f271SHermès Bélusca-Maïto driverName.Buffer[driverName.Length / sizeof(WCHAR)] = UNICODE_NULL; 160c4c0585fSVictor Perevertkin ExFreePool(kvInfo); 161c4c0585fSVictor Perevertkin } 162e1b20681SThomas Faber 163a82ff90bSHermès Bélusca-Maïto /* Check whether we need to get ServiceName as well, either to construct 164a82ff90bSHermès Bélusca-Maïto * the driver name (because we could not use "ObjectName"), or because 165a82ff90bSHermès Bélusca-Maïto * it is requested by the caller. */ 166e09d1decSHermès Bélusca-Maïto PKEY_BASIC_INFORMATION basicInfo = NULL; 167c4c0585fSVictor Perevertkin if (!NT_SUCCESS(status) || ServiceName != NULL) 168c4c0585fSVictor Perevertkin { 169a82ff90bSHermès Bélusca-Maïto /* Retrieve the necessary buffer size */ 170c4c0585fSVictor Perevertkin ULONG infoLength; 171c4c0585fSVictor Perevertkin status = ZwQueryKey(ServiceHandle, KeyBasicInformation, NULL, 0, &infoLength); 172a82ff90bSHermès Bélusca-Maïto if (status != STATUS_BUFFER_TOO_SMALL) 173c4c0585fSVictor Perevertkin { 17432a82eb1SHermès Bélusca-Maïto status = (NT_SUCCESS(status) ? STATUS_UNSUCCESSFUL : status); 17532a82eb1SHermès Bélusca-Maïto goto Cleanup; 176a82ff90bSHermès Bélusca-Maïto } 177a82ff90bSHermès Bélusca-Maïto 178a82ff90bSHermès Bélusca-Maïto /* Allocate the buffer and retrieve the data */ 179c4c0585fSVictor Perevertkin basicInfo = ExAllocatePoolWithTag(PagedPool, infoLength, TAG_IO); 180c4c0585fSVictor Perevertkin if (!basicInfo) 181e1b20681SThomas Faber { 18232a82eb1SHermès Bélusca-Maïto status = STATUS_INSUFFICIENT_RESOURCES; 18332a82eb1SHermès Bélusca-Maïto goto Cleanup; 184e1b20681SThomas Faber } 185c2c66affSColin Finck 186c4c0585fSVictor Perevertkin status = ZwQueryKey(ServiceHandle, KeyBasicInformation, basicInfo, infoLength, &infoLength); 187c4c0585fSVictor Perevertkin if (!NT_SUCCESS(status)) 188c2c66affSColin Finck { 18932a82eb1SHermès Bélusca-Maïto goto Cleanup; 190c2c66affSColin Finck } 191c2c66affSColin Finck 192c4c0585fSVictor Perevertkin serviceName.Length = basicInfo->NameLength; 193c4c0585fSVictor Perevertkin serviceName.MaximumLength = basicInfo->NameLength; 194c4c0585fSVictor Perevertkin serviceName.Buffer = basicInfo->Name; 195c4c0585fSVictor Perevertkin } 196c2c66affSColin Finck 197a82ff90bSHermès Bélusca-Maïto /* 2. There is no "ObjectName" - construct it ourselves. Depending on the driver type, 198a82ff90bSHermès Bélusca-Maïto * it will be either "\Driver\<ServiceName>" or "\FileSystem\<ServiceName>" */ 199c4c0585fSVictor Perevertkin if (driverName.Buffer == NULL) 200c4c0585fSVictor Perevertkin { 201e09d1decSHermès Bélusca-Maïto ASSERT(basicInfo); // Container for serviceName 202e09d1decSHermès Bélusca-Maïto 203a82ff90bSHermès Bélusca-Maïto /* Retrieve the driver type */ 204a82ff90bSHermès Bélusca-Maïto ULONG driverType; 205c4c0585fSVictor Perevertkin status = IopGetRegistryValue(ServiceHandle, L"Type", &kvInfo); 206aec3d9ccSVictor Perevertkin if (!NT_SUCCESS(status)) 207aec3d9ccSVictor Perevertkin { 208e09d1decSHermès Bélusca-Maïto goto Cleanup; 209aec3d9ccSVictor Perevertkin } 2100d28f271SHermès Bélusca-Maïto if (kvInfo->Type != REG_DWORD || kvInfo->DataLength != sizeof(ULONG)) 211c4c0585fSVictor Perevertkin { 212c4c0585fSVictor Perevertkin ExFreePool(kvInfo); 213e09d1decSHermès Bélusca-Maïto status = STATUS_ILL_FORMED_SERVICE_ENTRY; 214e09d1decSHermès Bélusca-Maïto goto Cleanup; 215c4c0585fSVictor Perevertkin } 216fe416b67SHermès Bélusca-Maïto 217fe416b67SHermès Bélusca-Maïto RtlMoveMemory(&driverType, 218fe416b67SHermès Bélusca-Maïto (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset), 219fe416b67SHermès Bélusca-Maïto sizeof(ULONG)); 220c4c0585fSVictor Perevertkin ExFreePool(kvInfo); 221c4c0585fSVictor Perevertkin 222a82ff90bSHermès Bélusca-Maïto /* Compute the necessary driver name string size */ 223c4c0585fSVictor Perevertkin if (driverType == SERVICE_RECOGNIZER_DRIVER || driverType == SERVICE_FILE_SYSTEM_DRIVER) 224a82ff90bSHermès Bélusca-Maïto driverName.MaximumLength = sizeof(FILESYSTEM_ROOT_NAME); 225c4c0585fSVictor Perevertkin else 226a82ff90bSHermès Bélusca-Maïto driverName.MaximumLength = sizeof(DRIVER_ROOT_NAME); 227a82ff90bSHermès Bélusca-Maïto 228a82ff90bSHermès Bélusca-Maïto driverName.MaximumLength += serviceName.Length; 229a82ff90bSHermès Bélusca-Maïto driverName.Length = 0; 230a82ff90bSHermès Bélusca-Maïto 231a82ff90bSHermès Bélusca-Maïto /* Allocate and build it */ 232c4c0585fSVictor Perevertkin driverName.Buffer = ExAllocatePoolWithTag(NonPagedPool, driverName.MaximumLength, TAG_IO); 233c4c0585fSVictor Perevertkin if (!driverName.Buffer) 234c4c0585fSVictor Perevertkin { 235e09d1decSHermès Bélusca-Maïto status = STATUS_INSUFFICIENT_RESOURCES; 236e09d1decSHermès Bélusca-Maïto goto Cleanup; 237c4c0585fSVictor Perevertkin } 238c4c0585fSVictor Perevertkin 239c4c0585fSVictor Perevertkin if (driverType == SERVICE_RECOGNIZER_DRIVER || driverType == SERVICE_FILE_SYSTEM_DRIVER) 240c4c0585fSVictor Perevertkin RtlAppendUnicodeToString(&driverName, FILESYSTEM_ROOT_NAME); 241c4c0585fSVictor Perevertkin else 242c4c0585fSVictor Perevertkin RtlAppendUnicodeToString(&driverName, DRIVER_ROOT_NAME); 243c4c0585fSVictor Perevertkin 244c4c0585fSVictor Perevertkin RtlAppendUnicodeStringToString(&driverName, &serviceName); 245c4c0585fSVictor Perevertkin } 246c4c0585fSVictor Perevertkin 247a82ff90bSHermès Bélusca-Maïto if (ServiceName != NULL) 248c4c0585fSVictor Perevertkin { 249e09d1decSHermès Bélusca-Maïto ASSERT(basicInfo); // Container for serviceName 250e09d1decSHermès Bélusca-Maïto 251a82ff90bSHermès Bélusca-Maïto /* Allocate a copy for the caller */ 252c4c0585fSVictor Perevertkin PWCHAR buf = ExAllocatePoolWithTag(PagedPool, serviceName.Length, TAG_IO); 253c4c0585fSVictor Perevertkin if (!buf) 254c4c0585fSVictor Perevertkin { 255e09d1decSHermès Bélusca-Maïto status = STATUS_INSUFFICIENT_RESOURCES; 256e09d1decSHermès Bélusca-Maïto goto Cleanup; 257c4c0585fSVictor Perevertkin } 258c4c0585fSVictor Perevertkin RtlMoveMemory(buf, serviceName.Buffer, serviceName.Length); 259c4c0585fSVictor Perevertkin ServiceName->MaximumLength = serviceName.Length; 260c4c0585fSVictor Perevertkin ServiceName->Length = serviceName.Length; 261c4c0585fSVictor Perevertkin ServiceName->Buffer = buf; 262c4c0585fSVictor Perevertkin } 263c4c0585fSVictor Perevertkin 264c4c0585fSVictor Perevertkin *DriverName = driverName; 265e09d1decSHermès Bélusca-Maïto status = STATUS_SUCCESS; 266c2c66affSColin Finck 267e09d1decSHermès Bélusca-Maïto Cleanup: 268e09d1decSHermès Bélusca-Maïto if (basicInfo) 269e09d1decSHermès Bélusca-Maïto ExFreePoolWithTag(basicInfo, TAG_IO); 270e09d1decSHermès Bélusca-Maïto 27132a82eb1SHermès Bélusca-Maïto if (!NT_SUCCESS(status) && driverName.Buffer) 27232a82eb1SHermès Bélusca-Maïto ExFreePoolWithTag(driverName.Buffer, TAG_IO); 27332a82eb1SHermès Bélusca-Maïto 274e09d1decSHermès Bélusca-Maïto return status; 275c2c66affSColin Finck } 276c2c66affSColin Finck 277c2c66affSColin Finck /* 278c2c66affSColin Finck * RETURNS 279c2c66affSColin Finck * TRUE if String2 contains String1 as a suffix. 280c2c66affSColin Finck */ 281c2c66affSColin Finck BOOLEAN 282c2c66affSColin Finck NTAPI 283c2c66affSColin Finck IopSuffixUnicodeString( 284c2c66affSColin Finck IN PCUNICODE_STRING String1, 285c2c66affSColin Finck IN PCUNICODE_STRING String2) 286c2c66affSColin Finck { 287c2c66affSColin Finck PWCHAR pc1; 288c2c66affSColin Finck PWCHAR pc2; 289c2c66affSColin Finck ULONG Length; 290c2c66affSColin Finck 291c2c66affSColin Finck if (String2->Length < String1->Length) 292c2c66affSColin Finck return FALSE; 293c2c66affSColin Finck 294c2c66affSColin Finck Length = String1->Length / 2; 295c2c66affSColin Finck pc1 = String1->Buffer; 296c2c66affSColin Finck pc2 = &String2->Buffer[String2->Length / sizeof(WCHAR) - Length]; 297c2c66affSColin Finck 298c2c66affSColin Finck if (pc1 && pc2) 299c2c66affSColin Finck { 300c2c66affSColin Finck while (Length--) 301c2c66affSColin Finck { 302c2c66affSColin Finck if( *pc1++ != *pc2++ ) 303c2c66affSColin Finck return FALSE; 304c2c66affSColin Finck } 305c2c66affSColin Finck return TRUE; 306c2c66affSColin Finck } 307c2c66affSColin Finck return FALSE; 308c2c66affSColin Finck } 309c2c66affSColin Finck 310c2c66affSColin Finck /* 311c2c66affSColin Finck * IopDisplayLoadingMessage 312c2c66affSColin Finck * 313c2c66affSColin Finck * Display 'Loading XXX...' message. 314c2c66affSColin Finck */ 315c2c66affSColin Finck VOID 316c2c66affSColin Finck FASTCALL 317c2c66affSColin Finck IopDisplayLoadingMessage(PUNICODE_STRING ServiceName) 318c2c66affSColin Finck { 319c2c66affSColin Finck CHAR TextBuffer[256]; 320c2c66affSColin Finck UNICODE_STRING DotSys = RTL_CONSTANT_STRING(L".SYS"); 321c2c66affSColin Finck 322c2c66affSColin Finck if (ExpInTextModeSetup) return; 323c2c66affSColin Finck if (!KeLoaderBlock) return; 324c2c66affSColin Finck RtlUpcaseUnicodeString(ServiceName, ServiceName, FALSE); 325c2c66affSColin Finck snprintf(TextBuffer, sizeof(TextBuffer), 326c2c66affSColin Finck "%s%sSystem32\\Drivers\\%wZ%s\r\n", 327c2c66affSColin Finck KeLoaderBlock->ArcBootDeviceName, 328c2c66affSColin Finck KeLoaderBlock->NtBootPathName, 329c2c66affSColin Finck ServiceName, 330c2c66affSColin Finck IopSuffixUnicodeString(&DotSys, ServiceName) ? "" : ".SYS"); 331c2c66affSColin Finck HalDisplayString(TextBuffer); 332c2c66affSColin Finck } 333c2c66affSColin Finck 334c2c66affSColin Finck /* 335c2c66affSColin Finck * IopNormalizeImagePath 336c2c66affSColin Finck * 337c2c66affSColin Finck * Normalize an image path to contain complete path. 338c2c66affSColin Finck * 339c2c66affSColin Finck * Parameters 340c2c66affSColin Finck * ImagePath 341c2c66affSColin Finck * The input path and on exit the result path. ImagePath.Buffer 342c2c66affSColin Finck * must be allocated by ExAllocatePool on input. Caller is responsible 343c2c66affSColin Finck * for freeing the buffer when it's no longer needed. 344c2c66affSColin Finck * 345c2c66affSColin Finck * ServiceName 346c2c66affSColin Finck * Name of the service that ImagePath belongs to. 347c2c66affSColin Finck * 348c2c66affSColin Finck * Return Value 349c2c66affSColin Finck * Status 350c2c66affSColin Finck * 351c2c66affSColin Finck * Remarks 352c2c66affSColin Finck * The input image path isn't freed on error. 353c2c66affSColin Finck */ 354c2c66affSColin Finck NTSTATUS 355c2c66affSColin Finck FASTCALL 356c2c66affSColin Finck IopNormalizeImagePath( 357c2c66affSColin Finck _Inout_ _When_(return>=0, _At_(ImagePath->Buffer, _Post_notnull_ __drv_allocatesMem(Mem))) 358c2c66affSColin Finck PUNICODE_STRING ImagePath, 359c2c66affSColin Finck _In_ PUNICODE_STRING ServiceName) 360c2c66affSColin Finck { 361c2c66affSColin Finck UNICODE_STRING SystemRootString = RTL_CONSTANT_STRING(L"\\SystemRoot\\"); 362c2c66affSColin Finck UNICODE_STRING DriversPathString = RTL_CONSTANT_STRING(L"\\SystemRoot\\System32\\drivers\\"); 363c2c66affSColin Finck UNICODE_STRING DotSysString = RTL_CONSTANT_STRING(L".sys"); 364c2c66affSColin Finck UNICODE_STRING InputImagePath; 365c2c66affSColin Finck 366c2c66affSColin Finck DPRINT("Normalizing image path '%wZ' for service '%wZ'\n", ImagePath, ServiceName); 367c2c66affSColin Finck 368c2c66affSColin Finck InputImagePath = *ImagePath; 369c2c66affSColin Finck if (InputImagePath.Length == 0) 370c2c66affSColin Finck { 371c2c66affSColin Finck ImagePath->Length = 0; 372c2c66affSColin Finck ImagePath->MaximumLength = DriversPathString.Length + 373c2c66affSColin Finck ServiceName->Length + 374c2c66affSColin Finck DotSysString.Length + 375c2c66affSColin Finck sizeof(UNICODE_NULL); 376c2c66affSColin Finck ImagePath->Buffer = ExAllocatePoolWithTag(NonPagedPool, 377c2c66affSColin Finck ImagePath->MaximumLength, 378c2c66affSColin Finck TAG_IO); 379c2c66affSColin Finck if (ImagePath->Buffer == NULL) 380c2c66affSColin Finck return STATUS_NO_MEMORY; 381c2c66affSColin Finck 382c2c66affSColin Finck RtlCopyUnicodeString(ImagePath, &DriversPathString); 383c2c66affSColin Finck RtlAppendUnicodeStringToString(ImagePath, ServiceName); 384c2c66affSColin Finck RtlAppendUnicodeStringToString(ImagePath, &DotSysString); 385c2c66affSColin Finck } 386c2c66affSColin Finck else if (InputImagePath.Buffer[0] != L'\\') 387c2c66affSColin Finck { 388c2c66affSColin Finck ImagePath->Length = 0; 389c2c66affSColin Finck ImagePath->MaximumLength = SystemRootString.Length + 390c2c66affSColin Finck InputImagePath.Length + 391c2c66affSColin Finck sizeof(UNICODE_NULL); 392c2c66affSColin Finck ImagePath->Buffer = ExAllocatePoolWithTag(NonPagedPool, 393c2c66affSColin Finck ImagePath->MaximumLength, 394c2c66affSColin Finck TAG_IO); 395c2c66affSColin Finck if (ImagePath->Buffer == NULL) 396c2c66affSColin Finck return STATUS_NO_MEMORY; 397c2c66affSColin Finck 398c2c66affSColin Finck RtlCopyUnicodeString(ImagePath, &SystemRootString); 399c2c66affSColin Finck RtlAppendUnicodeStringToString(ImagePath, &InputImagePath); 400c2c66affSColin Finck 401c2c66affSColin Finck /* Free caller's string */ 402c2c66affSColin Finck ExFreePoolWithTag(InputImagePath.Buffer, TAG_RTLREGISTRY); 403c2c66affSColin Finck } 404c2c66affSColin Finck 405c2c66affSColin Finck DPRINT("Normalized image path is '%wZ' for service '%wZ'\n", ImagePath, ServiceName); 406c2c66affSColin Finck 407c2c66affSColin Finck return STATUS_SUCCESS; 408c2c66affSColin Finck } 409c2c66affSColin Finck 410e18a32dfSVictor Perevertkin /** 411e18a32dfSVictor Perevertkin * @brief Initialize a loaded driver 412c2c66affSColin Finck * 413e18a32dfSVictor Perevertkin * @param[in] ModuleObject 414e18a32dfSVictor Perevertkin * Module object representing the driver. It can be retrieved by IopLoadServiceModule. 415e18a32dfSVictor Perevertkin * Freed on failure, so in a such case this should not be accessed anymore 416c2c66affSColin Finck * 4174c95339dSVictor Perevertkin * @param[in] ServiceHandle 4184c95339dSVictor Perevertkin * Handle to a driver's CCS/Services/<ServiceName> key 419c2c66affSColin Finck * 420e18a32dfSVictor Perevertkin * @param[out] DriverObject 421e18a32dfSVictor Perevertkin * This contains the driver object if it was created (even with unsuccessfull result) 422c2c66affSColin Finck * 423e18a32dfSVictor Perevertkin * @param[out] DriverEntryStatus 424e18a32dfSVictor Perevertkin * This contains the status value returned by the driver's DriverEntry routine 425e18a32dfSVictor Perevertkin * (will not be valid of the return value is not STATUS_SUCCESS or STATUS_FAILED_DRIVER_ENTRY) 426c2c66affSColin Finck * 427e18a32dfSVictor Perevertkin * @return Status of the operation 428c2c66affSColin Finck */ 429c2c66affSColin Finck NTSTATUS 430c2c66affSColin Finck IopInitializeDriverModule( 431e18a32dfSVictor Perevertkin _In_ PLDR_DATA_TABLE_ENTRY ModuleObject, 4324c95339dSVictor Perevertkin _In_ HANDLE ServiceHandle, 433e18a32dfSVictor Perevertkin _Out_ PDRIVER_OBJECT *OutDriverObject, 434e18a32dfSVictor Perevertkin _Out_ NTSTATUS *DriverEntryStatus) 435c2c66affSColin Finck { 4364c95339dSVictor Perevertkin UNICODE_STRING DriverName, RegistryPath, ServiceName; 437c2c66affSColin Finck NTSTATUS Status; 438c2c66affSColin Finck 439e18a32dfSVictor Perevertkin PAGED_CODE(); 440c2c66affSColin Finck 441c4c0585fSVictor Perevertkin Status = IopGetDriverNames(ServiceHandle, &DriverName, &ServiceName); 442e18a32dfSVictor Perevertkin if (!NT_SUCCESS(Status)) 443c2c66affSColin Finck { 444e18a32dfSVictor Perevertkin MmUnloadSystemImage(ModuleObject); 445e18a32dfSVictor Perevertkin return Status; 446e18a32dfSVictor Perevertkin } 447e18a32dfSVictor Perevertkin 448e18a32dfSVictor Perevertkin DPRINT("Driver name: '%wZ'\n", &DriverName); 449e18a32dfSVictor Perevertkin 4501fd730b7SHermès Bélusca-Maïto /* 4511fd730b7SHermès Bélusca-Maïto * Retrieve the driver's PE image NT header and perform some sanity checks. 4521fd730b7SHermès Bélusca-Maïto * NOTE: We suppose that since the driver has been successfully loaded, 4531fd730b7SHermès Bélusca-Maïto * its NT and optional headers are all valid and have expected sizes. 4541fd730b7SHermès Bélusca-Maïto */ 4551fd730b7SHermès Bélusca-Maïto PIMAGE_NT_HEADERS NtHeaders = RtlImageNtHeader(ModuleObject->DllBase); 4561fd730b7SHermès Bélusca-Maïto ASSERT(NtHeaders); 457*4795d953SHermès Bélusca-Maïto // NOTE: ModuleObject->SizeOfImage is actually (number of PTEs)*PAGE_SIZE. 458*4795d953SHermès Bélusca-Maïto ASSERT(ModuleObject->SizeOfImage == ROUND_TO_PAGES(NtHeaders->OptionalHeader.SizeOfImage)); 4591fd730b7SHermès Bélusca-Maïto ASSERT(ModuleObject->EntryPoint == RVA(ModuleObject->DllBase, NtHeaders->OptionalHeader.AddressOfEntryPoint)); 4601fd730b7SHermès Bélusca-Maïto 461a82ff90bSHermès Bélusca-Maïto /* Obtain the registry path for the DriverInit routine */ 4624c95339dSVictor Perevertkin PKEY_NAME_INFORMATION nameInfo; 463c4c0585fSVictor Perevertkin ULONG infoLength; 4644c95339dSVictor Perevertkin Status = ZwQueryKey(ServiceHandle, KeyNameInformation, NULL, 0, &infoLength); 4654c95339dSVictor Perevertkin if (Status == STATUS_BUFFER_TOO_SMALL) 4664c95339dSVictor Perevertkin { 4674c95339dSVictor Perevertkin nameInfo = ExAllocatePoolWithTag(NonPagedPool, infoLength, TAG_IO); 4684c95339dSVictor Perevertkin if (nameInfo) 4694c95339dSVictor Perevertkin { 4704c95339dSVictor Perevertkin Status = ZwQueryKey(ServiceHandle, 4714c95339dSVictor Perevertkin KeyNameInformation, 4724c95339dSVictor Perevertkin nameInfo, 4734c95339dSVictor Perevertkin infoLength, 4744c95339dSVictor Perevertkin &infoLength); 4754c95339dSVictor Perevertkin if (NT_SUCCESS(Status)) 4764c95339dSVictor Perevertkin { 4774c95339dSVictor Perevertkin RegistryPath.Length = nameInfo->NameLength; 4784c95339dSVictor Perevertkin RegistryPath.MaximumLength = nameInfo->NameLength; 4794c95339dSVictor Perevertkin RegistryPath.Buffer = nameInfo->Name; 4804c95339dSVictor Perevertkin } 4814c95339dSVictor Perevertkin else 4824c95339dSVictor Perevertkin { 4834c95339dSVictor Perevertkin ExFreePoolWithTag(nameInfo, TAG_IO); 4844c95339dSVictor Perevertkin } 4854c95339dSVictor Perevertkin } 4864c95339dSVictor Perevertkin else 4874c95339dSVictor Perevertkin { 4884c95339dSVictor Perevertkin Status = STATUS_INSUFFICIENT_RESOURCES; 4894c95339dSVictor Perevertkin } 4904c95339dSVictor Perevertkin } 4914c95339dSVictor Perevertkin else 4924c95339dSVictor Perevertkin { 4934c95339dSVictor Perevertkin Status = NT_SUCCESS(Status) ? STATUS_UNSUCCESSFUL : Status; 4944c95339dSVictor Perevertkin } 4954c95339dSVictor Perevertkin 4964c95339dSVictor Perevertkin if (!NT_SUCCESS(Status)) 4974c95339dSVictor Perevertkin { 498c4c0585fSVictor Perevertkin RtlFreeUnicodeString(&ServiceName); 4994c95339dSVictor Perevertkin RtlFreeUnicodeString(&DriverName); 5004c95339dSVictor Perevertkin MmUnloadSystemImage(ModuleObject); 5014c95339dSVictor Perevertkin return Status; 5024c95339dSVictor Perevertkin } 5034c95339dSVictor Perevertkin 504a82ff90bSHermès Bélusca-Maïto /* Create the driver object */ 505a82ff90bSHermès Bélusca-Maïto ULONG ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION); 506e18a32dfSVictor Perevertkin OBJECT_ATTRIBUTES objAttrs; 507e18a32dfSVictor Perevertkin PDRIVER_OBJECT driverObject; 508e18a32dfSVictor Perevertkin InitializeObjectAttributes(&objAttrs, 509e18a32dfSVictor Perevertkin &DriverName, 510e18a32dfSVictor Perevertkin OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 511e18a32dfSVictor Perevertkin NULL, 512e18a32dfSVictor Perevertkin NULL); 513e18a32dfSVictor Perevertkin 514e18a32dfSVictor Perevertkin Status = ObCreateObject(KernelMode, 515e18a32dfSVictor Perevertkin IoDriverObjectType, 516e18a32dfSVictor Perevertkin &objAttrs, 517e18a32dfSVictor Perevertkin KernelMode, 518e18a32dfSVictor Perevertkin NULL, 519e18a32dfSVictor Perevertkin ObjectSize, 520e18a32dfSVictor Perevertkin 0, 521e18a32dfSVictor Perevertkin 0, 522e18a32dfSVictor Perevertkin (PVOID*)&driverObject); 523e18a32dfSVictor Perevertkin if (!NT_SUCCESS(Status)) 524e18a32dfSVictor Perevertkin { 5254c95339dSVictor Perevertkin ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath 526c4c0585fSVictor Perevertkin RtlFreeUnicodeString(&ServiceName); 527e18a32dfSVictor Perevertkin RtlFreeUnicodeString(&DriverName); 528e18a32dfSVictor Perevertkin MmUnloadSystemImage(ModuleObject); 529e18a32dfSVictor Perevertkin DPRINT1("Error while creating driver object \"%wZ\" status %x\n", &DriverName, Status); 530e18a32dfSVictor Perevertkin return Status; 531e18a32dfSVictor Perevertkin } 532e18a32dfSVictor Perevertkin 533e18a32dfSVictor Perevertkin DPRINT("Created driver object 0x%p for \"%wZ\"\n", driverObject, &DriverName); 534e18a32dfSVictor Perevertkin 535e18a32dfSVictor Perevertkin RtlZeroMemory(driverObject, ObjectSize); 536e18a32dfSVictor Perevertkin driverObject->Type = IO_TYPE_DRIVER; 537e18a32dfSVictor Perevertkin driverObject->Size = sizeof(DRIVER_OBJECT); 5381fd730b7SHermès Bélusca-Maïto 5391fd730b7SHermès Bélusca-Maïto /* Set the legacy flag if this is not a WDM driver */ 5401fd730b7SHermès Bélusca-Maïto if (!(NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_WDM_DRIVER)) 5411fd730b7SHermès Bélusca-Maïto driverObject->Flags |= DRVO_LEGACY_DRIVER; 5421fd730b7SHermès Bélusca-Maïto 543e18a32dfSVictor Perevertkin driverObject->DriverSection = ModuleObject; 544e18a32dfSVictor Perevertkin driverObject->DriverStart = ModuleObject->DllBase; 545e18a32dfSVictor Perevertkin driverObject->DriverSize = ModuleObject->SizeOfImage; 546e18a32dfSVictor Perevertkin driverObject->DriverInit = ModuleObject->EntryPoint; 547e18a32dfSVictor Perevertkin driverObject->HardwareDatabase = &IopHardwareDatabaseKey; 548e18a32dfSVictor Perevertkin driverObject->DriverExtension = (PDRIVER_EXTENSION)(driverObject + 1); 549e18a32dfSVictor Perevertkin driverObject->DriverExtension->DriverObject = driverObject; 550e18a32dfSVictor Perevertkin 551e18a32dfSVictor Perevertkin /* Loop all Major Functions */ 552e18a32dfSVictor Perevertkin for (INT i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) 553e18a32dfSVictor Perevertkin { 554e18a32dfSVictor Perevertkin /* Invalidate each function */ 555e18a32dfSVictor Perevertkin driverObject->MajorFunction[i] = IopInvalidDeviceRequest; 556e18a32dfSVictor Perevertkin } 557e18a32dfSVictor Perevertkin 558e18a32dfSVictor Perevertkin /* Add the Object and get its handle */ 559e18a32dfSVictor Perevertkin HANDLE hDriver; 560e18a32dfSVictor Perevertkin Status = ObInsertObject(driverObject, NULL, FILE_READ_DATA, 0, NULL, &hDriver); 561e18a32dfSVictor Perevertkin if (!NT_SUCCESS(Status)) 562e18a32dfSVictor Perevertkin { 5634c95339dSVictor Perevertkin ExFreePoolWithTag(nameInfo, TAG_IO); 564c4c0585fSVictor Perevertkin RtlFreeUnicodeString(&ServiceName); 565e18a32dfSVictor Perevertkin RtlFreeUnicodeString(&DriverName); 566e18a32dfSVictor Perevertkin return Status; 567e18a32dfSVictor Perevertkin } 568e18a32dfSVictor Perevertkin 569e18a32dfSVictor Perevertkin /* Now reference it */ 570e18a32dfSVictor Perevertkin Status = ObReferenceObjectByHandle(hDriver, 571e18a32dfSVictor Perevertkin 0, 572e18a32dfSVictor Perevertkin IoDriverObjectType, 573e18a32dfSVictor Perevertkin KernelMode, 574e18a32dfSVictor Perevertkin (PVOID*)&driverObject, 575e18a32dfSVictor Perevertkin NULL); 576e18a32dfSVictor Perevertkin 577e18a32dfSVictor Perevertkin /* Close the extra handle */ 578e18a32dfSVictor Perevertkin ZwClose(hDriver); 579e18a32dfSVictor Perevertkin 580e18a32dfSVictor Perevertkin if (!NT_SUCCESS(Status)) 581e18a32dfSVictor Perevertkin { 5824c95339dSVictor Perevertkin ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath 583c4c0585fSVictor Perevertkin RtlFreeUnicodeString(&ServiceName); 584e18a32dfSVictor Perevertkin RtlFreeUnicodeString(&DriverName); 585e18a32dfSVictor Perevertkin return Status; 586e18a32dfSVictor Perevertkin } 587e18a32dfSVictor Perevertkin 588e18a32dfSVictor Perevertkin /* Set up the service key name buffer */ 589e18a32dfSVictor Perevertkin UNICODE_STRING serviceKeyName; 590e18a32dfSVictor Perevertkin serviceKeyName.Length = 0; 591a82ff90bSHermès Bélusca-Maïto // NULL-terminate for Windows compatibility 5924c95339dSVictor Perevertkin serviceKeyName.MaximumLength = ServiceName.MaximumLength + sizeof(UNICODE_NULL); 593e18a32dfSVictor Perevertkin serviceKeyName.Buffer = ExAllocatePoolWithTag(NonPagedPool, 594e18a32dfSVictor Perevertkin serviceKeyName.MaximumLength, 595e18a32dfSVictor Perevertkin TAG_IO); 596e18a32dfSVictor Perevertkin if (!serviceKeyName.Buffer) 597e18a32dfSVictor Perevertkin { 598e18a32dfSVictor Perevertkin ObMakeTemporaryObject(driverObject); 599e18a32dfSVictor Perevertkin ObDereferenceObject(driverObject); 6004c95339dSVictor Perevertkin ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath 601c4c0585fSVictor Perevertkin RtlFreeUnicodeString(&ServiceName); 602e18a32dfSVictor Perevertkin RtlFreeUnicodeString(&DriverName); 603e18a32dfSVictor Perevertkin return STATUS_INSUFFICIENT_RESOURCES; 604e18a32dfSVictor Perevertkin } 605e18a32dfSVictor Perevertkin 606e18a32dfSVictor Perevertkin /* Copy the name and set it in the driver extension */ 6074c95339dSVictor Perevertkin RtlCopyUnicodeString(&serviceKeyName, &ServiceName); 608c4c0585fSVictor Perevertkin RtlFreeUnicodeString(&ServiceName); 609e18a32dfSVictor Perevertkin driverObject->DriverExtension->ServiceKeyName = serviceKeyName; 610e18a32dfSVictor Perevertkin 611e18a32dfSVictor Perevertkin /* Make a copy of the driver name to store in the driver object */ 612e18a32dfSVictor Perevertkin UNICODE_STRING driverNamePaged; 613e18a32dfSVictor Perevertkin driverNamePaged.Length = 0; 614a82ff90bSHermès Bélusca-Maïto // NULL-terminate for Windows compatibility 615e18a32dfSVictor Perevertkin driverNamePaged.MaximumLength = DriverName.MaximumLength + sizeof(UNICODE_NULL); 616e18a32dfSVictor Perevertkin driverNamePaged.Buffer = ExAllocatePoolWithTag(PagedPool, 617e18a32dfSVictor Perevertkin driverNamePaged.MaximumLength, 618e18a32dfSVictor Perevertkin TAG_IO); 619e18a32dfSVictor Perevertkin if (!driverNamePaged.Buffer) 620e18a32dfSVictor Perevertkin { 621e18a32dfSVictor Perevertkin ObMakeTemporaryObject(driverObject); 622e18a32dfSVictor Perevertkin ObDereferenceObject(driverObject); 6234c95339dSVictor Perevertkin ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath 624e18a32dfSVictor Perevertkin RtlFreeUnicodeString(&DriverName); 625e18a32dfSVictor Perevertkin return STATUS_INSUFFICIENT_RESOURCES; 626e18a32dfSVictor Perevertkin } 627e18a32dfSVictor Perevertkin 628e18a32dfSVictor Perevertkin RtlCopyUnicodeString(&driverNamePaged, &DriverName); 629e18a32dfSVictor Perevertkin driverObject->DriverName = driverNamePaged; 630e18a32dfSVictor Perevertkin 631e18a32dfSVictor Perevertkin /* Finally, call its init function */ 6324c95339dSVictor Perevertkin Status = driverObject->DriverInit(driverObject, &RegistryPath); 633e18a32dfSVictor Perevertkin *DriverEntryStatus = Status; 634e18a32dfSVictor Perevertkin if (!NT_SUCCESS(Status)) 635e18a32dfSVictor Perevertkin { 636e18a32dfSVictor Perevertkin DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", &DriverName, Status); 637e18a32dfSVictor Perevertkin // return a special status value in case of failure 638e18a32dfSVictor Perevertkin Status = STATUS_FAILED_DRIVER_ENTRY; 639e18a32dfSVictor Perevertkin } 640e18a32dfSVictor Perevertkin 641e18a32dfSVictor Perevertkin /* HACK: We're going to say if we don't have any DOs from DriverEntry, then we're not legacy. 642e18a32dfSVictor Perevertkin * Other parts of the I/O manager depend on this behavior */ 643e18a32dfSVictor Perevertkin if (!driverObject->DeviceObject) 644e18a32dfSVictor Perevertkin { 645e18a32dfSVictor Perevertkin driverObject->Flags &= ~DRVO_LEGACY_DRIVER; 646e18a32dfSVictor Perevertkin } 647e18a32dfSVictor Perevertkin 648e18a32dfSVictor Perevertkin // Windows does this fixup - keep it for compatibility 649e18a32dfSVictor Perevertkin for (INT i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) 650e18a32dfSVictor Perevertkin { 651e18a32dfSVictor Perevertkin /* 652e18a32dfSVictor Perevertkin * Make sure the driver didn't set any dispatch entry point to NULL! 653e18a32dfSVictor Perevertkin * Doing so is illegal; drivers shouldn't touch entry points they 654e18a32dfSVictor Perevertkin * do not implement. 655e18a32dfSVictor Perevertkin */ 656e18a32dfSVictor Perevertkin 657e18a32dfSVictor Perevertkin /* Check if it did so anyway */ 658e18a32dfSVictor Perevertkin if (!driverObject->MajorFunction[i]) 659e18a32dfSVictor Perevertkin { 660e18a32dfSVictor Perevertkin /* Print a warning in the debug log */ 661e18a32dfSVictor Perevertkin DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%lu] to NULL!\n", 662e18a32dfSVictor Perevertkin &driverObject->DriverName, i); 663e18a32dfSVictor Perevertkin 664e18a32dfSVictor Perevertkin /* Fix it up */ 665e18a32dfSVictor Perevertkin driverObject->MajorFunction[i] = IopInvalidDeviceRequest; 666e18a32dfSVictor Perevertkin } 667e18a32dfSVictor Perevertkin } 668e18a32dfSVictor Perevertkin 669e18a32dfSVictor Perevertkin // TODO: for legacy drivers, unload the driver if it didn't create any DO 670e18a32dfSVictor Perevertkin 6714c95339dSVictor Perevertkin ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath 672c2c66affSColin Finck RtlFreeUnicodeString(&DriverName); 673c2c66affSColin Finck 674c2c66affSColin Finck if (!NT_SUCCESS(Status)) 675c2c66affSColin Finck { 676e18a32dfSVictor Perevertkin // if the driver entry has been failed, clear the object 677e18a32dfSVictor Perevertkin ObMakeTemporaryObject(driverObject); 678e18a32dfSVictor Perevertkin ObDereferenceObject(driverObject); 679c2c66affSColin Finck return Status; 680c2c66affSColin Finck } 681c2c66affSColin Finck 682e18a32dfSVictor Perevertkin *OutDriverObject = driverObject; 683c2c66affSColin Finck 684e18a32dfSVictor Perevertkin MmFreeDriverInitialization((PLDR_DATA_TABLE_ENTRY)driverObject->DriverSection); 685c2c66affSColin Finck 686c2c66affSColin Finck /* Set the driver as initialized */ 687e18a32dfSVictor Perevertkin IopReadyDeviceObjects(driverObject); 688c2c66affSColin Finck 689c2c66affSColin Finck if (PnpSystemInit) IopReinitializeDrivers(); 690c2c66affSColin Finck 691c2c66affSColin Finck return STATUS_SUCCESS; 692c2c66affSColin Finck } 693c2c66affSColin Finck 694c2c66affSColin Finck NTSTATUS 695c2c66affSColin Finck NTAPI 696c2c66affSColin Finck MiResolveImageReferences(IN PVOID ImageBase, 697c2c66affSColin Finck IN PUNICODE_STRING ImageFileDirectory, 698c2c66affSColin Finck IN PUNICODE_STRING NamePrefix OPTIONAL, 699c2c66affSColin Finck OUT PCHAR *MissingApi, 700c2c66affSColin Finck OUT PWCHAR *MissingDriver, 701c2c66affSColin Finck OUT PLOAD_IMPORTS *LoadImports); 702c2c66affSColin Finck 703c2c66affSColin Finck // 704c2c66affSColin Finck // Used for images already loaded (boot drivers) 705c2c66affSColin Finck // 7065c7ce447SVictor Perevertkin CODE_SEG("INIT") 707c2c66affSColin Finck NTSTATUS 708c2c66affSColin Finck NTAPI 709c2c66affSColin Finck LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry, 710c2c66affSColin Finck PUNICODE_STRING FileName, 711c2c66affSColin Finck PLDR_DATA_TABLE_ENTRY *ModuleObject) 712c2c66affSColin Finck { 713c2c66affSColin Finck NTSTATUS Status; 714c2c66affSColin Finck UNICODE_STRING BaseName, BaseDirectory; 715c2c66affSColin Finck PLOAD_IMPORTS LoadedImports = (PVOID)-2; 716c2c66affSColin Finck PCHAR MissingApiName, Buffer; 717c2c66affSColin Finck PWCHAR MissingDriverName; 718c2c66affSColin Finck PVOID DriverBase = LdrEntry->DllBase; 719c2c66affSColin Finck 720c2c66affSColin Finck /* Allocate a buffer we'll use for names */ 721f3a280f5SThomas Faber Buffer = ExAllocatePoolWithTag(NonPagedPool, 722f3a280f5SThomas Faber MAXIMUM_FILENAME_LENGTH, 723f3a280f5SThomas Faber TAG_LDR_WSTR); 724c2c66affSColin Finck if (!Buffer) 725c2c66affSColin Finck { 726c2c66affSColin Finck /* Fail */ 727c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 728c2c66affSColin Finck } 729c2c66affSColin Finck 730c2c66affSColin Finck /* Check for a separator */ 731c2c66affSColin Finck if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) 732c2c66affSColin Finck { 733c2c66affSColin Finck PWCHAR p; 734c2c66affSColin Finck ULONG BaseLength; 735c2c66affSColin Finck 736c2c66affSColin Finck /* Loop the path until we get to the base name */ 737c2c66affSColin Finck p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)]; 738c2c66affSColin Finck while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--; 739c2c66affSColin Finck 740c2c66affSColin Finck /* Get the length */ 741c2c66affSColin Finck BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p); 742c2c66affSColin Finck BaseLength *= sizeof(WCHAR); 743c2c66affSColin Finck 744c2c66affSColin Finck /* Setup the string */ 745c2c66affSColin Finck BaseName.Length = (USHORT)BaseLength; 746c2c66affSColin Finck BaseName.Buffer = p; 747c2c66affSColin Finck } 748c2c66affSColin Finck else 749c2c66affSColin Finck { 750c2c66affSColin Finck /* Otherwise, we already have a base name */ 751c2c66affSColin Finck BaseName.Length = FileName->Length; 752c2c66affSColin Finck BaseName.Buffer = FileName->Buffer; 753c2c66affSColin Finck } 754c2c66affSColin Finck 755c2c66affSColin Finck /* Setup the maximum length */ 756c2c66affSColin Finck BaseName.MaximumLength = BaseName.Length; 757c2c66affSColin Finck 758c2c66affSColin Finck /* Now compute the base directory */ 759c2c66affSColin Finck BaseDirectory = *FileName; 760c2c66affSColin Finck BaseDirectory.Length -= BaseName.Length; 761c2c66affSColin Finck BaseDirectory.MaximumLength = BaseDirectory.Length; 762c2c66affSColin Finck 763c2c66affSColin Finck /* Resolve imports */ 764c2c66affSColin Finck MissingApiName = Buffer; 765c2c66affSColin Finck Status = MiResolveImageReferences(DriverBase, 766c2c66affSColin Finck &BaseDirectory, 767c2c66affSColin Finck NULL, 768c2c66affSColin Finck &MissingApiName, 769c2c66affSColin Finck &MissingDriverName, 770c2c66affSColin Finck &LoadedImports); 771c2c66affSColin Finck 772c2c66affSColin Finck /* Free the temporary buffer */ 773c2c66affSColin Finck ExFreePoolWithTag(Buffer, TAG_LDR_WSTR); 774c2c66affSColin Finck 775c2c66affSColin Finck /* Check the result of the imports resolution */ 776c2c66affSColin Finck if (!NT_SUCCESS(Status)) return Status; 777c2c66affSColin Finck 778c2c66affSColin Finck /* Return */ 779c2c66affSColin Finck *ModuleObject = LdrEntry; 780c2c66affSColin Finck return STATUS_SUCCESS; 781c2c66affSColin Finck } 782c2c66affSColin Finck 78391fceab3SVictor Perevertkin PDEVICE_OBJECT 78491fceab3SVictor Perevertkin IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance); 78591fceab3SVictor Perevertkin 786c2c66affSColin Finck /* 787c2c66affSColin Finck * IopInitializeBuiltinDriver 788c2c66affSColin Finck * 789c2c66affSColin Finck * Initialize a driver that is already loaded in memory. 790c2c66affSColin Finck */ 7915c7ce447SVictor Perevertkin CODE_SEG("INIT") 7923adf4508SJérôme Gardou static 79391fceab3SVictor Perevertkin BOOLEAN 794c2c66affSColin Finck IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY BootLdrEntry) 795c2c66affSColin Finck { 796c2c66affSColin Finck PDRIVER_OBJECT DriverObject; 797c2c66affSColin Finck NTSTATUS Status; 798c2c66affSColin Finck PWCHAR Buffer, FileNameWithoutPath; 799c2c66affSColin Finck PWSTR FileExtension; 800c2c66affSColin Finck PUNICODE_STRING ModuleName = &BootLdrEntry->BaseDllName; 801c2c66affSColin Finck PLDR_DATA_TABLE_ENTRY LdrEntry; 802c2c66affSColin Finck PLIST_ENTRY NextEntry; 803c2c66affSColin Finck UNICODE_STRING ServiceName; 804c2c66affSColin Finck BOOLEAN Success; 805c2c66affSColin Finck 806c2c66affSColin Finck /* 807c2c66affSColin Finck * Display 'Loading XXX...' message 808c2c66affSColin Finck */ 809c2c66affSColin Finck IopDisplayLoadingMessage(ModuleName); 810c2c66affSColin Finck InbvIndicateProgress(); 811c2c66affSColin Finck 812c2c66affSColin Finck Buffer = ExAllocatePoolWithTag(PagedPool, 813c2c66affSColin Finck ModuleName->Length + sizeof(UNICODE_NULL), 814c2c66affSColin Finck TAG_IO); 815c2c66affSColin Finck if (Buffer == NULL) 816c2c66affSColin Finck { 81791fceab3SVictor Perevertkin return FALSE; 818c2c66affSColin Finck } 819c2c66affSColin Finck 820c2c66affSColin Finck RtlCopyMemory(Buffer, ModuleName->Buffer, ModuleName->Length); 821c2c66affSColin Finck Buffer[ModuleName->Length / sizeof(WCHAR)] = UNICODE_NULL; 822c2c66affSColin Finck 823c2c66affSColin Finck /* 824c2c66affSColin Finck * Generate filename without path (not needed by freeldr) 825c2c66affSColin Finck */ 826c2c66affSColin Finck FileNameWithoutPath = wcsrchr(Buffer, L'\\'); 827c2c66affSColin Finck if (FileNameWithoutPath == NULL) 828c2c66affSColin Finck { 829c2c66affSColin Finck FileNameWithoutPath = Buffer; 830c2c66affSColin Finck } 831c2c66affSColin Finck else 832c2c66affSColin Finck { 833c2c66affSColin Finck FileNameWithoutPath++; 834c2c66affSColin Finck } 835c2c66affSColin Finck 836c2c66affSColin Finck /* 837c2c66affSColin Finck * Strip the file extension from ServiceName 838c2c66affSColin Finck */ 839c2c66affSColin Finck Success = RtlCreateUnicodeString(&ServiceName, FileNameWithoutPath); 840c2c66affSColin Finck ExFreePoolWithTag(Buffer, TAG_IO); 841c2c66affSColin Finck if (!Success) 842c2c66affSColin Finck { 84391fceab3SVictor Perevertkin return FALSE; 844c2c66affSColin Finck } 845c2c66affSColin Finck 846c2c66affSColin Finck FileExtension = wcsrchr(ServiceName.Buffer, L'.'); 847c2c66affSColin Finck if (FileExtension != NULL) 848c2c66affSColin Finck { 849c2c66affSColin Finck ServiceName.Length -= (USHORT)wcslen(FileExtension) * sizeof(WCHAR); 850c2c66affSColin Finck FileExtension[0] = UNICODE_NULL; 851c2c66affSColin Finck } 852c2c66affSColin Finck 8534c95339dSVictor Perevertkin UNICODE_STRING RegistryPath; 8544c95339dSVictor Perevertkin 8554c95339dSVictor Perevertkin // Make the registry path for the driver 8564c95339dSVictor Perevertkin RegistryPath.Length = 0; 8574c95339dSVictor Perevertkin RegistryPath.MaximumLength = sizeof(ServicesKeyName) + ServiceName.Length; 8584c95339dSVictor Perevertkin RegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool, RegistryPath.MaximumLength, TAG_IO); 8594c95339dSVictor Perevertkin if (RegistryPath.Buffer == NULL) 8604c95339dSVictor Perevertkin { 86191fceab3SVictor Perevertkin return FALSE; 8624c95339dSVictor Perevertkin } 8634c95339dSVictor Perevertkin RtlAppendUnicodeToString(&RegistryPath, ServicesKeyName); 8644c95339dSVictor Perevertkin RtlAppendUnicodeStringToString(&RegistryPath, &ServiceName); 8654c95339dSVictor Perevertkin RtlFreeUnicodeString(&ServiceName); 8664c95339dSVictor Perevertkin 8674c95339dSVictor Perevertkin HANDLE serviceHandle; 8684c95339dSVictor Perevertkin Status = IopOpenRegistryKeyEx(&serviceHandle, NULL, &RegistryPath, KEY_READ); 8694c95339dSVictor Perevertkin RtlFreeUnicodeString(&RegistryPath); 8704c95339dSVictor Perevertkin if (!NT_SUCCESS(Status)) 8714c95339dSVictor Perevertkin { 87291fceab3SVictor Perevertkin return FALSE; 8734c95339dSVictor Perevertkin } 8744c95339dSVictor Perevertkin 875c2c66affSColin Finck /* Lookup the new Ldr entry in PsLoadedModuleList */ 876a82ff90bSHermès Bélusca-Maïto for (NextEntry = PsLoadedModuleList.Flink; 877a82ff90bSHermès Bélusca-Maïto NextEntry != &PsLoadedModuleList; 878a82ff90bSHermès Bélusca-Maïto NextEntry = NextEntry->Flink) 879c2c66affSColin Finck { 880c2c66affSColin Finck LdrEntry = CONTAINING_RECORD(NextEntry, 881c2c66affSColin Finck LDR_DATA_TABLE_ENTRY, 882c2c66affSColin Finck InLoadOrderLinks); 883c2c66affSColin Finck if (RtlEqualUnicodeString(ModuleName, &LdrEntry->BaseDllName, TRUE)) 884c2c66affSColin Finck { 885c2c66affSColin Finck break; 886c2c66affSColin Finck } 887c2c66affSColin Finck } 888c2c66affSColin Finck ASSERT(NextEntry != &PsLoadedModuleList); 889c2c66affSColin Finck 890c2c66affSColin Finck /* 891c2c66affSColin Finck * Initialize the driver 892c2c66affSColin Finck */ 893e18a32dfSVictor Perevertkin NTSTATUS driverEntryStatus; 8946f0e37b0SVictor Perevertkin Status = IopInitializeDriverModule(LdrEntry, 8954c95339dSVictor Perevertkin serviceHandle, 896e18a32dfSVictor Perevertkin &DriverObject, 897e18a32dfSVictor Perevertkin &driverEntryStatus); 898c2c66affSColin Finck 899c2c66affSColin Finck if (!NT_SUCCESS(Status)) 900c2c66affSColin Finck { 9016f0e37b0SVictor Perevertkin DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status); 90291fceab3SVictor Perevertkin return FALSE; 903c2c66affSColin Finck } 904c2c66affSColin Finck 90591fceab3SVictor Perevertkin // The driver has been loaded, now check if where are any PDOs 90691fceab3SVictor Perevertkin // for that driver, and queue AddDevice call for them. 90791fceab3SVictor Perevertkin // The check is possible because HKLM/SYSTEM/CCS/Services/<ServiceName>/Enum directory 90891fceab3SVictor Perevertkin // is populated upon a new device arrival based on a (critical) device database 90991fceab3SVictor Perevertkin 91091fceab3SVictor Perevertkin // Legacy drivers may add devices inside DriverEntry. 91191fceab3SVictor Perevertkin // We're lazy and always assume that they are doing so 912a82ff90bSHermès Bélusca-Maïto BOOLEAN deviceAdded = !!(DriverObject->Flags & DRVO_LEGACY_DRIVER); 91391fceab3SVictor Perevertkin 91491fceab3SVictor Perevertkin HANDLE enumServiceHandle; 91591fceab3SVictor Perevertkin UNICODE_STRING enumName = RTL_CONSTANT_STRING(L"Enum"); 91691fceab3SVictor Perevertkin 91791fceab3SVictor Perevertkin Status = IopOpenRegistryKeyEx(&enumServiceHandle, serviceHandle, &enumName, KEY_READ); 91891fceab3SVictor Perevertkin ZwClose(serviceHandle); 91991fceab3SVictor Perevertkin 92091fceab3SVictor Perevertkin if (NT_SUCCESS(Status)) 92191fceab3SVictor Perevertkin { 922a82ff90bSHermès Bélusca-Maïto ULONG instanceCount = 0; 92391fceab3SVictor Perevertkin PKEY_VALUE_FULL_INFORMATION kvInfo; 92491fceab3SVictor Perevertkin Status = IopGetRegistryValue(enumServiceHandle, L"Count", &kvInfo); 92591fceab3SVictor Perevertkin if (!NT_SUCCESS(Status)) 92691fceab3SVictor Perevertkin { 92791fceab3SVictor Perevertkin goto Cleanup; 92891fceab3SVictor Perevertkin } 9290d28f271SHermès Bélusca-Maïto if (kvInfo->Type != REG_DWORD || kvInfo->DataLength != sizeof(ULONG)) 93091fceab3SVictor Perevertkin { 93191fceab3SVictor Perevertkin ExFreePool(kvInfo); 93291fceab3SVictor Perevertkin goto Cleanup; 93391fceab3SVictor Perevertkin } 934fe416b67SHermès Bélusca-Maïto 935fe416b67SHermès Bélusca-Maïto RtlMoveMemory(&instanceCount, 936fe416b67SHermès Bélusca-Maïto (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset), 937fe416b67SHermès Bélusca-Maïto sizeof(ULONG)); 93891fceab3SVictor Perevertkin ExFreePool(kvInfo); 93991fceab3SVictor Perevertkin 94091fceab3SVictor Perevertkin DPRINT("Processing %u instances for %wZ module\n", instanceCount, ModuleName); 94191fceab3SVictor Perevertkin 942a82ff90bSHermès Bélusca-Maïto for (ULONG i = 0; i < instanceCount; i++) 94391fceab3SVictor Perevertkin { 94491fceab3SVictor Perevertkin WCHAR num[11]; 94591fceab3SVictor Perevertkin UNICODE_STRING instancePath; 94691fceab3SVictor Perevertkin RtlStringCchPrintfW(num, sizeof(num), L"%u", i); 94791fceab3SVictor Perevertkin 94891fceab3SVictor Perevertkin Status = IopGetRegistryValue(enumServiceHandle, num, &kvInfo); 94991fceab3SVictor Perevertkin if (!NT_SUCCESS(Status)) 95091fceab3SVictor Perevertkin { 95191fceab3SVictor Perevertkin continue; 95291fceab3SVictor Perevertkin } 95391fceab3SVictor Perevertkin if (kvInfo->Type != REG_SZ || kvInfo->DataLength == 0) 95491fceab3SVictor Perevertkin { 95591fceab3SVictor Perevertkin ExFreePool(kvInfo); 95691fceab3SVictor Perevertkin continue; 95791fceab3SVictor Perevertkin } 95891fceab3SVictor Perevertkin 9590d28f271SHermès Bélusca-Maïto instancePath.Length = kvInfo->DataLength - sizeof(UNICODE_NULL); 960a82ff90bSHermès Bélusca-Maïto instancePath.MaximumLength = kvInfo->DataLength; 96191fceab3SVictor Perevertkin instancePath.Buffer = ExAllocatePoolWithTag(NonPagedPool, 96291fceab3SVictor Perevertkin instancePath.MaximumLength, 96391fceab3SVictor Perevertkin TAG_IO); 96491fceab3SVictor Perevertkin if (instancePath.Buffer) 96591fceab3SVictor Perevertkin { 96691fceab3SVictor Perevertkin RtlMoveMemory(instancePath.Buffer, 96791fceab3SVictor Perevertkin (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset), 96891fceab3SVictor Perevertkin instancePath.Length); 9690d28f271SHermès Bélusca-Maïto instancePath.Buffer[instancePath.Length / sizeof(WCHAR)] = UNICODE_NULL; 97091fceab3SVictor Perevertkin 97191fceab3SVictor Perevertkin PDEVICE_OBJECT pdo = IopGetDeviceObjectFromDeviceInstance(&instancePath); 97291fceab3SVictor Perevertkin PiQueueDeviceAction(pdo, PiActionAddBootDevices, NULL, NULL); 97391fceab3SVictor Perevertkin ObDereferenceObject(pdo); 97491fceab3SVictor Perevertkin deviceAdded = TRUE; 97591fceab3SVictor Perevertkin } 97691fceab3SVictor Perevertkin 97791fceab3SVictor Perevertkin ExFreePool(kvInfo); 97891fceab3SVictor Perevertkin } 97991fceab3SVictor Perevertkin 98091fceab3SVictor Perevertkin ZwClose(enumServiceHandle); 98191fceab3SVictor Perevertkin } 98291fceab3SVictor Perevertkin Cleanup: 983c2c66affSColin Finck /* Remove extra reference from IopInitializeDriverModule */ 984c2c66affSColin Finck ObDereferenceObject(DriverObject); 985c2c66affSColin Finck 98691fceab3SVictor Perevertkin return deviceAdded; 987c2c66affSColin Finck } 988c2c66affSColin Finck 989c2c66affSColin Finck /* 990c2c66affSColin Finck * IopInitializeBootDrivers 991c2c66affSColin Finck * 992c2c66affSColin Finck * Initialize boot drivers and free memory for boot files. 993c2c66affSColin Finck * 994c2c66affSColin Finck * Parameters 995c2c66affSColin Finck * None 996c2c66affSColin Finck * 997c2c66affSColin Finck * Return Value 998c2c66affSColin Finck * None 999c2c66affSColin Finck */ 10005c7ce447SVictor Perevertkin CODE_SEG("INIT") 1001c2c66affSColin Finck VOID 1002c2c66affSColin Finck FASTCALL 1003c2c66affSColin Finck IopInitializeBootDrivers(VOID) 1004c2c66affSColin Finck { 1005c2c66affSColin Finck PLIST_ENTRY ListHead, NextEntry, NextEntry2; 1006c2c66affSColin Finck PLDR_DATA_TABLE_ENTRY LdrEntry; 1007c2c66affSColin Finck NTSTATUS Status; 1008c2c66affSColin Finck UNICODE_STRING DriverName; 1009c2c66affSColin Finck ULONG i, Index; 1010c2c66affSColin Finck PDRIVER_INFORMATION DriverInfo, DriverInfoTag; 1011c2c66affSColin Finck HANDLE KeyHandle; 1012c2c66affSColin Finck PBOOT_DRIVER_LIST_ENTRY BootEntry; 1013c2c66affSColin Finck DPRINT("IopInitializeBootDrivers()\n"); 1014c2c66affSColin Finck 1015e18a32dfSVictor Perevertkin /* Create the RAW FS built-in driver */ 1016e18a32dfSVictor Perevertkin RtlInitUnicodeString(&DriverName, L"\\FileSystem\\RAW"); 1017c2c66affSColin Finck 1018e18a32dfSVictor Perevertkin Status = IoCreateDriver(&DriverName, RawFsDriverEntry); 1019c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1020c2c66affSColin Finck { 1021c2c66affSColin Finck /* Fail */ 1022c2c66affSColin Finck return; 1023c2c66affSColin Finck } 1024c2c66affSColin Finck 1025c2c66affSColin Finck /* Get highest group order index */ 1026c2c66affSColin Finck IopGroupIndex = PpInitGetGroupOrderIndex(NULL); 1027c2c66affSColin Finck if (IopGroupIndex == 0xFFFF) ASSERT(FALSE); 1028c2c66affSColin Finck 1029c2c66affSColin Finck /* Allocate the group table */ 1030c2c66affSColin Finck IopGroupTable = ExAllocatePoolWithTag(PagedPool, 1031c2c66affSColin Finck IopGroupIndex * sizeof(LIST_ENTRY), 1032c2c66affSColin Finck TAG_IO); 1033c2c66affSColin Finck if (IopGroupTable == NULL) ASSERT(FALSE); 1034c2c66affSColin Finck 1035c2c66affSColin Finck /* Initialize the group table lists */ 1036c2c66affSColin Finck for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]); 1037c2c66affSColin Finck 1038c2c66affSColin Finck /* Loop the boot modules */ 1039c2c66affSColin Finck ListHead = &KeLoaderBlock->LoadOrderListHead; 1040a82ff90bSHermès Bélusca-Maïto for (NextEntry = ListHead->Flink; 1041a82ff90bSHermès Bélusca-Maïto NextEntry != ListHead; 1042a82ff90bSHermès Bélusca-Maïto NextEntry = NextEntry->Flink) 1043c2c66affSColin Finck { 1044c2c66affSColin Finck /* Get the entry */ 1045c2c66affSColin Finck LdrEntry = CONTAINING_RECORD(NextEntry, 1046c2c66affSColin Finck LDR_DATA_TABLE_ENTRY, 1047c2c66affSColin Finck InLoadOrderLinks); 1048c2c66affSColin Finck 1049c2c66affSColin Finck /* Check if the DLL needs to be initialized */ 1050c2c66affSColin Finck if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL) 1051c2c66affSColin Finck { 1052c2c66affSColin Finck /* Call its entrypoint */ 1053c2c66affSColin Finck MmCallDllInitialize(LdrEntry, NULL); 1054c2c66affSColin Finck } 1055c2c66affSColin Finck } 1056c2c66affSColin Finck 1057c2c66affSColin Finck /* Loop the boot drivers */ 1058c2c66affSColin Finck ListHead = &KeLoaderBlock->BootDriverListHead; 1059a82ff90bSHermès Bélusca-Maïto for (NextEntry = ListHead->Flink; 1060a82ff90bSHermès Bélusca-Maïto NextEntry != ListHead; 1061a82ff90bSHermès Bélusca-Maïto NextEntry = NextEntry->Flink) 1062c2c66affSColin Finck { 1063c2c66affSColin Finck /* Get the entry */ 1064c2c66affSColin Finck BootEntry = CONTAINING_RECORD(NextEntry, 1065c2c66affSColin Finck BOOT_DRIVER_LIST_ENTRY, 1066c2c66affSColin Finck Link); 1067c2c66affSColin Finck 1068f2645e48SHermès Bélusca-Maïto // FIXME: TODO: This LdrEntry is to be used in a special handling 1069f2645e48SHermès Bélusca-Maïto // for SETUPLDR (a similar procedure is done on Windows), where 1070f2645e48SHermès Bélusca-Maïto // the loader would, under certain conditions, be loaded in the 1071f2645e48SHermès Bélusca-Maïto // SETUPLDR-specific code block below... 1072f2645e48SHermès Bélusca-Maïto #if 0 1073c2c66affSColin Finck /* Get the driver loader entry */ 1074c2c66affSColin Finck LdrEntry = BootEntry->LdrEntry; 1075f2645e48SHermès Bélusca-Maïto #endif 1076c2c66affSColin Finck 1077c2c66affSColin Finck /* Allocate our internal accounting structure */ 1078c2c66affSColin Finck DriverInfo = ExAllocatePoolWithTag(PagedPool, 1079c2c66affSColin Finck sizeof(DRIVER_INFORMATION), 1080c2c66affSColin Finck TAG_IO); 1081c2c66affSColin Finck if (DriverInfo) 1082c2c66affSColin Finck { 1083c2c66affSColin Finck /* Zero it and initialize it */ 1084c2c66affSColin Finck RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION)); 1085c2c66affSColin Finck InitializeListHead(&DriverInfo->Link); 1086c2c66affSColin Finck DriverInfo->DataTableEntry = BootEntry; 1087c2c66affSColin Finck 1088c2c66affSColin Finck /* Open the registry key */ 1089c2c66affSColin Finck Status = IopOpenRegistryKeyEx(&KeyHandle, 1090c2c66affSColin Finck NULL, 1091c2c66affSColin Finck &BootEntry->RegistryPath, 1092c2c66affSColin Finck KEY_READ); 10938e51bb65SPierre Schweitzer DPRINT("IopOpenRegistryKeyEx(%wZ) returned 0x%08lx\n", &BootEntry->RegistryPath, Status); 1094cb69c4c6SHermès Bélusca-Maïto #if 0 1095cb69c4c6SHermès Bélusca-Maïto if (NT_SUCCESS(Status)) 1096cb69c4c6SHermès Bélusca-Maïto #else // Hack still needed... 1097c2c66affSColin Finck if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */ 1098c2c66affSColin Finck ((KeLoaderBlock->SetupLdrBlock) && ((KeyHandle = (PVOID)1)))) // yes, it's an assignment! 1099cb69c4c6SHermès Bélusca-Maïto #endif 1100c2c66affSColin Finck { 1101c2c66affSColin Finck /* Save the handle */ 1102c2c66affSColin Finck DriverInfo->ServiceHandle = KeyHandle; 1103c2c66affSColin Finck 1104c2c66affSColin Finck /* Get the group oder index */ 1105c2c66affSColin Finck Index = PpInitGetGroupOrderIndex(KeyHandle); 1106c2c66affSColin Finck 1107c2c66affSColin Finck /* Get the tag position */ 1108c2c66affSColin Finck DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle); 1109c2c66affSColin Finck 1110c2c66affSColin Finck /* Insert it into the list, at the right place */ 1111c2c66affSColin Finck ASSERT(Index < IopGroupIndex); 1112c2c66affSColin Finck NextEntry2 = IopGroupTable[Index].Flink; 1113c2c66affSColin Finck while (NextEntry2 != &IopGroupTable[Index]) 1114c2c66affSColin Finck { 1115c2c66affSColin Finck /* Get the driver info */ 1116c2c66affSColin Finck DriverInfoTag = CONTAINING_RECORD(NextEntry2, 1117c2c66affSColin Finck DRIVER_INFORMATION, 1118c2c66affSColin Finck Link); 1119c2c66affSColin Finck 1120c2c66affSColin Finck /* Check if we found the right tag position */ 1121c2c66affSColin Finck if (DriverInfoTag->TagPosition > DriverInfo->TagPosition) 1122c2c66affSColin Finck { 1123c2c66affSColin Finck /* We're done */ 1124c2c66affSColin Finck break; 1125c2c66affSColin Finck } 1126c2c66affSColin Finck 1127c2c66affSColin Finck /* Next entry */ 1128c2c66affSColin Finck NextEntry2 = NextEntry2->Flink; 1129c2c66affSColin Finck } 1130c2c66affSColin Finck 1131c2c66affSColin Finck /* Insert us right before the next entry */ 1132c2c66affSColin Finck NextEntry2 = NextEntry2->Blink; 1133c2c66affSColin Finck InsertHeadList(NextEntry2, &DriverInfo->Link); 1134c2c66affSColin Finck } 1135c2c66affSColin Finck } 1136c2c66affSColin Finck } 1137c2c66affSColin Finck 1138c2c66affSColin Finck /* Loop each group index */ 1139c2c66affSColin Finck for (i = 0; i < IopGroupIndex; i++) 1140c2c66affSColin Finck { 1141c2c66affSColin Finck /* Loop each group table */ 1142a82ff90bSHermès Bélusca-Maïto for (NextEntry = IopGroupTable[i].Flink; 1143a82ff90bSHermès Bélusca-Maïto NextEntry != &IopGroupTable[i]; 1144a82ff90bSHermès Bélusca-Maïto NextEntry = NextEntry->Flink) 1145c2c66affSColin Finck { 1146c2c66affSColin Finck /* Get the entry */ 1147c2c66affSColin Finck DriverInfo = CONTAINING_RECORD(NextEntry, 1148c2c66affSColin Finck DRIVER_INFORMATION, 1149c2c66affSColin Finck Link); 1150c2c66affSColin Finck 1151c2c66affSColin Finck /* Get the driver loader entry */ 1152c2c66affSColin Finck LdrEntry = DriverInfo->DataTableEntry->LdrEntry; 1153c2c66affSColin Finck 1154c2c66affSColin Finck /* Initialize it */ 115591fceab3SVictor Perevertkin if (IopInitializeBuiltinDriver(LdrEntry)) 115691fceab3SVictor Perevertkin { 115791fceab3SVictor Perevertkin // it does not make sense to enumerate the tree if there are no new devices added 1158d6ef8f97SVictor Perevertkin PiQueueDeviceAction(IopRootDeviceNode->PhysicalDeviceObject, 1159d6ef8f97SVictor Perevertkin PiActionEnumRootDevices, 1160d6ef8f97SVictor Perevertkin NULL, 1161d6ef8f97SVictor Perevertkin NULL); 116291fceab3SVictor Perevertkin } 1163c2c66affSColin Finck } 1164c2c66affSColin Finck } 1165c2c66affSColin Finck 11662839c850SVictor Perevertkin /* HAL Root Bus is being initialized before loading the boot drivers so this may cause issues 11672839c850SVictor Perevertkin * when some devices are not being initialized with their drivers. This flag is used to delay 11682839c850SVictor Perevertkin * all actions with devices (except PnP root device) until boot drivers are loaded. 11692839c850SVictor Perevertkin * See PiQueueDeviceAction function 11702839c850SVictor Perevertkin */ 11712839c850SVictor Perevertkin PnPBootDriversLoaded = TRUE; 1172b7042928SVictor Perevertkin 1173b7042928SVictor Perevertkin DbgPrint("BOOT DRIVERS LOADED\n"); 1174b7042928SVictor Perevertkin 1175b7042928SVictor Perevertkin PiQueueDeviceAction(IopRootDeviceNode->PhysicalDeviceObject, 1176b7042928SVictor Perevertkin PiActionEnumDeviceTree, 1177b7042928SVictor Perevertkin NULL, 1178b7042928SVictor Perevertkin NULL); 1179c2c66affSColin Finck } 1180c2c66affSColin Finck 11815c7ce447SVictor Perevertkin CODE_SEG("INIT") 1182c2c66affSColin Finck VOID 1183c2c66affSColin Finck FASTCALL 1184c2c66affSColin Finck IopInitializeSystemDrivers(VOID) 1185c2c66affSColin Finck { 1186c2c66affSColin Finck PUNICODE_STRING *DriverList, *SavedList; 1187c2c66affSColin Finck 1188b7042928SVictor Perevertkin PiPerformSyncDeviceAction(IopRootDeviceNode->PhysicalDeviceObject, PiActionEnumDeviceTree); 1189b7042928SVictor Perevertkin 1190c2c66affSColin Finck /* No system drivers on the boot cd */ 1191cb69c4c6SHermès Bélusca-Maïto if (KeLoaderBlock->SetupLdrBlock) return; // ExpInTextModeSetup 1192c2c66affSColin Finck 1193c2c66affSColin Finck /* Get the driver list */ 1194c2c66affSColin Finck SavedList = DriverList = CmGetSystemDriverList(); 1195c2c66affSColin Finck ASSERT(DriverList); 1196c2c66affSColin Finck 1197c2c66affSColin Finck /* Loop it */ 1198c2c66affSColin Finck while (*DriverList) 1199c2c66affSColin Finck { 1200c2c66affSColin Finck /* Load the driver */ 1201c2c66affSColin Finck ZwLoadDriver(*DriverList); 1202c2c66affSColin Finck 1203c2c66affSColin Finck /* Free the entry */ 1204c2c66affSColin Finck RtlFreeUnicodeString(*DriverList); 1205c2c66affSColin Finck ExFreePool(*DriverList); 1206c2c66affSColin Finck 1207c2c66affSColin Finck /* Next entry */ 1208c2c66affSColin Finck InbvIndicateProgress(); 1209c2c66affSColin Finck DriverList++; 1210c2c66affSColin Finck } 1211c2c66affSColin Finck 1212c2c66affSColin Finck /* Free the list */ 1213c2c66affSColin Finck ExFreePool(SavedList); 1214b7042928SVictor Perevertkin 1215b7042928SVictor Perevertkin PiQueueDeviceAction(IopRootDeviceNode->PhysicalDeviceObject, 1216b7042928SVictor Perevertkin PiActionEnumDeviceTree, 1217b7042928SVictor Perevertkin NULL, 1218b7042928SVictor Perevertkin NULL); 1219c2c66affSColin Finck } 1220c2c66affSColin Finck 1221c2c66affSColin Finck /* 1222c2c66affSColin Finck * IopUnloadDriver 1223c2c66affSColin Finck * 1224c2c66affSColin Finck * Unloads a device driver. 1225c2c66affSColin Finck * 1226c2c66affSColin Finck * Parameters 1227c2c66affSColin Finck * DriverServiceName 1228c2c66affSColin Finck * Name of the service to unload (registry key). 1229c2c66affSColin Finck * 1230c2c66affSColin Finck * UnloadPnpDrivers 1231c2c66affSColin Finck * Whether to unload Plug & Plug or only legacy drivers. If this 1232c2c66affSColin Finck * parameter is set to FALSE, the routine will unload only legacy 1233c2c66affSColin Finck * drivers. 1234c2c66affSColin Finck * 1235c2c66affSColin Finck * Return Value 1236c2c66affSColin Finck * Status 1237c2c66affSColin Finck * 1238c2c66affSColin Finck * To do 1239c2c66affSColin Finck * Guard the whole function by SEH. 1240c2c66affSColin Finck */ 1241c2c66affSColin Finck 1242c2c66affSColin Finck NTSTATUS NTAPI 1243c2c66affSColin Finck IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers) 1244c2c66affSColin Finck { 1245c904983bSThomas Faber UNICODE_STRING Backslash = RTL_CONSTANT_STRING(L"\\"); 1246c2c66affSColin Finck RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 1247c2c66affSColin Finck UNICODE_STRING ImagePath; 1248c2c66affSColin Finck UNICODE_STRING ServiceName; 1249c2c66affSColin Finck UNICODE_STRING ObjectName; 1250c2c66affSColin Finck PDRIVER_OBJECT DriverObject; 1251c2c66affSColin Finck PDEVICE_OBJECT DeviceObject; 1252c2c66affSColin Finck PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1253c2c66affSColin Finck NTSTATUS Status; 1254c904983bSThomas Faber USHORT LastBackslash; 1255c2c66affSColin Finck BOOLEAN SafeToUnload = TRUE; 1256daf9743cSPierre Schweitzer KPROCESSOR_MODE PreviousMode; 1257daf9743cSPierre Schweitzer UNICODE_STRING CapturedServiceName; 1258c2c66affSColin Finck 1259c2c66affSColin Finck PAGED_CODE(); 1260c2c66affSColin Finck 1261daf9743cSPierre Schweitzer PreviousMode = ExGetPreviousMode(); 1262daf9743cSPierre Schweitzer 1263daf9743cSPierre Schweitzer /* Need the appropriate priviliege */ 1264daf9743cSPierre Schweitzer if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode)) 1265daf9743cSPierre Schweitzer { 1266daf9743cSPierre Schweitzer DPRINT1("No unload privilege!\n"); 1267daf9743cSPierre Schweitzer return STATUS_PRIVILEGE_NOT_HELD; 1268daf9743cSPierre Schweitzer } 1269daf9743cSPierre Schweitzer 1270daf9743cSPierre Schweitzer /* Capture the service name */ 127144511f08SHermès Bélusca-Maïto Status = ProbeAndCaptureUnicodeString(&CapturedServiceName, 127244511f08SHermès Bélusca-Maïto PreviousMode, 127344511f08SHermès Bélusca-Maïto DriverServiceName); 1274daf9743cSPierre Schweitzer if (!NT_SUCCESS(Status)) 1275a6a3aa0fSVictor Perevertkin { 1276daf9743cSPierre Schweitzer return Status; 1277a6a3aa0fSVictor Perevertkin } 1278daf9743cSPierre Schweitzer 1279daf9743cSPierre Schweitzer DPRINT("IopUnloadDriver('%wZ', %u)\n", &CapturedServiceName, UnloadPnpDrivers); 1280daf9743cSPierre Schweitzer 1281daf9743cSPierre Schweitzer /* We need a service name */ 1282a748350fSHermès Bélusca-Maïto if (CapturedServiceName.Length == 0 || CapturedServiceName.Buffer == NULL) 1283daf9743cSPierre Schweitzer { 1284daf9743cSPierre Schweitzer ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1285daf9743cSPierre Schweitzer return STATUS_INVALID_PARAMETER; 1286daf9743cSPierre Schweitzer } 1287daf9743cSPierre Schweitzer 1288c2c66affSColin Finck /* 1289c2c66affSColin Finck * Get the service name from the registry key name 1290c2c66affSColin Finck */ 1291c904983bSThomas Faber Status = RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END, 1292c904983bSThomas Faber &CapturedServiceName, 1293c904983bSThomas Faber &Backslash, 1294c904983bSThomas Faber &LastBackslash); 1295c904983bSThomas Faber if (NT_SUCCESS(Status)) 1296c904983bSThomas Faber { 1297c904983bSThomas Faber NT_ASSERT(CapturedServiceName.Length >= LastBackslash + sizeof(WCHAR)); 1298c904983bSThomas Faber ServiceName.Buffer = &CapturedServiceName.Buffer[LastBackslash / sizeof(WCHAR) + 1]; 1299c904983bSThomas Faber ServiceName.Length = CapturedServiceName.Length - LastBackslash - sizeof(WCHAR); 1300c904983bSThomas Faber ServiceName.MaximumLength = CapturedServiceName.MaximumLength - LastBackslash - sizeof(WCHAR); 1301c904983bSThomas Faber } 1302c2c66affSColin Finck else 1303c904983bSThomas Faber { 1304c904983bSThomas Faber ServiceName = CapturedServiceName; 1305c904983bSThomas Faber } 1306c2c66affSColin Finck 1307c2c66affSColin Finck /* 1308c2c66affSColin Finck * Construct the driver object name 1309c2c66affSColin Finck */ 1310c904983bSThomas Faber Status = RtlUShortAdd(sizeof(DRIVER_ROOT_NAME), 1311c904983bSThomas Faber ServiceName.Length, 1312c904983bSThomas Faber &ObjectName.MaximumLength); 1313c904983bSThomas Faber if (!NT_SUCCESS(Status)) 1314c904983bSThomas Faber { 1315c904983bSThomas Faber ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1316c904983bSThomas Faber return Status; 1317c904983bSThomas Faber } 1318c904983bSThomas Faber ObjectName.Length = 0; 1319c2c66affSColin Finck ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool, 1320c2c66affSColin Finck ObjectName.MaximumLength, 1321c2c66affSColin Finck TAG_IO); 1322daf9743cSPierre Schweitzer if (!ObjectName.Buffer) 1323daf9743cSPierre Schweitzer { 1324daf9743cSPierre Schweitzer ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1325daf9743cSPierre Schweitzer return STATUS_INSUFFICIENT_RESOURCES; 1326daf9743cSPierre Schweitzer } 1327c904983bSThomas Faber NT_VERIFY(NT_SUCCESS(RtlAppendUnicodeToString(&ObjectName, DRIVER_ROOT_NAME))); 1328c904983bSThomas Faber NT_VERIFY(NT_SUCCESS(RtlAppendUnicodeStringToString(&ObjectName, &ServiceName))); 1329c2c66affSColin Finck 1330c2c66affSColin Finck /* 1331c2c66affSColin Finck * Find the driver object 1332c2c66affSColin Finck */ 1333c2c66affSColin Finck Status = ObReferenceObjectByName(&ObjectName, 1334c2c66affSColin Finck 0, 1335c2c66affSColin Finck 0, 1336c2c66affSColin Finck 0, 1337c2c66affSColin Finck IoDriverObjectType, 1338c2c66affSColin Finck KernelMode, 1339c2c66affSColin Finck 0, 1340c2c66affSColin Finck (PVOID*)&DriverObject); 1341c2c66affSColin Finck 1342c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1343c2c66affSColin Finck { 1344c2c66affSColin Finck DPRINT1("Can't locate driver object for %wZ\n", &ObjectName); 1345c2c66affSColin Finck ExFreePoolWithTag(ObjectName.Buffer, TAG_IO); 1346daf9743cSPierre Schweitzer ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1347c2c66affSColin Finck return Status; 1348c2c66affSColin Finck } 1349c2c66affSColin Finck 1350c2c66affSColin Finck /* Free the buffer for driver object name */ 1351c2c66affSColin Finck ExFreePoolWithTag(ObjectName.Buffer, TAG_IO); 1352c2c66affSColin Finck 1353c2c66affSColin Finck /* Check that driver is not already unloading */ 1354c2c66affSColin Finck if (DriverObject->Flags & DRVO_UNLOAD_INVOKED) 1355c2c66affSColin Finck { 1356c2c66affSColin Finck DPRINT1("Driver deletion pending\n"); 1357c2c66affSColin Finck ObDereferenceObject(DriverObject); 1358daf9743cSPierre Schweitzer ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1359c2c66affSColin Finck return STATUS_DELETE_PENDING; 1360c2c66affSColin Finck } 1361c2c66affSColin Finck 1362c2c66affSColin Finck /* 1363c2c66affSColin Finck * Get path of service... 1364c2c66affSColin Finck */ 1365c2c66affSColin Finck RtlZeroMemory(QueryTable, sizeof(QueryTable)); 1366c2c66affSColin Finck 1367c2c66affSColin Finck RtlInitUnicodeString(&ImagePath, NULL); 1368c2c66affSColin Finck 1369c2c66affSColin Finck QueryTable[0].Name = L"ImagePath"; 1370c2c66affSColin Finck QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 1371c2c66affSColin Finck QueryTable[0].EntryContext = &ImagePath; 1372c2c66affSColin Finck 1373c2c66affSColin Finck Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 1374daf9743cSPierre Schweitzer CapturedServiceName.Buffer, 1375c2c66affSColin Finck QueryTable, 1376c2c66affSColin Finck NULL, 1377c2c66affSColin Finck NULL); 1378c2c66affSColin Finck 1379daf9743cSPierre Schweitzer /* We no longer need service name */ 1380daf9743cSPierre Schweitzer ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1381daf9743cSPierre Schweitzer 1382c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1383c2c66affSColin Finck { 1384c2c66affSColin Finck DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status); 1385c2c66affSColin Finck ObDereferenceObject(DriverObject); 1386c2c66affSColin Finck return Status; 1387c2c66affSColin Finck } 1388c2c66affSColin Finck 1389c2c66affSColin Finck /* 1390c2c66affSColin Finck * Normalize the image path for all later processing. 1391c2c66affSColin Finck */ 1392c2c66affSColin Finck Status = IopNormalizeImagePath(&ImagePath, &ServiceName); 1393c2c66affSColin Finck 1394c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1395c2c66affSColin Finck { 1396c2c66affSColin Finck DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status); 1397c2c66affSColin Finck ObDereferenceObject(DriverObject); 1398c2c66affSColin Finck return Status; 1399c2c66affSColin Finck } 1400c2c66affSColin Finck 1401c2c66affSColin Finck /* Free the service path */ 1402c2c66affSColin Finck ExFreePool(ImagePath.Buffer); 1403c2c66affSColin Finck 1404c2c66affSColin Finck /* 1405c2c66affSColin Finck * Unload the module and release the references to the device object 1406c2c66affSColin Finck */ 1407c2c66affSColin Finck 1408c2c66affSColin Finck /* Call the load/unload routine, depending on current process */ 1409c2c66affSColin Finck if (DriverObject->DriverUnload && DriverObject->DriverSection && 1410c2c66affSColin Finck (UnloadPnpDrivers || (DriverObject->Flags & DRVO_LEGACY_DRIVER))) 1411c2c66affSColin Finck { 1412c2c66affSColin Finck /* Loop through each device object of the driver 1413c2c66affSColin Finck and set DOE_UNLOAD_PENDING flag */ 1414c2c66affSColin Finck DeviceObject = DriverObject->DeviceObject; 1415c2c66affSColin Finck while (DeviceObject) 1416c2c66affSColin Finck { 1417c2c66affSColin Finck /* Set the unload pending flag for the device */ 1418c2c66affSColin Finck DeviceExtension = IoGetDevObjExtension(DeviceObject); 1419c2c66affSColin Finck DeviceExtension->ExtensionFlags |= DOE_UNLOAD_PENDING; 1420c2c66affSColin Finck 1421c2c66affSColin Finck /* Make sure there are no attached devices or no reference counts */ 1422c2c66affSColin Finck if ((DeviceObject->ReferenceCount) || (DeviceObject->AttachedDevice)) 1423c2c66affSColin Finck { 1424c2c66affSColin Finck /* Not safe to unload */ 1425c2c66affSColin Finck DPRINT1("Drivers device object is referenced or has attached devices\n"); 1426c2c66affSColin Finck 1427c2c66affSColin Finck SafeToUnload = FALSE; 1428c2c66affSColin Finck } 1429c2c66affSColin Finck 1430c2c66affSColin Finck DeviceObject = DeviceObject->NextDevice; 1431c2c66affSColin Finck } 1432c2c66affSColin Finck 1433c2c66affSColin Finck /* If not safe to unload, then return success */ 1434c2c66affSColin Finck if (!SafeToUnload) 1435c2c66affSColin Finck { 1436c2c66affSColin Finck ObDereferenceObject(DriverObject); 1437c2c66affSColin Finck return STATUS_SUCCESS; 1438c2c66affSColin Finck } 1439c2c66affSColin Finck 1440c2c66affSColin Finck DPRINT1("Unloading driver '%wZ' (manual)\n", &DriverObject->DriverName); 1441c2c66affSColin Finck 1442c2c66affSColin Finck /* Set the unload invoked flag and call the unload routine */ 1443c2c66affSColin Finck DriverObject->Flags |= DRVO_UNLOAD_INVOKED; 1444a6a3aa0fSVictor Perevertkin Status = IopDoLoadUnloadDriver(NULL, &DriverObject); 1445c2c66affSColin Finck ASSERT(Status == STATUS_SUCCESS); 1446c2c66affSColin Finck 1447c2c66affSColin Finck /* Mark the driver object temporary, so it could be deleted later */ 1448c2c66affSColin Finck ObMakeTemporaryObject(DriverObject); 1449c2c66affSColin Finck 1450c2c66affSColin Finck /* Dereference it 2 times */ 1451c2c66affSColin Finck ObDereferenceObject(DriverObject); 1452c2c66affSColin Finck ObDereferenceObject(DriverObject); 1453c2c66affSColin Finck 1454c2c66affSColin Finck return Status; 1455c2c66affSColin Finck } 1456c2c66affSColin Finck else 1457c2c66affSColin Finck { 1458c2c66affSColin Finck DPRINT1("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject->DriverName); 1459c2c66affSColin Finck 1460c2c66affSColin Finck /* Dereference one time (refd inside this function) */ 1461c2c66affSColin Finck ObDereferenceObject(DriverObject); 1462c2c66affSColin Finck 1463c2c66affSColin Finck /* Return unloading failure */ 1464c2c66affSColin Finck return STATUS_INVALID_DEVICE_REQUEST; 1465c2c66affSColin Finck } 1466c2c66affSColin Finck } 1467c2c66affSColin Finck 1468c2c66affSColin Finck VOID 1469c2c66affSColin Finck NTAPI 1470c2c66affSColin Finck IopReinitializeDrivers(VOID) 1471c2c66affSColin Finck { 1472c2c66affSColin Finck PDRIVER_REINIT_ITEM ReinitItem; 1473c2c66affSColin Finck PLIST_ENTRY Entry; 1474c2c66affSColin Finck 1475c2c66affSColin Finck /* Get the first entry and start looping */ 1476c2c66affSColin Finck Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead, 1477c2c66affSColin Finck &DriverReinitListLock); 1478c2c66affSColin Finck while (Entry) 1479c2c66affSColin Finck { 1480c2c66affSColin Finck /* Get the item */ 1481c2c66affSColin Finck ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry); 1482c2c66affSColin Finck 1483c2c66affSColin Finck /* Increment reinitialization counter */ 1484c2c66affSColin Finck ReinitItem->DriverObject->DriverExtension->Count++; 1485c2c66affSColin Finck 1486c2c66affSColin Finck /* Remove the device object flag */ 1487c2c66affSColin Finck ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED; 1488c2c66affSColin Finck 1489c2c66affSColin Finck /* Call the routine */ 1490c2c66affSColin Finck ReinitItem->ReinitRoutine(ReinitItem->DriverObject, 1491c2c66affSColin Finck ReinitItem->Context, 1492c2c66affSColin Finck ReinitItem->DriverObject-> 1493c2c66affSColin Finck DriverExtension->Count); 1494c2c66affSColin Finck 1495c2c66affSColin Finck /* Free the entry */ 1496c2c66affSColin Finck ExFreePool(Entry); 1497c2c66affSColin Finck 1498c2c66affSColin Finck /* Move to the next one */ 1499c2c66affSColin Finck Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead, 1500c2c66affSColin Finck &DriverReinitListLock); 1501c2c66affSColin Finck } 1502c2c66affSColin Finck } 1503c2c66affSColin Finck 1504c2c66affSColin Finck VOID 1505c2c66affSColin Finck NTAPI 1506c2c66affSColin Finck IopReinitializeBootDrivers(VOID) 1507c2c66affSColin Finck { 1508c2c66affSColin Finck PDRIVER_REINIT_ITEM ReinitItem; 1509c2c66affSColin Finck PLIST_ENTRY Entry; 1510c2c66affSColin Finck 1511c2c66affSColin Finck /* Get the first entry and start looping */ 1512c2c66affSColin Finck Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead, 1513c2c66affSColin Finck &DriverBootReinitListLock); 1514c2c66affSColin Finck while (Entry) 1515c2c66affSColin Finck { 1516c2c66affSColin Finck /* Get the item */ 1517c2c66affSColin Finck ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry); 1518c2c66affSColin Finck 1519c2c66affSColin Finck /* Increment reinitialization counter */ 1520c2c66affSColin Finck ReinitItem->DriverObject->DriverExtension->Count++; 1521c2c66affSColin Finck 1522c2c66affSColin Finck /* Remove the device object flag */ 1523c2c66affSColin Finck ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED; 1524c2c66affSColin Finck 1525c2c66affSColin Finck /* Call the routine */ 1526c2c66affSColin Finck ReinitItem->ReinitRoutine(ReinitItem->DriverObject, 1527c2c66affSColin Finck ReinitItem->Context, 1528c2c66affSColin Finck ReinitItem->DriverObject-> 1529c2c66affSColin Finck DriverExtension->Count); 1530c2c66affSColin Finck 1531c2c66affSColin Finck /* Free the entry */ 1532c2c66affSColin Finck ExFreePool(Entry); 1533c2c66affSColin Finck 1534c2c66affSColin Finck /* Move to the next one */ 1535c2c66affSColin Finck Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead, 1536c2c66affSColin Finck &DriverBootReinitListLock); 1537c2c66affSColin Finck } 15382839c850SVictor Perevertkin 15392839c850SVictor Perevertkin /* Wait for all device actions being finished*/ 15402839c850SVictor Perevertkin KeWaitForSingleObject(&PiEnumerationFinished, Executive, KernelMode, FALSE, NULL); 1541c2c66affSColin Finck } 1542c2c66affSColin Finck 1543e18a32dfSVictor Perevertkin /* PUBLIC FUNCTIONS ***********************************************************/ 1544e18a32dfSVictor Perevertkin 1545e18a32dfSVictor Perevertkin /* 1546e18a32dfSVictor Perevertkin * @implemented 1547e18a32dfSVictor Perevertkin */ 1548c2c66affSColin Finck NTSTATUS 1549c2c66affSColin Finck NTAPI 1550e18a32dfSVictor Perevertkin IoCreateDriver( 1551e18a32dfSVictor Perevertkin _In_opt_ PUNICODE_STRING DriverName, 1552e18a32dfSVictor Perevertkin _In_ PDRIVER_INITIALIZE InitializationFunction) 1553c2c66affSColin Finck { 1554c2c66affSColin Finck WCHAR NameBuffer[100]; 1555c2c66affSColin Finck USHORT NameLength; 1556c2c66affSColin Finck UNICODE_STRING LocalDriverName; 1557c2c66affSColin Finck NTSTATUS Status; 1558c2c66affSColin Finck OBJECT_ATTRIBUTES ObjectAttributes; 1559c2c66affSColin Finck ULONG ObjectSize; 1560c2c66affSColin Finck PDRIVER_OBJECT DriverObject; 1561c2c66affSColin Finck UNICODE_STRING ServiceKeyName; 1562c2c66affSColin Finck HANDLE hDriver; 1563c2c66affSColin Finck ULONG i, RetryCount = 0; 1564c2c66affSColin Finck 1565c2c66affSColin Finck try_again: 1566c2c66affSColin Finck /* First, create a unique name for the driver if we don't have one */ 1567c2c66affSColin Finck if (!DriverName) 1568c2c66affSColin Finck { 1569c2c66affSColin Finck /* Create a random name and set up the string */ 1570c2c66affSColin Finck NameLength = (USHORT)swprintf(NameBuffer, 1571c2c66affSColin Finck DRIVER_ROOT_NAME L"%08u", 1572c2c66affSColin Finck KeTickCount.LowPart); 1573c2c66affSColin Finck LocalDriverName.Length = NameLength * sizeof(WCHAR); 1574c2c66affSColin Finck LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL); 1575c2c66affSColin Finck LocalDriverName.Buffer = NameBuffer; 1576c2c66affSColin Finck } 1577c2c66affSColin Finck else 1578c2c66affSColin Finck { 1579c2c66affSColin Finck /* So we can avoid another code path, use a local var */ 1580c2c66affSColin Finck LocalDriverName = *DriverName; 1581c2c66affSColin Finck } 1582c2c66affSColin Finck 1583c2c66affSColin Finck /* Initialize the Attributes */ 1584c2c66affSColin Finck ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION); 1585c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 1586c2c66affSColin Finck &LocalDriverName, 1587c2c66affSColin Finck OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 1588c2c66affSColin Finck NULL, 1589c2c66affSColin Finck NULL); 1590c2c66affSColin Finck 1591c2c66affSColin Finck /* Create the Object */ 1592c2c66affSColin Finck Status = ObCreateObject(KernelMode, 1593c2c66affSColin Finck IoDriverObjectType, 1594c2c66affSColin Finck &ObjectAttributes, 1595c2c66affSColin Finck KernelMode, 1596c2c66affSColin Finck NULL, 1597c2c66affSColin Finck ObjectSize, 1598c2c66affSColin Finck 0, 1599c2c66affSColin Finck 0, 1600c2c66affSColin Finck (PVOID*)&DriverObject); 1601c2c66affSColin Finck if (!NT_SUCCESS(Status)) return Status; 1602c2c66affSColin Finck 1603c2c66affSColin Finck DPRINT("IopCreateDriver(): created DO %p\n", DriverObject); 1604c2c66affSColin Finck 1605c2c66affSColin Finck /* Set up the Object */ 1606c2c66affSColin Finck RtlZeroMemory(DriverObject, ObjectSize); 1607c2c66affSColin Finck DriverObject->Type = IO_TYPE_DRIVER; 1608c2c66affSColin Finck DriverObject->Size = sizeof(DRIVER_OBJECT); 160945012aa4SHermès Bélusca-Maïto DriverObject->Flags = DRVO_BUILTIN_DRIVER; 1610c2c66affSColin Finck DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1); 1611c2c66affSColin Finck DriverObject->DriverExtension->DriverObject = DriverObject; 1612c2c66affSColin Finck DriverObject->DriverInit = InitializationFunction; 1613c2c66affSColin Finck /* Loop all Major Functions */ 1614c2c66affSColin Finck for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) 1615c2c66affSColin Finck { 1616c2c66affSColin Finck /* Invalidate each function */ 1617c2c66affSColin Finck DriverObject->MajorFunction[i] = IopInvalidDeviceRequest; 1618c2c66affSColin Finck } 1619c2c66affSColin Finck 1620c2c66affSColin Finck /* Set up the service key name buffer */ 1621e18a32dfSVictor Perevertkin ServiceKeyName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL); 1622e18a32dfSVictor Perevertkin ServiceKeyName.Buffer = ExAllocatePoolWithTag(PagedPool, LocalDriverName.MaximumLength, TAG_IO); 1623c2c66affSColin Finck if (!ServiceKeyName.Buffer) 1624c2c66affSColin Finck { 1625c2c66affSColin Finck /* Fail */ 1626c2c66affSColin Finck ObMakeTemporaryObject(DriverObject); 1627c2c66affSColin Finck ObDereferenceObject(DriverObject); 1628c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 1629c2c66affSColin Finck } 1630c2c66affSColin Finck 1631e18a32dfSVictor Perevertkin /* For builtin drivers, the ServiceKeyName is equal to DriverName */ 1632e18a32dfSVictor Perevertkin RtlCopyUnicodeString(&ServiceKeyName, &LocalDriverName); 1633e18a32dfSVictor Perevertkin ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL; 1634c2c66affSColin Finck DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName; 1635c2c66affSColin Finck 1636c2c66affSColin Finck /* Make a copy of the driver name to store in the driver object */ 1637c2c66affSColin Finck DriverObject->DriverName.MaximumLength = LocalDriverName.Length; 1638c2c66affSColin Finck DriverObject->DriverName.Buffer = ExAllocatePoolWithTag(PagedPool, 1639c2c66affSColin Finck DriverObject->DriverName.MaximumLength, 1640c2c66affSColin Finck TAG_IO); 1641c2c66affSColin Finck if (!DriverObject->DriverName.Buffer) 1642c2c66affSColin Finck { 1643c2c66affSColin Finck /* Fail */ 1644c2c66affSColin Finck ObMakeTemporaryObject(DriverObject); 1645c2c66affSColin Finck ObDereferenceObject(DriverObject); 1646c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 1647c2c66affSColin Finck } 1648c2c66affSColin Finck 1649e18a32dfSVictor Perevertkin RtlCopyUnicodeString(&DriverObject->DriverName, &LocalDriverName); 1650c2c66affSColin Finck 1651c2c66affSColin Finck /* Add the Object and get its handle */ 1652c2c66affSColin Finck Status = ObInsertObject(DriverObject, 1653c2c66affSColin Finck NULL, 1654c2c66affSColin Finck FILE_READ_DATA, 1655c2c66affSColin Finck 0, 1656c2c66affSColin Finck NULL, 1657c2c66affSColin Finck &hDriver); 1658c2c66affSColin Finck 1659c2c66affSColin Finck /* Eliminate small possibility when this function is called more than 1660c2c66affSColin Finck once in a row, and KeTickCount doesn't get enough time to change */ 1661c2c66affSColin Finck if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100)) 1662c2c66affSColin Finck { 1663c2c66affSColin Finck RetryCount++; 1664c2c66affSColin Finck goto try_again; 1665c2c66affSColin Finck } 1666c2c66affSColin Finck 1667c2c66affSColin Finck if (!NT_SUCCESS(Status)) return Status; 1668c2c66affSColin Finck 1669c2c66affSColin Finck /* Now reference it */ 1670c2c66affSColin Finck Status = ObReferenceObjectByHandle(hDriver, 1671c2c66affSColin Finck 0, 1672c2c66affSColin Finck IoDriverObjectType, 1673c2c66affSColin Finck KernelMode, 1674c2c66affSColin Finck (PVOID*)&DriverObject, 1675c2c66affSColin Finck NULL); 1676c2c66affSColin Finck 1677c2c66affSColin Finck /* Close the extra handle */ 1678c2c66affSColin Finck ZwClose(hDriver); 1679c2c66affSColin Finck 1680c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1681c2c66affSColin Finck { 1682c2c66affSColin Finck /* Fail */ 1683c2c66affSColin Finck ObMakeTemporaryObject(DriverObject); 1684c2c66affSColin Finck ObDereferenceObject(DriverObject); 1685c2c66affSColin Finck return Status; 1686c2c66affSColin Finck } 1687c2c66affSColin Finck 1688c2c66affSColin Finck /* Finally, call its init function */ 1689c2c66affSColin Finck DPRINT("Calling driver entrypoint at %p\n", InitializationFunction); 1690a82ff90bSHermès Bélusca-Maïto Status = InitializationFunction(DriverObject, NULL); 1691c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1692c2c66affSColin Finck { 1693c2c66affSColin Finck /* If it didn't work, then kill the object */ 1694c2c66affSColin Finck DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status); 1695c2c66affSColin Finck ObMakeTemporaryObject(DriverObject); 1696c2c66affSColin Finck ObDereferenceObject(DriverObject); 1697c2c66affSColin Finck return Status; 1698c2c66affSColin Finck } 1699c2c66affSColin Finck 1700e18a32dfSVictor Perevertkin // Windows does this fixup - keep it for compatibility 1701c2c66affSColin Finck for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) 1702c2c66affSColin Finck { 1703c2c66affSColin Finck /* 1704c2c66affSColin Finck * Make sure the driver didn't set any dispatch entry point to NULL! 1705c2c66affSColin Finck * Doing so is illegal; drivers shouldn't touch entry points they 1706c2c66affSColin Finck * do not implement. 1707c2c66affSColin Finck */ 1708c2c66affSColin Finck 1709c2c66affSColin Finck /* Check if it did so anyway */ 1710c2c66affSColin Finck if (!DriverObject->MajorFunction[i]) 1711c2c66affSColin Finck { 1712c2c66affSColin Finck /* Print a warning in the debug log */ 1713c2c66affSColin Finck DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%lu] to NULL!\n", 1714c2c66affSColin Finck &DriverObject->DriverName, i); 1715c2c66affSColin Finck 1716c2c66affSColin Finck /* Fix it up */ 1717c2c66affSColin Finck DriverObject->MajorFunction[i] = IopInvalidDeviceRequest; 1718c2c66affSColin Finck } 1719c2c66affSColin Finck } 1720c2c66affSColin Finck 1721c2c66affSColin Finck /* Return the Status */ 1722c2c66affSColin Finck return Status; 1723c2c66affSColin Finck } 1724c2c66affSColin Finck 1725c2c66affSColin Finck /* 1726c2c66affSColin Finck * @implemented 1727c2c66affSColin Finck */ 1728c2c66affSColin Finck VOID 1729c2c66affSColin Finck NTAPI 1730c2c66affSColin Finck IoDeleteDriver(IN PDRIVER_OBJECT DriverObject) 1731c2c66affSColin Finck { 1732c2c66affSColin Finck /* Simply dereference the Object */ 1733c2c66affSColin Finck ObDereferenceObject(DriverObject); 1734c2c66affSColin Finck } 1735c2c66affSColin Finck 1736c2c66affSColin Finck /* 1737c2c66affSColin Finck * @implemented 1738c2c66affSColin Finck */ 1739c2c66affSColin Finck VOID 1740c2c66affSColin Finck NTAPI 1741c2c66affSColin Finck IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject, 1742c2c66affSColin Finck IN PDRIVER_REINITIALIZE ReinitRoutine, 1743c2c66affSColin Finck IN PVOID Context) 1744c2c66affSColin Finck { 1745c2c66affSColin Finck PDRIVER_REINIT_ITEM ReinitItem; 1746c2c66affSColin Finck 1747c2c66affSColin Finck /* Allocate the entry */ 1748c2c66affSColin Finck ReinitItem = ExAllocatePoolWithTag(NonPagedPool, 1749c2c66affSColin Finck sizeof(DRIVER_REINIT_ITEM), 1750c2c66affSColin Finck TAG_REINIT); 1751c2c66affSColin Finck if (!ReinitItem) return; 1752c2c66affSColin Finck 1753c2c66affSColin Finck /* Fill it out */ 1754c2c66affSColin Finck ReinitItem->DriverObject = DriverObject; 1755c2c66affSColin Finck ReinitItem->ReinitRoutine = ReinitRoutine; 1756c2c66affSColin Finck ReinitItem->Context = Context; 1757c2c66affSColin Finck 1758c2c66affSColin Finck /* Set the Driver Object flag and insert the entry into the list */ 1759c2c66affSColin Finck DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED; 1760c2c66affSColin Finck ExInterlockedInsertTailList(&DriverBootReinitListHead, 1761c2c66affSColin Finck &ReinitItem->ItemEntry, 1762c2c66affSColin Finck &DriverBootReinitListLock); 1763c2c66affSColin Finck } 1764c2c66affSColin Finck 1765c2c66affSColin Finck /* 1766c2c66affSColin Finck * @implemented 1767c2c66affSColin Finck */ 1768c2c66affSColin Finck VOID 1769c2c66affSColin Finck NTAPI 1770c2c66affSColin Finck IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject, 1771c2c66affSColin Finck IN PDRIVER_REINITIALIZE ReinitRoutine, 1772c2c66affSColin Finck IN PVOID Context) 1773c2c66affSColin Finck { 1774c2c66affSColin Finck PDRIVER_REINIT_ITEM ReinitItem; 1775c2c66affSColin Finck 1776c2c66affSColin Finck /* Allocate the entry */ 1777c2c66affSColin Finck ReinitItem = ExAllocatePoolWithTag(NonPagedPool, 1778c2c66affSColin Finck sizeof(DRIVER_REINIT_ITEM), 1779c2c66affSColin Finck TAG_REINIT); 1780c2c66affSColin Finck if (!ReinitItem) return; 1781c2c66affSColin Finck 1782c2c66affSColin Finck /* Fill it out */ 1783c2c66affSColin Finck ReinitItem->DriverObject = DriverObject; 1784c2c66affSColin Finck ReinitItem->ReinitRoutine = ReinitRoutine; 1785c2c66affSColin Finck ReinitItem->Context = Context; 1786c2c66affSColin Finck 1787c2c66affSColin Finck /* Set the Driver Object flag and insert the entry into the list */ 1788c2c66affSColin Finck DriverObject->Flags |= DRVO_REINIT_REGISTERED; 1789c2c66affSColin Finck ExInterlockedInsertTailList(&DriverReinitListHead, 1790c2c66affSColin Finck &ReinitItem->ItemEntry, 1791c2c66affSColin Finck &DriverReinitListLock); 1792c2c66affSColin Finck } 1793c2c66affSColin Finck 1794c2c66affSColin Finck /* 1795c2c66affSColin Finck * @implemented 1796c2c66affSColin Finck */ 1797c2c66affSColin Finck NTSTATUS 1798c2c66affSColin Finck NTAPI 1799c2c66affSColin Finck IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject, 1800c2c66affSColin Finck IN PVOID ClientIdentificationAddress, 1801c2c66affSColin Finck IN ULONG DriverObjectExtensionSize, 1802c2c66affSColin Finck OUT PVOID *DriverObjectExtension) 1803c2c66affSColin Finck { 1804c2c66affSColin Finck KIRQL OldIrql; 1805c2c66affSColin Finck PIO_CLIENT_EXTENSION DriverExtensions, NewDriverExtension; 1806c2c66affSColin Finck BOOLEAN Inserted = FALSE; 1807c2c66affSColin Finck 1808c2c66affSColin Finck /* Assume failure */ 1809c2c66affSColin Finck *DriverObjectExtension = NULL; 1810c2c66affSColin Finck 1811c2c66affSColin Finck /* Allocate the extension */ 1812c2c66affSColin Finck NewDriverExtension = ExAllocatePoolWithTag(NonPagedPool, 1813c2c66affSColin Finck sizeof(IO_CLIENT_EXTENSION) + 1814c2c66affSColin Finck DriverObjectExtensionSize, 1815c2c66affSColin Finck TAG_DRIVER_EXTENSION); 1816c2c66affSColin Finck if (!NewDriverExtension) return STATUS_INSUFFICIENT_RESOURCES; 1817c2c66affSColin Finck 1818c2c66affSColin Finck /* Clear the extension for teh caller */ 1819c2c66affSColin Finck RtlZeroMemory(NewDriverExtension, 1820c2c66affSColin Finck sizeof(IO_CLIENT_EXTENSION) + DriverObjectExtensionSize); 1821c2c66affSColin Finck 1822c2c66affSColin Finck /* Acqure lock */ 1823c2c66affSColin Finck OldIrql = KeRaiseIrqlToDpcLevel(); 1824c2c66affSColin Finck 1825c2c66affSColin Finck /* Fill out the extension */ 1826c2c66affSColin Finck NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress; 1827c2c66affSColin Finck 1828c2c66affSColin Finck /* Loop the current extensions */ 1829c2c66affSColin Finck DriverExtensions = IoGetDrvObjExtension(DriverObject)-> 1830c2c66affSColin Finck ClientDriverExtension; 1831c2c66affSColin Finck while (DriverExtensions) 1832c2c66affSColin Finck { 1833c2c66affSColin Finck /* Check if the identifier matches */ 1834c2c66affSColin Finck if (DriverExtensions->ClientIdentificationAddress == 1835c2c66affSColin Finck ClientIdentificationAddress) 1836c2c66affSColin Finck { 1837c2c66affSColin Finck /* We have a collision, break out */ 1838c2c66affSColin Finck break; 1839c2c66affSColin Finck } 1840c2c66affSColin Finck 1841c2c66affSColin Finck /* Go to the next one */ 1842c2c66affSColin Finck DriverExtensions = DriverExtensions->NextExtension; 1843c2c66affSColin Finck } 1844c2c66affSColin Finck 1845c2c66affSColin Finck /* Check if we didn't collide */ 1846c2c66affSColin Finck if (!DriverExtensions) 1847c2c66affSColin Finck { 1848c2c66affSColin Finck /* Link this one in */ 1849c2c66affSColin Finck NewDriverExtension->NextExtension = 1850c2c66affSColin Finck IoGetDrvObjExtension(DriverObject)->ClientDriverExtension; 1851c2c66affSColin Finck IoGetDrvObjExtension(DriverObject)->ClientDriverExtension = 1852c2c66affSColin Finck NewDriverExtension; 1853c2c66affSColin Finck Inserted = TRUE; 1854c2c66affSColin Finck } 1855c2c66affSColin Finck 1856c2c66affSColin Finck /* Release the lock */ 1857c2c66affSColin Finck KeLowerIrql(OldIrql); 1858c2c66affSColin Finck 1859c2c66affSColin Finck /* Check if insertion failed */ 1860c2c66affSColin Finck if (!Inserted) 1861c2c66affSColin Finck { 1862c2c66affSColin Finck /* Free the entry and fail */ 1863c2c66affSColin Finck ExFreePoolWithTag(NewDriverExtension, TAG_DRIVER_EXTENSION); 1864c2c66affSColin Finck return STATUS_OBJECT_NAME_COLLISION; 1865c2c66affSColin Finck } 1866c2c66affSColin Finck 1867c2c66affSColin Finck /* Otherwise, return the pointer */ 1868c2c66affSColin Finck *DriverObjectExtension = NewDriverExtension + 1; 1869c2c66affSColin Finck return STATUS_SUCCESS; 1870c2c66affSColin Finck } 1871c2c66affSColin Finck 1872c2c66affSColin Finck /* 1873c2c66affSColin Finck * @implemented 1874c2c66affSColin Finck */ 1875c2c66affSColin Finck PVOID 1876c2c66affSColin Finck NTAPI 1877c2c66affSColin Finck IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject, 1878c2c66affSColin Finck IN PVOID ClientIdentificationAddress) 1879c2c66affSColin Finck { 1880c2c66affSColin Finck KIRQL OldIrql; 1881c2c66affSColin Finck PIO_CLIENT_EXTENSION DriverExtensions; 1882c2c66affSColin Finck 1883c2c66affSColin Finck /* Acquire lock */ 1884c2c66affSColin Finck OldIrql = KeRaiseIrqlToDpcLevel(); 1885c2c66affSColin Finck 1886c2c66affSColin Finck /* Loop the list until we find the right one */ 1887c2c66affSColin Finck DriverExtensions = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension; 1888c2c66affSColin Finck while (DriverExtensions) 1889c2c66affSColin Finck { 1890c2c66affSColin Finck /* Check for a match */ 1891c2c66affSColin Finck if (DriverExtensions->ClientIdentificationAddress == 1892c2c66affSColin Finck ClientIdentificationAddress) 1893c2c66affSColin Finck { 1894c2c66affSColin Finck /* Break out */ 1895c2c66affSColin Finck break; 1896c2c66affSColin Finck } 1897c2c66affSColin Finck 1898c2c66affSColin Finck /* Keep looping */ 1899c2c66affSColin Finck DriverExtensions = DriverExtensions->NextExtension; 1900c2c66affSColin Finck } 1901c2c66affSColin Finck 1902c2c66affSColin Finck /* Release lock */ 1903c2c66affSColin Finck KeLowerIrql(OldIrql); 1904c2c66affSColin Finck 1905c2c66affSColin Finck /* Return nothing or the extension */ 1906c2c66affSColin Finck if (!DriverExtensions) return NULL; 1907c2c66affSColin Finck return DriverExtensions + 1; 1908c2c66affSColin Finck } 1909c2c66affSColin Finck 1910c2c66affSColin Finck NTSTATUS 1911a6a3aa0fSVictor Perevertkin IopLoadDriver( 19124c95339dSVictor Perevertkin _In_ HANDLE ServiceHandle, 19134c95339dSVictor Perevertkin _Out_ PDRIVER_OBJECT *DriverObject) 1914c2c66affSColin Finck { 1915c2c66affSColin Finck UNICODE_STRING ImagePath; 1916c2c66affSColin Finck NTSTATUS Status; 1917c2c66affSColin Finck PLDR_DATA_TABLE_ENTRY ModuleObject; 1918c2c66affSColin Finck PVOID BaseAddress; 1919c2c66affSColin Finck 19204c95339dSVictor Perevertkin PKEY_VALUE_FULL_INFORMATION kvInfo; 19214c95339dSVictor Perevertkin Status = IopGetRegistryValue(ServiceHandle, L"ImagePath", &kvInfo); 19224c95339dSVictor Perevertkin if (NT_SUCCESS(Status)) 1923c2c66affSColin Finck { 19244c95339dSVictor Perevertkin if (kvInfo->Type != REG_EXPAND_SZ || kvInfo->DataLength == 0) 1925c2c66affSColin Finck { 19264c95339dSVictor Perevertkin ExFreePool(kvInfo); 19274c95339dSVictor Perevertkin return STATUS_ILL_FORMED_SERVICE_ENTRY; 1928c2c66affSColin Finck } 1929c2c66affSColin Finck 1930a82ff90bSHermès Bélusca-Maïto ImagePath.Length = kvInfo->DataLength - sizeof(UNICODE_NULL); 1931a82ff90bSHermès Bélusca-Maïto ImagePath.MaximumLength = kvInfo->DataLength; 19324c95339dSVictor Perevertkin ImagePath.Buffer = ExAllocatePoolWithTag(PagedPool, ImagePath.MaximumLength, TAG_RTLREGISTRY); 19334c95339dSVictor Perevertkin if (!ImagePath.Buffer) 1934c2c66affSColin Finck { 19354c95339dSVictor Perevertkin ExFreePool(kvInfo); 19364c95339dSVictor Perevertkin return STATUS_INSUFFICIENT_RESOURCES; 19374c95339dSVictor Perevertkin } 19384c95339dSVictor Perevertkin 19394c95339dSVictor Perevertkin RtlMoveMemory(ImagePath.Buffer, 19404c95339dSVictor Perevertkin (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset), 19414c95339dSVictor Perevertkin ImagePath.Length); 19420d28f271SHermès Bélusca-Maïto ImagePath.Buffer[ImagePath.Length / sizeof(WCHAR)] = UNICODE_NULL; 19434c95339dSVictor Perevertkin ExFreePool(kvInfo); 19444c95339dSVictor Perevertkin } 19454c95339dSVictor Perevertkin else 19464c95339dSVictor Perevertkin { 1947c2c66affSColin Finck return Status; 1948c2c66affSColin Finck } 1949c2c66affSColin Finck 1950c2c66affSColin Finck /* 1951c2c66affSColin Finck * Normalize the image path for all later processing. 1952c2c66affSColin Finck */ 19534c95339dSVictor Perevertkin Status = IopNormalizeImagePath(&ImagePath, NULL); 1954c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1955c2c66affSColin Finck { 1956c2c66affSColin Finck DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status); 1957c2c66affSColin Finck return Status; 1958c2c66affSColin Finck } 1959c2c66affSColin Finck 1960c2c66affSColin Finck DPRINT("FullImagePath: '%wZ'\n", &ImagePath); 1961c2c66affSColin Finck 1962c2c66affSColin Finck KeEnterCriticalRegion(); 1963c2c66affSColin Finck ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE); 1964c2c66affSColin Finck 1965c2c66affSColin Finck /* 1966c2c66affSColin Finck * Load the driver module 1967c2c66affSColin Finck */ 1968c2c66affSColin Finck DPRINT("Loading module from %wZ\n", &ImagePath); 1969c2c66affSColin Finck Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress); 19704c95339dSVictor Perevertkin RtlFreeUnicodeString(&ImagePath); 19714c95339dSVictor Perevertkin 1972c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1973c2c66affSColin Finck { 1974c2c66affSColin Finck DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status); 1975c2c66affSColin Finck ExReleaseResourceLite(&IopDriverLoadResource); 1976c2c66affSColin Finck KeLeaveCriticalRegion(); 1977c2c66affSColin Finck return Status; 1978c2c66affSColin Finck } 1979c2c66affSColin Finck 19804c95339dSVictor Perevertkin // Display the loading message 19814c95339dSVictor Perevertkin ULONG infoLength; 19824c95339dSVictor Perevertkin Status = ZwQueryKey(ServiceHandle, KeyBasicInformation, NULL, 0, &infoLength); 19834c95339dSVictor Perevertkin if (Status == STATUS_BUFFER_TOO_SMALL) 19844c95339dSVictor Perevertkin { 19854c95339dSVictor Perevertkin PKEY_BASIC_INFORMATION servName = ExAllocatePoolWithTag(PagedPool, infoLength, TAG_IO); 19864c95339dSVictor Perevertkin if (servName) 19874c95339dSVictor Perevertkin { 19884c95339dSVictor Perevertkin Status = ZwQueryKey(ServiceHandle, 19894c95339dSVictor Perevertkin KeyBasicInformation, 19904c95339dSVictor Perevertkin servName, 19914c95339dSVictor Perevertkin infoLength, 19924c95339dSVictor Perevertkin &infoLength); 19934c95339dSVictor Perevertkin if (NT_SUCCESS(Status)) 19944c95339dSVictor Perevertkin { 19954c95339dSVictor Perevertkin UNICODE_STRING serviceName = { 19964c95339dSVictor Perevertkin .Length = servName->NameLength, 19974c95339dSVictor Perevertkin .MaximumLength = servName->NameLength, 19984c95339dSVictor Perevertkin .Buffer = servName->Name 19994c95339dSVictor Perevertkin }; 20004c95339dSVictor Perevertkin 20014c95339dSVictor Perevertkin IopDisplayLoadingMessage(&serviceName); 20024c95339dSVictor Perevertkin } 20034c95339dSVictor Perevertkin ExFreePoolWithTag(servName, TAG_IO); 20044c95339dSVictor Perevertkin } 20054c95339dSVictor Perevertkin } 2006c2c66affSColin Finck 2007e18a32dfSVictor Perevertkin NTSTATUS driverEntryStatus; 20086f0e37b0SVictor Perevertkin Status = IopInitializeDriverModule(ModuleObject, 20094c95339dSVictor Perevertkin ServiceHandle, 2010e18a32dfSVictor Perevertkin DriverObject, 2011e18a32dfSVictor Perevertkin &driverEntryStatus); 2012c2c66affSColin Finck if (!NT_SUCCESS(Status)) 2013c2c66affSColin Finck { 2014c2c66affSColin Finck DPRINT1("IopInitializeDriverModule() failed (Status %lx)\n", Status); 2015c2c66affSColin Finck } 2016c2c66affSColin Finck 2017c2c66affSColin Finck ExReleaseResourceLite(&IopDriverLoadResource); 2018c2c66affSColin Finck KeLeaveCriticalRegion(); 2019c2c66affSColin Finck 2020c2c66affSColin Finck return Status; 2021c2c66affSColin Finck } 2022c2c66affSColin Finck 2023a6a3aa0fSVictor Perevertkin static 2024a6a3aa0fSVictor Perevertkin VOID 2025a6a3aa0fSVictor Perevertkin NTAPI 2026a6a3aa0fSVictor Perevertkin IopLoadUnloadDriverWorker( 2027a6a3aa0fSVictor Perevertkin _Inout_ PVOID Parameter) 2028a6a3aa0fSVictor Perevertkin { 2029a6a3aa0fSVictor Perevertkin PLOAD_UNLOAD_PARAMS LoadParams = Parameter; 2030a6a3aa0fSVictor Perevertkin 2031a6a3aa0fSVictor Perevertkin ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess); 2032a6a3aa0fSVictor Perevertkin 2033a6a3aa0fSVictor Perevertkin if (LoadParams->DriverObject) 2034a6a3aa0fSVictor Perevertkin { 2035a6a3aa0fSVictor Perevertkin // unload request 2036a6a3aa0fSVictor Perevertkin LoadParams->DriverObject->DriverUnload(LoadParams->DriverObject); 2037a6a3aa0fSVictor Perevertkin LoadParams->Status = STATUS_SUCCESS; 2038a6a3aa0fSVictor Perevertkin } 2039a6a3aa0fSVictor Perevertkin else 2040a6a3aa0fSVictor Perevertkin { 2041a6a3aa0fSVictor Perevertkin // load request 20424c95339dSVictor Perevertkin HANDLE serviceHandle; 20434c95339dSVictor Perevertkin NTSTATUS status; 20444c95339dSVictor Perevertkin status = IopOpenRegistryKeyEx(&serviceHandle, NULL, LoadParams->RegistryPath, KEY_READ); 20454c95339dSVictor Perevertkin if (!NT_SUCCESS(status)) 20464c95339dSVictor Perevertkin { 20474c95339dSVictor Perevertkin LoadParams->Status = status; 20484c95339dSVictor Perevertkin } 20494c95339dSVictor Perevertkin else 20504c95339dSVictor Perevertkin { 20514c95339dSVictor Perevertkin LoadParams->Status = IopLoadDriver(serviceHandle, &LoadParams->DriverObject); 20524c95339dSVictor Perevertkin ZwClose(serviceHandle); 20534c95339dSVictor Perevertkin } 2054a6a3aa0fSVictor Perevertkin } 2055a6a3aa0fSVictor Perevertkin 2056a6a3aa0fSVictor Perevertkin if (LoadParams->SetEvent) 2057a6a3aa0fSVictor Perevertkin { 2058a6a3aa0fSVictor Perevertkin KeSetEvent(&LoadParams->Event, 0, FALSE); 2059a6a3aa0fSVictor Perevertkin } 2060a6a3aa0fSVictor Perevertkin } 2061a6a3aa0fSVictor Perevertkin 2062a6a3aa0fSVictor Perevertkin /** 2063a6a3aa0fSVictor Perevertkin * @brief Process load and unload driver operations. This is mostly for NtLoadDriver 2064a6a3aa0fSVictor Perevertkin * and NtUnloadDriver, because their code should run inside PsInitialSystemProcess 2065a6a3aa0fSVictor Perevertkin * 2066a6a3aa0fSVictor Perevertkin * @param[in] RegistryPath The registry path 2067a6a3aa0fSVictor Perevertkin * @param DriverObject The driver object 2068a6a3aa0fSVictor Perevertkin * 2069a6a3aa0fSVictor Perevertkin * @return Status of the operation 2070a6a3aa0fSVictor Perevertkin */ 2071a6a3aa0fSVictor Perevertkin NTSTATUS 2072a6a3aa0fSVictor Perevertkin IopDoLoadUnloadDriver( 20734c95339dSVictor Perevertkin _In_opt_ PUNICODE_STRING RegistryPath, 2074a6a3aa0fSVictor Perevertkin _Inout_ PDRIVER_OBJECT *DriverObject) 2075a6a3aa0fSVictor Perevertkin { 2076a6a3aa0fSVictor Perevertkin LOAD_UNLOAD_PARAMS LoadParams; 2077a6a3aa0fSVictor Perevertkin 2078a6a3aa0fSVictor Perevertkin /* Prepare parameters block */ 2079a6a3aa0fSVictor Perevertkin LoadParams.RegistryPath = RegistryPath; 2080a6a3aa0fSVictor Perevertkin LoadParams.DriverObject = *DriverObject; 2081a6a3aa0fSVictor Perevertkin 2082a6a3aa0fSVictor Perevertkin if (PsGetCurrentProcess() != PsInitialSystemProcess) 2083a6a3aa0fSVictor Perevertkin { 2084a6a3aa0fSVictor Perevertkin LoadParams.SetEvent = TRUE; 2085a6a3aa0fSVictor Perevertkin KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE); 2086a6a3aa0fSVictor Perevertkin 2087a6a3aa0fSVictor Perevertkin /* Initialize and queue a work item */ 2088a6a3aa0fSVictor Perevertkin ExInitializeWorkItem(&LoadParams.WorkItem, IopLoadUnloadDriverWorker, &LoadParams); 2089a6a3aa0fSVictor Perevertkin ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue); 2090a6a3aa0fSVictor Perevertkin 2091a6a3aa0fSVictor Perevertkin /* And wait till it completes */ 2092a6a3aa0fSVictor Perevertkin KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode, FALSE, NULL); 2093a6a3aa0fSVictor Perevertkin } 2094a6a3aa0fSVictor Perevertkin else 2095a6a3aa0fSVictor Perevertkin { 2096a6a3aa0fSVictor Perevertkin /* If we're already in a system process, call it right here */ 2097a6a3aa0fSVictor Perevertkin LoadParams.SetEvent = FALSE; 2098a6a3aa0fSVictor Perevertkin IopLoadUnloadDriverWorker(&LoadParams); 2099a6a3aa0fSVictor Perevertkin } 2100a6a3aa0fSVictor Perevertkin 2101a6a3aa0fSVictor Perevertkin return LoadParams.Status; 2102a6a3aa0fSVictor Perevertkin } 2103a6a3aa0fSVictor Perevertkin 2104c2c66affSColin Finck /* 2105c2c66affSColin Finck * NtLoadDriver 2106c2c66affSColin Finck * 2107c2c66affSColin Finck * Loads a device driver. 2108c2c66affSColin Finck * 2109c2c66affSColin Finck * Parameters 2110c2c66affSColin Finck * DriverServiceName 2111c2c66affSColin Finck * Name of the service to load (registry key). 2112c2c66affSColin Finck * 2113c2c66affSColin Finck * Return Value 2114c2c66affSColin Finck * Status 2115c2c66affSColin Finck * 2116c2c66affSColin Finck * Status 2117c2c66affSColin Finck * implemented 2118c2c66affSColin Finck */ 2119c2c66affSColin Finck NTSTATUS NTAPI 2120c2c66affSColin Finck NtLoadDriver(IN PUNICODE_STRING DriverServiceName) 2121c2c66affSColin Finck { 212244511f08SHermès Bélusca-Maïto UNICODE_STRING CapturedServiceName = { 0, 0, NULL }; 2123c2c66affSColin Finck KPROCESSOR_MODE PreviousMode; 2124c2c66affSColin Finck PDRIVER_OBJECT DriverObject; 2125c2c66affSColin Finck NTSTATUS Status; 2126c2c66affSColin Finck 2127c2c66affSColin Finck PAGED_CODE(); 2128c2c66affSColin Finck 2129c2c66affSColin Finck PreviousMode = KeGetPreviousMode(); 2130c2c66affSColin Finck 213144511f08SHermès Bélusca-Maïto /* Need the appropriate priviliege */ 2132c2c66affSColin Finck if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode)) 2133c2c66affSColin Finck { 213444511f08SHermès Bélusca-Maïto DPRINT1("No load privilege!\n"); 2135c2c66affSColin Finck return STATUS_PRIVILEGE_NOT_HELD; 2136c2c66affSColin Finck } 2137c2c66affSColin Finck 213844511f08SHermès Bélusca-Maïto /* Capture the service name */ 213944511f08SHermès Bélusca-Maïto Status = ProbeAndCaptureUnicodeString(&CapturedServiceName, 2140c2c66affSColin Finck PreviousMode, 2141c2c66affSColin Finck DriverServiceName); 2142c2c66affSColin Finck if (!NT_SUCCESS(Status)) 2143a6a3aa0fSVictor Perevertkin { 2144c2c66affSColin Finck return Status; 2145a6a3aa0fSVictor Perevertkin } 2146c2c66affSColin Finck 214744511f08SHermès Bélusca-Maïto DPRINT("NtLoadDriver('%wZ')\n", &CapturedServiceName); 2148c2c66affSColin Finck 2149a748350fSHermès Bélusca-Maïto /* We need a service name */ 2150a748350fSHermès Bélusca-Maïto if (CapturedServiceName.Length == 0 || CapturedServiceName.Buffer == NULL) 2151a748350fSHermès Bélusca-Maïto { 2152a748350fSHermès Bélusca-Maïto ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 2153a748350fSHermès Bélusca-Maïto return STATUS_INVALID_PARAMETER; 2154a748350fSHermès Bélusca-Maïto } 2155a748350fSHermès Bélusca-Maïto 2156c2c66affSColin Finck /* Load driver and call its entry point */ 2157c2c66affSColin Finck DriverObject = NULL; 2158a6a3aa0fSVictor Perevertkin Status = IopDoLoadUnloadDriver(&CapturedServiceName, &DriverObject); 2159c2c66affSColin Finck 216044511f08SHermès Bélusca-Maïto ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 2161c2c66affSColin Finck return Status; 2162c2c66affSColin Finck } 2163c2c66affSColin Finck 2164c2c66affSColin Finck /* 2165c2c66affSColin Finck * NtUnloadDriver 2166c2c66affSColin Finck * 2167c2c66affSColin Finck * Unloads a legacy device driver. 2168c2c66affSColin Finck * 2169c2c66affSColin Finck * Parameters 2170c2c66affSColin Finck * DriverServiceName 2171c2c66affSColin Finck * Name of the service to unload (registry key). 2172c2c66affSColin Finck * 2173c2c66affSColin Finck * Return Value 2174c2c66affSColin Finck * Status 2175c2c66affSColin Finck * 2176c2c66affSColin Finck * Status 2177c2c66affSColin Finck * implemented 2178c2c66affSColin Finck */ 2179c2c66affSColin Finck 2180c2c66affSColin Finck NTSTATUS NTAPI 2181c2c66affSColin Finck NtUnloadDriver(IN PUNICODE_STRING DriverServiceName) 2182c2c66affSColin Finck { 2183c2c66affSColin Finck return IopUnloadDriver(DriverServiceName, FALSE); 2184c2c66affSColin Finck } 2185c2c66affSColin Finck 2186c2c66affSColin Finck /* EOF */ 2187