xref: /reactos/ntoskrnl/io/iomgr/driver.c (revision b1c33293)
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 
1138 INIT_FUNCTION
1139 VOID
1140 FASTCALL
1141 IopInitializeSystemDrivers(VOID)
1142 {
1143     PUNICODE_STRING *DriverList, *SavedList;
1144 
1145     /* No system drivers on the boot cd */
1146     if (KeLoaderBlock->SetupLdrBlock) return; // ExpInTextModeSetup
1147 
1148     /* Get the driver list */
1149     SavedList = DriverList = CmGetSystemDriverList();
1150     ASSERT(DriverList);
1151 
1152     /* Loop it */
1153     while (*DriverList)
1154     {
1155         /* Load the driver */
1156         ZwLoadDriver(*DriverList);
1157 
1158         /* Free the entry */
1159         RtlFreeUnicodeString(*DriverList);
1160         ExFreePool(*DriverList);
1161 
1162         /* Next entry */
1163         InbvIndicateProgress();
1164         DriverList++;
1165     }
1166 
1167     /* Free the list */
1168     ExFreePool(SavedList);
1169 }
1170 
1171 /*
1172  * IopUnloadDriver
1173  *
1174  * Unloads a device driver.
1175  *
1176  * Parameters
1177  *    DriverServiceName
1178  *       Name of the service to unload (registry key).
1179  *
1180  *    UnloadPnpDrivers
1181  *       Whether to unload Plug & Plug or only legacy drivers. If this
1182  *       parameter is set to FALSE, the routine will unload only legacy
1183  *       drivers.
1184  *
1185  * Return Value
1186  *    Status
1187  *
1188  * To do
1189  *    Guard the whole function by SEH.
1190  */
1191 
1192 NTSTATUS NTAPI
1193 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
1194 {
1195     UNICODE_STRING Backslash = RTL_CONSTANT_STRING(L"\\");
1196     RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1197     UNICODE_STRING ImagePath;
1198     UNICODE_STRING ServiceName;
1199     UNICODE_STRING ObjectName;
1200     PDRIVER_OBJECT DriverObject;
1201     PDEVICE_OBJECT DeviceObject;
1202     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1203     NTSTATUS Status;
1204     USHORT LastBackslash;
1205     BOOLEAN SafeToUnload = TRUE;
1206     KPROCESSOR_MODE PreviousMode;
1207     UNICODE_STRING CapturedServiceName;
1208 
1209     PAGED_CODE();
1210 
1211     PreviousMode = ExGetPreviousMode();
1212 
1213     /* Need the appropriate priviliege */
1214     if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
1215     {
1216         DPRINT1("No unload privilege!\n");
1217         return STATUS_PRIVILEGE_NOT_HELD;
1218     }
1219 
1220     /* Capture the service name */
1221     Status = ProbeAndCaptureUnicodeString(&CapturedServiceName, PreviousMode, DriverServiceName);
1222     if (!NT_SUCCESS(Status))
1223     {
1224         return Status;
1225     }
1226 
1227     DPRINT("IopUnloadDriver('%wZ', %u)\n", &CapturedServiceName, UnloadPnpDrivers);
1228 
1229 
1230     /* We need a service name */
1231     if (CapturedServiceName.Length == 0)
1232     {
1233         ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1234         return STATUS_INVALID_PARAMETER;
1235     }
1236 
1237     /*
1238      * Get the service name from the registry key name
1239      */
1240     Status = RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END,
1241                                         &CapturedServiceName,
1242                                         &Backslash,
1243                                         &LastBackslash);
1244     if (NT_SUCCESS(Status))
1245     {
1246         NT_ASSERT(CapturedServiceName.Length >= LastBackslash + sizeof(WCHAR));
1247         ServiceName.Buffer = &CapturedServiceName.Buffer[LastBackslash / sizeof(WCHAR) + 1];
1248         ServiceName.Length = CapturedServiceName.Length - LastBackslash - sizeof(WCHAR);
1249         ServiceName.MaximumLength = CapturedServiceName.MaximumLength - LastBackslash - sizeof(WCHAR);
1250     }
1251     else
1252     {
1253         ServiceName = CapturedServiceName;
1254     }
1255 
1256     /*
1257      * Construct the driver object name
1258      */
1259     Status = RtlUShortAdd(sizeof(DRIVER_ROOT_NAME),
1260                           ServiceName.Length,
1261                           &ObjectName.MaximumLength);
1262     if (!NT_SUCCESS(Status))
1263     {
1264         ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1265         return Status;
1266     }
1267     ObjectName.Length = 0;
1268     ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool,
1269                                               ObjectName.MaximumLength,
1270                                               TAG_IO);
1271     if (!ObjectName.Buffer)
1272     {
1273         ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1274         return STATUS_INSUFFICIENT_RESOURCES;
1275     }
1276     NT_VERIFY(NT_SUCCESS(RtlAppendUnicodeToString(&ObjectName, DRIVER_ROOT_NAME)));
1277     NT_VERIFY(NT_SUCCESS(RtlAppendUnicodeStringToString(&ObjectName, &ServiceName)));
1278 
1279     /*
1280      * Find the driver object
1281      */
1282     Status = ObReferenceObjectByName(&ObjectName,
1283                                      0,
1284                                      0,
1285                                      0,
1286                                      IoDriverObjectType,
1287                                      KernelMode,
1288                                      0,
1289                                      (PVOID*)&DriverObject);
1290 
1291     if (!NT_SUCCESS(Status))
1292     {
1293         DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
1294         ExFreePoolWithTag(ObjectName.Buffer, TAG_IO);
1295         ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1296         return Status;
1297     }
1298 
1299     /* Free the buffer for driver object name */
1300     ExFreePoolWithTag(ObjectName.Buffer, TAG_IO);
1301 
1302     /* Check that driver is not already unloading */
1303     if (DriverObject->Flags & DRVO_UNLOAD_INVOKED)
1304     {
1305         DPRINT1("Driver deletion pending\n");
1306         ObDereferenceObject(DriverObject);
1307         ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1308         return STATUS_DELETE_PENDING;
1309     }
1310 
1311     /*
1312      * Get path of service...
1313      */
1314     RtlZeroMemory(QueryTable, sizeof(QueryTable));
1315 
1316     RtlInitUnicodeString(&ImagePath, NULL);
1317 
1318     QueryTable[0].Name = L"ImagePath";
1319     QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1320     QueryTable[0].EntryContext = &ImagePath;
1321 
1322     Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1323                                     CapturedServiceName.Buffer,
1324                                     QueryTable,
1325                                     NULL,
1326                                     NULL);
1327 
1328     /* We no longer need service name */
1329     ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1330 
1331     if (!NT_SUCCESS(Status))
1332     {
1333         DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1334         ObDereferenceObject(DriverObject);
1335         return Status;
1336     }
1337 
1338     /*
1339      * Normalize the image path for all later processing.
1340      */
1341     Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1342 
1343     if (!NT_SUCCESS(Status))
1344     {
1345         DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status);
1346         ObDereferenceObject(DriverObject);
1347         return Status;
1348     }
1349 
1350     /* Free the service path */
1351     ExFreePool(ImagePath.Buffer);
1352 
1353     /*
1354      * Unload the module and release the references to the device object
1355      */
1356 
1357     /* Call the load/unload routine, depending on current process */
1358     if (DriverObject->DriverUnload && DriverObject->DriverSection &&
1359         (UnloadPnpDrivers || (DriverObject->Flags & DRVO_LEGACY_DRIVER)))
1360     {
1361         /* Loop through each device object of the driver
1362            and set DOE_UNLOAD_PENDING flag */
1363         DeviceObject = DriverObject->DeviceObject;
1364         while (DeviceObject)
1365         {
1366             /* Set the unload pending flag for the device */
1367             DeviceExtension = IoGetDevObjExtension(DeviceObject);
1368             DeviceExtension->ExtensionFlags |= DOE_UNLOAD_PENDING;
1369 
1370             /* Make sure there are no attached devices or no reference counts */
1371             if ((DeviceObject->ReferenceCount) || (DeviceObject->AttachedDevice))
1372             {
1373                 /* Not safe to unload */
1374                 DPRINT1("Drivers device object is referenced or has attached devices\n");
1375 
1376                 SafeToUnload = FALSE;
1377             }
1378 
1379             DeviceObject = DeviceObject->NextDevice;
1380         }
1381 
1382         /* If not safe to unload, then return success */
1383         if (!SafeToUnload)
1384         {
1385             ObDereferenceObject(DriverObject);
1386             return STATUS_SUCCESS;
1387         }
1388 
1389         DPRINT1("Unloading driver '%wZ' (manual)\n", &DriverObject->DriverName);
1390 
1391         /* Set the unload invoked flag and call the unload routine */
1392         DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
1393         Status = IopLoadUnloadDriver(NULL, &DriverObject);
1394         ASSERT(Status == STATUS_SUCCESS);
1395 
1396         /* Mark the driver object temporary, so it could be deleted later */
1397         ObMakeTemporaryObject(DriverObject);
1398 
1399         /* Dereference it 2 times */
1400         ObDereferenceObject(DriverObject);
1401         ObDereferenceObject(DriverObject);
1402 
1403         return Status;
1404     }
1405     else
1406     {
1407         DPRINT1("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
1408 
1409         /* Dereference one time (refd inside this function) */
1410         ObDereferenceObject(DriverObject);
1411 
1412         /* Return unloading failure */
1413         return STATUS_INVALID_DEVICE_REQUEST;
1414     }
1415 }
1416 
1417 VOID
1418 NTAPI
1419 IopReinitializeDrivers(VOID)
1420 {
1421     PDRIVER_REINIT_ITEM ReinitItem;
1422     PLIST_ENTRY Entry;
1423 
1424     /* Get the first entry and start looping */
1425     Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1426                                         &DriverReinitListLock);
1427     while (Entry)
1428     {
1429         /* Get the item */
1430         ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1431 
1432         /* Increment reinitialization counter */
1433         ReinitItem->DriverObject->DriverExtension->Count++;
1434 
1435         /* Remove the device object flag */
1436         ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED;
1437 
1438         /* Call the routine */
1439         ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1440                                   ReinitItem->Context,
1441                                   ReinitItem->DriverObject->
1442                                   DriverExtension->Count);
1443 
1444         /* Free the entry */
1445         ExFreePool(Entry);
1446 
1447         /* Move to the next one */
1448         Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1449                                             &DriverReinitListLock);
1450     }
1451 }
1452 
1453 VOID
1454 NTAPI
1455 IopReinitializeBootDrivers(VOID)
1456 {
1457     PDRIVER_REINIT_ITEM ReinitItem;
1458     PLIST_ENTRY Entry;
1459 
1460     /* Get the first entry and start looping */
1461     Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1462                                         &DriverBootReinitListLock);
1463     while (Entry)
1464     {
1465         /* Get the item */
1466         ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1467 
1468         /* Increment reinitialization counter */
1469         ReinitItem->DriverObject->DriverExtension->Count++;
1470 
1471         /* Remove the device object flag */
1472         ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED;
1473 
1474         /* Call the routine */
1475         ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1476                                   ReinitItem->Context,
1477                                   ReinitItem->DriverObject->
1478                                   DriverExtension->Count);
1479 
1480         /* Free the entry */
1481         ExFreePool(Entry);
1482 
1483         /* Move to the next one */
1484         Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1485                                             &DriverBootReinitListLock);
1486     }
1487 
1488     /* Wait for all device actions being finished*/
1489     KeWaitForSingleObject(&PiEnumerationFinished, Executive, KernelMode, FALSE, NULL);
1490 }
1491 
1492 NTSTATUS
1493 NTAPI
1494 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1495                 IN PDRIVER_INITIALIZE InitializationFunction,
1496                 IN PUNICODE_STRING RegistryPath OPTIONAL,
1497                 IN PCUNICODE_STRING ServiceName,
1498                 IN PLDR_DATA_TABLE_ENTRY ModuleObject OPTIONAL,
1499                 OUT PDRIVER_OBJECT *pDriverObject)
1500 {
1501     WCHAR NameBuffer[100];
1502     USHORT NameLength;
1503     UNICODE_STRING LocalDriverName;
1504     NTSTATUS Status;
1505     OBJECT_ATTRIBUTES ObjectAttributes;
1506     ULONG ObjectSize;
1507     PDRIVER_OBJECT DriverObject;
1508     UNICODE_STRING ServiceKeyName;
1509     HANDLE hDriver;
1510     ULONG i, RetryCount = 0;
1511 
1512 try_again:
1513     /* First, create a unique name for the driver if we don't have one */
1514     if (!DriverName)
1515     {
1516         /* Create a random name and set up the string */
1517         NameLength = (USHORT)swprintf(NameBuffer,
1518                                       DRIVER_ROOT_NAME L"%08u",
1519                                       KeTickCount.LowPart);
1520         LocalDriverName.Length = NameLength * sizeof(WCHAR);
1521         LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1522         LocalDriverName.Buffer = NameBuffer;
1523     }
1524     else
1525     {
1526         /* So we can avoid another code path, use a local var */
1527         LocalDriverName = *DriverName;
1528     }
1529 
1530     /* Initialize the Attributes */
1531     ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION);
1532     InitializeObjectAttributes(&ObjectAttributes,
1533                                &LocalDriverName,
1534                                OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1535                                NULL,
1536                                NULL);
1537 
1538     /* Create the Object */
1539     Status = ObCreateObject(KernelMode,
1540                             IoDriverObjectType,
1541                             &ObjectAttributes,
1542                             KernelMode,
1543                             NULL,
1544                             ObjectSize,
1545                             0,
1546                             0,
1547                             (PVOID*)&DriverObject);
1548     if (!NT_SUCCESS(Status)) return Status;
1549 
1550     DPRINT("IopCreateDriver(): created DO %p\n", DriverObject);
1551 
1552     /* Set up the Object */
1553     RtlZeroMemory(DriverObject, ObjectSize);
1554     DriverObject->Type = IO_TYPE_DRIVER;
1555     DriverObject->Size = sizeof(DRIVER_OBJECT);
1556 
1557     /*
1558      * Check whether RegistryPath and ModuleObject are both NULL because
1559      * IoCreateDriver() was called to initialize a built-in driver.
1560      */
1561     if ((RegistryPath != NULL) || (ModuleObject != NULL))
1562         DriverObject->Flags = DRVO_LEGACY_DRIVER;
1563     else
1564         DriverObject->Flags = DRVO_BUILTIN_DRIVER;
1565 
1566     DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1567     DriverObject->DriverExtension->DriverObject = DriverObject;
1568     DriverObject->DriverInit = InitializationFunction;
1569     DriverObject->DriverSection = ModuleObject;
1570     /* Loop all Major Functions */
1571     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1572     {
1573         /* Invalidate each function */
1574         DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1575     }
1576 
1577     /* Set up the service key name buffer */
1578     ServiceKeyName.MaximumLength = ServiceName->Length + sizeof(UNICODE_NULL);
1579     ServiceKeyName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
1580                                                   ServiceKeyName.MaximumLength,
1581                                                   TAG_IO);
1582     if (!ServiceKeyName.Buffer)
1583     {
1584         /* Fail */
1585         ObMakeTemporaryObject(DriverObject);
1586         ObDereferenceObject(DriverObject);
1587         return STATUS_INSUFFICIENT_RESOURCES;
1588     }
1589 
1590     /* Copy the name and set it in the driver extension */
1591     RtlCopyUnicodeString(&ServiceKeyName,
1592                          ServiceName);
1593     DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1594 
1595     /* Make a copy of the driver name to store in the driver object */
1596     DriverObject->DriverName.MaximumLength = LocalDriverName.Length;
1597     DriverObject->DriverName.Buffer = ExAllocatePoolWithTag(PagedPool,
1598                                                             DriverObject->DriverName.MaximumLength,
1599                                                             TAG_IO);
1600     if (!DriverObject->DriverName.Buffer)
1601     {
1602         /* Fail */
1603         ObMakeTemporaryObject(DriverObject);
1604         ObDereferenceObject(DriverObject);
1605         return STATUS_INSUFFICIENT_RESOURCES;
1606     }
1607 
1608     RtlCopyUnicodeString(&DriverObject->DriverName,
1609                          &LocalDriverName);
1610 
1611     /* Add the Object and get its handle */
1612     Status = ObInsertObject(DriverObject,
1613                             NULL,
1614                             FILE_READ_DATA,
1615                             0,
1616                             NULL,
1617                             &hDriver);
1618 
1619     /* Eliminate small possibility when this function is called more than
1620        once in a row, and KeTickCount doesn't get enough time to change */
1621     if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100))
1622     {
1623         RetryCount++;
1624         goto try_again;
1625     }
1626 
1627     if (!NT_SUCCESS(Status)) return Status;
1628 
1629     /* Now reference it */
1630     Status = ObReferenceObjectByHandle(hDriver,
1631                                        0,
1632                                        IoDriverObjectType,
1633                                        KernelMode,
1634                                        (PVOID*)&DriverObject,
1635                                        NULL);
1636 
1637     /* Close the extra handle */
1638     ZwClose(hDriver);
1639 
1640     if (!NT_SUCCESS(Status))
1641     {
1642         /* Fail */
1643         ObMakeTemporaryObject(DriverObject);
1644         ObDereferenceObject(DriverObject);
1645         return Status;
1646     }
1647 
1648     DriverObject->HardwareDatabase = &IopHardwareDatabaseKey;
1649     DriverObject->DriverStart = ModuleObject ? ModuleObject->DllBase : 0;
1650     DriverObject->DriverSize = ModuleObject ? ModuleObject->SizeOfImage : 0;
1651 
1652     /* Finally, call its init function */
1653     DPRINT("RegistryKey: %wZ\n", RegistryPath);
1654     DPRINT("Calling driver entrypoint at %p\n", InitializationFunction);
1655     Status = (*InitializationFunction)(DriverObject, RegistryPath);
1656     if (!NT_SUCCESS(Status))
1657     {
1658         /* If it didn't work, then kill the object */
1659         DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status);
1660         DriverObject->DriverSection = NULL;
1661         ObMakeTemporaryObject(DriverObject);
1662         ObDereferenceObject(DriverObject);
1663         return Status;
1664     }
1665     else
1666     {
1667         /* Returns to caller the object */
1668         *pDriverObject = DriverObject;
1669     }
1670 
1671     /* We're going to say if we don't have any DOs from DriverEntry, then we're not legacy.
1672      * Other parts of the I/O manager depend on this behavior */
1673     if (!DriverObject->DeviceObject) DriverObject->Flags &= ~DRVO_LEGACY_DRIVER;
1674 
1675     /* Loop all Major Functions */
1676     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1677     {
1678         /*
1679          * Make sure the driver didn't set any dispatch entry point to NULL!
1680          * Doing so is illegal; drivers shouldn't touch entry points they
1681          * do not implement.
1682          */
1683 
1684         /* Check if it did so anyway */
1685         if (!DriverObject->MajorFunction[i])
1686         {
1687             /* Print a warning in the debug log */
1688             DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%lu] to NULL!\n",
1689                     &DriverObject->DriverName, i);
1690 
1691             /* Fix it up */
1692             DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1693         }
1694     }
1695 
1696     /* Return the Status */
1697     return Status;
1698 }
1699 
1700 /* PUBLIC FUNCTIONS ***********************************************************/
1701 
1702 /*
1703  * @implemented
1704  */
1705 NTSTATUS
1706 NTAPI
1707 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1708                IN PDRIVER_INITIALIZE InitializationFunction)
1709 {
1710     PDRIVER_OBJECT DriverObject;
1711     return IopCreateDriver(DriverName, InitializationFunction, NULL, DriverName, NULL, &DriverObject);
1712 }
1713 
1714 /*
1715  * @implemented
1716  */
1717 VOID
1718 NTAPI
1719 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject)
1720 {
1721     /* Simply dereference the Object */
1722     ObDereferenceObject(DriverObject);
1723 }
1724 
1725 /*
1726  * @implemented
1727  */
1728 VOID
1729 NTAPI
1730 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1731                                      IN PDRIVER_REINITIALIZE ReinitRoutine,
1732                                      IN PVOID Context)
1733 {
1734     PDRIVER_REINIT_ITEM ReinitItem;
1735 
1736     /* Allocate the entry */
1737     ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1738                                        sizeof(DRIVER_REINIT_ITEM),
1739                                        TAG_REINIT);
1740     if (!ReinitItem) return;
1741 
1742     /* Fill it out */
1743     ReinitItem->DriverObject = DriverObject;
1744     ReinitItem->ReinitRoutine = ReinitRoutine;
1745     ReinitItem->Context = Context;
1746 
1747     /* Set the Driver Object flag and insert the entry into the list */
1748     DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
1749     ExInterlockedInsertTailList(&DriverBootReinitListHead,
1750                                 &ReinitItem->ItemEntry,
1751                                 &DriverBootReinitListLock);
1752 }
1753 
1754 /*
1755  * @implemented
1756  */
1757 VOID
1758 NTAPI
1759 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1760                                  IN PDRIVER_REINITIALIZE ReinitRoutine,
1761                                  IN PVOID Context)
1762 {
1763     PDRIVER_REINIT_ITEM ReinitItem;
1764 
1765     /* Allocate the entry */
1766     ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1767                                        sizeof(DRIVER_REINIT_ITEM),
1768                                        TAG_REINIT);
1769     if (!ReinitItem) return;
1770 
1771     /* Fill it out */
1772     ReinitItem->DriverObject = DriverObject;
1773     ReinitItem->ReinitRoutine = ReinitRoutine;
1774     ReinitItem->Context = Context;
1775 
1776     /* Set the Driver Object flag and insert the entry into the list */
1777     DriverObject->Flags |= DRVO_REINIT_REGISTERED;
1778     ExInterlockedInsertTailList(&DriverReinitListHead,
1779                                 &ReinitItem->ItemEntry,
1780                                 &DriverReinitListLock);
1781 }
1782 
1783 /*
1784  * @implemented
1785  */
1786 NTSTATUS
1787 NTAPI
1788 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1789                                 IN PVOID ClientIdentificationAddress,
1790                                 IN ULONG DriverObjectExtensionSize,
1791                                 OUT PVOID *DriverObjectExtension)
1792 {
1793     KIRQL OldIrql;
1794     PIO_CLIENT_EXTENSION DriverExtensions, NewDriverExtension;
1795     BOOLEAN Inserted = FALSE;
1796 
1797     /* Assume failure */
1798     *DriverObjectExtension = NULL;
1799 
1800     /* Allocate the extension */
1801     NewDriverExtension = ExAllocatePoolWithTag(NonPagedPool,
1802                                                sizeof(IO_CLIENT_EXTENSION) +
1803                                                DriverObjectExtensionSize,
1804                                                TAG_DRIVER_EXTENSION);
1805     if (!NewDriverExtension) return STATUS_INSUFFICIENT_RESOURCES;
1806 
1807     /* Clear the extension for teh caller */
1808     RtlZeroMemory(NewDriverExtension,
1809                   sizeof(IO_CLIENT_EXTENSION) + DriverObjectExtensionSize);
1810 
1811     /* Acqure lock */
1812     OldIrql = KeRaiseIrqlToDpcLevel();
1813 
1814     /* Fill out the extension */
1815     NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
1816 
1817     /* Loop the current extensions */
1818     DriverExtensions = IoGetDrvObjExtension(DriverObject)->
1819                        ClientDriverExtension;
1820     while (DriverExtensions)
1821     {
1822         /* Check if the identifier matches */
1823         if (DriverExtensions->ClientIdentificationAddress ==
1824             ClientIdentificationAddress)
1825         {
1826             /* We have a collision, break out */
1827             break;
1828         }
1829 
1830         /* Go to the next one */
1831         DriverExtensions = DriverExtensions->NextExtension;
1832     }
1833 
1834     /* Check if we didn't collide */
1835     if (!DriverExtensions)
1836     {
1837         /* Link this one in */
1838         NewDriverExtension->NextExtension =
1839             IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1840         IoGetDrvObjExtension(DriverObject)->ClientDriverExtension =
1841             NewDriverExtension;
1842         Inserted = TRUE;
1843     }
1844 
1845     /* Release the lock */
1846     KeLowerIrql(OldIrql);
1847 
1848     /* Check if insertion failed */
1849     if (!Inserted)
1850     {
1851         /* Free the entry and fail */
1852         ExFreePoolWithTag(NewDriverExtension, TAG_DRIVER_EXTENSION);
1853         return STATUS_OBJECT_NAME_COLLISION;
1854     }
1855 
1856     /* Otherwise, return the pointer */
1857     *DriverObjectExtension = NewDriverExtension + 1;
1858     return STATUS_SUCCESS;
1859 }
1860 
1861 /*
1862  * @implemented
1863  */
1864 PVOID
1865 NTAPI
1866 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1867                            IN PVOID ClientIdentificationAddress)
1868 {
1869     KIRQL OldIrql;
1870     PIO_CLIENT_EXTENSION DriverExtensions;
1871 
1872     /* Acquire lock */
1873     OldIrql = KeRaiseIrqlToDpcLevel();
1874 
1875     /* Loop the list until we find the right one */
1876     DriverExtensions = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1877     while (DriverExtensions)
1878     {
1879         /* Check for a match */
1880         if (DriverExtensions->ClientIdentificationAddress ==
1881             ClientIdentificationAddress)
1882         {
1883             /* Break out */
1884             break;
1885         }
1886 
1887         /* Keep looping */
1888         DriverExtensions = DriverExtensions->NextExtension;
1889     }
1890 
1891     /* Release lock */
1892     KeLowerIrql(OldIrql);
1893 
1894     /* Return nothing or the extension */
1895     if (!DriverExtensions) return NULL;
1896     return DriverExtensions + 1;
1897 }
1898 
1899 VOID
1900 NTAPI
1901 IopLoadUnloadDriverWorker(
1902     _Inout_ PVOID Parameter)
1903 {
1904     PLOAD_UNLOAD_PARAMS LoadParams = Parameter;
1905 
1906     ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess);
1907     LoadParams->Status = IopLoadUnloadDriver(LoadParams->RegistryPath,
1908                                              &LoadParams->DriverObject);
1909     KeSetEvent(&LoadParams->Event, 0, FALSE);
1910 }
1911 
1912 NTSTATUS
1913 NTAPI
1914 IopLoadUnloadDriver(
1915     _In_opt_ PCUNICODE_STRING RegistryPath,
1916     _Inout_ PDRIVER_OBJECT *DriverObject)
1917 {
1918     RTL_QUERY_REGISTRY_TABLE QueryTable[3];
1919     UNICODE_STRING ImagePath;
1920     UNICODE_STRING ServiceName;
1921     NTSTATUS Status;
1922     ULONG Type;
1923     PDEVICE_NODE DeviceNode;
1924     PLDR_DATA_TABLE_ENTRY ModuleObject;
1925     PVOID BaseAddress;
1926     WCHAR *cur;
1927 
1928     /* Load/Unload must be called from system process */
1929     if (PsGetCurrentProcess() != PsInitialSystemProcess)
1930     {
1931         LOAD_UNLOAD_PARAMS LoadParams;
1932 
1933         /* Prepare parameters block */
1934         LoadParams.RegistryPath = RegistryPath;
1935         LoadParams.DriverObject = *DriverObject;
1936         KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
1937 
1938         /* Initialize and queue a work item */
1939         ExInitializeWorkItem(&LoadParams.WorkItem,
1940                              IopLoadUnloadDriverWorker,
1941                              &LoadParams);
1942         ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
1943 
1944         /* And wait till it completes */
1945         KeWaitForSingleObject(&LoadParams.Event,
1946                               UserRequest,
1947                               KernelMode,
1948                               FALSE,
1949                               NULL);
1950         return LoadParams.Status;
1951     }
1952 
1953     /* Check if it's an unload request */
1954     if (*DriverObject)
1955     {
1956         (*DriverObject)->DriverUnload(*DriverObject);
1957         return STATUS_SUCCESS;
1958     }
1959 
1960     RtlInitUnicodeString(&ImagePath, NULL);
1961 
1962     /*
1963      * Get the service name from the registry key name.
1964      */
1965     ASSERT(RegistryPath->Length >= sizeof(WCHAR));
1966 
1967     ServiceName = *RegistryPath;
1968     cur = RegistryPath->Buffer + RegistryPath->Length / sizeof(WCHAR) - 1;
1969     while (RegistryPath->Buffer != cur)
1970     {
1971         if (*cur == L'\\')
1972         {
1973             ServiceName.Buffer = cur + 1;
1974             ServiceName.Length = RegistryPath->Length -
1975                                  (USHORT)((ULONG_PTR)ServiceName.Buffer -
1976                                           (ULONG_PTR)RegistryPath->Buffer);
1977             break;
1978         }
1979         cur--;
1980     }
1981 
1982     /*
1983      * Get service type.
1984      */
1985     RtlZeroMemory(&QueryTable, sizeof(QueryTable));
1986 
1987     RtlInitUnicodeString(&ImagePath, NULL);
1988 
1989     QueryTable[0].Name = L"Type";
1990     QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1991     QueryTable[0].EntryContext = &Type;
1992 
1993     QueryTable[1].Name = L"ImagePath";
1994     QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1995     QueryTable[1].EntryContext = &ImagePath;
1996 
1997     Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1998                                     RegistryPath->Buffer,
1999                                     QueryTable, NULL, NULL);
2000     if (!NT_SUCCESS(Status))
2001     {
2002         DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
2003         if (ImagePath.Buffer) ExFreePool(ImagePath.Buffer);
2004         return Status;
2005     }
2006 
2007     /*
2008      * Normalize the image path for all later processing.
2009      */
2010     Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
2011     if (!NT_SUCCESS(Status))
2012     {
2013         DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
2014         return Status;
2015     }
2016 
2017     DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
2018     DPRINT("Type: %lx\n", Type);
2019 
2020     KeEnterCriticalRegion();
2021     ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE);
2022     /*
2023      * Get existing DriverObject pointer (in case the driver
2024      * has already been loaded and initialized).
2025      */
2026     Status = IopGetDriverObject(DriverObject,
2027                                 &ServiceName,
2028                                 (Type == SERVICE_FILE_SYSTEM_DRIVER ||
2029                                  Type == SERVICE_RECOGNIZER_DRIVER));
2030 
2031     if (!NT_SUCCESS(Status))
2032     {
2033         /*
2034          * Load the driver module
2035          */
2036         DPRINT("Loading module from %wZ\n", &ImagePath);
2037         Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress);
2038         if (!NT_SUCCESS(Status))
2039         {
2040             DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
2041             ExReleaseResourceLite(&IopDriverLoadResource);
2042             KeLeaveCriticalRegion();
2043             return Status;
2044         }
2045 
2046         /*
2047          * Initialize the driver module if it's loaded for the first time
2048          */
2049         Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
2050         if (!NT_SUCCESS(Status))
2051         {
2052             DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status);
2053             ExReleaseResourceLite(&IopDriverLoadResource);
2054             KeLeaveCriticalRegion();
2055             MmUnloadSystemImage(ModuleObject);
2056             return Status;
2057         }
2058 
2059         IopDisplayLoadingMessage(&DeviceNode->ServiceName);
2060 
2061         Status = IopInitializeDriverModule(DeviceNode,
2062                                            ModuleObject,
2063                                            &DeviceNode->ServiceName,
2064                                            (Type == SERVICE_FILE_SYSTEM_DRIVER ||
2065                                             Type == SERVICE_RECOGNIZER_DRIVER),
2066                                            DriverObject);
2067         if (!NT_SUCCESS(Status))
2068         {
2069             DPRINT1("IopInitializeDriverModule() failed (Status %lx)\n", Status);
2070             ExReleaseResourceLite(&IopDriverLoadResource);
2071             KeLeaveCriticalRegion();
2072             MmUnloadSystemImage(ModuleObject);
2073             return Status;
2074         }
2075 
2076         ExReleaseResourceLite(&IopDriverLoadResource);
2077         KeLeaveCriticalRegion();
2078 
2079         /* Initialize and start device */
2080         IopInitializeDevice(DeviceNode, *DriverObject);
2081         Status = IopStartDevice(DeviceNode);
2082     }
2083     else
2084     {
2085         ExReleaseResourceLite(&IopDriverLoadResource);
2086         KeLeaveCriticalRegion();
2087 
2088         DPRINT("DriverObject already exist in ObjectManager\n");
2089         Status = STATUS_IMAGE_ALREADY_LOADED;
2090 
2091         /* IopGetDriverObject references the DriverObject, so dereference it */
2092         ObDereferenceObject(*DriverObject);
2093     }
2094 
2095     return Status;
2096 }
2097 
2098 /*
2099  * NtLoadDriver
2100  *
2101  * Loads a device driver.
2102  *
2103  * Parameters
2104  *    DriverServiceName
2105  *       Name of the service to load (registry key).
2106  *
2107  * Return Value
2108  *    Status
2109  *
2110  * Status
2111  *    implemented
2112  */
2113 NTSTATUS NTAPI
2114 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
2115 {
2116     UNICODE_STRING CapturedDriverServiceName = { 0, 0, NULL };
2117     KPROCESSOR_MODE PreviousMode;
2118     PDRIVER_OBJECT DriverObject;
2119     NTSTATUS Status;
2120 
2121     PAGED_CODE();
2122 
2123     PreviousMode = KeGetPreviousMode();
2124 
2125     /*
2126      * Check security privileges
2127      */
2128     if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2129     {
2130         DPRINT("Privilege not held\n");
2131         return STATUS_PRIVILEGE_NOT_HELD;
2132     }
2133 
2134     Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
2135                                           PreviousMode,
2136                                           DriverServiceName);
2137     if (!NT_SUCCESS(Status))
2138     {
2139         return Status;
2140     }
2141 
2142     DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
2143 
2144     /* Load driver and call its entry point */
2145     DriverObject = NULL;
2146     Status = IopLoadUnloadDriver(&CapturedDriverServiceName, &DriverObject);
2147 
2148     ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
2149                                  PreviousMode);
2150 
2151     return Status;
2152 }
2153 
2154 /*
2155  * NtUnloadDriver
2156  *
2157  * Unloads a legacy device driver.
2158  *
2159  * Parameters
2160  *    DriverServiceName
2161  *       Name of the service to unload (registry key).
2162  *
2163  * Return Value
2164  *    Status
2165  *
2166  * Status
2167  *    implemented
2168  */
2169 
2170 NTSTATUS NTAPI
2171 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
2172 {
2173     return IopUnloadDriver(DriverServiceName, FALSE);
2174 }
2175 
2176 /* EOF */
2177