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