1c2c66affSColin Finck /* 2c2c66affSColin Finck * PROJECT: ReactOS Kernel 3c2c66affSColin Finck * LICENSE: GPL - See COPYING in the top level directory 4c2c66affSColin Finck * FILE: ntoskrnl/io/iomgr/driver.c 5c2c66affSColin Finck * PURPOSE: Driver Object Management 6c2c66affSColin Finck * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7c2c66affSColin Finck * Filip Navara (navaraf@reactos.org) 8c2c66affSColin Finck * Herv� Poussineau (hpoussin@reactos.org) 9c2c66affSColin Finck */ 10c2c66affSColin Finck 11c2c66affSColin Finck /* INCLUDES *******************************************************************/ 12c2c66affSColin Finck 13c2c66affSColin Finck #include <ntoskrnl.h> 14c2c66affSColin Finck #define NDEBUG 15c2c66affSColin Finck #include <debug.h> 16c2c66affSColin Finck 17c2c66affSColin Finck /* GLOBALS ********************************************************************/ 18c2c66affSColin Finck 19c2c66affSColin Finck ERESOURCE IopDriverLoadResource; 20c2c66affSColin Finck 21c2c66affSColin Finck LIST_ENTRY DriverReinitListHead; 22c2c66affSColin Finck KSPIN_LOCK DriverReinitListLock; 23c2c66affSColin Finck PLIST_ENTRY DriverReinitTailEntry; 24c2c66affSColin Finck 25c2c66affSColin Finck PLIST_ENTRY DriverBootReinitTailEntry; 26c2c66affSColin Finck LIST_ENTRY DriverBootReinitListHead; 27c2c66affSColin Finck KSPIN_LOCK DriverBootReinitListLock; 28c2c66affSColin Finck 29c2c66affSColin Finck UNICODE_STRING IopHardwareDatabaseKey = 30c2c66affSColin Finck RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM"); 314c95339dSVictor Perevertkin static const WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"; 32c2c66affSColin Finck 33c2c66affSColin Finck POBJECT_TYPE IoDriverObjectType = NULL; 34c2c66affSColin Finck 35c2c66affSColin Finck #define TAG_RTLREGISTRY 'vrqR' 36c2c66affSColin Finck 37c2c66affSColin Finck extern BOOLEAN ExpInTextModeSetup; 38c2c66affSColin Finck extern BOOLEAN PnpSystemInit; 392839c850SVictor Perevertkin extern BOOLEAN PnPBootDriversLoaded; 402839c850SVictor Perevertkin extern KEVENT PiEnumerationFinished; 41c2c66affSColin Finck 42c2c66affSColin Finck USHORT IopGroupIndex; 43c2c66affSColin Finck PLIST_ENTRY IopGroupTable; 44c2c66affSColin Finck 45a6a3aa0fSVictor Perevertkin /* TYPES *********************************************************************/ 46a6a3aa0fSVictor Perevertkin 47a6a3aa0fSVictor Perevertkin // Parameters packet for Load/Unload work item's context 48a6a3aa0fSVictor Perevertkin typedef struct _LOAD_UNLOAD_PARAMS 49a6a3aa0fSVictor Perevertkin { 50a6a3aa0fSVictor Perevertkin NTSTATUS Status; 514c95339dSVictor Perevertkin PUNICODE_STRING RegistryPath; 52a6a3aa0fSVictor Perevertkin WORK_QUEUE_ITEM WorkItem; 53a6a3aa0fSVictor Perevertkin KEVENT Event; 54a6a3aa0fSVictor Perevertkin PDRIVER_OBJECT DriverObject; 55a6a3aa0fSVictor Perevertkin BOOLEAN SetEvent; 56a6a3aa0fSVictor Perevertkin } LOAD_UNLOAD_PARAMS, *PLOAD_UNLOAD_PARAMS; 57a6a3aa0fSVictor Perevertkin 58a6a3aa0fSVictor Perevertkin NTSTATUS 59a6a3aa0fSVictor Perevertkin IopDoLoadUnloadDriver( 604c95339dSVictor Perevertkin _In_opt_ PUNICODE_STRING RegistryPath, 61a6a3aa0fSVictor Perevertkin _Inout_ PDRIVER_OBJECT *DriverObject); 62a6a3aa0fSVictor Perevertkin 63c2c66affSColin Finck /* PRIVATE FUNCTIONS **********************************************************/ 64c2c66affSColin Finck 65c2c66affSColin Finck NTSTATUS 66c2c66affSColin Finck NTAPI 67c2c66affSColin Finck IopInvalidDeviceRequest( 68c2c66affSColin Finck PDEVICE_OBJECT DeviceObject, 69c2c66affSColin Finck PIRP Irp) 70c2c66affSColin Finck { 71c2c66affSColin Finck Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; 72c2c66affSColin Finck Irp->IoStatus.Information = 0; 73c2c66affSColin Finck IoCompleteRequest(Irp, IO_NO_INCREMENT); 74c2c66affSColin Finck return STATUS_INVALID_DEVICE_REQUEST; 75c2c66affSColin Finck } 76c2c66affSColin Finck 77c2c66affSColin Finck VOID 78c2c66affSColin Finck NTAPI 79c2c66affSColin Finck IopDeleteDriver(IN PVOID ObjectBody) 80c2c66affSColin Finck { 81c2c66affSColin Finck PDRIVER_OBJECT DriverObject = ObjectBody; 82c2c66affSColin Finck PIO_CLIENT_EXTENSION DriverExtension, NextDriverExtension; 83c2c66affSColin Finck PAGED_CODE(); 84c2c66affSColin Finck 85c2c66affSColin Finck DPRINT1("Deleting driver object '%wZ'\n", &DriverObject->DriverName); 86c2c66affSColin Finck 87c2c66affSColin Finck /* There must be no device objects remaining at this point */ 88c2c66affSColin Finck ASSERT(!DriverObject->DeviceObject); 89c2c66affSColin Finck 90c2c66affSColin Finck /* Get the extension and loop them */ 91c2c66affSColin Finck DriverExtension = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension; 92c2c66affSColin Finck while (DriverExtension) 93c2c66affSColin Finck { 94c2c66affSColin Finck /* Get the next one */ 95c2c66affSColin Finck NextDriverExtension = DriverExtension->NextExtension; 96c2c66affSColin Finck ExFreePoolWithTag(DriverExtension, TAG_DRIVER_EXTENSION); 97c2c66affSColin Finck 98c2c66affSColin Finck /* Move on */ 99c2c66affSColin Finck DriverExtension = NextDriverExtension; 100c2c66affSColin Finck } 101c2c66affSColin Finck 102c2c66affSColin Finck /* Check if the driver image is still loaded */ 103c2c66affSColin Finck if (DriverObject->DriverSection) 104c2c66affSColin Finck { 105c2c66affSColin Finck /* Unload it */ 106c2c66affSColin Finck MmUnloadSystemImage(DriverObject->DriverSection); 107c2c66affSColin Finck } 108c2c66affSColin Finck 109c2c66affSColin Finck /* Check if it has a name */ 110c2c66affSColin Finck if (DriverObject->DriverName.Buffer) 111c2c66affSColin Finck { 112c2c66affSColin Finck /* Free it */ 113c2c66affSColin Finck ExFreePool(DriverObject->DriverName.Buffer); 114c2c66affSColin Finck } 115c2c66affSColin Finck 116c2c66affSColin Finck /* Check if it has a service key name */ 117c2c66affSColin Finck if (DriverObject->DriverExtension->ServiceKeyName.Buffer) 118c2c66affSColin Finck { 119c2c66affSColin Finck /* Free it */ 120c2c66affSColin Finck ExFreePool(DriverObject->DriverExtension->ServiceKeyName.Buffer); 121c2c66affSColin Finck } 122c2c66affSColin Finck } 123c2c66affSColin Finck 124c2c66affSColin Finck NTSTATUS 125c4c0585fSVictor Perevertkin IopGetDriverNames( 126c4c0585fSVictor Perevertkin _In_ HANDLE ServiceHandle, 127c4c0585fSVictor Perevertkin _Out_ PUNICODE_STRING DriverName, 128c4c0585fSVictor Perevertkin _Out_opt_ PUNICODE_STRING ServiceName) 129c2c66affSColin Finck { 130c4c0585fSVictor Perevertkin UNICODE_STRING driverName = {.Buffer = NULL}, serviceName; 131c4c0585fSVictor Perevertkin PKEY_VALUE_FULL_INFORMATION kvInfo; 132c4c0585fSVictor Perevertkin NTSTATUS status; 133c2c66affSColin Finck 134c4c0585fSVictor Perevertkin PAGED_CODE(); 135c2c66affSColin Finck 136a82ff90bSHermès Bélusca-Maïto /* 1. Check the "ObjectName" field in the driver's registry key (it has priority) */ 137c4c0585fSVictor Perevertkin status = IopGetRegistryValue(ServiceHandle, L"ObjectName", &kvInfo); 138c4c0585fSVictor Perevertkin if (NT_SUCCESS(status)) 139c4c0585fSVictor Perevertkin { 140a82ff90bSHermès Bélusca-Maïto /* We've got the ObjectName, use it as the driver name */ 141c4c0585fSVictor Perevertkin if (kvInfo->Type != REG_SZ || kvInfo->DataLength == 0) 142c4c0585fSVictor Perevertkin { 143c4c0585fSVictor Perevertkin ExFreePool(kvInfo); 144c4c0585fSVictor Perevertkin return STATUS_ILL_FORMED_SERVICE_ENTRY; 145c4c0585fSVictor Perevertkin } 146c2c66affSColin Finck 1470d28f271SHermès Bélusca-Maïto driverName.Length = kvInfo->DataLength - sizeof(UNICODE_NULL); 148a82ff90bSHermès Bélusca-Maïto driverName.MaximumLength = kvInfo->DataLength; 149c4c0585fSVictor Perevertkin driverName.Buffer = ExAllocatePoolWithTag(NonPagedPool, driverName.MaximumLength, TAG_IO); 150c4c0585fSVictor Perevertkin if (!driverName.Buffer) 151c4c0585fSVictor Perevertkin { 152c4c0585fSVictor Perevertkin ExFreePool(kvInfo); 153c4c0585fSVictor Perevertkin return STATUS_INSUFFICIENT_RESOURCES; 154c4c0585fSVictor Perevertkin } 155c2c66affSColin Finck 156c4c0585fSVictor Perevertkin RtlMoveMemory(driverName.Buffer, 157c4c0585fSVictor Perevertkin (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset), 158c4c0585fSVictor Perevertkin driverName.Length); 1590d28f271SHermès Bélusca-Maïto driverName.Buffer[driverName.Length / sizeof(WCHAR)] = UNICODE_NULL; 160c4c0585fSVictor Perevertkin ExFreePool(kvInfo); 161c4c0585fSVictor Perevertkin } 162e1b20681SThomas Faber 163a82ff90bSHermès Bélusca-Maïto /* Check whether we need to get ServiceName as well, either to construct 164a82ff90bSHermès Bélusca-Maïto * the driver name (because we could not use "ObjectName"), or because 165a82ff90bSHermès Bélusca-Maïto * it is requested by the caller. */ 166*e09d1decSHermès Bélusca-Maïto PKEY_BASIC_INFORMATION basicInfo = NULL; 167c4c0585fSVictor Perevertkin if (!NT_SUCCESS(status) || ServiceName != NULL) 168c4c0585fSVictor Perevertkin { 169a82ff90bSHermès Bélusca-Maïto /* Retrieve the necessary buffer size */ 170c4c0585fSVictor Perevertkin ULONG infoLength; 171c4c0585fSVictor Perevertkin status = ZwQueryKey(ServiceHandle, KeyBasicInformation, NULL, 0, &infoLength); 172a82ff90bSHermès Bélusca-Maïto if (status != STATUS_BUFFER_TOO_SMALL) 173c4c0585fSVictor Perevertkin { 174a82ff90bSHermès Bélusca-Maïto return NT_SUCCESS(status) ? STATUS_UNSUCCESSFUL : status; 175a82ff90bSHermès Bélusca-Maïto } 176a82ff90bSHermès Bélusca-Maïto 177a82ff90bSHermès Bélusca-Maïto /* Allocate the buffer and retrieve the data */ 178c4c0585fSVictor Perevertkin basicInfo = ExAllocatePoolWithTag(PagedPool, infoLength, TAG_IO); 179c4c0585fSVictor Perevertkin if (!basicInfo) 180e1b20681SThomas Faber { 181e1b20681SThomas Faber return STATUS_INSUFFICIENT_RESOURCES; 182e1b20681SThomas Faber } 183c2c66affSColin Finck 184c4c0585fSVictor Perevertkin status = ZwQueryKey(ServiceHandle, KeyBasicInformation, basicInfo, infoLength, &infoLength); 185c4c0585fSVictor Perevertkin if (!NT_SUCCESS(status)) 186c2c66affSColin Finck { 187c4c0585fSVictor Perevertkin ExFreePoolWithTag(basicInfo, TAG_IO); 188c4c0585fSVictor Perevertkin return status; 189c2c66affSColin Finck } 190c2c66affSColin Finck 191c4c0585fSVictor Perevertkin serviceName.Length = basicInfo->NameLength; 192c4c0585fSVictor Perevertkin serviceName.MaximumLength = basicInfo->NameLength; 193c4c0585fSVictor Perevertkin serviceName.Buffer = basicInfo->Name; 194c4c0585fSVictor Perevertkin } 195c2c66affSColin Finck 196a82ff90bSHermès Bélusca-Maïto /* 2. There is no "ObjectName" - construct it ourselves. Depending on the driver type, 197a82ff90bSHermès Bélusca-Maïto * it will be either "\Driver\<ServiceName>" or "\FileSystem\<ServiceName>" */ 198c4c0585fSVictor Perevertkin if (driverName.Buffer == NULL) 199c4c0585fSVictor Perevertkin { 200*e09d1decSHermès Bélusca-Maïto ASSERT(basicInfo); // Container for serviceName 201*e09d1decSHermès Bélusca-Maïto 202a82ff90bSHermès Bélusca-Maïto /* Retrieve the driver type */ 203a82ff90bSHermès Bélusca-Maïto ULONG driverType; 204c4c0585fSVictor Perevertkin status = IopGetRegistryValue(ServiceHandle, L"Type", &kvInfo); 205aec3d9ccSVictor Perevertkin if (!NT_SUCCESS(status)) 206aec3d9ccSVictor Perevertkin { 207*e09d1decSHermès Bélusca-Maïto goto Cleanup; 208aec3d9ccSVictor Perevertkin } 2090d28f271SHermès Bélusca-Maïto if (kvInfo->Type != REG_DWORD || kvInfo->DataLength != sizeof(ULONG)) 210c4c0585fSVictor Perevertkin { 211c4c0585fSVictor Perevertkin ExFreePool(kvInfo); 212*e09d1decSHermès Bélusca-Maïto status = STATUS_ILL_FORMED_SERVICE_ENTRY; 213*e09d1decSHermès Bélusca-Maïto goto Cleanup; 214c4c0585fSVictor Perevertkin } 215a82ff90bSHermès Bélusca-Maïto driverType = *(PULONG)((ULONG_PTR)kvInfo + kvInfo->DataOffset); 216c4c0585fSVictor Perevertkin ExFreePool(kvInfo); 217c4c0585fSVictor Perevertkin 218a82ff90bSHermès Bélusca-Maïto /* Compute the necessary driver name string size */ 219c4c0585fSVictor Perevertkin if (driverType == SERVICE_RECOGNIZER_DRIVER || driverType == SERVICE_FILE_SYSTEM_DRIVER) 220a82ff90bSHermès Bélusca-Maïto driverName.MaximumLength = sizeof(FILESYSTEM_ROOT_NAME); 221c4c0585fSVictor Perevertkin else 222a82ff90bSHermès Bélusca-Maïto driverName.MaximumLength = sizeof(DRIVER_ROOT_NAME); 223a82ff90bSHermès Bélusca-Maïto 224a82ff90bSHermès Bélusca-Maïto driverName.MaximumLength += serviceName.Length; 225a82ff90bSHermès Bélusca-Maïto driverName.Length = 0; 226a82ff90bSHermès Bélusca-Maïto 227a82ff90bSHermès Bélusca-Maïto /* Allocate and build it */ 228c4c0585fSVictor Perevertkin driverName.Buffer = ExAllocatePoolWithTag(NonPagedPool, driverName.MaximumLength, TAG_IO); 229c4c0585fSVictor Perevertkin if (!driverName.Buffer) 230c4c0585fSVictor Perevertkin { 231*e09d1decSHermès Bélusca-Maïto status = STATUS_INSUFFICIENT_RESOURCES; 232*e09d1decSHermès Bélusca-Maïto goto Cleanup; 233c4c0585fSVictor Perevertkin } 234c4c0585fSVictor Perevertkin 235c4c0585fSVictor Perevertkin if (driverType == SERVICE_RECOGNIZER_DRIVER || driverType == SERVICE_FILE_SYSTEM_DRIVER) 236c4c0585fSVictor Perevertkin RtlAppendUnicodeToString(&driverName, FILESYSTEM_ROOT_NAME); 237c4c0585fSVictor Perevertkin else 238c4c0585fSVictor Perevertkin RtlAppendUnicodeToString(&driverName, DRIVER_ROOT_NAME); 239c4c0585fSVictor Perevertkin 240c4c0585fSVictor Perevertkin RtlAppendUnicodeStringToString(&driverName, &serviceName); 241c4c0585fSVictor Perevertkin } 242c4c0585fSVictor Perevertkin 243a82ff90bSHermès Bélusca-Maïto if (ServiceName != NULL) 244c4c0585fSVictor Perevertkin { 245*e09d1decSHermès Bélusca-Maïto ASSERT(basicInfo); // Container for serviceName 246*e09d1decSHermès Bélusca-Maïto 247a82ff90bSHermès Bélusca-Maïto /* Allocate a copy for the caller */ 248c4c0585fSVictor Perevertkin PWCHAR buf = ExAllocatePoolWithTag(PagedPool, serviceName.Length, TAG_IO); 249c4c0585fSVictor Perevertkin if (!buf) 250c4c0585fSVictor Perevertkin { 251c4c0585fSVictor Perevertkin ExFreePoolWithTag(driverName.Buffer, TAG_IO); 252*e09d1decSHermès Bélusca-Maïto status = STATUS_INSUFFICIENT_RESOURCES; 253*e09d1decSHermès Bélusca-Maïto goto Cleanup; 254c4c0585fSVictor Perevertkin } 255c4c0585fSVictor Perevertkin RtlMoveMemory(buf, serviceName.Buffer, serviceName.Length); 256c4c0585fSVictor Perevertkin ServiceName->MaximumLength = serviceName.Length; 257c4c0585fSVictor Perevertkin ServiceName->Length = serviceName.Length; 258c4c0585fSVictor Perevertkin ServiceName->Buffer = buf; 259c4c0585fSVictor Perevertkin } 260c4c0585fSVictor Perevertkin 261c4c0585fSVictor Perevertkin *DriverName = driverName; 262*e09d1decSHermès Bélusca-Maïto status = STATUS_SUCCESS; 263c2c66affSColin Finck 264*e09d1decSHermès Bélusca-Maïto Cleanup: 265*e09d1decSHermès Bélusca-Maïto if (basicInfo) 266*e09d1decSHermès Bélusca-Maïto ExFreePoolWithTag(basicInfo, TAG_IO); 267*e09d1decSHermès Bélusca-Maïto 268*e09d1decSHermès Bélusca-Maïto return status; 269c2c66affSColin Finck } 270c2c66affSColin Finck 271c2c66affSColin Finck /* 272c2c66affSColin Finck * RETURNS 273c2c66affSColin Finck * TRUE if String2 contains String1 as a suffix. 274c2c66affSColin Finck */ 275c2c66affSColin Finck BOOLEAN 276c2c66affSColin Finck NTAPI 277c2c66affSColin Finck IopSuffixUnicodeString( 278c2c66affSColin Finck IN PCUNICODE_STRING String1, 279c2c66affSColin Finck IN PCUNICODE_STRING String2) 280c2c66affSColin Finck { 281c2c66affSColin Finck PWCHAR pc1; 282c2c66affSColin Finck PWCHAR pc2; 283c2c66affSColin Finck ULONG Length; 284c2c66affSColin Finck 285c2c66affSColin Finck if (String2->Length < String1->Length) 286c2c66affSColin Finck return FALSE; 287c2c66affSColin Finck 288c2c66affSColin Finck Length = String1->Length / 2; 289c2c66affSColin Finck pc1 = String1->Buffer; 290c2c66affSColin Finck pc2 = &String2->Buffer[String2->Length / sizeof(WCHAR) - Length]; 291c2c66affSColin Finck 292c2c66affSColin Finck if (pc1 && pc2) 293c2c66affSColin Finck { 294c2c66affSColin Finck while (Length--) 295c2c66affSColin Finck { 296c2c66affSColin Finck if( *pc1++ != *pc2++ ) 297c2c66affSColin Finck return FALSE; 298c2c66affSColin Finck } 299c2c66affSColin Finck return TRUE; 300c2c66affSColin Finck } 301c2c66affSColin Finck return FALSE; 302c2c66affSColin Finck } 303c2c66affSColin Finck 304c2c66affSColin Finck /* 305c2c66affSColin Finck * IopDisplayLoadingMessage 306c2c66affSColin Finck * 307c2c66affSColin Finck * Display 'Loading XXX...' message. 308c2c66affSColin Finck */ 309c2c66affSColin Finck VOID 310c2c66affSColin Finck FASTCALL 311c2c66affSColin Finck IopDisplayLoadingMessage(PUNICODE_STRING ServiceName) 312c2c66affSColin Finck { 313c2c66affSColin Finck CHAR TextBuffer[256]; 314c2c66affSColin Finck UNICODE_STRING DotSys = RTL_CONSTANT_STRING(L".SYS"); 315c2c66affSColin Finck 316c2c66affSColin Finck if (ExpInTextModeSetup) return; 317c2c66affSColin Finck if (!KeLoaderBlock) return; 318c2c66affSColin Finck RtlUpcaseUnicodeString(ServiceName, ServiceName, FALSE); 319c2c66affSColin Finck snprintf(TextBuffer, sizeof(TextBuffer), 320c2c66affSColin Finck "%s%sSystem32\\Drivers\\%wZ%s\r\n", 321c2c66affSColin Finck KeLoaderBlock->ArcBootDeviceName, 322c2c66affSColin Finck KeLoaderBlock->NtBootPathName, 323c2c66affSColin Finck ServiceName, 324c2c66affSColin Finck IopSuffixUnicodeString(&DotSys, ServiceName) ? "" : ".SYS"); 325c2c66affSColin Finck HalDisplayString(TextBuffer); 326c2c66affSColin Finck } 327c2c66affSColin Finck 328c2c66affSColin Finck /* 329c2c66affSColin Finck * IopNormalizeImagePath 330c2c66affSColin Finck * 331c2c66affSColin Finck * Normalize an image path to contain complete path. 332c2c66affSColin Finck * 333c2c66affSColin Finck * Parameters 334c2c66affSColin Finck * ImagePath 335c2c66affSColin Finck * The input path and on exit the result path. ImagePath.Buffer 336c2c66affSColin Finck * must be allocated by ExAllocatePool on input. Caller is responsible 337c2c66affSColin Finck * for freeing the buffer when it's no longer needed. 338c2c66affSColin Finck * 339c2c66affSColin Finck * ServiceName 340c2c66affSColin Finck * Name of the service that ImagePath belongs to. 341c2c66affSColin Finck * 342c2c66affSColin Finck * Return Value 343c2c66affSColin Finck * Status 344c2c66affSColin Finck * 345c2c66affSColin Finck * Remarks 346c2c66affSColin Finck * The input image path isn't freed on error. 347c2c66affSColin Finck */ 348c2c66affSColin Finck NTSTATUS 349c2c66affSColin Finck FASTCALL 350c2c66affSColin Finck IopNormalizeImagePath( 351c2c66affSColin Finck _Inout_ _When_(return>=0, _At_(ImagePath->Buffer, _Post_notnull_ __drv_allocatesMem(Mem))) 352c2c66affSColin Finck PUNICODE_STRING ImagePath, 353c2c66affSColin Finck _In_ PUNICODE_STRING ServiceName) 354c2c66affSColin Finck { 355c2c66affSColin Finck UNICODE_STRING SystemRootString = RTL_CONSTANT_STRING(L"\\SystemRoot\\"); 356c2c66affSColin Finck UNICODE_STRING DriversPathString = RTL_CONSTANT_STRING(L"\\SystemRoot\\System32\\drivers\\"); 357c2c66affSColin Finck UNICODE_STRING DotSysString = RTL_CONSTANT_STRING(L".sys"); 358c2c66affSColin Finck UNICODE_STRING InputImagePath; 359c2c66affSColin Finck 360c2c66affSColin Finck DPRINT("Normalizing image path '%wZ' for service '%wZ'\n", ImagePath, ServiceName); 361c2c66affSColin Finck 362c2c66affSColin Finck InputImagePath = *ImagePath; 363c2c66affSColin Finck if (InputImagePath.Length == 0) 364c2c66affSColin Finck { 365c2c66affSColin Finck ImagePath->Length = 0; 366c2c66affSColin Finck ImagePath->MaximumLength = DriversPathString.Length + 367c2c66affSColin Finck ServiceName->Length + 368c2c66affSColin Finck DotSysString.Length + 369c2c66affSColin Finck sizeof(UNICODE_NULL); 370c2c66affSColin Finck ImagePath->Buffer = ExAllocatePoolWithTag(NonPagedPool, 371c2c66affSColin Finck ImagePath->MaximumLength, 372c2c66affSColin Finck TAG_IO); 373c2c66affSColin Finck if (ImagePath->Buffer == NULL) 374c2c66affSColin Finck return STATUS_NO_MEMORY; 375c2c66affSColin Finck 376c2c66affSColin Finck RtlCopyUnicodeString(ImagePath, &DriversPathString); 377c2c66affSColin Finck RtlAppendUnicodeStringToString(ImagePath, ServiceName); 378c2c66affSColin Finck RtlAppendUnicodeStringToString(ImagePath, &DotSysString); 379c2c66affSColin Finck } 380c2c66affSColin Finck else if (InputImagePath.Buffer[0] != L'\\') 381c2c66affSColin Finck { 382c2c66affSColin Finck ImagePath->Length = 0; 383c2c66affSColin Finck ImagePath->MaximumLength = SystemRootString.Length + 384c2c66affSColin Finck InputImagePath.Length + 385c2c66affSColin Finck sizeof(UNICODE_NULL); 386c2c66affSColin Finck ImagePath->Buffer = ExAllocatePoolWithTag(NonPagedPool, 387c2c66affSColin Finck ImagePath->MaximumLength, 388c2c66affSColin Finck TAG_IO); 389c2c66affSColin Finck if (ImagePath->Buffer == NULL) 390c2c66affSColin Finck return STATUS_NO_MEMORY; 391c2c66affSColin Finck 392c2c66affSColin Finck RtlCopyUnicodeString(ImagePath, &SystemRootString); 393c2c66affSColin Finck RtlAppendUnicodeStringToString(ImagePath, &InputImagePath); 394c2c66affSColin Finck 395c2c66affSColin Finck /* Free caller's string */ 396c2c66affSColin Finck ExFreePoolWithTag(InputImagePath.Buffer, TAG_RTLREGISTRY); 397c2c66affSColin Finck } 398c2c66affSColin Finck 399c2c66affSColin Finck DPRINT("Normalized image path is '%wZ' for service '%wZ'\n", ImagePath, ServiceName); 400c2c66affSColin Finck 401c2c66affSColin Finck return STATUS_SUCCESS; 402c2c66affSColin Finck } 403c2c66affSColin Finck 404e18a32dfSVictor Perevertkin /** 405e18a32dfSVictor Perevertkin * @brief Initialize a loaded driver 406c2c66affSColin Finck * 407e18a32dfSVictor Perevertkin * @param[in] ModuleObject 408e18a32dfSVictor Perevertkin * Module object representing the driver. It can be retrieved by IopLoadServiceModule. 409e18a32dfSVictor Perevertkin * Freed on failure, so in a such case this should not be accessed anymore 410c2c66affSColin Finck * 4114c95339dSVictor Perevertkin * @param[in] ServiceHandle 4124c95339dSVictor Perevertkin * Handle to a driver's CCS/Services/<ServiceName> key 413c2c66affSColin Finck * 414e18a32dfSVictor Perevertkin * @param[out] DriverObject 415e18a32dfSVictor Perevertkin * This contains the driver object if it was created (even with unsuccessfull result) 416c2c66affSColin Finck * 417e18a32dfSVictor Perevertkin * @param[out] DriverEntryStatus 418e18a32dfSVictor Perevertkin * This contains the status value returned by the driver's DriverEntry routine 419e18a32dfSVictor Perevertkin * (will not be valid of the return value is not STATUS_SUCCESS or STATUS_FAILED_DRIVER_ENTRY) 420c2c66affSColin Finck * 421e18a32dfSVictor Perevertkin * @return Status of the operation 422c2c66affSColin Finck */ 423c2c66affSColin Finck NTSTATUS 424c2c66affSColin Finck IopInitializeDriverModule( 425e18a32dfSVictor Perevertkin _In_ PLDR_DATA_TABLE_ENTRY ModuleObject, 4264c95339dSVictor Perevertkin _In_ HANDLE ServiceHandle, 427e18a32dfSVictor Perevertkin _Out_ PDRIVER_OBJECT *OutDriverObject, 428e18a32dfSVictor Perevertkin _Out_ NTSTATUS *DriverEntryStatus) 429c2c66affSColin Finck { 4304c95339dSVictor Perevertkin UNICODE_STRING DriverName, RegistryPath, ServiceName; 431c2c66affSColin Finck NTSTATUS Status; 432c2c66affSColin Finck 433e18a32dfSVictor Perevertkin PAGED_CODE(); 434c2c66affSColin Finck 435c4c0585fSVictor Perevertkin Status = IopGetDriverNames(ServiceHandle, &DriverName, &ServiceName); 436e18a32dfSVictor Perevertkin if (!NT_SUCCESS(Status)) 437c2c66affSColin Finck { 438e18a32dfSVictor Perevertkin MmUnloadSystemImage(ModuleObject); 439e18a32dfSVictor Perevertkin return Status; 440e18a32dfSVictor Perevertkin } 441e18a32dfSVictor Perevertkin 442e18a32dfSVictor Perevertkin DPRINT("Driver name: '%wZ'\n", &DriverName); 443e18a32dfSVictor Perevertkin 444a82ff90bSHermès Bélusca-Maïto /* Obtain the registry path for the DriverInit routine */ 4454c95339dSVictor Perevertkin PKEY_NAME_INFORMATION nameInfo; 446c4c0585fSVictor Perevertkin ULONG infoLength; 4474c95339dSVictor Perevertkin Status = ZwQueryKey(ServiceHandle, KeyNameInformation, NULL, 0, &infoLength); 4484c95339dSVictor Perevertkin if (Status == STATUS_BUFFER_TOO_SMALL) 4494c95339dSVictor Perevertkin { 4504c95339dSVictor Perevertkin nameInfo = ExAllocatePoolWithTag(NonPagedPool, infoLength, TAG_IO); 4514c95339dSVictor Perevertkin if (nameInfo) 4524c95339dSVictor Perevertkin { 4534c95339dSVictor Perevertkin Status = ZwQueryKey(ServiceHandle, 4544c95339dSVictor Perevertkin KeyNameInformation, 4554c95339dSVictor Perevertkin nameInfo, 4564c95339dSVictor Perevertkin infoLength, 4574c95339dSVictor Perevertkin &infoLength); 4584c95339dSVictor Perevertkin if (NT_SUCCESS(Status)) 4594c95339dSVictor Perevertkin { 4604c95339dSVictor Perevertkin RegistryPath.Length = nameInfo->NameLength; 4614c95339dSVictor Perevertkin RegistryPath.MaximumLength = nameInfo->NameLength; 4624c95339dSVictor Perevertkin RegistryPath.Buffer = nameInfo->Name; 4634c95339dSVictor Perevertkin } 4644c95339dSVictor Perevertkin else 4654c95339dSVictor Perevertkin { 4664c95339dSVictor Perevertkin ExFreePoolWithTag(nameInfo, TAG_IO); 4674c95339dSVictor Perevertkin } 4684c95339dSVictor Perevertkin } 4694c95339dSVictor Perevertkin else 4704c95339dSVictor Perevertkin { 4714c95339dSVictor Perevertkin Status = STATUS_INSUFFICIENT_RESOURCES; 4724c95339dSVictor Perevertkin } 4734c95339dSVictor Perevertkin } 4744c95339dSVictor Perevertkin else 4754c95339dSVictor Perevertkin { 4764c95339dSVictor Perevertkin Status = NT_SUCCESS(Status) ? STATUS_UNSUCCESSFUL : Status; 4774c95339dSVictor Perevertkin } 4784c95339dSVictor Perevertkin 4794c95339dSVictor Perevertkin if (!NT_SUCCESS(Status)) 4804c95339dSVictor Perevertkin { 481c4c0585fSVictor Perevertkin RtlFreeUnicodeString(&ServiceName); 4824c95339dSVictor Perevertkin RtlFreeUnicodeString(&DriverName); 4834c95339dSVictor Perevertkin MmUnloadSystemImage(ModuleObject); 4844c95339dSVictor Perevertkin return Status; 4854c95339dSVictor Perevertkin } 4864c95339dSVictor Perevertkin 487a82ff90bSHermès Bélusca-Maïto /* Create the driver object */ 488a82ff90bSHermès Bélusca-Maïto ULONG ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION); 489e18a32dfSVictor Perevertkin OBJECT_ATTRIBUTES objAttrs; 490e18a32dfSVictor Perevertkin PDRIVER_OBJECT driverObject; 491e18a32dfSVictor Perevertkin InitializeObjectAttributes(&objAttrs, 492e18a32dfSVictor Perevertkin &DriverName, 493e18a32dfSVictor Perevertkin OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 494e18a32dfSVictor Perevertkin NULL, 495e18a32dfSVictor Perevertkin NULL); 496e18a32dfSVictor Perevertkin 497e18a32dfSVictor Perevertkin Status = ObCreateObject(KernelMode, 498e18a32dfSVictor Perevertkin IoDriverObjectType, 499e18a32dfSVictor Perevertkin &objAttrs, 500e18a32dfSVictor Perevertkin KernelMode, 501e18a32dfSVictor Perevertkin NULL, 502e18a32dfSVictor Perevertkin ObjectSize, 503e18a32dfSVictor Perevertkin 0, 504e18a32dfSVictor Perevertkin 0, 505e18a32dfSVictor Perevertkin (PVOID*)&driverObject); 506e18a32dfSVictor Perevertkin if (!NT_SUCCESS(Status)) 507e18a32dfSVictor Perevertkin { 5084c95339dSVictor Perevertkin ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath 509c4c0585fSVictor Perevertkin RtlFreeUnicodeString(&ServiceName); 510e18a32dfSVictor Perevertkin RtlFreeUnicodeString(&DriverName); 511e18a32dfSVictor Perevertkin MmUnloadSystemImage(ModuleObject); 512e18a32dfSVictor Perevertkin DPRINT1("Error while creating driver object \"%wZ\" status %x\n", &DriverName, Status); 513e18a32dfSVictor Perevertkin return Status; 514e18a32dfSVictor Perevertkin } 515e18a32dfSVictor Perevertkin 516e18a32dfSVictor Perevertkin DPRINT("Created driver object 0x%p for \"%wZ\"\n", driverObject, &DriverName); 517e18a32dfSVictor Perevertkin 518e18a32dfSVictor Perevertkin RtlZeroMemory(driverObject, ObjectSize); 519e18a32dfSVictor Perevertkin driverObject->Type = IO_TYPE_DRIVER; 520e18a32dfSVictor Perevertkin driverObject->Size = sizeof(DRIVER_OBJECT); 521e18a32dfSVictor Perevertkin driverObject->Flags = DRVO_LEGACY_DRIVER; // TODO: check the WDM_DRIVER flag on the module 522e18a32dfSVictor Perevertkin driverObject->DriverSection = ModuleObject; 523e18a32dfSVictor Perevertkin driverObject->DriverStart = ModuleObject->DllBase; 524e18a32dfSVictor Perevertkin driverObject->DriverSize = ModuleObject->SizeOfImage; 525e18a32dfSVictor Perevertkin driverObject->DriverInit = ModuleObject->EntryPoint; 526e18a32dfSVictor Perevertkin driverObject->HardwareDatabase = &IopHardwareDatabaseKey; 527e18a32dfSVictor Perevertkin driverObject->DriverExtension = (PDRIVER_EXTENSION)(driverObject + 1); 528e18a32dfSVictor Perevertkin driverObject->DriverExtension->DriverObject = driverObject; 529e18a32dfSVictor Perevertkin 530e18a32dfSVictor Perevertkin /* Loop all Major Functions */ 531e18a32dfSVictor Perevertkin for (INT i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) 532e18a32dfSVictor Perevertkin { 533e18a32dfSVictor Perevertkin /* Invalidate each function */ 534e18a32dfSVictor Perevertkin driverObject->MajorFunction[i] = IopInvalidDeviceRequest; 535e18a32dfSVictor Perevertkin } 536e18a32dfSVictor Perevertkin 537e18a32dfSVictor Perevertkin /* Add the Object and get its handle */ 538e18a32dfSVictor Perevertkin HANDLE hDriver; 539e18a32dfSVictor Perevertkin Status = ObInsertObject(driverObject, NULL, FILE_READ_DATA, 0, NULL, &hDriver); 540e18a32dfSVictor Perevertkin if (!NT_SUCCESS(Status)) 541e18a32dfSVictor Perevertkin { 5424c95339dSVictor Perevertkin ExFreePoolWithTag(nameInfo, TAG_IO); 543c4c0585fSVictor Perevertkin RtlFreeUnicodeString(&ServiceName); 544e18a32dfSVictor Perevertkin RtlFreeUnicodeString(&DriverName); 545e18a32dfSVictor Perevertkin return Status; 546e18a32dfSVictor Perevertkin } 547e18a32dfSVictor Perevertkin 548e18a32dfSVictor Perevertkin /* Now reference it */ 549e18a32dfSVictor Perevertkin Status = ObReferenceObjectByHandle(hDriver, 550e18a32dfSVictor Perevertkin 0, 551e18a32dfSVictor Perevertkin IoDriverObjectType, 552e18a32dfSVictor Perevertkin KernelMode, 553e18a32dfSVictor Perevertkin (PVOID*)&driverObject, 554e18a32dfSVictor Perevertkin NULL); 555e18a32dfSVictor Perevertkin 556e18a32dfSVictor Perevertkin /* Close the extra handle */ 557e18a32dfSVictor Perevertkin ZwClose(hDriver); 558e18a32dfSVictor Perevertkin 559e18a32dfSVictor Perevertkin if (!NT_SUCCESS(Status)) 560e18a32dfSVictor Perevertkin { 5614c95339dSVictor Perevertkin ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath 562c4c0585fSVictor Perevertkin RtlFreeUnicodeString(&ServiceName); 563e18a32dfSVictor Perevertkin RtlFreeUnicodeString(&DriverName); 564e18a32dfSVictor Perevertkin return Status; 565e18a32dfSVictor Perevertkin } 566e18a32dfSVictor Perevertkin 567e18a32dfSVictor Perevertkin /* Set up the service key name buffer */ 568e18a32dfSVictor Perevertkin UNICODE_STRING serviceKeyName; 569e18a32dfSVictor Perevertkin serviceKeyName.Length = 0; 570a82ff90bSHermès Bélusca-Maïto // NULL-terminate for Windows compatibility 5714c95339dSVictor Perevertkin serviceKeyName.MaximumLength = ServiceName.MaximumLength + sizeof(UNICODE_NULL); 572e18a32dfSVictor Perevertkin serviceKeyName.Buffer = ExAllocatePoolWithTag(NonPagedPool, 573e18a32dfSVictor Perevertkin serviceKeyName.MaximumLength, 574e18a32dfSVictor Perevertkin TAG_IO); 575e18a32dfSVictor Perevertkin if (!serviceKeyName.Buffer) 576e18a32dfSVictor Perevertkin { 577e18a32dfSVictor Perevertkin ObMakeTemporaryObject(driverObject); 578e18a32dfSVictor Perevertkin ObDereferenceObject(driverObject); 5794c95339dSVictor Perevertkin ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath 580c4c0585fSVictor Perevertkin RtlFreeUnicodeString(&ServiceName); 581e18a32dfSVictor Perevertkin RtlFreeUnicodeString(&DriverName); 582e18a32dfSVictor Perevertkin return STATUS_INSUFFICIENT_RESOURCES; 583e18a32dfSVictor Perevertkin } 584e18a32dfSVictor Perevertkin 585e18a32dfSVictor Perevertkin /* Copy the name and set it in the driver extension */ 5864c95339dSVictor Perevertkin RtlCopyUnicodeString(&serviceKeyName, &ServiceName); 587c4c0585fSVictor Perevertkin RtlFreeUnicodeString(&ServiceName); 588e18a32dfSVictor Perevertkin driverObject->DriverExtension->ServiceKeyName = serviceKeyName; 589e18a32dfSVictor Perevertkin 590e18a32dfSVictor Perevertkin /* Make a copy of the driver name to store in the driver object */ 591e18a32dfSVictor Perevertkin UNICODE_STRING driverNamePaged; 592e18a32dfSVictor Perevertkin driverNamePaged.Length = 0; 593a82ff90bSHermès Bélusca-Maïto // NULL-terminate for Windows compatibility 594e18a32dfSVictor Perevertkin driverNamePaged.MaximumLength = DriverName.MaximumLength + sizeof(UNICODE_NULL); 595e18a32dfSVictor Perevertkin driverNamePaged.Buffer = ExAllocatePoolWithTag(PagedPool, 596e18a32dfSVictor Perevertkin driverNamePaged.MaximumLength, 597e18a32dfSVictor Perevertkin TAG_IO); 598e18a32dfSVictor Perevertkin if (!driverNamePaged.Buffer) 599e18a32dfSVictor Perevertkin { 600e18a32dfSVictor Perevertkin ObMakeTemporaryObject(driverObject); 601e18a32dfSVictor Perevertkin ObDereferenceObject(driverObject); 6024c95339dSVictor Perevertkin ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath 603e18a32dfSVictor Perevertkin RtlFreeUnicodeString(&DriverName); 604e18a32dfSVictor Perevertkin return STATUS_INSUFFICIENT_RESOURCES; 605e18a32dfSVictor Perevertkin } 606e18a32dfSVictor Perevertkin 607e18a32dfSVictor Perevertkin RtlCopyUnicodeString(&driverNamePaged, &DriverName); 608e18a32dfSVictor Perevertkin driverObject->DriverName = driverNamePaged; 609e18a32dfSVictor Perevertkin 610e18a32dfSVictor Perevertkin /* Finally, call its init function */ 6114c95339dSVictor Perevertkin Status = driverObject->DriverInit(driverObject, &RegistryPath); 612e18a32dfSVictor Perevertkin *DriverEntryStatus = Status; 613e18a32dfSVictor Perevertkin if (!NT_SUCCESS(Status)) 614e18a32dfSVictor Perevertkin { 615e18a32dfSVictor Perevertkin DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", &DriverName, Status); 616e18a32dfSVictor Perevertkin // return a special status value in case of failure 617e18a32dfSVictor Perevertkin Status = STATUS_FAILED_DRIVER_ENTRY; 618e18a32dfSVictor Perevertkin } 619e18a32dfSVictor Perevertkin 620e18a32dfSVictor Perevertkin /* HACK: We're going to say if we don't have any DOs from DriverEntry, then we're not legacy. 621e18a32dfSVictor Perevertkin * Other parts of the I/O manager depend on this behavior */ 622e18a32dfSVictor Perevertkin if (!driverObject->DeviceObject) 623e18a32dfSVictor Perevertkin { 624e18a32dfSVictor Perevertkin driverObject->Flags &= ~DRVO_LEGACY_DRIVER; 625e18a32dfSVictor Perevertkin } 626e18a32dfSVictor Perevertkin 627e18a32dfSVictor Perevertkin // Windows does this fixup - keep it for compatibility 628e18a32dfSVictor Perevertkin for (INT i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) 629e18a32dfSVictor Perevertkin { 630e18a32dfSVictor Perevertkin /* 631e18a32dfSVictor Perevertkin * Make sure the driver didn't set any dispatch entry point to NULL! 632e18a32dfSVictor Perevertkin * Doing so is illegal; drivers shouldn't touch entry points they 633e18a32dfSVictor Perevertkin * do not implement. 634e18a32dfSVictor Perevertkin */ 635e18a32dfSVictor Perevertkin 636e18a32dfSVictor Perevertkin /* Check if it did so anyway */ 637e18a32dfSVictor Perevertkin if (!driverObject->MajorFunction[i]) 638e18a32dfSVictor Perevertkin { 639e18a32dfSVictor Perevertkin /* Print a warning in the debug log */ 640e18a32dfSVictor Perevertkin DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%lu] to NULL!\n", 641e18a32dfSVictor Perevertkin &driverObject->DriverName, i); 642e18a32dfSVictor Perevertkin 643e18a32dfSVictor Perevertkin /* Fix it up */ 644e18a32dfSVictor Perevertkin driverObject->MajorFunction[i] = IopInvalidDeviceRequest; 645e18a32dfSVictor Perevertkin } 646e18a32dfSVictor Perevertkin } 647e18a32dfSVictor Perevertkin 648e18a32dfSVictor Perevertkin // TODO: for legacy drivers, unload the driver if it didn't create any DO 649e18a32dfSVictor Perevertkin 6504c95339dSVictor Perevertkin ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath 651c2c66affSColin Finck RtlFreeUnicodeString(&DriverName); 652c2c66affSColin Finck 653c2c66affSColin Finck if (!NT_SUCCESS(Status)) 654c2c66affSColin Finck { 655e18a32dfSVictor Perevertkin // if the driver entry has been failed, clear the object 656e18a32dfSVictor Perevertkin ObMakeTemporaryObject(driverObject); 657e18a32dfSVictor Perevertkin ObDereferenceObject(driverObject); 658c2c66affSColin Finck return Status; 659c2c66affSColin Finck } 660c2c66affSColin Finck 661e18a32dfSVictor Perevertkin *OutDriverObject = driverObject; 662c2c66affSColin Finck 663e18a32dfSVictor Perevertkin MmFreeDriverInitialization((PLDR_DATA_TABLE_ENTRY)driverObject->DriverSection); 664c2c66affSColin Finck 665c2c66affSColin Finck /* Set the driver as initialized */ 666e18a32dfSVictor Perevertkin IopReadyDeviceObjects(driverObject); 667c2c66affSColin Finck 668c2c66affSColin Finck if (PnpSystemInit) IopReinitializeDrivers(); 669c2c66affSColin Finck 670c2c66affSColin Finck return STATUS_SUCCESS; 671c2c66affSColin Finck } 672c2c66affSColin Finck 673c2c66affSColin Finck NTSTATUS 674c2c66affSColin Finck NTAPI 675c2c66affSColin Finck MiResolveImageReferences(IN PVOID ImageBase, 676c2c66affSColin Finck IN PUNICODE_STRING ImageFileDirectory, 677c2c66affSColin Finck IN PUNICODE_STRING NamePrefix OPTIONAL, 678c2c66affSColin Finck OUT PCHAR *MissingApi, 679c2c66affSColin Finck OUT PWCHAR *MissingDriver, 680c2c66affSColin Finck OUT PLOAD_IMPORTS *LoadImports); 681c2c66affSColin Finck 682c2c66affSColin Finck // 683c2c66affSColin Finck // Used for images already loaded (boot drivers) 684c2c66affSColin Finck // 6855c7ce447SVictor Perevertkin CODE_SEG("INIT") 686c2c66affSColin Finck NTSTATUS 687c2c66affSColin Finck NTAPI 688c2c66affSColin Finck LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry, 689c2c66affSColin Finck PUNICODE_STRING FileName, 690c2c66affSColin Finck PLDR_DATA_TABLE_ENTRY *ModuleObject) 691c2c66affSColin Finck { 692c2c66affSColin Finck NTSTATUS Status; 693c2c66affSColin Finck UNICODE_STRING BaseName, BaseDirectory; 694c2c66affSColin Finck PLOAD_IMPORTS LoadedImports = (PVOID)-2; 695c2c66affSColin Finck PCHAR MissingApiName, Buffer; 696c2c66affSColin Finck PWCHAR MissingDriverName; 697c2c66affSColin Finck PVOID DriverBase = LdrEntry->DllBase; 698c2c66affSColin Finck 699c2c66affSColin Finck /* Allocate a buffer we'll use for names */ 700f3a280f5SThomas Faber Buffer = ExAllocatePoolWithTag(NonPagedPool, 701f3a280f5SThomas Faber MAXIMUM_FILENAME_LENGTH, 702f3a280f5SThomas Faber TAG_LDR_WSTR); 703c2c66affSColin Finck if (!Buffer) 704c2c66affSColin Finck { 705c2c66affSColin Finck /* Fail */ 706c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 707c2c66affSColin Finck } 708c2c66affSColin Finck 709c2c66affSColin Finck /* Check for a separator */ 710c2c66affSColin Finck if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) 711c2c66affSColin Finck { 712c2c66affSColin Finck PWCHAR p; 713c2c66affSColin Finck ULONG BaseLength; 714c2c66affSColin Finck 715c2c66affSColin Finck /* Loop the path until we get to the base name */ 716c2c66affSColin Finck p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)]; 717c2c66affSColin Finck while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--; 718c2c66affSColin Finck 719c2c66affSColin Finck /* Get the length */ 720c2c66affSColin Finck BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p); 721c2c66affSColin Finck BaseLength *= sizeof(WCHAR); 722c2c66affSColin Finck 723c2c66affSColin Finck /* Setup the string */ 724c2c66affSColin Finck BaseName.Length = (USHORT)BaseLength; 725c2c66affSColin Finck BaseName.Buffer = p; 726c2c66affSColin Finck } 727c2c66affSColin Finck else 728c2c66affSColin Finck { 729c2c66affSColin Finck /* Otherwise, we already have a base name */ 730c2c66affSColin Finck BaseName.Length = FileName->Length; 731c2c66affSColin Finck BaseName.Buffer = FileName->Buffer; 732c2c66affSColin Finck } 733c2c66affSColin Finck 734c2c66affSColin Finck /* Setup the maximum length */ 735c2c66affSColin Finck BaseName.MaximumLength = BaseName.Length; 736c2c66affSColin Finck 737c2c66affSColin Finck /* Now compute the base directory */ 738c2c66affSColin Finck BaseDirectory = *FileName; 739c2c66affSColin Finck BaseDirectory.Length -= BaseName.Length; 740c2c66affSColin Finck BaseDirectory.MaximumLength = BaseDirectory.Length; 741c2c66affSColin Finck 742c2c66affSColin Finck /* Resolve imports */ 743c2c66affSColin Finck MissingApiName = Buffer; 744c2c66affSColin Finck Status = MiResolveImageReferences(DriverBase, 745c2c66affSColin Finck &BaseDirectory, 746c2c66affSColin Finck NULL, 747c2c66affSColin Finck &MissingApiName, 748c2c66affSColin Finck &MissingDriverName, 749c2c66affSColin Finck &LoadedImports); 750c2c66affSColin Finck 751c2c66affSColin Finck /* Free the temporary buffer */ 752c2c66affSColin Finck ExFreePoolWithTag(Buffer, TAG_LDR_WSTR); 753c2c66affSColin Finck 754c2c66affSColin Finck /* Check the result of the imports resolution */ 755c2c66affSColin Finck if (!NT_SUCCESS(Status)) return Status; 756c2c66affSColin Finck 757c2c66affSColin Finck /* Return */ 758c2c66affSColin Finck *ModuleObject = LdrEntry; 759c2c66affSColin Finck return STATUS_SUCCESS; 760c2c66affSColin Finck } 761c2c66affSColin Finck 76291fceab3SVictor Perevertkin PDEVICE_OBJECT 76391fceab3SVictor Perevertkin IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance); 76491fceab3SVictor Perevertkin 765c2c66affSColin Finck /* 766c2c66affSColin Finck * IopInitializeBuiltinDriver 767c2c66affSColin Finck * 768c2c66affSColin Finck * Initialize a driver that is already loaded in memory. 769c2c66affSColin Finck */ 7705c7ce447SVictor Perevertkin CODE_SEG("INIT") 7713adf4508SJérôme Gardou static 77291fceab3SVictor Perevertkin BOOLEAN 773c2c66affSColin Finck IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY BootLdrEntry) 774c2c66affSColin Finck { 775c2c66affSColin Finck PDRIVER_OBJECT DriverObject; 776c2c66affSColin Finck NTSTATUS Status; 777c2c66affSColin Finck PWCHAR Buffer, FileNameWithoutPath; 778c2c66affSColin Finck PWSTR FileExtension; 779c2c66affSColin Finck PUNICODE_STRING ModuleName = &BootLdrEntry->BaseDllName; 780c2c66affSColin Finck PLDR_DATA_TABLE_ENTRY LdrEntry; 781c2c66affSColin Finck PLIST_ENTRY NextEntry; 782c2c66affSColin Finck UNICODE_STRING ServiceName; 783c2c66affSColin Finck BOOLEAN Success; 784c2c66affSColin Finck 785c2c66affSColin Finck /* 786c2c66affSColin Finck * Display 'Loading XXX...' message 787c2c66affSColin Finck */ 788c2c66affSColin Finck IopDisplayLoadingMessage(ModuleName); 789c2c66affSColin Finck InbvIndicateProgress(); 790c2c66affSColin Finck 791c2c66affSColin Finck Buffer = ExAllocatePoolWithTag(PagedPool, 792c2c66affSColin Finck ModuleName->Length + sizeof(UNICODE_NULL), 793c2c66affSColin Finck TAG_IO); 794c2c66affSColin Finck if (Buffer == NULL) 795c2c66affSColin Finck { 79691fceab3SVictor Perevertkin return FALSE; 797c2c66affSColin Finck } 798c2c66affSColin Finck 799c2c66affSColin Finck RtlCopyMemory(Buffer, ModuleName->Buffer, ModuleName->Length); 800c2c66affSColin Finck Buffer[ModuleName->Length / sizeof(WCHAR)] = UNICODE_NULL; 801c2c66affSColin Finck 802c2c66affSColin Finck /* 803c2c66affSColin Finck * Generate filename without path (not needed by freeldr) 804c2c66affSColin Finck */ 805c2c66affSColin Finck FileNameWithoutPath = wcsrchr(Buffer, L'\\'); 806c2c66affSColin Finck if (FileNameWithoutPath == NULL) 807c2c66affSColin Finck { 808c2c66affSColin Finck FileNameWithoutPath = Buffer; 809c2c66affSColin Finck } 810c2c66affSColin Finck else 811c2c66affSColin Finck { 812c2c66affSColin Finck FileNameWithoutPath++; 813c2c66affSColin Finck } 814c2c66affSColin Finck 815c2c66affSColin Finck /* 816c2c66affSColin Finck * Strip the file extension from ServiceName 817c2c66affSColin Finck */ 818c2c66affSColin Finck Success = RtlCreateUnicodeString(&ServiceName, FileNameWithoutPath); 819c2c66affSColin Finck ExFreePoolWithTag(Buffer, TAG_IO); 820c2c66affSColin Finck if (!Success) 821c2c66affSColin Finck { 82291fceab3SVictor Perevertkin return FALSE; 823c2c66affSColin Finck } 824c2c66affSColin Finck 825c2c66affSColin Finck FileExtension = wcsrchr(ServiceName.Buffer, L'.'); 826c2c66affSColin Finck if (FileExtension != NULL) 827c2c66affSColin Finck { 828c2c66affSColin Finck ServiceName.Length -= (USHORT)wcslen(FileExtension) * sizeof(WCHAR); 829c2c66affSColin Finck FileExtension[0] = UNICODE_NULL; 830c2c66affSColin Finck } 831c2c66affSColin Finck 8324c95339dSVictor Perevertkin UNICODE_STRING RegistryPath; 8334c95339dSVictor Perevertkin 8344c95339dSVictor Perevertkin // Make the registry path for the driver 8354c95339dSVictor Perevertkin RegistryPath.Length = 0; 8364c95339dSVictor Perevertkin RegistryPath.MaximumLength = sizeof(ServicesKeyName) + ServiceName.Length; 8374c95339dSVictor Perevertkin RegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool, RegistryPath.MaximumLength, TAG_IO); 8384c95339dSVictor Perevertkin if (RegistryPath.Buffer == NULL) 8394c95339dSVictor Perevertkin { 84091fceab3SVictor Perevertkin return FALSE; 8414c95339dSVictor Perevertkin } 8424c95339dSVictor Perevertkin RtlAppendUnicodeToString(&RegistryPath, ServicesKeyName); 8434c95339dSVictor Perevertkin RtlAppendUnicodeStringToString(&RegistryPath, &ServiceName); 8444c95339dSVictor Perevertkin RtlFreeUnicodeString(&ServiceName); 8454c95339dSVictor Perevertkin 8464c95339dSVictor Perevertkin HANDLE serviceHandle; 8474c95339dSVictor Perevertkin Status = IopOpenRegistryKeyEx(&serviceHandle, NULL, &RegistryPath, KEY_READ); 8484c95339dSVictor Perevertkin RtlFreeUnicodeString(&RegistryPath); 8494c95339dSVictor Perevertkin if (!NT_SUCCESS(Status)) 8504c95339dSVictor Perevertkin { 85191fceab3SVictor Perevertkin return FALSE; 8524c95339dSVictor Perevertkin } 8534c95339dSVictor Perevertkin 854c2c66affSColin Finck /* Lookup the new Ldr entry in PsLoadedModuleList */ 855a82ff90bSHermès Bélusca-Maïto for (NextEntry = PsLoadedModuleList.Flink; 856a82ff90bSHermès Bélusca-Maïto NextEntry != &PsLoadedModuleList; 857a82ff90bSHermès Bélusca-Maïto NextEntry = NextEntry->Flink) 858c2c66affSColin Finck { 859c2c66affSColin Finck LdrEntry = CONTAINING_RECORD(NextEntry, 860c2c66affSColin Finck LDR_DATA_TABLE_ENTRY, 861c2c66affSColin Finck InLoadOrderLinks); 862c2c66affSColin Finck if (RtlEqualUnicodeString(ModuleName, &LdrEntry->BaseDllName, TRUE)) 863c2c66affSColin Finck { 864c2c66affSColin Finck break; 865c2c66affSColin Finck } 866c2c66affSColin Finck } 867c2c66affSColin Finck ASSERT(NextEntry != &PsLoadedModuleList); 868c2c66affSColin Finck 869c2c66affSColin Finck /* 870c2c66affSColin Finck * Initialize the driver 871c2c66affSColin Finck */ 872e18a32dfSVictor Perevertkin NTSTATUS driverEntryStatus; 8736f0e37b0SVictor Perevertkin Status = IopInitializeDriverModule(LdrEntry, 8744c95339dSVictor Perevertkin serviceHandle, 875e18a32dfSVictor Perevertkin &DriverObject, 876e18a32dfSVictor Perevertkin &driverEntryStatus); 877c2c66affSColin Finck 878c2c66affSColin Finck if (!NT_SUCCESS(Status)) 879c2c66affSColin Finck { 8806f0e37b0SVictor Perevertkin DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status); 88191fceab3SVictor Perevertkin return FALSE; 882c2c66affSColin Finck } 883c2c66affSColin Finck 88491fceab3SVictor Perevertkin // The driver has been loaded, now check if where are any PDOs 88591fceab3SVictor Perevertkin // for that driver, and queue AddDevice call for them. 88691fceab3SVictor Perevertkin // The check is possible because HKLM/SYSTEM/CCS/Services/<ServiceName>/Enum directory 88791fceab3SVictor Perevertkin // is populated upon a new device arrival based on a (critical) device database 88891fceab3SVictor Perevertkin 88991fceab3SVictor Perevertkin // Legacy drivers may add devices inside DriverEntry. 89091fceab3SVictor Perevertkin // We're lazy and always assume that they are doing so 891a82ff90bSHermès Bélusca-Maïto BOOLEAN deviceAdded = !!(DriverObject->Flags & DRVO_LEGACY_DRIVER); 89291fceab3SVictor Perevertkin 89391fceab3SVictor Perevertkin HANDLE enumServiceHandle; 89491fceab3SVictor Perevertkin UNICODE_STRING enumName = RTL_CONSTANT_STRING(L"Enum"); 89591fceab3SVictor Perevertkin 89691fceab3SVictor Perevertkin Status = IopOpenRegistryKeyEx(&enumServiceHandle, serviceHandle, &enumName, KEY_READ); 89791fceab3SVictor Perevertkin ZwClose(serviceHandle); 89891fceab3SVictor Perevertkin 89991fceab3SVictor Perevertkin if (NT_SUCCESS(Status)) 90091fceab3SVictor Perevertkin { 901a82ff90bSHermès Bélusca-Maïto ULONG instanceCount = 0; 90291fceab3SVictor Perevertkin PKEY_VALUE_FULL_INFORMATION kvInfo; 90391fceab3SVictor Perevertkin Status = IopGetRegistryValue(enumServiceHandle, L"Count", &kvInfo); 90491fceab3SVictor Perevertkin if (!NT_SUCCESS(Status)) 90591fceab3SVictor Perevertkin { 90691fceab3SVictor Perevertkin goto Cleanup; 90791fceab3SVictor Perevertkin } 9080d28f271SHermès Bélusca-Maïto if (kvInfo->Type != REG_DWORD || kvInfo->DataLength != sizeof(ULONG)) 90991fceab3SVictor Perevertkin { 91091fceab3SVictor Perevertkin ExFreePool(kvInfo); 91191fceab3SVictor Perevertkin goto Cleanup; 91291fceab3SVictor Perevertkin } 913a82ff90bSHermès Bélusca-Maïto instanceCount = *(PULONG)((ULONG_PTR)kvInfo + kvInfo->DataOffset); 91491fceab3SVictor Perevertkin ExFreePool(kvInfo); 91591fceab3SVictor Perevertkin 91691fceab3SVictor Perevertkin DPRINT("Processing %u instances for %wZ module\n", instanceCount, ModuleName); 91791fceab3SVictor Perevertkin 918a82ff90bSHermès Bélusca-Maïto for (ULONG i = 0; i < instanceCount; i++) 91991fceab3SVictor Perevertkin { 92091fceab3SVictor Perevertkin WCHAR num[11]; 92191fceab3SVictor Perevertkin UNICODE_STRING instancePath; 92291fceab3SVictor Perevertkin RtlStringCchPrintfW(num, sizeof(num), L"%u", i); 92391fceab3SVictor Perevertkin 92491fceab3SVictor Perevertkin Status = IopGetRegistryValue(enumServiceHandle, num, &kvInfo); 92591fceab3SVictor Perevertkin if (!NT_SUCCESS(Status)) 92691fceab3SVictor Perevertkin { 92791fceab3SVictor Perevertkin continue; 92891fceab3SVictor Perevertkin } 92991fceab3SVictor Perevertkin if (kvInfo->Type != REG_SZ || kvInfo->DataLength == 0) 93091fceab3SVictor Perevertkin { 93191fceab3SVictor Perevertkin ExFreePool(kvInfo); 93291fceab3SVictor Perevertkin continue; 93391fceab3SVictor Perevertkin } 93491fceab3SVictor Perevertkin 9350d28f271SHermès Bélusca-Maïto instancePath.Length = kvInfo->DataLength - sizeof(UNICODE_NULL); 936a82ff90bSHermès Bélusca-Maïto instancePath.MaximumLength = kvInfo->DataLength; 93791fceab3SVictor Perevertkin instancePath.Buffer = ExAllocatePoolWithTag(NonPagedPool, 93891fceab3SVictor Perevertkin instancePath.MaximumLength, 93991fceab3SVictor Perevertkin TAG_IO); 94091fceab3SVictor Perevertkin if (instancePath.Buffer) 94191fceab3SVictor Perevertkin { 94291fceab3SVictor Perevertkin RtlMoveMemory(instancePath.Buffer, 94391fceab3SVictor Perevertkin (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset), 94491fceab3SVictor Perevertkin instancePath.Length); 9450d28f271SHermès Bélusca-Maïto instancePath.Buffer[instancePath.Length / sizeof(WCHAR)] = UNICODE_NULL; 94691fceab3SVictor Perevertkin 94791fceab3SVictor Perevertkin PDEVICE_OBJECT pdo = IopGetDeviceObjectFromDeviceInstance(&instancePath); 94891fceab3SVictor Perevertkin PiQueueDeviceAction(pdo, PiActionAddBootDevices, NULL, NULL); 94991fceab3SVictor Perevertkin ObDereferenceObject(pdo); 95091fceab3SVictor Perevertkin deviceAdded = TRUE; 95191fceab3SVictor Perevertkin } 95291fceab3SVictor Perevertkin 95391fceab3SVictor Perevertkin ExFreePool(kvInfo); 95491fceab3SVictor Perevertkin } 95591fceab3SVictor Perevertkin 95691fceab3SVictor Perevertkin ZwClose(enumServiceHandle); 95791fceab3SVictor Perevertkin } 95891fceab3SVictor Perevertkin Cleanup: 959c2c66affSColin Finck /* Remove extra reference from IopInitializeDriverModule */ 960c2c66affSColin Finck ObDereferenceObject(DriverObject); 961c2c66affSColin Finck 96291fceab3SVictor Perevertkin return deviceAdded; 963c2c66affSColin Finck } 964c2c66affSColin Finck 965c2c66affSColin Finck /* 966c2c66affSColin Finck * IopInitializeBootDrivers 967c2c66affSColin Finck * 968c2c66affSColin Finck * Initialize boot drivers and free memory for boot files. 969c2c66affSColin Finck * 970c2c66affSColin Finck * Parameters 971c2c66affSColin Finck * None 972c2c66affSColin Finck * 973c2c66affSColin Finck * Return Value 974c2c66affSColin Finck * None 975c2c66affSColin Finck */ 9765c7ce447SVictor Perevertkin CODE_SEG("INIT") 977c2c66affSColin Finck VOID 978c2c66affSColin Finck FASTCALL 979c2c66affSColin Finck IopInitializeBootDrivers(VOID) 980c2c66affSColin Finck { 981c2c66affSColin Finck PLIST_ENTRY ListHead, NextEntry, NextEntry2; 982c2c66affSColin Finck PLDR_DATA_TABLE_ENTRY LdrEntry; 983c2c66affSColin Finck NTSTATUS Status; 984c2c66affSColin Finck UNICODE_STRING DriverName; 985c2c66affSColin Finck ULONG i, Index; 986c2c66affSColin Finck PDRIVER_INFORMATION DriverInfo, DriverInfoTag; 987c2c66affSColin Finck HANDLE KeyHandle; 988c2c66affSColin Finck PBOOT_DRIVER_LIST_ENTRY BootEntry; 989c2c66affSColin Finck DPRINT("IopInitializeBootDrivers()\n"); 990c2c66affSColin Finck 991e18a32dfSVictor Perevertkin /* Create the RAW FS built-in driver */ 992e18a32dfSVictor Perevertkin RtlInitUnicodeString(&DriverName, L"\\FileSystem\\RAW"); 993c2c66affSColin Finck 994e18a32dfSVictor Perevertkin Status = IoCreateDriver(&DriverName, RawFsDriverEntry); 995c2c66affSColin Finck if (!NT_SUCCESS(Status)) 996c2c66affSColin Finck { 997c2c66affSColin Finck /* Fail */ 998c2c66affSColin Finck return; 999c2c66affSColin Finck } 1000c2c66affSColin Finck 1001c2c66affSColin Finck /* Get highest group order index */ 1002c2c66affSColin Finck IopGroupIndex = PpInitGetGroupOrderIndex(NULL); 1003c2c66affSColin Finck if (IopGroupIndex == 0xFFFF) ASSERT(FALSE); 1004c2c66affSColin Finck 1005c2c66affSColin Finck /* Allocate the group table */ 1006c2c66affSColin Finck IopGroupTable = ExAllocatePoolWithTag(PagedPool, 1007c2c66affSColin Finck IopGroupIndex * sizeof(LIST_ENTRY), 1008c2c66affSColin Finck TAG_IO); 1009c2c66affSColin Finck if (IopGroupTable == NULL) ASSERT(FALSE); 1010c2c66affSColin Finck 1011c2c66affSColin Finck /* Initialize the group table lists */ 1012c2c66affSColin Finck for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]); 1013c2c66affSColin Finck 1014c2c66affSColin Finck /* Loop the boot modules */ 1015c2c66affSColin Finck ListHead = &KeLoaderBlock->LoadOrderListHead; 1016a82ff90bSHermès Bélusca-Maïto for (NextEntry = ListHead->Flink; 1017a82ff90bSHermès Bélusca-Maïto NextEntry != ListHead; 1018a82ff90bSHermès Bélusca-Maïto NextEntry = NextEntry->Flink) 1019c2c66affSColin Finck { 1020c2c66affSColin Finck /* Get the entry */ 1021c2c66affSColin Finck LdrEntry = CONTAINING_RECORD(NextEntry, 1022c2c66affSColin Finck LDR_DATA_TABLE_ENTRY, 1023c2c66affSColin Finck InLoadOrderLinks); 1024c2c66affSColin Finck 1025c2c66affSColin Finck /* Check if the DLL needs to be initialized */ 1026c2c66affSColin Finck if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL) 1027c2c66affSColin Finck { 1028c2c66affSColin Finck /* Call its entrypoint */ 1029c2c66affSColin Finck MmCallDllInitialize(LdrEntry, NULL); 1030c2c66affSColin Finck } 1031c2c66affSColin Finck } 1032c2c66affSColin Finck 1033c2c66affSColin Finck /* Loop the boot drivers */ 1034c2c66affSColin Finck ListHead = &KeLoaderBlock->BootDriverListHead; 1035a82ff90bSHermès Bélusca-Maïto for (NextEntry = ListHead->Flink; 1036a82ff90bSHermès Bélusca-Maïto NextEntry != ListHead; 1037a82ff90bSHermès Bélusca-Maïto NextEntry = NextEntry->Flink) 1038c2c66affSColin Finck { 1039c2c66affSColin Finck /* Get the entry */ 1040c2c66affSColin Finck BootEntry = CONTAINING_RECORD(NextEntry, 1041c2c66affSColin Finck BOOT_DRIVER_LIST_ENTRY, 1042c2c66affSColin Finck Link); 1043c2c66affSColin Finck 1044c2c66affSColin Finck /* Get the driver loader entry */ 1045c2c66affSColin Finck LdrEntry = BootEntry->LdrEntry; 1046c2c66affSColin Finck 1047c2c66affSColin Finck /* Allocate our internal accounting structure */ 1048c2c66affSColin Finck DriverInfo = ExAllocatePoolWithTag(PagedPool, 1049c2c66affSColin Finck sizeof(DRIVER_INFORMATION), 1050c2c66affSColin Finck TAG_IO); 1051c2c66affSColin Finck if (DriverInfo) 1052c2c66affSColin Finck { 1053c2c66affSColin Finck /* Zero it and initialize it */ 1054c2c66affSColin Finck RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION)); 1055c2c66affSColin Finck InitializeListHead(&DriverInfo->Link); 1056c2c66affSColin Finck DriverInfo->DataTableEntry = BootEntry; 1057c2c66affSColin Finck 1058c2c66affSColin Finck /* Open the registry key */ 1059c2c66affSColin Finck Status = IopOpenRegistryKeyEx(&KeyHandle, 1060c2c66affSColin Finck NULL, 1061c2c66affSColin Finck &BootEntry->RegistryPath, 1062c2c66affSColin Finck KEY_READ); 10638e51bb65SPierre Schweitzer DPRINT("IopOpenRegistryKeyEx(%wZ) returned 0x%08lx\n", &BootEntry->RegistryPath, Status); 1064cb69c4c6SHermès Bélusca-Maïto #if 0 1065cb69c4c6SHermès Bélusca-Maïto if (NT_SUCCESS(Status)) 1066cb69c4c6SHermès Bélusca-Maïto #else // Hack still needed... 1067c2c66affSColin Finck if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */ 1068c2c66affSColin Finck ((KeLoaderBlock->SetupLdrBlock) && ((KeyHandle = (PVOID)1)))) // yes, it's an assignment! 1069cb69c4c6SHermès Bélusca-Maïto #endif 1070c2c66affSColin Finck { 1071c2c66affSColin Finck /* Save the handle */ 1072c2c66affSColin Finck DriverInfo->ServiceHandle = KeyHandle; 1073c2c66affSColin Finck 1074c2c66affSColin Finck /* Get the group oder index */ 1075c2c66affSColin Finck Index = PpInitGetGroupOrderIndex(KeyHandle); 1076c2c66affSColin Finck 1077c2c66affSColin Finck /* Get the tag position */ 1078c2c66affSColin Finck DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle); 1079c2c66affSColin Finck 1080c2c66affSColin Finck /* Insert it into the list, at the right place */ 1081c2c66affSColin Finck ASSERT(Index < IopGroupIndex); 1082c2c66affSColin Finck NextEntry2 = IopGroupTable[Index].Flink; 1083c2c66affSColin Finck while (NextEntry2 != &IopGroupTable[Index]) 1084c2c66affSColin Finck { 1085c2c66affSColin Finck /* Get the driver info */ 1086c2c66affSColin Finck DriverInfoTag = CONTAINING_RECORD(NextEntry2, 1087c2c66affSColin Finck DRIVER_INFORMATION, 1088c2c66affSColin Finck Link); 1089c2c66affSColin Finck 1090c2c66affSColin Finck /* Check if we found the right tag position */ 1091c2c66affSColin Finck if (DriverInfoTag->TagPosition > DriverInfo->TagPosition) 1092c2c66affSColin Finck { 1093c2c66affSColin Finck /* We're done */ 1094c2c66affSColin Finck break; 1095c2c66affSColin Finck } 1096c2c66affSColin Finck 1097c2c66affSColin Finck /* Next entry */ 1098c2c66affSColin Finck NextEntry2 = NextEntry2->Flink; 1099c2c66affSColin Finck } 1100c2c66affSColin Finck 1101c2c66affSColin Finck /* Insert us right before the next entry */ 1102c2c66affSColin Finck NextEntry2 = NextEntry2->Blink; 1103c2c66affSColin Finck InsertHeadList(NextEntry2, &DriverInfo->Link); 1104c2c66affSColin Finck } 1105c2c66affSColin Finck } 1106c2c66affSColin Finck } 1107c2c66affSColin Finck 1108c2c66affSColin Finck /* Loop each group index */ 1109c2c66affSColin Finck for (i = 0; i < IopGroupIndex; i++) 1110c2c66affSColin Finck { 1111c2c66affSColin Finck /* Loop each group table */ 1112a82ff90bSHermès Bélusca-Maïto for (NextEntry = IopGroupTable[i].Flink; 1113a82ff90bSHermès Bélusca-Maïto NextEntry != &IopGroupTable[i]; 1114a82ff90bSHermès Bélusca-Maïto NextEntry = NextEntry->Flink) 1115c2c66affSColin Finck { 1116c2c66affSColin Finck /* Get the entry */ 1117c2c66affSColin Finck DriverInfo = CONTAINING_RECORD(NextEntry, 1118c2c66affSColin Finck DRIVER_INFORMATION, 1119c2c66affSColin Finck Link); 1120c2c66affSColin Finck 1121c2c66affSColin Finck /* Get the driver loader entry */ 1122c2c66affSColin Finck LdrEntry = DriverInfo->DataTableEntry->LdrEntry; 1123c2c66affSColin Finck 1124c2c66affSColin Finck /* Initialize it */ 112591fceab3SVictor Perevertkin if (IopInitializeBuiltinDriver(LdrEntry)) 112691fceab3SVictor Perevertkin { 112791fceab3SVictor Perevertkin // it does not make sense to enumerate the tree if there are no new devices added 1128d6ef8f97SVictor Perevertkin PiQueueDeviceAction(IopRootDeviceNode->PhysicalDeviceObject, 1129d6ef8f97SVictor Perevertkin PiActionEnumRootDevices, 1130d6ef8f97SVictor Perevertkin NULL, 1131d6ef8f97SVictor Perevertkin NULL); 113291fceab3SVictor Perevertkin } 1133c2c66affSColin Finck } 1134c2c66affSColin Finck } 1135c2c66affSColin Finck 11362839c850SVictor Perevertkin /* HAL Root Bus is being initialized before loading the boot drivers so this may cause issues 11372839c850SVictor Perevertkin * when some devices are not being initialized with their drivers. This flag is used to delay 11382839c850SVictor Perevertkin * all actions with devices (except PnP root device) until boot drivers are loaded. 11392839c850SVictor Perevertkin * See PiQueueDeviceAction function 11402839c850SVictor Perevertkin */ 11412839c850SVictor Perevertkin PnPBootDriversLoaded = TRUE; 1142b7042928SVictor Perevertkin 1143b7042928SVictor Perevertkin DbgPrint("BOOT DRIVERS LOADED\n"); 1144b7042928SVictor Perevertkin 1145b7042928SVictor Perevertkin PiQueueDeviceAction(IopRootDeviceNode->PhysicalDeviceObject, 1146b7042928SVictor Perevertkin PiActionEnumDeviceTree, 1147b7042928SVictor Perevertkin NULL, 1148b7042928SVictor Perevertkin NULL); 1149c2c66affSColin Finck } 1150c2c66affSColin Finck 11515c7ce447SVictor Perevertkin CODE_SEG("INIT") 1152c2c66affSColin Finck VOID 1153c2c66affSColin Finck FASTCALL 1154c2c66affSColin Finck IopInitializeSystemDrivers(VOID) 1155c2c66affSColin Finck { 1156c2c66affSColin Finck PUNICODE_STRING *DriverList, *SavedList; 1157c2c66affSColin Finck 1158b7042928SVictor Perevertkin PiPerformSyncDeviceAction(IopRootDeviceNode->PhysicalDeviceObject, PiActionEnumDeviceTree); 1159b7042928SVictor Perevertkin 1160c2c66affSColin Finck /* No system drivers on the boot cd */ 1161cb69c4c6SHermès Bélusca-Maïto if (KeLoaderBlock->SetupLdrBlock) return; // ExpInTextModeSetup 1162c2c66affSColin Finck 1163c2c66affSColin Finck /* Get the driver list */ 1164c2c66affSColin Finck SavedList = DriverList = CmGetSystemDriverList(); 1165c2c66affSColin Finck ASSERT(DriverList); 1166c2c66affSColin Finck 1167c2c66affSColin Finck /* Loop it */ 1168c2c66affSColin Finck while (*DriverList) 1169c2c66affSColin Finck { 1170c2c66affSColin Finck /* Load the driver */ 1171c2c66affSColin Finck ZwLoadDriver(*DriverList); 1172c2c66affSColin Finck 1173c2c66affSColin Finck /* Free the entry */ 1174c2c66affSColin Finck RtlFreeUnicodeString(*DriverList); 1175c2c66affSColin Finck ExFreePool(*DriverList); 1176c2c66affSColin Finck 1177c2c66affSColin Finck /* Next entry */ 1178c2c66affSColin Finck InbvIndicateProgress(); 1179c2c66affSColin Finck DriverList++; 1180c2c66affSColin Finck } 1181c2c66affSColin Finck 1182c2c66affSColin Finck /* Free the list */ 1183c2c66affSColin Finck ExFreePool(SavedList); 1184b7042928SVictor Perevertkin 1185b7042928SVictor Perevertkin PiQueueDeviceAction(IopRootDeviceNode->PhysicalDeviceObject, 1186b7042928SVictor Perevertkin PiActionEnumDeviceTree, 1187b7042928SVictor Perevertkin NULL, 1188b7042928SVictor Perevertkin NULL); 1189c2c66affSColin Finck } 1190c2c66affSColin Finck 1191c2c66affSColin Finck /* 1192c2c66affSColin Finck * IopUnloadDriver 1193c2c66affSColin Finck * 1194c2c66affSColin Finck * Unloads a device driver. 1195c2c66affSColin Finck * 1196c2c66affSColin Finck * Parameters 1197c2c66affSColin Finck * DriverServiceName 1198c2c66affSColin Finck * Name of the service to unload (registry key). 1199c2c66affSColin Finck * 1200c2c66affSColin Finck * UnloadPnpDrivers 1201c2c66affSColin Finck * Whether to unload Plug & Plug or only legacy drivers. If this 1202c2c66affSColin Finck * parameter is set to FALSE, the routine will unload only legacy 1203c2c66affSColin Finck * drivers. 1204c2c66affSColin Finck * 1205c2c66affSColin Finck * Return Value 1206c2c66affSColin Finck * Status 1207c2c66affSColin Finck * 1208c2c66affSColin Finck * To do 1209c2c66affSColin Finck * Guard the whole function by SEH. 1210c2c66affSColin Finck */ 1211c2c66affSColin Finck 1212c2c66affSColin Finck NTSTATUS NTAPI 1213c2c66affSColin Finck IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers) 1214c2c66affSColin Finck { 1215c904983bSThomas Faber UNICODE_STRING Backslash = RTL_CONSTANT_STRING(L"\\"); 1216c2c66affSColin Finck RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 1217c2c66affSColin Finck UNICODE_STRING ImagePath; 1218c2c66affSColin Finck UNICODE_STRING ServiceName; 1219c2c66affSColin Finck UNICODE_STRING ObjectName; 1220c2c66affSColin Finck PDRIVER_OBJECT DriverObject; 1221c2c66affSColin Finck PDEVICE_OBJECT DeviceObject; 1222c2c66affSColin Finck PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1223c2c66affSColin Finck NTSTATUS Status; 1224c904983bSThomas Faber USHORT LastBackslash; 1225c2c66affSColin Finck BOOLEAN SafeToUnload = TRUE; 1226daf9743cSPierre Schweitzer KPROCESSOR_MODE PreviousMode; 1227daf9743cSPierre Schweitzer UNICODE_STRING CapturedServiceName; 1228c2c66affSColin Finck 1229c2c66affSColin Finck PAGED_CODE(); 1230c2c66affSColin Finck 1231daf9743cSPierre Schweitzer PreviousMode = ExGetPreviousMode(); 1232daf9743cSPierre Schweitzer 1233daf9743cSPierre Schweitzer /* Need the appropriate priviliege */ 1234daf9743cSPierre Schweitzer if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode)) 1235daf9743cSPierre Schweitzer { 1236daf9743cSPierre Schweitzer DPRINT1("No unload privilege!\n"); 1237daf9743cSPierre Schweitzer return STATUS_PRIVILEGE_NOT_HELD; 1238daf9743cSPierre Schweitzer } 1239daf9743cSPierre Schweitzer 1240daf9743cSPierre Schweitzer /* Capture the service name */ 124144511f08SHermès Bélusca-Maïto Status = ProbeAndCaptureUnicodeString(&CapturedServiceName, 124244511f08SHermès Bélusca-Maïto PreviousMode, 124344511f08SHermès Bélusca-Maïto DriverServiceName); 1244daf9743cSPierre Schweitzer if (!NT_SUCCESS(Status)) 1245a6a3aa0fSVictor Perevertkin { 1246daf9743cSPierre Schweitzer return Status; 1247a6a3aa0fSVictor Perevertkin } 1248daf9743cSPierre Schweitzer 1249daf9743cSPierre Schweitzer DPRINT("IopUnloadDriver('%wZ', %u)\n", &CapturedServiceName, UnloadPnpDrivers); 1250daf9743cSPierre Schweitzer 1251daf9743cSPierre Schweitzer /* We need a service name */ 1252a748350fSHermès Bélusca-Maïto if (CapturedServiceName.Length == 0 || CapturedServiceName.Buffer == NULL) 1253daf9743cSPierre Schweitzer { 1254daf9743cSPierre Schweitzer ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1255daf9743cSPierre Schweitzer return STATUS_INVALID_PARAMETER; 1256daf9743cSPierre Schweitzer } 1257daf9743cSPierre Schweitzer 1258c2c66affSColin Finck /* 1259c2c66affSColin Finck * Get the service name from the registry key name 1260c2c66affSColin Finck */ 1261c904983bSThomas Faber Status = RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END, 1262c904983bSThomas Faber &CapturedServiceName, 1263c904983bSThomas Faber &Backslash, 1264c904983bSThomas Faber &LastBackslash); 1265c904983bSThomas Faber if (NT_SUCCESS(Status)) 1266c904983bSThomas Faber { 1267c904983bSThomas Faber NT_ASSERT(CapturedServiceName.Length >= LastBackslash + sizeof(WCHAR)); 1268c904983bSThomas Faber ServiceName.Buffer = &CapturedServiceName.Buffer[LastBackslash / sizeof(WCHAR) + 1]; 1269c904983bSThomas Faber ServiceName.Length = CapturedServiceName.Length - LastBackslash - sizeof(WCHAR); 1270c904983bSThomas Faber ServiceName.MaximumLength = CapturedServiceName.MaximumLength - LastBackslash - sizeof(WCHAR); 1271c904983bSThomas Faber } 1272c2c66affSColin Finck else 1273c904983bSThomas Faber { 1274c904983bSThomas Faber ServiceName = CapturedServiceName; 1275c904983bSThomas Faber } 1276c2c66affSColin Finck 1277c2c66affSColin Finck /* 1278c2c66affSColin Finck * Construct the driver object name 1279c2c66affSColin Finck */ 1280c904983bSThomas Faber Status = RtlUShortAdd(sizeof(DRIVER_ROOT_NAME), 1281c904983bSThomas Faber ServiceName.Length, 1282c904983bSThomas Faber &ObjectName.MaximumLength); 1283c904983bSThomas Faber if (!NT_SUCCESS(Status)) 1284c904983bSThomas Faber { 1285c904983bSThomas Faber ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1286c904983bSThomas Faber return Status; 1287c904983bSThomas Faber } 1288c904983bSThomas Faber ObjectName.Length = 0; 1289c2c66affSColin Finck ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool, 1290c2c66affSColin Finck ObjectName.MaximumLength, 1291c2c66affSColin Finck TAG_IO); 1292daf9743cSPierre Schweitzer if (!ObjectName.Buffer) 1293daf9743cSPierre Schweitzer { 1294daf9743cSPierre Schweitzer ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1295daf9743cSPierre Schweitzer return STATUS_INSUFFICIENT_RESOURCES; 1296daf9743cSPierre Schweitzer } 1297c904983bSThomas Faber NT_VERIFY(NT_SUCCESS(RtlAppendUnicodeToString(&ObjectName, DRIVER_ROOT_NAME))); 1298c904983bSThomas Faber NT_VERIFY(NT_SUCCESS(RtlAppendUnicodeStringToString(&ObjectName, &ServiceName))); 1299c2c66affSColin Finck 1300c2c66affSColin Finck /* 1301c2c66affSColin Finck * Find the driver object 1302c2c66affSColin Finck */ 1303c2c66affSColin Finck Status = ObReferenceObjectByName(&ObjectName, 1304c2c66affSColin Finck 0, 1305c2c66affSColin Finck 0, 1306c2c66affSColin Finck 0, 1307c2c66affSColin Finck IoDriverObjectType, 1308c2c66affSColin Finck KernelMode, 1309c2c66affSColin Finck 0, 1310c2c66affSColin Finck (PVOID*)&DriverObject); 1311c2c66affSColin Finck 1312c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1313c2c66affSColin Finck { 1314c2c66affSColin Finck DPRINT1("Can't locate driver object for %wZ\n", &ObjectName); 1315c2c66affSColin Finck ExFreePoolWithTag(ObjectName.Buffer, TAG_IO); 1316daf9743cSPierre Schweitzer ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1317c2c66affSColin Finck return Status; 1318c2c66affSColin Finck } 1319c2c66affSColin Finck 1320c2c66affSColin Finck /* Free the buffer for driver object name */ 1321c2c66affSColin Finck ExFreePoolWithTag(ObjectName.Buffer, TAG_IO); 1322c2c66affSColin Finck 1323c2c66affSColin Finck /* Check that driver is not already unloading */ 1324c2c66affSColin Finck if (DriverObject->Flags & DRVO_UNLOAD_INVOKED) 1325c2c66affSColin Finck { 1326c2c66affSColin Finck DPRINT1("Driver deletion pending\n"); 1327c2c66affSColin Finck ObDereferenceObject(DriverObject); 1328daf9743cSPierre Schweitzer ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1329c2c66affSColin Finck return STATUS_DELETE_PENDING; 1330c2c66affSColin Finck } 1331c2c66affSColin Finck 1332c2c66affSColin Finck /* 1333c2c66affSColin Finck * Get path of service... 1334c2c66affSColin Finck */ 1335c2c66affSColin Finck RtlZeroMemory(QueryTable, sizeof(QueryTable)); 1336c2c66affSColin Finck 1337c2c66affSColin Finck RtlInitUnicodeString(&ImagePath, NULL); 1338c2c66affSColin Finck 1339c2c66affSColin Finck QueryTable[0].Name = L"ImagePath"; 1340c2c66affSColin Finck QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 1341c2c66affSColin Finck QueryTable[0].EntryContext = &ImagePath; 1342c2c66affSColin Finck 1343c2c66affSColin Finck Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 1344daf9743cSPierre Schweitzer CapturedServiceName.Buffer, 1345c2c66affSColin Finck QueryTable, 1346c2c66affSColin Finck NULL, 1347c2c66affSColin Finck NULL); 1348c2c66affSColin Finck 1349daf9743cSPierre Schweitzer /* We no longer need service name */ 1350daf9743cSPierre Schweitzer ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1351daf9743cSPierre Schweitzer 1352c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1353c2c66affSColin Finck { 1354c2c66affSColin Finck DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status); 1355c2c66affSColin Finck ObDereferenceObject(DriverObject); 1356c2c66affSColin Finck return Status; 1357c2c66affSColin Finck } 1358c2c66affSColin Finck 1359c2c66affSColin Finck /* 1360c2c66affSColin Finck * Normalize the image path for all later processing. 1361c2c66affSColin Finck */ 1362c2c66affSColin Finck Status = IopNormalizeImagePath(&ImagePath, &ServiceName); 1363c2c66affSColin Finck 1364c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1365c2c66affSColin Finck { 1366c2c66affSColin Finck DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status); 1367c2c66affSColin Finck ObDereferenceObject(DriverObject); 1368c2c66affSColin Finck return Status; 1369c2c66affSColin Finck } 1370c2c66affSColin Finck 1371c2c66affSColin Finck /* Free the service path */ 1372c2c66affSColin Finck ExFreePool(ImagePath.Buffer); 1373c2c66affSColin Finck 1374c2c66affSColin Finck /* 1375c2c66affSColin Finck * Unload the module and release the references to the device object 1376c2c66affSColin Finck */ 1377c2c66affSColin Finck 1378c2c66affSColin Finck /* Call the load/unload routine, depending on current process */ 1379c2c66affSColin Finck if (DriverObject->DriverUnload && DriverObject->DriverSection && 1380c2c66affSColin Finck (UnloadPnpDrivers || (DriverObject->Flags & DRVO_LEGACY_DRIVER))) 1381c2c66affSColin Finck { 1382c2c66affSColin Finck /* Loop through each device object of the driver 1383c2c66affSColin Finck and set DOE_UNLOAD_PENDING flag */ 1384c2c66affSColin Finck DeviceObject = DriverObject->DeviceObject; 1385c2c66affSColin Finck while (DeviceObject) 1386c2c66affSColin Finck { 1387c2c66affSColin Finck /* Set the unload pending flag for the device */ 1388c2c66affSColin Finck DeviceExtension = IoGetDevObjExtension(DeviceObject); 1389c2c66affSColin Finck DeviceExtension->ExtensionFlags |= DOE_UNLOAD_PENDING; 1390c2c66affSColin Finck 1391c2c66affSColin Finck /* Make sure there are no attached devices or no reference counts */ 1392c2c66affSColin Finck if ((DeviceObject->ReferenceCount) || (DeviceObject->AttachedDevice)) 1393c2c66affSColin Finck { 1394c2c66affSColin Finck /* Not safe to unload */ 1395c2c66affSColin Finck DPRINT1("Drivers device object is referenced or has attached devices\n"); 1396c2c66affSColin Finck 1397c2c66affSColin Finck SafeToUnload = FALSE; 1398c2c66affSColin Finck } 1399c2c66affSColin Finck 1400c2c66affSColin Finck DeviceObject = DeviceObject->NextDevice; 1401c2c66affSColin Finck } 1402c2c66affSColin Finck 1403c2c66affSColin Finck /* If not safe to unload, then return success */ 1404c2c66affSColin Finck if (!SafeToUnload) 1405c2c66affSColin Finck { 1406c2c66affSColin Finck ObDereferenceObject(DriverObject); 1407c2c66affSColin Finck return STATUS_SUCCESS; 1408c2c66affSColin Finck } 1409c2c66affSColin Finck 1410c2c66affSColin Finck DPRINT1("Unloading driver '%wZ' (manual)\n", &DriverObject->DriverName); 1411c2c66affSColin Finck 1412c2c66affSColin Finck /* Set the unload invoked flag and call the unload routine */ 1413c2c66affSColin Finck DriverObject->Flags |= DRVO_UNLOAD_INVOKED; 1414a6a3aa0fSVictor Perevertkin Status = IopDoLoadUnloadDriver(NULL, &DriverObject); 1415c2c66affSColin Finck ASSERT(Status == STATUS_SUCCESS); 1416c2c66affSColin Finck 1417c2c66affSColin Finck /* Mark the driver object temporary, so it could be deleted later */ 1418c2c66affSColin Finck ObMakeTemporaryObject(DriverObject); 1419c2c66affSColin Finck 1420c2c66affSColin Finck /* Dereference it 2 times */ 1421c2c66affSColin Finck ObDereferenceObject(DriverObject); 1422c2c66affSColin Finck ObDereferenceObject(DriverObject); 1423c2c66affSColin Finck 1424c2c66affSColin Finck return Status; 1425c2c66affSColin Finck } 1426c2c66affSColin Finck else 1427c2c66affSColin Finck { 1428c2c66affSColin Finck DPRINT1("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject->DriverName); 1429c2c66affSColin Finck 1430c2c66affSColin Finck /* Dereference one time (refd inside this function) */ 1431c2c66affSColin Finck ObDereferenceObject(DriverObject); 1432c2c66affSColin Finck 1433c2c66affSColin Finck /* Return unloading failure */ 1434c2c66affSColin Finck return STATUS_INVALID_DEVICE_REQUEST; 1435c2c66affSColin Finck } 1436c2c66affSColin Finck } 1437c2c66affSColin Finck 1438c2c66affSColin Finck VOID 1439c2c66affSColin Finck NTAPI 1440c2c66affSColin Finck IopReinitializeDrivers(VOID) 1441c2c66affSColin Finck { 1442c2c66affSColin Finck PDRIVER_REINIT_ITEM ReinitItem; 1443c2c66affSColin Finck PLIST_ENTRY Entry; 1444c2c66affSColin Finck 1445c2c66affSColin Finck /* Get the first entry and start looping */ 1446c2c66affSColin Finck Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead, 1447c2c66affSColin Finck &DriverReinitListLock); 1448c2c66affSColin Finck while (Entry) 1449c2c66affSColin Finck { 1450c2c66affSColin Finck /* Get the item */ 1451c2c66affSColin Finck ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry); 1452c2c66affSColin Finck 1453c2c66affSColin Finck /* Increment reinitialization counter */ 1454c2c66affSColin Finck ReinitItem->DriverObject->DriverExtension->Count++; 1455c2c66affSColin Finck 1456c2c66affSColin Finck /* Remove the device object flag */ 1457c2c66affSColin Finck ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED; 1458c2c66affSColin Finck 1459c2c66affSColin Finck /* Call the routine */ 1460c2c66affSColin Finck ReinitItem->ReinitRoutine(ReinitItem->DriverObject, 1461c2c66affSColin Finck ReinitItem->Context, 1462c2c66affSColin Finck ReinitItem->DriverObject-> 1463c2c66affSColin Finck DriverExtension->Count); 1464c2c66affSColin Finck 1465c2c66affSColin Finck /* Free the entry */ 1466c2c66affSColin Finck ExFreePool(Entry); 1467c2c66affSColin Finck 1468c2c66affSColin Finck /* Move to the next one */ 1469c2c66affSColin Finck Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead, 1470c2c66affSColin Finck &DriverReinitListLock); 1471c2c66affSColin Finck } 1472c2c66affSColin Finck } 1473c2c66affSColin Finck 1474c2c66affSColin Finck VOID 1475c2c66affSColin Finck NTAPI 1476c2c66affSColin Finck IopReinitializeBootDrivers(VOID) 1477c2c66affSColin Finck { 1478c2c66affSColin Finck PDRIVER_REINIT_ITEM ReinitItem; 1479c2c66affSColin Finck PLIST_ENTRY Entry; 1480c2c66affSColin Finck 1481c2c66affSColin Finck /* Get the first entry and start looping */ 1482c2c66affSColin Finck Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead, 1483c2c66affSColin Finck &DriverBootReinitListLock); 1484c2c66affSColin Finck while (Entry) 1485c2c66affSColin Finck { 1486c2c66affSColin Finck /* Get the item */ 1487c2c66affSColin Finck ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry); 1488c2c66affSColin Finck 1489c2c66affSColin Finck /* Increment reinitialization counter */ 1490c2c66affSColin Finck ReinitItem->DriverObject->DriverExtension->Count++; 1491c2c66affSColin Finck 1492c2c66affSColin Finck /* Remove the device object flag */ 1493c2c66affSColin Finck ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED; 1494c2c66affSColin Finck 1495c2c66affSColin Finck /* Call the routine */ 1496c2c66affSColin Finck ReinitItem->ReinitRoutine(ReinitItem->DriverObject, 1497c2c66affSColin Finck ReinitItem->Context, 1498c2c66affSColin Finck ReinitItem->DriverObject-> 1499c2c66affSColin Finck DriverExtension->Count); 1500c2c66affSColin Finck 1501c2c66affSColin Finck /* Free the entry */ 1502c2c66affSColin Finck ExFreePool(Entry); 1503c2c66affSColin Finck 1504c2c66affSColin Finck /* Move to the next one */ 1505c2c66affSColin Finck Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead, 1506c2c66affSColin Finck &DriverBootReinitListLock); 1507c2c66affSColin Finck } 15082839c850SVictor Perevertkin 15092839c850SVictor Perevertkin /* Wait for all device actions being finished*/ 15102839c850SVictor Perevertkin KeWaitForSingleObject(&PiEnumerationFinished, Executive, KernelMode, FALSE, NULL); 1511c2c66affSColin Finck } 1512c2c66affSColin Finck 1513e18a32dfSVictor Perevertkin /* PUBLIC FUNCTIONS ***********************************************************/ 1514e18a32dfSVictor Perevertkin 1515e18a32dfSVictor Perevertkin /* 1516e18a32dfSVictor Perevertkin * @implemented 1517e18a32dfSVictor Perevertkin */ 1518c2c66affSColin Finck NTSTATUS 1519c2c66affSColin Finck NTAPI 1520e18a32dfSVictor Perevertkin IoCreateDriver( 1521e18a32dfSVictor Perevertkin _In_opt_ PUNICODE_STRING DriverName, 1522e18a32dfSVictor Perevertkin _In_ PDRIVER_INITIALIZE InitializationFunction) 1523c2c66affSColin Finck { 1524c2c66affSColin Finck WCHAR NameBuffer[100]; 1525c2c66affSColin Finck USHORT NameLength; 1526c2c66affSColin Finck UNICODE_STRING LocalDriverName; 1527c2c66affSColin Finck NTSTATUS Status; 1528c2c66affSColin Finck OBJECT_ATTRIBUTES ObjectAttributes; 1529c2c66affSColin Finck ULONG ObjectSize; 1530c2c66affSColin Finck PDRIVER_OBJECT DriverObject; 1531c2c66affSColin Finck UNICODE_STRING ServiceKeyName; 1532c2c66affSColin Finck HANDLE hDriver; 1533c2c66affSColin Finck ULONG i, RetryCount = 0; 1534c2c66affSColin Finck 1535c2c66affSColin Finck try_again: 1536c2c66affSColin Finck /* First, create a unique name for the driver if we don't have one */ 1537c2c66affSColin Finck if (!DriverName) 1538c2c66affSColin Finck { 1539c2c66affSColin Finck /* Create a random name and set up the string */ 1540c2c66affSColin Finck NameLength = (USHORT)swprintf(NameBuffer, 1541c2c66affSColin Finck DRIVER_ROOT_NAME L"%08u", 1542c2c66affSColin Finck KeTickCount.LowPart); 1543c2c66affSColin Finck LocalDriverName.Length = NameLength * sizeof(WCHAR); 1544c2c66affSColin Finck LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL); 1545c2c66affSColin Finck LocalDriverName.Buffer = NameBuffer; 1546c2c66affSColin Finck } 1547c2c66affSColin Finck else 1548c2c66affSColin Finck { 1549c2c66affSColin Finck /* So we can avoid another code path, use a local var */ 1550c2c66affSColin Finck LocalDriverName = *DriverName; 1551c2c66affSColin Finck } 1552c2c66affSColin Finck 1553c2c66affSColin Finck /* Initialize the Attributes */ 1554c2c66affSColin Finck ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION); 1555c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 1556c2c66affSColin Finck &LocalDriverName, 1557c2c66affSColin Finck OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 1558c2c66affSColin Finck NULL, 1559c2c66affSColin Finck NULL); 1560c2c66affSColin Finck 1561c2c66affSColin Finck /* Create the Object */ 1562c2c66affSColin Finck Status = ObCreateObject(KernelMode, 1563c2c66affSColin Finck IoDriverObjectType, 1564c2c66affSColin Finck &ObjectAttributes, 1565c2c66affSColin Finck KernelMode, 1566c2c66affSColin Finck NULL, 1567c2c66affSColin Finck ObjectSize, 1568c2c66affSColin Finck 0, 1569c2c66affSColin Finck 0, 1570c2c66affSColin Finck (PVOID*)&DriverObject); 1571c2c66affSColin Finck if (!NT_SUCCESS(Status)) return Status; 1572c2c66affSColin Finck 1573c2c66affSColin Finck DPRINT("IopCreateDriver(): created DO %p\n", DriverObject); 1574c2c66affSColin Finck 1575c2c66affSColin Finck /* Set up the Object */ 1576c2c66affSColin Finck RtlZeroMemory(DriverObject, ObjectSize); 1577c2c66affSColin Finck DriverObject->Type = IO_TYPE_DRIVER; 1578c2c66affSColin Finck DriverObject->Size = sizeof(DRIVER_OBJECT); 157945012aa4SHermès Bélusca-Maïto DriverObject->Flags = DRVO_BUILTIN_DRIVER; 1580c2c66affSColin Finck DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1); 1581c2c66affSColin Finck DriverObject->DriverExtension->DriverObject = DriverObject; 1582c2c66affSColin Finck DriverObject->DriverInit = InitializationFunction; 1583c2c66affSColin Finck /* Loop all Major Functions */ 1584c2c66affSColin Finck for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) 1585c2c66affSColin Finck { 1586c2c66affSColin Finck /* Invalidate each function */ 1587c2c66affSColin Finck DriverObject->MajorFunction[i] = IopInvalidDeviceRequest; 1588c2c66affSColin Finck } 1589c2c66affSColin Finck 1590c2c66affSColin Finck /* Set up the service key name buffer */ 1591e18a32dfSVictor Perevertkin ServiceKeyName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL); 1592e18a32dfSVictor Perevertkin ServiceKeyName.Buffer = ExAllocatePoolWithTag(PagedPool, LocalDriverName.MaximumLength, TAG_IO); 1593c2c66affSColin Finck if (!ServiceKeyName.Buffer) 1594c2c66affSColin Finck { 1595c2c66affSColin Finck /* Fail */ 1596c2c66affSColin Finck ObMakeTemporaryObject(DriverObject); 1597c2c66affSColin Finck ObDereferenceObject(DriverObject); 1598c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 1599c2c66affSColin Finck } 1600c2c66affSColin Finck 1601e18a32dfSVictor Perevertkin /* For builtin drivers, the ServiceKeyName is equal to DriverName */ 1602e18a32dfSVictor Perevertkin RtlCopyUnicodeString(&ServiceKeyName, &LocalDriverName); 1603e18a32dfSVictor Perevertkin ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL; 1604c2c66affSColin Finck DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName; 1605c2c66affSColin Finck 1606c2c66affSColin Finck /* Make a copy of the driver name to store in the driver object */ 1607c2c66affSColin Finck DriverObject->DriverName.MaximumLength = LocalDriverName.Length; 1608c2c66affSColin Finck DriverObject->DriverName.Buffer = ExAllocatePoolWithTag(PagedPool, 1609c2c66affSColin Finck DriverObject->DriverName.MaximumLength, 1610c2c66affSColin Finck TAG_IO); 1611c2c66affSColin Finck if (!DriverObject->DriverName.Buffer) 1612c2c66affSColin Finck { 1613c2c66affSColin Finck /* Fail */ 1614c2c66affSColin Finck ObMakeTemporaryObject(DriverObject); 1615c2c66affSColin Finck ObDereferenceObject(DriverObject); 1616c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 1617c2c66affSColin Finck } 1618c2c66affSColin Finck 1619e18a32dfSVictor Perevertkin RtlCopyUnicodeString(&DriverObject->DriverName, &LocalDriverName); 1620c2c66affSColin Finck 1621c2c66affSColin Finck /* Add the Object and get its handle */ 1622c2c66affSColin Finck Status = ObInsertObject(DriverObject, 1623c2c66affSColin Finck NULL, 1624c2c66affSColin Finck FILE_READ_DATA, 1625c2c66affSColin Finck 0, 1626c2c66affSColin Finck NULL, 1627c2c66affSColin Finck &hDriver); 1628c2c66affSColin Finck 1629c2c66affSColin Finck /* Eliminate small possibility when this function is called more than 1630c2c66affSColin Finck once in a row, and KeTickCount doesn't get enough time to change */ 1631c2c66affSColin Finck if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100)) 1632c2c66affSColin Finck { 1633c2c66affSColin Finck RetryCount++; 1634c2c66affSColin Finck goto try_again; 1635c2c66affSColin Finck } 1636c2c66affSColin Finck 1637c2c66affSColin Finck if (!NT_SUCCESS(Status)) return Status; 1638c2c66affSColin Finck 1639c2c66affSColin Finck /* Now reference it */ 1640c2c66affSColin Finck Status = ObReferenceObjectByHandle(hDriver, 1641c2c66affSColin Finck 0, 1642c2c66affSColin Finck IoDriverObjectType, 1643c2c66affSColin Finck KernelMode, 1644c2c66affSColin Finck (PVOID*)&DriverObject, 1645c2c66affSColin Finck NULL); 1646c2c66affSColin Finck 1647c2c66affSColin Finck /* Close the extra handle */ 1648c2c66affSColin Finck ZwClose(hDriver); 1649c2c66affSColin Finck 1650c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1651c2c66affSColin Finck { 1652c2c66affSColin Finck /* Fail */ 1653c2c66affSColin Finck ObMakeTemporaryObject(DriverObject); 1654c2c66affSColin Finck ObDereferenceObject(DriverObject); 1655c2c66affSColin Finck return Status; 1656c2c66affSColin Finck } 1657c2c66affSColin Finck 1658c2c66affSColin Finck /* Finally, call its init function */ 1659c2c66affSColin Finck DPRINT("Calling driver entrypoint at %p\n", InitializationFunction); 1660a82ff90bSHermès Bélusca-Maïto Status = InitializationFunction(DriverObject, NULL); 1661c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1662c2c66affSColin Finck { 1663c2c66affSColin Finck /* If it didn't work, then kill the object */ 1664c2c66affSColin Finck DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status); 1665c2c66affSColin Finck ObMakeTemporaryObject(DriverObject); 1666c2c66affSColin Finck ObDereferenceObject(DriverObject); 1667c2c66affSColin Finck return Status; 1668c2c66affSColin Finck } 1669c2c66affSColin Finck 1670e18a32dfSVictor Perevertkin // Windows does this fixup - keep it for compatibility 1671c2c66affSColin Finck for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) 1672c2c66affSColin Finck { 1673c2c66affSColin Finck /* 1674c2c66affSColin Finck * Make sure the driver didn't set any dispatch entry point to NULL! 1675c2c66affSColin Finck * Doing so is illegal; drivers shouldn't touch entry points they 1676c2c66affSColin Finck * do not implement. 1677c2c66affSColin Finck */ 1678c2c66affSColin Finck 1679c2c66affSColin Finck /* Check if it did so anyway */ 1680c2c66affSColin Finck if (!DriverObject->MajorFunction[i]) 1681c2c66affSColin Finck { 1682c2c66affSColin Finck /* Print a warning in the debug log */ 1683c2c66affSColin Finck DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%lu] to NULL!\n", 1684c2c66affSColin Finck &DriverObject->DriverName, i); 1685c2c66affSColin Finck 1686c2c66affSColin Finck /* Fix it up */ 1687c2c66affSColin Finck DriverObject->MajorFunction[i] = IopInvalidDeviceRequest; 1688c2c66affSColin Finck } 1689c2c66affSColin Finck } 1690c2c66affSColin Finck 1691c2c66affSColin Finck /* Return the Status */ 1692c2c66affSColin Finck return Status; 1693c2c66affSColin Finck } 1694c2c66affSColin Finck 1695c2c66affSColin Finck /* 1696c2c66affSColin Finck * @implemented 1697c2c66affSColin Finck */ 1698c2c66affSColin Finck VOID 1699c2c66affSColin Finck NTAPI 1700c2c66affSColin Finck IoDeleteDriver(IN PDRIVER_OBJECT DriverObject) 1701c2c66affSColin Finck { 1702c2c66affSColin Finck /* Simply dereference the Object */ 1703c2c66affSColin Finck ObDereferenceObject(DriverObject); 1704c2c66affSColin Finck } 1705c2c66affSColin Finck 1706c2c66affSColin Finck /* 1707c2c66affSColin Finck * @implemented 1708c2c66affSColin Finck */ 1709c2c66affSColin Finck VOID 1710c2c66affSColin Finck NTAPI 1711c2c66affSColin Finck IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject, 1712c2c66affSColin Finck IN PDRIVER_REINITIALIZE ReinitRoutine, 1713c2c66affSColin Finck IN PVOID Context) 1714c2c66affSColin Finck { 1715c2c66affSColin Finck PDRIVER_REINIT_ITEM ReinitItem; 1716c2c66affSColin Finck 1717c2c66affSColin Finck /* Allocate the entry */ 1718c2c66affSColin Finck ReinitItem = ExAllocatePoolWithTag(NonPagedPool, 1719c2c66affSColin Finck sizeof(DRIVER_REINIT_ITEM), 1720c2c66affSColin Finck TAG_REINIT); 1721c2c66affSColin Finck if (!ReinitItem) return; 1722c2c66affSColin Finck 1723c2c66affSColin Finck /* Fill it out */ 1724c2c66affSColin Finck ReinitItem->DriverObject = DriverObject; 1725c2c66affSColin Finck ReinitItem->ReinitRoutine = ReinitRoutine; 1726c2c66affSColin Finck ReinitItem->Context = Context; 1727c2c66affSColin Finck 1728c2c66affSColin Finck /* Set the Driver Object flag and insert the entry into the list */ 1729c2c66affSColin Finck DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED; 1730c2c66affSColin Finck ExInterlockedInsertTailList(&DriverBootReinitListHead, 1731c2c66affSColin Finck &ReinitItem->ItemEntry, 1732c2c66affSColin Finck &DriverBootReinitListLock); 1733c2c66affSColin Finck } 1734c2c66affSColin Finck 1735c2c66affSColin Finck /* 1736c2c66affSColin Finck * @implemented 1737c2c66affSColin Finck */ 1738c2c66affSColin Finck VOID 1739c2c66affSColin Finck NTAPI 1740c2c66affSColin Finck IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject, 1741c2c66affSColin Finck IN PDRIVER_REINITIALIZE ReinitRoutine, 1742c2c66affSColin Finck IN PVOID Context) 1743c2c66affSColin Finck { 1744c2c66affSColin Finck PDRIVER_REINIT_ITEM ReinitItem; 1745c2c66affSColin Finck 1746c2c66affSColin Finck /* Allocate the entry */ 1747c2c66affSColin Finck ReinitItem = ExAllocatePoolWithTag(NonPagedPool, 1748c2c66affSColin Finck sizeof(DRIVER_REINIT_ITEM), 1749c2c66affSColin Finck TAG_REINIT); 1750c2c66affSColin Finck if (!ReinitItem) return; 1751c2c66affSColin Finck 1752c2c66affSColin Finck /* Fill it out */ 1753c2c66affSColin Finck ReinitItem->DriverObject = DriverObject; 1754c2c66affSColin Finck ReinitItem->ReinitRoutine = ReinitRoutine; 1755c2c66affSColin Finck ReinitItem->Context = Context; 1756c2c66affSColin Finck 1757c2c66affSColin Finck /* Set the Driver Object flag and insert the entry into the list */ 1758c2c66affSColin Finck DriverObject->Flags |= DRVO_REINIT_REGISTERED; 1759c2c66affSColin Finck ExInterlockedInsertTailList(&DriverReinitListHead, 1760c2c66affSColin Finck &ReinitItem->ItemEntry, 1761c2c66affSColin Finck &DriverReinitListLock); 1762c2c66affSColin Finck } 1763c2c66affSColin Finck 1764c2c66affSColin Finck /* 1765c2c66affSColin Finck * @implemented 1766c2c66affSColin Finck */ 1767c2c66affSColin Finck NTSTATUS 1768c2c66affSColin Finck NTAPI 1769c2c66affSColin Finck IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject, 1770c2c66affSColin Finck IN PVOID ClientIdentificationAddress, 1771c2c66affSColin Finck IN ULONG DriverObjectExtensionSize, 1772c2c66affSColin Finck OUT PVOID *DriverObjectExtension) 1773c2c66affSColin Finck { 1774c2c66affSColin Finck KIRQL OldIrql; 1775c2c66affSColin Finck PIO_CLIENT_EXTENSION DriverExtensions, NewDriverExtension; 1776c2c66affSColin Finck BOOLEAN Inserted = FALSE; 1777c2c66affSColin Finck 1778c2c66affSColin Finck /* Assume failure */ 1779c2c66affSColin Finck *DriverObjectExtension = NULL; 1780c2c66affSColin Finck 1781c2c66affSColin Finck /* Allocate the extension */ 1782c2c66affSColin Finck NewDriverExtension = ExAllocatePoolWithTag(NonPagedPool, 1783c2c66affSColin Finck sizeof(IO_CLIENT_EXTENSION) + 1784c2c66affSColin Finck DriverObjectExtensionSize, 1785c2c66affSColin Finck TAG_DRIVER_EXTENSION); 1786c2c66affSColin Finck if (!NewDriverExtension) return STATUS_INSUFFICIENT_RESOURCES; 1787c2c66affSColin Finck 1788c2c66affSColin Finck /* Clear the extension for teh caller */ 1789c2c66affSColin Finck RtlZeroMemory(NewDriverExtension, 1790c2c66affSColin Finck sizeof(IO_CLIENT_EXTENSION) + DriverObjectExtensionSize); 1791c2c66affSColin Finck 1792c2c66affSColin Finck /* Acqure lock */ 1793c2c66affSColin Finck OldIrql = KeRaiseIrqlToDpcLevel(); 1794c2c66affSColin Finck 1795c2c66affSColin Finck /* Fill out the extension */ 1796c2c66affSColin Finck NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress; 1797c2c66affSColin Finck 1798c2c66affSColin Finck /* Loop the current extensions */ 1799c2c66affSColin Finck DriverExtensions = IoGetDrvObjExtension(DriverObject)-> 1800c2c66affSColin Finck ClientDriverExtension; 1801c2c66affSColin Finck while (DriverExtensions) 1802c2c66affSColin Finck { 1803c2c66affSColin Finck /* Check if the identifier matches */ 1804c2c66affSColin Finck if (DriverExtensions->ClientIdentificationAddress == 1805c2c66affSColin Finck ClientIdentificationAddress) 1806c2c66affSColin Finck { 1807c2c66affSColin Finck /* We have a collision, break out */ 1808c2c66affSColin Finck break; 1809c2c66affSColin Finck } 1810c2c66affSColin Finck 1811c2c66affSColin Finck /* Go to the next one */ 1812c2c66affSColin Finck DriverExtensions = DriverExtensions->NextExtension; 1813c2c66affSColin Finck } 1814c2c66affSColin Finck 1815c2c66affSColin Finck /* Check if we didn't collide */ 1816c2c66affSColin Finck if (!DriverExtensions) 1817c2c66affSColin Finck { 1818c2c66affSColin Finck /* Link this one in */ 1819c2c66affSColin Finck NewDriverExtension->NextExtension = 1820c2c66affSColin Finck IoGetDrvObjExtension(DriverObject)->ClientDriverExtension; 1821c2c66affSColin Finck IoGetDrvObjExtension(DriverObject)->ClientDriverExtension = 1822c2c66affSColin Finck NewDriverExtension; 1823c2c66affSColin Finck Inserted = TRUE; 1824c2c66affSColin Finck } 1825c2c66affSColin Finck 1826c2c66affSColin Finck /* Release the lock */ 1827c2c66affSColin Finck KeLowerIrql(OldIrql); 1828c2c66affSColin Finck 1829c2c66affSColin Finck /* Check if insertion failed */ 1830c2c66affSColin Finck if (!Inserted) 1831c2c66affSColin Finck { 1832c2c66affSColin Finck /* Free the entry and fail */ 1833c2c66affSColin Finck ExFreePoolWithTag(NewDriverExtension, TAG_DRIVER_EXTENSION); 1834c2c66affSColin Finck return STATUS_OBJECT_NAME_COLLISION; 1835c2c66affSColin Finck } 1836c2c66affSColin Finck 1837c2c66affSColin Finck /* Otherwise, return the pointer */ 1838c2c66affSColin Finck *DriverObjectExtension = NewDriverExtension + 1; 1839c2c66affSColin Finck return STATUS_SUCCESS; 1840c2c66affSColin Finck } 1841c2c66affSColin Finck 1842c2c66affSColin Finck /* 1843c2c66affSColin Finck * @implemented 1844c2c66affSColin Finck */ 1845c2c66affSColin Finck PVOID 1846c2c66affSColin Finck NTAPI 1847c2c66affSColin Finck IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject, 1848c2c66affSColin Finck IN PVOID ClientIdentificationAddress) 1849c2c66affSColin Finck { 1850c2c66affSColin Finck KIRQL OldIrql; 1851c2c66affSColin Finck PIO_CLIENT_EXTENSION DriverExtensions; 1852c2c66affSColin Finck 1853c2c66affSColin Finck /* Acquire lock */ 1854c2c66affSColin Finck OldIrql = KeRaiseIrqlToDpcLevel(); 1855c2c66affSColin Finck 1856c2c66affSColin Finck /* Loop the list until we find the right one */ 1857c2c66affSColin Finck DriverExtensions = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension; 1858c2c66affSColin Finck while (DriverExtensions) 1859c2c66affSColin Finck { 1860c2c66affSColin Finck /* Check for a match */ 1861c2c66affSColin Finck if (DriverExtensions->ClientIdentificationAddress == 1862c2c66affSColin Finck ClientIdentificationAddress) 1863c2c66affSColin Finck { 1864c2c66affSColin Finck /* Break out */ 1865c2c66affSColin Finck break; 1866c2c66affSColin Finck } 1867c2c66affSColin Finck 1868c2c66affSColin Finck /* Keep looping */ 1869c2c66affSColin Finck DriverExtensions = DriverExtensions->NextExtension; 1870c2c66affSColin Finck } 1871c2c66affSColin Finck 1872c2c66affSColin Finck /* Release lock */ 1873c2c66affSColin Finck KeLowerIrql(OldIrql); 1874c2c66affSColin Finck 1875c2c66affSColin Finck /* Return nothing or the extension */ 1876c2c66affSColin Finck if (!DriverExtensions) return NULL; 1877c2c66affSColin Finck return DriverExtensions + 1; 1878c2c66affSColin Finck } 1879c2c66affSColin Finck 1880c2c66affSColin Finck NTSTATUS 1881a6a3aa0fSVictor Perevertkin IopLoadDriver( 18824c95339dSVictor Perevertkin _In_ HANDLE ServiceHandle, 18834c95339dSVictor Perevertkin _Out_ PDRIVER_OBJECT *DriverObject) 1884c2c66affSColin Finck { 1885c2c66affSColin Finck UNICODE_STRING ImagePath; 1886c2c66affSColin Finck NTSTATUS Status; 1887c2c66affSColin Finck PLDR_DATA_TABLE_ENTRY ModuleObject; 1888c2c66affSColin Finck PVOID BaseAddress; 1889c2c66affSColin Finck 18904c95339dSVictor Perevertkin PKEY_VALUE_FULL_INFORMATION kvInfo; 18914c95339dSVictor Perevertkin Status = IopGetRegistryValue(ServiceHandle, L"ImagePath", &kvInfo); 18924c95339dSVictor Perevertkin if (NT_SUCCESS(Status)) 1893c2c66affSColin Finck { 18944c95339dSVictor Perevertkin if (kvInfo->Type != REG_EXPAND_SZ || kvInfo->DataLength == 0) 1895c2c66affSColin Finck { 18964c95339dSVictor Perevertkin ExFreePool(kvInfo); 18974c95339dSVictor Perevertkin return STATUS_ILL_FORMED_SERVICE_ENTRY; 1898c2c66affSColin Finck } 1899c2c66affSColin Finck 1900a82ff90bSHermès Bélusca-Maïto ImagePath.Length = kvInfo->DataLength - sizeof(UNICODE_NULL); 1901a82ff90bSHermès Bélusca-Maïto ImagePath.MaximumLength = kvInfo->DataLength; 19024c95339dSVictor Perevertkin ImagePath.Buffer = ExAllocatePoolWithTag(PagedPool, ImagePath.MaximumLength, TAG_RTLREGISTRY); 19034c95339dSVictor Perevertkin if (!ImagePath.Buffer) 1904c2c66affSColin Finck { 19054c95339dSVictor Perevertkin ExFreePool(kvInfo); 19064c95339dSVictor Perevertkin return STATUS_INSUFFICIENT_RESOURCES; 19074c95339dSVictor Perevertkin } 19084c95339dSVictor Perevertkin 19094c95339dSVictor Perevertkin RtlMoveMemory(ImagePath.Buffer, 19104c95339dSVictor Perevertkin (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset), 19114c95339dSVictor Perevertkin ImagePath.Length); 19120d28f271SHermès Bélusca-Maïto ImagePath.Buffer[ImagePath.Length / sizeof(WCHAR)] = UNICODE_NULL; 19134c95339dSVictor Perevertkin ExFreePool(kvInfo); 19144c95339dSVictor Perevertkin } 19154c95339dSVictor Perevertkin else 19164c95339dSVictor Perevertkin { 1917c2c66affSColin Finck return Status; 1918c2c66affSColin Finck } 1919c2c66affSColin Finck 1920c2c66affSColin Finck /* 1921c2c66affSColin Finck * Normalize the image path for all later processing. 1922c2c66affSColin Finck */ 19234c95339dSVictor Perevertkin Status = IopNormalizeImagePath(&ImagePath, NULL); 1924c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1925c2c66affSColin Finck { 1926c2c66affSColin Finck DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status); 1927c2c66affSColin Finck return Status; 1928c2c66affSColin Finck } 1929c2c66affSColin Finck 1930c2c66affSColin Finck DPRINT("FullImagePath: '%wZ'\n", &ImagePath); 1931c2c66affSColin Finck 1932c2c66affSColin Finck KeEnterCriticalRegion(); 1933c2c66affSColin Finck ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE); 1934c2c66affSColin Finck 1935c2c66affSColin Finck /* 1936c2c66affSColin Finck * Load the driver module 1937c2c66affSColin Finck */ 1938c2c66affSColin Finck DPRINT("Loading module from %wZ\n", &ImagePath); 1939c2c66affSColin Finck Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress); 19404c95339dSVictor Perevertkin RtlFreeUnicodeString(&ImagePath); 19414c95339dSVictor Perevertkin 1942c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1943c2c66affSColin Finck { 1944c2c66affSColin Finck DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status); 1945c2c66affSColin Finck ExReleaseResourceLite(&IopDriverLoadResource); 1946c2c66affSColin Finck KeLeaveCriticalRegion(); 1947c2c66affSColin Finck return Status; 1948c2c66affSColin Finck } 1949c2c66affSColin Finck 19504c95339dSVictor Perevertkin // Display the loading message 19514c95339dSVictor Perevertkin ULONG infoLength; 19524c95339dSVictor Perevertkin Status = ZwQueryKey(ServiceHandle, KeyBasicInformation, NULL, 0, &infoLength); 19534c95339dSVictor Perevertkin if (Status == STATUS_BUFFER_TOO_SMALL) 19544c95339dSVictor Perevertkin { 19554c95339dSVictor Perevertkin PKEY_BASIC_INFORMATION servName = ExAllocatePoolWithTag(PagedPool, infoLength, TAG_IO); 19564c95339dSVictor Perevertkin if (servName) 19574c95339dSVictor Perevertkin { 19584c95339dSVictor Perevertkin Status = ZwQueryKey(ServiceHandle, 19594c95339dSVictor Perevertkin KeyBasicInformation, 19604c95339dSVictor Perevertkin servName, 19614c95339dSVictor Perevertkin infoLength, 19624c95339dSVictor Perevertkin &infoLength); 19634c95339dSVictor Perevertkin if (NT_SUCCESS(Status)) 19644c95339dSVictor Perevertkin { 19654c95339dSVictor Perevertkin UNICODE_STRING serviceName = { 19664c95339dSVictor Perevertkin .Length = servName->NameLength, 19674c95339dSVictor Perevertkin .MaximumLength = servName->NameLength, 19684c95339dSVictor Perevertkin .Buffer = servName->Name 19694c95339dSVictor Perevertkin }; 19704c95339dSVictor Perevertkin 19714c95339dSVictor Perevertkin IopDisplayLoadingMessage(&serviceName); 19724c95339dSVictor Perevertkin } 19734c95339dSVictor Perevertkin ExFreePoolWithTag(servName, TAG_IO); 19744c95339dSVictor Perevertkin } 19754c95339dSVictor Perevertkin } 1976c2c66affSColin Finck 1977e18a32dfSVictor Perevertkin NTSTATUS driverEntryStatus; 19786f0e37b0SVictor Perevertkin Status = IopInitializeDriverModule(ModuleObject, 19794c95339dSVictor Perevertkin ServiceHandle, 1980e18a32dfSVictor Perevertkin DriverObject, 1981e18a32dfSVictor Perevertkin &driverEntryStatus); 1982c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1983c2c66affSColin Finck { 1984c2c66affSColin Finck DPRINT1("IopInitializeDriverModule() failed (Status %lx)\n", Status); 1985c2c66affSColin Finck } 1986c2c66affSColin Finck 1987c2c66affSColin Finck ExReleaseResourceLite(&IopDriverLoadResource); 1988c2c66affSColin Finck KeLeaveCriticalRegion(); 1989c2c66affSColin Finck 1990c2c66affSColin Finck return Status; 1991c2c66affSColin Finck } 1992c2c66affSColin Finck 1993a6a3aa0fSVictor Perevertkin static 1994a6a3aa0fSVictor Perevertkin VOID 1995a6a3aa0fSVictor Perevertkin NTAPI 1996a6a3aa0fSVictor Perevertkin IopLoadUnloadDriverWorker( 1997a6a3aa0fSVictor Perevertkin _Inout_ PVOID Parameter) 1998a6a3aa0fSVictor Perevertkin { 1999a6a3aa0fSVictor Perevertkin PLOAD_UNLOAD_PARAMS LoadParams = Parameter; 2000a6a3aa0fSVictor Perevertkin 2001a6a3aa0fSVictor Perevertkin ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess); 2002a6a3aa0fSVictor Perevertkin 2003a6a3aa0fSVictor Perevertkin if (LoadParams->DriverObject) 2004a6a3aa0fSVictor Perevertkin { 2005a6a3aa0fSVictor Perevertkin // unload request 2006a6a3aa0fSVictor Perevertkin LoadParams->DriverObject->DriverUnload(LoadParams->DriverObject); 2007a6a3aa0fSVictor Perevertkin LoadParams->Status = STATUS_SUCCESS; 2008a6a3aa0fSVictor Perevertkin } 2009a6a3aa0fSVictor Perevertkin else 2010a6a3aa0fSVictor Perevertkin { 2011a6a3aa0fSVictor Perevertkin // load request 20124c95339dSVictor Perevertkin HANDLE serviceHandle; 20134c95339dSVictor Perevertkin NTSTATUS status; 20144c95339dSVictor Perevertkin status = IopOpenRegistryKeyEx(&serviceHandle, NULL, LoadParams->RegistryPath, KEY_READ); 20154c95339dSVictor Perevertkin if (!NT_SUCCESS(status)) 20164c95339dSVictor Perevertkin { 20174c95339dSVictor Perevertkin LoadParams->Status = status; 20184c95339dSVictor Perevertkin } 20194c95339dSVictor Perevertkin else 20204c95339dSVictor Perevertkin { 20214c95339dSVictor Perevertkin LoadParams->Status = IopLoadDriver(serviceHandle, &LoadParams->DriverObject); 20224c95339dSVictor Perevertkin ZwClose(serviceHandle); 20234c95339dSVictor Perevertkin } 2024a6a3aa0fSVictor Perevertkin } 2025a6a3aa0fSVictor Perevertkin 2026a6a3aa0fSVictor Perevertkin if (LoadParams->SetEvent) 2027a6a3aa0fSVictor Perevertkin { 2028a6a3aa0fSVictor Perevertkin KeSetEvent(&LoadParams->Event, 0, FALSE); 2029a6a3aa0fSVictor Perevertkin } 2030a6a3aa0fSVictor Perevertkin } 2031a6a3aa0fSVictor Perevertkin 2032a6a3aa0fSVictor Perevertkin /** 2033a6a3aa0fSVictor Perevertkin * @brief Process load and unload driver operations. This is mostly for NtLoadDriver 2034a6a3aa0fSVictor Perevertkin * and NtUnloadDriver, because their code should run inside PsInitialSystemProcess 2035a6a3aa0fSVictor Perevertkin * 2036a6a3aa0fSVictor Perevertkin * @param[in] RegistryPath The registry path 2037a6a3aa0fSVictor Perevertkin * @param DriverObject The driver object 2038a6a3aa0fSVictor Perevertkin * 2039a6a3aa0fSVictor Perevertkin * @return Status of the operation 2040a6a3aa0fSVictor Perevertkin */ 2041a6a3aa0fSVictor Perevertkin NTSTATUS 2042a6a3aa0fSVictor Perevertkin IopDoLoadUnloadDriver( 20434c95339dSVictor Perevertkin _In_opt_ PUNICODE_STRING RegistryPath, 2044a6a3aa0fSVictor Perevertkin _Inout_ PDRIVER_OBJECT *DriverObject) 2045a6a3aa0fSVictor Perevertkin { 2046a6a3aa0fSVictor Perevertkin LOAD_UNLOAD_PARAMS LoadParams; 2047a6a3aa0fSVictor Perevertkin 2048a6a3aa0fSVictor Perevertkin /* Prepare parameters block */ 2049a6a3aa0fSVictor Perevertkin LoadParams.RegistryPath = RegistryPath; 2050a6a3aa0fSVictor Perevertkin LoadParams.DriverObject = *DriverObject; 2051a6a3aa0fSVictor Perevertkin 2052a6a3aa0fSVictor Perevertkin if (PsGetCurrentProcess() != PsInitialSystemProcess) 2053a6a3aa0fSVictor Perevertkin { 2054a6a3aa0fSVictor Perevertkin LoadParams.SetEvent = TRUE; 2055a6a3aa0fSVictor Perevertkin KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE); 2056a6a3aa0fSVictor Perevertkin 2057a6a3aa0fSVictor Perevertkin /* Initialize and queue a work item */ 2058a6a3aa0fSVictor Perevertkin ExInitializeWorkItem(&LoadParams.WorkItem, IopLoadUnloadDriverWorker, &LoadParams); 2059a6a3aa0fSVictor Perevertkin ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue); 2060a6a3aa0fSVictor Perevertkin 2061a6a3aa0fSVictor Perevertkin /* And wait till it completes */ 2062a6a3aa0fSVictor Perevertkin KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode, FALSE, NULL); 2063a6a3aa0fSVictor Perevertkin } 2064a6a3aa0fSVictor Perevertkin else 2065a6a3aa0fSVictor Perevertkin { 2066a6a3aa0fSVictor Perevertkin /* If we're already in a system process, call it right here */ 2067a6a3aa0fSVictor Perevertkin LoadParams.SetEvent = FALSE; 2068a6a3aa0fSVictor Perevertkin IopLoadUnloadDriverWorker(&LoadParams); 2069a6a3aa0fSVictor Perevertkin } 2070a6a3aa0fSVictor Perevertkin 2071a6a3aa0fSVictor Perevertkin return LoadParams.Status; 2072a6a3aa0fSVictor Perevertkin } 2073a6a3aa0fSVictor Perevertkin 2074c2c66affSColin Finck /* 2075c2c66affSColin Finck * NtLoadDriver 2076c2c66affSColin Finck * 2077c2c66affSColin Finck * Loads a device driver. 2078c2c66affSColin Finck * 2079c2c66affSColin Finck * Parameters 2080c2c66affSColin Finck * DriverServiceName 2081c2c66affSColin Finck * Name of the service to load (registry key). 2082c2c66affSColin Finck * 2083c2c66affSColin Finck * Return Value 2084c2c66affSColin Finck * Status 2085c2c66affSColin Finck * 2086c2c66affSColin Finck * Status 2087c2c66affSColin Finck * implemented 2088c2c66affSColin Finck */ 2089c2c66affSColin Finck NTSTATUS NTAPI 2090c2c66affSColin Finck NtLoadDriver(IN PUNICODE_STRING DriverServiceName) 2091c2c66affSColin Finck { 209244511f08SHermès Bélusca-Maïto UNICODE_STRING CapturedServiceName = { 0, 0, NULL }; 2093c2c66affSColin Finck KPROCESSOR_MODE PreviousMode; 2094c2c66affSColin Finck PDRIVER_OBJECT DriverObject; 2095c2c66affSColin Finck NTSTATUS Status; 2096c2c66affSColin Finck 2097c2c66affSColin Finck PAGED_CODE(); 2098c2c66affSColin Finck 2099c2c66affSColin Finck PreviousMode = KeGetPreviousMode(); 2100c2c66affSColin Finck 210144511f08SHermès Bélusca-Maïto /* Need the appropriate priviliege */ 2102c2c66affSColin Finck if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode)) 2103c2c66affSColin Finck { 210444511f08SHermès Bélusca-Maïto DPRINT1("No load privilege!\n"); 2105c2c66affSColin Finck return STATUS_PRIVILEGE_NOT_HELD; 2106c2c66affSColin Finck } 2107c2c66affSColin Finck 210844511f08SHermès Bélusca-Maïto /* Capture the service name */ 210944511f08SHermès Bélusca-Maïto Status = ProbeAndCaptureUnicodeString(&CapturedServiceName, 2110c2c66affSColin Finck PreviousMode, 2111c2c66affSColin Finck DriverServiceName); 2112c2c66affSColin Finck if (!NT_SUCCESS(Status)) 2113a6a3aa0fSVictor Perevertkin { 2114c2c66affSColin Finck return Status; 2115a6a3aa0fSVictor Perevertkin } 2116c2c66affSColin Finck 211744511f08SHermès Bélusca-Maïto DPRINT("NtLoadDriver('%wZ')\n", &CapturedServiceName); 2118c2c66affSColin Finck 2119a748350fSHermès Bélusca-Maïto /* We need a service name */ 2120a748350fSHermès Bélusca-Maïto if (CapturedServiceName.Length == 0 || CapturedServiceName.Buffer == NULL) 2121a748350fSHermès Bélusca-Maïto { 2122a748350fSHermès Bélusca-Maïto ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 2123a748350fSHermès Bélusca-Maïto return STATUS_INVALID_PARAMETER; 2124a748350fSHermès Bélusca-Maïto } 2125a748350fSHermès Bélusca-Maïto 2126c2c66affSColin Finck /* Load driver and call its entry point */ 2127c2c66affSColin Finck DriverObject = NULL; 2128a6a3aa0fSVictor Perevertkin Status = IopDoLoadUnloadDriver(&CapturedServiceName, &DriverObject); 2129c2c66affSColin Finck 213044511f08SHermès Bélusca-Maïto ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 2131c2c66affSColin Finck return Status; 2132c2c66affSColin Finck } 2133c2c66affSColin Finck 2134c2c66affSColin Finck /* 2135c2c66affSColin Finck * NtUnloadDriver 2136c2c66affSColin Finck * 2137c2c66affSColin Finck * Unloads a legacy device driver. 2138c2c66affSColin Finck * 2139c2c66affSColin Finck * Parameters 2140c2c66affSColin Finck * DriverServiceName 2141c2c66affSColin Finck * Name of the service to unload (registry key). 2142c2c66affSColin Finck * 2143c2c66affSColin Finck * Return Value 2144c2c66affSColin Finck * Status 2145c2c66affSColin Finck * 2146c2c66affSColin Finck * Status 2147c2c66affSColin Finck * implemented 2148c2c66affSColin Finck */ 2149c2c66affSColin Finck 2150c2c66affSColin Finck NTSTATUS NTAPI 2151c2c66affSColin Finck NtUnloadDriver(IN PUNICODE_STRING DriverServiceName) 2152c2c66affSColin Finck { 2153c2c66affSColin Finck return IopUnloadDriver(DriverServiceName, FALSE); 2154c2c66affSColin Finck } 2155c2c66affSColin Finck 2156c2c66affSColin Finck /* EOF */ 2157