2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/driver.c
5 * PURPOSE: Driver Object Management
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Filip Navara (navaraf@reactos.org)
8 * Hervé Poussineau (hpoussin@reactos.org)
11 /* INCLUDES *******************************************************************/
17 /* GLOBALS ********************************************************************/
19 LIST_ENTRY DriverReinitListHead
;
20 KSPIN_LOCK DriverReinitListLock
;
21 PLIST_ENTRY DriverReinitTailEntry
;
23 PLIST_ENTRY DriverBootReinitTailEntry
;
24 LIST_ENTRY DriverBootReinitListHead
;
25 KSPIN_LOCK DriverBootReinitListLock
;
27 UNICODE_STRING IopHardwareDatabaseKey
=
28 RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
30 POBJECT_TYPE IoDriverObjectType
= NULL
;
32 #define TAG_RTLREGISTRY 'vrqR'
34 extern BOOLEAN ExpInTextModeSetup
;
35 extern BOOLEAN PnpSystemInit
;
38 PLIST_ENTRY IopGroupTable
;
40 /* PRIVATE FUNCTIONS **********************************************************/
43 IopInvalidDeviceRequest(
44 PDEVICE_OBJECT DeviceObject
,
47 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
48 Irp
->IoStatus
.Information
= 0;
49 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
50 return STATUS_INVALID_DEVICE_REQUEST
;
55 IopDeleteDriver(IN PVOID ObjectBody
)
57 PDRIVER_OBJECT DriverObject
= ObjectBody
;
58 PIO_CLIENT_EXTENSION DriverExtension
, NextDriverExtension
;
61 DPRINT1("Deleting driver object '%wZ'\n", &DriverObject
->DriverName
);
63 /* There must be no device objects remaining at this point */
64 ASSERT(!DriverObject
->DeviceObject
);
66 /* Get the extension and loop them */
67 DriverExtension
= IoGetDrvObjExtension(DriverObject
)->
68 ClientDriverExtension
;
69 while (DriverExtension
)
71 /* Get the next one */
72 NextDriverExtension
= DriverExtension
->NextExtension
;
73 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
76 DriverExtension
= NextDriverExtension
;
79 /* Check if the driver image is still loaded */
80 if (DriverObject
->DriverSection
)
83 MmUnloadSystemImage(DriverObject
->DriverSection
);
86 /* Check if it has a name */
87 if (DriverObject
->DriverName
.Buffer
)
90 ExFreePool(DriverObject
->DriverName
.Buffer
);
93 /* Check if it has a service key name */
94 if (DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
)
97 ExFreePool(DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
);
103 PDRIVER_OBJECT
*DriverObject
,
104 PUNICODE_STRING ServiceName
,
107 PDRIVER_OBJECT Object
;
108 WCHAR NameBuffer
[MAX_PATH
];
109 UNICODE_STRING DriverName
;
112 DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
113 DriverObject
, ServiceName
, FileSystem
);
115 *DriverObject
= NULL
;
117 /* Create ModuleName string */
118 if (ServiceName
== NULL
|| ServiceName
->Buffer
== NULL
)
119 /* We don't know which DriverObject we have to open */
120 return STATUS_INVALID_PARAMETER_2
;
122 DriverName
.Buffer
= NameBuffer
;
123 DriverName
.Length
= 0;
124 DriverName
.MaximumLength
= sizeof(NameBuffer
);
126 if (FileSystem
== TRUE
)
127 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
129 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
130 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
132 DPRINT("Driver name: '%wZ'\n", &DriverName
);
134 /* Open driver object */
135 Status
= ObReferenceObjectByName(
137 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, /* Attributes */
138 NULL
, /* PassedAccessState */
139 0, /* DesiredAccess */
142 NULL
, /* ParseContext */
145 if (!NT_SUCCESS(Status
))
147 DPRINT("Failed to reference driver object, status=0x%08x\n", Status
);
151 *DriverObject
= Object
;
153 DPRINT("Driver Object: %p\n", Object
);
155 return STATUS_SUCCESS
;
160 * TRUE if String2 contains String1 as a suffix.
164 IopSuffixUnicodeString(
165 IN PCUNICODE_STRING String1
,
166 IN PCUNICODE_STRING String2
)
172 if (String2
->Length
< String1
->Length
)
175 Length
= String1
->Length
/ 2;
176 pc1
= String1
->Buffer
;
177 pc2
= &String2
->Buffer
[String2
->Length
/ sizeof(WCHAR
) - Length
];
183 if( *pc1
++ != *pc2
++ )
192 * IopDisplayLoadingMessage
194 * Display 'Loading XXX...' message.
200 IopDisplayLoadingMessage(PUNICODE_STRING ServiceName
)
202 CHAR TextBuffer
[256];
203 UNICODE_STRING DotSys
= RTL_CONSTANT_STRING(L
".SYS");
205 if (ExpInTextModeSetup
) return;
206 if (!KeLoaderBlock
) return;
207 RtlUpcaseUnicodeString(ServiceName
, ServiceName
, FALSE
);
208 snprintf(TextBuffer
, sizeof(TextBuffer
),
209 "%s%sSystem32\\Drivers\\%wZ%s\r\n",
210 KeLoaderBlock
->ArcBootDeviceName
,
211 KeLoaderBlock
->NtBootPathName
,
213 IopSuffixUnicodeString(&DotSys
, ServiceName
) ? "" : ".SYS");
214 HalDisplayString(TextBuffer
);
218 * IopNormalizeImagePath
220 * Normalize an image path to contain complete path.
224 * The input path and on exit the result path. ImagePath.Buffer
225 * must be allocated by ExAllocatePool on input. Caller is responsible
226 * for freeing the buffer when it's no longer needed.
229 * Name of the service that ImagePath belongs to.
235 * The input image path isn't freed on error.
240 IopNormalizeImagePath(
241 _Inout_
_When_(return>=0, _At_(ImagePath
->Buffer
, _Post_notnull_
__drv_allocatesMem(Mem
)))
242 PUNICODE_STRING ImagePath
,
243 _In_ PUNICODE_STRING ServiceName
)
245 UNICODE_STRING InputImagePath
;
247 DPRINT("Normalizing image path '%wZ' for service '%wZ'\n", ImagePath
, ServiceName
);
252 sizeof(UNICODE_STRING
));
254 if (InputImagePath
.Length
== 0)
256 ImagePath
->Length
= 0;
257 ImagePath
->MaximumLength
=
258 (33 * sizeof(WCHAR
)) + ServiceName
->Length
+ sizeof(UNICODE_NULL
);
259 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
260 if (ImagePath
->Buffer
== NULL
)
261 return STATUS_NO_MEMORY
;
263 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\system32\\drivers\\");
264 RtlAppendUnicodeStringToString(ImagePath
, ServiceName
);
265 RtlAppendUnicodeToString(ImagePath
, L
".sys");
267 if (InputImagePath
.Buffer
[0] != L
'\\')
269 ImagePath
->Length
= 0;
270 ImagePath
->MaximumLength
=
271 12 * sizeof(WCHAR
) + InputImagePath
.Length
+ sizeof(UNICODE_NULL
);
272 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
273 if (ImagePath
->Buffer
== NULL
)
274 return STATUS_NO_MEMORY
;
276 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\");
277 RtlAppendUnicodeStringToString(ImagePath
, &InputImagePath
);
279 /* Free caller's string */
280 ExFreePoolWithTag(InputImagePath
.Buffer
, TAG_RTLREGISTRY
);
283 DPRINT("Normalized image path is '%wZ' for service '%wZ'\n", ImagePath
, ServiceName
);
285 return STATUS_SUCCESS
;
289 * IopLoadServiceModule
291 * Load a module specified by registry settings for service.
295 * Name of the service to load.
302 IopLoadServiceModule(
303 IN PUNICODE_STRING ServiceName
,
304 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
306 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
308 UNICODE_STRING ServiceImagePath
, CCSName
;
310 HANDLE CCSKey
, ServiceKey
;
313 ASSERT(ServiceName
->Length
);
314 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
316 if (ExpInTextModeSetup
)
318 /* We have no registry, but luckily we know where all the drivers are */
320 /* ServiceStart < 4 is all that matters */
323 /* IopNormalizeImagePath will do all of the work for us if we give it an empty string */
324 ServiceImagePath
.Length
= ServiceImagePath
.MaximumLength
= 0;
325 ServiceImagePath
.Buffer
= NULL
;
329 /* Open CurrentControlSet */
330 RtlInitUnicodeString(&CCSName
,
331 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
332 Status
= IopOpenRegistryKeyEx(&CCSKey
, NULL
, &CCSName
, KEY_READ
);
333 if (!NT_SUCCESS(Status
))
335 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with Status %08X\n",
340 /* Open service key */
341 Status
= IopOpenRegistryKeyEx(&ServiceKey
, CCSKey
, ServiceName
, KEY_READ
);
342 if (!NT_SUCCESS(Status
))
344 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with Status %08X\n",
345 ServiceName
, Status
);
351 * Get information about the service.
354 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
356 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
358 QueryTable
[0].Name
= L
"Start";
359 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
360 QueryTable
[0].EntryContext
= &ServiceStart
;
362 QueryTable
[1].Name
= L
"ImagePath";
363 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
364 QueryTable
[1].EntryContext
= &ServiceImagePath
;
366 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
367 (PWSTR
)ServiceKey
, QueryTable
, NULL
, NULL
);
372 if (!NT_SUCCESS(Status
))
374 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
380 * Normalize the image path for all later processing.
383 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
385 if (!NT_SUCCESS(Status
))
387 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
392 * Case for disabled drivers
395 if (ServiceStart
>= 4)
397 /* We can't load this */
398 Status
= STATUS_DRIVER_UNABLE_TO_LOAD
;
402 DPRINT("Loading module from %wZ\n", &ServiceImagePath
);
403 Status
= MmLoadSystemImage(&ServiceImagePath
, NULL
, NULL
, 0, (PVOID
)ModuleObject
, &BaseAddress
);
404 if (NT_SUCCESS(Status
))
406 IopDisplayLoadingMessage(ServiceName
);
410 ExFreePool(ServiceImagePath
.Buffer
);
413 * Now check if the module was loaded successfully.
416 if (!NT_SUCCESS(Status
))
418 DPRINT("Module loading failed (Status %x)\n", Status
);
421 DPRINT("Module loading (Status %x)\n", Status
);
428 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry
);
431 * IopInitializeDriverModule
433 * Initialize a loaded driver.
437 * Pointer to device node.
440 * Module object representing the driver. It can be retrieve by
441 * IopLoadServiceModule.
444 * Name of the service (as in registry).
447 * Set to TRUE for file system drivers.
450 * On successful return this contains the driver object representing
455 IopInitializeDriverModule(
456 IN PDEVICE_NODE DeviceNode
,
457 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
458 IN PUNICODE_STRING ServiceName
,
459 IN BOOLEAN FileSystemDriver
,
460 OUT PDRIVER_OBJECT
*DriverObject
)
462 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
463 WCHAR NameBuffer
[MAX_PATH
];
464 UNICODE_STRING DriverName
;
465 UNICODE_STRING RegistryKey
;
466 PDRIVER_INITIALIZE DriverEntry
;
467 PDRIVER_OBJECT Driver
;
470 DriverEntry
= ModuleObject
->EntryPoint
;
472 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
474 RegistryKey
.Length
= 0;
475 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
476 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
477 if (RegistryKey
.Buffer
== NULL
)
479 return STATUS_INSUFFICIENT_RESOURCES
;
481 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
482 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
486 RtlInitUnicodeString(&RegistryKey
, NULL
);
489 /* Create ModuleName string */
490 if (ServiceName
&& ServiceName
->Length
> 0)
492 if (FileSystemDriver
== TRUE
)
493 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
495 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
497 RtlInitUnicodeString(&DriverName
, NameBuffer
);
498 DriverName
.MaximumLength
= sizeof(NameBuffer
);
500 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
502 DPRINT("Driver name: '%wZ'\n", &DriverName
);
505 DriverName
.Length
= 0;
507 Status
= IopCreateDriver(
508 DriverName
.Length
> 0 ? &DriverName
: NULL
,
514 RtlFreeUnicodeString(&RegistryKey
);
516 *DriverObject
= Driver
;
517 if (!NT_SUCCESS(Status
))
519 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status
);
523 MmFreeDriverInitialization((PLDR_DATA_TABLE_ENTRY
)Driver
->DriverSection
);
525 /* Set the driver as initialized */
526 IopReadyDeviceObjects(Driver
);
528 if (PnpSystemInit
) IopReinitializeDrivers();
530 return STATUS_SUCCESS
;
534 * IopAttachFilterDriversCallback
536 * Internal routine used by IopAttachFilterDrivers.
540 IopAttachFilterDriversCallback(
548 PDEVICE_NODE DeviceNode
= Context
;
549 UNICODE_STRING ServiceName
;
551 PLDR_DATA_TABLE_ENTRY ModuleObject
;
552 PDRIVER_OBJECT DriverObject
;
555 /* No filter value present */
556 if (ValueType
== REG_NONE
)
557 return STATUS_SUCCESS
;
559 for (Filters
= ValueData
;
560 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
562 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
564 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
566 ServiceName
.Buffer
= Filters
;
567 ServiceName
.MaximumLength
=
568 ServiceName
.Length
= (USHORT
)wcslen(Filters
) * sizeof(WCHAR
);
570 Status
= IopGetDriverObject(&DriverObject
,
573 if (!NT_SUCCESS(Status
))
575 /* Load and initialize the filter driver */
576 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
577 if (!NT_SUCCESS(Status
))
580 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
581 FALSE
, &DriverObject
);
582 if (!NT_SUCCESS(Status
))
586 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
588 /* Remove extra reference */
589 ObDereferenceObject(DriverObject
);
591 if (!NT_SUCCESS(Status
))
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
= 0;
649 QueryTable
[0].DefaultType
= REG_NONE
;
651 Status
= RtlQueryRegistryValues(
657 if (!NT_SUCCESS(Status
))
659 DPRINT1("Failed to load device %s filters: %08X\n",
660 Lower
? "lower" : "upper", Status
);
662 ZwClose(EnumRootKey
);
667 * Now get the class GUID
670 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
671 Class
.Buffer
= ClassBuffer
;
672 QueryTable
[0].QueryRoutine
= NULL
;
673 QueryTable
[0].Name
= L
"ClassGUID";
674 QueryTable
[0].EntryContext
= &Class
;
675 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
677 Status
= RtlQueryRegistryValues(
686 ZwClose(EnumRootKey
);
689 * Load the class filter driver
691 if (NT_SUCCESS(Status
))
693 UNICODE_STRING ControlClass
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
695 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
696 &ControlClass
, KEY_READ
);
697 if (!NT_SUCCESS(Status
))
699 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
704 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
706 if (!NT_SUCCESS(Status
))
708 /* It's okay if there's no class key */
709 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
710 ZwClose(EnumRootKey
);
711 return STATUS_SUCCESS
;
714 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
716 QueryTable
[0].Name
= L
"LowerFilters";
718 QueryTable
[0].Name
= L
"UpperFilters";
719 QueryTable
[0].EntryContext
= NULL
;
720 QueryTable
[0].Flags
= 0;
721 QueryTable
[0].DefaultType
= REG_NONE
;
723 Status
= RtlQueryRegistryValues(
732 ZwClose(EnumRootKey
);
734 if (!NT_SUCCESS(Status
))
736 DPRINT1("Failed to load class %s filters: %08X\n",
737 Lower
? "lower" : "upper", Status
);
739 ZwClose(EnumRootKey
);
744 return STATUS_SUCCESS
;
749 MiResolveImageReferences(IN PVOID ImageBase
,
750 IN PUNICODE_STRING ImageFileDirectory
,
751 IN PUNICODE_STRING NamePrefix OPTIONAL
,
752 OUT PCHAR
*MissingApi
,
753 OUT PWCHAR
*MissingDriver
,
754 OUT PLOAD_IMPORTS
*LoadImports
);
757 // Used for images already loaded (boot drivers)
762 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry
,
763 PUNICODE_STRING FileName
,
764 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
767 UNICODE_STRING BaseName
, BaseDirectory
;
768 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
769 PCHAR MissingApiName
, Buffer
;
770 PWCHAR MissingDriverName
;
771 PVOID DriverBase
= LdrEntry
->DllBase
;
773 /* Allocate a buffer we'll use for names */
774 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
778 return STATUS_INSUFFICIENT_RESOURCES
;
781 /* Check for a separator */
782 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
787 /* Loop the path until we get to the base name */
788 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
789 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
792 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
793 BaseLength
*= sizeof(WCHAR
);
795 /* Setup the string */
796 BaseName
.Length
= (USHORT
)BaseLength
;
801 /* Otherwise, we already have a base name */
802 BaseName
.Length
= FileName
->Length
;
803 BaseName
.Buffer
= FileName
->Buffer
;
806 /* Setup the maximum length */
807 BaseName
.MaximumLength
= BaseName
.Length
;
809 /* Now compute the base directory */
810 BaseDirectory
= *FileName
;
811 BaseDirectory
.Length
-= BaseName
.Length
;
812 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
814 /* Resolve imports */
815 MissingApiName
= Buffer
;
816 Status
= MiResolveImageReferences(DriverBase
,
823 /* Free the temporary buffer */
824 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
826 /* Check the result of the imports resolution */
827 if (!NT_SUCCESS(Status
)) return Status
;
830 *ModuleObject
= LdrEntry
;
831 return STATUS_SUCCESS
;
835 * IopInitializeBuiltinDriver
837 * Initialize a driver that is already loaded in memory.
843 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY BootLdrEntry
)
845 PDEVICE_NODE DeviceNode
;
846 PDRIVER_OBJECT DriverObject
;
848 PWCHAR FileNameWithoutPath
;
849 LPWSTR FileExtension
;
850 PUNICODE_STRING ModuleName
= &BootLdrEntry
->BaseDllName
;
851 PLDR_DATA_TABLE_ENTRY LdrEntry
;
852 PLIST_ENTRY NextEntry
;
853 UNICODE_STRING ServiceName
;
856 * Display 'Loading XXX...' message
858 IopDisplayLoadingMessage(ModuleName
);
859 InbvIndicateProgress();
862 * Generate filename without path (not needed by freeldr)
864 FileNameWithoutPath
= wcsrchr(ModuleName
->Buffer
, L
'\\');
865 if (FileNameWithoutPath
== NULL
)
867 FileNameWithoutPath
= ModuleName
->Buffer
;
871 FileNameWithoutPath
++;
875 * Strip the file extension from ServiceName
877 RtlCreateUnicodeString(&ServiceName
, FileNameWithoutPath
);
878 FileExtension
= wcsrchr(ServiceName
.Buffer
, '.');
879 if (FileExtension
!= NULL
)
881 ServiceName
.Length
-= (USHORT
)wcslen(FileExtension
) * sizeof(WCHAR
);
882 FileExtension
[0] = 0;
886 * Determine the right device object
888 /* Use IopRootDeviceNode for now */
889 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
890 if (!NT_SUCCESS(Status
))
892 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
896 /* Lookup the new Ldr entry in PsLoadedModuleList */
897 NextEntry
= PsLoadedModuleList
.Flink
;
898 while (NextEntry
!= &PsLoadedModuleList
)
900 LdrEntry
= CONTAINING_RECORD(NextEntry
,
901 LDR_DATA_TABLE_ENTRY
,
903 if (RtlEqualUnicodeString(ModuleName
, &LdrEntry
->BaseDllName
, TRUE
))
908 NextEntry
= NextEntry
->Flink
;
910 NT_ASSERT(NextEntry
!= &PsLoadedModuleList
);
913 * Initialize the driver
915 Status
= IopInitializeDriverModule(DeviceNode
, LdrEntry
,
916 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
918 if (!NT_SUCCESS(Status
))
920 IopFreeDeviceNode(DeviceNode
);
924 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
925 if (NT_SUCCESS(Status
))
927 Status
= IopStartDevice(DeviceNode
);
930 /* Remove extra reference from IopInitializeDriverModule */
931 ObDereferenceObject(DriverObject
);
937 * IopInitializeBootDrivers
939 * Initialize boot drivers and free memory for boot files.
950 IopInitializeBootDrivers(VOID
)
952 PLIST_ENTRY ListHead
, NextEntry
, NextEntry2
;
953 PLDR_DATA_TABLE_ENTRY LdrEntry
;
954 PDEVICE_NODE DeviceNode
;
955 PDRIVER_OBJECT DriverObject
;
956 LDR_DATA_TABLE_ENTRY ModuleObject
;
958 UNICODE_STRING DriverName
;
960 PDRIVER_INFORMATION DriverInfo
, DriverInfoTag
;
962 PBOOT_DRIVER_LIST_ENTRY BootEntry
;
963 DPRINT("IopInitializeBootDrivers()\n");
965 /* Use IopRootDeviceNode for now */
966 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, NULL
, &DeviceNode
);
967 if (!NT_SUCCESS(Status
)) return;
969 /* Setup the module object for the RAW FS Driver */
970 ModuleObject
.DllBase
= NULL
;
971 ModuleObject
.SizeOfImage
= 0;
972 ModuleObject
.EntryPoint
= RawFsDriverEntry
;
973 RtlInitUnicodeString(&DriverName
, L
"RAW");
976 Status
= IopInitializeDriverModule(DeviceNode
,
981 if (!NT_SUCCESS(Status
))
984 IopFreeDeviceNode(DeviceNode
);
988 /* Now initialize the associated device */
989 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
990 if (!NT_SUCCESS(Status
))
993 IopFreeDeviceNode(DeviceNode
);
994 ObDereferenceObject(DriverObject
);
999 Status
= IopStartDevice(DeviceNode
);
1000 if (!NT_SUCCESS(Status
))
1003 IopFreeDeviceNode(DeviceNode
);
1004 ObDereferenceObject(DriverObject
);
1008 /* Get highest group order index */
1009 IopGroupIndex
= PpInitGetGroupOrderIndex(NULL
);
1010 if (IopGroupIndex
== 0xFFFF) ASSERT(FALSE
);
1012 /* Allocate the group table */
1013 IopGroupTable
= ExAllocatePoolWithTag(PagedPool
,
1014 IopGroupIndex
* sizeof(LIST_ENTRY
),
1016 if (IopGroupTable
== NULL
) ASSERT(FALSE
);
1018 /* Initialize the group table lists */
1019 for (i
= 0; i
< IopGroupIndex
; i
++) InitializeListHead(&IopGroupTable
[i
]);
1021 /* Loop the boot modules */
1022 ListHead
= &KeLoaderBlock
->LoadOrderListHead
;
1023 NextEntry
= ListHead
->Flink
;
1024 while (ListHead
!= NextEntry
)
1027 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1028 LDR_DATA_TABLE_ENTRY
,
1031 /* Check if the DLL needs to be initialized */
1032 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
1034 /* Call its entrypoint */
1035 MmCallDllInitialize(LdrEntry
, NULL
);
1038 /* Go to the next driver */
1039 NextEntry
= NextEntry
->Flink
;
1042 /* Loop the boot drivers */
1043 ListHead
= &KeLoaderBlock
->BootDriverListHead
;
1044 NextEntry
= ListHead
->Flink
;
1045 while (ListHead
!= NextEntry
)
1048 BootEntry
= CONTAINING_RECORD(NextEntry
,
1049 BOOT_DRIVER_LIST_ENTRY
,
1052 /* Get the driver loader entry */
1053 LdrEntry
= BootEntry
->LdrEntry
;
1055 /* Allocate our internal accounting structure */
1056 DriverInfo
= ExAllocatePoolWithTag(PagedPool
,
1057 sizeof(DRIVER_INFORMATION
),
1061 /* Zero it and initialize it */
1062 RtlZeroMemory(DriverInfo
, sizeof(DRIVER_INFORMATION
));
1063 InitializeListHead(&DriverInfo
->Link
);
1064 DriverInfo
->DataTableEntry
= BootEntry
;
1066 /* Open the registry key */
1067 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
1069 &BootEntry
->RegistryPath
,
1071 if ((NT_SUCCESS(Status
)) || /* ReactOS HACK for SETUPLDR */
1072 ((KeLoaderBlock
->SetupLdrBlock
) && ((KeyHandle
= (PVOID
)1)))) // yes, it's an assignment!
1074 /* Save the handle */
1075 DriverInfo
->ServiceHandle
= KeyHandle
;
1077 /* Get the group oder index */
1078 Index
= PpInitGetGroupOrderIndex(KeyHandle
);
1080 /* Get the tag position */
1081 DriverInfo
->TagPosition
= PipGetDriverTagPriority(KeyHandle
);
1083 /* Insert it into the list, at the right place */
1084 ASSERT(Index
< IopGroupIndex
);
1085 NextEntry2
= IopGroupTable
[Index
].Flink
;
1086 while (NextEntry2
!= &IopGroupTable
[Index
])
1088 /* Get the driver info */
1089 DriverInfoTag
= CONTAINING_RECORD(NextEntry2
,
1093 /* Check if we found the right tag position */
1094 if (DriverInfoTag
->TagPosition
> DriverInfo
->TagPosition
)
1101 NextEntry2
= NextEntry2
->Flink
;
1104 /* Insert us right before the next entry */
1105 NextEntry2
= NextEntry2
->Blink
;
1106 InsertHeadList(NextEntry2
, &DriverInfo
->Link
);
1110 /* Go to the next driver */
1111 NextEntry
= NextEntry
->Flink
;
1114 /* Loop each group index */
1115 for (i
= 0; i
< IopGroupIndex
; i
++)
1117 /* Loop each group table */
1118 NextEntry
= IopGroupTable
[i
].Flink
;
1119 while (NextEntry
!= &IopGroupTable
[i
])
1122 DriverInfo
= CONTAINING_RECORD(NextEntry
,
1126 /* Get the driver loader entry */
1127 LdrEntry
= DriverInfo
->DataTableEntry
->LdrEntry
;
1130 IopInitializeBuiltinDriver(LdrEntry
);
1133 NextEntry
= NextEntry
->Flink
;
1137 /* In old ROS, the loader list became empty after this point. Simulate. */
1138 InitializeListHead(&KeLoaderBlock
->LoadOrderListHead
);
1144 IopInitializeSystemDrivers(VOID
)
1146 PUNICODE_STRING
*DriverList
, *SavedList
;
1148 /* No system drivers on the boot cd */
1149 if (KeLoaderBlock
->SetupLdrBlock
) return;
1151 /* Get the driver list */
1152 SavedList
= DriverList
= CmGetSystemDriverList();
1158 /* Load the driver */
1159 ZwLoadDriver(*DriverList
);
1161 /* Free the entry */
1162 RtlFreeUnicodeString(*DriverList
);
1163 ExFreePool(*DriverList
);
1166 InbvIndicateProgress();
1171 ExFreePool(SavedList
);
1177 * Unloads a device driver.
1181 * Name of the service to unload (registry key).
1184 * Whether to unload Plug & Plug or only legacy drivers. If this
1185 * parameter is set to FALSE, the routine will unload only legacy
1192 * Guard the whole function by SEH.
1196 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1198 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1199 UNICODE_STRING ImagePath
;
1200 UNICODE_STRING ServiceName
;
1201 UNICODE_STRING ObjectName
;
1202 PDRIVER_OBJECT DriverObject
;
1203 PDEVICE_OBJECT DeviceObject
;
1204 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1205 LOAD_UNLOAD_PARAMS LoadParams
;
1208 BOOLEAN SafeToUnload
= TRUE
;
1210 DPRINT("IopUnloadDriver('%wZ', %u)\n", DriverServiceName
, UnloadPnpDrivers
);
1215 * Get the service name from the registry key name
1218 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1220 Start
= DriverServiceName
->Buffer
;
1224 RtlInitUnicodeString(&ServiceName
, Start
);
1227 * Construct the driver object name
1230 ObjectName
.Length
= ((USHORT
)wcslen(Start
) + 8) * sizeof(WCHAR
);
1231 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1232 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1233 if (!ObjectName
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1234 wcscpy(ObjectName
.Buffer
, DRIVER_ROOT_NAME
);
1235 memcpy(ObjectName
.Buffer
+ 8, Start
, ObjectName
.Length
- 8 * sizeof(WCHAR
));
1236 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1239 * Find the driver object
1241 Status
= ObReferenceObjectByName(&ObjectName
,
1248 (PVOID
*)&DriverObject
);
1250 if (!NT_SUCCESS(Status
))
1252 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName
);
1253 ExFreePool(ObjectName
.Buffer
);
1258 * Free the buffer for driver object name
1260 ExFreePool(ObjectName
.Buffer
);
1262 /* Check that driver is not already unloading */
1263 if (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
)
1265 DPRINT1("Driver deletion pending\n");
1266 ObDereferenceObject(DriverObject
);
1267 return STATUS_DELETE_PENDING
;
1271 * Get path of service...
1274 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1276 RtlInitUnicodeString(&ImagePath
, NULL
);
1278 QueryTable
[0].Name
= L
"ImagePath";
1279 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1280 QueryTable
[0].EntryContext
= &ImagePath
;
1282 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1283 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1285 if (!NT_SUCCESS(Status
))
1287 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1288 ObDereferenceObject(DriverObject
);
1293 * Normalize the image path for all later processing.
1296 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1298 if (!NT_SUCCESS(Status
))
1300 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1301 ObDereferenceObject(DriverObject
);
1306 * Free the service path
1309 ExFreePool(ImagePath
.Buffer
);
1312 * Unload the module and release the references to the device object
1315 /* Call the load/unload routine, depending on current process */
1316 if (DriverObject
->DriverUnload
&& DriverObject
->DriverSection
&&
1317 (UnloadPnpDrivers
|| (DriverObject
->Flags
& DRVO_LEGACY_DRIVER
)))
1319 /* Loop through each device object of the driver
1320 and set DOE_UNLOAD_PENDING flag */
1321 DeviceObject
= DriverObject
->DeviceObject
;
1322 while (DeviceObject
)
1324 /* Set the unload pending flag for the device */
1325 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1326 DeviceExtension
->ExtensionFlags
|= DOE_UNLOAD_PENDING
;
1328 /* Make sure there are no attached devices or no reference counts */
1329 if ((DeviceObject
->ReferenceCount
) || (DeviceObject
->AttachedDevice
))
1331 /* Not safe to unload */
1332 DPRINT1("Drivers device object is referenced or has attached devices\n");
1334 SafeToUnload
= FALSE
;
1337 DeviceObject
= DeviceObject
->NextDevice
;
1340 /* If not safe to unload, then return success */
1343 ObDereferenceObject(DriverObject
);
1344 return STATUS_SUCCESS
;
1347 DPRINT1("Unloading driver '%wZ' (manual)\n", &DriverObject
->DriverName
);
1349 /* Set the unload invoked flag */
1350 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
1352 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1354 /* Just call right away */
1355 (*DriverObject
->DriverUnload
)(DriverObject
);
1359 /* Load/Unload must be called from system process */
1361 /* Prepare parameters block */
1362 LoadParams
.DriverObject
= DriverObject
;
1363 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1365 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1366 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1367 (PVOID
)&LoadParams
);
1370 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1372 /* And wait when it completes */
1373 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1377 /* Mark the driver object temporary, so it could be deleted later */
1378 ObMakeTemporaryObject(DriverObject
);
1380 /* Dereference it 2 times */
1381 ObDereferenceObject(DriverObject
);
1382 ObDereferenceObject(DriverObject
);
1384 return STATUS_SUCCESS
;
1388 DPRINT1("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject
->DriverName
);
1390 /* Dereference one time (refd inside this function) */
1391 ObDereferenceObject(DriverObject
);
1393 /* Return unloading failure */
1394 return STATUS_INVALID_DEVICE_REQUEST
;
1400 IopReinitializeDrivers(VOID
)
1402 PDRIVER_REINIT_ITEM ReinitItem
;
1405 /* Get the first entry and start looping */
1406 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1407 &DriverReinitListLock
);
1411 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1413 /* Increment reinitialization counter */
1414 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1416 /* Remove the device object flag */
1417 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1419 /* Call the routine */
1420 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1421 ReinitItem
->Context
,
1422 ReinitItem
->DriverObject
->
1423 DriverExtension
->Count
);
1425 /* Free the entry */
1428 /* Move to the next one */
1429 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1430 &DriverReinitListLock
);
1436 IopReinitializeBootDrivers(VOID
)
1438 PDRIVER_REINIT_ITEM ReinitItem
;
1441 /* Get the first entry and start looping */
1442 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1443 &DriverBootReinitListLock
);
1447 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1449 /* Increment reinitialization counter */
1450 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1452 /* Remove the device object flag */
1453 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1455 /* Call the routine */
1456 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1457 ReinitItem
->Context
,
1458 ReinitItem
->DriverObject
->
1459 DriverExtension
->Count
);
1461 /* Free the entry */
1464 /* Move to the next one */
1465 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1466 &DriverBootReinitListLock
);
1472 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1473 IN PDRIVER_INITIALIZE InitializationFunction
,
1474 IN PUNICODE_STRING RegistryPath
,
1475 IN PCUNICODE_STRING ServiceName
,
1476 PLDR_DATA_TABLE_ENTRY ModuleObject
,
1477 OUT PDRIVER_OBJECT
*pDriverObject
)
1479 WCHAR NameBuffer
[100];
1481 UNICODE_STRING LocalDriverName
;
1483 OBJECT_ATTRIBUTES ObjectAttributes
;
1485 PDRIVER_OBJECT DriverObject
;
1486 UNICODE_STRING ServiceKeyName
;
1488 ULONG i
, RetryCount
= 0;
1491 /* First, create a unique name for the driver if we don't have one */
1494 /* Create a random name and set up the string*/
1495 NameLength
= (USHORT
)swprintf(NameBuffer
,
1496 DRIVER_ROOT_NAME L
"%08u",
1498 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1499 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1500 LocalDriverName
.Buffer
= NameBuffer
;
1504 /* So we can avoid another code path, use a local var */
1505 LocalDriverName
= *DriverName
;
1508 /* Initialize the Attributes */
1509 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1510 InitializeObjectAttributes(&ObjectAttributes
,
1512 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1516 /* Create the Object */
1517 Status
= ObCreateObject(KernelMode
,
1525 (PVOID
*)&DriverObject
);
1526 if (!NT_SUCCESS(Status
)) return Status
;
1528 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1530 /* Set up the Object */
1531 RtlZeroMemory(DriverObject
, ObjectSize
);
1532 DriverObject
->Type
= IO_TYPE_DRIVER
;
1533 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1534 DriverObject
->Flags
= DRVO_LEGACY_DRIVER
;
1535 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1536 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1537 DriverObject
->DriverInit
= InitializationFunction
;
1538 DriverObject
->DriverSection
= ModuleObject
;
1539 /* Loop all Major Functions */
1540 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1542 /* Invalidate each function */
1543 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1546 /* Set up the service key name buffer */
1547 ServiceKeyName
.MaximumLength
= ServiceName
->Length
+ sizeof(UNICODE_NULL
);
1548 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1549 ServiceKeyName
.MaximumLength
,
1551 if (!ServiceKeyName
.Buffer
)
1554 ObMakeTemporaryObject(DriverObject
);
1555 ObDereferenceObject(DriverObject
);
1556 return STATUS_INSUFFICIENT_RESOURCES
;
1559 /* Copy the name and set it in the driver extension */
1560 RtlCopyUnicodeString(&ServiceKeyName
,
1562 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1564 /* Make a copy of the driver name to store in the driver object */
1565 DriverObject
->DriverName
.MaximumLength
= LocalDriverName
.Length
;
1566 DriverObject
->DriverName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1567 DriverObject
->DriverName
.MaximumLength
,
1569 if (!DriverObject
->DriverName
.Buffer
)
1572 ObMakeTemporaryObject(DriverObject
);
1573 ObDereferenceObject(DriverObject
);
1574 return STATUS_INSUFFICIENT_RESOURCES
;
1577 RtlCopyUnicodeString(&DriverObject
->DriverName
,
1580 /* Add the Object and get its handle */
1581 Status
= ObInsertObject(DriverObject
,
1588 /* Eliminate small possibility when this function is called more than
1589 once in a row, and KeTickCount doesn't get enough time to change */
1590 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1596 if (!NT_SUCCESS(Status
)) return Status
;
1598 /* Now reference it */
1599 Status
= ObReferenceObjectByHandle(hDriver
,
1603 (PVOID
*)&DriverObject
,
1606 /* Close the extra handle */
1609 if (!NT_SUCCESS(Status
))
1612 ObMakeTemporaryObject(DriverObject
);
1613 ObDereferenceObject(DriverObject
);
1617 DriverObject
->HardwareDatabase
= &IopHardwareDatabaseKey
;
1618 DriverObject
->DriverStart
= ModuleObject
? ModuleObject
->DllBase
: 0;
1619 DriverObject
->DriverSize
= ModuleObject
? ModuleObject
->SizeOfImage
: 0;
1621 /* Finally, call its init function */
1622 DPRINT("RegistryKey: %wZ\n", RegistryPath
);
1623 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction
);
1624 Status
= (*InitializationFunction
)(DriverObject
, RegistryPath
);
1625 if (!NT_SUCCESS(Status
))
1627 /* If it didn't work, then kill the object */
1628 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName
, Status
);
1629 DriverObject
->DriverSection
= NULL
;
1630 ObMakeTemporaryObject(DriverObject
);
1631 ObDereferenceObject(DriverObject
);
1636 /* Returns to caller the object */
1637 *pDriverObject
= DriverObject
;
1640 /* We're going to say if we don't have any DOs from DriverEntry, then we're not legacy.
1641 * Other parts of the I/O manager depend on this behavior */
1642 if (!DriverObject
->DeviceObject
) DriverObject
->Flags
&= ~DRVO_LEGACY_DRIVER
;
1644 /* Loop all Major Functions */
1645 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1648 * Make sure the driver didn't set any dispatch entry point to NULL!
1649 * Doing so is illegal; drivers shouldn't touch entry points they
1653 /* Check if it did so anyway */
1654 if (!DriverObject
->MajorFunction
[i
])
1656 /* Print a warning in the debug log */
1657 DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%lu] to NULL!\n",
1658 &DriverObject
->DriverName
, i
);
1661 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1665 /* Return the Status */
1669 /* PUBLIC FUNCTIONS ***********************************************************/
1676 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1677 IN PDRIVER_INITIALIZE InitializationFunction
)
1679 PDRIVER_OBJECT DriverObject
;
1680 return IopCreateDriver(DriverName
, InitializationFunction
, NULL
, DriverName
, NULL
, &DriverObject
);
1688 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1690 /* Simply dereference the Object */
1691 ObDereferenceObject(DriverObject
);
1699 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1700 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1703 PDRIVER_REINIT_ITEM ReinitItem
;
1705 /* Allocate the entry */
1706 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1707 sizeof(DRIVER_REINIT_ITEM
),
1709 if (!ReinitItem
) return;
1712 ReinitItem
->DriverObject
= DriverObject
;
1713 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1714 ReinitItem
->Context
= Context
;
1716 /* Set the Driver Object flag and insert the entry into the list */
1717 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1718 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1719 &ReinitItem
->ItemEntry
,
1720 &DriverBootReinitListLock
);
1728 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1729 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1732 PDRIVER_REINIT_ITEM ReinitItem
;
1734 /* Allocate the entry */
1735 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1736 sizeof(DRIVER_REINIT_ITEM
),
1738 if (!ReinitItem
) return;
1741 ReinitItem
->DriverObject
= DriverObject
;
1742 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1743 ReinitItem
->Context
= Context
;
1745 /* Set the Driver Object flag and insert the entry into the list */
1746 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1747 ExInterlockedInsertTailList(&DriverReinitListHead
,
1748 &ReinitItem
->ItemEntry
,
1749 &DriverReinitListLock
);
1757 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1758 IN PVOID ClientIdentificationAddress
,
1759 IN ULONG DriverObjectExtensionSize
,
1760 OUT PVOID
*DriverObjectExtension
)
1763 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1764 BOOLEAN Inserted
= FALSE
;
1766 /* Assume failure */
1767 *DriverObjectExtension
= NULL
;
1769 /* Allocate the extension */
1770 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1771 sizeof(IO_CLIENT_EXTENSION
) +
1772 DriverObjectExtensionSize
,
1773 TAG_DRIVER_EXTENSION
);
1774 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1776 /* Clear the extension for teh caller */
1777 RtlZeroMemory(NewDriverExtension
,
1778 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1781 OldIrql
= KeRaiseIrqlToDpcLevel();
1783 /* Fill out the extension */
1784 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1786 /* Loop the current extensions */
1787 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1788 ClientDriverExtension
;
1789 while (DriverExtensions
)
1791 /* Check if the identifier matches */
1792 if (DriverExtensions
->ClientIdentificationAddress
==
1793 ClientIdentificationAddress
)
1795 /* We have a collision, break out */
1799 /* Go to the next one */
1800 DriverExtensions
= DriverExtensions
->NextExtension
;
1803 /* Check if we didn't collide */
1804 if (!DriverExtensions
)
1806 /* Link this one in */
1807 NewDriverExtension
->NextExtension
=
1808 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1809 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1814 /* Release the lock */
1815 KeLowerIrql(OldIrql
);
1817 /* Check if insertion failed */
1820 /* Free the entry and fail */
1821 ExFreePoolWithTag(NewDriverExtension
, TAG_DRIVER_EXTENSION
);
1822 return STATUS_OBJECT_NAME_COLLISION
;
1825 /* Otherwise, return the pointer */
1826 *DriverObjectExtension
= NewDriverExtension
+ 1;
1827 return STATUS_SUCCESS
;
1835 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1836 IN PVOID ClientIdentificationAddress
)
1839 PIO_CLIENT_EXTENSION DriverExtensions
;
1842 OldIrql
= KeRaiseIrqlToDpcLevel();
1844 /* Loop the list until we find the right one */
1845 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1846 while (DriverExtensions
)
1848 /* Check for a match */
1849 if (DriverExtensions
->ClientIdentificationAddress
==
1850 ClientIdentificationAddress
)
1857 DriverExtensions
= DriverExtensions
->NextExtension
;
1861 KeLowerIrql(OldIrql
);
1863 /* Return nothing or the extension */
1864 if (!DriverExtensions
) return NULL
;
1865 return DriverExtensions
+ 1;
1869 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams
)
1871 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1872 UNICODE_STRING ImagePath
;
1873 UNICODE_STRING ServiceName
;
1876 PDEVICE_NODE DeviceNode
;
1877 PDRIVER_OBJECT DriverObject
;
1878 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1882 /* Check if it's an unload request */
1883 if (LoadParams
->DriverObject
)
1885 (*LoadParams
->DriverObject
->DriverUnload
)(LoadParams
->DriverObject
);
1887 /* Return success and signal the event */
1888 LoadParams
->Status
= STATUS_SUCCESS
;
1889 KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1893 RtlInitUnicodeString(&ImagePath
, NULL
);
1896 * Get the service name from the registry key name.
1898 ASSERT(LoadParams
->ServiceName
->Length
>= sizeof(WCHAR
));
1900 ServiceName
= *LoadParams
->ServiceName
;
1901 cur
= LoadParams
->ServiceName
->Buffer
+
1902 (LoadParams
->ServiceName
->Length
/ sizeof(WCHAR
)) - 1;
1903 while (LoadParams
->ServiceName
->Buffer
!= cur
)
1907 ServiceName
.Buffer
= cur
+ 1;
1908 ServiceName
.Length
= LoadParams
->ServiceName
->Length
-
1909 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1910 (ULONG_PTR
)LoadParams
->ServiceName
->Buffer
);
1920 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1922 RtlInitUnicodeString(&ImagePath
, NULL
);
1924 QueryTable
[0].Name
= L
"Type";
1925 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1926 QueryTable
[0].EntryContext
= &Type
;
1928 QueryTable
[1].Name
= L
"ImagePath";
1929 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1930 QueryTable
[1].EntryContext
= &ImagePath
;
1932 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1933 LoadParams
->ServiceName
->Buffer
,
1934 QueryTable
, NULL
, NULL
);
1935 if (!NT_SUCCESS(Status
))
1937 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1938 if (ImagePath
.Buffer
) ExFreePool(ImagePath
.Buffer
);
1939 LoadParams
->Status
= Status
;
1940 KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1945 * Normalize the image path for all later processing.
1948 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1949 if (!NT_SUCCESS(Status
))
1951 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1952 LoadParams
->Status
= Status
;
1953 KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1957 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1958 DPRINT("Type: %lx\n", Type
);
1961 * Get existing DriverObject pointer (in case the driver
1962 * has already been loaded and initialized).
1964 Status
= IopGetDriverObject(&DriverObject
,
1966 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1967 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */));
1969 if (!NT_SUCCESS(Status
))
1972 * Load the driver module
1975 DPRINT("Loading module from %wZ\n", &ImagePath
);
1976 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, &BaseAddress
);
1977 if (!NT_SUCCESS(Status
))
1979 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1980 LoadParams
->Status
= Status
;
1981 KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1986 * Initialize the driver module if it's loaded for the first time
1988 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1989 if (!NT_SUCCESS(Status
))
1991 DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1992 MmUnloadSystemImage(ModuleObject
);
1993 LoadParams
->Status
= Status
;
1994 KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1998 IopDisplayLoadingMessage(&DeviceNode
->ServiceName
);
2000 Status
= IopInitializeDriverModule(DeviceNode
,
2002 &DeviceNode
->ServiceName
,
2003 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
2004 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
2006 if (!NT_SUCCESS(Status
))
2008 DPRINT1("IopInitializeDriverModule() failed (Status %lx)\n", Status
);
2009 MmUnloadSystemImage(ModuleObject
);
2010 IopFreeDeviceNode(DeviceNode
);
2011 LoadParams
->Status
= Status
;
2012 KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
2016 /* Initialize and start device */
2017 IopInitializeDevice(DeviceNode
, DriverObject
);
2018 Status
= IopStartDevice(DeviceNode
);
2022 DPRINT("DriverObject already exist in ObjectManager\n");
2023 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2025 /* IopGetDriverObject references the DriverObject, so dereference it */
2026 ObDereferenceObject(DriverObject
);
2029 /* Pass status to the caller and signal the event */
2030 LoadParams
->Status
= Status
;
2031 KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
2037 * Loads a device driver.
2041 * Name of the service to load (registry key).
2050 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
2052 UNICODE_STRING CapturedDriverServiceName
= { 0, 0, NULL
};
2053 KPROCESSOR_MODE PreviousMode
;
2054 LOAD_UNLOAD_PARAMS LoadParams
;
2059 PreviousMode
= KeGetPreviousMode();
2062 * Check security privileges
2065 /* FIXME: Uncomment when privileges will be correctly implemented. */
2067 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
2069 DPRINT("Privilege not held\n");
2070 return STATUS_PRIVILEGE_NOT_HELD
;
2074 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
2077 if (!NT_SUCCESS(Status
))
2082 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
2084 LoadParams
.ServiceName
= &CapturedDriverServiceName
;
2085 LoadParams
.DriverObject
= NULL
;
2086 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
2088 /* Call the load/unload routine, depending on current process */
2089 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
2091 /* Just call right away */
2092 IopLoadUnloadDriver(&LoadParams
);
2096 /* Load/Unload must be called from system process */
2097 ExInitializeWorkItem(&LoadParams
.WorkItem
,
2098 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
2099 (PVOID
)&LoadParams
);
2102 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
2104 /* And wait when it completes */
2105 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
2109 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
2112 return LoadParams
.Status
;
2118 * Unloads a legacy device driver.
2122 * Name of the service to unload (registry key).
2132 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
2134 return IopUnloadDriver(DriverServiceName
, FALSE
);