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