2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/driver.c
5 * PURPOSE: Driver Object Management
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Filip Navara (navaraf@reactos.org)
8 * Hervé Poussineau (hpoussin@reactos.org)
11 /* INCLUDES *******************************************************************/
17 /* GLOBALS ********************************************************************/
19 LIST_ENTRY DriverReinitListHead
;
20 KSPIN_LOCK DriverReinitListLock
;
21 PLIST_ENTRY DriverReinitTailEntry
;
23 PLIST_ENTRY DriverBootReinitTailEntry
;
24 LIST_ENTRY DriverBootReinitListHead
;
25 KSPIN_LOCK DriverBootReinitListLock
;
27 UNICODE_STRING IopHardwareDatabaseKey
=
28 RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
30 POBJECT_TYPE IoDriverObjectType
= NULL
;
32 #define TAG_RTLREGISTRY 'vrqR'
34 extern BOOLEAN ExpInTextModeSetup
;
35 extern BOOLEAN PnpSystemInit
;
38 PLIST_ENTRY IopGroupTable
;
40 /* PRIVATE FUNCTIONS **********************************************************/
43 IopInvalidDeviceRequest(
44 PDEVICE_OBJECT DeviceObject
,
47 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
48 Irp
->IoStatus
.Information
= 0;
49 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
50 return STATUS_INVALID_DEVICE_REQUEST
;
55 IopDeleteDriver(IN PVOID ObjectBody
)
57 PDRIVER_OBJECT DriverObject
= ObjectBody
;
58 PIO_CLIENT_EXTENSION DriverExtension
, NextDriverExtension
;
61 /* Get the extension and loop them */
62 DriverExtension
= IoGetDrvObjExtension(DriverObject
)->
63 ClientDriverExtension
;
64 while (DriverExtension
)
66 /* Get the next one */
67 NextDriverExtension
= DriverExtension
->NextExtension
;
68 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
71 DriverExtension
= NextDriverExtension
;
74 /* Check if the driver image is still loaded */
75 if (DriverObject
->DriverSection
)
78 MmUnloadSystemImage(DriverObject
->DriverSection
);
81 /* Check if it has a name */
82 if (DriverObject
->DriverName
.Buffer
)
85 ExFreePool(DriverObject
->DriverName
.Buffer
);
88 #if 0 /* See a bit of hack in IopCreateDriver */
89 /* Check if it has a service key name */
90 if (DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
)
93 ExFreePool(DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
);
100 PDRIVER_OBJECT
*DriverObject
,
101 PUNICODE_STRING ServiceName
,
104 PDRIVER_OBJECT Object
;
105 WCHAR NameBuffer
[MAX_PATH
];
106 UNICODE_STRING DriverName
;
109 DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
110 DriverObject
, ServiceName
, FileSystem
);
112 *DriverObject
= NULL
;
114 /* Create ModuleName string */
115 if (ServiceName
== NULL
|| ServiceName
->Buffer
== NULL
)
116 /* We don't know which DriverObject we have to open */
117 return STATUS_INVALID_PARAMETER_2
;
119 DriverName
.Buffer
= NameBuffer
;
120 DriverName
.Length
= 0;
121 DriverName
.MaximumLength
= sizeof(NameBuffer
);
123 if (FileSystem
== TRUE
)
124 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
126 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
127 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
129 DPRINT("Driver name: '%wZ'\n", &DriverName
);
131 /* Open driver object */
132 Status
= ObReferenceObjectByName(
134 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, /* Attributes */
135 NULL
, /* PassedAccessState */
136 0, /* DesiredAccess */
139 NULL
, /* ParseContext */
142 if (!NT_SUCCESS(Status
))
144 DPRINT("Failed to reference driver object, status=0x%08x\n", Status
);
148 *DriverObject
= Object
;
150 DPRINT("Driver Object: %p\n", Object
);
152 return STATUS_SUCCESS
;
157 * TRUE if String2 contains String1 as a suffix.
161 IopSuffixUnicodeString(
162 IN PCUNICODE_STRING String1
,
163 IN PCUNICODE_STRING String2
)
169 if (String2
->Length
< String1
->Length
)
172 Length
= String1
->Length
/ 2;
173 pc1
= String1
->Buffer
;
174 pc2
= &String2
->Buffer
[String2
->Length
/ sizeof(WCHAR
) - Length
];
180 if( *pc1
++ != *pc2
++ )
189 * IopDisplayLoadingMessage
191 * Display 'Loading XXX...' message.
197 IopDisplayLoadingMessage(PUNICODE_STRING ServiceName
)
199 CHAR TextBuffer
[256];
200 UNICODE_STRING DotSys
= RTL_CONSTANT_STRING(L
".SYS");
202 if (ExpInTextModeSetup
) return;
203 if (!KeLoaderBlock
) return;
204 RtlUpcaseUnicodeString(ServiceName
, ServiceName
, FALSE
);
205 snprintf(TextBuffer
, sizeof(TextBuffer
),
206 "%s%sSystem32\\Drivers\\%wZ%s\n",
207 KeLoaderBlock
->ArcBootDeviceName
,
208 KeLoaderBlock
->NtBootPathName
,
210 IopSuffixUnicodeString(&DotSys
, ServiceName
) ? "" : ".SYS");
211 HalDisplayString(TextBuffer
);
215 * IopNormalizeImagePath
217 * Normalize an image path to contain complete path.
221 * The input path and on exit the result path. ImagePath.Buffer
222 * must be allocated by ExAllocatePool on input. Caller is responsible
223 * for freeing the buffer when it's no longer needed.
226 * Name of the service that ImagePath belongs to.
232 * The input image path isn't freed on error.
236 IopNormalizeImagePath(
237 IN OUT PUNICODE_STRING ImagePath
,
238 IN PUNICODE_STRING ServiceName
)
240 UNICODE_STRING InputImagePath
;
242 DPRINT("Normalizing image path '%wZ' for service '%wZ'\n", ImagePath
, ServiceName
);
247 sizeof(UNICODE_STRING
));
249 if (InputImagePath
.Length
== 0)
251 ImagePath
->Length
= 0;
252 ImagePath
->MaximumLength
=
253 (33 * sizeof(WCHAR
)) + ServiceName
->Length
+ sizeof(UNICODE_NULL
);
254 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
255 if (ImagePath
->Buffer
== NULL
)
256 return STATUS_NO_MEMORY
;
258 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\system32\\drivers\\");
259 RtlAppendUnicodeStringToString(ImagePath
, ServiceName
);
260 RtlAppendUnicodeToString(ImagePath
, L
".sys");
262 if (InputImagePath
.Buffer
[0] != L
'\\')
264 ImagePath
->Length
= 0;
265 ImagePath
->MaximumLength
=
266 12 * sizeof(WCHAR
) + InputImagePath
.Length
+ sizeof(UNICODE_NULL
);
267 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
268 if (ImagePath
->Buffer
== NULL
)
269 return STATUS_NO_MEMORY
;
271 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\");
272 RtlAppendUnicodeStringToString(ImagePath
, &InputImagePath
);
274 /* Free caller's string */
275 ExFreePoolWithTag(InputImagePath
.Buffer
, TAG_RTLREGISTRY
);
278 DPRINT("Normalized image path is '%wZ' for service '%wZ'\n", ImagePath
, ServiceName
);
280 return STATUS_SUCCESS
;
284 * IopLoadServiceModule
286 * Load a module specified by registry settings for service.
290 * Name of the service to load.
297 IopLoadServiceModule(
298 IN PUNICODE_STRING ServiceName
,
299 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
301 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
303 UNICODE_STRING ServiceImagePath
, CCSName
;
305 HANDLE CCSKey
, ServiceKey
;
308 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
310 /* FIXME: This check may be removed once the bug is fixed */
311 if (ServiceName
->Buffer
== NULL
)
313 DPRINT1("If you see this, please report to Fireball or hpoussin!\n");
314 return STATUS_UNSUCCESSFUL
;
317 if (ExpInTextModeSetup
)
319 /* We have no registry, but luckily we know where all the drivers are */
321 /* ServiceStart < 4 is all that matters */
324 /* IopNormalizeImagePath will do all of the work for us if we give it an empty string */
325 ServiceImagePath
.Length
= ServiceImagePath
.MaximumLength
= 0;
326 ServiceImagePath
.Buffer
= NULL
;
330 /* Open CurrentControlSet */
331 RtlInitUnicodeString(&CCSName
,
332 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
333 Status
= IopOpenRegistryKeyEx(&CCSKey
, NULL
, &CCSName
, KEY_READ
);
334 if (!NT_SUCCESS(Status
))
336 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
340 /* Open service key */
341 Status
= IopOpenRegistryKeyEx(&ServiceKey
, CCSKey
, ServiceName
, KEY_READ
);
342 if (!NT_SUCCESS(Status
))
344 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
350 * Get information about the service.
353 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
355 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
357 QueryTable
[0].Name
= L
"Start";
358 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
359 QueryTable
[0].EntryContext
= &ServiceStart
;
361 QueryTable
[1].Name
= L
"ImagePath";
362 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
363 QueryTable
[1].EntryContext
= &ServiceImagePath
;
365 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
366 (PWSTR
)ServiceKey
, QueryTable
, NULL
, NULL
);
371 if (!NT_SUCCESS(Status
))
373 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
379 * Normalize the image path for all later processing.
382 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
384 if (!NT_SUCCESS(Status
))
386 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
391 * Case for disabled drivers
394 if (ServiceStart
>= 4)
396 /* FIXME: Check if it is the right status code */
397 Status
= STATUS_PLUGPLAY_NO_DEVICE
;
401 DPRINT("Loading module from %wZ\n", &ServiceImagePath
);
402 Status
= MmLoadSystemImage(&ServiceImagePath
, NULL
, NULL
, 0, (PVOID
)ModuleObject
, &BaseAddress
);
403 if (NT_SUCCESS(Status
))
405 IopDisplayLoadingMessage(ServiceName
);
409 ExFreePool(ServiceImagePath
.Buffer
);
412 * Now check if the module was loaded successfully.
415 if (!NT_SUCCESS(Status
))
417 DPRINT("Module loading failed (Status %x)\n", Status
);
420 DPRINT("Module loading (Status %x)\n", Status
);
426 * IopInitializeDriverModule
428 * Initalize a loaded driver.
432 * Pointer to device node.
435 * Module object representing the driver. It can be retrieve by
436 * IopLoadServiceModule.
439 * Name of the service (as in registry).
442 * Set to TRUE for file system drivers.
445 * On successful return this contains the driver object representing
450 IopInitializeDriverModule(
451 IN PDEVICE_NODE DeviceNode
,
452 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
453 IN PUNICODE_STRING ServiceName
,
454 IN BOOLEAN FileSystemDriver
,
455 OUT PDRIVER_OBJECT
*DriverObject
)
457 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
458 WCHAR NameBuffer
[MAX_PATH
];
459 UNICODE_STRING DriverName
;
460 UNICODE_STRING RegistryKey
;
461 PDRIVER_INITIALIZE DriverEntry
;
462 PDRIVER_OBJECT Driver
;
465 DriverEntry
= ModuleObject
->EntryPoint
;
467 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
469 RegistryKey
.Length
= 0;
470 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
471 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
472 if (RegistryKey
.Buffer
== NULL
)
474 return STATUS_INSUFFICIENT_RESOURCES
;
476 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
477 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
481 RtlInitUnicodeString(&RegistryKey
, NULL
);
484 /* Create ModuleName string */
485 if (ServiceName
&& ServiceName
->Length
> 0)
487 if (FileSystemDriver
== TRUE
)
488 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
490 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
492 RtlInitUnicodeString(&DriverName
, NameBuffer
);
493 DriverName
.MaximumLength
= sizeof(NameBuffer
);
495 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
497 DPRINT("Driver name: '%wZ'\n", &DriverName
);
500 DriverName
.Length
= 0;
502 Status
= IopCreateDriver(
503 DriverName
.Length
> 0 ? &DriverName
: NULL
,
508 RtlFreeUnicodeString(&RegistryKey
);
510 *DriverObject
= Driver
;
511 if (!NT_SUCCESS(Status
))
513 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status
);
517 /* Set the driver as initialized */
518 IopReadyDeviceObjects(Driver
);
520 if (PnpSystemInit
) IopReinitializeDrivers();
522 return STATUS_SUCCESS
;
526 * IopAttachFilterDriversCallback
528 * Internal routine used by IopAttachFilterDrivers.
532 IopAttachFilterDriversCallback(
540 PDEVICE_NODE DeviceNode
= Context
;
541 UNICODE_STRING ServiceName
;
543 PLDR_DATA_TABLE_ENTRY ModuleObject
;
544 PDRIVER_OBJECT DriverObject
;
547 for (Filters
= ValueData
;
548 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
550 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
552 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
553 ServiceName
.Buffer
= Filters
;
554 ServiceName
.MaximumLength
=
555 ServiceName
.Length
= (USHORT
)wcslen(Filters
) * sizeof(WCHAR
);
557 /* Load and initialize the filter driver */
558 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
559 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
561 if (!NT_SUCCESS(Status
))
564 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
565 FALSE
, &DriverObject
);
566 if (!NT_SUCCESS(Status
))
571 /* get existing DriverObject pointer */
572 Status
= IopGetDriverObject(
576 if (!NT_SUCCESS(Status
))
578 DPRINT1("IopGetDriverObject() returned status 0x%08x!\n", Status
);
583 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
584 if (!NT_SUCCESS(Status
))
588 return STATUS_SUCCESS
;
592 * IopAttachFilterDrivers
594 * Load filter drivers for specified device node.
598 * Set to TRUE for loading lower level filters or FALSE for upper
603 IopAttachFilterDrivers(
604 PDEVICE_NODE DeviceNode
,
607 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = { { NULL
, 0, NULL
, NULL
, 0, NULL
, 0 }, };
608 UNICODE_STRING Class
;
609 WCHAR ClassBuffer
[40];
610 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
611 HANDLE EnumRootKey
, SubKey
;
614 /* Open enumeration root key */
615 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
616 &EnumRoot
, KEY_READ
);
617 if (!NT_SUCCESS(Status
))
619 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
624 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
625 &DeviceNode
->InstancePath
, KEY_READ
);
626 if (!NT_SUCCESS(Status
))
628 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
629 ZwClose(EnumRootKey
);
634 * First load the device filters
636 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
638 QueryTable
[0].Name
= L
"LowerFilters";
640 QueryTable
[0].Name
= L
"UpperFilters";
641 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
643 RtlQueryRegistryValues(
651 * Now get the class GUID
654 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
655 Class
.Buffer
= ClassBuffer
;
656 QueryTable
[0].QueryRoutine
= NULL
;
657 QueryTable
[0].Name
= L
"ClassGUID";
658 QueryTable
[0].EntryContext
= &Class
;
659 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
661 Status
= RtlQueryRegistryValues(
670 ZwClose(EnumRootKey
);
673 * Load the class filter driver
675 if (NT_SUCCESS(Status
))
677 UNICODE_STRING ControlClass
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
679 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
680 &ControlClass
, KEY_READ
);
681 if (!NT_SUCCESS(Status
))
683 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
688 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
690 if (!NT_SUCCESS(Status
))
692 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
693 ZwClose(EnumRootKey
);
697 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
699 QueryTable
[0].Name
= L
"LowerFilters";
701 QueryTable
[0].Name
= L
"UpperFilters";
702 QueryTable
[0].EntryContext
= NULL
;
703 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
705 RtlQueryRegistryValues(
714 ZwClose(EnumRootKey
);
717 return STATUS_SUCCESS
;
722 MiResolveImageReferences(IN PVOID ImageBase
,
723 IN PUNICODE_STRING ImageFileDirectory
,
724 IN PUNICODE_STRING NamePrefix OPTIONAL
,
725 OUT PCHAR
*MissingApi
,
726 OUT PWCHAR
*MissingDriver
,
727 OUT PLOAD_IMPORTS
*LoadImports
);
730 // Used for images already loaded (boot drivers)
735 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry
,
736 PUNICODE_STRING FileName
,
737 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
740 UNICODE_STRING BaseName
, BaseDirectory
;
741 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
742 PCHAR MissingApiName
, Buffer
;
743 PWCHAR MissingDriverName
;
744 PVOID DriverBase
= LdrEntry
->DllBase
;
746 /* Allocate a buffer we'll use for names */
747 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
751 return STATUS_INSUFFICIENT_RESOURCES
;
754 /* Check for a separator */
755 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
760 /* Loop the path until we get to the base name */
761 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
762 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
765 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
766 BaseLength
*= sizeof(WCHAR
);
768 /* Setup the string */
769 BaseName
.Length
= (USHORT
)BaseLength
;
774 /* Otherwise, we already have a base name */
775 BaseName
.Length
= FileName
->Length
;
776 BaseName
.Buffer
= FileName
->Buffer
;
779 /* Setup the maximum length */
780 BaseName
.MaximumLength
= BaseName
.Length
;
782 /* Now compute the base directory */
783 BaseDirectory
= *FileName
;
784 BaseDirectory
.Length
-= BaseName
.Length
;
785 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
787 /* Resolve imports */
788 MissingApiName
= Buffer
;
789 Status
= MiResolveImageReferences(DriverBase
,
795 if (!NT_SUCCESS(Status
)) return Status
;
798 *ModuleObject
= LdrEntry
;
799 return STATUS_SUCCESS
;
803 * IopInitializeBuiltinDriver
805 * Initialize a driver that is already loaded in memory.
811 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
813 PDEVICE_NODE DeviceNode
;
814 PDRIVER_OBJECT DriverObject
;
816 PWCHAR FileNameWithoutPath
;
817 LPWSTR FileExtension
;
818 PUNICODE_STRING ModuleName
= &LdrEntry
->BaseDllName
;
819 UNICODE_STRING ServiceName
;
822 * Display 'Loading XXX...' message
824 IopDisplayLoadingMessage(ModuleName
);
825 InbvIndicateProgress();
828 * Generate filename without path (not needed by freeldr)
830 FileNameWithoutPath
= wcsrchr(ModuleName
->Buffer
, L
'\\');
831 if (FileNameWithoutPath
== NULL
)
833 FileNameWithoutPath
= ModuleName
->Buffer
;
837 FileNameWithoutPath
++;
841 * Strip the file extension from ServiceName
843 RtlCreateUnicodeString(&ServiceName
, FileNameWithoutPath
);
844 FileExtension
= wcsrchr(ServiceName
.Buffer
, '.');
845 if (FileExtension
!= NULL
)
847 ServiceName
.Length
-= (USHORT
)wcslen(FileExtension
) * sizeof(WCHAR
);
848 FileExtension
[0] = 0;
852 * Determine the right device object
854 /* Use IopRootDeviceNode for now */
855 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
856 if (!NT_SUCCESS(Status
))
858 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
863 * Initialize the driver
865 Status
= IopInitializeDriverModule(DeviceNode
, LdrEntry
,
866 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
868 if (!NT_SUCCESS(Status
))
870 IopFreeDeviceNode(DeviceNode
);
874 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
875 if (NT_SUCCESS(Status
))
877 Status
= IopStartDevice(DeviceNode
);
884 * IopInitializeBootDrivers
886 * Initialize boot drivers and free memory for boot files.
897 IopInitializeBootDrivers(VOID
)
899 PLIST_ENTRY ListHead
, NextEntry
, NextEntry2
;
900 PLDR_DATA_TABLE_ENTRY LdrEntry
;
901 PDEVICE_NODE DeviceNode
;
902 PDRIVER_OBJECT DriverObject
;
903 LDR_DATA_TABLE_ENTRY ModuleObject
;
905 UNICODE_STRING DriverName
;
907 PDRIVER_INFORMATION DriverInfo
, DriverInfoTag
;
909 PBOOT_DRIVER_LIST_ENTRY BootEntry
;
910 DPRINT("IopInitializeBootDrivers()\n");
912 /* Use IopRootDeviceNode for now */
913 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, NULL
, &DeviceNode
);
914 if (!NT_SUCCESS(Status
)) return;
916 /* Setup the module object for the RAW FS Driver */
917 ModuleObject
.DllBase
= NULL
;
918 ModuleObject
.SizeOfImage
= 0;
919 ModuleObject
.EntryPoint
= RawFsDriverEntry
;
920 RtlInitUnicodeString(&DriverName
, L
"RAW");
923 Status
= IopInitializeDriverModule(DeviceNode
,
928 if (!NT_SUCCESS(Status
))
931 IopFreeDeviceNode(DeviceNode
);
935 /* Now initialize the associated device */
936 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
937 if (!NT_SUCCESS(Status
))
940 IopFreeDeviceNode(DeviceNode
);
945 Status
= IopStartDevice(DeviceNode
);
946 if (!NT_SUCCESS(Status
))
949 IopFreeDeviceNode(DeviceNode
);
953 /* Get highest group order index */
954 IopGroupIndex
= PpInitGetGroupOrderIndex(NULL
);
955 if (IopGroupIndex
== 0xFFFF) ASSERT(FALSE
);
957 /* Allocate the group table */
958 IopGroupTable
= ExAllocatePoolWithTag(PagedPool
,
959 IopGroupIndex
* sizeof(LIST_ENTRY
),
961 if (IopGroupTable
== NULL
) ASSERT(FALSE
);
963 /* Initialize the group table lists */
964 for (i
= 0; i
< IopGroupIndex
; i
++) InitializeListHead(&IopGroupTable
[i
]);
966 /* Loop the boot modules */
967 ListHead
= &KeLoaderBlock
->LoadOrderListHead
;
968 NextEntry
= ListHead
->Flink
;
969 while (ListHead
!= NextEntry
)
972 LdrEntry
= CONTAINING_RECORD(NextEntry
,
973 LDR_DATA_TABLE_ENTRY
,
976 /* Check if the DLL needs to be initialized */
977 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
979 /* Call its entrypoint */
980 MmCallDllInitialize(LdrEntry
, NULL
);
983 /* Go to the next driver */
984 NextEntry
= NextEntry
->Flink
;
987 /* Loop the boot drivers */
988 ListHead
= &KeLoaderBlock
->BootDriverListHead
;
989 NextEntry
= ListHead
->Flink
;
990 while (ListHead
!= NextEntry
)
993 BootEntry
= CONTAINING_RECORD(NextEntry
,
994 BOOT_DRIVER_LIST_ENTRY
,
997 /* Get the driver loader entry */
998 LdrEntry
= BootEntry
->LdrEntry
;
1000 /* Allocate our internal accounting structure */
1001 DriverInfo
= ExAllocatePoolWithTag(PagedPool
,
1002 sizeof(DRIVER_INFORMATION
),
1006 /* Zero it and initialize it */
1007 RtlZeroMemory(DriverInfo
, sizeof(DRIVER_INFORMATION
));
1008 InitializeListHead(&DriverInfo
->Link
);
1009 DriverInfo
->DataTableEntry
= BootEntry
;
1011 /* Open the registry key */
1012 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
1014 &BootEntry
->RegistryPath
,
1016 if ((NT_SUCCESS(Status
)) || /* ReactOS HACK for SETUPLDR */
1017 ((KeLoaderBlock
->SetupLdrBlock
) && ((KeyHandle
= (PVOID
)1)))) // yes, it's an assignment!
1019 /* Save the handle */
1020 DriverInfo
->ServiceHandle
= KeyHandle
;
1022 /* Get the group oder index */
1023 Index
= PpInitGetGroupOrderIndex(KeyHandle
);
1025 /* Get the tag position */
1026 DriverInfo
->TagPosition
= PipGetDriverTagPriority(KeyHandle
);
1028 /* Insert it into the list, at the right place */
1029 ASSERT(Index
< IopGroupIndex
);
1030 NextEntry2
= IopGroupTable
[Index
].Flink
;
1031 while (NextEntry2
!= &IopGroupTable
[Index
])
1033 /* Get the driver info */
1034 DriverInfoTag
= CONTAINING_RECORD(NextEntry2
,
1038 /* Check if we found the right tag position */
1039 if (DriverInfoTag
->TagPosition
> DriverInfo
->TagPosition
)
1046 NextEntry2
= NextEntry2
->Flink
;
1049 /* Insert us right before the next entry */
1050 NextEntry2
= NextEntry2
->Blink
;
1051 InsertHeadList(NextEntry2
, &DriverInfo
->Link
);
1055 /* Go to the next driver */
1056 NextEntry
= NextEntry
->Flink
;
1059 /* Loop each group index */
1060 for (i
= 0; i
< IopGroupIndex
; i
++)
1062 /* Loop each group table */
1063 NextEntry
= IopGroupTable
[i
].Flink
;
1064 while (NextEntry
!= &IopGroupTable
[i
])
1067 DriverInfo
= CONTAINING_RECORD(NextEntry
,
1071 /* Get the driver loader entry */
1072 LdrEntry
= DriverInfo
->DataTableEntry
->LdrEntry
;
1075 IopInitializeBuiltinDriver(LdrEntry
);
1078 NextEntry
= NextEntry
->Flink
;
1082 /* In old ROS, the loader list became empty after this point. Simulate. */
1083 InitializeListHead(&KeLoaderBlock
->LoadOrderListHead
);
1089 IopInitializeSystemDrivers(VOID
)
1091 PUNICODE_STRING
*DriverList
, *SavedList
;
1093 /* No system drivers on the boot cd */
1094 if (KeLoaderBlock
->SetupLdrBlock
) return;
1096 /* Get the driver list */
1097 SavedList
= DriverList
= CmGetSystemDriverList();
1103 /* Load the driver */
1104 ZwLoadDriver(*DriverList
);
1106 /* Free the entry */
1107 RtlFreeUnicodeString(*DriverList
);
1108 ExFreePool(*DriverList
);
1111 InbvIndicateProgress();
1116 ExFreePool(SavedList
);
1122 * Unloads a device driver.
1126 * Name of the service to unload (registry key).
1129 * Whether to unload Plug & Plug or only legacy drivers. If this
1130 * parameter is set to FALSE, the routine will unload only legacy
1137 * Guard the whole function by SEH.
1141 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1143 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1144 UNICODE_STRING ImagePath
;
1145 UNICODE_STRING ServiceName
;
1146 UNICODE_STRING ObjectName
;
1147 PDRIVER_OBJECT DriverObject
;
1148 PDEVICE_OBJECT DeviceObject
;
1149 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1150 LOAD_UNLOAD_PARAMS LoadParams
;
1153 BOOLEAN SafeToUnload
= TRUE
;
1155 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1160 * Get the service name from the registry key name
1163 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1165 Start
= DriverServiceName
->Buffer
;
1169 RtlInitUnicodeString(&ServiceName
, Start
);
1172 * Construct the driver object name
1175 ObjectName
.Length
= ((USHORT
)wcslen(Start
) + 8) * sizeof(WCHAR
);
1176 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1177 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1178 if (!ObjectName
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1179 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1180 memcpy(ObjectName
.Buffer
+ 8, Start
, ObjectName
.Length
- 8 * sizeof(WCHAR
));
1181 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1184 * Find the driver object
1186 Status
= ObReferenceObjectByName(&ObjectName
,
1193 (PVOID
*)&DriverObject
);
1195 if (!NT_SUCCESS(Status
))
1197 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName
);
1198 ExFreePool(ObjectName
.Buffer
);
1203 * Free the buffer for driver object name
1205 ExFreePool(ObjectName
.Buffer
);
1207 /* Check that driver is not already unloading */
1208 if (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
)
1210 DPRINT1("Driver deletion pending\n");
1211 ObDereferenceObject(DriverObject
);
1212 return STATUS_DELETE_PENDING
;
1216 * Get path of service...
1219 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1221 RtlInitUnicodeString(&ImagePath
, NULL
);
1223 QueryTable
[0].Name
= L
"ImagePath";
1224 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1225 QueryTable
[0].EntryContext
= &ImagePath
;
1227 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1228 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1230 if (!NT_SUCCESS(Status
))
1232 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1233 ObDereferenceObject(DriverObject
);
1238 * Normalize the image path for all later processing.
1241 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1243 if (!NT_SUCCESS(Status
))
1245 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1246 ObDereferenceObject(DriverObject
);
1251 * Free the service path
1254 ExFreePool(ImagePath
.Buffer
);
1257 * Unload the module and release the references to the device object
1260 /* Call the load/unload routine, depending on current process */
1261 if (DriverObject
->DriverUnload
&& DriverObject
->DriverSection
)
1263 /* Loop through each device object of the driver
1264 and set DOE_UNLOAD_PENDING flag */
1265 DeviceObject
= DriverObject
->DeviceObject
;
1266 while (DeviceObject
)
1268 /* Set the unload pending flag for the device */
1269 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1270 DeviceExtension
->ExtensionFlags
|= DOE_UNLOAD_PENDING
;
1272 /* Make sure there are no attached devices or no reference counts */
1273 if ((DeviceObject
->ReferenceCount
) || (DeviceObject
->AttachedDevice
))
1275 /* Not safe to unload */
1276 DPRINT1("Drivers device object is referenced or has attached devices\n");
1278 SafeToUnload
= FALSE
;
1281 DeviceObject
= DeviceObject
->NextDevice
;
1284 /* If not safe to unload, then return success */
1287 ObDereferenceObject(DriverObject
);
1288 return STATUS_SUCCESS
;
1291 /* Set the unload invoked flag */
1292 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
1294 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1296 /* Just call right away */
1297 (*DriverObject
->DriverUnload
)(DriverObject
);
1301 /* Load/Unload must be called from system process */
1303 /* Prepare parameters block */
1304 LoadParams
.DriverObject
= DriverObject
;
1305 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1307 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1308 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1309 (PVOID
)&LoadParams
);
1312 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1314 /* And wait when it completes */
1315 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1319 /* Mark the driver object temporary, so it could be deleted later */
1320 ObMakeTemporaryObject(DriverObject
);
1322 /* Dereference it 2 times */
1323 ObDereferenceObject(DriverObject
);
1324 ObDereferenceObject(DriverObject
);
1326 return STATUS_SUCCESS
;
1330 /* Dereference one time (refd inside this function) */
1331 ObDereferenceObject(DriverObject
);
1333 /* Return unloading failure */
1334 return STATUS_INVALID_DEVICE_REQUEST
;
1340 IopReinitializeDrivers(VOID
)
1342 PDRIVER_REINIT_ITEM ReinitItem
;
1345 /* Get the first entry and start looping */
1346 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1347 &DriverReinitListLock
);
1351 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1353 /* Increment reinitialization counter */
1354 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1356 /* Remove the device object flag */
1357 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1359 /* Call the routine */
1360 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1361 ReinitItem
->Context
,
1362 ReinitItem
->DriverObject
->
1363 DriverExtension
->Count
);
1365 /* Free the entry */
1368 /* Move to the next one */
1369 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1370 &DriverReinitListLock
);
1376 IopReinitializeBootDrivers(VOID
)
1378 PDRIVER_REINIT_ITEM ReinitItem
;
1381 /* Get the first entry and start looping */
1382 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1383 &DriverBootReinitListLock
);
1387 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1389 /* Increment reinitialization counter */
1390 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1392 /* Remove the device object flag */
1393 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1395 /* Call the routine */
1396 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1397 ReinitItem
->Context
,
1398 ReinitItem
->DriverObject
->
1399 DriverExtension
->Count
);
1401 /* Free the entry */
1404 /* Move to the next one */
1405 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1406 &DriverBootReinitListLock
);
1412 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1413 IN PDRIVER_INITIALIZE InitializationFunction
,
1414 IN PUNICODE_STRING RegistryPath
,
1415 PLDR_DATA_TABLE_ENTRY ModuleObject
,
1416 OUT PDRIVER_OBJECT
*pDriverObject
)
1418 WCHAR NameBuffer
[100];
1420 UNICODE_STRING LocalDriverName
;
1422 OBJECT_ATTRIBUTES ObjectAttributes
;
1424 PDRIVER_OBJECT DriverObject
;
1425 UNICODE_STRING ServiceKeyName
;
1427 ULONG i
, RetryCount
= 0;
1430 /* First, create a unique name for the driver if we don't have one */
1433 /* Create a random name and set up the string*/
1434 NameLength
= (USHORT
)swprintf(NameBuffer
,
1437 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1438 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1439 LocalDriverName
.Buffer
= NameBuffer
;
1443 /* So we can avoid another code path, use a local var */
1444 LocalDriverName
= *DriverName
;
1447 /* Initialize the Attributes */
1448 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1449 InitializeObjectAttributes(&ObjectAttributes
,
1451 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1455 /* Create the Object */
1456 Status
= ObCreateObject(KernelMode
,
1464 (PVOID
*)&DriverObject
);
1465 if (!NT_SUCCESS(Status
)) return Status
;
1467 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1469 /* Set up the Object */
1470 RtlZeroMemory(DriverObject
, ObjectSize
);
1471 DriverObject
->Type
= IO_TYPE_DRIVER
;
1472 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1473 DriverObject
->Flags
= DRVO_LEGACY_DRIVER
;//DRVO_BUILTIN_DRIVER;
1474 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1475 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1476 DriverObject
->DriverInit
= InitializationFunction
;
1477 DriverObject
->DriverSection
= ModuleObject
;
1478 /* Loop all Major Functions */
1479 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1481 /* Invalidate each function */
1482 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1485 /* Set up the service key name buffer */
1486 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1487 LocalDriverName
.Length
+
1490 if (!ServiceKeyName
.Buffer
)
1493 ObMakeTemporaryObject(DriverObject
);
1494 ObDereferenceObject(DriverObject
);
1495 return STATUS_INSUFFICIENT_RESOURCES
;
1498 /* Fill out the key data and copy the buffer */
1499 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1500 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1501 RtlCopyMemory(ServiceKeyName
.Buffer
,
1502 LocalDriverName
.Buffer
,
1503 LocalDriverName
.Length
);
1505 /* Null-terminate it and set it */
1506 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1507 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1509 /* Also store it in the Driver Object. This is a bit of a hack. */
1510 RtlCopyMemory(&DriverObject
->DriverName
,
1512 sizeof(UNICODE_STRING
));
1514 /* Add the Object and get its handle */
1515 Status
= ObInsertObject(DriverObject
,
1522 /* Eliminate small possibility when this function is called more than
1523 once in a row, and KeTickCount doesn't get enough time to change */
1524 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1530 if (!NT_SUCCESS(Status
)) return Status
;
1532 /* Now reference it */
1533 Status
= ObReferenceObjectByHandle(hDriver
,
1537 (PVOID
*)&DriverObject
,
1539 if (!NT_SUCCESS(Status
))
1542 ObMakeTemporaryObject(DriverObject
);
1543 ObDereferenceObject(DriverObject
);
1547 /* Close the extra handle */
1550 DriverObject
->HardwareDatabase
= &IopHardwareDatabaseKey
;
1551 DriverObject
->DriverStart
= ModuleObject
? ModuleObject
->DllBase
: 0;
1552 DriverObject
->DriverSize
= ModuleObject
? ModuleObject
->SizeOfImage
: 0;
1554 /* Finally, call its init function */
1555 DPRINT("RegistryKey: %wZ\n", RegistryPath
);
1556 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction
);
1557 Status
= (*InitializationFunction
)(DriverObject
, RegistryPath
);
1558 if (!NT_SUCCESS(Status
))
1560 /* If it didn't work, then kill the object */
1561 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName
, Status
);
1562 DriverObject
->DriverSection
= NULL
;
1563 ObMakeTemporaryObject(DriverObject
);
1564 ObDereferenceObject(DriverObject
);
1568 /* Returns to caller the object */
1569 *pDriverObject
= DriverObject
;
1572 /* Loop all Major Functions */
1573 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1576 * Make sure the driver didn't set any dispatch entry point to NULL!
1577 * Doing so is illegal; drivers shouldn't touch entry points they
1581 /* Check if it did so anyway */
1582 if (!DriverObject
->MajorFunction
[i
])
1584 /* Print a warning in the debug log */
1585 DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%d] to NULL!\n",
1586 &DriverObject
->DriverName
, i
);
1589 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1593 /* Return the Status */
1597 /* PUBLIC FUNCTIONS ***********************************************************/
1604 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1605 IN PDRIVER_INITIALIZE InitializationFunction
)
1607 PDRIVER_OBJECT DriverObject
;
1608 return IopCreateDriver(DriverName
, InitializationFunction
, NULL
, NULL
, &DriverObject
);
1616 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1618 /* Simply dereference the Object */
1619 ObDereferenceObject(DriverObject
);
1627 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1628 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1631 PDRIVER_REINIT_ITEM ReinitItem
;
1633 /* Allocate the entry */
1634 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1635 sizeof(DRIVER_REINIT_ITEM
),
1637 if (!ReinitItem
) return;
1640 ReinitItem
->DriverObject
= DriverObject
;
1641 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1642 ReinitItem
->Context
= Context
;
1644 /* Set the Driver Object flag and insert the entry into the list */
1645 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1646 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1647 &ReinitItem
->ItemEntry
,
1648 &DriverBootReinitListLock
);
1656 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1657 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1660 PDRIVER_REINIT_ITEM ReinitItem
;
1662 /* Allocate the entry */
1663 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1664 sizeof(DRIVER_REINIT_ITEM
),
1666 if (!ReinitItem
) return;
1669 ReinitItem
->DriverObject
= DriverObject
;
1670 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1671 ReinitItem
->Context
= Context
;
1673 /* Set the Driver Object flag and insert the entry into the list */
1674 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1675 ExInterlockedInsertTailList(&DriverReinitListHead
,
1676 &ReinitItem
->ItemEntry
,
1677 &DriverReinitListLock
);
1685 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1686 IN PVOID ClientIdentificationAddress
,
1687 IN ULONG DriverObjectExtensionSize
,
1688 OUT PVOID
*DriverObjectExtension
)
1691 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1692 BOOLEAN Inserted
= FALSE
;
1694 /* Assume failure */
1695 *DriverObjectExtension
= NULL
;
1697 /* Allocate the extension */
1698 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1699 sizeof(IO_CLIENT_EXTENSION
) +
1700 DriverObjectExtensionSize
,
1701 TAG_DRIVER_EXTENSION
);
1702 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1704 /* Clear the extension for teh caller */
1705 RtlZeroMemory(NewDriverExtension
,
1706 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1709 OldIrql
= KeRaiseIrqlToDpcLevel();
1711 /* Fill out the extension */
1712 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1714 /* Loop the current extensions */
1715 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1716 ClientDriverExtension
;
1717 while (DriverExtensions
)
1719 /* Check if the identifier matches */
1720 if (DriverExtensions
->ClientIdentificationAddress
==
1721 ClientIdentificationAddress
)
1723 /* We have a collision, break out */
1727 /* Go to the next one */
1728 DriverExtensions
= DriverExtensions
->NextExtension
;
1731 /* Check if we didn't collide */
1732 if (!DriverExtensions
)
1734 /* Link this one in */
1735 NewDriverExtension
->NextExtension
=
1736 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1737 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1742 /* Release the lock */
1743 KeLowerIrql(OldIrql
);
1745 /* Check if insertion failed */
1748 /* Free the entry and fail */
1749 ExFreePool(NewDriverExtension
);
1750 return STATUS_OBJECT_NAME_COLLISION
;
1753 /* Otherwise, return the pointer */
1754 *DriverObjectExtension
= NewDriverExtension
+ 1;
1755 return STATUS_SUCCESS
;
1763 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1764 IN PVOID ClientIdentificationAddress
)
1767 PIO_CLIENT_EXTENSION DriverExtensions
;
1770 OldIrql
= KeRaiseIrqlToDpcLevel();
1772 /* Loop the list until we find the right one */
1773 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1774 while (DriverExtensions
)
1776 /* Check for a match */
1777 if (DriverExtensions
->ClientIdentificationAddress
==
1778 ClientIdentificationAddress
)
1785 DriverExtensions
= DriverExtensions
->NextExtension
;
1789 KeLowerIrql(OldIrql
);
1791 /* Return nothing or the extension */
1792 if (!DriverExtensions
) return NULL
;
1793 return DriverExtensions
+ 1;
1797 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams
)
1799 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1800 UNICODE_STRING ImagePath
;
1801 UNICODE_STRING ServiceName
;
1804 PDEVICE_NODE DeviceNode
;
1805 PDRIVER_OBJECT DriverObject
;
1806 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1810 /* Check if it's an unload request */
1811 if (LoadParams
->DriverObject
)
1813 (*LoadParams
->DriverObject
->DriverUnload
)(LoadParams
->DriverObject
);
1815 /* Return success and signal the event */
1816 LoadParams
->Status
= STATUS_SUCCESS
;
1817 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1821 RtlInitUnicodeString(&ImagePath
, NULL
);
1824 * Get the service name from the registry key name.
1826 ASSERT(LoadParams
->ServiceName
->Length
>= sizeof(WCHAR
));
1828 ServiceName
= *LoadParams
->ServiceName
;
1829 cur
= LoadParams
->ServiceName
->Buffer
+
1830 (LoadParams
->ServiceName
->Length
/ sizeof(WCHAR
)) - 1;
1831 while (LoadParams
->ServiceName
->Buffer
!= cur
)
1835 ServiceName
.Buffer
= cur
+ 1;
1836 ServiceName
.Length
= LoadParams
->ServiceName
->Length
-
1837 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1838 (ULONG_PTR
)LoadParams
->ServiceName
->Buffer
);
1848 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1850 RtlInitUnicodeString(&ImagePath
, NULL
);
1852 QueryTable
[0].Name
= L
"Type";
1853 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1854 QueryTable
[0].EntryContext
= &Type
;
1856 QueryTable
[1].Name
= L
"ImagePath";
1857 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1858 QueryTable
[1].EntryContext
= &ImagePath
;
1860 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1861 LoadParams
->ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1863 if (!NT_SUCCESS(Status
))
1865 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1866 if (ImagePath
.Buffer
)
1867 ExFreePool(ImagePath
.Buffer
);
1868 LoadParams
->Status
= Status
;
1869 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1874 * Normalize the image path for all later processing.
1877 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1879 if (!NT_SUCCESS(Status
))
1881 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1882 LoadParams
->Status
= Status
;
1883 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1887 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1888 DPRINT("Type: %lx\n", Type
);
1890 /* Get existing DriverObject pointer (in case the driver has
1891 already been loaded and initialized) */
1892 Status
= IopGetDriverObject(
1895 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1896 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */));
1898 if (!NT_SUCCESS(Status
))
1901 * Load the driver module
1904 DPRINT("Loading module from %wZ\n", &ImagePath
);
1905 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, &BaseAddress
);
1907 if (!NT_SUCCESS(Status
) && Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1909 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1910 LoadParams
->Status
= Status
;
1911 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1916 * Initialize the driver module if it's loaded for the first time
1918 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1920 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1922 if (!NT_SUCCESS(Status
))
1924 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1925 MmUnloadSystemImage(ModuleObject
);
1926 LoadParams
->Status
= Status
;
1927 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1931 IopDisplayLoadingMessage(&DeviceNode
->ServiceName
);
1933 Status
= IopInitializeDriverModule(
1936 &DeviceNode
->ServiceName
,
1937 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1938 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1941 if (!NT_SUCCESS(Status
))
1943 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1944 MmUnloadSystemImage(ModuleObject
);
1945 IopFreeDeviceNode(DeviceNode
);
1946 LoadParams
->Status
= Status
;
1947 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1951 /* Initialize and start device */
1952 IopInitializeDevice(DeviceNode
, DriverObject
);
1953 Status
= IopStartDevice(DeviceNode
);
1958 DPRINT("DriverObject already exist in ObjectManager\n");
1960 /* IopGetDriverObject references the DriverObject, so dereference it */
1961 ObDereferenceObject(DriverObject
);
1964 /* Pass status to the caller and signal the event */
1965 LoadParams
->Status
= Status
;
1966 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1972 * Loads a device driver.
1976 * Name of the service to load (registry key).
1985 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1987 UNICODE_STRING CapturedDriverServiceName
= { 0, 0, NULL
};
1988 KPROCESSOR_MODE PreviousMode
;
1989 LOAD_UNLOAD_PARAMS LoadParams
;
1994 PreviousMode
= KeGetPreviousMode();
1997 * Check security privileges
2000 /* FIXME: Uncomment when privileges will be correctly implemented. */
2002 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
2004 DPRINT("Privilege not held\n");
2005 return STATUS_PRIVILEGE_NOT_HELD
;
2009 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
2012 if (!NT_SUCCESS(Status
))
2017 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
2019 LoadParams
.ServiceName
= &CapturedDriverServiceName
;
2020 LoadParams
.DriverObject
= NULL
;
2021 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
2023 /* Call the load/unload routine, depending on current process */
2024 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
2026 /* Just call right away */
2027 IopLoadUnloadDriver(&LoadParams
);
2031 /* Load/Unload must be called from system process */
2032 ExInitializeWorkItem(&LoadParams
.WorkItem
,
2033 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
2034 (PVOID
)&LoadParams
);
2037 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
2039 /* And wait when it completes */
2040 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
2044 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
2047 return LoadParams
.Status
;
2053 * Unloads a legacy device driver.
2057 * Name of the service to unload (registry key).
2067 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
2069 return IopUnloadDriver(DriverServiceName
, FALSE
);