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