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 RtlUpcaseUnicodeString(ServiceName
, ServiceName
, FALSE
);
204 snprintf(TextBuffer
, sizeof(TextBuffer
),
205 "%s%sSystem32\\Drivers\\%wZ%s\n",
206 KeLoaderBlock
->ArcBootDeviceName
,
207 KeLoaderBlock
->NtBootPathName
,
209 IopSuffixUnicodeString(&DotSys
, ServiceName
) ? "" : ".SYS");
210 HalDisplayString(TextBuffer
);
214 * IopNormalizeImagePath
216 * Normalize an image path to contain complete path.
220 * The input path and on exit the result path. ImagePath.Buffer
221 * must be allocated by ExAllocatePool on input. Caller is responsible
222 * for freeing the buffer when it's no longer needed.
225 * Name of the service that ImagePath belongs to.
231 * The input image path isn't freed on error.
235 IopNormalizeImagePath(
236 IN OUT PUNICODE_STRING ImagePath
,
237 IN PUNICODE_STRING ServiceName
)
239 UNICODE_STRING InputImagePath
;
244 sizeof(UNICODE_STRING
));
246 if (InputImagePath
.Length
== 0)
248 ImagePath
->Length
= 0;
249 ImagePath
->MaximumLength
=
250 (33 * sizeof(WCHAR
)) + ServiceName
->Length
+ sizeof(UNICODE_NULL
);
251 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
252 if (ImagePath
->Buffer
== NULL
)
253 return STATUS_NO_MEMORY
;
255 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\system32\\drivers\\");
256 RtlAppendUnicodeStringToString(ImagePath
, ServiceName
);
257 RtlAppendUnicodeToString(ImagePath
, L
".sys");
259 if (InputImagePath
.Buffer
[0] != L
'\\')
261 ImagePath
->Length
= 0;
262 ImagePath
->MaximumLength
=
263 12 * sizeof(WCHAR
) + InputImagePath
.Length
+ sizeof(UNICODE_NULL
);
264 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
265 if (ImagePath
->Buffer
== NULL
)
266 return STATUS_NO_MEMORY
;
268 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\");
269 RtlAppendUnicodeStringToString(ImagePath
, &InputImagePath
);
271 /* Free caller's string */
272 ExFreePoolWithTag(InputImagePath
.Buffer
, TAG_RTLREGISTRY
);
275 return STATUS_SUCCESS
;
279 * IopLoadServiceModule
281 * Load a module specified by registry settings for service.
285 * Name of the service to load.
292 IopLoadServiceModule(
293 IN PUNICODE_STRING ServiceName
,
294 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
296 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
298 UNICODE_STRING ServiceImagePath
, CCSName
;
300 HANDLE CCSKey
, ServiceKey
;
303 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
305 /* FIXME: This check may be removed once the bug is fixed */
306 if (ServiceName
->Buffer
== NULL
)
308 DPRINT1("If you see this, please report to Fireball or hpoussin!\n");
309 return STATUS_UNSUCCESSFUL
;
312 /* Open CurrentControlSet */
313 RtlInitUnicodeString(&CCSName
,
314 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
315 Status
= IopOpenRegistryKeyEx(&CCSKey
, NULL
, &CCSName
, KEY_READ
);
316 if (!NT_SUCCESS(Status
))
318 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
322 /* Open service key */
323 Status
= IopOpenRegistryKeyEx(&ServiceKey
, CCSKey
, ServiceName
, KEY_READ
);
324 if (!NT_SUCCESS(Status
))
326 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
332 * Get information about the service.
335 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
337 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
339 QueryTable
[0].Name
= L
"Start";
340 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
341 QueryTable
[0].EntryContext
= &ServiceStart
;
343 QueryTable
[1].Name
= L
"ImagePath";
344 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
345 QueryTable
[1].EntryContext
= &ServiceImagePath
;
347 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
348 (PWSTR
)ServiceKey
, QueryTable
, NULL
, NULL
);
353 if (!NT_SUCCESS(Status
))
355 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
360 * Normalize the image path for all later processing.
363 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
365 if (!NT_SUCCESS(Status
))
367 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
372 * Case for disabled drivers
375 if (ServiceStart
>= 4)
377 /* FIXME: Check if it is the right status code */
378 Status
= STATUS_PLUGPLAY_NO_DEVICE
;
382 DPRINT("Loading module\n");
383 Status
= MmLoadSystemImage(&ServiceImagePath
, NULL
, NULL
, 0, (PVOID
)ModuleObject
, &BaseAddress
);
386 ExFreePool(ServiceImagePath
.Buffer
);
389 * Now check if the module was loaded successfully.
392 if (!NT_SUCCESS(Status
))
394 DPRINT("Module loading failed (Status %x)\n", Status
);
397 DPRINT("Module loading (Status %x)\n", Status
);
403 * IopInitializeDriverModule
405 * Initalize a loaded driver.
409 * Pointer to device node.
412 * Module object representing the driver. It can be retrieve by
413 * IopLoadServiceModule.
416 * Name of the service (as in registry).
419 * Set to TRUE for file system drivers.
422 * On successful return this contains the driver object representing
427 IopInitializeDriverModule(
428 IN PDEVICE_NODE DeviceNode
,
429 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
430 IN PUNICODE_STRING ServiceName
,
431 IN BOOLEAN FileSystemDriver
,
432 OUT PDRIVER_OBJECT
*DriverObject
)
434 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
435 WCHAR NameBuffer
[MAX_PATH
];
436 UNICODE_STRING DriverName
;
437 UNICODE_STRING RegistryKey
;
438 PDRIVER_INITIALIZE DriverEntry
;
439 PDRIVER_OBJECT Driver
;
440 PDEVICE_OBJECT DeviceObject
;
443 DriverEntry
= ModuleObject
->EntryPoint
;
445 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
447 RegistryKey
.Length
= 0;
448 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
449 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
450 if (RegistryKey
.Buffer
== NULL
)
452 return STATUS_INSUFFICIENT_RESOURCES
;
454 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
455 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
459 RtlInitUnicodeString(&RegistryKey
, NULL
);
462 /* Create ModuleName string */
463 if (ServiceName
&& ServiceName
->Length
> 0)
465 if (FileSystemDriver
== TRUE
)
466 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
468 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
470 RtlInitUnicodeString(&DriverName
, NameBuffer
);
471 DriverName
.MaximumLength
= sizeof(NameBuffer
);
473 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
475 DPRINT("Driver name: '%wZ'\n", &DriverName
);
478 DriverName
.Length
= 0;
480 Status
= IopCreateDriver(
481 DriverName
.Length
> 0 ? &DriverName
: NULL
,
484 ModuleObject
->DllBase
,
485 ModuleObject
->SizeOfImage
,
487 RtlFreeUnicodeString(&RegistryKey
);
489 *DriverObject
= Driver
;
490 if (!NT_SUCCESS(Status
))
492 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status
);
496 /* Set the driver as initialized */
497 Driver
->Flags
|= DRVO_INITIALIZED
;
498 DeviceObject
= Driver
->DeviceObject
;
501 /* Set every device as initialized too */
502 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
503 DeviceObject
= DeviceObject
->NextDevice
;
506 if (PnpSystemInit
) IopReinitializeDrivers();
508 return STATUS_SUCCESS
;
512 * IopAttachFilterDriversCallback
514 * Internal routine used by IopAttachFilterDrivers.
518 IopAttachFilterDriversCallback(
526 PDEVICE_NODE DeviceNode
= Context
;
527 UNICODE_STRING ServiceName
;
529 PLDR_DATA_TABLE_ENTRY ModuleObject
;
530 PDRIVER_OBJECT DriverObject
;
533 for (Filters
= ValueData
;
534 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
536 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
538 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
539 ServiceName
.Buffer
= Filters
;
540 ServiceName
.MaximumLength
=
541 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
543 /* Load and initialize the filter driver */
544 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
545 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
547 if (!NT_SUCCESS(Status
))
550 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
551 FALSE
, &DriverObject
);
552 if (!NT_SUCCESS(Status
))
557 /* get existing DriverObject pointer */
558 Status
= IopGetDriverObject(
562 if (!NT_SUCCESS(Status
))
564 DPRINT1("IopGetDriverObject() returned status 0x%08x!\n", Status
);
569 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
570 if (!NT_SUCCESS(Status
))
574 return STATUS_SUCCESS
;
578 * IopAttachFilterDrivers
580 * Load filter drivers for specified device node.
584 * Set to TRUE for loading lower level filters or FALSE for upper
589 IopAttachFilterDrivers(
590 PDEVICE_NODE DeviceNode
,
593 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = { { NULL
, 0, NULL
, NULL
, 0, NULL
, 0 }, };
594 UNICODE_STRING Class
;
595 WCHAR ClassBuffer
[40];
596 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
597 HANDLE EnumRootKey
, SubKey
;
600 /* Open enumeration root key */
601 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
602 &EnumRoot
, KEY_READ
);
603 if (!NT_SUCCESS(Status
))
605 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
610 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
611 &DeviceNode
->InstancePath
, KEY_READ
);
612 if (!NT_SUCCESS(Status
))
614 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
615 ZwClose(EnumRootKey
);
620 * First load the device filters
622 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
624 QueryTable
[0].Name
= L
"LowerFilters";
626 QueryTable
[0].Name
= L
"UpperFilters";
627 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
629 RtlQueryRegistryValues(
637 * Now get the class GUID
640 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
641 Class
.Buffer
= ClassBuffer
;
642 QueryTable
[0].QueryRoutine
= NULL
;
643 QueryTable
[0].Name
= L
"ClassGUID";
644 QueryTable
[0].EntryContext
= &Class
;
645 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
647 Status
= RtlQueryRegistryValues(
656 ZwClose(EnumRootKey
);
659 * Load the class filter driver
661 if (NT_SUCCESS(Status
))
663 UNICODE_STRING ControlClass
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
665 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
666 &ControlClass
, KEY_READ
);
667 if (!NT_SUCCESS(Status
))
669 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
674 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
676 if (!NT_SUCCESS(Status
))
678 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
679 ZwClose(EnumRootKey
);
683 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
685 QueryTable
[0].Name
= L
"LowerFilters";
687 QueryTable
[0].Name
= L
"UpperFilters";
688 QueryTable
[0].EntryContext
= NULL
;
689 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
691 RtlQueryRegistryValues(
700 ZwClose(EnumRootKey
);
703 return STATUS_SUCCESS
;
708 MiResolveImageReferences(IN PVOID ImageBase
,
709 IN PUNICODE_STRING ImageFileDirectory
,
710 IN PUNICODE_STRING NamePrefix OPTIONAL
,
711 OUT PCHAR
*MissingApi
,
712 OUT PWCHAR
*MissingDriver
,
713 OUT PLOAD_IMPORTS
*LoadImports
);
716 // Used for images already loaded (boot drivers)
720 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry
,
721 PUNICODE_STRING FileName
,
722 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
725 PLDR_DATA_TABLE_ENTRY NewEntry
;
726 UNICODE_STRING BaseName
, BaseDirectory
;
727 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
728 PCHAR MissingApiName
, Buffer
;
729 PWCHAR MissingDriverName
;
730 PVOID DriverBase
= LdrEntry
->DllBase
;
732 /* Allocate a buffer we'll use for names */
733 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
737 return STATUS_INSUFFICIENT_RESOURCES
;
740 /* Check for a separator */
741 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
746 /* Loop the path until we get to the base name */
747 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
748 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
751 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
752 BaseLength
*= sizeof(WCHAR
);
754 /* Setup the string */
755 BaseName
.Length
= (USHORT
)BaseLength
;
760 /* Otherwise, we already have a base name */
761 BaseName
.Length
= FileName
->Length
;
762 BaseName
.Buffer
= FileName
->Buffer
;
765 /* Setup the maximum length */
766 BaseName
.MaximumLength
= BaseName
.Length
;
768 /* Now compute the base directory */
769 BaseDirectory
= *FileName
;
770 BaseDirectory
.Length
-= BaseName
.Length
;
771 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
775 /* Resolve imports */
776 MissingApiName
= Buffer
;
777 Status
= MiResolveImageReferences(DriverBase
,
783 if (!NT_SUCCESS(Status
)) return Status
;
786 *ModuleObject
= LdrEntry
;
787 return STATUS_SUCCESS
;
791 * IopInitializeBuiltinDriver
793 * Initialize a driver that is already loaded in memory.
798 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
800 PDEVICE_NODE DeviceNode
;
801 PDRIVER_OBJECT DriverObject
;
803 PWCHAR FileNameWithoutPath
;
804 LPWSTR FileExtension
;
805 PUNICODE_STRING ModuleName
= &LdrEntry
->BaseDllName
;
806 UNICODE_STRING ServiceName
;
809 * Display 'Loading XXX...' message
811 IopDisplayLoadingMessage(ModuleName
);
812 InbvIndicateProgress();
815 * Generate filename without path (not needed by freeldr)
817 FileNameWithoutPath
= wcsrchr(ModuleName
->Buffer
, L
'\\');
818 if (FileNameWithoutPath
== NULL
)
820 FileNameWithoutPath
= ModuleName
->Buffer
;
824 FileNameWithoutPath
++;
828 * Strip the file extension from ServiceName
830 RtlCreateUnicodeString(&ServiceName
, FileNameWithoutPath
);
831 FileExtension
= wcsrchr(ServiceName
.Buffer
, '.');
832 if (FileExtension
!= NULL
)
834 ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
835 FileExtension
[0] = 0;
839 * Determine the right device object
841 /* Use IopRootDeviceNode for now */
842 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
843 if (!NT_SUCCESS(Status
))
845 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
848 DeviceNode
->ServiceName
= ServiceName
;
851 * Initialize the driver
853 Status
= IopInitializeDriverModule(DeviceNode
, LdrEntry
,
854 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
856 if (!NT_SUCCESS(Status
))
858 IopFreeDeviceNode(DeviceNode
);
862 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
863 if (NT_SUCCESS(Status
))
865 Status
= IopStartDevice(DeviceNode
);
872 * IopInitializeBootDrivers
874 * Initialize boot drivers and free memory for boot files.
884 IopInitializeBootDrivers(VOID
)
886 PLIST_ENTRY ListHead
, NextEntry
, NextEntry2
;
887 PLDR_DATA_TABLE_ENTRY LdrEntry
;
888 PDEVICE_NODE DeviceNode
;
889 PDRIVER_OBJECT DriverObject
;
890 LDR_DATA_TABLE_ENTRY ModuleObject
;
892 UNICODE_STRING DriverName
;
894 PDRIVER_INFORMATION DriverInfo
, DriverInfoTag
;
896 PBOOT_DRIVER_LIST_ENTRY BootEntry
;
897 DPRINT("IopInitializeBootDrivers()\n");
899 /* Use IopRootDeviceNode for now */
900 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, NULL
, &DeviceNode
);
901 if (!NT_SUCCESS(Status
)) return;
903 /* Setup the module object for the RAW FS Driver */
904 ModuleObject
.DllBase
= NULL
;
905 ModuleObject
.SizeOfImage
= 0;
906 ModuleObject
.EntryPoint
= RawFsDriverEntry
;
907 RtlInitUnicodeString(&DriverName
, L
"RAW");
910 Status
= IopInitializeDriverModule(DeviceNode
,
915 if (!NT_SUCCESS(Status
))
918 IopFreeDeviceNode(DeviceNode
);
922 /* Now initialize the associated device */
923 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
924 if (!NT_SUCCESS(Status
))
927 IopFreeDeviceNode(DeviceNode
);
932 Status
= IopStartDevice(DeviceNode
);
933 if (!NT_SUCCESS(Status
))
936 IopFreeDeviceNode(DeviceNode
);
940 /* Get highest group order index */
941 IopGroupIndex
= PpInitGetGroupOrderIndex(NULL
);
942 if (IopGroupIndex
== 0xFFFF) ASSERT(FALSE
);
944 /* Allocate the group table */
945 IopGroupTable
= ExAllocatePoolWithTag(PagedPool
,
946 IopGroupIndex
* sizeof(LIST_ENTRY
),
948 if (IopGroupTable
== NULL
) ASSERT(FALSE
);
950 /* Initialize the group table lists */
951 for (i
= 0; i
< IopGroupIndex
; i
++) InitializeListHead(&IopGroupTable
[i
]);
953 /* Loop the boot modules */
954 ListHead
= &KeLoaderBlock
->LoadOrderListHead
;
955 NextEntry
= ListHead
->Flink
;
956 while (ListHead
!= NextEntry
)
959 LdrEntry
= CONTAINING_RECORD(NextEntry
,
960 LDR_DATA_TABLE_ENTRY
,
963 /* Check if the DLL needs to be initialized */
964 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
966 /* Call its entrypoint */
967 MmCallDllInitialize(LdrEntry
, NULL
);
970 /* Go to the next driver */
971 NextEntry
= NextEntry
->Flink
;
974 /* Loop the boot drivers */
975 ListHead
= &KeLoaderBlock
->BootDriverListHead
;
976 NextEntry
= ListHead
->Flink
;
977 while (ListHead
!= NextEntry
)
980 BootEntry
= CONTAINING_RECORD(NextEntry
,
981 BOOT_DRIVER_LIST_ENTRY
,
984 /* Get the driver loader entry */
985 LdrEntry
= BootEntry
->LdrEntry
;
987 /* Allocate our internal accounting structure */
988 DriverInfo
= ExAllocatePoolWithTag(PagedPool
,
989 sizeof(DRIVER_INFORMATION
),
993 /* Zero it and initialize it */
994 RtlZeroMemory(DriverInfo
, sizeof(DRIVER_INFORMATION
));
995 InitializeListHead(&DriverInfo
->Link
);
996 DriverInfo
->DataTableEntry
= BootEntry
;
998 /* Open the registry key */
999 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
1001 &BootEntry
->RegistryPath
,
1003 if ((NT_SUCCESS(Status
)) || /* ReactOS HACK for SETUPLDR */
1004 ((KeLoaderBlock
->SetupLdrBlock
) && (KeyHandle
= (PVOID
)1)))
1006 /* Save the handle */
1007 DriverInfo
->ServiceHandle
= KeyHandle
;
1009 /* Get the group oder index */
1010 Index
= PpInitGetGroupOrderIndex(KeyHandle
);
1012 /* Get the tag position */
1013 DriverInfo
->TagPosition
= PipGetDriverTagPriority(KeyHandle
);
1015 /* Insert it into the list, at the right place */
1016 ASSERT(Index
< IopGroupIndex
);
1017 NextEntry2
= IopGroupTable
[Index
].Flink
;
1018 while (NextEntry2
!= &IopGroupTable
[Index
])
1020 /* Get the driver info */
1021 DriverInfoTag
= CONTAINING_RECORD(NextEntry2
,
1025 /* Check if we found the right tag position */
1026 if (DriverInfoTag
->TagPosition
> DriverInfo
->TagPosition
)
1033 NextEntry2
= NextEntry2
->Flink
;
1036 /* Insert us right before the next entry */
1037 NextEntry2
= NextEntry2
->Blink
;
1038 InsertHeadList(NextEntry2
, &DriverInfo
->Link
);
1042 /* Go to the next driver */
1043 NextEntry
= NextEntry
->Flink
;
1046 /* Loop each group index */
1047 for (i
= 0; i
< IopGroupIndex
; i
++)
1049 /* Loop each group table */
1050 NextEntry
= IopGroupTable
[i
].Flink
;
1051 while (NextEntry
!= &IopGroupTable
[i
])
1054 DriverInfo
= CONTAINING_RECORD(NextEntry
,
1058 /* Get the driver loader entry */
1059 LdrEntry
= DriverInfo
->DataTableEntry
->LdrEntry
;
1062 IopInitializeBuiltinDriver(LdrEntry
);
1065 NextEntry
= NextEntry
->Flink
;
1069 /* In old ROS, the loader list became empty after this point. Simulate. */
1070 InitializeListHead(&KeLoaderBlock
->LoadOrderListHead
);
1076 * Unloads a device driver.
1080 * Name of the service to unload (registry key).
1083 * Whether to unload Plug & Plug or only legacy drivers. If this
1084 * parameter is set to FALSE, the routine will unload only legacy
1091 * Guard the whole function by SEH.
1095 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1097 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1098 UNICODE_STRING ImagePath
;
1099 UNICODE_STRING ServiceName
;
1100 UNICODE_STRING ObjectName
;
1101 PDRIVER_OBJECT DriverObject
;
1102 PDEVICE_OBJECT DeviceObject
;
1103 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1104 LOAD_UNLOAD_PARAMS LoadParams
;
1107 BOOLEAN SafeToUnload
= TRUE
;
1109 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1114 * Get the service name from the registry key name
1117 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1119 Start
= DriverServiceName
->Buffer
;
1123 RtlInitUnicodeString(&ServiceName
, Start
);
1126 * Construct the driver object name
1129 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1130 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1131 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1132 if (!ObjectName
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1133 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1134 memcpy(ObjectName
.Buffer
+ 8, Start
, ObjectName
.Length
- 8 * sizeof(WCHAR
));
1135 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1138 * Find the driver object
1140 Status
= ObReferenceObjectByName(&ObjectName
,
1147 (PVOID
*)&DriverObject
);
1150 * Free the buffer for driver object name
1152 ExFreePool(ObjectName
.Buffer
);
1154 if (!NT_SUCCESS(Status
))
1156 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName
);
1160 /* Check that driver is not already unloading */
1161 if (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
)
1163 DPRINT1("Driver deletion pending\n");
1164 ObDereferenceObject(DriverObject
);
1165 return STATUS_DELETE_PENDING
;
1169 * Get path of service...
1172 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1174 RtlInitUnicodeString(&ImagePath
, NULL
);
1176 QueryTable
[0].Name
= L
"ImagePath";
1177 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1178 QueryTable
[0].EntryContext
= &ImagePath
;
1180 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1181 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1183 if (!NT_SUCCESS(Status
))
1185 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1186 ObDereferenceObject(DriverObject
);
1191 * Normalize the image path for all later processing.
1194 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1196 if (!NT_SUCCESS(Status
))
1198 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1199 ObDereferenceObject(DriverObject
);
1204 * Free the service path
1207 ExFreePool(ImagePath
.Buffer
);
1210 * Unload the module and release the references to the device object
1213 /* Call the load/unload routine, depending on current process */
1214 if (DriverObject
->DriverUnload
&& DriverObject
->DriverSection
)
1216 /* Loop through each device object of the driver
1217 and set DOE_UNLOAD_PENDING flag */
1218 DeviceObject
= DriverObject
->DeviceObject
;
1219 while (DeviceObject
)
1221 /* Set the unload pending flag for the device */
1222 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1223 DeviceExtension
->ExtensionFlags
|= DOE_UNLOAD_PENDING
;
1225 /* Make sure there are no attached devices or no reference counts */
1226 if ((DeviceObject
->ReferenceCount
) || (DeviceObject
->AttachedDevice
))
1228 /* Not safe to unload */
1229 DPRINT1("Drivers device object is referenced or has attached devices\n");
1231 SafeToUnload
= FALSE
;
1234 DeviceObject
= DeviceObject
->NextDevice
;
1237 /* If not safe to unload, then return success */
1240 ObDereferenceObject(DriverObject
);
1241 return STATUS_SUCCESS
;
1244 /* Set the unload invoked flag */
1245 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
1247 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1249 /* Just call right away */
1250 (*DriverObject
->DriverUnload
)(DriverObject
);
1254 /* Load/Unload must be called from system process */
1256 /* Prepare parameters block */
1257 LoadParams
.DriverObject
= DriverObject
;
1258 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1260 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1261 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1262 (PVOID
)&LoadParams
);
1265 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1267 /* And wait when it completes */
1268 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1272 /* Mark the driver object temporary, so it could be deleted later */
1273 ObMakeTemporaryObject(DriverObject
);
1275 /* Dereference it 2 times */
1276 ObDereferenceObject(DriverObject
);
1277 ObDereferenceObject(DriverObject
);
1279 return STATUS_SUCCESS
;
1283 /* Dereference one time (refd inside this function) */
1284 ObDereferenceObject(DriverObject
);
1286 /* Return unloading failure */
1287 return STATUS_INVALID_DEVICE_REQUEST
;
1293 IopReinitializeDrivers(VOID
)
1295 PDRIVER_REINIT_ITEM ReinitItem
;
1298 /* Get the first entry and start looping */
1299 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1300 &DriverReinitListLock
);
1304 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1306 /* Increment reinitialization counter */
1307 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1309 /* Remove the device object flag */
1310 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1312 /* Call the routine */
1313 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1314 ReinitItem
->Context
,
1315 ReinitItem
->DriverObject
->
1316 DriverExtension
->Count
);
1318 /* Free the entry */
1321 /* Move to the next one */
1322 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1323 &DriverReinitListLock
);
1329 IopReinitializeBootDrivers(VOID
)
1331 PDRIVER_REINIT_ITEM ReinitItem
;
1334 /* Get the first entry and start looping */
1335 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1336 &DriverBootReinitListLock
);
1340 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1342 /* Increment reinitialization counter */
1343 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1345 /* Remove the device object flag */
1346 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1348 /* Call the routine */
1349 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1350 ReinitItem
->Context
,
1351 ReinitItem
->DriverObject
->
1352 DriverExtension
->Count
);
1354 /* Free the entry */
1357 /* Move to the next one */
1358 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1359 &DriverBootReinitListLock
);
1365 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1366 IN PDRIVER_INITIALIZE InitializationFunction
,
1367 IN PUNICODE_STRING RegistryPath
,
1369 IN ULONG SizeOfImage
,
1370 OUT PDRIVER_OBJECT
*pDriverObject
)
1372 WCHAR NameBuffer
[100];
1374 UNICODE_STRING LocalDriverName
;
1376 OBJECT_ATTRIBUTES ObjectAttributes
;
1378 PDRIVER_OBJECT DriverObject
;
1379 UNICODE_STRING ServiceKeyName
;
1381 ULONG i
, RetryCount
= 0;
1384 /* First, create a unique name for the driver if we don't have one */
1387 /* Create a random name and set up the string*/
1388 NameLength
= (USHORT
)swprintf(NameBuffer
,
1391 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1392 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1393 LocalDriverName
.Buffer
= NameBuffer
;
1397 /* So we can avoid another code path, use a local var */
1398 LocalDriverName
= *DriverName
;
1401 /* Initialize the Attributes */
1402 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1403 InitializeObjectAttributes(&ObjectAttributes
,
1405 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1409 /* Create the Object */
1410 Status
= ObCreateObject(KernelMode
,
1418 (PVOID
*)&DriverObject
);
1419 if (!NT_SUCCESS(Status
)) return Status
;
1421 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1423 /* Set up the Object */
1424 RtlZeroMemory(DriverObject
, ObjectSize
);
1425 DriverObject
->Type
= IO_TYPE_DRIVER
;
1426 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1427 DriverObject
->Flags
= DRVO_LEGACY_DRIVER
;//DRVO_BUILTIN_DRIVER;
1428 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1429 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1430 DriverObject
->DriverInit
= InitializationFunction
;
1432 /* Loop all Major Functions */
1433 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1435 /* Invalidate each function */
1436 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1439 /* Set up the service key name buffer */
1440 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1441 LocalDriverName
.Length
+
1444 if (!ServiceKeyName
.Buffer
)
1447 ObMakeTemporaryObject(DriverObject
);
1448 ObDereferenceObject(DriverObject
);
1449 return STATUS_INSUFFICIENT_RESOURCES
;
1452 /* Fill out the key data and copy the buffer */
1453 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1454 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1455 RtlCopyMemory(ServiceKeyName
.Buffer
,
1456 LocalDriverName
.Buffer
,
1457 LocalDriverName
.Length
);
1459 /* Null-terminate it and set it */
1460 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1461 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1463 /* Also store it in the Driver Object. This is a bit of a hack. */
1464 RtlCopyMemory(&DriverObject
->DriverName
,
1466 sizeof(UNICODE_STRING
));
1468 /* Add the Object and get its handle */
1469 Status
= ObInsertObject(DriverObject
,
1476 /* Eliminate small possibility when this function is called more than
1477 once in a row, and KeTickCount doesn't get enough time to change */
1478 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1484 if (!NT_SUCCESS(Status
)) return Status
;
1486 /* Now reference it */
1487 Status
= ObReferenceObjectByHandle(hDriver
,
1491 (PVOID
*)&DriverObject
,
1493 if (!NT_SUCCESS(Status
))
1496 ObMakeTemporaryObject(DriverObject
);
1497 ObDereferenceObject(DriverObject
);
1501 /* Close the extra handle */
1504 DriverObject
->HardwareDatabase
= &IopHardwareDatabaseKey
;
1505 DriverObject
->DriverStart
= DllBase
;
1506 DriverObject
->DriverSize
= SizeOfImage
;
1508 /* Finally, call its init function */
1509 DPRINT("RegistryKey: %wZ\n", RegistryPath
);
1510 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction
);
1511 Status
= (*InitializationFunction
)(DriverObject
, RegistryPath
);
1512 if (!NT_SUCCESS(Status
))
1514 /* If it didn't work, then kill the object */
1515 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName
, Status
);
1516 ObMakeTemporaryObject(DriverObject
);
1517 ObDereferenceObject(DriverObject
);
1521 /* Returns to caller the object */
1522 *pDriverObject
= DriverObject
;
1525 /* Loop all Major Functions */
1526 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1529 * Make sure the driver didn't set any dispatch entry point to NULL!
1530 * Doing so is illegal; drivers shouldn't touch entry points they
1533 ASSERT(DriverObject
->MajorFunction
[i
] != NULL
);
1535 /* Check if it did so anyway */
1536 if (!DriverObject
->MajorFunction
[i
])
1539 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1543 /* Return the Status */
1547 /* PUBLIC FUNCTIONS ***********************************************************/
1554 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1555 IN PDRIVER_INITIALIZE InitializationFunction
)
1557 PDRIVER_OBJECT DriverObject
;
1558 return IopCreateDriver(DriverName
, InitializationFunction
, NULL
, 0, 0, &DriverObject
);
1566 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1568 /* Simply dereference the Object */
1569 ObDereferenceObject(DriverObject
);
1577 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1578 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1581 PDRIVER_REINIT_ITEM ReinitItem
;
1583 /* Allocate the entry */
1584 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1585 sizeof(DRIVER_REINIT_ITEM
),
1587 if (!ReinitItem
) return;
1590 ReinitItem
->DriverObject
= DriverObject
;
1591 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1592 ReinitItem
->Context
= Context
;
1594 /* Set the Driver Object flag and insert the entry into the list */
1595 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1596 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1597 &ReinitItem
->ItemEntry
,
1598 &DriverBootReinitListLock
);
1606 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1607 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1610 PDRIVER_REINIT_ITEM ReinitItem
;
1612 /* Allocate the entry */
1613 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1614 sizeof(DRIVER_REINIT_ITEM
),
1616 if (!ReinitItem
) return;
1619 ReinitItem
->DriverObject
= DriverObject
;
1620 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1621 ReinitItem
->Context
= Context
;
1623 /* Set the Driver Object flag and insert the entry into the list */
1624 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1625 ExInterlockedInsertTailList(&DriverReinitListHead
,
1626 &ReinitItem
->ItemEntry
,
1627 &DriverReinitListLock
);
1635 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1636 IN PVOID ClientIdentificationAddress
,
1637 IN ULONG DriverObjectExtensionSize
,
1638 OUT PVOID
*DriverObjectExtension
)
1641 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1642 BOOLEAN Inserted
= FALSE
;
1644 /* Assume failure */
1645 *DriverObjectExtension
= NULL
;
1647 /* Allocate the extension */
1648 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1649 sizeof(IO_CLIENT_EXTENSION
) +
1650 DriverObjectExtensionSize
,
1651 TAG_DRIVER_EXTENSION
);
1652 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1654 /* Clear the extension for teh caller */
1655 RtlZeroMemory(NewDriverExtension
,
1656 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1659 OldIrql
= KeRaiseIrqlToDpcLevel();
1661 /* Fill out the extension */
1662 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1664 /* Loop the current extensions */
1665 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1666 ClientDriverExtension
;
1667 while (DriverExtensions
)
1669 /* Check if the identifier matches */
1670 if (DriverExtensions
->ClientIdentificationAddress
==
1671 ClientIdentificationAddress
)
1673 /* We have a collision, break out */
1677 /* Go to the next one */
1678 DriverExtensions
= DriverExtensions
->NextExtension
;
1681 /* Check if we didn't collide */
1682 if (!DriverExtensions
)
1684 /* Link this one in */
1685 NewDriverExtension
->NextExtension
=
1686 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1687 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1692 /* Release the lock */
1693 KeLowerIrql(OldIrql
);
1695 /* Check if insertion failed */
1698 /* Free the entry and fail */
1699 ExFreePool(NewDriverExtension
);
1700 return STATUS_OBJECT_NAME_COLLISION
;
1703 /* Otherwise, return the pointer */
1704 *DriverObjectExtension
= NewDriverExtension
+ 1;
1705 return STATUS_SUCCESS
;
1713 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1714 IN PVOID ClientIdentificationAddress
)
1717 PIO_CLIENT_EXTENSION DriverExtensions
;
1720 OldIrql
= KeRaiseIrqlToDpcLevel();
1722 /* Loop the list until we find the right one */
1723 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1724 while (DriverExtensions
)
1726 /* Check for a match */
1727 if (DriverExtensions
->ClientIdentificationAddress
==
1728 ClientIdentificationAddress
)
1735 DriverExtensions
= DriverExtensions
->NextExtension
;
1739 KeLowerIrql(OldIrql
);
1741 /* Return nothing or the extension */
1742 if (!DriverExtensions
) return NULL
;
1743 return DriverExtensions
+ 1;
1747 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams
)
1749 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1750 UNICODE_STRING ImagePath
;
1751 UNICODE_STRING ServiceName
;
1754 PDEVICE_NODE DeviceNode
;
1755 PDRIVER_OBJECT DriverObject
;
1756 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1760 /* Check if it's an unload request */
1761 if (LoadParams
->DriverObject
)
1763 (*LoadParams
->DriverObject
->DriverUnload
)(LoadParams
->DriverObject
);
1765 /* Return success and signal the event */
1766 LoadParams
->Status
= STATUS_SUCCESS
;
1767 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1771 RtlInitUnicodeString(&ImagePath
, NULL
);
1774 * Get the service name from the registry key name.
1776 ASSERT(LoadParams
->ServiceName
->Length
>= sizeof(WCHAR
));
1778 ServiceName
= *LoadParams
->ServiceName
;
1779 cur
= LoadParams
->ServiceName
->Buffer
+
1780 (LoadParams
->ServiceName
->Length
/ sizeof(WCHAR
)) - 1;
1781 while (LoadParams
->ServiceName
->Buffer
!= cur
)
1785 ServiceName
.Buffer
= cur
+ 1;
1786 ServiceName
.Length
= LoadParams
->ServiceName
->Length
-
1787 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1788 (ULONG_PTR
)LoadParams
->ServiceName
->Buffer
);
1798 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1800 RtlInitUnicodeString(&ImagePath
, NULL
);
1802 QueryTable
[0].Name
= L
"Type";
1803 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1804 QueryTable
[0].EntryContext
= &Type
;
1806 QueryTable
[1].Name
= L
"ImagePath";
1807 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1808 QueryTable
[1].EntryContext
= &ImagePath
;
1810 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1811 LoadParams
->ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1813 if (!NT_SUCCESS(Status
))
1815 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1816 if (ImagePath
.Buffer
)
1817 ExFreePool(ImagePath
.Buffer
);
1818 LoadParams
->Status
= Status
;
1819 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1824 * Normalize the image path for all later processing.
1827 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1829 if (!NT_SUCCESS(Status
))
1831 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1832 LoadParams
->Status
= Status
;
1833 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1837 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1838 DPRINT("Type: %lx\n", Type
);
1841 * Create device node
1844 /* Use IopRootDeviceNode for now */
1845 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1847 if (!NT_SUCCESS(Status
))
1849 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1850 LoadParams
->Status
= Status
;
1851 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1855 /* Get existing DriverObject pointer (in case the driver has
1856 already been loaded and initialized) */
1857 Status
= IopGetDriverObject(
1860 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1861 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */));
1863 if (!NT_SUCCESS(Status
))
1866 * Load the driver module
1869 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, &BaseAddress
);
1870 if (!NT_SUCCESS(Status
) && Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1872 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1873 IopFreeDeviceNode(DeviceNode
);
1874 LoadParams
->Status
= Status
;
1875 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1880 * Set a service name for the device node
1883 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
);
1886 * Initialize the driver module if it's loaded for the first time
1888 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1890 Status
= IopInitializeDriverModule(
1893 &DeviceNode
->ServiceName
,
1894 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1895 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1898 if (!NT_SUCCESS(Status
))
1900 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1901 MmUnloadSystemImage(ModuleObject
);
1902 IopFreeDeviceNode(DeviceNode
);
1903 LoadParams
->Status
= Status
;
1904 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1909 /* Store its DriverSection, so that it could be unloaded */
1910 DriverObject
->DriverSection
= ModuleObject
;
1912 /* Initialize and start device */
1913 IopInitializeDevice(DeviceNode
, DriverObject
);
1914 Status
= IopStartDevice(DeviceNode
);
1918 DPRINT("DriverObject already exist in ObjectManager\n");
1920 /* IopGetDriverObject references the DriverObject, so dereference it */
1921 ObDereferenceObject(DriverObject
);
1923 /* Free device node since driver loading failed */
1924 IopFreeDeviceNode(DeviceNode
);
1927 /* Pass status to the caller and signal the event */
1928 LoadParams
->Status
= Status
;
1929 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1935 * Loads a device driver.
1939 * Name of the service to load (registry key).
1948 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1950 UNICODE_STRING CapturedDriverServiceName
= { 0, 0, NULL
};
1951 KPROCESSOR_MODE PreviousMode
;
1952 LOAD_UNLOAD_PARAMS LoadParams
;
1957 PreviousMode
= KeGetPreviousMode();
1960 * Check security privileges
1963 /* FIXME: Uncomment when privileges will be correctly implemented. */
1965 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1967 DPRINT("Privilege not held\n");
1968 return STATUS_PRIVILEGE_NOT_HELD
;
1972 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
1975 if (!NT_SUCCESS(Status
))
1980 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1982 LoadParams
.ServiceName
= &CapturedDriverServiceName
;
1983 LoadParams
.DriverObject
= NULL
;
1984 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1986 /* Call the load/unload routine, depending on current process */
1987 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1989 /* Just call right away */
1990 IopLoadUnloadDriver(&LoadParams
);
1994 /* Load/Unload must be called from system process */
1995 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1996 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1997 (PVOID
)&LoadParams
);
2000 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
2002 /* And wait when it completes */
2003 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
2007 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
2010 return LoadParams
.Status
;
2016 * Unloads a legacy device driver.
2020 * Name of the service to unload (registry key).
2030 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
2032 return IopUnloadDriver(DriverServiceName
, FALSE
);