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