2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/driver.c
5 * PURPOSE: Driver Object Management
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Filip Navara (navaraf@reactos.org)
8 * Hervé Poussineau (hpoussin@reactos.org)
11 /* INCLUDES *******************************************************************/
17 /* GLOBALS ********************************************************************/
19 LIST_ENTRY DriverReinitListHead
;
20 KSPIN_LOCK DriverReinitListLock
;
21 PLIST_ENTRY DriverReinitTailEntry
;
23 PLIST_ENTRY DriverBootReinitTailEntry
;
24 LIST_ENTRY DriverBootReinitListHead
;
25 KSPIN_LOCK DriverBootReinitListLock
;
27 UNICODE_STRING IopHardwareDatabaseKey
=
28 RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
30 POBJECT_TYPE IoDriverObjectType
= NULL
;
32 #define TAG_RTLREGISTRY 'vrqR'
34 extern BOOLEAN ExpInTextModeSetup
;
35 extern BOOLEAN PnpSystemInit
;
38 PLIST_ENTRY IopGroupTable
;
40 /* PRIVATE FUNCTIONS **********************************************************/
43 IopInvalidDeviceRequest(
44 PDEVICE_OBJECT DeviceObject
,
47 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
48 Irp
->IoStatus
.Information
= 0;
49 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
50 return STATUS_INVALID_DEVICE_REQUEST
;
55 IopDeleteDriver(IN PVOID ObjectBody
)
57 PDRIVER_OBJECT DriverObject
= ObjectBody
;
58 PIO_CLIENT_EXTENSION DriverExtension
, NextDriverExtension
;
61 DPRINT1("Deleting driver object '%wZ'\n", &DriverObject
->DriverName
);
63 /* There must be no device objects remaining at this point */
64 ASSERT(!DriverObject
->DeviceObject
);
66 /* Get the extension and loop them */
67 DriverExtension
= IoGetDrvObjExtension(DriverObject
)->
68 ClientDriverExtension
;
69 while (DriverExtension
)
71 /* Get the next one */
72 NextDriverExtension
= DriverExtension
->NextExtension
;
73 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
76 DriverExtension
= NextDriverExtension
;
80 /* Check if the driver image is still loaded */
81 if (DriverObject
->DriverSection
)
84 MmUnloadSystemImage(DriverObject
->DriverSection
);
87 DPRINT1("HACK: Not unloading the driver image due to critical bugs!\n");
90 /* Check if it has a name */
91 if (DriverObject
->DriverName
.Buffer
)
94 ExFreePool(DriverObject
->DriverName
.Buffer
);
97 #if 0 /* See a bit of hack in IopCreateDriver */
98 /* Check if it has a service key name */
99 if (DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
)
102 ExFreePool(DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
);
109 PDRIVER_OBJECT
*DriverObject
,
110 PUNICODE_STRING ServiceName
,
113 PDRIVER_OBJECT Object
;
114 WCHAR NameBuffer
[MAX_PATH
];
115 UNICODE_STRING DriverName
;
118 DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
119 DriverObject
, ServiceName
, FileSystem
);
121 *DriverObject
= NULL
;
123 /* Create ModuleName string */
124 if (ServiceName
== NULL
|| ServiceName
->Buffer
== NULL
)
125 /* We don't know which DriverObject we have to open */
126 return STATUS_INVALID_PARAMETER_2
;
128 DriverName
.Buffer
= NameBuffer
;
129 DriverName
.Length
= 0;
130 DriverName
.MaximumLength
= sizeof(NameBuffer
);
132 if (FileSystem
== TRUE
)
133 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
135 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
136 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
138 DPRINT("Driver name: '%wZ'\n", &DriverName
);
140 /* Open driver object */
141 Status
= ObReferenceObjectByName(
143 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, /* Attributes */
144 NULL
, /* PassedAccessState */
145 0, /* DesiredAccess */
148 NULL
, /* ParseContext */
151 if (!NT_SUCCESS(Status
))
153 DPRINT("Failed to reference driver object, status=0x%08x\n", Status
);
157 *DriverObject
= Object
;
159 DPRINT("Driver Object: %p\n", Object
);
161 return STATUS_SUCCESS
;
166 * TRUE if String2 contains String1 as a suffix.
170 IopSuffixUnicodeString(
171 IN PCUNICODE_STRING String1
,
172 IN PCUNICODE_STRING String2
)
178 if (String2
->Length
< String1
->Length
)
181 Length
= String1
->Length
/ 2;
182 pc1
= String1
->Buffer
;
183 pc2
= &String2
->Buffer
[String2
->Length
/ sizeof(WCHAR
) - Length
];
189 if( *pc1
++ != *pc2
++ )
198 * IopDisplayLoadingMessage
200 * Display 'Loading XXX...' message.
206 IopDisplayLoadingMessage(PUNICODE_STRING ServiceName
)
208 CHAR TextBuffer
[256];
209 UNICODE_STRING DotSys
= RTL_CONSTANT_STRING(L
".SYS");
211 if (ExpInTextModeSetup
) return;
212 if (!KeLoaderBlock
) return;
213 RtlUpcaseUnicodeString(ServiceName
, ServiceName
, FALSE
);
214 snprintf(TextBuffer
, sizeof(TextBuffer
),
215 "%s%sSystem32\\Drivers\\%wZ%s\n",
216 KeLoaderBlock
->ArcBootDeviceName
,
217 KeLoaderBlock
->NtBootPathName
,
219 IopSuffixUnicodeString(&DotSys
, ServiceName
) ? "" : ".SYS");
220 HalDisplayString(TextBuffer
);
224 * IopNormalizeImagePath
226 * Normalize an image path to contain complete path.
230 * The input path and on exit the result path. ImagePath.Buffer
231 * must be allocated by ExAllocatePool on input. Caller is responsible
232 * for freeing the buffer when it's no longer needed.
235 * Name of the service that ImagePath belongs to.
241 * The input image path isn't freed on error.
245 IopNormalizeImagePath(
246 IN OUT PUNICODE_STRING ImagePath
,
247 IN PUNICODE_STRING ServiceName
)
249 UNICODE_STRING InputImagePath
;
251 DPRINT("Normalizing image path '%wZ' for service '%wZ'\n", ImagePath
, ServiceName
);
256 sizeof(UNICODE_STRING
));
258 if (InputImagePath
.Length
== 0)
260 ImagePath
->Length
= 0;
261 ImagePath
->MaximumLength
=
262 (33 * sizeof(WCHAR
)) + ServiceName
->Length
+ sizeof(UNICODE_NULL
);
263 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
264 if (ImagePath
->Buffer
== NULL
)
265 return STATUS_NO_MEMORY
;
267 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\system32\\drivers\\");
268 RtlAppendUnicodeStringToString(ImagePath
, ServiceName
);
269 RtlAppendUnicodeToString(ImagePath
, L
".sys");
271 if (InputImagePath
.Buffer
[0] != L
'\\')
273 ImagePath
->Length
= 0;
274 ImagePath
->MaximumLength
=
275 12 * sizeof(WCHAR
) + InputImagePath
.Length
+ sizeof(UNICODE_NULL
);
276 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
277 if (ImagePath
->Buffer
== NULL
)
278 return STATUS_NO_MEMORY
;
280 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\");
281 RtlAppendUnicodeStringToString(ImagePath
, &InputImagePath
);
283 /* Free caller's string */
284 ExFreePoolWithTag(InputImagePath
.Buffer
, TAG_RTLREGISTRY
);
287 DPRINT("Normalized image path is '%wZ' for service '%wZ'\n", ImagePath
, ServiceName
);
289 return STATUS_SUCCESS
;
293 * IopLoadServiceModule
295 * Load a module specified by registry settings for service.
299 * Name of the service to load.
306 IopLoadServiceModule(
307 IN PUNICODE_STRING ServiceName
,
308 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
310 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
312 UNICODE_STRING ServiceImagePath
, CCSName
;
314 HANDLE CCSKey
, ServiceKey
;
317 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
319 /* FIXME: This check may be removed once the bug is fixed */
320 if (ServiceName
->Buffer
== NULL
)
322 DPRINT1("If you see this, please report to Fireball or hpoussin!\n");
323 return STATUS_UNSUCCESSFUL
;
326 if (ExpInTextModeSetup
)
328 /* We have no registry, but luckily we know where all the drivers are */
330 /* ServiceStart < 4 is all that matters */
333 /* IopNormalizeImagePath will do all of the work for us if we give it an empty string */
334 ServiceImagePath
.Length
= ServiceImagePath
.MaximumLength
= 0;
335 ServiceImagePath
.Buffer
= NULL
;
339 /* Open CurrentControlSet */
340 RtlInitUnicodeString(&CCSName
,
341 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
342 Status
= IopOpenRegistryKeyEx(&CCSKey
, NULL
, &CCSName
, KEY_READ
);
343 if (!NT_SUCCESS(Status
))
345 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
349 /* Open service key */
350 Status
= IopOpenRegistryKeyEx(&ServiceKey
, CCSKey
, ServiceName
, KEY_READ
);
351 if (!NT_SUCCESS(Status
))
353 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
359 * Get information about the service.
362 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
364 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
366 QueryTable
[0].Name
= L
"Start";
367 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
368 QueryTable
[0].EntryContext
= &ServiceStart
;
370 QueryTable
[1].Name
= L
"ImagePath";
371 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
372 QueryTable
[1].EntryContext
= &ServiceImagePath
;
374 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
375 (PWSTR
)ServiceKey
, QueryTable
, NULL
, NULL
);
380 if (!NT_SUCCESS(Status
))
382 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
388 * Normalize the image path for all later processing.
391 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
393 if (!NT_SUCCESS(Status
))
395 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
400 * Case for disabled drivers
403 if (ServiceStart
>= 4)
405 /* FIXME: Check if it is the right status code */
406 Status
= STATUS_PLUGPLAY_NO_DEVICE
;
410 DPRINT("Loading module from %wZ\n", &ServiceImagePath
);
411 Status
= MmLoadSystemImage(&ServiceImagePath
, NULL
, NULL
, 0, (PVOID
)ModuleObject
, &BaseAddress
);
412 if (NT_SUCCESS(Status
))
414 IopDisplayLoadingMessage(ServiceName
);
418 ExFreePool(ServiceImagePath
.Buffer
);
421 * Now check if the module was loaded successfully.
424 if (!NT_SUCCESS(Status
))
426 DPRINT("Module loading failed (Status %x)\n", Status
);
429 DPRINT("Module loading (Status %x)\n", Status
);
436 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry
);
439 * IopInitializeDriverModule
441 * Initalize a loaded driver.
445 * Pointer to device node.
448 * Module object representing the driver. It can be retrieve by
449 * IopLoadServiceModule.
452 * Name of the service (as in registry).
455 * Set to TRUE for file system drivers.
458 * On successful return this contains the driver object representing
463 IopInitializeDriverModule(
464 IN PDEVICE_NODE DeviceNode
,
465 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
466 IN PUNICODE_STRING ServiceName
,
467 IN BOOLEAN FileSystemDriver
,
468 OUT PDRIVER_OBJECT
*DriverObject
)
470 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
471 WCHAR NameBuffer
[MAX_PATH
];
472 UNICODE_STRING DriverName
;
473 UNICODE_STRING RegistryKey
;
474 PDRIVER_INITIALIZE DriverEntry
;
475 PDRIVER_OBJECT Driver
;
478 DriverEntry
= ModuleObject
->EntryPoint
;
480 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
482 RegistryKey
.Length
= 0;
483 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
484 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
485 if (RegistryKey
.Buffer
== NULL
)
487 return STATUS_INSUFFICIENT_RESOURCES
;
489 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
490 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
494 RtlInitUnicodeString(&RegistryKey
, NULL
);
497 /* Create ModuleName string */
498 if (ServiceName
&& ServiceName
->Length
> 0)
500 if (FileSystemDriver
== TRUE
)
501 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
503 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
505 RtlInitUnicodeString(&DriverName
, NameBuffer
);
506 DriverName
.MaximumLength
= sizeof(NameBuffer
);
508 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
510 DPRINT("Driver name: '%wZ'\n", &DriverName
);
513 DriverName
.Length
= 0;
515 Status
= IopCreateDriver(
516 DriverName
.Length
> 0 ? &DriverName
: NULL
,
521 RtlFreeUnicodeString(&RegistryKey
);
523 *DriverObject
= Driver
;
524 if (!NT_SUCCESS(Status
))
526 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status
);
530 MmFreeDriverInitialization((PLDR_DATA_TABLE_ENTRY
)Driver
->DriverSection
);
532 /* Set the driver as initialized */
533 IopReadyDeviceObjects(Driver
);
535 if (PnpSystemInit
) IopReinitializeDrivers();
537 return STATUS_SUCCESS
;
541 * IopAttachFilterDriversCallback
543 * Internal routine used by IopAttachFilterDrivers.
547 IopAttachFilterDriversCallback(
555 PDEVICE_NODE DeviceNode
= Context
;
556 UNICODE_STRING ServiceName
;
558 PLDR_DATA_TABLE_ENTRY ModuleObject
;
559 PDRIVER_OBJECT DriverObject
;
562 for (Filters
= ValueData
;
563 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
565 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
567 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
569 ServiceName
.Buffer
= Filters
;
570 ServiceName
.MaximumLength
=
571 ServiceName
.Length
= (USHORT
)wcslen(Filters
) * sizeof(WCHAR
);
573 Status
= IopGetDriverObject(&DriverObject
,
576 if (!NT_SUCCESS(Status
))
578 /* Load and initialize the filter driver */
579 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
580 if (!NT_SUCCESS(Status
))
583 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
584 FALSE
, &DriverObject
);
585 if (!NT_SUCCESS(Status
))
589 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
591 /* Remove extra reference */
592 ObDereferenceObject(DriverObject
);
595 return STATUS_SUCCESS
;
599 * IopAttachFilterDrivers
601 * Load filter drivers for specified device node.
605 * Set to TRUE for loading lower level filters or FALSE for upper
610 IopAttachFilterDrivers(
611 PDEVICE_NODE DeviceNode
,
614 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = { { NULL
, 0, NULL
, NULL
, 0, NULL
, 0 }, };
615 UNICODE_STRING Class
;
616 WCHAR ClassBuffer
[40];
617 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
618 HANDLE EnumRootKey
, SubKey
;
621 /* Open enumeration root key */
622 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
623 &EnumRoot
, KEY_READ
);
624 if (!NT_SUCCESS(Status
))
626 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
631 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
632 &DeviceNode
->InstancePath
, KEY_READ
);
633 if (!NT_SUCCESS(Status
))
635 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
636 ZwClose(EnumRootKey
);
641 * First load the device filters
643 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
645 QueryTable
[0].Name
= L
"LowerFilters";
647 QueryTable
[0].Name
= L
"UpperFilters";
648 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
650 RtlQueryRegistryValues(
658 * Now get the class GUID
661 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
662 Class
.Buffer
= ClassBuffer
;
663 QueryTable
[0].QueryRoutine
= NULL
;
664 QueryTable
[0].Name
= L
"ClassGUID";
665 QueryTable
[0].EntryContext
= &Class
;
666 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
668 Status
= RtlQueryRegistryValues(
677 ZwClose(EnumRootKey
);
680 * Load the class filter driver
682 if (NT_SUCCESS(Status
))
684 UNICODE_STRING ControlClass
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
686 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
687 &ControlClass
, KEY_READ
);
688 if (!NT_SUCCESS(Status
))
690 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
695 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
697 if (!NT_SUCCESS(Status
))
699 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
700 ZwClose(EnumRootKey
);
704 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
706 QueryTable
[0].Name
= L
"LowerFilters";
708 QueryTable
[0].Name
= L
"UpperFilters";
709 QueryTable
[0].EntryContext
= NULL
;
710 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
712 RtlQueryRegistryValues(
721 ZwClose(EnumRootKey
);
724 return STATUS_SUCCESS
;
729 MiResolveImageReferences(IN PVOID ImageBase
,
730 IN PUNICODE_STRING ImageFileDirectory
,
731 IN PUNICODE_STRING NamePrefix OPTIONAL
,
732 OUT PCHAR
*MissingApi
,
733 OUT PWCHAR
*MissingDriver
,
734 OUT PLOAD_IMPORTS
*LoadImports
);
737 // Used for images already loaded (boot drivers)
742 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry
,
743 PUNICODE_STRING FileName
,
744 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
747 UNICODE_STRING BaseName
, BaseDirectory
;
748 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
749 PCHAR MissingApiName
, Buffer
;
750 PWCHAR MissingDriverName
;
751 PVOID DriverBase
= LdrEntry
->DllBase
;
753 /* Allocate a buffer we'll use for names */
754 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
758 return STATUS_INSUFFICIENT_RESOURCES
;
761 /* Check for a separator */
762 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
767 /* Loop the path until we get to the base name */
768 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
769 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
772 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
773 BaseLength
*= sizeof(WCHAR
);
775 /* Setup the string */
776 BaseName
.Length
= (USHORT
)BaseLength
;
781 /* Otherwise, we already have a base name */
782 BaseName
.Length
= FileName
->Length
;
783 BaseName
.Buffer
= FileName
->Buffer
;
786 /* Setup the maximum length */
787 BaseName
.MaximumLength
= BaseName
.Length
;
789 /* Now compute the base directory */
790 BaseDirectory
= *FileName
;
791 BaseDirectory
.Length
-= BaseName
.Length
;
792 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
794 /* Resolve imports */
795 MissingApiName
= Buffer
;
796 Status
= MiResolveImageReferences(DriverBase
,
802 if (!NT_SUCCESS(Status
)) return Status
;
805 *ModuleObject
= LdrEntry
;
806 return STATUS_SUCCESS
;
810 * IopInitializeBuiltinDriver
812 * Initialize a driver that is already loaded in memory.
818 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
820 PDEVICE_NODE DeviceNode
;
821 PDRIVER_OBJECT DriverObject
;
823 PWCHAR FileNameWithoutPath
;
824 LPWSTR FileExtension
;
825 PUNICODE_STRING ModuleName
= &LdrEntry
->BaseDllName
;
826 UNICODE_STRING ServiceName
;
829 * Display 'Loading XXX...' message
831 IopDisplayLoadingMessage(ModuleName
);
832 InbvIndicateProgress();
835 * Generate filename without path (not needed by freeldr)
837 FileNameWithoutPath
= wcsrchr(ModuleName
->Buffer
, L
'\\');
838 if (FileNameWithoutPath
== NULL
)
840 FileNameWithoutPath
= ModuleName
->Buffer
;
844 FileNameWithoutPath
++;
848 * Strip the file extension from ServiceName
850 RtlCreateUnicodeString(&ServiceName
, FileNameWithoutPath
);
851 FileExtension
= wcsrchr(ServiceName
.Buffer
, '.');
852 if (FileExtension
!= NULL
)
854 ServiceName
.Length
-= (USHORT
)wcslen(FileExtension
) * sizeof(WCHAR
);
855 FileExtension
[0] = 0;
859 * Determine the right device object
861 /* Use IopRootDeviceNode for now */
862 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
863 if (!NT_SUCCESS(Status
))
865 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
870 * Initialize the driver
872 Status
= IopInitializeDriverModule(DeviceNode
, LdrEntry
,
873 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
875 if (!NT_SUCCESS(Status
))
877 IopFreeDeviceNode(DeviceNode
);
881 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
882 if (NT_SUCCESS(Status
))
884 Status
= IopStartDevice(DeviceNode
);
887 /* Remove extra reference from IopInitializeDriverModule */
888 ObDereferenceObject(DriverObject
);
894 * IopInitializeBootDrivers
896 * Initialize boot drivers and free memory for boot files.
907 IopInitializeBootDrivers(VOID
)
909 PLIST_ENTRY ListHead
, NextEntry
, NextEntry2
;
910 PLDR_DATA_TABLE_ENTRY LdrEntry
;
911 PDEVICE_NODE DeviceNode
;
912 PDRIVER_OBJECT DriverObject
;
913 LDR_DATA_TABLE_ENTRY ModuleObject
;
915 UNICODE_STRING DriverName
;
917 PDRIVER_INFORMATION DriverInfo
, DriverInfoTag
;
919 PBOOT_DRIVER_LIST_ENTRY BootEntry
;
920 DPRINT("IopInitializeBootDrivers()\n");
922 /* Use IopRootDeviceNode for now */
923 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, NULL
, &DeviceNode
);
924 if (!NT_SUCCESS(Status
)) return;
926 /* Setup the module object for the RAW FS Driver */
927 ModuleObject
.DllBase
= NULL
;
928 ModuleObject
.SizeOfImage
= 0;
929 ModuleObject
.EntryPoint
= RawFsDriverEntry
;
930 RtlInitUnicodeString(&DriverName
, L
"RAW");
933 Status
= IopInitializeDriverModule(DeviceNode
,
938 if (!NT_SUCCESS(Status
))
941 IopFreeDeviceNode(DeviceNode
);
945 /* Now initialize the associated device */
946 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
947 if (!NT_SUCCESS(Status
))
950 IopFreeDeviceNode(DeviceNode
);
955 Status
= IopStartDevice(DeviceNode
);
956 if (!NT_SUCCESS(Status
))
959 IopFreeDeviceNode(DeviceNode
);
963 /* Get highest group order index */
964 IopGroupIndex
= PpInitGetGroupOrderIndex(NULL
);
965 if (IopGroupIndex
== 0xFFFF) ASSERT(FALSE
);
967 /* Allocate the group table */
968 IopGroupTable
= ExAllocatePoolWithTag(PagedPool
,
969 IopGroupIndex
* sizeof(LIST_ENTRY
),
971 if (IopGroupTable
== NULL
) ASSERT(FALSE
);
973 /* Initialize the group table lists */
974 for (i
= 0; i
< IopGroupIndex
; i
++) InitializeListHead(&IopGroupTable
[i
]);
976 /* Loop the boot modules */
977 ListHead
= &KeLoaderBlock
->LoadOrderListHead
;
978 NextEntry
= ListHead
->Flink
;
979 while (ListHead
!= NextEntry
)
982 LdrEntry
= CONTAINING_RECORD(NextEntry
,
983 LDR_DATA_TABLE_ENTRY
,
986 /* Check if the DLL needs to be initialized */
987 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
989 /* Call its entrypoint */
990 MmCallDllInitialize(LdrEntry
, NULL
);
993 /* Go to the next driver */
994 NextEntry
= NextEntry
->Flink
;
997 /* Loop the boot drivers */
998 ListHead
= &KeLoaderBlock
->BootDriverListHead
;
999 NextEntry
= ListHead
->Flink
;
1000 while (ListHead
!= NextEntry
)
1003 BootEntry
= CONTAINING_RECORD(NextEntry
,
1004 BOOT_DRIVER_LIST_ENTRY
,
1007 /* Get the driver loader entry */
1008 LdrEntry
= BootEntry
->LdrEntry
;
1010 /* Allocate our internal accounting structure */
1011 DriverInfo
= ExAllocatePoolWithTag(PagedPool
,
1012 sizeof(DRIVER_INFORMATION
),
1016 /* Zero it and initialize it */
1017 RtlZeroMemory(DriverInfo
, sizeof(DRIVER_INFORMATION
));
1018 InitializeListHead(&DriverInfo
->Link
);
1019 DriverInfo
->DataTableEntry
= BootEntry
;
1021 /* Open the registry key */
1022 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
1024 &BootEntry
->RegistryPath
,
1026 if ((NT_SUCCESS(Status
)) || /* ReactOS HACK for SETUPLDR */
1027 ((KeLoaderBlock
->SetupLdrBlock
) && ((KeyHandle
= (PVOID
)1)))) // yes, it's an assignment!
1029 /* Save the handle */
1030 DriverInfo
->ServiceHandle
= KeyHandle
;
1032 /* Get the group oder index */
1033 Index
= PpInitGetGroupOrderIndex(KeyHandle
);
1035 /* Get the tag position */
1036 DriverInfo
->TagPosition
= PipGetDriverTagPriority(KeyHandle
);
1038 /* Insert it into the list, at the right place */
1039 ASSERT(Index
< IopGroupIndex
);
1040 NextEntry2
= IopGroupTable
[Index
].Flink
;
1041 while (NextEntry2
!= &IopGroupTable
[Index
])
1043 /* Get the driver info */
1044 DriverInfoTag
= CONTAINING_RECORD(NextEntry2
,
1048 /* Check if we found the right tag position */
1049 if (DriverInfoTag
->TagPosition
> DriverInfo
->TagPosition
)
1056 NextEntry2
= NextEntry2
->Flink
;
1059 /* Insert us right before the next entry */
1060 NextEntry2
= NextEntry2
->Blink
;
1061 InsertHeadList(NextEntry2
, &DriverInfo
->Link
);
1065 /* Go to the next driver */
1066 NextEntry
= NextEntry
->Flink
;
1069 /* Loop each group index */
1070 for (i
= 0; i
< IopGroupIndex
; i
++)
1072 /* Loop each group table */
1073 NextEntry
= IopGroupTable
[i
].Flink
;
1074 while (NextEntry
!= &IopGroupTable
[i
])
1077 DriverInfo
= CONTAINING_RECORD(NextEntry
,
1081 /* Get the driver loader entry */
1082 LdrEntry
= DriverInfo
->DataTableEntry
->LdrEntry
;
1085 IopInitializeBuiltinDriver(LdrEntry
);
1088 NextEntry
= NextEntry
->Flink
;
1092 /* In old ROS, the loader list became empty after this point. Simulate. */
1093 InitializeListHead(&KeLoaderBlock
->LoadOrderListHead
);
1099 IopInitializeSystemDrivers(VOID
)
1101 PUNICODE_STRING
*DriverList
, *SavedList
;
1103 /* No system drivers on the boot cd */
1104 if (KeLoaderBlock
->SetupLdrBlock
) return;
1106 /* Get the driver list */
1107 SavedList
= DriverList
= CmGetSystemDriverList();
1113 /* Load the driver */
1114 ZwLoadDriver(*DriverList
);
1116 /* Free the entry */
1117 RtlFreeUnicodeString(*DriverList
);
1118 ExFreePool(*DriverList
);
1121 InbvIndicateProgress();
1126 ExFreePool(SavedList
);
1132 * Unloads a device driver.
1136 * Name of the service to unload (registry key).
1139 * Whether to unload Plug & Plug or only legacy drivers. If this
1140 * parameter is set to FALSE, the routine will unload only legacy
1147 * Guard the whole function by SEH.
1151 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1153 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1154 UNICODE_STRING ImagePath
;
1155 UNICODE_STRING ServiceName
;
1156 UNICODE_STRING ObjectName
;
1157 PDRIVER_OBJECT DriverObject
;
1158 PDEVICE_OBJECT DeviceObject
;
1159 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1160 LOAD_UNLOAD_PARAMS LoadParams
;
1163 BOOLEAN SafeToUnload
= TRUE
;
1165 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1170 * Get the service name from the registry key name
1173 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1175 Start
= DriverServiceName
->Buffer
;
1179 RtlInitUnicodeString(&ServiceName
, Start
);
1182 * Construct the driver object name
1185 ObjectName
.Length
= ((USHORT
)wcslen(Start
) + 8) * sizeof(WCHAR
);
1186 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1187 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1188 if (!ObjectName
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1189 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1190 memcpy(ObjectName
.Buffer
+ 8, Start
, ObjectName
.Length
- 8 * sizeof(WCHAR
));
1191 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1194 * Find the driver object
1196 Status
= ObReferenceObjectByName(&ObjectName
,
1203 (PVOID
*)&DriverObject
);
1205 if (!NT_SUCCESS(Status
))
1207 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName
);
1208 ExFreePool(ObjectName
.Buffer
);
1213 * Free the buffer for driver object name
1215 ExFreePool(ObjectName
.Buffer
);
1217 /* Check that driver is not already unloading */
1218 if (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
)
1220 DPRINT1("Driver deletion pending\n");
1221 ObDereferenceObject(DriverObject
);
1222 return STATUS_DELETE_PENDING
;
1226 * Get path of service...
1229 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1231 RtlInitUnicodeString(&ImagePath
, NULL
);
1233 QueryTable
[0].Name
= L
"ImagePath";
1234 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1235 QueryTable
[0].EntryContext
= &ImagePath
;
1237 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1238 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1240 if (!NT_SUCCESS(Status
))
1242 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1243 ObDereferenceObject(DriverObject
);
1248 * Normalize the image path for all later processing.
1251 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1253 if (!NT_SUCCESS(Status
))
1255 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1256 ObDereferenceObject(DriverObject
);
1261 * Free the service path
1264 ExFreePool(ImagePath
.Buffer
);
1267 * Unload the module and release the references to the device object
1270 /* Call the load/unload routine, depending on current process */
1271 if (DriverObject
->DriverUnload
&& DriverObject
->DriverSection
)
1273 /* Loop through each device object of the driver
1274 and set DOE_UNLOAD_PENDING flag */
1275 DeviceObject
= DriverObject
->DeviceObject
;
1276 while (DeviceObject
)
1278 /* Set the unload pending flag for the device */
1279 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1280 DeviceExtension
->ExtensionFlags
|= DOE_UNLOAD_PENDING
;
1282 /* Make sure there are no attached devices or no reference counts */
1283 if ((DeviceObject
->ReferenceCount
) || (DeviceObject
->AttachedDevice
))
1285 /* Not safe to unload */
1286 DPRINT1("Drivers device object is referenced or has attached devices\n");
1288 SafeToUnload
= FALSE
;
1291 DeviceObject
= DeviceObject
->NextDevice
;
1294 /* If not safe to unload, then return success */
1297 ObDereferenceObject(DriverObject
);
1298 return STATUS_SUCCESS
;
1301 DPRINT1("Unloading driver '%wZ' (manual)\n", &DriverObject
->DriverName
);
1303 /* Set the unload invoked flag */
1304 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
1306 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1308 /* Just call right away */
1309 (*DriverObject
->DriverUnload
)(DriverObject
);
1313 /* Load/Unload must be called from system process */
1315 /* Prepare parameters block */
1316 LoadParams
.DriverObject
= DriverObject
;
1317 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1319 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1320 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1321 (PVOID
)&LoadParams
);
1324 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1326 /* And wait when it completes */
1327 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1331 /* Mark the driver object temporary, so it could be deleted later */
1332 ObMakeTemporaryObject(DriverObject
);
1334 /* Dereference it 2 times */
1335 ObDereferenceObject(DriverObject
);
1336 ObDereferenceObject(DriverObject
);
1338 return STATUS_SUCCESS
;
1342 DPRINT1("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject
->DriverName
);
1344 /* Dereference one time (refd inside this function) */
1345 ObDereferenceObject(DriverObject
);
1347 /* Return unloading failure */
1348 return STATUS_INVALID_DEVICE_REQUEST
;
1354 IopReinitializeDrivers(VOID
)
1356 PDRIVER_REINIT_ITEM ReinitItem
;
1359 /* Get the first entry and start looping */
1360 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1361 &DriverReinitListLock
);
1365 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1367 /* Increment reinitialization counter */
1368 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1370 /* Remove the device object flag */
1371 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1373 /* Call the routine */
1374 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1375 ReinitItem
->Context
,
1376 ReinitItem
->DriverObject
->
1377 DriverExtension
->Count
);
1379 /* Free the entry */
1382 /* Move to the next one */
1383 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1384 &DriverReinitListLock
);
1390 IopReinitializeBootDrivers(VOID
)
1392 PDRIVER_REINIT_ITEM ReinitItem
;
1395 /* Get the first entry and start looping */
1396 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1397 &DriverBootReinitListLock
);
1401 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1403 /* Increment reinitialization counter */
1404 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1406 /* Remove the device object flag */
1407 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1409 /* Call the routine */
1410 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1411 ReinitItem
->Context
,
1412 ReinitItem
->DriverObject
->
1413 DriverExtension
->Count
);
1415 /* Free the entry */
1418 /* Move to the next one */
1419 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1420 &DriverBootReinitListLock
);
1426 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1427 IN PDRIVER_INITIALIZE InitializationFunction
,
1428 IN PUNICODE_STRING RegistryPath
,
1429 PLDR_DATA_TABLE_ENTRY ModuleObject
,
1430 OUT PDRIVER_OBJECT
*pDriverObject
)
1432 WCHAR NameBuffer
[100];
1434 UNICODE_STRING LocalDriverName
;
1436 OBJECT_ATTRIBUTES ObjectAttributes
;
1438 PDRIVER_OBJECT DriverObject
;
1439 UNICODE_STRING ServiceKeyName
;
1441 ULONG i
, RetryCount
= 0;
1444 /* First, create a unique name for the driver if we don't have one */
1447 /* Create a random name and set up the string*/
1448 NameLength
= (USHORT
)swprintf(NameBuffer
,
1451 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1452 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1453 LocalDriverName
.Buffer
= NameBuffer
;
1457 /* So we can avoid another code path, use a local var */
1458 LocalDriverName
= *DriverName
;
1461 /* Initialize the Attributes */
1462 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1463 InitializeObjectAttributes(&ObjectAttributes
,
1465 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1469 /* Create the Object */
1470 Status
= ObCreateObject(KernelMode
,
1478 (PVOID
*)&DriverObject
);
1479 if (!NT_SUCCESS(Status
)) return Status
;
1481 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1483 /* Set up the Object */
1484 RtlZeroMemory(DriverObject
, ObjectSize
);
1485 DriverObject
->Type
= IO_TYPE_DRIVER
;
1486 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1487 DriverObject
->Flags
= DRVO_LEGACY_DRIVER
;//DRVO_BUILTIN_DRIVER;
1488 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1489 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1490 DriverObject
->DriverInit
= InitializationFunction
;
1491 DriverObject
->DriverSection
= ModuleObject
;
1492 /* Loop all Major Functions */
1493 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1495 /* Invalidate each function */
1496 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1499 /* Set up the service key name buffer */
1500 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1501 LocalDriverName
.Length
+
1504 if (!ServiceKeyName
.Buffer
)
1507 ObMakeTemporaryObject(DriverObject
);
1508 ObDereferenceObject(DriverObject
);
1509 return STATUS_INSUFFICIENT_RESOURCES
;
1512 /* Fill out the key data and copy the buffer */
1513 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1514 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1515 RtlCopyMemory(ServiceKeyName
.Buffer
,
1516 LocalDriverName
.Buffer
,
1517 LocalDriverName
.Length
);
1519 /* Null-terminate it and set it */
1520 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1521 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1523 /* Also store it in the Driver Object. This is a bit of a hack. */
1524 RtlCopyMemory(&DriverObject
->DriverName
,
1526 sizeof(UNICODE_STRING
));
1528 /* Add the Object and get its handle */
1529 Status
= ObInsertObject(DriverObject
,
1536 /* Eliminate small possibility when this function is called more than
1537 once in a row, and KeTickCount doesn't get enough time to change */
1538 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1544 if (!NT_SUCCESS(Status
)) return Status
;
1546 /* Now reference it */
1547 Status
= ObReferenceObjectByHandle(hDriver
,
1551 (PVOID
*)&DriverObject
,
1554 /* Close the extra handle */
1557 if (!NT_SUCCESS(Status
))
1560 ObMakeTemporaryObject(DriverObject
);
1561 ObDereferenceObject(DriverObject
);
1565 DriverObject
->HardwareDatabase
= &IopHardwareDatabaseKey
;
1566 DriverObject
->DriverStart
= ModuleObject
? ModuleObject
->DllBase
: 0;
1567 DriverObject
->DriverSize
= ModuleObject
? ModuleObject
->SizeOfImage
: 0;
1569 /* Finally, call its init function */
1570 DPRINT("RegistryKey: %wZ\n", RegistryPath
);
1571 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction
);
1572 Status
= (*InitializationFunction
)(DriverObject
, RegistryPath
);
1573 if (!NT_SUCCESS(Status
))
1575 /* If it didn't work, then kill the object */
1576 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName
, Status
);
1577 DriverObject
->DriverSection
= NULL
;
1578 ObMakeTemporaryObject(DriverObject
);
1579 ObDereferenceObject(DriverObject
);
1584 /* Returns to caller the object */
1585 *pDriverObject
= DriverObject
;
1588 /* Loop all Major Functions */
1589 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1592 * Make sure the driver didn't set any dispatch entry point to NULL!
1593 * Doing so is illegal; drivers shouldn't touch entry points they
1597 /* Check if it did so anyway */
1598 if (!DriverObject
->MajorFunction
[i
])
1600 /* Print a warning in the debug log */
1601 DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%d] to NULL!\n",
1602 &DriverObject
->DriverName
, i
);
1605 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1609 /* Return the Status */
1613 /* PUBLIC FUNCTIONS ***********************************************************/
1620 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1621 IN PDRIVER_INITIALIZE InitializationFunction
)
1623 PDRIVER_OBJECT DriverObject
;
1624 return IopCreateDriver(DriverName
, InitializationFunction
, NULL
, NULL
, &DriverObject
);
1632 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1634 /* Simply dereference the Object */
1635 ObDereferenceObject(DriverObject
);
1643 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1644 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1647 PDRIVER_REINIT_ITEM ReinitItem
;
1649 /* Allocate the entry */
1650 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1651 sizeof(DRIVER_REINIT_ITEM
),
1653 if (!ReinitItem
) return;
1656 ReinitItem
->DriverObject
= DriverObject
;
1657 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1658 ReinitItem
->Context
= Context
;
1660 /* Set the Driver Object flag and insert the entry into the list */
1661 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1662 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1663 &ReinitItem
->ItemEntry
,
1664 &DriverBootReinitListLock
);
1672 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1673 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1676 PDRIVER_REINIT_ITEM ReinitItem
;
1678 /* Allocate the entry */
1679 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1680 sizeof(DRIVER_REINIT_ITEM
),
1682 if (!ReinitItem
) return;
1685 ReinitItem
->DriverObject
= DriverObject
;
1686 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1687 ReinitItem
->Context
= Context
;
1689 /* Set the Driver Object flag and insert the entry into the list */
1690 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1691 ExInterlockedInsertTailList(&DriverReinitListHead
,
1692 &ReinitItem
->ItemEntry
,
1693 &DriverReinitListLock
);
1701 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1702 IN PVOID ClientIdentificationAddress
,
1703 IN ULONG DriverObjectExtensionSize
,
1704 OUT PVOID
*DriverObjectExtension
)
1707 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1708 BOOLEAN Inserted
= FALSE
;
1710 /* Assume failure */
1711 *DriverObjectExtension
= NULL
;
1713 /* Allocate the extension */
1714 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1715 sizeof(IO_CLIENT_EXTENSION
) +
1716 DriverObjectExtensionSize
,
1717 TAG_DRIVER_EXTENSION
);
1718 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1720 /* Clear the extension for teh caller */
1721 RtlZeroMemory(NewDriverExtension
,
1722 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1725 OldIrql
= KeRaiseIrqlToDpcLevel();
1727 /* Fill out the extension */
1728 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1730 /* Loop the current extensions */
1731 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1732 ClientDriverExtension
;
1733 while (DriverExtensions
)
1735 /* Check if the identifier matches */
1736 if (DriverExtensions
->ClientIdentificationAddress
==
1737 ClientIdentificationAddress
)
1739 /* We have a collision, break out */
1743 /* Go to the next one */
1744 DriverExtensions
= DriverExtensions
->NextExtension
;
1747 /* Check if we didn't collide */
1748 if (!DriverExtensions
)
1750 /* Link this one in */
1751 NewDriverExtension
->NextExtension
=
1752 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1753 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1758 /* Release the lock */
1759 KeLowerIrql(OldIrql
);
1761 /* Check if insertion failed */
1764 /* Free the entry and fail */
1765 ExFreePool(NewDriverExtension
);
1766 return STATUS_OBJECT_NAME_COLLISION
;
1769 /* Otherwise, return the pointer */
1770 *DriverObjectExtension
= NewDriverExtension
+ 1;
1771 return STATUS_SUCCESS
;
1779 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1780 IN PVOID ClientIdentificationAddress
)
1783 PIO_CLIENT_EXTENSION DriverExtensions
;
1786 OldIrql
= KeRaiseIrqlToDpcLevel();
1788 /* Loop the list until we find the right one */
1789 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1790 while (DriverExtensions
)
1792 /* Check for a match */
1793 if (DriverExtensions
->ClientIdentificationAddress
==
1794 ClientIdentificationAddress
)
1801 DriverExtensions
= DriverExtensions
->NextExtension
;
1805 KeLowerIrql(OldIrql
);
1807 /* Return nothing or the extension */
1808 if (!DriverExtensions
) return NULL
;
1809 return DriverExtensions
+ 1;
1813 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams
)
1815 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1816 UNICODE_STRING ImagePath
;
1817 UNICODE_STRING ServiceName
;
1820 PDEVICE_NODE DeviceNode
;
1821 PDRIVER_OBJECT DriverObject
;
1822 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1826 /* Check if it's an unload request */
1827 if (LoadParams
->DriverObject
)
1829 (*LoadParams
->DriverObject
->DriverUnload
)(LoadParams
->DriverObject
);
1831 /* Return success and signal the event */
1832 LoadParams
->Status
= STATUS_SUCCESS
;
1833 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1837 RtlInitUnicodeString(&ImagePath
, NULL
);
1840 * Get the service name from the registry key name.
1842 ASSERT(LoadParams
->ServiceName
->Length
>= sizeof(WCHAR
));
1844 ServiceName
= *LoadParams
->ServiceName
;
1845 cur
= LoadParams
->ServiceName
->Buffer
+
1846 (LoadParams
->ServiceName
->Length
/ sizeof(WCHAR
)) - 1;
1847 while (LoadParams
->ServiceName
->Buffer
!= cur
)
1851 ServiceName
.Buffer
= cur
+ 1;
1852 ServiceName
.Length
= LoadParams
->ServiceName
->Length
-
1853 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1854 (ULONG_PTR
)LoadParams
->ServiceName
->Buffer
);
1864 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1866 RtlInitUnicodeString(&ImagePath
, NULL
);
1868 QueryTable
[0].Name
= L
"Type";
1869 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1870 QueryTable
[0].EntryContext
= &Type
;
1872 QueryTable
[1].Name
= L
"ImagePath";
1873 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1874 QueryTable
[1].EntryContext
= &ImagePath
;
1876 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1877 LoadParams
->ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1879 if (!NT_SUCCESS(Status
))
1881 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1882 if (ImagePath
.Buffer
)
1883 ExFreePool(ImagePath
.Buffer
);
1884 LoadParams
->Status
= Status
;
1885 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1890 * Normalize the image path for all later processing.
1893 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1895 if (!NT_SUCCESS(Status
))
1897 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1898 LoadParams
->Status
= Status
;
1899 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1903 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1904 DPRINT("Type: %lx\n", Type
);
1906 /* Get existing DriverObject pointer (in case the driver has
1907 already been loaded and initialized) */
1908 Status
= IopGetDriverObject(
1911 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1912 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */));
1914 if (!NT_SUCCESS(Status
))
1917 * Load the driver module
1920 DPRINT("Loading module from %wZ\n", &ImagePath
);
1921 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, &BaseAddress
);
1923 if (!NT_SUCCESS(Status
) && Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1925 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1926 LoadParams
->Status
= Status
;
1927 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1932 * Initialize the driver module if it's loaded for the first time
1934 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1936 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1938 if (!NT_SUCCESS(Status
))
1940 DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1941 MmUnloadSystemImage(ModuleObject
);
1942 LoadParams
->Status
= Status
;
1943 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1947 IopDisplayLoadingMessage(&DeviceNode
->ServiceName
);
1949 Status
= IopInitializeDriverModule(
1952 &DeviceNode
->ServiceName
,
1953 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1954 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1957 if (!NT_SUCCESS(Status
))
1959 DPRINT1("IopInitializeDriver() failed (Status %lx)\n", Status
);
1960 MmUnloadSystemImage(ModuleObject
);
1961 IopFreeDeviceNode(DeviceNode
);
1962 LoadParams
->Status
= Status
;
1963 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1967 /* Initialize and start device */
1968 IopInitializeDevice(DeviceNode
, DriverObject
);
1969 Status
= IopStartDevice(DeviceNode
);
1974 DPRINT("DriverObject already exist in ObjectManager\n");
1975 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1977 /* IopGetDriverObject references the DriverObject, so dereference it */
1978 ObDereferenceObject(DriverObject
);
1981 /* Pass status to the caller and signal the event */
1982 LoadParams
->Status
= Status
;
1983 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1989 * Loads a device driver.
1993 * Name of the service to load (registry key).
2002 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
2004 UNICODE_STRING CapturedDriverServiceName
= { 0, 0, NULL
};
2005 KPROCESSOR_MODE PreviousMode
;
2006 LOAD_UNLOAD_PARAMS LoadParams
;
2011 PreviousMode
= KeGetPreviousMode();
2014 * Check security privileges
2017 /* FIXME: Uncomment when privileges will be correctly implemented. */
2019 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
2021 DPRINT("Privilege not held\n");
2022 return STATUS_PRIVILEGE_NOT_HELD
;
2026 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
2029 if (!NT_SUCCESS(Status
))
2034 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
2036 LoadParams
.ServiceName
= &CapturedDriverServiceName
;
2037 LoadParams
.DriverObject
= NULL
;
2038 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
2040 /* Call the load/unload routine, depending on current process */
2041 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
2043 /* Just call right away */
2044 IopLoadUnloadDriver(&LoadParams
);
2048 /* Load/Unload must be called from system process */
2049 ExInitializeWorkItem(&LoadParams
.WorkItem
,
2050 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
2051 (PVOID
)&LoadParams
);
2054 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
2056 /* And wait when it completes */
2057 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
2061 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
2064 return LoadParams
.Status
;
2070 * Unloads a legacy device driver.
2074 * Name of the service to unload (registry key).
2084 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
2086 return IopUnloadDriver(DriverServiceName
, FALSE
);