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