xref: /reactos/ntoskrnl/io/iomgr/driver.c (revision daf9743c)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:         ReactOS Kernel
3c2c66affSColin Finck  * LICENSE:         GPL - See COPYING in the top level directory
4c2c66affSColin Finck  * FILE:            ntoskrnl/io/iomgr/driver.c
5c2c66affSColin Finck  * PURPOSE:         Driver Object Management
6c2c66affSColin Finck  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7c2c66affSColin Finck  *                  Filip Navara (navaraf@reactos.org)
8c2c66affSColin Finck  *                  Herv� Poussineau (hpoussin@reactos.org)
9c2c66affSColin Finck  */
10c2c66affSColin Finck 
11c2c66affSColin Finck /* INCLUDES *******************************************************************/
12c2c66affSColin Finck 
13c2c66affSColin Finck #include <ntoskrnl.h>
14c2c66affSColin Finck #define NDEBUG
15c2c66affSColin Finck #include <debug.h>
16c2c66affSColin Finck 
17c2c66affSColin Finck /* GLOBALS ********************************************************************/
18c2c66affSColin Finck 
19c2c66affSColin Finck ERESOURCE IopDriverLoadResource;
20c2c66affSColin Finck 
21c2c66affSColin Finck LIST_ENTRY DriverReinitListHead;
22c2c66affSColin Finck KSPIN_LOCK DriverReinitListLock;
23c2c66affSColin Finck PLIST_ENTRY DriverReinitTailEntry;
24c2c66affSColin Finck 
25c2c66affSColin Finck PLIST_ENTRY DriverBootReinitTailEntry;
26c2c66affSColin Finck LIST_ENTRY DriverBootReinitListHead;
27c2c66affSColin Finck KSPIN_LOCK DriverBootReinitListLock;
28c2c66affSColin Finck 
29c2c66affSColin Finck UNICODE_STRING IopHardwareDatabaseKey =
30c2c66affSColin Finck    RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
31c2c66affSColin Finck 
32c2c66affSColin Finck POBJECT_TYPE IoDriverObjectType = NULL;
33c2c66affSColin Finck 
34c2c66affSColin Finck #define TAG_RTLREGISTRY 'vrqR'
35c2c66affSColin Finck 
36c2c66affSColin Finck extern BOOLEAN ExpInTextModeSetup;
37c2c66affSColin Finck extern BOOLEAN PnpSystemInit;
38c2c66affSColin Finck 
39c2c66affSColin Finck USHORT IopGroupIndex;
40c2c66affSColin Finck PLIST_ENTRY IopGroupTable;
41c2c66affSColin Finck 
42c2c66affSColin Finck /* PRIVATE FUNCTIONS **********************************************************/
43c2c66affSColin Finck 
44c2c66affSColin Finck NTSTATUS
45c2c66affSColin Finck NTAPI
46c2c66affSColin Finck IopInvalidDeviceRequest(
47c2c66affSColin Finck     PDEVICE_OBJECT DeviceObject,
48c2c66affSColin Finck     PIRP Irp)
49c2c66affSColin Finck {
50c2c66affSColin Finck     Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
51c2c66affSColin Finck     Irp->IoStatus.Information = 0;
52c2c66affSColin Finck     IoCompleteRequest(Irp, IO_NO_INCREMENT);
53c2c66affSColin Finck     return STATUS_INVALID_DEVICE_REQUEST;
54c2c66affSColin Finck }
55c2c66affSColin Finck 
56c2c66affSColin Finck VOID
57c2c66affSColin Finck NTAPI
58c2c66affSColin Finck IopDeleteDriver(IN PVOID ObjectBody)
59c2c66affSColin Finck {
60c2c66affSColin Finck     PDRIVER_OBJECT DriverObject = ObjectBody;
61c2c66affSColin Finck     PIO_CLIENT_EXTENSION DriverExtension, NextDriverExtension;
62c2c66affSColin Finck     PAGED_CODE();
63c2c66affSColin Finck 
64c2c66affSColin Finck     DPRINT1("Deleting driver object '%wZ'\n", &DriverObject->DriverName);
65c2c66affSColin Finck 
66c2c66affSColin Finck     /* There must be no device objects remaining at this point */
67c2c66affSColin Finck     ASSERT(!DriverObject->DeviceObject);
68c2c66affSColin Finck 
69c2c66affSColin Finck     /* Get the extension and loop them */
70c2c66affSColin Finck     DriverExtension = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
71c2c66affSColin Finck     while (DriverExtension)
72c2c66affSColin Finck     {
73c2c66affSColin Finck         /* Get the next one */
74c2c66affSColin Finck         NextDriverExtension = DriverExtension->NextExtension;
75c2c66affSColin Finck         ExFreePoolWithTag(DriverExtension, TAG_DRIVER_EXTENSION);
76c2c66affSColin Finck 
77c2c66affSColin Finck         /* Move on */
78c2c66affSColin Finck         DriverExtension = NextDriverExtension;
79c2c66affSColin Finck     }
80c2c66affSColin Finck 
81c2c66affSColin Finck     /* Check if the driver image is still loaded */
82c2c66affSColin Finck     if (DriverObject->DriverSection)
83c2c66affSColin Finck     {
84c2c66affSColin Finck         /* Unload it */
85c2c66affSColin Finck         MmUnloadSystemImage(DriverObject->DriverSection);
86c2c66affSColin Finck     }
87c2c66affSColin Finck 
88c2c66affSColin Finck     /* Check if it has a name */
89c2c66affSColin Finck     if (DriverObject->DriverName.Buffer)
90c2c66affSColin Finck     {
91c2c66affSColin Finck         /* Free it */
92c2c66affSColin Finck         ExFreePool(DriverObject->DriverName.Buffer);
93c2c66affSColin Finck     }
94c2c66affSColin Finck 
95c2c66affSColin Finck     /* Check if it has a service key name */
96c2c66affSColin Finck     if (DriverObject->DriverExtension->ServiceKeyName.Buffer)
97c2c66affSColin Finck     {
98c2c66affSColin Finck         /* Free it */
99c2c66affSColin Finck         ExFreePool(DriverObject->DriverExtension->ServiceKeyName.Buffer);
100c2c66affSColin Finck     }
101c2c66affSColin Finck }
102c2c66affSColin Finck 
103c2c66affSColin Finck NTSTATUS
104c2c66affSColin Finck FASTCALL
105c2c66affSColin Finck IopGetDriverObject(
106c2c66affSColin Finck     PDRIVER_OBJECT *DriverObject,
107c2c66affSColin Finck     PUNICODE_STRING ServiceName,
108c2c66affSColin Finck     BOOLEAN FileSystem)
109c2c66affSColin Finck {
110c2c66affSColin Finck     PDRIVER_OBJECT Object;
111c2c66affSColin Finck     WCHAR NameBuffer[MAX_PATH];
112c2c66affSColin Finck     UNICODE_STRING DriverName;
113c2c66affSColin Finck     NTSTATUS Status;
114c2c66affSColin Finck 
115c2c66affSColin Finck     DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
116c2c66affSColin Finck            DriverObject, ServiceName, FileSystem);
117c2c66affSColin Finck 
118c2c66affSColin Finck     ASSERT(ExIsResourceAcquiredExclusiveLite(&IopDriverLoadResource));
119c2c66affSColin Finck     *DriverObject = NULL;
120c2c66affSColin Finck 
121c2c66affSColin Finck     /* Create ModuleName string */
122c2c66affSColin Finck     if (ServiceName == NULL || ServiceName->Buffer == NULL)
123c2c66affSColin Finck         /* We don't know which DriverObject we have to open */
124c2c66affSColin Finck         return STATUS_INVALID_PARAMETER_2;
125c2c66affSColin Finck 
126c2c66affSColin Finck     DriverName.Buffer = NameBuffer;
127c2c66affSColin Finck     DriverName.Length = 0;
128c2c66affSColin Finck     DriverName.MaximumLength = sizeof(NameBuffer);
129c2c66affSColin Finck 
130c2c66affSColin Finck     if (FileSystem != FALSE)
131c2c66affSColin Finck         RtlAppendUnicodeToString(&DriverName, FILESYSTEM_ROOT_NAME);
132c2c66affSColin Finck     else
133c2c66affSColin Finck         RtlAppendUnicodeToString(&DriverName, DRIVER_ROOT_NAME);
134c2c66affSColin Finck     RtlAppendUnicodeStringToString(&DriverName, ServiceName);
135c2c66affSColin Finck 
136c2c66affSColin Finck     DPRINT("Driver name: '%wZ'\n", &DriverName);
137c2c66affSColin Finck 
138c2c66affSColin Finck     /* Open driver object */
139c2c66affSColin Finck     Status = ObReferenceObjectByName(&DriverName,
140c2c66affSColin Finck                                      OBJ_OPENIF | OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, /* Attributes */
141c2c66affSColin Finck                                      NULL, /* PassedAccessState */
142c2c66affSColin Finck                                      0, /* DesiredAccess */
143c2c66affSColin Finck                                      IoDriverObjectType,
144c2c66affSColin Finck                                      KernelMode,
145c2c66affSColin Finck                                      NULL, /* ParseContext */
146c2c66affSColin Finck                                      (PVOID*)&Object);
147c2c66affSColin Finck     if (!NT_SUCCESS(Status))
148c2c66affSColin Finck     {
149c2c66affSColin Finck         DPRINT("Failed to reference driver object, status=0x%08x\n", Status);
150c2c66affSColin Finck         return Status;
151c2c66affSColin Finck     }
152c2c66affSColin Finck 
153c2c66affSColin Finck     *DriverObject = Object;
154c2c66affSColin Finck 
155c2c66affSColin Finck     DPRINT("Driver Object: %p\n", Object);
156c2c66affSColin Finck 
157c2c66affSColin Finck     return STATUS_SUCCESS;
158c2c66affSColin Finck }
159c2c66affSColin Finck 
160c2c66affSColin Finck /*
161c2c66affSColin Finck  * RETURNS
162c2c66affSColin Finck  *  TRUE if String2 contains String1 as a suffix.
163c2c66affSColin Finck  */
164c2c66affSColin Finck BOOLEAN
165c2c66affSColin Finck NTAPI
166c2c66affSColin Finck IopSuffixUnicodeString(
167c2c66affSColin Finck     IN PCUNICODE_STRING String1,
168c2c66affSColin Finck     IN PCUNICODE_STRING String2)
169c2c66affSColin Finck {
170c2c66affSColin Finck     PWCHAR pc1;
171c2c66affSColin Finck     PWCHAR pc2;
172c2c66affSColin Finck     ULONG Length;
173c2c66affSColin Finck 
174c2c66affSColin Finck     if (String2->Length < String1->Length)
175c2c66affSColin Finck         return FALSE;
176c2c66affSColin Finck 
177c2c66affSColin Finck     Length = String1->Length / 2;
178c2c66affSColin Finck     pc1 = String1->Buffer;
179c2c66affSColin Finck     pc2 = &String2->Buffer[String2->Length / sizeof(WCHAR) - Length];
180c2c66affSColin Finck 
181c2c66affSColin Finck     if (pc1 && pc2)
182c2c66affSColin Finck     {
183c2c66affSColin Finck         while (Length--)
184c2c66affSColin Finck         {
185c2c66affSColin Finck             if( *pc1++ != *pc2++ )
186c2c66affSColin Finck                 return FALSE;
187c2c66affSColin Finck         }
188c2c66affSColin Finck         return TRUE;
189c2c66affSColin Finck     }
190c2c66affSColin Finck     return FALSE;
191c2c66affSColin Finck }
192c2c66affSColin Finck 
193c2c66affSColin Finck /*
194c2c66affSColin Finck  * IopDisplayLoadingMessage
195c2c66affSColin Finck  *
196c2c66affSColin Finck  * Display 'Loading XXX...' message.
197c2c66affSColin Finck  */
198c2c66affSColin Finck VOID
199c2c66affSColin Finck FASTCALL
200c2c66affSColin Finck IopDisplayLoadingMessage(PUNICODE_STRING ServiceName)
201c2c66affSColin Finck {
202c2c66affSColin Finck     CHAR TextBuffer[256];
203c2c66affSColin Finck     UNICODE_STRING DotSys = RTL_CONSTANT_STRING(L".SYS");
204c2c66affSColin Finck 
205c2c66affSColin Finck     if (ExpInTextModeSetup) return;
206c2c66affSColin Finck     if (!KeLoaderBlock) return;
207c2c66affSColin Finck     RtlUpcaseUnicodeString(ServiceName, ServiceName, FALSE);
208c2c66affSColin Finck     snprintf(TextBuffer, sizeof(TextBuffer),
209c2c66affSColin Finck             "%s%sSystem32\\Drivers\\%wZ%s\r\n",
210c2c66affSColin Finck             KeLoaderBlock->ArcBootDeviceName,
211c2c66affSColin Finck             KeLoaderBlock->NtBootPathName,
212c2c66affSColin Finck             ServiceName,
213c2c66affSColin Finck             IopSuffixUnicodeString(&DotSys, ServiceName) ? "" : ".SYS");
214c2c66affSColin Finck     HalDisplayString(TextBuffer);
215c2c66affSColin Finck }
216c2c66affSColin Finck 
217c2c66affSColin Finck /*
218c2c66affSColin Finck  * IopNormalizeImagePath
219c2c66affSColin Finck  *
220c2c66affSColin Finck  * Normalize an image path to contain complete path.
221c2c66affSColin Finck  *
222c2c66affSColin Finck  * Parameters
223c2c66affSColin Finck  *    ImagePath
224c2c66affSColin Finck  *       The input path and on exit the result path. ImagePath.Buffer
225c2c66affSColin Finck  *       must be allocated by ExAllocatePool on input. Caller is responsible
226c2c66affSColin Finck  *       for freeing the buffer when it's no longer needed.
227c2c66affSColin Finck  *
228c2c66affSColin Finck  *    ServiceName
229c2c66affSColin Finck  *       Name of the service that ImagePath belongs to.
230c2c66affSColin Finck  *
231c2c66affSColin Finck  * Return Value
232c2c66affSColin Finck  *    Status
233c2c66affSColin Finck  *
234c2c66affSColin Finck  * Remarks
235c2c66affSColin Finck  *    The input image path isn't freed on error.
236c2c66affSColin Finck  */
237c2c66affSColin Finck NTSTATUS
238c2c66affSColin Finck FASTCALL
239c2c66affSColin Finck IopNormalizeImagePath(
240c2c66affSColin Finck     _Inout_ _When_(return>=0, _At_(ImagePath->Buffer, _Post_notnull_ __drv_allocatesMem(Mem)))
241c2c66affSColin Finck          PUNICODE_STRING ImagePath,
242c2c66affSColin Finck     _In_ PUNICODE_STRING ServiceName)
243c2c66affSColin Finck {
244c2c66affSColin Finck     UNICODE_STRING SystemRootString = RTL_CONSTANT_STRING(L"\\SystemRoot\\");
245c2c66affSColin Finck     UNICODE_STRING DriversPathString = RTL_CONSTANT_STRING(L"\\SystemRoot\\System32\\drivers\\");
246c2c66affSColin Finck     UNICODE_STRING DotSysString = RTL_CONSTANT_STRING(L".sys");
247c2c66affSColin Finck     UNICODE_STRING InputImagePath;
248c2c66affSColin Finck 
249c2c66affSColin Finck     DPRINT("Normalizing image path '%wZ' for service '%wZ'\n", ImagePath, ServiceName);
250c2c66affSColin Finck 
251c2c66affSColin Finck     InputImagePath = *ImagePath;
252c2c66affSColin Finck     if (InputImagePath.Length == 0)
253c2c66affSColin Finck     {
254c2c66affSColin Finck         ImagePath->Length = 0;
255c2c66affSColin Finck         ImagePath->MaximumLength = DriversPathString.Length +
256c2c66affSColin Finck                                    ServiceName->Length +
257c2c66affSColin Finck                                    DotSysString.Length +
258c2c66affSColin Finck                                    sizeof(UNICODE_NULL);
259c2c66affSColin Finck         ImagePath->Buffer = ExAllocatePoolWithTag(NonPagedPool,
260c2c66affSColin Finck                                                   ImagePath->MaximumLength,
261c2c66affSColin Finck                                                   TAG_IO);
262c2c66affSColin Finck         if (ImagePath->Buffer == NULL)
263c2c66affSColin Finck             return STATUS_NO_MEMORY;
264c2c66affSColin Finck 
265c2c66affSColin Finck         RtlCopyUnicodeString(ImagePath, &DriversPathString);
266c2c66affSColin Finck         RtlAppendUnicodeStringToString(ImagePath, ServiceName);
267c2c66affSColin Finck         RtlAppendUnicodeStringToString(ImagePath, &DotSysString);
268c2c66affSColin Finck     }
269c2c66affSColin Finck     else if (InputImagePath.Buffer[0] != L'\\')
270c2c66affSColin Finck     {
271c2c66affSColin Finck         ImagePath->Length = 0;
272c2c66affSColin Finck         ImagePath->MaximumLength = SystemRootString.Length +
273c2c66affSColin Finck                                    InputImagePath.Length +
274c2c66affSColin Finck                                    sizeof(UNICODE_NULL);
275c2c66affSColin Finck         ImagePath->Buffer = ExAllocatePoolWithTag(NonPagedPool,
276c2c66affSColin Finck                                                   ImagePath->MaximumLength,
277c2c66affSColin Finck                                                   TAG_IO);
278c2c66affSColin Finck         if (ImagePath->Buffer == NULL)
279c2c66affSColin Finck             return STATUS_NO_MEMORY;
280c2c66affSColin Finck 
281c2c66affSColin Finck         RtlCopyUnicodeString(ImagePath, &SystemRootString);
282c2c66affSColin Finck         RtlAppendUnicodeStringToString(ImagePath, &InputImagePath);
283c2c66affSColin Finck 
284c2c66affSColin Finck         /* Free caller's string */
285c2c66affSColin Finck         ExFreePoolWithTag(InputImagePath.Buffer, TAG_RTLREGISTRY);
286c2c66affSColin Finck     }
287c2c66affSColin Finck 
288c2c66affSColin Finck     DPRINT("Normalized image path is '%wZ' for service '%wZ'\n", ImagePath, ServiceName);
289c2c66affSColin Finck 
290c2c66affSColin Finck     return STATUS_SUCCESS;
291c2c66affSColin Finck }
292c2c66affSColin Finck 
293c2c66affSColin Finck /*
294c2c66affSColin Finck  * IopLoadServiceModule
295c2c66affSColin Finck  *
296c2c66affSColin Finck  * Load a module specified by registry settings for service.
297c2c66affSColin Finck  *
298c2c66affSColin Finck  * Parameters
299c2c66affSColin Finck  *    ServiceName
300c2c66affSColin Finck  *       Name of the service to load.
301c2c66affSColin Finck  *
302c2c66affSColin Finck  * Return Value
303c2c66affSColin Finck  *    Status
304c2c66affSColin Finck  */
305c2c66affSColin Finck NTSTATUS
306c2c66affSColin Finck FASTCALL
307c2c66affSColin Finck IopLoadServiceModule(
308c2c66affSColin Finck     IN PUNICODE_STRING ServiceName,
309c2c66affSColin Finck     OUT PLDR_DATA_TABLE_ENTRY *ModuleObject)
310c2c66affSColin Finck {
311c2c66affSColin Finck     RTL_QUERY_REGISTRY_TABLE QueryTable[3];
312c2c66affSColin Finck     ULONG ServiceStart;
313c2c66affSColin Finck     UNICODE_STRING ServiceImagePath, CCSName;
314c2c66affSColin Finck     NTSTATUS Status;
315c2c66affSColin Finck     HANDLE CCSKey, ServiceKey;
316c2c66affSColin Finck     PVOID BaseAddress;
317c2c66affSColin Finck 
318c2c66affSColin Finck     ASSERT(ExIsResourceAcquiredExclusiveLite(&IopDriverLoadResource));
319c2c66affSColin Finck     ASSERT(ServiceName->Length);
320c2c66affSColin Finck     DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName, ModuleObject);
321c2c66affSColin Finck 
322c2c66affSColin Finck     if (ExpInTextModeSetup)
323c2c66affSColin Finck     {
324c2c66affSColin Finck         /* We have no registry, but luckily we know where all the drivers are */
325cb69c4c6SHermès Bélusca-Maïto         DPRINT1("IopLoadServiceModule(%wZ, 0x%p) called in ExpInTextModeSetup mode...\n", ServiceName, ModuleObject);
326c2c66affSColin Finck 
327c2c66affSColin Finck         /* ServiceStart < 4 is all that matters */
328c2c66affSColin Finck         ServiceStart = 0;
329c2c66affSColin Finck 
330c2c66affSColin Finck         /* IopNormalizeImagePath will do all of the work for us if we give it an empty string */
331c2c66affSColin Finck         RtlInitEmptyUnicodeString(&ServiceImagePath, NULL, 0);
332c2c66affSColin Finck     }
333c2c66affSColin Finck     else
334c2c66affSColin Finck     {
335c2c66affSColin Finck         /* Open CurrentControlSet */
336c2c66affSColin Finck         RtlInitUnicodeString(&CCSName,
337c2c66affSColin Finck                              L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
338c2c66affSColin Finck         Status = IopOpenRegistryKeyEx(&CCSKey, NULL, &CCSName, KEY_READ);
339c2c66affSColin Finck         if (!NT_SUCCESS(Status))
340c2c66affSColin Finck         {
341c2c66affSColin Finck             DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
342c2c66affSColin Finck                     &CCSName, Status);
343c2c66affSColin Finck             return Status;
344c2c66affSColin Finck         }
345c2c66affSColin Finck 
346c2c66affSColin Finck         /* Open service key */
347c2c66affSColin Finck         Status = IopOpenRegistryKeyEx(&ServiceKey, CCSKey, ServiceName, KEY_READ);
348c2c66affSColin Finck         if (!NT_SUCCESS(Status))
349c2c66affSColin Finck         {
350c2c66affSColin Finck             DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
351c2c66affSColin Finck                     ServiceName, Status);
352c2c66affSColin Finck             ZwClose(CCSKey);
353c2c66affSColin Finck             return Status;
354c2c66affSColin Finck         }
355c2c66affSColin Finck 
356c2c66affSColin Finck         /*
357c2c66affSColin Finck          * Get information about the service.
358c2c66affSColin Finck          */
359c2c66affSColin Finck         RtlZeroMemory(QueryTable, sizeof(QueryTable));
360c2c66affSColin Finck 
361c2c66affSColin Finck         RtlInitUnicodeString(&ServiceImagePath, NULL);
362c2c66affSColin Finck 
363c2c66affSColin Finck         QueryTable[0].Name = L"Start";
364c2c66affSColin Finck         QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
365c2c66affSColin Finck         QueryTable[0].EntryContext = &ServiceStart;
366c2c66affSColin Finck 
367c2c66affSColin Finck         QueryTable[1].Name = L"ImagePath";
368c2c66affSColin Finck         QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
369c2c66affSColin Finck         QueryTable[1].EntryContext = &ServiceImagePath;
370c2c66affSColin Finck 
371c2c66affSColin Finck         Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
372c2c66affSColin Finck                                         (PWSTR)ServiceKey,
373c2c66affSColin Finck                                         QueryTable,
374c2c66affSColin Finck                                         NULL,
375c2c66affSColin Finck                                         NULL);
376c2c66affSColin Finck 
377c2c66affSColin Finck         ZwClose(ServiceKey);
378c2c66affSColin Finck         ZwClose(CCSKey);
379c2c66affSColin Finck 
380c2c66affSColin Finck         if (!NT_SUCCESS(Status))
381c2c66affSColin Finck         {
382c2c66affSColin Finck             DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
383c2c66affSColin Finck             return Status;
384c2c66affSColin Finck         }
385c2c66affSColin Finck     }
386c2c66affSColin Finck 
387c2c66affSColin Finck     /*
388c2c66affSColin Finck      * Normalize the image path for all later processing.
389c2c66affSColin Finck      */
390c2c66affSColin Finck     Status = IopNormalizeImagePath(&ServiceImagePath, ServiceName);
391c2c66affSColin Finck 
392c2c66affSColin Finck     if (!NT_SUCCESS(Status))
393c2c66affSColin Finck     {
394c2c66affSColin Finck         DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
395c2c66affSColin Finck         return Status;
396c2c66affSColin Finck     }
397c2c66affSColin Finck 
398c2c66affSColin Finck     /*
399c2c66affSColin Finck      * Case for disabled drivers
400c2c66affSColin Finck      */
401c2c66affSColin Finck     if (ServiceStart >= 4)
402c2c66affSColin Finck     {
403c2c66affSColin Finck         /* We can't load this */
404c2c66affSColin Finck         Status = STATUS_DRIVER_UNABLE_TO_LOAD;
405c2c66affSColin Finck     }
406c2c66affSColin Finck     else
407c2c66affSColin Finck     {
408c2c66affSColin Finck         DPRINT("Loading module from %wZ\n", &ServiceImagePath);
409c2c66affSColin Finck         Status = MmLoadSystemImage(&ServiceImagePath, NULL, NULL, 0, (PVOID)ModuleObject, &BaseAddress);
410c2c66affSColin Finck         if (NT_SUCCESS(Status))
411c2c66affSColin Finck         {
412c2c66affSColin Finck             IopDisplayLoadingMessage(ServiceName);
413c2c66affSColin Finck         }
414c2c66affSColin Finck     }
415c2c66affSColin Finck 
416c2c66affSColin Finck     ExFreePool(ServiceImagePath.Buffer);
417c2c66affSColin Finck 
418c2c66affSColin Finck     /*
419c2c66affSColin Finck      * Now check if the module was loaded successfully.
420c2c66affSColin Finck      */
421c2c66affSColin Finck     if (!NT_SUCCESS(Status))
422c2c66affSColin Finck     {
423c2c66affSColin Finck         DPRINT("Module loading failed (Status %x)\n", Status);
424c2c66affSColin Finck     }
425c2c66affSColin Finck 
426c2c66affSColin Finck     DPRINT("Module loading (Status %x)\n", Status);
427c2c66affSColin Finck 
428c2c66affSColin Finck     return Status;
429c2c66affSColin Finck }
430c2c66affSColin Finck 
431c2c66affSColin Finck VOID
432c2c66affSColin Finck NTAPI
433c2c66affSColin Finck MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry);
434c2c66affSColin Finck 
435c2c66affSColin Finck /*
436c2c66affSColin Finck  * IopInitializeDriverModule
437c2c66affSColin Finck  *
438c2c66affSColin Finck  * Initialize a loaded driver.
439c2c66affSColin Finck  *
440c2c66affSColin Finck  * Parameters
441c2c66affSColin Finck  *    DeviceNode
442c2c66affSColin Finck  *       Pointer to device node.
443c2c66affSColin Finck  *
444c2c66affSColin Finck  *    ModuleObject
445c2c66affSColin Finck  *       Module object representing the driver. It can be retrieve by
446c2c66affSColin Finck  *       IopLoadServiceModule.
447c2c66affSColin Finck  *
448c2c66affSColin Finck  *    ServiceName
449c2c66affSColin Finck  *       Name of the service (as in registry).
450c2c66affSColin Finck  *
451c2c66affSColin Finck  *    FileSystemDriver
452c2c66affSColin Finck  *       Set to TRUE for file system drivers.
453c2c66affSColin Finck  *
454c2c66affSColin Finck  *    DriverObject
455c2c66affSColin Finck  *       On successful return this contains the driver object representing
456c2c66affSColin Finck  *       the loaded driver.
457c2c66affSColin Finck  */
458c2c66affSColin Finck NTSTATUS
459c2c66affSColin Finck FASTCALL
460c2c66affSColin Finck IopInitializeDriverModule(
461c2c66affSColin Finck     IN PDEVICE_NODE DeviceNode,
462c2c66affSColin Finck     IN PLDR_DATA_TABLE_ENTRY ModuleObject,
463c2c66affSColin Finck     IN PUNICODE_STRING ServiceName,
464c2c66affSColin Finck     IN BOOLEAN FileSystemDriver,
465c2c66affSColin Finck     OUT PDRIVER_OBJECT *DriverObject)
466c2c66affSColin Finck {
467c2c66affSColin Finck     static const WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
468c2c66affSColin Finck     UNICODE_STRING DriverName;
469c2c66affSColin Finck     UNICODE_STRING RegistryKey;
470c2c66affSColin Finck     PDRIVER_INITIALIZE DriverEntry;
471c2c66affSColin Finck     PDRIVER_OBJECT Driver;
472c2c66affSColin Finck     NTSTATUS Status;
473c2c66affSColin Finck 
474c2c66affSColin Finck     DriverEntry = ModuleObject->EntryPoint;
475c2c66affSColin Finck 
476c2c66affSColin Finck     if (ServiceName != NULL && ServiceName->Length != 0)
477c2c66affSColin Finck     {
478c2c66affSColin Finck         RegistryKey.Length = 0;
479c2c66affSColin Finck         RegistryKey.MaximumLength = sizeof(ServicesKeyName) + ServiceName->Length;
480c2c66affSColin Finck         RegistryKey.Buffer = ExAllocatePoolWithTag(PagedPool,
481c2c66affSColin Finck                                                    RegistryKey.MaximumLength,
482c2c66affSColin Finck                                                    TAG_IO);
483c2c66affSColin Finck         if (RegistryKey.Buffer == NULL)
484c2c66affSColin Finck         {
485c2c66affSColin Finck             return STATUS_INSUFFICIENT_RESOURCES;
486c2c66affSColin Finck         }
487c2c66affSColin Finck         RtlAppendUnicodeToString(&RegistryKey, ServicesKeyName);
488c2c66affSColin Finck         RtlAppendUnicodeStringToString(&RegistryKey, ServiceName);
489c2c66affSColin Finck     }
490c2c66affSColin Finck     else
491c2c66affSColin Finck     {
492c2c66affSColin Finck         RtlInitEmptyUnicodeString(&RegistryKey, NULL, 0);
493c2c66affSColin Finck     }
494c2c66affSColin Finck 
495c2c66affSColin Finck     /* Create ModuleName string */
496c2c66affSColin Finck     if (ServiceName && ServiceName->Length > 0)
497c2c66affSColin Finck     {
498c2c66affSColin Finck         DriverName.Length = 0;
499c2c66affSColin Finck         DriverName.MaximumLength = sizeof(FILESYSTEM_ROOT_NAME) + ServiceName->Length;
500c2c66affSColin Finck         DriverName.Buffer = ExAllocatePoolWithTag(PagedPool,
501c2c66affSColin Finck                                                   DriverName.MaximumLength,
502c2c66affSColin Finck                                                   TAG_IO);
503c2c66affSColin Finck         if (DriverName.Buffer == NULL)
504c2c66affSColin Finck         {
505c2c66affSColin Finck             RtlFreeUnicodeString(&RegistryKey);
506c2c66affSColin Finck             return STATUS_INSUFFICIENT_RESOURCES;
507c2c66affSColin Finck         }
508c2c66affSColin Finck 
509c2c66affSColin Finck         if (FileSystemDriver != FALSE)
510c2c66affSColin Finck             RtlAppendUnicodeToString(&DriverName, FILESYSTEM_ROOT_NAME);
511c2c66affSColin Finck         else
512c2c66affSColin Finck             RtlAppendUnicodeToString(&DriverName, DRIVER_ROOT_NAME);
513c2c66affSColin Finck         RtlAppendUnicodeStringToString(&DriverName, ServiceName);
514c2c66affSColin Finck 
515c2c66affSColin Finck         DPRINT("Driver name: '%wZ'\n", &DriverName);
516c2c66affSColin Finck     }
517c2c66affSColin Finck     else
518c2c66affSColin Finck     {
519c2c66affSColin Finck         RtlInitEmptyUnicodeString(&DriverName, NULL, 0);
520c2c66affSColin Finck     }
521c2c66affSColin Finck 
522c2c66affSColin Finck     Status = IopCreateDriver(DriverName.Length > 0 ? &DriverName : NULL,
523c2c66affSColin Finck                              DriverEntry,
524c2c66affSColin Finck                              &RegistryKey,
525c2c66affSColin Finck                              ServiceName,
526c2c66affSColin Finck                              ModuleObject,
527c2c66affSColin Finck                              &Driver);
528c2c66affSColin Finck     RtlFreeUnicodeString(&RegistryKey);
529c2c66affSColin Finck     RtlFreeUnicodeString(&DriverName);
530c2c66affSColin Finck 
531c2c66affSColin Finck     if (!NT_SUCCESS(Status))
532c2c66affSColin Finck     {
533c2c66affSColin Finck         DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status);
534c2c66affSColin Finck         return Status;
535c2c66affSColin Finck     }
536c2c66affSColin Finck 
537c2c66affSColin Finck     *DriverObject = Driver;
538c2c66affSColin Finck 
539c2c66affSColin Finck     MmFreeDriverInitialization((PLDR_DATA_TABLE_ENTRY)Driver->DriverSection);
540c2c66affSColin Finck 
541c2c66affSColin Finck     /* Set the driver as initialized */
542c2c66affSColin Finck     IopReadyDeviceObjects(Driver);
543c2c66affSColin Finck 
544c2c66affSColin Finck     if (PnpSystemInit) IopReinitializeDrivers();
545c2c66affSColin Finck 
546c2c66affSColin Finck     return STATUS_SUCCESS;
547c2c66affSColin Finck }
548c2c66affSColin Finck 
549c2c66affSColin Finck /*
550c2c66affSColin Finck  * IopAttachFilterDriversCallback
551c2c66affSColin Finck  *
552c2c66affSColin Finck  * Internal routine used by IopAttachFilterDrivers.
553c2c66affSColin Finck  */
554c2c66affSColin Finck NTSTATUS
555c2c66affSColin Finck NTAPI
556c2c66affSColin Finck IopAttachFilterDriversCallback(
557c2c66affSColin Finck     PWSTR ValueName,
558c2c66affSColin Finck     ULONG ValueType,
559c2c66affSColin Finck     PVOID ValueData,
560c2c66affSColin Finck     ULONG ValueLength,
561c2c66affSColin Finck     PVOID Context,
562c2c66affSColin Finck     PVOID EntryContext)
563c2c66affSColin Finck {
564c2c66affSColin Finck     PDEVICE_NODE DeviceNode = Context;
565c2c66affSColin Finck     UNICODE_STRING ServiceName;
566c2c66affSColin Finck     PWCHAR Filters;
567c2c66affSColin Finck     PLDR_DATA_TABLE_ENTRY ModuleObject;
568c2c66affSColin Finck     PDRIVER_OBJECT DriverObject;
569c2c66affSColin Finck     NTSTATUS Status;
570c2c66affSColin Finck 
571c2c66affSColin Finck     /* No filter value present */
572c2c66affSColin Finck     if (ValueType == REG_NONE)
573c2c66affSColin Finck         return STATUS_SUCCESS;
574c2c66affSColin Finck 
575c2c66affSColin Finck     for (Filters = ValueData;
576c2c66affSColin Finck          ((ULONG_PTR)Filters - (ULONG_PTR)ValueData) < ValueLength &&
577c2c66affSColin Finck          *Filters != 0;
578c2c66affSColin Finck          Filters += (ServiceName.Length / sizeof(WCHAR)) + 1)
579c2c66affSColin Finck     {
580c2c66affSColin Finck         DPRINT("Filter Driver: %S (%wZ)\n", Filters, &DeviceNode->InstancePath);
581c2c66affSColin Finck 
582c2c66affSColin Finck         ServiceName.Buffer = Filters;
583c2c66affSColin Finck         ServiceName.MaximumLength =
584c2c66affSColin Finck         ServiceName.Length = (USHORT)wcslen(Filters) * sizeof(WCHAR);
585c2c66affSColin Finck 
586c2c66affSColin Finck         KeEnterCriticalRegion();
587c2c66affSColin Finck         ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE);
588c2c66affSColin Finck         Status = IopGetDriverObject(&DriverObject,
589c2c66affSColin Finck                                     &ServiceName,
590c2c66affSColin Finck                                     FALSE);
591c2c66affSColin Finck         if (!NT_SUCCESS(Status))
592c2c66affSColin Finck         {
593c2c66affSColin Finck             /* Load and initialize the filter driver */
594c2c66affSColin Finck             Status = IopLoadServiceModule(&ServiceName, &ModuleObject);
595c2c66affSColin Finck             if (!NT_SUCCESS(Status))
596c2c66affSColin Finck             {
597c2c66affSColin Finck                 ExReleaseResourceLite(&IopDriverLoadResource);
598c2c66affSColin Finck                 KeLeaveCriticalRegion();
599c2c66affSColin Finck                 return Status;
600c2c66affSColin Finck             }
601c2c66affSColin Finck 
602c2c66affSColin Finck             Status = IopInitializeDriverModule(DeviceNode,
603c2c66affSColin Finck                                                ModuleObject,
604c2c66affSColin Finck                                                &ServiceName,
605c2c66affSColin Finck                                                FALSE,
606c2c66affSColin Finck                                                &DriverObject);
607c2c66affSColin Finck             if (!NT_SUCCESS(Status))
608c2c66affSColin Finck             {
609c2c66affSColin Finck                 ExReleaseResourceLite(&IopDriverLoadResource);
610c2c66affSColin Finck                 KeLeaveCriticalRegion();
611c2c66affSColin Finck                 return Status;
612c2c66affSColin Finck             }
613c2c66affSColin Finck         }
614c2c66affSColin Finck 
615c2c66affSColin Finck         ExReleaseResourceLite(&IopDriverLoadResource);
616c2c66affSColin Finck         KeLeaveCriticalRegion();
617c2c66affSColin Finck 
618c2c66affSColin Finck         Status = IopInitializeDevice(DeviceNode, DriverObject);
619c2c66affSColin Finck 
620c2c66affSColin Finck         /* Remove extra reference */
621c2c66affSColin Finck         ObDereferenceObject(DriverObject);
622c2c66affSColin Finck 
623c2c66affSColin Finck         if (!NT_SUCCESS(Status))
624c2c66affSColin Finck             return Status;
625c2c66affSColin Finck     }
626c2c66affSColin Finck 
627c2c66affSColin Finck     return STATUS_SUCCESS;
628c2c66affSColin Finck }
629c2c66affSColin Finck 
630c2c66affSColin Finck /*
631c2c66affSColin Finck  * IopAttachFilterDrivers
632c2c66affSColin Finck  *
633c2c66affSColin Finck  * Load filter drivers for specified device node.
634c2c66affSColin Finck  *
635c2c66affSColin Finck  * Parameters
636c2c66affSColin Finck  *    Lower
637c2c66affSColin Finck  *       Set to TRUE for loading lower level filters or FALSE for upper
638c2c66affSColin Finck  *       level filters.
639c2c66affSColin Finck  */
640c2c66affSColin Finck NTSTATUS
641c2c66affSColin Finck FASTCALL
642c2c66affSColin Finck IopAttachFilterDrivers(
643c2c66affSColin Finck     PDEVICE_NODE DeviceNode,
644c2c66affSColin Finck     HANDLE EnumSubKey,
645c2c66affSColin Finck     HANDLE ClassKey,
646c2c66affSColin Finck     BOOLEAN Lower)
647c2c66affSColin Finck {
648c2c66affSColin Finck     RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { NULL, 0, NULL, NULL, 0, NULL, 0 }, };
649c2c66affSColin Finck     NTSTATUS Status;
650c2c66affSColin Finck 
651c2c66affSColin Finck     /*
652c2c66affSColin Finck      * First load the device filters
653c2c66affSColin Finck      */
654c2c66affSColin Finck     QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
655c2c66affSColin Finck     if (Lower)
656c2c66affSColin Finck         QueryTable[0].Name = L"LowerFilters";
657c2c66affSColin Finck     else
658c2c66affSColin Finck         QueryTable[0].Name = L"UpperFilters";
659c2c66affSColin Finck     QueryTable[0].Flags = 0;
660c2c66affSColin Finck     QueryTable[0].DefaultType = REG_NONE;
661c2c66affSColin Finck 
662c2c66affSColin Finck     Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
663c2c66affSColin Finck                                     (PWSTR)EnumSubKey,
664c2c66affSColin Finck                                     QueryTable,
665c2c66affSColin Finck                                     DeviceNode,
666c2c66affSColin Finck                                     NULL);
667c2c66affSColin Finck     if (!NT_SUCCESS(Status))
668c2c66affSColin Finck     {
669c2c66affSColin Finck         DPRINT1("Failed to load device %s filters: %08X\n",
670c2c66affSColin Finck                 Lower ? "lower" : "upper", Status);
671c2c66affSColin Finck         return Status;
672c2c66affSColin Finck     }
673c2c66affSColin Finck 
674c2c66affSColin Finck     QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
675c2c66affSColin Finck     if (Lower)
676c2c66affSColin Finck         QueryTable[0].Name = L"LowerFilters";
677c2c66affSColin Finck     else
678c2c66affSColin Finck         QueryTable[0].Name = L"UpperFilters";
679c2c66affSColin Finck     QueryTable[0].EntryContext = NULL;
680c2c66affSColin Finck     QueryTable[0].Flags = 0;
681c2c66affSColin Finck     QueryTable[0].DefaultType = REG_NONE;
682c2c66affSColin Finck 
683c2c66affSColin Finck     if (ClassKey == NULL)
684c2c66affSColin Finck     {
685c2c66affSColin Finck         return STATUS_SUCCESS;
686c2c66affSColin Finck     }
687c2c66affSColin Finck 
688c2c66affSColin Finck     Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
689c2c66affSColin Finck                                     (PWSTR)ClassKey,
690c2c66affSColin Finck                                     QueryTable,
691c2c66affSColin Finck                                     DeviceNode,
692c2c66affSColin Finck                                     NULL);
693c2c66affSColin Finck 
694c2c66affSColin Finck     if (!NT_SUCCESS(Status))
695c2c66affSColin Finck     {
696c2c66affSColin Finck         DPRINT1("Failed to load class %s filters: %08X\n",
697c2c66affSColin Finck                 Lower ? "lower" : "upper", Status);
698c2c66affSColin Finck         return Status;
699c2c66affSColin Finck     }
700c2c66affSColin Finck 
701c2c66affSColin Finck     return STATUS_SUCCESS;
702c2c66affSColin Finck }
703c2c66affSColin Finck 
704c2c66affSColin Finck NTSTATUS
705c2c66affSColin Finck NTAPI
706c2c66affSColin Finck MiResolveImageReferences(IN PVOID ImageBase,
707c2c66affSColin Finck                          IN PUNICODE_STRING ImageFileDirectory,
708c2c66affSColin Finck                          IN PUNICODE_STRING NamePrefix OPTIONAL,
709c2c66affSColin Finck                          OUT PCHAR *MissingApi,
710c2c66affSColin Finck                          OUT PWCHAR *MissingDriver,
711c2c66affSColin Finck                          OUT PLOAD_IMPORTS *LoadImports);
712c2c66affSColin Finck 
713c2c66affSColin Finck //
714c2c66affSColin Finck // Used for images already loaded (boot drivers)
715c2c66affSColin Finck //
716c2c66affSColin Finck NTSTATUS
717c2c66affSColin Finck NTAPI
718c2c66affSColin Finck INIT_FUNCTION
719c2c66affSColin Finck LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry,
720c2c66affSColin Finck                        PUNICODE_STRING FileName,
721c2c66affSColin Finck                        PLDR_DATA_TABLE_ENTRY *ModuleObject)
722c2c66affSColin Finck {
723c2c66affSColin Finck     NTSTATUS Status;
724c2c66affSColin Finck     UNICODE_STRING BaseName, BaseDirectory;
725c2c66affSColin Finck     PLOAD_IMPORTS LoadedImports = (PVOID)-2;
726c2c66affSColin Finck     PCHAR MissingApiName, Buffer;
727c2c66affSColin Finck     PWCHAR MissingDriverName;
728c2c66affSColin Finck     PVOID DriverBase = LdrEntry->DllBase;
729c2c66affSColin Finck 
730c2c66affSColin Finck     /* Allocate a buffer we'll use for names */
731c2c66affSColin Finck     Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
732c2c66affSColin Finck     if (!Buffer)
733c2c66affSColin Finck     {
734c2c66affSColin Finck         /* Fail */
735c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
736c2c66affSColin Finck     }
737c2c66affSColin Finck 
738c2c66affSColin Finck     /* Check for a separator */
739c2c66affSColin Finck     if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
740c2c66affSColin Finck     {
741c2c66affSColin Finck         PWCHAR p;
742c2c66affSColin Finck         ULONG BaseLength;
743c2c66affSColin Finck 
744c2c66affSColin Finck         /* Loop the path until we get to the base name */
745c2c66affSColin Finck         p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
746c2c66affSColin Finck         while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
747c2c66affSColin Finck 
748c2c66affSColin Finck         /* Get the length */
749c2c66affSColin Finck         BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
750c2c66affSColin Finck         BaseLength *= sizeof(WCHAR);
751c2c66affSColin Finck 
752c2c66affSColin Finck         /* Setup the string */
753c2c66affSColin Finck         BaseName.Length = (USHORT)BaseLength;
754c2c66affSColin Finck         BaseName.Buffer = p;
755c2c66affSColin Finck     }
756c2c66affSColin Finck     else
757c2c66affSColin Finck     {
758c2c66affSColin Finck         /* Otherwise, we already have a base name */
759c2c66affSColin Finck         BaseName.Length = FileName->Length;
760c2c66affSColin Finck         BaseName.Buffer = FileName->Buffer;
761c2c66affSColin Finck     }
762c2c66affSColin Finck 
763c2c66affSColin Finck     /* Setup the maximum length */
764c2c66affSColin Finck     BaseName.MaximumLength = BaseName.Length;
765c2c66affSColin Finck 
766c2c66affSColin Finck     /* Now compute the base directory */
767c2c66affSColin Finck     BaseDirectory = *FileName;
768c2c66affSColin Finck     BaseDirectory.Length -= BaseName.Length;
769c2c66affSColin Finck     BaseDirectory.MaximumLength = BaseDirectory.Length;
770c2c66affSColin Finck 
771c2c66affSColin Finck     /* Resolve imports */
772c2c66affSColin Finck     MissingApiName = Buffer;
773c2c66affSColin Finck     Status = MiResolveImageReferences(DriverBase,
774c2c66affSColin Finck                                       &BaseDirectory,
775c2c66affSColin Finck                                       NULL,
776c2c66affSColin Finck                                       &MissingApiName,
777c2c66affSColin Finck                                       &MissingDriverName,
778c2c66affSColin Finck                                       &LoadedImports);
779c2c66affSColin Finck 
780c2c66affSColin Finck     /* Free the temporary buffer */
781c2c66affSColin Finck     ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);
782c2c66affSColin Finck 
783c2c66affSColin Finck     /* Check the result of the imports resolution */
784c2c66affSColin Finck     if (!NT_SUCCESS(Status)) return Status;
785c2c66affSColin Finck 
786c2c66affSColin Finck     /* Return */
787c2c66affSColin Finck     *ModuleObject = LdrEntry;
788c2c66affSColin Finck     return STATUS_SUCCESS;
789c2c66affSColin Finck }
790c2c66affSColin Finck 
791c2c66affSColin Finck /*
792c2c66affSColin Finck  * IopInitializeBuiltinDriver
793c2c66affSColin Finck  *
794c2c66affSColin Finck  * Initialize a driver that is already loaded in memory.
795c2c66affSColin Finck  */
796c2c66affSColin Finck NTSTATUS
797c2c66affSColin Finck NTAPI
798c2c66affSColin Finck INIT_FUNCTION
799c2c66affSColin Finck IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY BootLdrEntry)
800c2c66affSColin Finck {
801c2c66affSColin Finck     PDEVICE_NODE DeviceNode;
802c2c66affSColin Finck     PDRIVER_OBJECT DriverObject;
803c2c66affSColin Finck     NTSTATUS Status;
804c2c66affSColin Finck     PWCHAR Buffer, FileNameWithoutPath;
805c2c66affSColin Finck     PWSTR FileExtension;
806c2c66affSColin Finck     PUNICODE_STRING ModuleName = &BootLdrEntry->BaseDllName;
807c2c66affSColin Finck     PLDR_DATA_TABLE_ENTRY LdrEntry;
808c2c66affSColin Finck     PLIST_ENTRY NextEntry;
809c2c66affSColin Finck     UNICODE_STRING ServiceName;
810c2c66affSColin Finck     BOOLEAN Success;
811c2c66affSColin Finck 
812c2c66affSColin Finck     /*
813c2c66affSColin Finck      * Display 'Loading XXX...' message
814c2c66affSColin Finck      */
815c2c66affSColin Finck     IopDisplayLoadingMessage(ModuleName);
816c2c66affSColin Finck     InbvIndicateProgress();
817c2c66affSColin Finck 
818c2c66affSColin Finck     Buffer = ExAllocatePoolWithTag(PagedPool,
819c2c66affSColin Finck                                    ModuleName->Length + sizeof(UNICODE_NULL),
820c2c66affSColin Finck                                    TAG_IO);
821c2c66affSColin Finck     if (Buffer == NULL)
822c2c66affSColin Finck     {
823c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
824c2c66affSColin Finck     }
825c2c66affSColin Finck 
826c2c66affSColin Finck     RtlCopyMemory(Buffer, ModuleName->Buffer, ModuleName->Length);
827c2c66affSColin Finck     Buffer[ModuleName->Length / sizeof(WCHAR)] = UNICODE_NULL;
828c2c66affSColin Finck 
829c2c66affSColin Finck     /*
830c2c66affSColin Finck      * Generate filename without path (not needed by freeldr)
831c2c66affSColin Finck      */
832c2c66affSColin Finck     FileNameWithoutPath = wcsrchr(Buffer, L'\\');
833c2c66affSColin Finck     if (FileNameWithoutPath == NULL)
834c2c66affSColin Finck     {
835c2c66affSColin Finck         FileNameWithoutPath = Buffer;
836c2c66affSColin Finck     }
837c2c66affSColin Finck     else
838c2c66affSColin Finck     {
839c2c66affSColin Finck         FileNameWithoutPath++;
840c2c66affSColin Finck     }
841c2c66affSColin Finck 
842c2c66affSColin Finck     /*
843c2c66affSColin Finck      * Strip the file extension from ServiceName
844c2c66affSColin Finck      */
845c2c66affSColin Finck     Success = RtlCreateUnicodeString(&ServiceName, FileNameWithoutPath);
846c2c66affSColin Finck     ExFreePoolWithTag(Buffer, TAG_IO);
847c2c66affSColin Finck     if (!Success)
848c2c66affSColin Finck     {
849c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
850c2c66affSColin Finck     }
851c2c66affSColin Finck 
852c2c66affSColin Finck     FileExtension = wcsrchr(ServiceName.Buffer, L'.');
853c2c66affSColin Finck     if (FileExtension != NULL)
854c2c66affSColin Finck     {
855c2c66affSColin Finck         ServiceName.Length -= (USHORT)wcslen(FileExtension) * sizeof(WCHAR);
856c2c66affSColin Finck         FileExtension[0] = UNICODE_NULL;
857c2c66affSColin Finck     }
858c2c66affSColin Finck 
859c2c66affSColin Finck     /*
860c2c66affSColin Finck      * Determine the right device object
861c2c66affSColin Finck      */
862c2c66affSColin Finck     /* Use IopRootDeviceNode for now */
863c2c66affSColin Finck     Status = IopCreateDeviceNode(IopRootDeviceNode,
864c2c66affSColin Finck                                  NULL,
865c2c66affSColin Finck                                  &ServiceName,
866c2c66affSColin Finck                                  &DeviceNode);
867c2c66affSColin Finck     RtlFreeUnicodeString(&ServiceName);
868c2c66affSColin Finck     if (!NT_SUCCESS(Status))
869c2c66affSColin Finck     {
870c2c66affSColin Finck         DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
871c2c66affSColin Finck         return Status;
872c2c66affSColin Finck     }
873c2c66affSColin Finck 
874c2c66affSColin Finck     /* Lookup the new Ldr entry in PsLoadedModuleList */
875c2c66affSColin Finck     NextEntry = PsLoadedModuleList.Flink;
876c2c66affSColin Finck     while (NextEntry != &PsLoadedModuleList)
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         NextEntry = NextEntry->Flink;
887c2c66affSColin Finck     }
888c2c66affSColin Finck     ASSERT(NextEntry != &PsLoadedModuleList);
889c2c66affSColin Finck 
890c2c66affSColin Finck     /*
891c2c66affSColin Finck      * Initialize the driver
892c2c66affSColin Finck      */
893c2c66affSColin Finck     Status = IopInitializeDriverModule(DeviceNode,
894c2c66affSColin Finck                                        LdrEntry,
895c2c66affSColin Finck                                        &DeviceNode->ServiceName,
896c2c66affSColin Finck                                        FALSE,
897c2c66affSColin Finck                                        &DriverObject);
898c2c66affSColin Finck 
899c2c66affSColin Finck     if (!NT_SUCCESS(Status))
900c2c66affSColin Finck     {
901c2c66affSColin Finck         return Status;
902c2c66affSColin Finck     }
903c2c66affSColin Finck 
904c2c66affSColin Finck     Status = IopInitializeDevice(DeviceNode, DriverObject);
905c2c66affSColin Finck     if (NT_SUCCESS(Status))
906c2c66affSColin Finck     {
907c2c66affSColin Finck         Status = IopStartDevice(DeviceNode);
908c2c66affSColin Finck     }
909c2c66affSColin Finck 
910c2c66affSColin Finck     /* Remove extra reference from IopInitializeDriverModule */
911c2c66affSColin Finck     ObDereferenceObject(DriverObject);
912c2c66affSColin Finck 
913c2c66affSColin Finck     return Status;
914c2c66affSColin Finck }
915c2c66affSColin Finck 
916c2c66affSColin Finck /*
917c2c66affSColin Finck  * IopInitializeBootDrivers
918c2c66affSColin Finck  *
919c2c66affSColin Finck  * Initialize boot drivers and free memory for boot files.
920c2c66affSColin Finck  *
921c2c66affSColin Finck  * Parameters
922c2c66affSColin Finck  *    None
923c2c66affSColin Finck  *
924c2c66affSColin Finck  * Return Value
925c2c66affSColin Finck  *    None
926c2c66affSColin Finck  */
927c2c66affSColin Finck VOID
928c2c66affSColin Finck FASTCALL
929c2c66affSColin Finck INIT_FUNCTION
930c2c66affSColin Finck IopInitializeBootDrivers(VOID)
931c2c66affSColin Finck {
932c2c66affSColin Finck     PLIST_ENTRY ListHead, NextEntry, NextEntry2;
933c2c66affSColin Finck     PLDR_DATA_TABLE_ENTRY LdrEntry;
934c2c66affSColin Finck     PDEVICE_NODE DeviceNode;
935c2c66affSColin Finck     PDRIVER_OBJECT DriverObject;
936c2c66affSColin Finck     LDR_DATA_TABLE_ENTRY ModuleObject;
937c2c66affSColin Finck     NTSTATUS Status;
938c2c66affSColin Finck     UNICODE_STRING DriverName;
939c2c66affSColin Finck     ULONG i, Index;
940c2c66affSColin Finck     PDRIVER_INFORMATION DriverInfo, DriverInfoTag;
941c2c66affSColin Finck     HANDLE KeyHandle;
942c2c66affSColin Finck     PBOOT_DRIVER_LIST_ENTRY BootEntry;
943c2c66affSColin Finck     DPRINT("IopInitializeBootDrivers()\n");
944c2c66affSColin Finck 
945c2c66affSColin Finck     /* Use IopRootDeviceNode for now */
946c2c66affSColin Finck     Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, NULL, &DeviceNode);
947c2c66affSColin Finck     if (!NT_SUCCESS(Status)) return;
948c2c66affSColin Finck 
949c2c66affSColin Finck     /* Setup the module object for the RAW FS Driver */
950c2c66affSColin Finck     ModuleObject.DllBase = NULL;
951c2c66affSColin Finck     ModuleObject.SizeOfImage = 0;
952c2c66affSColin Finck     ModuleObject.EntryPoint = RawFsDriverEntry;
953c2c66affSColin Finck     RtlInitUnicodeString(&DriverName, L"RAW");
954c2c66affSColin Finck 
955c2c66affSColin Finck     /* Initialize it */
956c2c66affSColin Finck     Status = IopInitializeDriverModule(DeviceNode,
957c2c66affSColin Finck                                        &ModuleObject,
958c2c66affSColin Finck                                        &DriverName,
959c2c66affSColin Finck                                        TRUE,
960c2c66affSColin Finck                                        &DriverObject);
961c2c66affSColin Finck     if (!NT_SUCCESS(Status))
962c2c66affSColin Finck     {
963c2c66affSColin Finck         /* Fail */
964c2c66affSColin Finck         return;
965c2c66affSColin Finck     }
966c2c66affSColin Finck 
967c2c66affSColin Finck     /* Now initialize the associated device */
968c2c66affSColin Finck     Status = IopInitializeDevice(DeviceNode, DriverObject);
969c2c66affSColin Finck     if (!NT_SUCCESS(Status))
970c2c66affSColin Finck     {
971c2c66affSColin Finck         /* Fail */
972c2c66affSColin Finck         ObDereferenceObject(DriverObject);
973c2c66affSColin Finck         return;
974c2c66affSColin Finck     }
975c2c66affSColin Finck 
976c2c66affSColin Finck     /* Start it up */
977c2c66affSColin Finck     Status = IopStartDevice(DeviceNode);
978c2c66affSColin Finck     if (!NT_SUCCESS(Status))
979c2c66affSColin Finck     {
980c2c66affSColin Finck         /* Fail */
981c2c66affSColin Finck         ObDereferenceObject(DriverObject);
982c2c66affSColin Finck         return;
983c2c66affSColin Finck     }
984c2c66affSColin Finck 
985c2c66affSColin Finck     /* Get highest group order index */
986c2c66affSColin Finck     IopGroupIndex = PpInitGetGroupOrderIndex(NULL);
987c2c66affSColin Finck     if (IopGroupIndex == 0xFFFF) ASSERT(FALSE);
988c2c66affSColin Finck 
989c2c66affSColin Finck     /* Allocate the group table */
990c2c66affSColin Finck     IopGroupTable = ExAllocatePoolWithTag(PagedPool,
991c2c66affSColin Finck                                           IopGroupIndex * sizeof(LIST_ENTRY),
992c2c66affSColin Finck                                           TAG_IO);
993c2c66affSColin Finck     if (IopGroupTable == NULL) ASSERT(FALSE);
994c2c66affSColin Finck 
995c2c66affSColin Finck     /* Initialize the group table lists */
996c2c66affSColin Finck     for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]);
997c2c66affSColin Finck 
998c2c66affSColin Finck     /* Loop the boot modules */
999c2c66affSColin Finck     ListHead = &KeLoaderBlock->LoadOrderListHead;
1000c2c66affSColin Finck     NextEntry = ListHead->Flink;
1001c2c66affSColin Finck     while (ListHead != NextEntry)
1002c2c66affSColin Finck     {
1003c2c66affSColin Finck         /* Get the entry */
1004c2c66affSColin Finck         LdrEntry = CONTAINING_RECORD(NextEntry,
1005c2c66affSColin Finck                                      LDR_DATA_TABLE_ENTRY,
1006c2c66affSColin Finck                                      InLoadOrderLinks);
1007c2c66affSColin Finck 
1008c2c66affSColin Finck         /* Check if the DLL needs to be initialized */
1009c2c66affSColin Finck         if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
1010c2c66affSColin Finck         {
1011c2c66affSColin Finck             /* Call its entrypoint */
1012c2c66affSColin Finck             MmCallDllInitialize(LdrEntry, NULL);
1013c2c66affSColin Finck         }
1014c2c66affSColin Finck 
1015c2c66affSColin Finck         /* Go to the next driver */
1016c2c66affSColin Finck         NextEntry = NextEntry->Flink;
1017c2c66affSColin Finck     }
1018c2c66affSColin Finck 
1019c2c66affSColin Finck     /* Loop the boot drivers */
1020c2c66affSColin Finck     ListHead = &KeLoaderBlock->BootDriverListHead;
1021c2c66affSColin Finck     NextEntry = ListHead->Flink;
1022c2c66affSColin Finck     while (ListHead != NextEntry)
1023c2c66affSColin Finck     {
1024c2c66affSColin Finck         /* Get the entry */
1025c2c66affSColin Finck         BootEntry = CONTAINING_RECORD(NextEntry,
1026c2c66affSColin Finck                                       BOOT_DRIVER_LIST_ENTRY,
1027c2c66affSColin Finck                                       Link);
1028c2c66affSColin Finck 
1029c2c66affSColin Finck         /* Get the driver loader entry */
1030c2c66affSColin Finck         LdrEntry = BootEntry->LdrEntry;
1031c2c66affSColin Finck 
1032c2c66affSColin Finck         /* Allocate our internal accounting structure */
1033c2c66affSColin Finck         DriverInfo = ExAllocatePoolWithTag(PagedPool,
1034c2c66affSColin Finck                                            sizeof(DRIVER_INFORMATION),
1035c2c66affSColin Finck                                            TAG_IO);
1036c2c66affSColin Finck         if (DriverInfo)
1037c2c66affSColin Finck         {
1038c2c66affSColin Finck             /* Zero it and initialize it */
1039c2c66affSColin Finck             RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION));
1040c2c66affSColin Finck             InitializeListHead(&DriverInfo->Link);
1041c2c66affSColin Finck             DriverInfo->DataTableEntry = BootEntry;
1042c2c66affSColin Finck 
1043c2c66affSColin Finck             /* Open the registry key */
1044c2c66affSColin Finck             Status = IopOpenRegistryKeyEx(&KeyHandle,
1045c2c66affSColin Finck                                           NULL,
1046c2c66affSColin Finck                                           &BootEntry->RegistryPath,
1047c2c66affSColin Finck                                           KEY_READ);
10488e51bb65SPierre Schweitzer             DPRINT("IopOpenRegistryKeyEx(%wZ) returned 0x%08lx\n", &BootEntry->RegistryPath, Status);
1049cb69c4c6SHermès Bélusca-Maïto #if 0
1050cb69c4c6SHermès Bélusca-Maïto             if (NT_SUCCESS(Status))
1051cb69c4c6SHermès Bélusca-Maïto #else // Hack still needed...
1052c2c66affSColin Finck             if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */
1053c2c66affSColin Finck                 ((KeLoaderBlock->SetupLdrBlock) && ((KeyHandle = (PVOID)1)))) // yes, it's an assignment!
1054cb69c4c6SHermès Bélusca-Maïto #endif
1055c2c66affSColin Finck             {
1056c2c66affSColin Finck                 /* Save the handle */
1057c2c66affSColin Finck                 DriverInfo->ServiceHandle = KeyHandle;
1058c2c66affSColin Finck 
1059c2c66affSColin Finck                 /* Get the group oder index */
1060c2c66affSColin Finck                 Index = PpInitGetGroupOrderIndex(KeyHandle);
1061c2c66affSColin Finck 
1062c2c66affSColin Finck                 /* Get the tag position */
1063c2c66affSColin Finck                 DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle);
1064c2c66affSColin Finck 
1065c2c66affSColin Finck                 /* Insert it into the list, at the right place */
1066c2c66affSColin Finck                 ASSERT(Index < IopGroupIndex);
1067c2c66affSColin Finck                 NextEntry2 = IopGroupTable[Index].Flink;
1068c2c66affSColin Finck                 while (NextEntry2 != &IopGroupTable[Index])
1069c2c66affSColin Finck                 {
1070c2c66affSColin Finck                     /* Get the driver info */
1071c2c66affSColin Finck                     DriverInfoTag = CONTAINING_RECORD(NextEntry2,
1072c2c66affSColin Finck                                                       DRIVER_INFORMATION,
1073c2c66affSColin Finck                                                       Link);
1074c2c66affSColin Finck 
1075c2c66affSColin Finck                     /* Check if we found the right tag position */
1076c2c66affSColin Finck                     if (DriverInfoTag->TagPosition > DriverInfo->TagPosition)
1077c2c66affSColin Finck                     {
1078c2c66affSColin Finck                         /* We're done */
1079c2c66affSColin Finck                         break;
1080c2c66affSColin Finck                     }
1081c2c66affSColin Finck 
1082c2c66affSColin Finck                     /* Next entry */
1083c2c66affSColin Finck                     NextEntry2 = NextEntry2->Flink;
1084c2c66affSColin Finck                 }
1085c2c66affSColin Finck 
1086c2c66affSColin Finck                 /* Insert us right before the next entry */
1087c2c66affSColin Finck                 NextEntry2 = NextEntry2->Blink;
1088c2c66affSColin Finck                 InsertHeadList(NextEntry2, &DriverInfo->Link);
1089c2c66affSColin Finck             }
1090c2c66affSColin Finck         }
1091c2c66affSColin Finck 
1092c2c66affSColin Finck         /* Go to the next driver */
1093c2c66affSColin Finck         NextEntry = NextEntry->Flink;
1094c2c66affSColin Finck     }
1095c2c66affSColin Finck 
1096c2c66affSColin Finck     /* Loop each group index */
1097c2c66affSColin Finck     for (i = 0; i < IopGroupIndex; i++)
1098c2c66affSColin Finck     {
1099c2c66affSColin Finck         /* Loop each group table */
1100c2c66affSColin Finck         NextEntry = IopGroupTable[i].Flink;
1101c2c66affSColin Finck         while (NextEntry != &IopGroupTable[i])
1102c2c66affSColin Finck         {
1103c2c66affSColin Finck             /* Get the entry */
1104c2c66affSColin Finck             DriverInfo = CONTAINING_RECORD(NextEntry,
1105c2c66affSColin Finck                                            DRIVER_INFORMATION,
1106c2c66affSColin Finck                                            Link);
1107c2c66affSColin Finck 
1108c2c66affSColin Finck             /* Get the driver loader entry */
1109c2c66affSColin Finck             LdrEntry = DriverInfo->DataTableEntry->LdrEntry;
1110c2c66affSColin Finck 
1111c2c66affSColin Finck             /* Initialize it */
1112c2c66affSColin Finck             IopInitializeBuiltinDriver(LdrEntry);
1113c2c66affSColin Finck 
1114c2c66affSColin Finck             /* Next entry */
1115c2c66affSColin Finck             NextEntry = NextEntry->Flink;
1116c2c66affSColin Finck         }
1117c2c66affSColin Finck     }
1118c2c66affSColin Finck 
1119c2c66affSColin Finck     /* In old ROS, the loader list became empty after this point. Simulate. */
1120c2c66affSColin Finck     InitializeListHead(&KeLoaderBlock->LoadOrderListHead);
1121c2c66affSColin Finck }
1122c2c66affSColin Finck 
1123c2c66affSColin Finck VOID
1124c2c66affSColin Finck FASTCALL
1125c2c66affSColin Finck INIT_FUNCTION
1126c2c66affSColin Finck IopInitializeSystemDrivers(VOID)
1127c2c66affSColin Finck {
1128c2c66affSColin Finck     PUNICODE_STRING *DriverList, *SavedList;
1129c2c66affSColin Finck 
1130c2c66affSColin Finck     /* No system drivers on the boot cd */
1131cb69c4c6SHermès Bélusca-Maïto     if (KeLoaderBlock->SetupLdrBlock) return; // ExpInTextModeSetup
1132c2c66affSColin Finck 
1133c2c66affSColin Finck     /* Get the driver list */
1134c2c66affSColin Finck     SavedList = DriverList = CmGetSystemDriverList();
1135c2c66affSColin Finck     ASSERT(DriverList);
1136c2c66affSColin Finck 
1137c2c66affSColin Finck     /* Loop it */
1138c2c66affSColin Finck     while (*DriverList)
1139c2c66affSColin Finck     {
1140c2c66affSColin Finck         /* Load the driver */
1141c2c66affSColin Finck         ZwLoadDriver(*DriverList);
1142c2c66affSColin Finck 
1143c2c66affSColin Finck         /* Free the entry */
1144c2c66affSColin Finck         RtlFreeUnicodeString(*DriverList);
1145c2c66affSColin Finck         ExFreePool(*DriverList);
1146c2c66affSColin Finck 
1147c2c66affSColin Finck         /* Next entry */
1148c2c66affSColin Finck         InbvIndicateProgress();
1149c2c66affSColin Finck         DriverList++;
1150c2c66affSColin Finck     }
1151c2c66affSColin Finck 
1152c2c66affSColin Finck     /* Free the list */
1153c2c66affSColin Finck     ExFreePool(SavedList);
1154c2c66affSColin Finck }
1155c2c66affSColin Finck 
1156c2c66affSColin Finck /*
1157c2c66affSColin Finck  * IopUnloadDriver
1158c2c66affSColin Finck  *
1159c2c66affSColin Finck  * Unloads a device driver.
1160c2c66affSColin Finck  *
1161c2c66affSColin Finck  * Parameters
1162c2c66affSColin Finck  *    DriverServiceName
1163c2c66affSColin Finck  *       Name of the service to unload (registry key).
1164c2c66affSColin Finck  *
1165c2c66affSColin Finck  *    UnloadPnpDrivers
1166c2c66affSColin Finck  *       Whether to unload Plug & Plug or only legacy drivers. If this
1167c2c66affSColin Finck  *       parameter is set to FALSE, the routine will unload only legacy
1168c2c66affSColin Finck  *       drivers.
1169c2c66affSColin Finck  *
1170c2c66affSColin Finck  * Return Value
1171c2c66affSColin Finck  *    Status
1172c2c66affSColin Finck  *
1173c2c66affSColin Finck  * To do
1174c2c66affSColin Finck  *    Guard the whole function by SEH.
1175c2c66affSColin Finck  */
1176c2c66affSColin Finck 
1177c2c66affSColin Finck NTSTATUS NTAPI
1178c2c66affSColin Finck IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
1179c2c66affSColin Finck {
1180c2c66affSColin Finck     RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1181c2c66affSColin Finck     UNICODE_STRING ImagePath;
1182c2c66affSColin Finck     UNICODE_STRING ServiceName;
1183c2c66affSColin Finck     UNICODE_STRING ObjectName;
1184c2c66affSColin Finck     PDRIVER_OBJECT DriverObject;
1185c2c66affSColin Finck     PDEVICE_OBJECT DeviceObject;
1186c2c66affSColin Finck     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1187c2c66affSColin Finck     NTSTATUS Status;
1188c2c66affSColin Finck     PWSTR Start;
1189c2c66affSColin Finck     BOOLEAN SafeToUnload = TRUE;
1190*daf9743cSPierre Schweitzer     KPROCESSOR_MODE PreviousMode;
1191*daf9743cSPierre Schweitzer     UNICODE_STRING CapturedServiceName;
1192c2c66affSColin Finck 
1193c2c66affSColin Finck     PAGED_CODE();
1194c2c66affSColin Finck 
1195*daf9743cSPierre Schweitzer     PreviousMode = ExGetPreviousMode();
1196*daf9743cSPierre Schweitzer 
1197*daf9743cSPierre Schweitzer     /* Need the appropriate priviliege */
1198*daf9743cSPierre Schweitzer     if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
1199*daf9743cSPierre Schweitzer     {
1200*daf9743cSPierre Schweitzer         DPRINT1("No unload privilege!\n");
1201*daf9743cSPierre Schweitzer         return STATUS_PRIVILEGE_NOT_HELD;
1202*daf9743cSPierre Schweitzer     }
1203*daf9743cSPierre Schweitzer 
1204*daf9743cSPierre Schweitzer     /* Capture the service name */
1205*daf9743cSPierre Schweitzer     Status = ProbeAndCaptureUnicodeString(&CapturedServiceName, PreviousMode, DriverServiceName);
1206*daf9743cSPierre Schweitzer     if (!NT_SUCCESS(Status))
1207*daf9743cSPierre Schweitzer     {
1208*daf9743cSPierre Schweitzer         return Status;
1209*daf9743cSPierre Schweitzer     }
1210*daf9743cSPierre Schweitzer 
1211*daf9743cSPierre Schweitzer     DPRINT("IopUnloadDriver('%wZ', %u)\n", &CapturedServiceName, UnloadPnpDrivers);
1212*daf9743cSPierre Schweitzer 
1213*daf9743cSPierre Schweitzer 
1214*daf9743cSPierre Schweitzer     /* We need a service name */
1215*daf9743cSPierre Schweitzer     if (CapturedServiceName.Length == 0)
1216*daf9743cSPierre Schweitzer     {
1217*daf9743cSPierre Schweitzer         ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1218*daf9743cSPierre Schweitzer         return STATUS_INVALID_PARAMETER;
1219*daf9743cSPierre Schweitzer     }
1220*daf9743cSPierre Schweitzer 
1221c2c66affSColin Finck     /*
1222c2c66affSColin Finck      * Get the service name from the registry key name
1223c2c66affSColin Finck      */
1224*daf9743cSPierre Schweitzer     Start = wcsrchr(CapturedServiceName.Buffer, L'\\');
1225c2c66affSColin Finck     if (Start == NULL)
1226*daf9743cSPierre Schweitzer         Start = CapturedServiceName.Buffer;
1227c2c66affSColin Finck     else
1228c2c66affSColin Finck         Start++;
1229c2c66affSColin Finck 
1230c2c66affSColin Finck     RtlInitUnicodeString(&ServiceName, Start);
1231c2c66affSColin Finck 
1232c2c66affSColin Finck     /*
1233c2c66affSColin Finck      * Construct the driver object name
1234c2c66affSColin Finck      */
1235c2c66affSColin Finck     ObjectName.Length = ((USHORT)wcslen(Start) + 8) * sizeof(WCHAR);
1236c2c66affSColin Finck     ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
1237c2c66affSColin Finck     ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool,
1238c2c66affSColin Finck                                               ObjectName.MaximumLength,
1239c2c66affSColin Finck                                               TAG_IO);
1240*daf9743cSPierre Schweitzer     if (!ObjectName.Buffer)
1241*daf9743cSPierre Schweitzer     {
1242*daf9743cSPierre Schweitzer         ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1243*daf9743cSPierre Schweitzer         return STATUS_INSUFFICIENT_RESOURCES;
1244*daf9743cSPierre Schweitzer     }
1245c2c66affSColin Finck     wcscpy(ObjectName.Buffer, DRIVER_ROOT_NAME);
1246c2c66affSColin Finck     memcpy(ObjectName.Buffer + 8, Start, ObjectName.Length - 8 * sizeof(WCHAR));
1247c2c66affSColin Finck     ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = UNICODE_NULL;
1248c2c66affSColin Finck 
1249c2c66affSColin Finck     /*
1250c2c66affSColin Finck      * Find the driver object
1251c2c66affSColin Finck      */
1252c2c66affSColin Finck     Status = ObReferenceObjectByName(&ObjectName,
1253c2c66affSColin Finck                                      0,
1254c2c66affSColin Finck                                      0,
1255c2c66affSColin Finck                                      0,
1256c2c66affSColin Finck                                      IoDriverObjectType,
1257c2c66affSColin Finck                                      KernelMode,
1258c2c66affSColin Finck                                      0,
1259c2c66affSColin Finck                                      (PVOID*)&DriverObject);
1260c2c66affSColin Finck 
1261c2c66affSColin Finck     if (!NT_SUCCESS(Status))
1262c2c66affSColin Finck     {
1263c2c66affSColin Finck         DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
1264c2c66affSColin Finck         ExFreePoolWithTag(ObjectName.Buffer, TAG_IO);
1265*daf9743cSPierre Schweitzer         ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1266c2c66affSColin Finck         return Status;
1267c2c66affSColin Finck     }
1268c2c66affSColin Finck 
1269c2c66affSColin Finck     /* Free the buffer for driver object name */
1270c2c66affSColin Finck     ExFreePoolWithTag(ObjectName.Buffer, TAG_IO);
1271c2c66affSColin Finck 
1272c2c66affSColin Finck     /* Check that driver is not already unloading */
1273c2c66affSColin Finck     if (DriverObject->Flags & DRVO_UNLOAD_INVOKED)
1274c2c66affSColin Finck     {
1275c2c66affSColin Finck         DPRINT1("Driver deletion pending\n");
1276c2c66affSColin Finck         ObDereferenceObject(DriverObject);
1277*daf9743cSPierre Schweitzer         ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1278c2c66affSColin Finck         return STATUS_DELETE_PENDING;
1279c2c66affSColin Finck     }
1280c2c66affSColin Finck 
1281c2c66affSColin Finck     /*
1282c2c66affSColin Finck      * Get path of service...
1283c2c66affSColin Finck      */
1284c2c66affSColin Finck     RtlZeroMemory(QueryTable, sizeof(QueryTable));
1285c2c66affSColin Finck 
1286c2c66affSColin Finck     RtlInitUnicodeString(&ImagePath, NULL);
1287c2c66affSColin Finck 
1288c2c66affSColin Finck     QueryTable[0].Name = L"ImagePath";
1289c2c66affSColin Finck     QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1290c2c66affSColin Finck     QueryTable[0].EntryContext = &ImagePath;
1291c2c66affSColin Finck 
1292c2c66affSColin Finck     Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1293*daf9743cSPierre Schweitzer                                     CapturedServiceName.Buffer,
1294c2c66affSColin Finck                                     QueryTable,
1295c2c66affSColin Finck                                     NULL,
1296c2c66affSColin Finck                                     NULL);
1297c2c66affSColin Finck 
1298*daf9743cSPierre Schweitzer     /* We no longer need service name */
1299*daf9743cSPierre Schweitzer     ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1300*daf9743cSPierre Schweitzer 
1301c2c66affSColin Finck     if (!NT_SUCCESS(Status))
1302c2c66affSColin Finck     {
1303c2c66affSColin Finck         DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1304c2c66affSColin Finck         ObDereferenceObject(DriverObject);
1305c2c66affSColin Finck         return Status;
1306c2c66affSColin Finck     }
1307c2c66affSColin Finck 
1308c2c66affSColin Finck     /*
1309c2c66affSColin Finck      * Normalize the image path for all later processing.
1310c2c66affSColin Finck      */
1311c2c66affSColin Finck     Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1312c2c66affSColin Finck 
1313c2c66affSColin Finck     if (!NT_SUCCESS(Status))
1314c2c66affSColin Finck     {
1315c2c66affSColin Finck         DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status);
1316c2c66affSColin Finck         ObDereferenceObject(DriverObject);
1317c2c66affSColin Finck         return Status;
1318c2c66affSColin Finck     }
1319c2c66affSColin Finck 
1320c2c66affSColin Finck     /* Free the service path */
1321c2c66affSColin Finck     ExFreePool(ImagePath.Buffer);
1322c2c66affSColin Finck 
1323c2c66affSColin Finck     /*
1324c2c66affSColin Finck      * Unload the module and release the references to the device object
1325c2c66affSColin Finck      */
1326c2c66affSColin Finck 
1327c2c66affSColin Finck     /* Call the load/unload routine, depending on current process */
1328c2c66affSColin Finck     if (DriverObject->DriverUnload && DriverObject->DriverSection &&
1329c2c66affSColin Finck         (UnloadPnpDrivers || (DriverObject->Flags & DRVO_LEGACY_DRIVER)))
1330c2c66affSColin Finck     {
1331c2c66affSColin Finck         /* Loop through each device object of the driver
1332c2c66affSColin Finck            and set DOE_UNLOAD_PENDING flag */
1333c2c66affSColin Finck         DeviceObject = DriverObject->DeviceObject;
1334c2c66affSColin Finck         while (DeviceObject)
1335c2c66affSColin Finck         {
1336c2c66affSColin Finck             /* Set the unload pending flag for the device */
1337c2c66affSColin Finck             DeviceExtension = IoGetDevObjExtension(DeviceObject);
1338c2c66affSColin Finck             DeviceExtension->ExtensionFlags |= DOE_UNLOAD_PENDING;
1339c2c66affSColin Finck 
1340c2c66affSColin Finck             /* Make sure there are no attached devices or no reference counts */
1341c2c66affSColin Finck             if ((DeviceObject->ReferenceCount) || (DeviceObject->AttachedDevice))
1342c2c66affSColin Finck             {
1343c2c66affSColin Finck                 /* Not safe to unload */
1344c2c66affSColin Finck                 DPRINT1("Drivers device object is referenced or has attached devices\n");
1345c2c66affSColin Finck 
1346c2c66affSColin Finck                 SafeToUnload = FALSE;
1347c2c66affSColin Finck             }
1348c2c66affSColin Finck 
1349c2c66affSColin Finck             DeviceObject = DeviceObject->NextDevice;
1350c2c66affSColin Finck         }
1351c2c66affSColin Finck 
1352c2c66affSColin Finck         /* If not safe to unload, then return success */
1353c2c66affSColin Finck         if (!SafeToUnload)
1354c2c66affSColin Finck         {
1355c2c66affSColin Finck             ObDereferenceObject(DriverObject);
1356c2c66affSColin Finck             return STATUS_SUCCESS;
1357c2c66affSColin Finck         }
1358c2c66affSColin Finck 
1359c2c66affSColin Finck         DPRINT1("Unloading driver '%wZ' (manual)\n", &DriverObject->DriverName);
1360c2c66affSColin Finck 
1361c2c66affSColin Finck         /* Set the unload invoked flag and call the unload routine */
1362c2c66affSColin Finck         DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
1363c2c66affSColin Finck         Status = IopLoadUnloadDriver(NULL, &DriverObject);
1364c2c66affSColin Finck         ASSERT(Status == STATUS_SUCCESS);
1365c2c66affSColin Finck 
1366c2c66affSColin Finck         /* Mark the driver object temporary, so it could be deleted later */
1367c2c66affSColin Finck         ObMakeTemporaryObject(DriverObject);
1368c2c66affSColin Finck 
1369c2c66affSColin Finck         /* Dereference it 2 times */
1370c2c66affSColin Finck         ObDereferenceObject(DriverObject);
1371c2c66affSColin Finck         ObDereferenceObject(DriverObject);
1372c2c66affSColin Finck 
1373c2c66affSColin Finck         return Status;
1374c2c66affSColin Finck     }
1375c2c66affSColin Finck     else
1376c2c66affSColin Finck     {
1377c2c66affSColin Finck         DPRINT1("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
1378c2c66affSColin Finck 
1379c2c66affSColin Finck         /* Dereference one time (refd inside this function) */
1380c2c66affSColin Finck         ObDereferenceObject(DriverObject);
1381c2c66affSColin Finck 
1382c2c66affSColin Finck         /* Return unloading failure */
1383c2c66affSColin Finck         return STATUS_INVALID_DEVICE_REQUEST;
1384c2c66affSColin Finck     }
1385c2c66affSColin Finck }
1386c2c66affSColin Finck 
1387c2c66affSColin Finck VOID
1388c2c66affSColin Finck NTAPI
1389c2c66affSColin Finck IopReinitializeDrivers(VOID)
1390c2c66affSColin Finck {
1391c2c66affSColin Finck     PDRIVER_REINIT_ITEM ReinitItem;
1392c2c66affSColin Finck     PLIST_ENTRY Entry;
1393c2c66affSColin Finck 
1394c2c66affSColin Finck     /* Get the first entry and start looping */
1395c2c66affSColin Finck     Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1396c2c66affSColin Finck                                         &DriverReinitListLock);
1397c2c66affSColin Finck     while (Entry)
1398c2c66affSColin Finck     {
1399c2c66affSColin Finck         /* Get the item */
1400c2c66affSColin Finck         ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1401c2c66affSColin Finck 
1402c2c66affSColin Finck         /* Increment reinitialization counter */
1403c2c66affSColin Finck         ReinitItem->DriverObject->DriverExtension->Count++;
1404c2c66affSColin Finck 
1405c2c66affSColin Finck         /* Remove the device object flag */
1406c2c66affSColin Finck         ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED;
1407c2c66affSColin Finck 
1408c2c66affSColin Finck         /* Call the routine */
1409c2c66affSColin Finck         ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1410c2c66affSColin Finck                                   ReinitItem->Context,
1411c2c66affSColin Finck                                   ReinitItem->DriverObject->
1412c2c66affSColin Finck                                   DriverExtension->Count);
1413c2c66affSColin Finck 
1414c2c66affSColin Finck         /* Free the entry */
1415c2c66affSColin Finck         ExFreePool(Entry);
1416c2c66affSColin Finck 
1417c2c66affSColin Finck         /* Move to the next one */
1418c2c66affSColin Finck         Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1419c2c66affSColin Finck                                             &DriverReinitListLock);
1420c2c66affSColin Finck     }
1421c2c66affSColin Finck }
1422c2c66affSColin Finck 
1423c2c66affSColin Finck VOID
1424c2c66affSColin Finck NTAPI
1425c2c66affSColin Finck IopReinitializeBootDrivers(VOID)
1426c2c66affSColin Finck {
1427c2c66affSColin Finck     PDRIVER_REINIT_ITEM ReinitItem;
1428c2c66affSColin Finck     PLIST_ENTRY Entry;
1429c2c66affSColin Finck 
1430c2c66affSColin Finck     /* Get the first entry and start looping */
1431c2c66affSColin Finck     Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1432c2c66affSColin Finck                                         &DriverBootReinitListLock);
1433c2c66affSColin Finck     while (Entry)
1434c2c66affSColin Finck     {
1435c2c66affSColin Finck         /* Get the item */
1436c2c66affSColin Finck         ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1437c2c66affSColin Finck 
1438c2c66affSColin Finck         /* Increment reinitialization counter */
1439c2c66affSColin Finck         ReinitItem->DriverObject->DriverExtension->Count++;
1440c2c66affSColin Finck 
1441c2c66affSColin Finck         /* Remove the device object flag */
1442c2c66affSColin Finck         ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED;
1443c2c66affSColin Finck 
1444c2c66affSColin Finck         /* Call the routine */
1445c2c66affSColin Finck         ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1446c2c66affSColin Finck                                   ReinitItem->Context,
1447c2c66affSColin Finck                                   ReinitItem->DriverObject->
1448c2c66affSColin Finck                                   DriverExtension->Count);
1449c2c66affSColin Finck 
1450c2c66affSColin Finck         /* Free the entry */
1451c2c66affSColin Finck         ExFreePool(Entry);
1452c2c66affSColin Finck 
1453c2c66affSColin Finck         /* Move to the next one */
1454c2c66affSColin Finck         Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1455c2c66affSColin Finck                                             &DriverBootReinitListLock);
1456c2c66affSColin Finck     }
1457c2c66affSColin Finck }
1458c2c66affSColin Finck 
1459c2c66affSColin Finck NTSTATUS
1460c2c66affSColin Finck NTAPI
1461c2c66affSColin Finck IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1462c2c66affSColin Finck                 IN PDRIVER_INITIALIZE InitializationFunction,
146345012aa4SHermès Bélusca-Maïto                 IN PUNICODE_STRING RegistryPath OPTIONAL,
1464c2c66affSColin Finck                 IN PCUNICODE_STRING ServiceName,
146545012aa4SHermès Bélusca-Maïto                 IN PLDR_DATA_TABLE_ENTRY ModuleObject OPTIONAL,
1466c2c66affSColin Finck                 OUT PDRIVER_OBJECT *pDriverObject)
1467c2c66affSColin Finck {
1468c2c66affSColin Finck     WCHAR NameBuffer[100];
1469c2c66affSColin Finck     USHORT NameLength;
1470c2c66affSColin Finck     UNICODE_STRING LocalDriverName;
1471c2c66affSColin Finck     NTSTATUS Status;
1472c2c66affSColin Finck     OBJECT_ATTRIBUTES ObjectAttributes;
1473c2c66affSColin Finck     ULONG ObjectSize;
1474c2c66affSColin Finck     PDRIVER_OBJECT DriverObject;
1475c2c66affSColin Finck     UNICODE_STRING ServiceKeyName;
1476c2c66affSColin Finck     HANDLE hDriver;
1477c2c66affSColin Finck     ULONG i, RetryCount = 0;
1478c2c66affSColin Finck 
1479c2c66affSColin Finck try_again:
1480c2c66affSColin Finck     /* First, create a unique name for the driver if we don't have one */
1481c2c66affSColin Finck     if (!DriverName)
1482c2c66affSColin Finck     {
1483c2c66affSColin Finck         /* Create a random name and set up the string */
1484c2c66affSColin Finck         NameLength = (USHORT)swprintf(NameBuffer,
1485c2c66affSColin Finck                                       DRIVER_ROOT_NAME L"%08u",
1486c2c66affSColin Finck                                       KeTickCount.LowPart);
1487c2c66affSColin Finck         LocalDriverName.Length = NameLength * sizeof(WCHAR);
1488c2c66affSColin Finck         LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1489c2c66affSColin Finck         LocalDriverName.Buffer = NameBuffer;
1490c2c66affSColin Finck     }
1491c2c66affSColin Finck     else
1492c2c66affSColin Finck     {
1493c2c66affSColin Finck         /* So we can avoid another code path, use a local var */
1494c2c66affSColin Finck         LocalDriverName = *DriverName;
1495c2c66affSColin Finck     }
1496c2c66affSColin Finck 
1497c2c66affSColin Finck     /* Initialize the Attributes */
1498c2c66affSColin Finck     ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION);
1499c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
1500c2c66affSColin Finck                                &LocalDriverName,
1501c2c66affSColin Finck                                OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1502c2c66affSColin Finck                                NULL,
1503c2c66affSColin Finck                                NULL);
1504c2c66affSColin Finck 
1505c2c66affSColin Finck     /* Create the Object */
1506c2c66affSColin Finck     Status = ObCreateObject(KernelMode,
1507c2c66affSColin Finck                             IoDriverObjectType,
1508c2c66affSColin Finck                             &ObjectAttributes,
1509c2c66affSColin Finck                             KernelMode,
1510c2c66affSColin Finck                             NULL,
1511c2c66affSColin Finck                             ObjectSize,
1512c2c66affSColin Finck                             0,
1513c2c66affSColin Finck                             0,
1514c2c66affSColin Finck                             (PVOID*)&DriverObject);
1515c2c66affSColin Finck     if (!NT_SUCCESS(Status)) return Status;
1516c2c66affSColin Finck 
1517c2c66affSColin Finck     DPRINT("IopCreateDriver(): created DO %p\n", DriverObject);
1518c2c66affSColin Finck 
1519c2c66affSColin Finck     /* Set up the Object */
1520c2c66affSColin Finck     RtlZeroMemory(DriverObject, ObjectSize);
1521c2c66affSColin Finck     DriverObject->Type = IO_TYPE_DRIVER;
1522c2c66affSColin Finck     DriverObject->Size = sizeof(DRIVER_OBJECT);
152345012aa4SHermès Bélusca-Maïto 
152445012aa4SHermès Bélusca-Maïto     /*
152545012aa4SHermès Bélusca-Maïto      * Check whether RegistryPath and ModuleObject are both NULL because
152645012aa4SHermès Bélusca-Maïto      * IoCreateDriver() was called to initialize a built-in driver.
152745012aa4SHermès Bélusca-Maïto      */
152845012aa4SHermès Bélusca-Maïto     if ((RegistryPath != NULL) || (ModuleObject != NULL))
1529c2c66affSColin Finck         DriverObject->Flags = DRVO_LEGACY_DRIVER;
153045012aa4SHermès Bélusca-Maïto     else
153145012aa4SHermès Bélusca-Maïto         DriverObject->Flags = DRVO_BUILTIN_DRIVER;
153245012aa4SHermès Bélusca-Maïto 
1533c2c66affSColin Finck     DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1534c2c66affSColin Finck     DriverObject->DriverExtension->DriverObject = DriverObject;
1535c2c66affSColin Finck     DriverObject->DriverInit = InitializationFunction;
1536c2c66affSColin Finck     DriverObject->DriverSection = ModuleObject;
1537c2c66affSColin Finck     /* Loop all Major Functions */
1538c2c66affSColin Finck     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1539c2c66affSColin Finck     {
1540c2c66affSColin Finck         /* Invalidate each function */
1541c2c66affSColin Finck         DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1542c2c66affSColin Finck     }
1543c2c66affSColin Finck 
1544c2c66affSColin Finck     /* Set up the service key name buffer */
1545c2c66affSColin Finck     ServiceKeyName.MaximumLength = ServiceName->Length + sizeof(UNICODE_NULL);
1546c2c66affSColin Finck     ServiceKeyName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
1547c2c66affSColin Finck                                                   ServiceKeyName.MaximumLength,
1548c2c66affSColin Finck                                                   TAG_IO);
1549c2c66affSColin Finck     if (!ServiceKeyName.Buffer)
1550c2c66affSColin Finck     {
1551c2c66affSColin Finck         /* Fail */
1552c2c66affSColin Finck         ObMakeTemporaryObject(DriverObject);
1553c2c66affSColin Finck         ObDereferenceObject(DriverObject);
1554c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
1555c2c66affSColin Finck     }
1556c2c66affSColin Finck 
1557c2c66affSColin Finck     /* Copy the name and set it in the driver extension */
1558c2c66affSColin Finck     RtlCopyUnicodeString(&ServiceKeyName,
1559c2c66affSColin Finck                          ServiceName);
1560c2c66affSColin Finck     DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1561c2c66affSColin Finck 
1562c2c66affSColin Finck     /* Make a copy of the driver name to store in the driver object */
1563c2c66affSColin Finck     DriverObject->DriverName.MaximumLength = LocalDriverName.Length;
1564c2c66affSColin Finck     DriverObject->DriverName.Buffer = ExAllocatePoolWithTag(PagedPool,
1565c2c66affSColin Finck                                                             DriverObject->DriverName.MaximumLength,
1566c2c66affSColin Finck                                                             TAG_IO);
1567c2c66affSColin Finck     if (!DriverObject->DriverName.Buffer)
1568c2c66affSColin Finck     {
1569c2c66affSColin Finck         /* Fail */
1570c2c66affSColin Finck         ObMakeTemporaryObject(DriverObject);
1571c2c66affSColin Finck         ObDereferenceObject(DriverObject);
1572c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
1573c2c66affSColin Finck     }
1574c2c66affSColin Finck 
1575c2c66affSColin Finck     RtlCopyUnicodeString(&DriverObject->DriverName,
1576c2c66affSColin Finck                          &LocalDriverName);
1577c2c66affSColin Finck 
1578c2c66affSColin Finck     /* Add the Object and get its handle */
1579c2c66affSColin Finck     Status = ObInsertObject(DriverObject,
1580c2c66affSColin Finck                             NULL,
1581c2c66affSColin Finck                             FILE_READ_DATA,
1582c2c66affSColin Finck                             0,
1583c2c66affSColin Finck                             NULL,
1584c2c66affSColin Finck                             &hDriver);
1585c2c66affSColin Finck 
1586c2c66affSColin Finck     /* Eliminate small possibility when this function is called more than
1587c2c66affSColin Finck        once in a row, and KeTickCount doesn't get enough time to change */
1588c2c66affSColin Finck     if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100))
1589c2c66affSColin Finck     {
1590c2c66affSColin Finck         RetryCount++;
1591c2c66affSColin Finck         goto try_again;
1592c2c66affSColin Finck     }
1593c2c66affSColin Finck 
1594c2c66affSColin Finck     if (!NT_SUCCESS(Status)) return Status;
1595c2c66affSColin Finck 
1596c2c66affSColin Finck     /* Now reference it */
1597c2c66affSColin Finck     Status = ObReferenceObjectByHandle(hDriver,
1598c2c66affSColin Finck                                        0,
1599c2c66affSColin Finck                                        IoDriverObjectType,
1600c2c66affSColin Finck                                        KernelMode,
1601c2c66affSColin Finck                                        (PVOID*)&DriverObject,
1602c2c66affSColin Finck                                        NULL);
1603c2c66affSColin Finck 
1604c2c66affSColin Finck     /* Close the extra handle */
1605c2c66affSColin Finck     ZwClose(hDriver);
1606c2c66affSColin Finck 
1607c2c66affSColin Finck     if (!NT_SUCCESS(Status))
1608c2c66affSColin Finck     {
1609c2c66affSColin Finck         /* Fail */
1610c2c66affSColin Finck         ObMakeTemporaryObject(DriverObject);
1611c2c66affSColin Finck         ObDereferenceObject(DriverObject);
1612c2c66affSColin Finck         return Status;
1613c2c66affSColin Finck     }
1614c2c66affSColin Finck 
1615c2c66affSColin Finck     DriverObject->HardwareDatabase = &IopHardwareDatabaseKey;
1616c2c66affSColin Finck     DriverObject->DriverStart = ModuleObject ? ModuleObject->DllBase : 0;
1617c2c66affSColin Finck     DriverObject->DriverSize = ModuleObject ? ModuleObject->SizeOfImage : 0;
1618c2c66affSColin Finck 
1619c2c66affSColin Finck     /* Finally, call its init function */
1620c2c66affSColin Finck     DPRINT("RegistryKey: %wZ\n", RegistryPath);
1621c2c66affSColin Finck     DPRINT("Calling driver entrypoint at %p\n", InitializationFunction);
1622c2c66affSColin Finck     Status = (*InitializationFunction)(DriverObject, RegistryPath);
1623c2c66affSColin Finck     if (!NT_SUCCESS(Status))
1624c2c66affSColin Finck     {
1625c2c66affSColin Finck         /* If it didn't work, then kill the object */
1626c2c66affSColin Finck         DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status);
1627c2c66affSColin Finck         DriverObject->DriverSection = NULL;
1628c2c66affSColin Finck         ObMakeTemporaryObject(DriverObject);
1629c2c66affSColin Finck         ObDereferenceObject(DriverObject);
1630c2c66affSColin Finck         return Status;
1631c2c66affSColin Finck     }
1632c2c66affSColin Finck     else
1633c2c66affSColin Finck     {
1634c2c66affSColin Finck         /* Returns to caller the object */
1635c2c66affSColin Finck         *pDriverObject = DriverObject;
1636c2c66affSColin Finck     }
1637c2c66affSColin Finck 
1638c2c66affSColin Finck     /* We're going to say if we don't have any DOs from DriverEntry, then we're not legacy.
1639c2c66affSColin Finck      * Other parts of the I/O manager depend on this behavior */
1640c2c66affSColin Finck     if (!DriverObject->DeviceObject) DriverObject->Flags &= ~DRVO_LEGACY_DRIVER;
1641c2c66affSColin Finck 
1642c2c66affSColin Finck     /* Loop all Major Functions */
1643c2c66affSColin Finck     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1644c2c66affSColin Finck     {
1645c2c66affSColin Finck         /*
1646c2c66affSColin Finck          * Make sure the driver didn't set any dispatch entry point to NULL!
1647c2c66affSColin Finck          * Doing so is illegal; drivers shouldn't touch entry points they
1648c2c66affSColin Finck          * do not implement.
1649c2c66affSColin Finck          */
1650c2c66affSColin Finck 
1651c2c66affSColin Finck         /* Check if it did so anyway */
1652c2c66affSColin Finck         if (!DriverObject->MajorFunction[i])
1653c2c66affSColin Finck         {
1654c2c66affSColin Finck             /* Print a warning in the debug log */
1655c2c66affSColin Finck             DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%lu] to NULL!\n",
1656c2c66affSColin Finck                     &DriverObject->DriverName, i);
1657c2c66affSColin Finck 
1658c2c66affSColin Finck             /* Fix it up */
1659c2c66affSColin Finck             DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1660c2c66affSColin Finck         }
1661c2c66affSColin Finck     }
1662c2c66affSColin Finck 
1663c2c66affSColin Finck     /* Return the Status */
1664c2c66affSColin Finck     return Status;
1665c2c66affSColin Finck }
1666c2c66affSColin Finck 
1667c2c66affSColin Finck /* PUBLIC FUNCTIONS ***********************************************************/
1668c2c66affSColin Finck 
1669c2c66affSColin Finck /*
1670c2c66affSColin Finck  * @implemented
1671c2c66affSColin Finck  */
1672c2c66affSColin Finck NTSTATUS
1673c2c66affSColin Finck NTAPI
1674c2c66affSColin Finck IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1675c2c66affSColin Finck                IN PDRIVER_INITIALIZE InitializationFunction)
1676c2c66affSColin Finck {
1677c2c66affSColin Finck     PDRIVER_OBJECT DriverObject;
1678c2c66affSColin Finck     return IopCreateDriver(DriverName, InitializationFunction, NULL, DriverName, NULL, &DriverObject);
1679c2c66affSColin Finck }
1680c2c66affSColin Finck 
1681c2c66affSColin Finck /*
1682c2c66affSColin Finck  * @implemented
1683c2c66affSColin Finck  */
1684c2c66affSColin Finck VOID
1685c2c66affSColin Finck NTAPI
1686c2c66affSColin Finck IoDeleteDriver(IN PDRIVER_OBJECT DriverObject)
1687c2c66affSColin Finck {
1688c2c66affSColin Finck     /* Simply dereference the Object */
1689c2c66affSColin Finck     ObDereferenceObject(DriverObject);
1690c2c66affSColin Finck }
1691c2c66affSColin Finck 
1692c2c66affSColin Finck /*
1693c2c66affSColin Finck  * @implemented
1694c2c66affSColin Finck  */
1695c2c66affSColin Finck VOID
1696c2c66affSColin Finck NTAPI
1697c2c66affSColin Finck IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1698c2c66affSColin Finck                                      IN PDRIVER_REINITIALIZE ReinitRoutine,
1699c2c66affSColin Finck                                      IN PVOID Context)
1700c2c66affSColin Finck {
1701c2c66affSColin Finck     PDRIVER_REINIT_ITEM ReinitItem;
1702c2c66affSColin Finck 
1703c2c66affSColin Finck     /* Allocate the entry */
1704c2c66affSColin Finck     ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1705c2c66affSColin Finck                                        sizeof(DRIVER_REINIT_ITEM),
1706c2c66affSColin Finck                                        TAG_REINIT);
1707c2c66affSColin Finck     if (!ReinitItem) return;
1708c2c66affSColin Finck 
1709c2c66affSColin Finck     /* Fill it out */
1710c2c66affSColin Finck     ReinitItem->DriverObject = DriverObject;
1711c2c66affSColin Finck     ReinitItem->ReinitRoutine = ReinitRoutine;
1712c2c66affSColin Finck     ReinitItem->Context = Context;
1713c2c66affSColin Finck 
1714c2c66affSColin Finck     /* Set the Driver Object flag and insert the entry into the list */
1715c2c66affSColin Finck     DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
1716c2c66affSColin Finck     ExInterlockedInsertTailList(&DriverBootReinitListHead,
1717c2c66affSColin Finck                                 &ReinitItem->ItemEntry,
1718c2c66affSColin Finck                                 &DriverBootReinitListLock);
1719c2c66affSColin Finck }
1720c2c66affSColin Finck 
1721c2c66affSColin Finck /*
1722c2c66affSColin Finck  * @implemented
1723c2c66affSColin Finck  */
1724c2c66affSColin Finck VOID
1725c2c66affSColin Finck NTAPI
1726c2c66affSColin Finck IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1727c2c66affSColin Finck                                  IN PDRIVER_REINITIALIZE ReinitRoutine,
1728c2c66affSColin Finck                                  IN PVOID Context)
1729c2c66affSColin Finck {
1730c2c66affSColin Finck     PDRIVER_REINIT_ITEM ReinitItem;
1731c2c66affSColin Finck 
1732c2c66affSColin Finck     /* Allocate the entry */
1733c2c66affSColin Finck     ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1734c2c66affSColin Finck                                        sizeof(DRIVER_REINIT_ITEM),
1735c2c66affSColin Finck                                        TAG_REINIT);
1736c2c66affSColin Finck     if (!ReinitItem) return;
1737c2c66affSColin Finck 
1738c2c66affSColin Finck     /* Fill it out */
1739c2c66affSColin Finck     ReinitItem->DriverObject = DriverObject;
1740c2c66affSColin Finck     ReinitItem->ReinitRoutine = ReinitRoutine;
1741c2c66affSColin Finck     ReinitItem->Context = Context;
1742c2c66affSColin Finck 
1743c2c66affSColin Finck     /* Set the Driver Object flag and insert the entry into the list */
1744c2c66affSColin Finck     DriverObject->Flags |= DRVO_REINIT_REGISTERED;
1745c2c66affSColin Finck     ExInterlockedInsertTailList(&DriverReinitListHead,
1746c2c66affSColin Finck                                 &ReinitItem->ItemEntry,
1747c2c66affSColin Finck                                 &DriverReinitListLock);
1748c2c66affSColin Finck }
1749c2c66affSColin Finck 
1750c2c66affSColin Finck /*
1751c2c66affSColin Finck  * @implemented
1752c2c66affSColin Finck  */
1753c2c66affSColin Finck NTSTATUS
1754c2c66affSColin Finck NTAPI
1755c2c66affSColin Finck IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1756c2c66affSColin Finck                                 IN PVOID ClientIdentificationAddress,
1757c2c66affSColin Finck                                 IN ULONG DriverObjectExtensionSize,
1758c2c66affSColin Finck                                 OUT PVOID *DriverObjectExtension)
1759c2c66affSColin Finck {
1760c2c66affSColin Finck     KIRQL OldIrql;
1761c2c66affSColin Finck     PIO_CLIENT_EXTENSION DriverExtensions, NewDriverExtension;
1762c2c66affSColin Finck     BOOLEAN Inserted = FALSE;
1763c2c66affSColin Finck 
1764c2c66affSColin Finck     /* Assume failure */
1765c2c66affSColin Finck     *DriverObjectExtension = NULL;
1766c2c66affSColin Finck 
1767c2c66affSColin Finck     /* Allocate the extension */
1768c2c66affSColin Finck     NewDriverExtension = ExAllocatePoolWithTag(NonPagedPool,
1769c2c66affSColin Finck                                                sizeof(IO_CLIENT_EXTENSION) +
1770c2c66affSColin Finck                                                DriverObjectExtensionSize,
1771c2c66affSColin Finck                                                TAG_DRIVER_EXTENSION);
1772c2c66affSColin Finck     if (!NewDriverExtension) return STATUS_INSUFFICIENT_RESOURCES;
1773c2c66affSColin Finck 
1774c2c66affSColin Finck     /* Clear the extension for teh caller */
1775c2c66affSColin Finck     RtlZeroMemory(NewDriverExtension,
1776c2c66affSColin Finck                   sizeof(IO_CLIENT_EXTENSION) + DriverObjectExtensionSize);
1777c2c66affSColin Finck 
1778c2c66affSColin Finck     /* Acqure lock */
1779c2c66affSColin Finck     OldIrql = KeRaiseIrqlToDpcLevel();
1780c2c66affSColin Finck 
1781c2c66affSColin Finck     /* Fill out the extension */
1782c2c66affSColin Finck     NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
1783c2c66affSColin Finck 
1784c2c66affSColin Finck     /* Loop the current extensions */
1785c2c66affSColin Finck     DriverExtensions = IoGetDrvObjExtension(DriverObject)->
1786c2c66affSColin Finck                        ClientDriverExtension;
1787c2c66affSColin Finck     while (DriverExtensions)
1788c2c66affSColin Finck     {
1789c2c66affSColin Finck         /* Check if the identifier matches */
1790c2c66affSColin Finck         if (DriverExtensions->ClientIdentificationAddress ==
1791c2c66affSColin Finck             ClientIdentificationAddress)
1792c2c66affSColin Finck         {
1793c2c66affSColin Finck             /* We have a collision, break out */
1794c2c66affSColin Finck             break;
1795c2c66affSColin Finck         }
1796c2c66affSColin Finck 
1797c2c66affSColin Finck         /* Go to the next one */
1798c2c66affSColin Finck         DriverExtensions = DriverExtensions->NextExtension;
1799c2c66affSColin Finck     }
1800c2c66affSColin Finck 
1801c2c66affSColin Finck     /* Check if we didn't collide */
1802c2c66affSColin Finck     if (!DriverExtensions)
1803c2c66affSColin Finck     {
1804c2c66affSColin Finck         /* Link this one in */
1805c2c66affSColin Finck         NewDriverExtension->NextExtension =
1806c2c66affSColin Finck             IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1807c2c66affSColin Finck         IoGetDrvObjExtension(DriverObject)->ClientDriverExtension =
1808c2c66affSColin Finck             NewDriverExtension;
1809c2c66affSColin Finck         Inserted = TRUE;
1810c2c66affSColin Finck     }
1811c2c66affSColin Finck 
1812c2c66affSColin Finck     /* Release the lock */
1813c2c66affSColin Finck     KeLowerIrql(OldIrql);
1814c2c66affSColin Finck 
1815c2c66affSColin Finck     /* Check if insertion failed */
1816c2c66affSColin Finck     if (!Inserted)
1817c2c66affSColin Finck     {
1818c2c66affSColin Finck         /* Free the entry and fail */
1819c2c66affSColin Finck         ExFreePoolWithTag(NewDriverExtension, TAG_DRIVER_EXTENSION);
1820c2c66affSColin Finck         return STATUS_OBJECT_NAME_COLLISION;
1821c2c66affSColin Finck     }
1822c2c66affSColin Finck 
1823c2c66affSColin Finck     /* Otherwise, return the pointer */
1824c2c66affSColin Finck     *DriverObjectExtension = NewDriverExtension + 1;
1825c2c66affSColin Finck     return STATUS_SUCCESS;
1826c2c66affSColin Finck }
1827c2c66affSColin Finck 
1828c2c66affSColin Finck /*
1829c2c66affSColin Finck  * @implemented
1830c2c66affSColin Finck  */
1831c2c66affSColin Finck PVOID
1832c2c66affSColin Finck NTAPI
1833c2c66affSColin Finck IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1834c2c66affSColin Finck                            IN PVOID ClientIdentificationAddress)
1835c2c66affSColin Finck {
1836c2c66affSColin Finck     KIRQL OldIrql;
1837c2c66affSColin Finck     PIO_CLIENT_EXTENSION DriverExtensions;
1838c2c66affSColin Finck 
1839c2c66affSColin Finck     /* Acquire lock */
1840c2c66affSColin Finck     OldIrql = KeRaiseIrqlToDpcLevel();
1841c2c66affSColin Finck 
1842c2c66affSColin Finck     /* Loop the list until we find the right one */
1843c2c66affSColin Finck     DriverExtensions = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1844c2c66affSColin Finck     while (DriverExtensions)
1845c2c66affSColin Finck     {
1846c2c66affSColin Finck         /* Check for a match */
1847c2c66affSColin Finck         if (DriverExtensions->ClientIdentificationAddress ==
1848c2c66affSColin Finck             ClientIdentificationAddress)
1849c2c66affSColin Finck         {
1850c2c66affSColin Finck             /* Break out */
1851c2c66affSColin Finck             break;
1852c2c66affSColin Finck         }
1853c2c66affSColin Finck 
1854c2c66affSColin Finck         /* Keep looping */
1855c2c66affSColin Finck         DriverExtensions = DriverExtensions->NextExtension;
1856c2c66affSColin Finck     }
1857c2c66affSColin Finck 
1858c2c66affSColin Finck     /* Release lock */
1859c2c66affSColin Finck     KeLowerIrql(OldIrql);
1860c2c66affSColin Finck 
1861c2c66affSColin Finck     /* Return nothing or the extension */
1862c2c66affSColin Finck     if (!DriverExtensions) return NULL;
1863c2c66affSColin Finck     return DriverExtensions + 1;
1864c2c66affSColin Finck }
1865c2c66affSColin Finck 
1866c2c66affSColin Finck VOID
1867c2c66affSColin Finck NTAPI
1868c2c66affSColin Finck IopLoadUnloadDriverWorker(
1869c2c66affSColin Finck     _Inout_ PVOID Parameter)
1870c2c66affSColin Finck {
1871c2c66affSColin Finck     PLOAD_UNLOAD_PARAMS LoadParams = Parameter;
1872c2c66affSColin Finck 
1873c2c66affSColin Finck     ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess);
1874c2c66affSColin Finck     LoadParams->Status = IopLoadUnloadDriver(LoadParams->RegistryPath,
1875c2c66affSColin Finck                                              &LoadParams->DriverObject);
1876c2c66affSColin Finck     KeSetEvent(&LoadParams->Event, 0, FALSE);
1877c2c66affSColin Finck }
1878c2c66affSColin Finck 
1879c2c66affSColin Finck NTSTATUS
1880c2c66affSColin Finck NTAPI
1881c2c66affSColin Finck IopLoadUnloadDriver(
1882c2c66affSColin Finck     _In_opt_ PCUNICODE_STRING RegistryPath,
1883c2c66affSColin Finck     _Inout_ PDRIVER_OBJECT *DriverObject)
1884c2c66affSColin Finck {
1885c2c66affSColin Finck     RTL_QUERY_REGISTRY_TABLE QueryTable[3];
1886c2c66affSColin Finck     UNICODE_STRING ImagePath;
1887c2c66affSColin Finck     UNICODE_STRING ServiceName;
1888c2c66affSColin Finck     NTSTATUS Status;
1889c2c66affSColin Finck     ULONG Type;
1890c2c66affSColin Finck     PDEVICE_NODE DeviceNode;
1891c2c66affSColin Finck     PLDR_DATA_TABLE_ENTRY ModuleObject;
1892c2c66affSColin Finck     PVOID BaseAddress;
1893c2c66affSColin Finck     WCHAR *cur;
1894c2c66affSColin Finck 
1895c2c66affSColin Finck     /* Load/Unload must be called from system process */
1896c2c66affSColin Finck     if (PsGetCurrentProcess() != PsInitialSystemProcess)
1897c2c66affSColin Finck     {
1898c2c66affSColin Finck         LOAD_UNLOAD_PARAMS LoadParams;
1899c2c66affSColin Finck 
1900c2c66affSColin Finck         /* Prepare parameters block */
1901c2c66affSColin Finck         LoadParams.RegistryPath = RegistryPath;
1902c2c66affSColin Finck         LoadParams.DriverObject = *DriverObject;
1903c2c66affSColin Finck         KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
1904c2c66affSColin Finck 
1905c2c66affSColin Finck         /* Initialize and queue a work item */
1906c2c66affSColin Finck         ExInitializeWorkItem(&LoadParams.WorkItem,
1907c2c66affSColin Finck                              IopLoadUnloadDriverWorker,
1908c2c66affSColin Finck                              &LoadParams);
1909c2c66affSColin Finck         ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
1910c2c66affSColin Finck 
1911c2c66affSColin Finck         /* And wait till it completes */
1912c2c66affSColin Finck         KeWaitForSingleObject(&LoadParams.Event,
1913c2c66affSColin Finck                               UserRequest,
1914c2c66affSColin Finck                               KernelMode,
1915c2c66affSColin Finck                               FALSE,
1916c2c66affSColin Finck                               NULL);
1917c2c66affSColin Finck         return LoadParams.Status;
1918c2c66affSColin Finck     }
1919c2c66affSColin Finck 
1920c2c66affSColin Finck     /* Check if it's an unload request */
1921c2c66affSColin Finck     if (*DriverObject)
1922c2c66affSColin Finck     {
1923c2c66affSColin Finck         (*DriverObject)->DriverUnload(*DriverObject);
1924c2c66affSColin Finck         return STATUS_SUCCESS;
1925c2c66affSColin Finck     }
1926c2c66affSColin Finck 
1927c2c66affSColin Finck     RtlInitUnicodeString(&ImagePath, NULL);
1928c2c66affSColin Finck 
1929c2c66affSColin Finck     /*
1930c2c66affSColin Finck      * Get the service name from the registry key name.
1931c2c66affSColin Finck      */
1932c2c66affSColin Finck     ASSERT(RegistryPath->Length >= sizeof(WCHAR));
1933c2c66affSColin Finck 
1934c2c66affSColin Finck     ServiceName = *RegistryPath;
1935c2c66affSColin Finck     cur = RegistryPath->Buffer + RegistryPath->Length / sizeof(WCHAR) - 1;
1936c2c66affSColin Finck     while (RegistryPath->Buffer != cur)
1937c2c66affSColin Finck     {
1938c2c66affSColin Finck         if (*cur == L'\\')
1939c2c66affSColin Finck         {
1940c2c66affSColin Finck             ServiceName.Buffer = cur + 1;
1941c2c66affSColin Finck             ServiceName.Length = RegistryPath->Length -
1942c2c66affSColin Finck                                  (USHORT)((ULONG_PTR)ServiceName.Buffer -
1943c2c66affSColin Finck                                           (ULONG_PTR)RegistryPath->Buffer);
1944c2c66affSColin Finck             break;
1945c2c66affSColin Finck         }
1946c2c66affSColin Finck         cur--;
1947c2c66affSColin Finck     }
1948c2c66affSColin Finck 
1949c2c66affSColin Finck     /*
1950c2c66affSColin Finck      * Get service type.
1951c2c66affSColin Finck      */
1952c2c66affSColin Finck     RtlZeroMemory(&QueryTable, sizeof(QueryTable));
1953c2c66affSColin Finck 
1954c2c66affSColin Finck     RtlInitUnicodeString(&ImagePath, NULL);
1955c2c66affSColin Finck 
1956c2c66affSColin Finck     QueryTable[0].Name = L"Type";
1957c2c66affSColin Finck     QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1958c2c66affSColin Finck     QueryTable[0].EntryContext = &Type;
1959c2c66affSColin Finck 
1960c2c66affSColin Finck     QueryTable[1].Name = L"ImagePath";
1961c2c66affSColin Finck     QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1962c2c66affSColin Finck     QueryTable[1].EntryContext = &ImagePath;
1963c2c66affSColin Finck 
1964c2c66affSColin Finck     Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1965c2c66affSColin Finck                                     RegistryPath->Buffer,
1966c2c66affSColin Finck                                     QueryTable, NULL, NULL);
1967c2c66affSColin Finck     if (!NT_SUCCESS(Status))
1968c2c66affSColin Finck     {
1969c2c66affSColin Finck         DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
1970c2c66affSColin Finck         if (ImagePath.Buffer) ExFreePool(ImagePath.Buffer);
1971c2c66affSColin Finck         return Status;
1972c2c66affSColin Finck     }
1973c2c66affSColin Finck 
1974c2c66affSColin Finck     /*
1975c2c66affSColin Finck      * Normalize the image path for all later processing.
1976c2c66affSColin Finck      */
1977c2c66affSColin Finck     Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1978c2c66affSColin Finck     if (!NT_SUCCESS(Status))
1979c2c66affSColin Finck     {
1980c2c66affSColin Finck         DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1981c2c66affSColin Finck         return Status;
1982c2c66affSColin Finck     }
1983c2c66affSColin Finck 
1984c2c66affSColin Finck     DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
1985c2c66affSColin Finck     DPRINT("Type: %lx\n", Type);
1986c2c66affSColin Finck 
1987c2c66affSColin Finck     KeEnterCriticalRegion();
1988c2c66affSColin Finck     ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE);
1989c2c66affSColin Finck     /*
1990c2c66affSColin Finck      * Get existing DriverObject pointer (in case the driver
1991c2c66affSColin Finck      * has already been loaded and initialized).
1992c2c66affSColin Finck      */
1993c2c66affSColin Finck     Status = IopGetDriverObject(DriverObject,
1994c2c66affSColin Finck                                 &ServiceName,
1995c2c66affSColin Finck                                 (Type == SERVICE_FILE_SYSTEM_DRIVER ||
1996c2c66affSColin Finck                                  Type == SERVICE_RECOGNIZER_DRIVER));
1997c2c66affSColin Finck 
1998c2c66affSColin Finck     if (!NT_SUCCESS(Status))
1999c2c66affSColin Finck     {
2000c2c66affSColin Finck         /*
2001c2c66affSColin Finck          * Load the driver module
2002c2c66affSColin Finck          */
2003c2c66affSColin Finck         DPRINT("Loading module from %wZ\n", &ImagePath);
2004c2c66affSColin Finck         Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress);
2005c2c66affSColin Finck         if (!NT_SUCCESS(Status))
2006c2c66affSColin Finck         {
2007c2c66affSColin Finck             DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
2008c2c66affSColin Finck             ExReleaseResourceLite(&IopDriverLoadResource);
2009c2c66affSColin Finck             KeLeaveCriticalRegion();
2010c2c66affSColin Finck             return Status;
2011c2c66affSColin Finck         }
2012c2c66affSColin Finck 
2013c2c66affSColin Finck         /*
2014c2c66affSColin Finck          * Initialize the driver module if it's loaded for the first time
2015c2c66affSColin Finck          */
2016c2c66affSColin Finck         Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
2017c2c66affSColin Finck         if (!NT_SUCCESS(Status))
2018c2c66affSColin Finck         {
2019c2c66affSColin Finck             DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status);
2020c2c66affSColin Finck             ExReleaseResourceLite(&IopDriverLoadResource);
2021c2c66affSColin Finck             KeLeaveCriticalRegion();
2022c2c66affSColin Finck             MmUnloadSystemImage(ModuleObject);
2023c2c66affSColin Finck             return Status;
2024c2c66affSColin Finck         }
2025c2c66affSColin Finck 
2026c2c66affSColin Finck         IopDisplayLoadingMessage(&DeviceNode->ServiceName);
2027c2c66affSColin Finck 
2028c2c66affSColin Finck         Status = IopInitializeDriverModule(DeviceNode,
2029c2c66affSColin Finck                                            ModuleObject,
2030c2c66affSColin Finck                                            &DeviceNode->ServiceName,
2031c2c66affSColin Finck                                            (Type == SERVICE_FILE_SYSTEM_DRIVER ||
2032c2c66affSColin Finck                                             Type == SERVICE_RECOGNIZER_DRIVER),
2033c2c66affSColin Finck                                            DriverObject);
2034c2c66affSColin Finck         if (!NT_SUCCESS(Status))
2035c2c66affSColin Finck         {
2036c2c66affSColin Finck             DPRINT1("IopInitializeDriverModule() failed (Status %lx)\n", Status);
2037c2c66affSColin Finck             ExReleaseResourceLite(&IopDriverLoadResource);
2038c2c66affSColin Finck             KeLeaveCriticalRegion();
2039c2c66affSColin Finck             MmUnloadSystemImage(ModuleObject);
2040c2c66affSColin Finck             return Status;
2041c2c66affSColin Finck         }
2042c2c66affSColin Finck 
2043c2c66affSColin Finck         ExReleaseResourceLite(&IopDriverLoadResource);
2044c2c66affSColin Finck         KeLeaveCriticalRegion();
2045c2c66affSColin Finck 
2046c2c66affSColin Finck         /* Initialize and start device */
2047c2c66affSColin Finck         IopInitializeDevice(DeviceNode, *DriverObject);
2048c2c66affSColin Finck         Status = IopStartDevice(DeviceNode);
2049c2c66affSColin Finck     }
2050c2c66affSColin Finck     else
2051c2c66affSColin Finck     {
2052c2c66affSColin Finck         ExReleaseResourceLite(&IopDriverLoadResource);
2053c2c66affSColin Finck         KeLeaveCriticalRegion();
2054c2c66affSColin Finck 
2055c2c66affSColin Finck         DPRINT("DriverObject already exist in ObjectManager\n");
2056c2c66affSColin Finck         Status = STATUS_IMAGE_ALREADY_LOADED;
2057c2c66affSColin Finck 
2058c2c66affSColin Finck         /* IopGetDriverObject references the DriverObject, so dereference it */
2059c2c66affSColin Finck         ObDereferenceObject(*DriverObject);
2060c2c66affSColin Finck     }
2061c2c66affSColin Finck 
2062c2c66affSColin Finck     return Status;
2063c2c66affSColin Finck }
2064c2c66affSColin Finck 
2065c2c66affSColin Finck /*
2066c2c66affSColin Finck  * NtLoadDriver
2067c2c66affSColin Finck  *
2068c2c66affSColin Finck  * Loads a device driver.
2069c2c66affSColin Finck  *
2070c2c66affSColin Finck  * Parameters
2071c2c66affSColin Finck  *    DriverServiceName
2072c2c66affSColin Finck  *       Name of the service to load (registry key).
2073c2c66affSColin Finck  *
2074c2c66affSColin Finck  * Return Value
2075c2c66affSColin Finck  *    Status
2076c2c66affSColin Finck  *
2077c2c66affSColin Finck  * Status
2078c2c66affSColin Finck  *    implemented
2079c2c66affSColin Finck  */
2080c2c66affSColin Finck NTSTATUS NTAPI
2081c2c66affSColin Finck NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
2082c2c66affSColin Finck {
2083c2c66affSColin Finck     UNICODE_STRING CapturedDriverServiceName = { 0, 0, NULL };
2084c2c66affSColin Finck     KPROCESSOR_MODE PreviousMode;
2085c2c66affSColin Finck     PDRIVER_OBJECT DriverObject;
2086c2c66affSColin Finck     NTSTATUS Status;
2087c2c66affSColin Finck 
2088c2c66affSColin Finck     PAGED_CODE();
2089c2c66affSColin Finck 
2090c2c66affSColin Finck     PreviousMode = KeGetPreviousMode();
2091c2c66affSColin Finck 
2092c2c66affSColin Finck     /*
2093c2c66affSColin Finck      * Check security privileges
2094c2c66affSColin Finck      */
2095c2c66affSColin Finck 
2096c2c66affSColin Finck     /* FIXME: Uncomment when privileges will be correctly implemented. */
2097c2c66affSColin Finck #if 0
2098c2c66affSColin Finck     if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2099c2c66affSColin Finck     {
2100c2c66affSColin Finck         DPRINT("Privilege not held\n");
2101c2c66affSColin Finck         return STATUS_PRIVILEGE_NOT_HELD;
2102c2c66affSColin Finck     }
2103c2c66affSColin Finck #endif
2104c2c66affSColin Finck 
2105c2c66affSColin Finck     Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
2106c2c66affSColin Finck                                           PreviousMode,
2107c2c66affSColin Finck                                           DriverServiceName);
2108c2c66affSColin Finck     if (!NT_SUCCESS(Status))
2109c2c66affSColin Finck     {
2110c2c66affSColin Finck         return Status;
2111c2c66affSColin Finck     }
2112c2c66affSColin Finck 
2113c2c66affSColin Finck     DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
2114c2c66affSColin Finck 
2115c2c66affSColin Finck     /* Load driver and call its entry point */
2116c2c66affSColin Finck     DriverObject = NULL;
2117c2c66affSColin Finck     Status = IopLoadUnloadDriver(&CapturedDriverServiceName, &DriverObject);
2118c2c66affSColin Finck 
2119c2c66affSColin Finck     ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
2120c2c66affSColin Finck                                  PreviousMode);
2121c2c66affSColin Finck 
2122c2c66affSColin Finck     return Status;
2123c2c66affSColin Finck }
2124c2c66affSColin Finck 
2125c2c66affSColin Finck /*
2126c2c66affSColin Finck  * NtUnloadDriver
2127c2c66affSColin Finck  *
2128c2c66affSColin Finck  * Unloads a legacy device driver.
2129c2c66affSColin Finck  *
2130c2c66affSColin Finck  * Parameters
2131c2c66affSColin Finck  *    DriverServiceName
2132c2c66affSColin Finck  *       Name of the service to unload (registry key).
2133c2c66affSColin Finck  *
2134c2c66affSColin Finck  * Return Value
2135c2c66affSColin Finck  *    Status
2136c2c66affSColin Finck  *
2137c2c66affSColin Finck  * Status
2138c2c66affSColin Finck  *    implemented
2139c2c66affSColin Finck  */
2140c2c66affSColin Finck 
2141c2c66affSColin Finck NTSTATUS NTAPI
2142c2c66affSColin Finck NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
2143c2c66affSColin Finck {
2144c2c66affSColin Finck     return IopUnloadDriver(DriverServiceName, FALSE);
2145c2c66affSColin Finck }
2146c2c66affSColin Finck 
2147c2c66affSColin Finck /* EOF */
2148