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