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 /* Get the extension and loop them */
62 DriverExtension
= IoGetDrvObjExtension(DriverObject
)->
63 ClientDriverExtension
;
64 while (DriverExtension
)
66 /* Get the next one */
67 NextDriverExtension
= DriverExtension
->NextExtension
;
68 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
71 DriverExtension
= NextDriverExtension
;
74 /* Check if the driver image is still loaded */
75 if (DriverObject
->DriverSection
)
78 MmUnloadSystemImage(DriverObject
->DriverSection
);
81 /* Check if it has a name */
82 if (DriverObject
->DriverName
.Buffer
)
85 ExFreePool(DriverObject
->DriverName
.Buffer
);
88 #if 0 /* See a bit of hack in IopCreateDriver */
89 /* Check if it has a service key name */
90 if (DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
)
93 ExFreePool(DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
);
100 PDRIVER_OBJECT
*DriverObject
,
101 PUNICODE_STRING ServiceName
,
104 PDRIVER_OBJECT Object
;
105 WCHAR NameBuffer
[MAX_PATH
];
106 UNICODE_STRING DriverName
;
109 DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
110 DriverObject
, ServiceName
, FileSystem
);
112 *DriverObject
= NULL
;
114 /* Create ModuleName string */
115 if (ServiceName
== NULL
|| ServiceName
->Buffer
== NULL
)
116 /* We don't know which DriverObject we have to open */
117 return STATUS_INVALID_PARAMETER_2
;
119 DriverName
.Buffer
= NameBuffer
;
120 DriverName
.Length
= 0;
121 DriverName
.MaximumLength
= sizeof(NameBuffer
);
123 if (FileSystem
== TRUE
)
124 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
126 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
127 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
129 DPRINT("Driver name: '%wZ'\n", &DriverName
);
131 /* Open driver object */
132 Status
= ObReferenceObjectByName(
134 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, /* Attributes */
135 NULL
, /* PassedAccessState */
136 0, /* DesiredAccess */
139 NULL
, /* ParseContext */
142 if (!NT_SUCCESS(Status
))
144 DPRINT("Failed to reference driver object, status=0x%08x\n", Status
);
148 *DriverObject
= Object
;
150 DPRINT("Driver Object: %p\n", Object
);
152 return STATUS_SUCCESS
;
157 * TRUE if String2 contains String1 as a suffix.
161 IopSuffixUnicodeString(
162 IN PCUNICODE_STRING String1
,
163 IN PCUNICODE_STRING String2
)
169 if (String2
->Length
< String1
->Length
)
172 Length
= String1
->Length
/ 2;
173 pc1
= String1
->Buffer
;
174 pc2
= &String2
->Buffer
[String2
->Length
/ sizeof(WCHAR
) - Length
];
180 if( *pc1
++ != *pc2
++ )
189 * IopDisplayLoadingMessage
191 * Display 'Loading XXX...' message.
197 IopDisplayLoadingMessage(PUNICODE_STRING ServiceName
)
199 CHAR TextBuffer
[256];
200 UNICODE_STRING DotSys
= RTL_CONSTANT_STRING(L
".SYS");
202 if (ExpInTextModeSetup
) return;
203 if (!KeLoaderBlock
) return;
204 RtlUpcaseUnicodeString(ServiceName
, ServiceName
, FALSE
);
205 snprintf(TextBuffer
, sizeof(TextBuffer
),
206 "%s%sSystem32\\Drivers\\%wZ%s\n",
207 KeLoaderBlock
->ArcBootDeviceName
,
208 KeLoaderBlock
->NtBootPathName
,
210 IopSuffixUnicodeString(&DotSys
, ServiceName
) ? "" : ".SYS");
211 HalDisplayString(TextBuffer
);
215 * IopNormalizeImagePath
217 * Normalize an image path to contain complete path.
221 * The input path and on exit the result path. ImagePath.Buffer
222 * must be allocated by ExAllocatePool on input. Caller is responsible
223 * for freeing the buffer when it's no longer needed.
226 * Name of the service that ImagePath belongs to.
232 * The input image path isn't freed on error.
236 IopNormalizeImagePath(
237 IN OUT PUNICODE_STRING ImagePath
,
238 IN PUNICODE_STRING ServiceName
)
240 UNICODE_STRING InputImagePath
;
245 sizeof(UNICODE_STRING
));
247 if (InputImagePath
.Length
== 0)
249 ImagePath
->Length
= 0;
250 ImagePath
->MaximumLength
=
251 (33 * sizeof(WCHAR
)) + ServiceName
->Length
+ sizeof(UNICODE_NULL
);
252 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
253 if (ImagePath
->Buffer
== NULL
)
254 return STATUS_NO_MEMORY
;
256 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\system32\\drivers\\");
257 RtlAppendUnicodeStringToString(ImagePath
, ServiceName
);
258 RtlAppendUnicodeToString(ImagePath
, L
".sys");
260 if (InputImagePath
.Buffer
[0] != L
'\\')
262 ImagePath
->Length
= 0;
263 ImagePath
->MaximumLength
=
264 12 * sizeof(WCHAR
) + InputImagePath
.Length
+ sizeof(UNICODE_NULL
);
265 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
266 if (ImagePath
->Buffer
== NULL
)
267 return STATUS_NO_MEMORY
;
269 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\");
270 RtlAppendUnicodeStringToString(ImagePath
, &InputImagePath
);
272 /* Free caller's string */
273 ExFreePoolWithTag(InputImagePath
.Buffer
, TAG_RTLREGISTRY
);
276 return STATUS_SUCCESS
;
280 * IopLoadServiceModule
282 * Load a module specified by registry settings for service.
286 * Name of the service to load.
293 IopLoadServiceModule(
294 IN PUNICODE_STRING ServiceName
,
295 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
297 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
299 UNICODE_STRING ServiceImagePath
, CCSName
;
301 HANDLE CCSKey
, ServiceKey
;
304 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
306 /* FIXME: This check may be removed once the bug is fixed */
307 if (ServiceName
->Buffer
== NULL
)
309 DPRINT1("If you see this, please report to Fireball or hpoussin!\n");
310 return STATUS_UNSUCCESSFUL
;
313 if (ExpInTextModeSetup
)
315 /* We have no registry, but luckily we know where all the drivers are */
317 /* ServiceStart < 4 is all that matters */
320 /* IopNormalizeImagePath will do all of the work for us if we give it an empty string */
321 ServiceImagePath
.Length
= ServiceImagePath
.MaximumLength
= 0;
322 ServiceImagePath
.Buffer
= NULL
;
326 /* Open CurrentControlSet */
327 RtlInitUnicodeString(&CCSName
,
328 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
329 Status
= IopOpenRegistryKeyEx(&CCSKey
, NULL
, &CCSName
, KEY_READ
);
330 if (!NT_SUCCESS(Status
))
332 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
336 /* Open service key */
337 Status
= IopOpenRegistryKeyEx(&ServiceKey
, CCSKey
, ServiceName
, KEY_READ
);
338 if (!NT_SUCCESS(Status
))
340 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
346 * Get information about the service.
349 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
351 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
353 QueryTable
[0].Name
= L
"Start";
354 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
355 QueryTable
[0].EntryContext
= &ServiceStart
;
357 QueryTable
[1].Name
= L
"ImagePath";
358 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
359 QueryTable
[1].EntryContext
= &ServiceImagePath
;
361 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
362 (PWSTR
)ServiceKey
, QueryTable
, NULL
, NULL
);
367 if (!NT_SUCCESS(Status
))
369 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
375 * Normalize the image path for all later processing.
378 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
380 if (!NT_SUCCESS(Status
))
382 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
387 * Case for disabled drivers
390 if (ServiceStart
>= 4)
392 /* FIXME: Check if it is the right status code */
393 Status
= STATUS_PLUGPLAY_NO_DEVICE
;
397 DPRINT("Loading module\n");
398 Status
= MmLoadSystemImage(&ServiceImagePath
, NULL
, NULL
, 0, (PVOID
)ModuleObject
, &BaseAddress
);
401 ExFreePool(ServiceImagePath
.Buffer
);
404 * Now check if the module was loaded successfully.
407 if (!NT_SUCCESS(Status
))
409 DPRINT("Module loading failed (Status %x)\n", Status
);
412 DPRINT("Module loading (Status %x)\n", Status
);
418 * IopInitializeDriverModule
420 * Initalize a loaded driver.
424 * Pointer to device node.
427 * Module object representing the driver. It can be retrieve by
428 * IopLoadServiceModule.
431 * Name of the service (as in registry).
434 * Set to TRUE for file system drivers.
437 * On successful return this contains the driver object representing
442 IopInitializeDriverModule(
443 IN PDEVICE_NODE DeviceNode
,
444 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
445 IN PUNICODE_STRING ServiceName
,
446 IN BOOLEAN FileSystemDriver
,
447 OUT PDRIVER_OBJECT
*DriverObject
)
449 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
450 WCHAR NameBuffer
[MAX_PATH
];
451 UNICODE_STRING DriverName
;
452 UNICODE_STRING RegistryKey
;
453 PDRIVER_INITIALIZE DriverEntry
;
454 PDRIVER_OBJECT Driver
;
457 DriverEntry
= ModuleObject
->EntryPoint
;
459 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
461 RegistryKey
.Length
= 0;
462 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
463 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
464 if (RegistryKey
.Buffer
== NULL
)
466 return STATUS_INSUFFICIENT_RESOURCES
;
468 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
469 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
473 RtlInitUnicodeString(&RegistryKey
, NULL
);
476 /* Create ModuleName string */
477 if (ServiceName
&& ServiceName
->Length
> 0)
479 if (FileSystemDriver
== TRUE
)
480 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
482 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
484 RtlInitUnicodeString(&DriverName
, NameBuffer
);
485 DriverName
.MaximumLength
= sizeof(NameBuffer
);
487 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
489 DPRINT("Driver name: '%wZ'\n", &DriverName
);
492 DriverName
.Length
= 0;
494 Status
= IopCreateDriver(
495 DriverName
.Length
> 0 ? &DriverName
: NULL
,
500 RtlFreeUnicodeString(&RegistryKey
);
502 *DriverObject
= Driver
;
503 if (!NT_SUCCESS(Status
))
505 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status
);
509 /* Set the driver as initialized */
510 IopReadyDeviceObjects(Driver
);
512 if (PnpSystemInit
) IopReinitializeDrivers();
514 return STATUS_SUCCESS
;
518 * IopAttachFilterDriversCallback
520 * Internal routine used by IopAttachFilterDrivers.
524 IopAttachFilterDriversCallback(
532 PDEVICE_NODE DeviceNode
= Context
;
533 UNICODE_STRING ServiceName
;
535 PLDR_DATA_TABLE_ENTRY ModuleObject
;
536 PDRIVER_OBJECT DriverObject
;
539 for (Filters
= ValueData
;
540 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
542 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
544 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
545 ServiceName
.Buffer
= Filters
;
546 ServiceName
.MaximumLength
=
547 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
549 /* Load and initialize the filter driver */
550 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
551 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
553 if (!NT_SUCCESS(Status
))
556 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
557 FALSE
, &DriverObject
);
558 if (!NT_SUCCESS(Status
))
563 /* get existing DriverObject pointer */
564 Status
= IopGetDriverObject(
568 if (!NT_SUCCESS(Status
))
570 DPRINT1("IopGetDriverObject() returned status 0x%08x!\n", Status
);
575 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
576 if (!NT_SUCCESS(Status
))
580 return STATUS_SUCCESS
;
584 * IopAttachFilterDrivers
586 * Load filter drivers for specified device node.
590 * Set to TRUE for loading lower level filters or FALSE for upper
595 IopAttachFilterDrivers(
596 PDEVICE_NODE DeviceNode
,
599 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = { { NULL
, 0, NULL
, NULL
, 0, NULL
, 0 }, };
600 UNICODE_STRING Class
;
601 WCHAR ClassBuffer
[40];
602 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
603 HANDLE EnumRootKey
, SubKey
;
606 /* Open enumeration root key */
607 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
608 &EnumRoot
, KEY_READ
);
609 if (!NT_SUCCESS(Status
))
611 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
616 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
617 &DeviceNode
->InstancePath
, KEY_READ
);
618 if (!NT_SUCCESS(Status
))
620 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
621 ZwClose(EnumRootKey
);
626 * First load the device filters
628 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
630 QueryTable
[0].Name
= L
"LowerFilters";
632 QueryTable
[0].Name
= L
"UpperFilters";
633 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
635 RtlQueryRegistryValues(
643 * Now get the class GUID
646 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
647 Class
.Buffer
= ClassBuffer
;
648 QueryTable
[0].QueryRoutine
= NULL
;
649 QueryTable
[0].Name
= L
"ClassGUID";
650 QueryTable
[0].EntryContext
= &Class
;
651 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
653 Status
= RtlQueryRegistryValues(
662 ZwClose(EnumRootKey
);
665 * Load the class filter driver
667 if (NT_SUCCESS(Status
))
669 UNICODE_STRING ControlClass
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
671 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
672 &ControlClass
, KEY_READ
);
673 if (!NT_SUCCESS(Status
))
675 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
680 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
682 if (!NT_SUCCESS(Status
))
684 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
685 ZwClose(EnumRootKey
);
689 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
691 QueryTable
[0].Name
= L
"LowerFilters";
693 QueryTable
[0].Name
= L
"UpperFilters";
694 QueryTable
[0].EntryContext
= NULL
;
695 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
697 RtlQueryRegistryValues(
706 ZwClose(EnumRootKey
);
709 return STATUS_SUCCESS
;
714 MiResolveImageReferences(IN PVOID ImageBase
,
715 IN PUNICODE_STRING ImageFileDirectory
,
716 IN PUNICODE_STRING NamePrefix OPTIONAL
,
717 OUT PCHAR
*MissingApi
,
718 OUT PWCHAR
*MissingDriver
,
719 OUT PLOAD_IMPORTS
*LoadImports
);
722 // Used for images already loaded (boot drivers)
727 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry
,
728 PUNICODE_STRING FileName
,
729 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
732 UNICODE_STRING BaseName
, BaseDirectory
;
733 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
734 PCHAR MissingApiName
, Buffer
;
735 PWCHAR MissingDriverName
;
736 PVOID DriverBase
= LdrEntry
->DllBase
;
738 /* Allocate a buffer we'll use for names */
739 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
743 return STATUS_INSUFFICIENT_RESOURCES
;
746 /* Check for a separator */
747 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
752 /* Loop the path until we get to the base name */
753 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
754 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
757 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
758 BaseLength
*= sizeof(WCHAR
);
760 /* Setup the string */
761 BaseName
.Length
= (USHORT
)BaseLength
;
766 /* Otherwise, we already have a base name */
767 BaseName
.Length
= FileName
->Length
;
768 BaseName
.Buffer
= FileName
->Buffer
;
771 /* Setup the maximum length */
772 BaseName
.MaximumLength
= BaseName
.Length
;
774 /* Now compute the base directory */
775 BaseDirectory
= *FileName
;
776 BaseDirectory
.Length
-= BaseName
.Length
;
777 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
779 /* Resolve imports */
780 MissingApiName
= Buffer
;
781 Status
= MiResolveImageReferences(DriverBase
,
787 if (!NT_SUCCESS(Status
)) return Status
;
790 *ModuleObject
= LdrEntry
;
791 return STATUS_SUCCESS
;
795 * IopInitializeBuiltinDriver
797 * Initialize a driver that is already loaded in memory.
803 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
805 PDEVICE_NODE DeviceNode
;
806 PDRIVER_OBJECT DriverObject
;
808 PWCHAR FileNameWithoutPath
;
809 LPWSTR FileExtension
;
810 PUNICODE_STRING ModuleName
= &LdrEntry
->BaseDllName
;
811 UNICODE_STRING ServiceName
;
814 * Display 'Loading XXX...' message
816 IopDisplayLoadingMessage(ModuleName
);
817 InbvIndicateProgress();
820 * Generate filename without path (not needed by freeldr)
822 FileNameWithoutPath
= wcsrchr(ModuleName
->Buffer
, L
'\\');
823 if (FileNameWithoutPath
== NULL
)
825 FileNameWithoutPath
= ModuleName
->Buffer
;
829 FileNameWithoutPath
++;
833 * Strip the file extension from ServiceName
835 RtlCreateUnicodeString(&ServiceName
, FileNameWithoutPath
);
836 FileExtension
= wcsrchr(ServiceName
.Buffer
, '.');
837 if (FileExtension
!= NULL
)
839 ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
840 FileExtension
[0] = 0;
844 * Determine the right device object
846 /* Use IopRootDeviceNode for now */
847 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
848 if (!NT_SUCCESS(Status
))
850 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
853 DeviceNode
->ServiceName
= ServiceName
;
856 * Initialize the driver
858 Status
= IopInitializeDriverModule(DeviceNode
, LdrEntry
,
859 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
861 if (!NT_SUCCESS(Status
))
863 IopFreeDeviceNode(DeviceNode
);
867 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
868 if (NT_SUCCESS(Status
))
870 Status
= IopStartDevice(DeviceNode
);
877 * IopInitializeBootDrivers
879 * Initialize boot drivers and free memory for boot files.
890 IopInitializeBootDrivers(VOID
)
892 PLIST_ENTRY ListHead
, NextEntry
, NextEntry2
;
893 PLDR_DATA_TABLE_ENTRY LdrEntry
;
894 PDEVICE_NODE DeviceNode
;
895 PDRIVER_OBJECT DriverObject
;
896 LDR_DATA_TABLE_ENTRY ModuleObject
;
898 UNICODE_STRING DriverName
;
900 PDRIVER_INFORMATION DriverInfo
, DriverInfoTag
;
902 PBOOT_DRIVER_LIST_ENTRY BootEntry
;
903 DPRINT("IopInitializeBootDrivers()\n");
905 /* Use IopRootDeviceNode for now */
906 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, NULL
, &DeviceNode
);
907 if (!NT_SUCCESS(Status
)) return;
909 /* Setup the module object for the RAW FS Driver */
910 ModuleObject
.DllBase
= NULL
;
911 ModuleObject
.SizeOfImage
= 0;
912 ModuleObject
.EntryPoint
= RawFsDriverEntry
;
913 RtlInitUnicodeString(&DriverName
, L
"RAW");
916 Status
= IopInitializeDriverModule(DeviceNode
,
921 if (!NT_SUCCESS(Status
))
924 IopFreeDeviceNode(DeviceNode
);
928 /* Now initialize the associated device */
929 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
930 if (!NT_SUCCESS(Status
))
933 IopFreeDeviceNode(DeviceNode
);
938 Status
= IopStartDevice(DeviceNode
);
939 if (!NT_SUCCESS(Status
))
942 IopFreeDeviceNode(DeviceNode
);
946 /* Get highest group order index */
947 IopGroupIndex
= PpInitGetGroupOrderIndex(NULL
);
948 if (IopGroupIndex
== 0xFFFF) ASSERT(FALSE
);
950 /* Allocate the group table */
951 IopGroupTable
= ExAllocatePoolWithTag(PagedPool
,
952 IopGroupIndex
* sizeof(LIST_ENTRY
),
954 if (IopGroupTable
== NULL
) ASSERT(FALSE
);
956 /* Initialize the group table lists */
957 for (i
= 0; i
< IopGroupIndex
; i
++) InitializeListHead(&IopGroupTable
[i
]);
959 /* Loop the boot modules */
960 ListHead
= &KeLoaderBlock
->LoadOrderListHead
;
961 NextEntry
= ListHead
->Flink
;
962 while (ListHead
!= NextEntry
)
965 LdrEntry
= CONTAINING_RECORD(NextEntry
,
966 LDR_DATA_TABLE_ENTRY
,
969 /* Check if the DLL needs to be initialized */
970 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
972 /* Call its entrypoint */
973 MmCallDllInitialize(LdrEntry
, NULL
);
976 /* Go to the next driver */
977 NextEntry
= NextEntry
->Flink
;
980 /* Loop the boot drivers */
981 ListHead
= &KeLoaderBlock
->BootDriverListHead
;
982 NextEntry
= ListHead
->Flink
;
983 while (ListHead
!= NextEntry
)
986 BootEntry
= CONTAINING_RECORD(NextEntry
,
987 BOOT_DRIVER_LIST_ENTRY
,
990 /* Get the driver loader entry */
991 LdrEntry
= BootEntry
->LdrEntry
;
993 /* Allocate our internal accounting structure */
994 DriverInfo
= ExAllocatePoolWithTag(PagedPool
,
995 sizeof(DRIVER_INFORMATION
),
999 /* Zero it and initialize it */
1000 RtlZeroMemory(DriverInfo
, sizeof(DRIVER_INFORMATION
));
1001 InitializeListHead(&DriverInfo
->Link
);
1002 DriverInfo
->DataTableEntry
= BootEntry
;
1004 /* Open the registry key */
1005 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
1007 &BootEntry
->RegistryPath
,
1009 if ((NT_SUCCESS(Status
)) || /* ReactOS HACK for SETUPLDR */
1010 ((KeLoaderBlock
->SetupLdrBlock
) && ((KeyHandle
= (PVOID
)1)))) // yes, it's an assignment!
1012 /* Save the handle */
1013 DriverInfo
->ServiceHandle
= KeyHandle
;
1015 /* Get the group oder index */
1016 Index
= PpInitGetGroupOrderIndex(KeyHandle
);
1018 /* Get the tag position */
1019 DriverInfo
->TagPosition
= PipGetDriverTagPriority(KeyHandle
);
1021 /* Insert it into the list, at the right place */
1022 ASSERT(Index
< IopGroupIndex
);
1023 NextEntry2
= IopGroupTable
[Index
].Flink
;
1024 while (NextEntry2
!= &IopGroupTable
[Index
])
1026 /* Get the driver info */
1027 DriverInfoTag
= CONTAINING_RECORD(NextEntry2
,
1031 /* Check if we found the right tag position */
1032 if (DriverInfoTag
->TagPosition
> DriverInfo
->TagPosition
)
1039 NextEntry2
= NextEntry2
->Flink
;
1042 /* Insert us right before the next entry */
1043 NextEntry2
= NextEntry2
->Blink
;
1044 InsertHeadList(NextEntry2
, &DriverInfo
->Link
);
1048 /* Go to the next driver */
1049 NextEntry
= NextEntry
->Flink
;
1052 /* Loop each group index */
1053 for (i
= 0; i
< IopGroupIndex
; i
++)
1055 /* Loop each group table */
1056 NextEntry
= IopGroupTable
[i
].Flink
;
1057 while (NextEntry
!= &IopGroupTable
[i
])
1060 DriverInfo
= CONTAINING_RECORD(NextEntry
,
1064 /* Get the driver loader entry */
1065 LdrEntry
= DriverInfo
->DataTableEntry
->LdrEntry
;
1068 IopInitializeBuiltinDriver(LdrEntry
);
1071 NextEntry
= NextEntry
->Flink
;
1075 /* In old ROS, the loader list became empty after this point. Simulate. */
1076 InitializeListHead(&KeLoaderBlock
->LoadOrderListHead
);
1082 IopInitializeSystemDrivers(VOID
)
1084 PUNICODE_STRING
*DriverList
, *SavedList
;
1086 /* No system drivers on the boot cd */
1087 if (KeLoaderBlock
->SetupLdrBlock
) return;
1089 /* Get the driver list */
1090 SavedList
= DriverList
= CmGetSystemDriverList();
1096 /* Load the driver */
1097 ZwLoadDriver(*DriverList
);
1099 /* Free the entry */
1100 RtlFreeUnicodeString(*DriverList
);
1101 ExFreePool(*DriverList
);
1104 InbvIndicateProgress();
1109 ExFreePool(SavedList
);
1115 * Unloads a device driver.
1119 * Name of the service to unload (registry key).
1122 * Whether to unload Plug & Plug or only legacy drivers. If this
1123 * parameter is set to FALSE, the routine will unload only legacy
1130 * Guard the whole function by SEH.
1134 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1136 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1137 UNICODE_STRING ImagePath
;
1138 UNICODE_STRING ServiceName
;
1139 UNICODE_STRING ObjectName
;
1140 PDRIVER_OBJECT DriverObject
;
1141 PDEVICE_OBJECT DeviceObject
;
1142 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1143 LOAD_UNLOAD_PARAMS LoadParams
;
1146 BOOLEAN SafeToUnload
= TRUE
;
1148 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1153 * Get the service name from the registry key name
1156 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1158 Start
= DriverServiceName
->Buffer
;
1162 RtlInitUnicodeString(&ServiceName
, Start
);
1165 * Construct the driver object name
1168 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1169 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1170 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1171 if (!ObjectName
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1172 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1173 memcpy(ObjectName
.Buffer
+ 8, Start
, ObjectName
.Length
- 8 * sizeof(WCHAR
));
1174 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1177 * Find the driver object
1179 Status
= ObReferenceObjectByName(&ObjectName
,
1186 (PVOID
*)&DriverObject
);
1188 if (!NT_SUCCESS(Status
))
1190 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName
);
1191 ExFreePool(ObjectName
.Buffer
);
1196 * Free the buffer for driver object name
1198 ExFreePool(ObjectName
.Buffer
);
1200 /* Check that driver is not already unloading */
1201 if (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
)
1203 DPRINT1("Driver deletion pending\n");
1204 ObDereferenceObject(DriverObject
);
1205 return STATUS_DELETE_PENDING
;
1209 * Get path of service...
1212 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1214 RtlInitUnicodeString(&ImagePath
, NULL
);
1216 QueryTable
[0].Name
= L
"ImagePath";
1217 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1218 QueryTable
[0].EntryContext
= &ImagePath
;
1220 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1221 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1223 if (!NT_SUCCESS(Status
))
1225 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1226 ObDereferenceObject(DriverObject
);
1231 * Normalize the image path for all later processing.
1234 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1236 if (!NT_SUCCESS(Status
))
1238 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1239 ObDereferenceObject(DriverObject
);
1244 * Free the service path
1247 ExFreePool(ImagePath
.Buffer
);
1250 * Unload the module and release the references to the device object
1253 /* Call the load/unload routine, depending on current process */
1254 if (DriverObject
->DriverUnload
&& DriverObject
->DriverSection
)
1256 /* Loop through each device object of the driver
1257 and set DOE_UNLOAD_PENDING flag */
1258 DeviceObject
= DriverObject
->DeviceObject
;
1259 while (DeviceObject
)
1261 /* Set the unload pending flag for the device */
1262 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1263 DeviceExtension
->ExtensionFlags
|= DOE_UNLOAD_PENDING
;
1265 /* Make sure there are no attached devices or no reference counts */
1266 if ((DeviceObject
->ReferenceCount
) || (DeviceObject
->AttachedDevice
))
1268 /* Not safe to unload */
1269 DPRINT1("Drivers device object is referenced or has attached devices\n");
1271 SafeToUnload
= FALSE
;
1274 DeviceObject
= DeviceObject
->NextDevice
;
1277 /* If not safe to unload, then return success */
1280 ObDereferenceObject(DriverObject
);
1281 return STATUS_SUCCESS
;
1284 /* Set the unload invoked flag */
1285 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
1287 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1289 /* Just call right away */
1290 (*DriverObject
->DriverUnload
)(DriverObject
);
1294 /* Load/Unload must be called from system process */
1296 /* Prepare parameters block */
1297 LoadParams
.DriverObject
= DriverObject
;
1298 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1300 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1301 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1302 (PVOID
)&LoadParams
);
1305 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1307 /* And wait when it completes */
1308 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1312 /* Mark the driver object temporary, so it could be deleted later */
1313 ObMakeTemporaryObject(DriverObject
);
1315 /* Dereference it 2 times */
1316 ObDereferenceObject(DriverObject
);
1317 ObDereferenceObject(DriverObject
);
1319 return STATUS_SUCCESS
;
1323 /* Dereference one time (refd inside this function) */
1324 ObDereferenceObject(DriverObject
);
1326 /* Return unloading failure */
1327 return STATUS_INVALID_DEVICE_REQUEST
;
1333 IopReinitializeDrivers(VOID
)
1335 PDRIVER_REINIT_ITEM ReinitItem
;
1338 /* Get the first entry and start looping */
1339 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1340 &DriverReinitListLock
);
1344 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1346 /* Increment reinitialization counter */
1347 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1349 /* Remove the device object flag */
1350 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1352 /* Call the routine */
1353 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1354 ReinitItem
->Context
,
1355 ReinitItem
->DriverObject
->
1356 DriverExtension
->Count
);
1358 /* Free the entry */
1361 /* Move to the next one */
1362 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1363 &DriverReinitListLock
);
1369 IopReinitializeBootDrivers(VOID
)
1371 PDRIVER_REINIT_ITEM ReinitItem
;
1374 /* Get the first entry and start looping */
1375 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1376 &DriverBootReinitListLock
);
1380 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1382 /* Increment reinitialization counter */
1383 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1385 /* Remove the device object flag */
1386 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1388 /* Call the routine */
1389 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1390 ReinitItem
->Context
,
1391 ReinitItem
->DriverObject
->
1392 DriverExtension
->Count
);
1394 /* Free the entry */
1397 /* Move to the next one */
1398 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1399 &DriverBootReinitListLock
);
1405 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1406 IN PDRIVER_INITIALIZE InitializationFunction
,
1407 IN PUNICODE_STRING RegistryPath
,
1408 PLDR_DATA_TABLE_ENTRY ModuleObject
,
1409 OUT PDRIVER_OBJECT
*pDriverObject
)
1411 WCHAR NameBuffer
[100];
1413 UNICODE_STRING LocalDriverName
;
1415 OBJECT_ATTRIBUTES ObjectAttributes
;
1417 PDRIVER_OBJECT DriverObject
;
1418 UNICODE_STRING ServiceKeyName
;
1420 ULONG i
, RetryCount
= 0;
1423 /* First, create a unique name for the driver if we don't have one */
1426 /* Create a random name and set up the string*/
1427 NameLength
= (USHORT
)swprintf(NameBuffer
,
1430 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1431 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1432 LocalDriverName
.Buffer
= NameBuffer
;
1436 /* So we can avoid another code path, use a local var */
1437 LocalDriverName
= *DriverName
;
1440 /* Initialize the Attributes */
1441 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1442 InitializeObjectAttributes(&ObjectAttributes
,
1444 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1448 /* Create the Object */
1449 Status
= ObCreateObject(KernelMode
,
1457 (PVOID
*)&DriverObject
);
1458 if (!NT_SUCCESS(Status
)) return Status
;
1460 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1462 /* Set up the Object */
1463 RtlZeroMemory(DriverObject
, ObjectSize
);
1464 DriverObject
->Type
= IO_TYPE_DRIVER
;
1465 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1466 DriverObject
->Flags
= DRVO_LEGACY_DRIVER
;//DRVO_BUILTIN_DRIVER;
1467 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1468 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1469 DriverObject
->DriverInit
= InitializationFunction
;
1470 DriverObject
->DriverSection
= ModuleObject
;
1471 /* Loop all Major Functions */
1472 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1474 /* Invalidate each function */
1475 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1478 /* Set up the service key name buffer */
1479 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1480 LocalDriverName
.Length
+
1483 if (!ServiceKeyName
.Buffer
)
1486 ObMakeTemporaryObject(DriverObject
);
1487 ObDereferenceObject(DriverObject
);
1488 return STATUS_INSUFFICIENT_RESOURCES
;
1491 /* Fill out the key data and copy the buffer */
1492 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1493 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1494 RtlCopyMemory(ServiceKeyName
.Buffer
,
1495 LocalDriverName
.Buffer
,
1496 LocalDriverName
.Length
);
1498 /* Null-terminate it and set it */
1499 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1500 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1502 /* Also store it in the Driver Object. This is a bit of a hack. */
1503 RtlCopyMemory(&DriverObject
->DriverName
,
1505 sizeof(UNICODE_STRING
));
1507 /* Add the Object and get its handle */
1508 Status
= ObInsertObject(DriverObject
,
1515 /* Eliminate small possibility when this function is called more than
1516 once in a row, and KeTickCount doesn't get enough time to change */
1517 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1523 if (!NT_SUCCESS(Status
)) return Status
;
1525 /* Now reference it */
1526 Status
= ObReferenceObjectByHandle(hDriver
,
1530 (PVOID
*)&DriverObject
,
1532 if (!NT_SUCCESS(Status
))
1535 ObMakeTemporaryObject(DriverObject
);
1536 ObDereferenceObject(DriverObject
);
1540 /* Close the extra handle */
1543 DriverObject
->HardwareDatabase
= &IopHardwareDatabaseKey
;
1544 DriverObject
->DriverStart
= ModuleObject
? ModuleObject
->DllBase
: 0;
1545 DriverObject
->DriverSize
= ModuleObject
? ModuleObject
->SizeOfImage
: 0;
1547 /* Finally, call its init function */
1548 DPRINT("RegistryKey: %wZ\n", RegistryPath
);
1549 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction
);
1550 Status
= (*InitializationFunction
)(DriverObject
, RegistryPath
);
1551 if (!NT_SUCCESS(Status
))
1553 /* If it didn't work, then kill the object */
1554 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName
, Status
);
1555 DriverObject
->DriverSection
= NULL
;
1556 ObMakeTemporaryObject(DriverObject
);
1557 ObDereferenceObject(DriverObject
);
1561 /* Returns to caller the object */
1562 *pDriverObject
= DriverObject
;
1565 /* Loop all Major Functions */
1566 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1569 * Make sure the driver didn't set any dispatch entry point to NULL!
1570 * Doing so is illegal; drivers shouldn't touch entry points they
1574 /* Check if it did so anyway */
1575 if (!DriverObject
->MajorFunction
[i
])
1577 /* Print a warning in the debug log */
1578 DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%d] to NULL!\n",
1579 &DriverObject
->DriverName
, i
);
1582 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1586 /* Return the Status */
1590 /* PUBLIC FUNCTIONS ***********************************************************/
1597 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1598 IN PDRIVER_INITIALIZE InitializationFunction
)
1600 PDRIVER_OBJECT DriverObject
;
1601 return IopCreateDriver(DriverName
, InitializationFunction
, NULL
, NULL
, &DriverObject
);
1609 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1611 /* Simply dereference the Object */
1612 ObDereferenceObject(DriverObject
);
1620 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1621 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1624 PDRIVER_REINIT_ITEM ReinitItem
;
1626 /* Allocate the entry */
1627 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1628 sizeof(DRIVER_REINIT_ITEM
),
1630 if (!ReinitItem
) return;
1633 ReinitItem
->DriverObject
= DriverObject
;
1634 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1635 ReinitItem
->Context
= Context
;
1637 /* Set the Driver Object flag and insert the entry into the list */
1638 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1639 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1640 &ReinitItem
->ItemEntry
,
1641 &DriverBootReinitListLock
);
1649 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1650 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1653 PDRIVER_REINIT_ITEM ReinitItem
;
1655 /* Allocate the entry */
1656 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1657 sizeof(DRIVER_REINIT_ITEM
),
1659 if (!ReinitItem
) return;
1662 ReinitItem
->DriverObject
= DriverObject
;
1663 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1664 ReinitItem
->Context
= Context
;
1666 /* Set the Driver Object flag and insert the entry into the list */
1667 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1668 ExInterlockedInsertTailList(&DriverReinitListHead
,
1669 &ReinitItem
->ItemEntry
,
1670 &DriverReinitListLock
);
1678 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1679 IN PVOID ClientIdentificationAddress
,
1680 IN ULONG DriverObjectExtensionSize
,
1681 OUT PVOID
*DriverObjectExtension
)
1684 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1685 BOOLEAN Inserted
= FALSE
;
1687 /* Assume failure */
1688 *DriverObjectExtension
= NULL
;
1690 /* Allocate the extension */
1691 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1692 sizeof(IO_CLIENT_EXTENSION
) +
1693 DriverObjectExtensionSize
,
1694 TAG_DRIVER_EXTENSION
);
1695 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1697 /* Clear the extension for teh caller */
1698 RtlZeroMemory(NewDriverExtension
,
1699 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1702 OldIrql
= KeRaiseIrqlToDpcLevel();
1704 /* Fill out the extension */
1705 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1707 /* Loop the current extensions */
1708 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1709 ClientDriverExtension
;
1710 while (DriverExtensions
)
1712 /* Check if the identifier matches */
1713 if (DriverExtensions
->ClientIdentificationAddress
==
1714 ClientIdentificationAddress
)
1716 /* We have a collision, break out */
1720 /* Go to the next one */
1721 DriverExtensions
= DriverExtensions
->NextExtension
;
1724 /* Check if we didn't collide */
1725 if (!DriverExtensions
)
1727 /* Link this one in */
1728 NewDriverExtension
->NextExtension
=
1729 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1730 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1735 /* Release the lock */
1736 KeLowerIrql(OldIrql
);
1738 /* Check if insertion failed */
1741 /* Free the entry and fail */
1742 ExFreePool(NewDriverExtension
);
1743 return STATUS_OBJECT_NAME_COLLISION
;
1746 /* Otherwise, return the pointer */
1747 *DriverObjectExtension
= NewDriverExtension
+ 1;
1748 return STATUS_SUCCESS
;
1756 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1757 IN PVOID ClientIdentificationAddress
)
1760 PIO_CLIENT_EXTENSION DriverExtensions
;
1763 OldIrql
= KeRaiseIrqlToDpcLevel();
1765 /* Loop the list until we find the right one */
1766 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1767 while (DriverExtensions
)
1769 /* Check for a match */
1770 if (DriverExtensions
->ClientIdentificationAddress
==
1771 ClientIdentificationAddress
)
1778 DriverExtensions
= DriverExtensions
->NextExtension
;
1782 KeLowerIrql(OldIrql
);
1784 /* Return nothing or the extension */
1785 if (!DriverExtensions
) return NULL
;
1786 return DriverExtensions
+ 1;
1790 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams
)
1792 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1793 UNICODE_STRING ImagePath
;
1794 UNICODE_STRING ServiceName
;
1797 PDEVICE_NODE DeviceNode
;
1798 PDRIVER_OBJECT DriverObject
;
1799 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1803 /* Check if it's an unload request */
1804 if (LoadParams
->DriverObject
)
1806 (*LoadParams
->DriverObject
->DriverUnload
)(LoadParams
->DriverObject
);
1808 /* Return success and signal the event */
1809 LoadParams
->Status
= STATUS_SUCCESS
;
1810 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1814 RtlInitUnicodeString(&ImagePath
, NULL
);
1817 * Get the service name from the registry key name.
1819 ASSERT(LoadParams
->ServiceName
->Length
>= sizeof(WCHAR
));
1821 ServiceName
= *LoadParams
->ServiceName
;
1822 cur
= LoadParams
->ServiceName
->Buffer
+
1823 (LoadParams
->ServiceName
->Length
/ sizeof(WCHAR
)) - 1;
1824 while (LoadParams
->ServiceName
->Buffer
!= cur
)
1828 ServiceName
.Buffer
= cur
+ 1;
1829 ServiceName
.Length
= LoadParams
->ServiceName
->Length
-
1830 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1831 (ULONG_PTR
)LoadParams
->ServiceName
->Buffer
);
1837 IopDisplayLoadingMessage(&ServiceName
);
1843 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1845 RtlInitUnicodeString(&ImagePath
, NULL
);
1847 QueryTable
[0].Name
= L
"Type";
1848 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1849 QueryTable
[0].EntryContext
= &Type
;
1851 QueryTable
[1].Name
= L
"ImagePath";
1852 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1853 QueryTable
[1].EntryContext
= &ImagePath
;
1855 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1856 LoadParams
->ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1858 if (!NT_SUCCESS(Status
))
1860 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1861 if (ImagePath
.Buffer
)
1862 ExFreePool(ImagePath
.Buffer
);
1863 LoadParams
->Status
= Status
;
1864 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1869 * Normalize the image path for all later processing.
1872 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1874 if (!NT_SUCCESS(Status
))
1876 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1877 LoadParams
->Status
= Status
;
1878 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1882 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1883 DPRINT("Type: %lx\n", Type
);
1886 * Create device node
1889 /* Use IopRootDeviceNode for now */
1890 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1892 if (!NT_SUCCESS(Status
))
1894 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1895 LoadParams
->Status
= Status
;
1896 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1900 /* Get existing DriverObject pointer (in case the driver has
1901 already been loaded and initialized) */
1902 Status
= IopGetDriverObject(
1905 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1906 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */));
1908 if (!NT_SUCCESS(Status
))
1911 * Load the driver module
1914 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, &BaseAddress
);
1916 if (!NT_SUCCESS(Status
) && Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1918 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1919 IopFreeDeviceNode(DeviceNode
);
1920 LoadParams
->Status
= Status
;
1921 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1926 * Set a service name for the device node
1929 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
);
1932 * Initialize the driver module if it's loaded for the first time
1934 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1936 Status
= IopInitializeDriverModule(
1939 &DeviceNode
->ServiceName
,
1940 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1941 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1944 if (!NT_SUCCESS(Status
))
1946 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1947 MmUnloadSystemImage(ModuleObject
);
1948 IopFreeDeviceNode(DeviceNode
);
1949 LoadParams
->Status
= Status
;
1950 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1955 /* Initialize and start device */
1956 IopInitializeDevice(DeviceNode
, DriverObject
);
1957 Status
= IopStartDevice(DeviceNode
);
1961 DPRINT("DriverObject already exist in ObjectManager\n");
1963 /* IopGetDriverObject references the DriverObject, so dereference it */
1964 ObDereferenceObject(DriverObject
);
1966 /* Free device node since driver loading failed */
1967 IopFreeDeviceNode(DeviceNode
);
1970 /* Pass status to the caller and signal the event */
1971 LoadParams
->Status
= Status
;
1972 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1978 * Loads a device driver.
1982 * Name of the service to load (registry key).
1991 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1993 UNICODE_STRING CapturedDriverServiceName
= { 0, 0, NULL
};
1994 KPROCESSOR_MODE PreviousMode
;
1995 LOAD_UNLOAD_PARAMS LoadParams
;
2000 PreviousMode
= KeGetPreviousMode();
2003 * Check security privileges
2006 /* FIXME: Uncomment when privileges will be correctly implemented. */
2008 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
2010 DPRINT("Privilege not held\n");
2011 return STATUS_PRIVILEGE_NOT_HELD
;
2015 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
2018 if (!NT_SUCCESS(Status
))
2023 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
2025 LoadParams
.ServiceName
= &CapturedDriverServiceName
;
2026 LoadParams
.DriverObject
= NULL
;
2027 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
2029 /* Call the load/unload routine, depending on current process */
2030 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
2032 /* Just call right away */
2033 IopLoadUnloadDriver(&LoadParams
);
2037 /* Load/Unload must be called from system process */
2038 ExInitializeWorkItem(&LoadParams
.WorkItem
,
2039 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
2040 (PVOID
)&LoadParams
);
2043 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
2045 /* And wait when it completes */
2046 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
2050 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
2053 return LoadParams
.Status
;
2059 * Unloads a legacy device driver.
2063 * Name of the service to unload (registry key).
2073 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
2075 return IopUnloadDriver(DriverServiceName
, FALSE
);