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