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)
11 /* INCLUDES *******************************************************************/
17 /* GLOBALS ********************************************************************/
19 LIST_ENTRY DriverReinitListHead
;
20 KSPIN_LOCK DriverReinitListLock
;
21 PLIST_ENTRY DriverReinitTailEntry
;
23 PLIST_ENTRY DriverBootReinitTailEntry
;
24 LIST_ENTRY DriverBootReinitListHead
;
25 KSPIN_LOCK DriverBootReinitListLock
;
27 UNICODE_STRING IopHardwareDatabaseKey
=
28 RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
30 POBJECT_TYPE IoDriverObjectType
= NULL
;
32 #define TAG_RTLREGISTRY 'vrqR'
34 extern BOOLEAN ExpInTextModeSetup
;
35 extern BOOLEAN PnpSystemInit
;
38 PLIST_ENTRY IopGroupTable
;
40 /* PRIVATE FUNCTIONS **********************************************************/
43 IopInvalidDeviceRequest(
44 PDEVICE_OBJECT DeviceObject
,
47 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
48 Irp
->IoStatus
.Information
= 0;
49 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
50 return STATUS_INVALID_DEVICE_REQUEST
;
55 IopDeleteDriver(IN PVOID ObjectBody
)
57 PDRIVER_OBJECT DriverObject
= ObjectBody
;
58 PIO_CLIENT_EXTENSION DriverExtension
, NextDriverExtension
;
61 DPRINT1("Deleting driver object '%wZ'\n", &DriverObject
->DriverName
);
63 /* There must be no device objects remaining at this point */
64 ASSERT(!DriverObject
->DeviceObject
);
66 /* Get the extension and loop them */
67 DriverExtension
= IoGetDrvObjExtension(DriverObject
)->
68 ClientDriverExtension
;
69 while (DriverExtension
)
71 /* Get the next one */
72 NextDriverExtension
= DriverExtension
->NextExtension
;
73 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
76 DriverExtension
= NextDriverExtension
;
79 /* Check if the driver image is still loaded */
80 if (DriverObject
->DriverSection
)
83 MmUnloadSystemImage(DriverObject
->DriverSection
);
86 /* Check if it has a name */
87 if (DriverObject
->DriverName
.Buffer
)
90 ExFreePool(DriverObject
->DriverName
.Buffer
);
93 #if 0 /* See a bit of hack in IopCreateDriver */
94 /* Check if it has a service key name */
95 if (DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
)
98 ExFreePool(DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
);
105 PDRIVER_OBJECT
*DriverObject
,
106 PUNICODE_STRING ServiceName
,
109 PDRIVER_OBJECT Object
;
110 WCHAR NameBuffer
[MAX_PATH
];
111 UNICODE_STRING DriverName
;
114 DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
115 DriverObject
, ServiceName
, FileSystem
);
117 *DriverObject
= NULL
;
119 /* Create ModuleName string */
120 if (ServiceName
== NULL
|| ServiceName
->Buffer
== NULL
)
121 /* We don't know which DriverObject we have to open */
122 return STATUS_INVALID_PARAMETER_2
;
124 DriverName
.Buffer
= NameBuffer
;
125 DriverName
.Length
= 0;
126 DriverName
.MaximumLength
= sizeof(NameBuffer
);
128 if (FileSystem
== TRUE
)
129 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
131 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
132 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
134 DPRINT("Driver name: '%wZ'\n", &DriverName
);
136 /* Open driver object */
137 Status
= ObReferenceObjectByName(
139 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, /* Attributes */
140 NULL
, /* PassedAccessState */
141 0, /* DesiredAccess */
144 NULL
, /* ParseContext */
147 if (!NT_SUCCESS(Status
))
149 DPRINT("Failed to reference driver object, status=0x%08x\n", Status
);
153 *DriverObject
= Object
;
155 DPRINT("Driver Object: %p\n", Object
);
157 return STATUS_SUCCESS
;
162 * TRUE if String2 contains String1 as a suffix.
166 IopSuffixUnicodeString(
167 IN PCUNICODE_STRING String1
,
168 IN PCUNICODE_STRING String2
)
174 if (String2
->Length
< String1
->Length
)
177 Length
= String1
->Length
/ 2;
178 pc1
= String1
->Buffer
;
179 pc2
= &String2
->Buffer
[String2
->Length
/ sizeof(WCHAR
) - Length
];
185 if( *pc1
++ != *pc2
++ )
194 * IopDisplayLoadingMessage
196 * Display 'Loading XXX...' message.
202 IopDisplayLoadingMessage(PUNICODE_STRING ServiceName
)
204 CHAR TextBuffer
[256];
205 UNICODE_STRING DotSys
= RTL_CONSTANT_STRING(L
".SYS");
207 if (ExpInTextModeSetup
) return;
208 if (!KeLoaderBlock
) return;
209 RtlUpcaseUnicodeString(ServiceName
, ServiceName
, FALSE
);
210 snprintf(TextBuffer
, sizeof(TextBuffer
),
211 "%s%sSystem32\\Drivers\\%wZ%s\n",
212 KeLoaderBlock
->ArcBootDeviceName
,
213 KeLoaderBlock
->NtBootPathName
,
215 IopSuffixUnicodeString(&DotSys
, ServiceName
) ? "" : ".SYS");
216 HalDisplayString(TextBuffer
);
220 * IopNormalizeImagePath
222 * Normalize an image path to contain complete path.
226 * The input path and on exit the result path. ImagePath.Buffer
227 * must be allocated by ExAllocatePool on input. Caller is responsible
228 * for freeing the buffer when it's no longer needed.
231 * Name of the service that ImagePath belongs to.
237 * The input image path isn't freed on error.
241 IopNormalizeImagePath(
242 IN OUT PUNICODE_STRING ImagePath
,
243 IN PUNICODE_STRING ServiceName
)
245 UNICODE_STRING InputImagePath
;
247 DPRINT("Normalizing image path '%wZ' for service '%wZ'\n", ImagePath
, ServiceName
);
252 sizeof(UNICODE_STRING
));
254 if (InputImagePath
.Length
== 0)
256 ImagePath
->Length
= 0;
257 ImagePath
->MaximumLength
=
258 (33 * sizeof(WCHAR
)) + ServiceName
->Length
+ sizeof(UNICODE_NULL
);
259 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
260 if (ImagePath
->Buffer
== NULL
)
261 return STATUS_NO_MEMORY
;
263 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\system32\\drivers\\");
264 RtlAppendUnicodeStringToString(ImagePath
, ServiceName
);
265 RtlAppendUnicodeToString(ImagePath
, L
".sys");
267 if (InputImagePath
.Buffer
[0] != L
'\\')
269 ImagePath
->Length
= 0;
270 ImagePath
->MaximumLength
=
271 12 * sizeof(WCHAR
) + InputImagePath
.Length
+ sizeof(UNICODE_NULL
);
272 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
273 if (ImagePath
->Buffer
== NULL
)
274 return STATUS_NO_MEMORY
;
276 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\");
277 RtlAppendUnicodeStringToString(ImagePath
, &InputImagePath
);
279 /* Free caller's string */
280 ExFreePoolWithTag(InputImagePath
.Buffer
, TAG_RTLREGISTRY
);
283 DPRINT("Normalized image path is '%wZ' for service '%wZ'\n", ImagePath
, ServiceName
);
285 return STATUS_SUCCESS
;
289 * IopLoadServiceModule
291 * Load a module specified by registry settings for service.
295 * Name of the service to load.
302 IopLoadServiceModule(
303 IN PUNICODE_STRING ServiceName
,
304 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
306 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
308 UNICODE_STRING ServiceImagePath
, CCSName
;
310 HANDLE CCSKey
, ServiceKey
;
313 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
315 /* FIXME: This check may be removed once the bug is fixed */
316 if (ServiceName
->Buffer
== NULL
)
318 DPRINT1("If you see this, please report to Fireball or hpoussin!\n");
319 return STATUS_UNSUCCESSFUL
;
322 if (ExpInTextModeSetup
)
324 /* We have no registry, but luckily we know where all the drivers are */
326 /* ServiceStart < 4 is all that matters */
329 /* IopNormalizeImagePath will do all of the work for us if we give it an empty string */
330 ServiceImagePath
.Length
= ServiceImagePath
.MaximumLength
= 0;
331 ServiceImagePath
.Buffer
= NULL
;
335 /* Open CurrentControlSet */
336 RtlInitUnicodeString(&CCSName
,
337 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
338 Status
= IopOpenRegistryKeyEx(&CCSKey
, NULL
, &CCSName
, KEY_READ
);
339 if (!NT_SUCCESS(Status
))
341 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
345 /* Open service key */
346 Status
= IopOpenRegistryKeyEx(&ServiceKey
, CCSKey
, ServiceName
, KEY_READ
);
347 if (!NT_SUCCESS(Status
))
349 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
355 * Get information about the service.
358 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
360 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
362 QueryTable
[0].Name
= L
"Start";
363 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
364 QueryTable
[0].EntryContext
= &ServiceStart
;
366 QueryTable
[1].Name
= L
"ImagePath";
367 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
368 QueryTable
[1].EntryContext
= &ServiceImagePath
;
370 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
371 (PWSTR
)ServiceKey
, QueryTable
, NULL
, NULL
);
376 if (!NT_SUCCESS(Status
))
378 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
384 * Normalize the image path for all later processing.
387 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
389 if (!NT_SUCCESS(Status
))
391 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
396 * Case for disabled drivers
399 if (ServiceStart
>= 4)
401 /* We can't load this */
402 Status
= STATUS_DRIVER_UNABLE_TO_LOAD
;
406 DPRINT("Loading module from %wZ\n", &ServiceImagePath
);
407 Status
= MmLoadSystemImage(&ServiceImagePath
, NULL
, NULL
, 0, (PVOID
)ModuleObject
, &BaseAddress
);
408 if (NT_SUCCESS(Status
))
410 IopDisplayLoadingMessage(ServiceName
);
414 ExFreePool(ServiceImagePath
.Buffer
);
417 * Now check if the module was loaded successfully.
420 if (!NT_SUCCESS(Status
))
422 DPRINT("Module loading failed (Status %x)\n", Status
);
425 DPRINT("Module loading (Status %x)\n", Status
);
432 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry
);
435 * IopInitializeDriverModule
437 * Initalize a loaded driver.
441 * Pointer to device node.
444 * Module object representing the driver. It can be retrieve by
445 * IopLoadServiceModule.
448 * Name of the service (as in registry).
451 * Set to TRUE for file system drivers.
454 * On successful return this contains the driver object representing
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
)
466 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
467 WCHAR NameBuffer
[MAX_PATH
];
468 UNICODE_STRING DriverName
;
469 UNICODE_STRING RegistryKey
;
470 PDRIVER_INITIALIZE DriverEntry
;
471 PDRIVER_OBJECT Driver
;
474 DriverEntry
= ModuleObject
->EntryPoint
;
476 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
478 RegistryKey
.Length
= 0;
479 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
480 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
481 if (RegistryKey
.Buffer
== NULL
)
483 return STATUS_INSUFFICIENT_RESOURCES
;
485 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
486 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
490 RtlInitUnicodeString(&RegistryKey
, NULL
);
493 /* Create ModuleName string */
494 if (ServiceName
&& ServiceName
->Length
> 0)
496 if (FileSystemDriver
== TRUE
)
497 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
499 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
501 RtlInitUnicodeString(&DriverName
, NameBuffer
);
502 DriverName
.MaximumLength
= sizeof(NameBuffer
);
504 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
506 DPRINT("Driver name: '%wZ'\n", &DriverName
);
509 DriverName
.Length
= 0;
511 Status
= IopCreateDriver(
512 DriverName
.Length
> 0 ? &DriverName
: NULL
,
517 RtlFreeUnicodeString(&RegistryKey
);
519 *DriverObject
= Driver
;
520 if (!NT_SUCCESS(Status
))
522 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status
);
526 MmFreeDriverInitialization((PLDR_DATA_TABLE_ENTRY
)Driver
->DriverSection
);
528 /* Set the driver as initialized */
529 IopReadyDeviceObjects(Driver
);
531 if (PnpSystemInit
) IopReinitializeDrivers();
533 return STATUS_SUCCESS
;
537 * IopAttachFilterDriversCallback
539 * Internal routine used by IopAttachFilterDrivers.
543 IopAttachFilterDriversCallback(
551 PDEVICE_NODE DeviceNode
= Context
;
552 UNICODE_STRING ServiceName
;
554 PLDR_DATA_TABLE_ENTRY ModuleObject
;
555 PDRIVER_OBJECT DriverObject
;
558 for (Filters
= ValueData
;
559 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
561 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
563 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
565 ServiceName
.Buffer
= Filters
;
566 ServiceName
.MaximumLength
=
567 ServiceName
.Length
= (USHORT
)wcslen(Filters
) * sizeof(WCHAR
);
569 Status
= IopGetDriverObject(&DriverObject
,
572 if (!NT_SUCCESS(Status
))
574 /* Load and initialize the filter driver */
575 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
576 if (!NT_SUCCESS(Status
))
579 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
580 FALSE
, &DriverObject
);
581 if (!NT_SUCCESS(Status
))
585 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
587 /* Remove extra reference */
588 ObDereferenceObject(DriverObject
);
591 return STATUS_SUCCESS
;
595 * IopAttachFilterDrivers
597 * Load filter drivers for specified device node.
601 * Set to TRUE for loading lower level filters or FALSE for upper
606 IopAttachFilterDrivers(
607 PDEVICE_NODE DeviceNode
,
610 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = { { NULL
, 0, NULL
, NULL
, 0, NULL
, 0 }, };
611 UNICODE_STRING Class
;
612 WCHAR ClassBuffer
[40];
613 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
614 HANDLE EnumRootKey
, SubKey
;
617 /* Open enumeration root key */
618 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
619 &EnumRoot
, KEY_READ
);
620 if (!NT_SUCCESS(Status
))
622 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
627 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
628 &DeviceNode
->InstancePath
, KEY_READ
);
629 if (!NT_SUCCESS(Status
))
631 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
632 ZwClose(EnumRootKey
);
637 * First load the device filters
639 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
641 QueryTable
[0].Name
= L
"LowerFilters";
643 QueryTable
[0].Name
= L
"UpperFilters";
644 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
646 RtlQueryRegistryValues(
654 * Now get the class GUID
657 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
658 Class
.Buffer
= ClassBuffer
;
659 QueryTable
[0].QueryRoutine
= NULL
;
660 QueryTable
[0].Name
= L
"ClassGUID";
661 QueryTable
[0].EntryContext
= &Class
;
662 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
664 Status
= RtlQueryRegistryValues(
673 ZwClose(EnumRootKey
);
676 * Load the class filter driver
678 if (NT_SUCCESS(Status
))
680 UNICODE_STRING ControlClass
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
682 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
683 &ControlClass
, KEY_READ
);
684 if (!NT_SUCCESS(Status
))
686 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
691 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
693 if (!NT_SUCCESS(Status
))
695 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
696 ZwClose(EnumRootKey
);
700 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
702 QueryTable
[0].Name
= L
"LowerFilters";
704 QueryTable
[0].Name
= L
"UpperFilters";
705 QueryTable
[0].EntryContext
= NULL
;
706 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
708 RtlQueryRegistryValues(
717 ZwClose(EnumRootKey
);
720 return STATUS_SUCCESS
;
725 MiResolveImageReferences(IN PVOID ImageBase
,
726 IN PUNICODE_STRING ImageFileDirectory
,
727 IN PUNICODE_STRING NamePrefix OPTIONAL
,
728 OUT PCHAR
*MissingApi
,
729 OUT PWCHAR
*MissingDriver
,
730 OUT PLOAD_IMPORTS
*LoadImports
);
733 // Used for images already loaded (boot drivers)
738 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry
,
739 PUNICODE_STRING FileName
,
740 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
743 UNICODE_STRING BaseName
, BaseDirectory
;
744 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
745 PCHAR MissingApiName
, Buffer
;
746 PWCHAR MissingDriverName
;
747 PVOID DriverBase
= LdrEntry
->DllBase
;
749 /* Allocate a buffer we'll use for names */
750 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
754 return STATUS_INSUFFICIENT_RESOURCES
;
757 /* Check for a separator */
758 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
763 /* Loop the path until we get to the base name */
764 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
765 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
768 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
769 BaseLength
*= sizeof(WCHAR
);
771 /* Setup the string */
772 BaseName
.Length
= (USHORT
)BaseLength
;
777 /* Otherwise, we already have a base name */
778 BaseName
.Length
= FileName
->Length
;
779 BaseName
.Buffer
= FileName
->Buffer
;
782 /* Setup the maximum length */
783 BaseName
.MaximumLength
= BaseName
.Length
;
785 /* Now compute the base directory */
786 BaseDirectory
= *FileName
;
787 BaseDirectory
.Length
-= BaseName
.Length
;
788 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
790 /* Resolve imports */
791 MissingApiName
= Buffer
;
792 Status
= MiResolveImageReferences(DriverBase
,
798 if (!NT_SUCCESS(Status
)) return Status
;
801 *ModuleObject
= LdrEntry
;
802 return STATUS_SUCCESS
;
806 * IopInitializeBuiltinDriver
808 * Initialize a driver that is already loaded in memory.
814 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
816 PDEVICE_NODE DeviceNode
;
817 PDRIVER_OBJECT DriverObject
;
819 PWCHAR FileNameWithoutPath
;
820 LPWSTR FileExtension
;
821 PUNICODE_STRING ModuleName
= &LdrEntry
->BaseDllName
;
822 UNICODE_STRING ServiceName
;
825 * Display 'Loading XXX...' message
827 IopDisplayLoadingMessage(ModuleName
);
828 InbvIndicateProgress();
831 * Generate filename without path (not needed by freeldr)
833 FileNameWithoutPath
= wcsrchr(ModuleName
->Buffer
, L
'\\');
834 if (FileNameWithoutPath
== NULL
)
836 FileNameWithoutPath
= ModuleName
->Buffer
;
840 FileNameWithoutPath
++;
844 * Strip the file extension from ServiceName
846 RtlCreateUnicodeString(&ServiceName
, FileNameWithoutPath
);
847 FileExtension
= wcsrchr(ServiceName
.Buffer
, '.');
848 if (FileExtension
!= NULL
)
850 ServiceName
.Length
-= (USHORT
)wcslen(FileExtension
) * sizeof(WCHAR
);
851 FileExtension
[0] = 0;
855 * Determine the right device object
857 /* Use IopRootDeviceNode for now */
858 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
859 if (!NT_SUCCESS(Status
))
861 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
866 * Initialize the driver
868 Status
= IopInitializeDriverModule(DeviceNode
, LdrEntry
,
869 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
871 if (!NT_SUCCESS(Status
))
873 IopFreeDeviceNode(DeviceNode
);
877 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
878 if (NT_SUCCESS(Status
))
880 Status
= IopStartDevice(DeviceNode
);
883 /* Remove extra reference from IopInitializeDriverModule */
884 ObDereferenceObject(DriverObject
);
890 * IopInitializeBootDrivers
892 * Initialize boot drivers and free memory for boot files.
903 IopInitializeBootDrivers(VOID
)
905 PLIST_ENTRY ListHead
, NextEntry
, NextEntry2
;
906 PLDR_DATA_TABLE_ENTRY LdrEntry
;
907 PDEVICE_NODE DeviceNode
;
908 PDRIVER_OBJECT DriverObject
;
909 LDR_DATA_TABLE_ENTRY ModuleObject
;
911 UNICODE_STRING DriverName
;
913 PDRIVER_INFORMATION DriverInfo
, DriverInfoTag
;
915 PBOOT_DRIVER_LIST_ENTRY BootEntry
;
916 DPRINT("IopInitializeBootDrivers()\n");
918 /* Use IopRootDeviceNode for now */
919 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, NULL
, &DeviceNode
);
920 if (!NT_SUCCESS(Status
)) return;
922 /* Setup the module object for the RAW FS Driver */
923 ModuleObject
.DllBase
= NULL
;
924 ModuleObject
.SizeOfImage
= 0;
925 ModuleObject
.EntryPoint
= RawFsDriverEntry
;
926 RtlInitUnicodeString(&DriverName
, L
"RAW");
929 Status
= IopInitializeDriverModule(DeviceNode
,
934 if (!NT_SUCCESS(Status
))
937 IopFreeDeviceNode(DeviceNode
);
941 /* Now initialize the associated device */
942 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
943 if (!NT_SUCCESS(Status
))
946 IopFreeDeviceNode(DeviceNode
);
947 ObDereferenceObject(DriverObject
);
952 Status
= IopStartDevice(DeviceNode
);
953 if (!NT_SUCCESS(Status
))
956 IopFreeDeviceNode(DeviceNode
);
957 ObDereferenceObject(DriverObject
);
961 /* Get highest group order index */
962 IopGroupIndex
= PpInitGetGroupOrderIndex(NULL
);
963 if (IopGroupIndex
== 0xFFFF) ASSERT(FALSE
);
965 /* Allocate the group table */
966 IopGroupTable
= ExAllocatePoolWithTag(PagedPool
,
967 IopGroupIndex
* sizeof(LIST_ENTRY
),
969 if (IopGroupTable
== NULL
) ASSERT(FALSE
);
971 /* Initialize the group table lists */
972 for (i
= 0; i
< IopGroupIndex
; i
++) InitializeListHead(&IopGroupTable
[i
]);
974 /* Loop the boot modules */
975 ListHead
= &KeLoaderBlock
->LoadOrderListHead
;
976 NextEntry
= ListHead
->Flink
;
977 while (ListHead
!= NextEntry
)
980 LdrEntry
= CONTAINING_RECORD(NextEntry
,
981 LDR_DATA_TABLE_ENTRY
,
984 /* Check if the DLL needs to be initialized */
985 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
987 /* Call its entrypoint */
988 MmCallDllInitialize(LdrEntry
, NULL
);
991 /* Go to the next driver */
992 NextEntry
= NextEntry
->Flink
;
995 /* Loop the boot drivers */
996 ListHead
= &KeLoaderBlock
->BootDriverListHead
;
997 NextEntry
= ListHead
->Flink
;
998 while (ListHead
!= NextEntry
)
1001 BootEntry
= CONTAINING_RECORD(NextEntry
,
1002 BOOT_DRIVER_LIST_ENTRY
,
1005 /* Get the driver loader entry */
1006 LdrEntry
= BootEntry
->LdrEntry
;
1008 /* Allocate our internal accounting structure */
1009 DriverInfo
= ExAllocatePoolWithTag(PagedPool
,
1010 sizeof(DRIVER_INFORMATION
),
1014 /* Zero it and initialize it */
1015 RtlZeroMemory(DriverInfo
, sizeof(DRIVER_INFORMATION
));
1016 InitializeListHead(&DriverInfo
->Link
);
1017 DriverInfo
->DataTableEntry
= BootEntry
;
1019 /* Open the registry key */
1020 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
1022 &BootEntry
->RegistryPath
,
1024 if ((NT_SUCCESS(Status
)) || /* ReactOS HACK for SETUPLDR */
1025 ((KeLoaderBlock
->SetupLdrBlock
) && ((KeyHandle
= (PVOID
)1)))) // yes, it's an assignment!
1027 /* Save the handle */
1028 DriverInfo
->ServiceHandle
= KeyHandle
;
1030 /* Get the group oder index */
1031 Index
= PpInitGetGroupOrderIndex(KeyHandle
);
1033 /* Get the tag position */
1034 DriverInfo
->TagPosition
= PipGetDriverTagPriority(KeyHandle
);
1036 /* Insert it into the list, at the right place */
1037 ASSERT(Index
< IopGroupIndex
);
1038 NextEntry2
= IopGroupTable
[Index
].Flink
;
1039 while (NextEntry2
!= &IopGroupTable
[Index
])
1041 /* Get the driver info */
1042 DriverInfoTag
= CONTAINING_RECORD(NextEntry2
,
1046 /* Check if we found the right tag position */
1047 if (DriverInfoTag
->TagPosition
> DriverInfo
->TagPosition
)
1054 NextEntry2
= NextEntry2
->Flink
;
1057 /* Insert us right before the next entry */
1058 NextEntry2
= NextEntry2
->Blink
;
1059 InsertHeadList(NextEntry2
, &DriverInfo
->Link
);
1063 /* Go to the next driver */
1064 NextEntry
= NextEntry
->Flink
;
1067 /* Loop each group index */
1068 for (i
= 0; i
< IopGroupIndex
; i
++)
1070 /* Loop each group table */
1071 NextEntry
= IopGroupTable
[i
].Flink
;
1072 while (NextEntry
!= &IopGroupTable
[i
])
1075 DriverInfo
= CONTAINING_RECORD(NextEntry
,
1079 /* Get the driver loader entry */
1080 LdrEntry
= DriverInfo
->DataTableEntry
->LdrEntry
;
1083 IopInitializeBuiltinDriver(LdrEntry
);
1086 NextEntry
= NextEntry
->Flink
;
1090 /* In old ROS, the loader list became empty after this point. Simulate. */
1091 InitializeListHead(&KeLoaderBlock
->LoadOrderListHead
);
1097 IopInitializeSystemDrivers(VOID
)
1099 PUNICODE_STRING
*DriverList
, *SavedList
;
1101 /* No system drivers on the boot cd */
1102 if (KeLoaderBlock
->SetupLdrBlock
) return;
1104 /* Get the driver list */
1105 SavedList
= DriverList
= CmGetSystemDriverList();
1111 /* Load the driver */
1112 ZwLoadDriver(*DriverList
);
1114 /* Free the entry */
1115 RtlFreeUnicodeString(*DriverList
);
1116 ExFreePool(*DriverList
);
1119 InbvIndicateProgress();
1124 ExFreePool(SavedList
);
1130 * Unloads a device driver.
1134 * Name of the service to unload (registry key).
1137 * Whether to unload Plug & Plug or only legacy drivers. If this
1138 * parameter is set to FALSE, the routine will unload only legacy
1145 * Guard the whole function by SEH.
1149 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1151 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1152 UNICODE_STRING ImagePath
;
1153 UNICODE_STRING ServiceName
;
1154 UNICODE_STRING ObjectName
;
1155 PDRIVER_OBJECT DriverObject
;
1156 PDEVICE_OBJECT DeviceObject
;
1157 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1158 LOAD_UNLOAD_PARAMS LoadParams
;
1161 BOOLEAN SafeToUnload
= TRUE
;
1163 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1168 * Get the service name from the registry key name
1171 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1173 Start
= DriverServiceName
->Buffer
;
1177 RtlInitUnicodeString(&ServiceName
, Start
);
1180 * Construct the driver object name
1183 ObjectName
.Length
= ((USHORT
)wcslen(Start
) + 8) * sizeof(WCHAR
);
1184 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1185 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1186 if (!ObjectName
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1187 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1188 memcpy(ObjectName
.Buffer
+ 8, Start
, ObjectName
.Length
- 8 * sizeof(WCHAR
));
1189 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1192 * Find the driver object
1194 Status
= ObReferenceObjectByName(&ObjectName
,
1201 (PVOID
*)&DriverObject
);
1203 if (!NT_SUCCESS(Status
))
1205 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName
);
1206 ExFreePool(ObjectName
.Buffer
);
1211 * Free the buffer for driver object name
1213 ExFreePool(ObjectName
.Buffer
);
1215 /* Check that driver is not already unloading */
1216 if (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
)
1218 DPRINT1("Driver deletion pending\n");
1219 ObDereferenceObject(DriverObject
);
1220 return STATUS_DELETE_PENDING
;
1224 * Get path of service...
1227 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1229 RtlInitUnicodeString(&ImagePath
, NULL
);
1231 QueryTable
[0].Name
= L
"ImagePath";
1232 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1233 QueryTable
[0].EntryContext
= &ImagePath
;
1235 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1236 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1238 if (!NT_SUCCESS(Status
))
1240 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1241 ObDereferenceObject(DriverObject
);
1246 * Normalize the image path for all later processing.
1249 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1251 if (!NT_SUCCESS(Status
))
1253 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1254 ObDereferenceObject(DriverObject
);
1259 * Free the service path
1262 ExFreePool(ImagePath
.Buffer
);
1265 * Unload the module and release the references to the device object
1268 /* Call the load/unload routine, depending on current process */
1269 if (DriverObject
->DriverUnload
&& DriverObject
->DriverSection
&&
1270 (UnloadPnpDrivers
|| (DriverObject
->Flags
& DRVO_LEGACY_DRIVER
)))
1272 /* Loop through each device object of the driver
1273 and set DOE_UNLOAD_PENDING flag */
1274 DeviceObject
= DriverObject
->DeviceObject
;
1275 while (DeviceObject
)
1277 /* Set the unload pending flag for the device */
1278 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1279 DeviceExtension
->ExtensionFlags
|= DOE_UNLOAD_PENDING
;
1281 /* Make sure there are no attached devices or no reference counts */
1282 if ((DeviceObject
->ReferenceCount
) || (DeviceObject
->AttachedDevice
))
1284 /* Not safe to unload */
1285 DPRINT1("Drivers device object is referenced or has attached devices\n");
1287 SafeToUnload
= FALSE
;
1290 DeviceObject
= DeviceObject
->NextDevice
;
1293 /* If not safe to unload, then return success */
1296 ObDereferenceObject(DriverObject
);
1297 return STATUS_SUCCESS
;
1300 DPRINT1("Unloading driver '%wZ' (manual)\n", &DriverObject
->DriverName
);
1302 /* Set the unload invoked flag */
1303 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
1305 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1307 /* Just call right away */
1308 (*DriverObject
->DriverUnload
)(DriverObject
);
1312 /* Load/Unload must be called from system process */
1314 /* Prepare parameters block */
1315 LoadParams
.DriverObject
= DriverObject
;
1316 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1318 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1319 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1320 (PVOID
)&LoadParams
);
1323 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1325 /* And wait when it completes */
1326 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1330 /* Mark the driver object temporary, so it could be deleted later */
1331 ObMakeTemporaryObject(DriverObject
);
1333 /* Dereference it 2 times */
1334 ObDereferenceObject(DriverObject
);
1335 ObDereferenceObject(DriverObject
);
1337 return STATUS_SUCCESS
;
1341 DPRINT1("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject
->DriverName
);
1343 /* Dereference one time (refd inside this function) */
1344 ObDereferenceObject(DriverObject
);
1346 /* Return unloading failure */
1347 return STATUS_INVALID_DEVICE_REQUEST
;
1353 IopReinitializeDrivers(VOID
)
1355 PDRIVER_REINIT_ITEM ReinitItem
;
1358 /* Get the first entry and start looping */
1359 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1360 &DriverReinitListLock
);
1364 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1366 /* Increment reinitialization counter */
1367 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1369 /* Remove the device object flag */
1370 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1372 /* Call the routine */
1373 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1374 ReinitItem
->Context
,
1375 ReinitItem
->DriverObject
->
1376 DriverExtension
->Count
);
1378 /* Free the entry */
1381 /* Move to the next one */
1382 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1383 &DriverReinitListLock
);
1389 IopReinitializeBootDrivers(VOID
)
1391 PDRIVER_REINIT_ITEM ReinitItem
;
1394 /* Get the first entry and start looping */
1395 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1396 &DriverBootReinitListLock
);
1400 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1402 /* Increment reinitialization counter */
1403 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1405 /* Remove the device object flag */
1406 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1408 /* Call the routine */
1409 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1410 ReinitItem
->Context
,
1411 ReinitItem
->DriverObject
->
1412 DriverExtension
->Count
);
1414 /* Free the entry */
1417 /* Move to the next one */
1418 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1419 &DriverBootReinitListLock
);
1425 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1426 IN PDRIVER_INITIALIZE InitializationFunction
,
1427 IN PUNICODE_STRING RegistryPath
,
1428 PLDR_DATA_TABLE_ENTRY ModuleObject
,
1429 OUT PDRIVER_OBJECT
*pDriverObject
)
1431 WCHAR NameBuffer
[100];
1433 UNICODE_STRING LocalDriverName
;
1435 OBJECT_ATTRIBUTES ObjectAttributes
;
1437 PDRIVER_OBJECT DriverObject
;
1438 UNICODE_STRING ServiceKeyName
;
1440 ULONG i
, RetryCount
= 0;
1443 /* First, create a unique name for the driver if we don't have one */
1446 /* Create a random name and set up the string*/
1447 NameLength
= (USHORT
)swprintf(NameBuffer
,
1450 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1451 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1452 LocalDriverName
.Buffer
= NameBuffer
;
1456 /* So we can avoid another code path, use a local var */
1457 LocalDriverName
= *DriverName
;
1460 /* Initialize the Attributes */
1461 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1462 InitializeObjectAttributes(&ObjectAttributes
,
1464 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1468 /* Create the Object */
1469 Status
= ObCreateObject(KernelMode
,
1477 (PVOID
*)&DriverObject
);
1478 if (!NT_SUCCESS(Status
)) return Status
;
1480 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1482 /* Set up the Object */
1483 RtlZeroMemory(DriverObject
, ObjectSize
);
1484 DriverObject
->Type
= IO_TYPE_DRIVER
;
1485 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1486 DriverObject
->Flags
= DRVO_LEGACY_DRIVER
;
1487 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1488 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1489 DriverObject
->DriverInit
= InitializationFunction
;
1490 DriverObject
->DriverSection
= ModuleObject
;
1491 /* Loop all Major Functions */
1492 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1494 /* Invalidate each function */
1495 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1498 /* Set up the service key name buffer */
1499 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1500 LocalDriverName
.Length
+
1503 if (!ServiceKeyName
.Buffer
)
1506 ObMakeTemporaryObject(DriverObject
);
1507 ObDereferenceObject(DriverObject
);
1508 return STATUS_INSUFFICIENT_RESOURCES
;
1511 /* Fill out the key data and copy the buffer */
1512 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1513 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1514 RtlCopyMemory(ServiceKeyName
.Buffer
,
1515 LocalDriverName
.Buffer
,
1516 LocalDriverName
.Length
);
1518 /* Null-terminate it and set it */
1519 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1520 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1522 /* Also store it in the Driver Object. This is a bit of a hack. */
1523 RtlCopyMemory(&DriverObject
->DriverName
,
1525 sizeof(UNICODE_STRING
));
1527 /* Add the Object and get its handle */
1528 Status
= ObInsertObject(DriverObject
,
1535 /* Eliminate small possibility when this function is called more than
1536 once in a row, and KeTickCount doesn't get enough time to change */
1537 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1543 if (!NT_SUCCESS(Status
)) return Status
;
1545 /* Now reference it */
1546 Status
= ObReferenceObjectByHandle(hDriver
,
1550 (PVOID
*)&DriverObject
,
1553 /* Close the extra handle */
1556 if (!NT_SUCCESS(Status
))
1559 ObMakeTemporaryObject(DriverObject
);
1560 ObDereferenceObject(DriverObject
);
1564 DriverObject
->HardwareDatabase
= &IopHardwareDatabaseKey
;
1565 DriverObject
->DriverStart
= ModuleObject
? ModuleObject
->DllBase
: 0;
1566 DriverObject
->DriverSize
= ModuleObject
? ModuleObject
->SizeOfImage
: 0;
1568 /* Finally, call its init function */
1569 DPRINT("RegistryKey: %wZ\n", RegistryPath
);
1570 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction
);
1571 Status
= (*InitializationFunction
)(DriverObject
, RegistryPath
);
1572 if (!NT_SUCCESS(Status
))
1574 /* If it didn't work, then kill the object */
1575 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName
, Status
);
1576 DriverObject
->DriverSection
= NULL
;
1577 ObMakeTemporaryObject(DriverObject
);
1578 ObDereferenceObject(DriverObject
);
1583 /* Returns to caller the object */
1584 *pDriverObject
= DriverObject
;
1587 /* We're going to say if we don't have any DOs from DriverEntry, then we're not legacy.
1588 * Other parts of the I/O manager depend on this behavior */
1589 if (!DriverObject
->DeviceObject
) DriverObject
->Flags
&= ~DRVO_LEGACY_DRIVER
;
1591 /* Loop all Major Functions */
1592 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1595 * Make sure the driver didn't set any dispatch entry point to NULL!
1596 * Doing so is illegal; drivers shouldn't touch entry points they
1600 /* Check if it did so anyway */
1601 if (!DriverObject
->MajorFunction
[i
])
1603 /* Print a warning in the debug log */
1604 DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%d] to NULL!\n",
1605 &DriverObject
->DriverName
, i
);
1608 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1612 /* Return the Status */
1616 /* PUBLIC FUNCTIONS ***********************************************************/
1623 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1624 IN PDRIVER_INITIALIZE InitializationFunction
)
1626 PDRIVER_OBJECT DriverObject
;
1627 return IopCreateDriver(DriverName
, InitializationFunction
, NULL
, NULL
, &DriverObject
);
1635 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1637 /* Simply dereference the Object */
1638 ObDereferenceObject(DriverObject
);
1646 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1647 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1650 PDRIVER_REINIT_ITEM ReinitItem
;
1652 /* Allocate the entry */
1653 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1654 sizeof(DRIVER_REINIT_ITEM
),
1656 if (!ReinitItem
) return;
1659 ReinitItem
->DriverObject
= DriverObject
;
1660 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1661 ReinitItem
->Context
= Context
;
1663 /* Set the Driver Object flag and insert the entry into the list */
1664 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1665 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1666 &ReinitItem
->ItemEntry
,
1667 &DriverBootReinitListLock
);
1675 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1676 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1679 PDRIVER_REINIT_ITEM ReinitItem
;
1681 /* Allocate the entry */
1682 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1683 sizeof(DRIVER_REINIT_ITEM
),
1685 if (!ReinitItem
) return;
1688 ReinitItem
->DriverObject
= DriverObject
;
1689 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1690 ReinitItem
->Context
= Context
;
1692 /* Set the Driver Object flag and insert the entry into the list */
1693 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1694 ExInterlockedInsertTailList(&DriverReinitListHead
,
1695 &ReinitItem
->ItemEntry
,
1696 &DriverReinitListLock
);
1704 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1705 IN PVOID ClientIdentificationAddress
,
1706 IN ULONG DriverObjectExtensionSize
,
1707 OUT PVOID
*DriverObjectExtension
)
1710 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1711 BOOLEAN Inserted
= FALSE
;
1713 /* Assume failure */
1714 *DriverObjectExtension
= NULL
;
1716 /* Allocate the extension */
1717 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1718 sizeof(IO_CLIENT_EXTENSION
) +
1719 DriverObjectExtensionSize
,
1720 TAG_DRIVER_EXTENSION
);
1721 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1723 /* Clear the extension for teh caller */
1724 RtlZeroMemory(NewDriverExtension
,
1725 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1728 OldIrql
= KeRaiseIrqlToDpcLevel();
1730 /* Fill out the extension */
1731 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1733 /* Loop the current extensions */
1734 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1735 ClientDriverExtension
;
1736 while (DriverExtensions
)
1738 /* Check if the identifier matches */
1739 if (DriverExtensions
->ClientIdentificationAddress
==
1740 ClientIdentificationAddress
)
1742 /* We have a collision, break out */
1746 /* Go to the next one */
1747 DriverExtensions
= DriverExtensions
->NextExtension
;
1750 /* Check if we didn't collide */
1751 if (!DriverExtensions
)
1753 /* Link this one in */
1754 NewDriverExtension
->NextExtension
=
1755 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1756 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1761 /* Release the lock */
1762 KeLowerIrql(OldIrql
);
1764 /* Check if insertion failed */
1767 /* Free the entry and fail */
1768 ExFreePool(NewDriverExtension
);
1769 return STATUS_OBJECT_NAME_COLLISION
;
1772 /* Otherwise, return the pointer */
1773 *DriverObjectExtension
= NewDriverExtension
+ 1;
1774 return STATUS_SUCCESS
;
1782 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1783 IN PVOID ClientIdentificationAddress
)
1786 PIO_CLIENT_EXTENSION DriverExtensions
;
1789 OldIrql
= KeRaiseIrqlToDpcLevel();
1791 /* Loop the list until we find the right one */
1792 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1793 while (DriverExtensions
)
1795 /* Check for a match */
1796 if (DriverExtensions
->ClientIdentificationAddress
==
1797 ClientIdentificationAddress
)
1804 DriverExtensions
= DriverExtensions
->NextExtension
;
1808 KeLowerIrql(OldIrql
);
1810 /* Return nothing or the extension */
1811 if (!DriverExtensions
) return NULL
;
1812 return DriverExtensions
+ 1;
1816 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams
)
1818 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1819 UNICODE_STRING ImagePath
;
1820 UNICODE_STRING ServiceName
;
1823 PDEVICE_NODE DeviceNode
;
1824 PDRIVER_OBJECT DriverObject
;
1825 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1829 /* Check if it's an unload request */
1830 if (LoadParams
->DriverObject
)
1832 (*LoadParams
->DriverObject
->DriverUnload
)(LoadParams
->DriverObject
);
1834 /* Return success and signal the event */
1835 LoadParams
->Status
= STATUS_SUCCESS
;
1836 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1840 RtlInitUnicodeString(&ImagePath
, NULL
);
1843 * Get the service name from the registry key name.
1845 ASSERT(LoadParams
->ServiceName
->Length
>= sizeof(WCHAR
));
1847 ServiceName
= *LoadParams
->ServiceName
;
1848 cur
= LoadParams
->ServiceName
->Buffer
+
1849 (LoadParams
->ServiceName
->Length
/ sizeof(WCHAR
)) - 1;
1850 while (LoadParams
->ServiceName
->Buffer
!= cur
)
1854 ServiceName
.Buffer
= cur
+ 1;
1855 ServiceName
.Length
= LoadParams
->ServiceName
->Length
-
1856 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1857 (ULONG_PTR
)LoadParams
->ServiceName
->Buffer
);
1867 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1869 RtlInitUnicodeString(&ImagePath
, NULL
);
1871 QueryTable
[0].Name
= L
"Type";
1872 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1873 QueryTable
[0].EntryContext
= &Type
;
1875 QueryTable
[1].Name
= L
"ImagePath";
1876 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1877 QueryTable
[1].EntryContext
= &ImagePath
;
1879 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1880 LoadParams
->ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1882 if (!NT_SUCCESS(Status
))
1884 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1885 if (ImagePath
.Buffer
)
1886 ExFreePool(ImagePath
.Buffer
);
1887 LoadParams
->Status
= Status
;
1888 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1893 * Normalize the image path for all later processing.
1896 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1898 if (!NT_SUCCESS(Status
))
1900 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1901 LoadParams
->Status
= Status
;
1902 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1906 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1907 DPRINT("Type: %lx\n", Type
);
1909 /* Get existing DriverObject pointer (in case the driver has
1910 already been loaded and initialized) */
1911 Status
= IopGetDriverObject(
1914 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1915 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */));
1917 if (!NT_SUCCESS(Status
))
1920 * Load the driver module
1923 DPRINT("Loading module from %wZ\n", &ImagePath
);
1924 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, &BaseAddress
);
1926 if (!NT_SUCCESS(Status
))
1928 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1929 LoadParams
->Status
= Status
;
1930 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1935 * Initialize the driver module if it's loaded for the first time
1937 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1938 if (!NT_SUCCESS(Status
))
1940 DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1941 MmUnloadSystemImage(ModuleObject
);
1942 LoadParams
->Status
= Status
;
1943 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1947 IopDisplayLoadingMessage(&DeviceNode
->ServiceName
);
1949 Status
= IopInitializeDriverModule(DeviceNode
,
1951 &DeviceNode
->ServiceName
,
1952 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1953 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1955 if (!NT_SUCCESS(Status
))
1957 DPRINT1("IopInitializeDriver() failed (Status %lx)\n", Status
);
1958 MmUnloadSystemImage(ModuleObject
);
1959 IopFreeDeviceNode(DeviceNode
);
1960 LoadParams
->Status
= Status
;
1961 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1965 /* Initialize and start device */
1966 IopInitializeDevice(DeviceNode
, DriverObject
);
1967 Status
= IopStartDevice(DeviceNode
);
1971 DPRINT("DriverObject already exist in ObjectManager\n");
1972 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1974 /* IopGetDriverObject references the DriverObject, so dereference it */
1975 ObDereferenceObject(DriverObject
);
1978 /* Pass status to the caller and signal the event */
1979 LoadParams
->Status
= Status
;
1980 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1986 * Loads a device driver.
1990 * Name of the service to load (registry key).
1999 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
2001 UNICODE_STRING CapturedDriverServiceName
= { 0, 0, NULL
};
2002 KPROCESSOR_MODE PreviousMode
;
2003 LOAD_UNLOAD_PARAMS LoadParams
;
2008 PreviousMode
= KeGetPreviousMode();
2011 * Check security privileges
2014 /* FIXME: Uncomment when privileges will be correctly implemented. */
2016 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
2018 DPRINT("Privilege not held\n");
2019 return STATUS_PRIVILEGE_NOT_HELD
;
2023 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
2026 if (!NT_SUCCESS(Status
))
2031 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
2033 LoadParams
.ServiceName
= &CapturedDriverServiceName
;
2034 LoadParams
.DriverObject
= NULL
;
2035 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
2037 /* Call the load/unload routine, depending on current process */
2038 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
2040 /* Just call right away */
2041 IopLoadUnloadDriver(&LoadParams
);
2045 /* Load/Unload must be called from system process */
2046 ExInitializeWorkItem(&LoadParams
.WorkItem
,
2047 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
2048 (PVOID
)&LoadParams
);
2051 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
2053 /* And wait when it completes */
2054 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
2058 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
2061 return LoadParams
.Status
;
2067 * Unloads a legacy device driver.
2071 * Name of the service to unload (registry key).
2081 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
2083 return IopUnloadDriver(DriverServiceName
, FALSE
);