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