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