413458d71f1050c3c84e61c8cf25c3c03a3f16c9
[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 %08X\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 %08X\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 BOOLEAN Lower)
644 {
645 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { NULL, 0, NULL, NULL, 0, NULL, 0 }, };
646 UNICODE_STRING Class;
647 WCHAR ClassBuffer[40];
648 UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
649 HANDLE EnumRootKey, SubKey;
650 NTSTATUS Status;
651
652 /* Open enumeration root key */
653 Status = IopOpenRegistryKeyEx(&EnumRootKey,
654 NULL,
655 &EnumRoot,
656 KEY_READ);
657 if (!NT_SUCCESS(Status))
658 {
659 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
660 return Status;
661 }
662
663 /* Open subkey */
664 Status = IopOpenRegistryKeyEx(&SubKey,
665 EnumRootKey,
666 &DeviceNode->InstancePath,
667 KEY_READ);
668 if (!NT_SUCCESS(Status))
669 {
670 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
671 ZwClose(EnumRootKey);
672 return Status;
673 }
674
675 /*
676 * First load the device filters
677 */
678 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
679 if (Lower)
680 QueryTable[0].Name = L"LowerFilters";
681 else
682 QueryTable[0].Name = L"UpperFilters";
683 QueryTable[0].Flags = 0;
684 QueryTable[0].DefaultType = REG_NONE;
685
686 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
687 (PWSTR)SubKey,
688 QueryTable,
689 DeviceNode,
690 NULL);
691 if (!NT_SUCCESS(Status))
692 {
693 DPRINT1("Failed to load device %s filters: %08X\n",
694 Lower ? "lower" : "upper", Status);
695 ZwClose(SubKey);
696 ZwClose(EnumRootKey);
697 return Status;
698 }
699
700 /*
701 * Now get the class GUID
702 */
703 Class.Length = 0;
704 Class.MaximumLength = 40 * sizeof(WCHAR);
705 Class.Buffer = ClassBuffer;
706 QueryTable[0].QueryRoutine = NULL;
707 QueryTable[0].Name = L"ClassGUID";
708 QueryTable[0].EntryContext = &Class;
709 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
710
711 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
712 (PWSTR)SubKey,
713 QueryTable,
714 DeviceNode,
715 NULL);
716
717 /* Close handles */
718 ZwClose(SubKey);
719 ZwClose(EnumRootKey);
720
721 /*
722 * Load the class filter driver
723 */
724 if (NT_SUCCESS(Status))
725 {
726 UNICODE_STRING ControlClass = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
727
728 Status = IopOpenRegistryKeyEx(&EnumRootKey,
729 NULL,
730 &ControlClass,
731 KEY_READ);
732 if (!NT_SUCCESS(Status))
733 {
734 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
735 return Status;
736 }
737
738 /* Open subkey */
739 Status = IopOpenRegistryKeyEx(&SubKey,
740 EnumRootKey,
741 &Class,
742 KEY_READ);
743 if (!NT_SUCCESS(Status))
744 {
745 /* It's okay if there's no class key */
746 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
747 ZwClose(EnumRootKey);
748 return STATUS_SUCCESS;
749 }
750
751 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
752 if (Lower)
753 QueryTable[0].Name = L"LowerFilters";
754 else
755 QueryTable[0].Name = L"UpperFilters";
756 QueryTable[0].EntryContext = NULL;
757 QueryTable[0].Flags = 0;
758 QueryTable[0].DefaultType = REG_NONE;
759
760 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
761 (PWSTR)SubKey,
762 QueryTable,
763 DeviceNode,
764 NULL);
765
766 /* Clean up */
767 ZwClose(SubKey);
768 ZwClose(EnumRootKey);
769
770 if (!NT_SUCCESS(Status))
771 {
772 DPRINT1("Failed to load class %s filters: %08X\n",
773 Lower ? "lower" : "upper", Status);
774 ZwClose(SubKey);
775 ZwClose(EnumRootKey);
776 return Status;
777 }
778 }
779
780 return STATUS_SUCCESS;
781 }
782
783 NTSTATUS
784 NTAPI
785 MiResolveImageReferences(IN PVOID ImageBase,
786 IN PUNICODE_STRING ImageFileDirectory,
787 IN PUNICODE_STRING NamePrefix OPTIONAL,
788 OUT PCHAR *MissingApi,
789 OUT PWCHAR *MissingDriver,
790 OUT PLOAD_IMPORTS *LoadImports);
791
792 //
793 // Used for images already loaded (boot drivers)
794 //
795 NTSTATUS
796 NTAPI
797 INIT_FUNCTION
798 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry,
799 PUNICODE_STRING FileName,
800 PLDR_DATA_TABLE_ENTRY *ModuleObject)
801 {
802 NTSTATUS Status;
803 UNICODE_STRING BaseName, BaseDirectory;
804 PLOAD_IMPORTS LoadedImports = (PVOID)-2;
805 PCHAR MissingApiName, Buffer;
806 PWCHAR MissingDriverName;
807 PVOID DriverBase = LdrEntry->DllBase;
808
809 /* Allocate a buffer we'll use for names */
810 Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
811 if (!Buffer)
812 {
813 /* Fail */
814 return STATUS_INSUFFICIENT_RESOURCES;
815 }
816
817 /* Check for a separator */
818 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
819 {
820 PWCHAR p;
821 ULONG BaseLength;
822
823 /* Loop the path until we get to the base name */
824 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
825 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
826
827 /* Get the length */
828 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
829 BaseLength *= sizeof(WCHAR);
830
831 /* Setup the string */
832 BaseName.Length = (USHORT)BaseLength;
833 BaseName.Buffer = p;
834 }
835 else
836 {
837 /* Otherwise, we already have a base name */
838 BaseName.Length = FileName->Length;
839 BaseName.Buffer = FileName->Buffer;
840 }
841
842 /* Setup the maximum length */
843 BaseName.MaximumLength = BaseName.Length;
844
845 /* Now compute the base directory */
846 BaseDirectory = *FileName;
847 BaseDirectory.Length -= BaseName.Length;
848 BaseDirectory.MaximumLength = BaseDirectory.Length;
849
850 /* Resolve imports */
851 MissingApiName = Buffer;
852 Status = MiResolveImageReferences(DriverBase,
853 &BaseDirectory,
854 NULL,
855 &MissingApiName,
856 &MissingDriverName,
857 &LoadedImports);
858
859 /* Free the temporary buffer */
860 ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);
861
862 /* Check the result of the imports resolution */
863 if (!NT_SUCCESS(Status)) return Status;
864
865 /* Return */
866 *ModuleObject = LdrEntry;
867 return STATUS_SUCCESS;
868 }
869
870 /*
871 * IopInitializeBuiltinDriver
872 *
873 * Initialize a driver that is already loaded in memory.
874 */
875 NTSTATUS
876 NTAPI
877 INIT_FUNCTION
878 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY BootLdrEntry)
879 {
880 PDEVICE_NODE DeviceNode;
881 PDRIVER_OBJECT DriverObject;
882 NTSTATUS Status;
883 PWCHAR FileNameWithoutPath;
884 LPWSTR FileExtension;
885 PUNICODE_STRING ModuleName = &BootLdrEntry->BaseDllName;
886 PLDR_DATA_TABLE_ENTRY LdrEntry;
887 PLIST_ENTRY NextEntry;
888 UNICODE_STRING ServiceName;
889 BOOLEAN Success;
890
891 /*
892 * Display 'Loading XXX...' message
893 */
894 IopDisplayLoadingMessage(ModuleName);
895 InbvIndicateProgress();
896
897 /*
898 * Generate filename without path (not needed by freeldr)
899 */
900 FileNameWithoutPath = wcsrchr(ModuleName->Buffer, L'\\');
901 if (FileNameWithoutPath == NULL)
902 {
903 FileNameWithoutPath = ModuleName->Buffer;
904 }
905 else
906 {
907 FileNameWithoutPath++;
908 }
909
910 /*
911 * Strip the file extension from ServiceName
912 */
913 Success = RtlCreateUnicodeString(&ServiceName, FileNameWithoutPath);
914 if (!Success)
915 {
916 return STATUS_INSUFFICIENT_RESOURCES;
917 }
918
919 FileExtension = wcsrchr(ServiceName.Buffer, '.');
920 if (FileExtension != NULL)
921 {
922 ServiceName.Length -= (USHORT)wcslen(FileExtension) * sizeof(WCHAR);
923 FileExtension[0] = 0;
924 }
925
926 /*
927 * Determine the right device object
928 */
929 /* Use IopRootDeviceNode for now */
930 Status = IopCreateDeviceNode(IopRootDeviceNode,
931 NULL,
932 &ServiceName,
933 &DeviceNode);
934 RtlFreeUnicodeString(&ServiceName);
935 if (!NT_SUCCESS(Status))
936 {
937 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
938 return(Status);
939 }
940
941 /* Lookup the new Ldr entry in PsLoadedModuleList */
942 NextEntry = PsLoadedModuleList.Flink;
943 while (NextEntry != &PsLoadedModuleList)
944 {
945 LdrEntry = CONTAINING_RECORD(NextEntry,
946 LDR_DATA_TABLE_ENTRY,
947 InLoadOrderLinks);
948 if (RtlEqualUnicodeString(ModuleName, &LdrEntry->BaseDllName, TRUE))
949 {
950 break;
951 }
952
953 NextEntry = NextEntry->Flink;
954 }
955 ASSERT(NextEntry != &PsLoadedModuleList);
956
957 /*
958 * Initialize the driver
959 */
960 Status = IopInitializeDriverModule(DeviceNode,
961 LdrEntry,
962 &DeviceNode->ServiceName,
963 FALSE,
964 &DriverObject);
965
966 if (!NT_SUCCESS(Status))
967 {
968 return Status;
969 }
970
971 Status = IopInitializeDevice(DeviceNode, DriverObject);
972 if (NT_SUCCESS(Status))
973 {
974 Status = IopStartDevice(DeviceNode);
975 }
976
977 /* Remove extra reference from IopInitializeDriverModule */
978 ObDereferenceObject(DriverObject);
979
980 return Status;
981 }
982
983 /*
984 * IopInitializeBootDrivers
985 *
986 * Initialize boot drivers and free memory for boot files.
987 *
988 * Parameters
989 * None
990 *
991 * Return Value
992 * None
993 */
994 VOID
995 FASTCALL
996 INIT_FUNCTION
997 IopInitializeBootDrivers(VOID)
998 {
999 PLIST_ENTRY ListHead, NextEntry, NextEntry2;
1000 PLDR_DATA_TABLE_ENTRY LdrEntry;
1001 PDEVICE_NODE DeviceNode;
1002 PDRIVER_OBJECT DriverObject;
1003 LDR_DATA_TABLE_ENTRY ModuleObject;
1004 NTSTATUS Status;
1005 UNICODE_STRING DriverName;
1006 ULONG i, Index;
1007 PDRIVER_INFORMATION DriverInfo, DriverInfoTag;
1008 HANDLE KeyHandle;
1009 PBOOT_DRIVER_LIST_ENTRY BootEntry;
1010 DPRINT("IopInitializeBootDrivers()\n");
1011
1012 /* Use IopRootDeviceNode for now */
1013 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, NULL, &DeviceNode);
1014 if (!NT_SUCCESS(Status)) return;
1015
1016 /* Setup the module object for the RAW FS Driver */
1017 ModuleObject.DllBase = NULL;
1018 ModuleObject.SizeOfImage = 0;
1019 ModuleObject.EntryPoint = RawFsDriverEntry;
1020 RtlInitUnicodeString(&DriverName, L"RAW");
1021
1022 /* Initialize it */
1023 Status = IopInitializeDriverModule(DeviceNode,
1024 &ModuleObject,
1025 &DriverName,
1026 TRUE,
1027 &DriverObject);
1028 if (!NT_SUCCESS(Status))
1029 {
1030 /* Fail */
1031 return;
1032 }
1033
1034 /* Now initialize the associated device */
1035 Status = IopInitializeDevice(DeviceNode, DriverObject);
1036 if (!NT_SUCCESS(Status))
1037 {
1038 /* Fail */
1039 ObDereferenceObject(DriverObject);
1040 return;
1041 }
1042
1043 /* Start it up */
1044 Status = IopStartDevice(DeviceNode);
1045 if (!NT_SUCCESS(Status))
1046 {
1047 /* Fail */
1048 ObDereferenceObject(DriverObject);
1049 return;
1050 }
1051
1052 /* Get highest group order index */
1053 IopGroupIndex = PpInitGetGroupOrderIndex(NULL);
1054 if (IopGroupIndex == 0xFFFF) ASSERT(FALSE);
1055
1056 /* Allocate the group table */
1057 IopGroupTable = ExAllocatePoolWithTag(PagedPool,
1058 IopGroupIndex * sizeof(LIST_ENTRY),
1059 TAG_IO);
1060 if (IopGroupTable == NULL) ASSERT(FALSE);
1061
1062 /* Initialize the group table lists */
1063 for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]);
1064
1065 /* Loop the boot modules */
1066 ListHead = &KeLoaderBlock->LoadOrderListHead;
1067 NextEntry = ListHead->Flink;
1068 while (ListHead != NextEntry)
1069 {
1070 /* Get the entry */
1071 LdrEntry = CONTAINING_RECORD(NextEntry,
1072 LDR_DATA_TABLE_ENTRY,
1073 InLoadOrderLinks);
1074
1075 /* Check if the DLL needs to be initialized */
1076 if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
1077 {
1078 /* Call its entrypoint */
1079 MmCallDllInitialize(LdrEntry, NULL);
1080 }
1081
1082 /* Go to the next driver */
1083 NextEntry = NextEntry->Flink;
1084 }
1085
1086 /* Loop the boot drivers */
1087 ListHead = &KeLoaderBlock->BootDriverListHead;
1088 NextEntry = ListHead->Flink;
1089 while (ListHead != NextEntry)
1090 {
1091 /* Get the entry */
1092 BootEntry = CONTAINING_RECORD(NextEntry,
1093 BOOT_DRIVER_LIST_ENTRY,
1094 Link);
1095
1096 /* Get the driver loader entry */
1097 LdrEntry = BootEntry->LdrEntry;
1098
1099 /* Allocate our internal accounting structure */
1100 DriverInfo = ExAllocatePoolWithTag(PagedPool,
1101 sizeof(DRIVER_INFORMATION),
1102 TAG_IO);
1103 if (DriverInfo)
1104 {
1105 /* Zero it and initialize it */
1106 RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION));
1107 InitializeListHead(&DriverInfo->Link);
1108 DriverInfo->DataTableEntry = BootEntry;
1109
1110 /* Open the registry key */
1111 Status = IopOpenRegistryKeyEx(&KeyHandle,
1112 NULL,
1113 &BootEntry->RegistryPath,
1114 KEY_READ);
1115 if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */
1116 ((KeLoaderBlock->SetupLdrBlock) && ((KeyHandle = (PVOID)1)))) // yes, it's an assignment!
1117 {
1118 /* Save the handle */
1119 DriverInfo->ServiceHandle = KeyHandle;
1120
1121 /* Get the group oder index */
1122 Index = PpInitGetGroupOrderIndex(KeyHandle);
1123
1124 /* Get the tag position */
1125 DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle);
1126
1127 /* Insert it into the list, at the right place */
1128 ASSERT(Index < IopGroupIndex);
1129 NextEntry2 = IopGroupTable[Index].Flink;
1130 while (NextEntry2 != &IopGroupTable[Index])
1131 {
1132 /* Get the driver info */
1133 DriverInfoTag = CONTAINING_RECORD(NextEntry2,
1134 DRIVER_INFORMATION,
1135 Link);
1136
1137 /* Check if we found the right tag position */
1138 if (DriverInfoTag->TagPosition > DriverInfo->TagPosition)
1139 {
1140 /* We're done */
1141 break;
1142 }
1143
1144 /* Next entry */
1145 NextEntry2 = NextEntry2->Flink;
1146 }
1147
1148 /* Insert us right before the next entry */
1149 NextEntry2 = NextEntry2->Blink;
1150 InsertHeadList(NextEntry2, &DriverInfo->Link);
1151 }
1152 }
1153
1154 /* Go to the next driver */
1155 NextEntry = NextEntry->Flink;
1156 }
1157
1158 /* Loop each group index */
1159 for (i = 0; i < IopGroupIndex; i++)
1160 {
1161 /* Loop each group table */
1162 NextEntry = IopGroupTable[i].Flink;
1163 while (NextEntry != &IopGroupTable[i])
1164 {
1165 /* Get the entry */
1166 DriverInfo = CONTAINING_RECORD(NextEntry,
1167 DRIVER_INFORMATION,
1168 Link);
1169
1170 /* Get the driver loader entry */
1171 LdrEntry = DriverInfo->DataTableEntry->LdrEntry;
1172
1173 /* Initialize it */
1174 IopInitializeBuiltinDriver(LdrEntry);
1175
1176 /* Next entry */
1177 NextEntry = NextEntry->Flink;
1178 }
1179 }
1180
1181 /* In old ROS, the loader list became empty after this point. Simulate. */
1182 InitializeListHead(&KeLoaderBlock->LoadOrderListHead);
1183 }
1184
1185 VOID
1186 FASTCALL
1187 INIT_FUNCTION
1188 IopInitializeSystemDrivers(VOID)
1189 {
1190 PUNICODE_STRING *DriverList, *SavedList;
1191
1192 /* No system drivers on the boot cd */
1193 if (KeLoaderBlock->SetupLdrBlock) return;
1194
1195 /* Get the driver list */
1196 SavedList = DriverList = CmGetSystemDriverList();
1197 ASSERT(DriverList);
1198
1199 /* Loop it */
1200 while (*DriverList)
1201 {
1202 /* Load the driver */
1203 ZwLoadDriver(*DriverList);
1204
1205 /* Free the entry */
1206 RtlFreeUnicodeString(*DriverList);
1207 ExFreePool(*DriverList);
1208
1209 /* Next entry */
1210 InbvIndicateProgress();
1211 DriverList++;
1212 }
1213
1214 /* Free the list */
1215 ExFreePool(SavedList);
1216 }
1217
1218 /*
1219 * IopUnloadDriver
1220 *
1221 * Unloads a device driver.
1222 *
1223 * Parameters
1224 * DriverServiceName
1225 * Name of the service to unload (registry key).
1226 *
1227 * UnloadPnpDrivers
1228 * Whether to unload Plug & Plug or only legacy drivers. If this
1229 * parameter is set to FALSE, the routine will unload only legacy
1230 * drivers.
1231 *
1232 * Return Value
1233 * Status
1234 *
1235 * To do
1236 * Guard the whole function by SEH.
1237 */
1238
1239 NTSTATUS NTAPI
1240 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
1241 {
1242 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1243 UNICODE_STRING ImagePath;
1244 UNICODE_STRING ServiceName;
1245 UNICODE_STRING ObjectName;
1246 PDRIVER_OBJECT DriverObject;
1247 PDEVICE_OBJECT DeviceObject;
1248 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1249 NTSTATUS Status;
1250 LPWSTR Start;
1251 BOOLEAN SafeToUnload = TRUE;
1252
1253 DPRINT("IopUnloadDriver('%wZ', %u)\n", DriverServiceName, UnloadPnpDrivers);
1254
1255 PAGED_CODE();
1256
1257 /*
1258 * Get the service name from the registry key name
1259 */
1260
1261 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
1262 if (Start == NULL)
1263 Start = DriverServiceName->Buffer;
1264 else
1265 Start++;
1266
1267 RtlInitUnicodeString(&ServiceName, Start);
1268
1269 /*
1270 * Construct the driver object name
1271 */
1272
1273 ObjectName.Length = ((USHORT)wcslen(Start) + 8) * sizeof(WCHAR);
1274 ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
1275 ObjectName.Buffer = ExAllocatePool(PagedPool, ObjectName.MaximumLength);
1276 if (!ObjectName.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
1277 wcscpy(ObjectName.Buffer, DRIVER_ROOT_NAME);
1278 memcpy(ObjectName.Buffer + 8, Start, ObjectName.Length - 8 * sizeof(WCHAR));
1279 ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = 0;
1280
1281 /*
1282 * Find the driver object
1283 */
1284 Status = ObReferenceObjectByName(&ObjectName,
1285 0,
1286 0,
1287 0,
1288 IoDriverObjectType,
1289 KernelMode,
1290 0,
1291 (PVOID*)&DriverObject);
1292
1293 if (!NT_SUCCESS(Status))
1294 {
1295 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
1296 ExFreePool(ObjectName.Buffer);
1297 return Status;
1298 }
1299
1300 /*
1301 * Free the buffer for driver object name
1302 */
1303 ExFreePool(ObjectName.Buffer);
1304
1305 /* Check that driver is not already unloading */
1306 if (DriverObject->Flags & DRVO_UNLOAD_INVOKED)
1307 {
1308 DPRINT1("Driver deletion pending\n");
1309 ObDereferenceObject(DriverObject);
1310 return STATUS_DELETE_PENDING;
1311 }
1312
1313 /*
1314 * Get path of service...
1315 */
1316 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1317
1318 RtlInitUnicodeString(&ImagePath, NULL);
1319
1320 QueryTable[0].Name = L"ImagePath";
1321 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1322 QueryTable[0].EntryContext = &ImagePath;
1323
1324 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1325 DriverServiceName->Buffer,
1326 QueryTable,
1327 NULL,
1328 NULL);
1329
1330 if (!NT_SUCCESS(Status))
1331 {
1332 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1333 ObDereferenceObject(DriverObject);
1334 return Status;
1335 }
1336
1337 /*
1338 * Normalize the image path for all later processing.
1339 */
1340 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1341
1342 if (!NT_SUCCESS(Status))
1343 {
1344 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status);
1345 ObDereferenceObject(DriverObject);
1346 return Status;
1347 }
1348
1349 /*
1350 * Free the service path
1351 */
1352 ExFreePool(ImagePath.Buffer);
1353
1354 /*
1355 * Unload the module and release the references to the device object
1356 */
1357
1358 /* Call the load/unload routine, depending on current process */
1359 if (DriverObject->DriverUnload && DriverObject->DriverSection &&
1360 (UnloadPnpDrivers || (DriverObject->Flags & DRVO_LEGACY_DRIVER)))
1361 {
1362 /* Loop through each device object of the driver
1363 and set DOE_UNLOAD_PENDING flag */
1364 DeviceObject = DriverObject->DeviceObject;
1365 while (DeviceObject)
1366 {
1367 /* Set the unload pending flag for the device */
1368 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1369 DeviceExtension->ExtensionFlags |= DOE_UNLOAD_PENDING;
1370
1371 /* Make sure there are no attached devices or no reference counts */
1372 if ((DeviceObject->ReferenceCount) || (DeviceObject->AttachedDevice))
1373 {
1374 /* Not safe to unload */
1375 DPRINT1("Drivers device object is referenced or has attached devices\n");
1376
1377 SafeToUnload = FALSE;
1378 }
1379
1380 DeviceObject = DeviceObject->NextDevice;
1381 }
1382
1383 /* If not safe to unload, then return success */
1384 if (!SafeToUnload)
1385 {
1386 ObDereferenceObject(DriverObject);
1387 return STATUS_SUCCESS;
1388 }
1389
1390 DPRINT1("Unloading driver '%wZ' (manual)\n", &DriverObject->DriverName);
1391
1392 /* Set the unload invoked flag and call the unload routine */
1393 DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
1394 Status = IopLoadUnloadDriver(NULL, &DriverObject);
1395 ASSERT(Status == STATUS_SUCCESS);
1396
1397 /* Mark the driver object temporary, so it could be deleted later */
1398 ObMakeTemporaryObject(DriverObject);
1399
1400 /* Dereference it 2 times */
1401 ObDereferenceObject(DriverObject);
1402 ObDereferenceObject(DriverObject);
1403
1404 return Status;
1405 }
1406 else
1407 {
1408 DPRINT1("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
1409
1410 /* Dereference one time (refd inside this function) */
1411 ObDereferenceObject(DriverObject);
1412
1413 /* Return unloading failure */
1414 return STATUS_INVALID_DEVICE_REQUEST;
1415 }
1416 }
1417
1418 VOID
1419 NTAPI
1420 IopReinitializeDrivers(VOID)
1421 {
1422 PDRIVER_REINIT_ITEM ReinitItem;
1423 PLIST_ENTRY Entry;
1424
1425 /* Get the first entry and start looping */
1426 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1427 &DriverReinitListLock);
1428 while (Entry)
1429 {
1430 /* Get the item */
1431 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1432
1433 /* Increment reinitialization counter */
1434 ReinitItem->DriverObject->DriverExtension->Count++;
1435
1436 /* Remove the device object flag */
1437 ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED;
1438
1439 /* Call the routine */
1440 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1441 ReinitItem->Context,
1442 ReinitItem->DriverObject->
1443 DriverExtension->Count);
1444
1445 /* Free the entry */
1446 ExFreePool(Entry);
1447
1448 /* Move to the next one */
1449 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1450 &DriverReinitListLock);
1451 }
1452 }
1453
1454 VOID
1455 NTAPI
1456 IopReinitializeBootDrivers(VOID)
1457 {
1458 PDRIVER_REINIT_ITEM ReinitItem;
1459 PLIST_ENTRY Entry;
1460
1461 /* Get the first entry and start looping */
1462 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1463 &DriverBootReinitListLock);
1464 while (Entry)
1465 {
1466 /* Get the item */
1467 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1468
1469 /* Increment reinitialization counter */
1470 ReinitItem->DriverObject->DriverExtension->Count++;
1471
1472 /* Remove the device object flag */
1473 ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED;
1474
1475 /* Call the routine */
1476 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1477 ReinitItem->Context,
1478 ReinitItem->DriverObject->
1479 DriverExtension->Count);
1480
1481 /* Free the entry */
1482 ExFreePool(Entry);
1483
1484 /* Move to the next one */
1485 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1486 &DriverBootReinitListLock);
1487 }
1488 }
1489
1490 NTSTATUS
1491 NTAPI
1492 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1493 IN PDRIVER_INITIALIZE InitializationFunction,
1494 IN PUNICODE_STRING RegistryPath,
1495 IN PCUNICODE_STRING ServiceName,
1496 PLDR_DATA_TABLE_ENTRY ModuleObject,
1497 OUT PDRIVER_OBJECT *pDriverObject)
1498 {
1499 WCHAR NameBuffer[100];
1500 USHORT NameLength;
1501 UNICODE_STRING LocalDriverName;
1502 NTSTATUS Status;
1503 OBJECT_ATTRIBUTES ObjectAttributes;
1504 ULONG ObjectSize;
1505 PDRIVER_OBJECT DriverObject;
1506 UNICODE_STRING ServiceKeyName;
1507 HANDLE hDriver;
1508 ULONG i, RetryCount = 0;
1509
1510 try_again:
1511 /* First, create a unique name for the driver if we don't have one */
1512 if (!DriverName)
1513 {
1514 /* Create a random name and set up the string */
1515 NameLength = (USHORT)swprintf(NameBuffer,
1516 DRIVER_ROOT_NAME L"%08u",
1517 KeTickCount.LowPart);
1518 LocalDriverName.Length = NameLength * sizeof(WCHAR);
1519 LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1520 LocalDriverName.Buffer = NameBuffer;
1521 }
1522 else
1523 {
1524 /* So we can avoid another code path, use a local var */
1525 LocalDriverName = *DriverName;
1526 }
1527
1528 /* Initialize the Attributes */
1529 ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION);
1530 InitializeObjectAttributes(&ObjectAttributes,
1531 &LocalDriverName,
1532 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1533 NULL,
1534 NULL);
1535
1536 /* Create the Object */
1537 Status = ObCreateObject(KernelMode,
1538 IoDriverObjectType,
1539 &ObjectAttributes,
1540 KernelMode,
1541 NULL,
1542 ObjectSize,
1543 0,
1544 0,
1545 (PVOID*)&DriverObject);
1546 if (!NT_SUCCESS(Status)) return Status;
1547
1548 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject);
1549
1550 /* Set up the Object */
1551 RtlZeroMemory(DriverObject, ObjectSize);
1552 DriverObject->Type = IO_TYPE_DRIVER;
1553 DriverObject->Size = sizeof(DRIVER_OBJECT);
1554 DriverObject->Flags = DRVO_LEGACY_DRIVER;
1555 DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1556 DriverObject->DriverExtension->DriverObject = DriverObject;
1557 DriverObject->DriverInit = InitializationFunction;
1558 DriverObject->DriverSection = ModuleObject;
1559 /* Loop all Major Functions */
1560 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1561 {
1562 /* Invalidate each function */
1563 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1564 }
1565
1566 /* Set up the service key name buffer */
1567 ServiceKeyName.MaximumLength = ServiceName->Length + sizeof(UNICODE_NULL);
1568 ServiceKeyName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
1569 ServiceKeyName.MaximumLength,
1570 TAG_IO);
1571 if (!ServiceKeyName.Buffer)
1572 {
1573 /* Fail */
1574 ObMakeTemporaryObject(DriverObject);
1575 ObDereferenceObject(DriverObject);
1576 return STATUS_INSUFFICIENT_RESOURCES;
1577 }
1578
1579 /* Copy the name and set it in the driver extension */
1580 RtlCopyUnicodeString(&ServiceKeyName,
1581 ServiceName);
1582 DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1583
1584 /* Make a copy of the driver name to store in the driver object */
1585 DriverObject->DriverName.MaximumLength = LocalDriverName.Length;
1586 DriverObject->DriverName.Buffer = ExAllocatePoolWithTag(PagedPool,
1587 DriverObject->DriverName.MaximumLength,
1588 TAG_IO);
1589 if (!DriverObject->DriverName.Buffer)
1590 {
1591 /* Fail */
1592 ObMakeTemporaryObject(DriverObject);
1593 ObDereferenceObject(DriverObject);
1594 return STATUS_INSUFFICIENT_RESOURCES;
1595 }
1596
1597 RtlCopyUnicodeString(&DriverObject->DriverName,
1598 &LocalDriverName);
1599
1600 /* Add the Object and get its handle */
1601 Status = ObInsertObject(DriverObject,
1602 NULL,
1603 FILE_READ_DATA,
1604 0,
1605 NULL,
1606 &hDriver);
1607
1608 /* Eliminate small possibility when this function is called more than
1609 once in a row, and KeTickCount doesn't get enough time to change */
1610 if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100))
1611 {
1612 RetryCount++;
1613 goto try_again;
1614 }
1615
1616 if (!NT_SUCCESS(Status)) return Status;
1617
1618 /* Now reference it */
1619 Status = ObReferenceObjectByHandle(hDriver,
1620 0,
1621 IoDriverObjectType,
1622 KernelMode,
1623 (PVOID*)&DriverObject,
1624 NULL);
1625
1626 /* Close the extra handle */
1627 ZwClose(hDriver);
1628
1629 if (!NT_SUCCESS(Status))
1630 {
1631 /* Fail */
1632 ObMakeTemporaryObject(DriverObject);
1633 ObDereferenceObject(DriverObject);
1634 return Status;
1635 }
1636
1637 DriverObject->HardwareDatabase = &IopHardwareDatabaseKey;
1638 DriverObject->DriverStart = ModuleObject ? ModuleObject->DllBase : 0;
1639 DriverObject->DriverSize = ModuleObject ? ModuleObject->SizeOfImage : 0;
1640
1641 /* Finally, call its init function */
1642 DPRINT("RegistryKey: %wZ\n", RegistryPath);
1643 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction);
1644 Status = (*InitializationFunction)(DriverObject, RegistryPath);
1645 if (!NT_SUCCESS(Status))
1646 {
1647 /* If it didn't work, then kill the object */
1648 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status);
1649 DriverObject->DriverSection = NULL;
1650 ObMakeTemporaryObject(DriverObject);
1651 ObDereferenceObject(DriverObject);
1652 return Status;
1653 }
1654 else
1655 {
1656 /* Returns to caller the object */
1657 *pDriverObject = DriverObject;
1658 }
1659
1660 /* We're going to say if we don't have any DOs from DriverEntry, then we're not legacy.
1661 * Other parts of the I/O manager depend on this behavior */
1662 if (!DriverObject->DeviceObject) DriverObject->Flags &= ~DRVO_LEGACY_DRIVER;
1663
1664 /* Loop all Major Functions */
1665 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1666 {
1667 /*
1668 * Make sure the driver didn't set any dispatch entry point to NULL!
1669 * Doing so is illegal; drivers shouldn't touch entry points they
1670 * do not implement.
1671 */
1672
1673 /* Check if it did so anyway */
1674 if (!DriverObject->MajorFunction[i])
1675 {
1676 /* Print a warning in the debug log */
1677 DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%lu] to NULL!\n",
1678 &DriverObject->DriverName, i);
1679
1680 /* Fix it up */
1681 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1682 }
1683 }
1684
1685 /* Return the Status */
1686 return Status;
1687 }
1688
1689 /* PUBLIC FUNCTIONS ***********************************************************/
1690
1691 /*
1692 * @implemented
1693 */
1694 NTSTATUS
1695 NTAPI
1696 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1697 IN PDRIVER_INITIALIZE InitializationFunction)
1698 {
1699 PDRIVER_OBJECT DriverObject;
1700 return IopCreateDriver(DriverName, InitializationFunction, NULL, DriverName, NULL, &DriverObject);
1701 }
1702
1703 /*
1704 * @implemented
1705 */
1706 VOID
1707 NTAPI
1708 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject)
1709 {
1710 /* Simply dereference the Object */
1711 ObDereferenceObject(DriverObject);
1712 }
1713
1714 /*
1715 * @implemented
1716 */
1717 VOID
1718 NTAPI
1719 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1720 IN PDRIVER_REINITIALIZE ReinitRoutine,
1721 IN PVOID Context)
1722 {
1723 PDRIVER_REINIT_ITEM ReinitItem;
1724
1725 /* Allocate the entry */
1726 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1727 sizeof(DRIVER_REINIT_ITEM),
1728 TAG_REINIT);
1729 if (!ReinitItem) return;
1730
1731 /* Fill it out */
1732 ReinitItem->DriverObject = DriverObject;
1733 ReinitItem->ReinitRoutine = ReinitRoutine;
1734 ReinitItem->Context = Context;
1735
1736 /* Set the Driver Object flag and insert the entry into the list */
1737 DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
1738 ExInterlockedInsertTailList(&DriverBootReinitListHead,
1739 &ReinitItem->ItemEntry,
1740 &DriverBootReinitListLock);
1741 }
1742
1743 /*
1744 * @implemented
1745 */
1746 VOID
1747 NTAPI
1748 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1749 IN PDRIVER_REINITIALIZE ReinitRoutine,
1750 IN PVOID Context)
1751 {
1752 PDRIVER_REINIT_ITEM ReinitItem;
1753
1754 /* Allocate the entry */
1755 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1756 sizeof(DRIVER_REINIT_ITEM),
1757 TAG_REINIT);
1758 if (!ReinitItem) return;
1759
1760 /* Fill it out */
1761 ReinitItem->DriverObject = DriverObject;
1762 ReinitItem->ReinitRoutine = ReinitRoutine;
1763 ReinitItem->Context = Context;
1764
1765 /* Set the Driver Object flag and insert the entry into the list */
1766 DriverObject->Flags |= DRVO_REINIT_REGISTERED;
1767 ExInterlockedInsertTailList(&DriverReinitListHead,
1768 &ReinitItem->ItemEntry,
1769 &DriverReinitListLock);
1770 }
1771
1772 /*
1773 * @implemented
1774 */
1775 NTSTATUS
1776 NTAPI
1777 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1778 IN PVOID ClientIdentificationAddress,
1779 IN ULONG DriverObjectExtensionSize,
1780 OUT PVOID *DriverObjectExtension)
1781 {
1782 KIRQL OldIrql;
1783 PIO_CLIENT_EXTENSION DriverExtensions, NewDriverExtension;
1784 BOOLEAN Inserted = FALSE;
1785
1786 /* Assume failure */
1787 *DriverObjectExtension = NULL;
1788
1789 /* Allocate the extension */
1790 NewDriverExtension = ExAllocatePoolWithTag(NonPagedPool,
1791 sizeof(IO_CLIENT_EXTENSION) +
1792 DriverObjectExtensionSize,
1793 TAG_DRIVER_EXTENSION);
1794 if (!NewDriverExtension) return STATUS_INSUFFICIENT_RESOURCES;
1795
1796 /* Clear the extension for teh caller */
1797 RtlZeroMemory(NewDriverExtension,
1798 sizeof(IO_CLIENT_EXTENSION) + DriverObjectExtensionSize);
1799
1800 /* Acqure lock */
1801 OldIrql = KeRaiseIrqlToDpcLevel();
1802
1803 /* Fill out the extension */
1804 NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
1805
1806 /* Loop the current extensions */
1807 DriverExtensions = IoGetDrvObjExtension(DriverObject)->
1808 ClientDriverExtension;
1809 while (DriverExtensions)
1810 {
1811 /* Check if the identifier matches */
1812 if (DriverExtensions->ClientIdentificationAddress ==
1813 ClientIdentificationAddress)
1814 {
1815 /* We have a collision, break out */
1816 break;
1817 }
1818
1819 /* Go to the next one */
1820 DriverExtensions = DriverExtensions->NextExtension;
1821 }
1822
1823 /* Check if we didn't collide */
1824 if (!DriverExtensions)
1825 {
1826 /* Link this one in */
1827 NewDriverExtension->NextExtension =
1828 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1829 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension =
1830 NewDriverExtension;
1831 Inserted = TRUE;
1832 }
1833
1834 /* Release the lock */
1835 KeLowerIrql(OldIrql);
1836
1837 /* Check if insertion failed */
1838 if (!Inserted)
1839 {
1840 /* Free the entry and fail */
1841 ExFreePoolWithTag(NewDriverExtension, TAG_DRIVER_EXTENSION);
1842 return STATUS_OBJECT_NAME_COLLISION;
1843 }
1844
1845 /* Otherwise, return the pointer */
1846 *DriverObjectExtension = NewDriverExtension + 1;
1847 return STATUS_SUCCESS;
1848 }
1849
1850 /*
1851 * @implemented
1852 */
1853 PVOID
1854 NTAPI
1855 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1856 IN PVOID ClientIdentificationAddress)
1857 {
1858 KIRQL OldIrql;
1859 PIO_CLIENT_EXTENSION DriverExtensions;
1860
1861 /* Acquire lock */
1862 OldIrql = KeRaiseIrqlToDpcLevel();
1863
1864 /* Loop the list until we find the right one */
1865 DriverExtensions = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1866 while (DriverExtensions)
1867 {
1868 /* Check for a match */
1869 if (DriverExtensions->ClientIdentificationAddress ==
1870 ClientIdentificationAddress)
1871 {
1872 /* Break out */
1873 break;
1874 }
1875
1876 /* Keep looping */
1877 DriverExtensions = DriverExtensions->NextExtension;
1878 }
1879
1880 /* Release lock */
1881 KeLowerIrql(OldIrql);
1882
1883 /* Return nothing or the extension */
1884 if (!DriverExtensions) return NULL;
1885 return DriverExtensions + 1;
1886 }
1887
1888 VOID
1889 NTAPI
1890 IopLoadUnloadDriverWorker(
1891 _Inout_ PVOID Parameter)
1892 {
1893 PLOAD_UNLOAD_PARAMS LoadParams = Parameter;
1894
1895 ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess);
1896 LoadParams->Status = IopLoadUnloadDriver(LoadParams->RegistryPath,
1897 &LoadParams->DriverObject);
1898 KeSetEvent(&LoadParams->Event, 0, FALSE);
1899 }
1900
1901 NTSTATUS
1902 NTAPI
1903 IopLoadUnloadDriver(
1904 _In_opt_ PCUNICODE_STRING RegistryPath,
1905 _Inout_ PDRIVER_OBJECT *DriverObject)
1906 {
1907 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
1908 UNICODE_STRING ImagePath;
1909 UNICODE_STRING ServiceName;
1910 NTSTATUS Status;
1911 ULONG Type;
1912 PDEVICE_NODE DeviceNode;
1913 PLDR_DATA_TABLE_ENTRY ModuleObject;
1914 PVOID BaseAddress;
1915 WCHAR *cur;
1916
1917 /* Load/Unload must be called from system process */
1918 if (PsGetCurrentProcess() != PsInitialSystemProcess)
1919 {
1920 LOAD_UNLOAD_PARAMS LoadParams;
1921
1922 /* Prepare parameters block */
1923 LoadParams.RegistryPath = RegistryPath;
1924 LoadParams.DriverObject = *DriverObject;
1925 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
1926
1927 /* Initialize and queue a work item */
1928 ExInitializeWorkItem(&LoadParams.WorkItem,
1929 IopLoadUnloadDriverWorker,
1930 &LoadParams);
1931 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
1932
1933 /* And wait till it completes */
1934 KeWaitForSingleObject(&LoadParams.Event,
1935 UserRequest,
1936 KernelMode,
1937 FALSE,
1938 NULL);
1939 return LoadParams.Status;
1940 }
1941
1942 /* Check if it's an unload request */
1943 if (*DriverObject)
1944 {
1945 (*DriverObject)->DriverUnload(*DriverObject);
1946 return STATUS_SUCCESS;
1947 }
1948
1949 RtlInitUnicodeString(&ImagePath, NULL);
1950
1951 /*
1952 * Get the service name from the registry key name.
1953 */
1954 ASSERT(RegistryPath->Length >= sizeof(WCHAR));
1955
1956 ServiceName = *RegistryPath;
1957 cur = RegistryPath->Buffer + RegistryPath->Length / sizeof(WCHAR) - 1;
1958 while (RegistryPath->Buffer != cur)
1959 {
1960 if (*cur == L'\\')
1961 {
1962 ServiceName.Buffer = cur + 1;
1963 ServiceName.Length = RegistryPath->Length -
1964 (USHORT)((ULONG_PTR)ServiceName.Buffer -
1965 (ULONG_PTR)RegistryPath->Buffer);
1966 break;
1967 }
1968 cur--;
1969 }
1970
1971 /*
1972 * Get service type.
1973 */
1974 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
1975
1976 RtlInitUnicodeString(&ImagePath, NULL);
1977
1978 QueryTable[0].Name = L"Type";
1979 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1980 QueryTable[0].EntryContext = &Type;
1981
1982 QueryTable[1].Name = L"ImagePath";
1983 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1984 QueryTable[1].EntryContext = &ImagePath;
1985
1986 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1987 RegistryPath->Buffer,
1988 QueryTable, NULL, NULL);
1989 if (!NT_SUCCESS(Status))
1990 {
1991 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
1992 if (ImagePath.Buffer) ExFreePool(ImagePath.Buffer);
1993 return Status;
1994 }
1995
1996 /*
1997 * Normalize the image path for all later processing.
1998 */
1999 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
2000 if (!NT_SUCCESS(Status))
2001 {
2002 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
2003 return Status;
2004 }
2005
2006 DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
2007 DPRINT("Type: %lx\n", Type);
2008
2009 KeEnterCriticalRegion();
2010 ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE);
2011 /*
2012 * Get existing DriverObject pointer (in case the driver
2013 * has already been loaded and initialized).
2014 */
2015 Status = IopGetDriverObject(DriverObject,
2016 &ServiceName,
2017 (Type == SERVICE_FILE_SYSTEM_DRIVER ||
2018 Type == SERVICE_RECOGNIZER_DRIVER));
2019
2020 if (!NT_SUCCESS(Status))
2021 {
2022 /*
2023 * Load the driver module
2024 */
2025 DPRINT("Loading module from %wZ\n", &ImagePath);
2026 Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress);
2027 if (!NT_SUCCESS(Status))
2028 {
2029 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
2030 ExReleaseResourceLite(&IopDriverLoadResource);
2031 KeLeaveCriticalRegion();
2032 return Status;
2033 }
2034
2035 /*
2036 * Initialize the driver module if it's loaded for the first time
2037 */
2038 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
2039 if (!NT_SUCCESS(Status))
2040 {
2041 DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status);
2042 ExReleaseResourceLite(&IopDriverLoadResource);
2043 KeLeaveCriticalRegion();
2044 MmUnloadSystemImage(ModuleObject);
2045 return Status;
2046 }
2047
2048 IopDisplayLoadingMessage(&DeviceNode->ServiceName);
2049
2050 Status = IopInitializeDriverModule(DeviceNode,
2051 ModuleObject,
2052 &DeviceNode->ServiceName,
2053 (Type == SERVICE_FILE_SYSTEM_DRIVER ||
2054 Type == SERVICE_RECOGNIZER_DRIVER),
2055 DriverObject);
2056 if (!NT_SUCCESS(Status))
2057 {
2058 DPRINT1("IopInitializeDriverModule() failed (Status %lx)\n", Status);
2059 ExReleaseResourceLite(&IopDriverLoadResource);
2060 KeLeaveCriticalRegion();
2061 MmUnloadSystemImage(ModuleObject);
2062 return Status;
2063 }
2064
2065 ExReleaseResourceLite(&IopDriverLoadResource);
2066 KeLeaveCriticalRegion();
2067
2068 /* Initialize and start device */
2069 IopInitializeDevice(DeviceNode, *DriverObject);
2070 Status = IopStartDevice(DeviceNode);
2071 }
2072 else
2073 {
2074 ExReleaseResourceLite(&IopDriverLoadResource);
2075 KeLeaveCriticalRegion();
2076
2077 DPRINT("DriverObject already exist in ObjectManager\n");
2078 Status = STATUS_IMAGE_ALREADY_LOADED;
2079
2080 /* IopGetDriverObject references the DriverObject, so dereference it */
2081 ObDereferenceObject(*DriverObject);
2082 }
2083
2084 return Status;
2085 }
2086
2087 /*
2088 * NtLoadDriver
2089 *
2090 * Loads a device driver.
2091 *
2092 * Parameters
2093 * DriverServiceName
2094 * Name of the service to load (registry key).
2095 *
2096 * Return Value
2097 * Status
2098 *
2099 * Status
2100 * implemented
2101 */
2102 NTSTATUS NTAPI
2103 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
2104 {
2105 UNICODE_STRING CapturedDriverServiceName = { 0, 0, NULL };
2106 KPROCESSOR_MODE PreviousMode;
2107 PDRIVER_OBJECT DriverObject;
2108 NTSTATUS Status;
2109
2110 PAGED_CODE();
2111
2112 PreviousMode = KeGetPreviousMode();
2113
2114 /*
2115 * Check security privileges
2116 */
2117
2118 /* FIXME: Uncomment when privileges will be correctly implemented. */
2119 #if 0
2120 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2121 {
2122 DPRINT("Privilege not held\n");
2123 return STATUS_PRIVILEGE_NOT_HELD;
2124 }
2125 #endif
2126
2127 Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
2128 PreviousMode,
2129 DriverServiceName);
2130 if (!NT_SUCCESS(Status))
2131 {
2132 return Status;
2133 }
2134
2135 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
2136
2137 /* Load driver and call its entry point */
2138 DriverObject = NULL;
2139 Status = IopLoadUnloadDriver(&CapturedDriverServiceName, &DriverObject);
2140
2141 ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
2142 PreviousMode);
2143
2144 return Status;
2145 }
2146
2147 /*
2148 * NtUnloadDriver
2149 *
2150 * Unloads a legacy device driver.
2151 *
2152 * Parameters
2153 * DriverServiceName
2154 * Name of the service to unload (registry key).
2155 *
2156 * Return Value
2157 * Status
2158 *
2159 * Status
2160 * implemented
2161 */
2162
2163 NTSTATUS NTAPI
2164 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
2165 {
2166 return IopUnloadDriver(DriverServiceName, FALSE);
2167 }
2168
2169 /* EOF */