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 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
315 /* FIXME: This check may be removed once the bug is fixed */
316 if (ServiceName
->Buffer
== NULL
)
318 DPRINT1("If you see this, please report to Fireball or hpoussin!\n");
319 return STATUS_UNSUCCESSFUL
;
322 if (ExpInTextModeSetup
)
324 /* We have no registry, but luckily we know where all the drivers are */
326 /* ServiceStart < 4 is all that matters */
329 /* IopNormalizeImagePath will do all of the work for us if we give it an empty string */
330 ServiceImagePath
.Length
= ServiceImagePath
.MaximumLength
= 0;
331 ServiceImagePath
.Buffer
= NULL
;
335 /* Open CurrentControlSet */
336 RtlInitUnicodeString(&CCSName
,
337 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
338 Status
= IopOpenRegistryKeyEx(&CCSKey
, NULL
, &CCSName
, KEY_READ
);
339 if (!NT_SUCCESS(Status
))
341 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with Status %08X\n",
346 /* Open service key */
347 Status
= IopOpenRegistryKeyEx(&ServiceKey
, CCSKey
, ServiceName
, KEY_READ
);
348 if (!NT_SUCCESS(Status
))
350 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with Status %08X\n",
351 ServiceName
, Status
);
357 * Get information about the service.
360 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
362 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
364 QueryTable
[0].Name
= L
"Start";
365 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
366 QueryTable
[0].EntryContext
= &ServiceStart
;
368 QueryTable
[1].Name
= L
"ImagePath";
369 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
370 QueryTable
[1].EntryContext
= &ServiceImagePath
;
372 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
373 (PWSTR
)ServiceKey
, QueryTable
, NULL
, NULL
);
378 if (!NT_SUCCESS(Status
))
380 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
386 * Normalize the image path for all later processing.
389 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
391 if (!NT_SUCCESS(Status
))
393 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
398 * Case for disabled drivers
401 if (ServiceStart
>= 4)
403 /* We can't load this */
404 Status
= STATUS_DRIVER_UNABLE_TO_LOAD
;
408 DPRINT("Loading module from %wZ\n", &ServiceImagePath
);
409 Status
= MmLoadSystemImage(&ServiceImagePath
, NULL
, NULL
, 0, (PVOID
)ModuleObject
, &BaseAddress
);
410 if (NT_SUCCESS(Status
))
412 IopDisplayLoadingMessage(ServiceName
);
416 ExFreePool(ServiceImagePath
.Buffer
);
419 * Now check if the module was loaded successfully.
422 if (!NT_SUCCESS(Status
))
424 DPRINT("Module loading failed (Status %x)\n", Status
);
427 DPRINT("Module loading (Status %x)\n", Status
);
434 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry
);
437 * IopInitializeDriverModule
439 * Initialize a loaded driver.
443 * Pointer to device node.
446 * Module object representing the driver. It can be retrieve by
447 * IopLoadServiceModule.
450 * Name of the service (as in registry).
453 * Set to TRUE for file system drivers.
456 * On successful return this contains the driver object representing
461 IopInitializeDriverModule(
462 IN PDEVICE_NODE DeviceNode
,
463 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
464 IN PUNICODE_STRING ServiceName
,
465 IN BOOLEAN FileSystemDriver
,
466 OUT PDRIVER_OBJECT
*DriverObject
)
468 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
469 WCHAR NameBuffer
[MAX_PATH
];
470 UNICODE_STRING DriverName
;
471 UNICODE_STRING RegistryKey
;
472 PDRIVER_INITIALIZE DriverEntry
;
473 PDRIVER_OBJECT Driver
;
476 DriverEntry
= ModuleObject
->EntryPoint
;
478 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
480 RegistryKey
.Length
= 0;
481 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
482 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
483 if (RegistryKey
.Buffer
== NULL
)
485 return STATUS_INSUFFICIENT_RESOURCES
;
487 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
488 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
492 RtlInitUnicodeString(&RegistryKey
, NULL
);
495 /* Create ModuleName string */
496 if (ServiceName
&& ServiceName
->Length
> 0)
498 if (FileSystemDriver
== TRUE
)
499 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
501 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
503 RtlInitUnicodeString(&DriverName
, NameBuffer
);
504 DriverName
.MaximumLength
= sizeof(NameBuffer
);
506 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
508 DPRINT("Driver name: '%wZ'\n", &DriverName
);
511 DriverName
.Length
= 0;
513 Status
= IopCreateDriver(
514 DriverName
.Length
> 0 ? &DriverName
: NULL
,
520 RtlFreeUnicodeString(&RegistryKey
);
522 *DriverObject
= Driver
;
523 if (!NT_SUCCESS(Status
))
525 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status
);
529 MmFreeDriverInitialization((PLDR_DATA_TABLE_ENTRY
)Driver
->DriverSection
);
531 /* Set the driver as initialized */
532 IopReadyDeviceObjects(Driver
);
534 if (PnpSystemInit
) IopReinitializeDrivers();
536 return STATUS_SUCCESS
;
540 * IopAttachFilterDriversCallback
542 * Internal routine used by IopAttachFilterDrivers.
546 IopAttachFilterDriversCallback(
554 PDEVICE_NODE DeviceNode
= Context
;
555 UNICODE_STRING ServiceName
;
557 PLDR_DATA_TABLE_ENTRY ModuleObject
;
558 PDRIVER_OBJECT DriverObject
;
561 /* No filter value present */
562 if (ValueType
== REG_NONE
)
563 return STATUS_SUCCESS
;
565 for (Filters
= ValueData
;
566 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
568 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
570 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
572 ServiceName
.Buffer
= Filters
;
573 ServiceName
.MaximumLength
=
574 ServiceName
.Length
= (USHORT
)wcslen(Filters
) * sizeof(WCHAR
);
576 Status
= IopGetDriverObject(&DriverObject
,
579 if (!NT_SUCCESS(Status
))
581 /* Load and initialize the filter driver */
582 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
583 if (!NT_SUCCESS(Status
))
586 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
587 FALSE
, &DriverObject
);
588 if (!NT_SUCCESS(Status
))
592 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
594 /* Remove extra reference */
595 ObDereferenceObject(DriverObject
);
597 if (!NT_SUCCESS(Status
))
601 return STATUS_SUCCESS
;
605 * IopAttachFilterDrivers
607 * Load filter drivers for specified device node.
611 * Set to TRUE for loading lower level filters or FALSE for upper
616 IopAttachFilterDrivers(
617 PDEVICE_NODE DeviceNode
,
620 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = { { NULL
, 0, NULL
, NULL
, 0, NULL
, 0 }, };
621 UNICODE_STRING Class
;
622 WCHAR ClassBuffer
[40];
623 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
624 HANDLE EnumRootKey
, SubKey
;
627 /* Open enumeration root key */
628 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
629 &EnumRoot
, KEY_READ
);
630 if (!NT_SUCCESS(Status
))
632 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
637 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
638 &DeviceNode
->InstancePath
, KEY_READ
);
639 if (!NT_SUCCESS(Status
))
641 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
642 ZwClose(EnumRootKey
);
647 * First load the device filters
649 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
651 QueryTable
[0].Name
= L
"LowerFilters";
653 QueryTable
[0].Name
= L
"UpperFilters";
654 QueryTable
[0].Flags
= 0;
655 QueryTable
[0].DefaultType
= REG_NONE
;
657 Status
= RtlQueryRegistryValues(
663 if (!NT_SUCCESS(Status
))
665 DPRINT1("Failed to load device %s filters: %08X\n",
666 Lower
? "lower" : "upper", Status
);
668 ZwClose(EnumRootKey
);
673 * Now get the class GUID
676 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
677 Class
.Buffer
= ClassBuffer
;
678 QueryTable
[0].QueryRoutine
= NULL
;
679 QueryTable
[0].Name
= L
"ClassGUID";
680 QueryTable
[0].EntryContext
= &Class
;
681 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
683 Status
= RtlQueryRegistryValues(
692 ZwClose(EnumRootKey
);
695 * Load the class filter driver
697 if (NT_SUCCESS(Status
))
699 UNICODE_STRING ControlClass
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
701 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
702 &ControlClass
, KEY_READ
);
703 if (!NT_SUCCESS(Status
))
705 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
710 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
712 if (!NT_SUCCESS(Status
))
714 /* It's okay if there's no class key */
715 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
716 ZwClose(EnumRootKey
);
717 return STATUS_SUCCESS
;
720 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
722 QueryTable
[0].Name
= L
"LowerFilters";
724 QueryTable
[0].Name
= L
"UpperFilters";
725 QueryTable
[0].EntryContext
= NULL
;
726 QueryTable
[0].Flags
= 0;
727 QueryTable
[0].DefaultType
= REG_NONE
;
729 Status
= RtlQueryRegistryValues(
738 ZwClose(EnumRootKey
);
740 if (!NT_SUCCESS(Status
))
742 DPRINT1("Failed to load class %s filters: %08X\n",
743 Lower
? "lower" : "upper", Status
);
745 ZwClose(EnumRootKey
);
750 return STATUS_SUCCESS
;
755 MiResolveImageReferences(IN PVOID ImageBase
,
756 IN PUNICODE_STRING ImageFileDirectory
,
757 IN PUNICODE_STRING NamePrefix OPTIONAL
,
758 OUT PCHAR
*MissingApi
,
759 OUT PWCHAR
*MissingDriver
,
760 OUT PLOAD_IMPORTS
*LoadImports
);
763 // Used for images already loaded (boot drivers)
768 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry
,
769 PUNICODE_STRING FileName
,
770 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
773 UNICODE_STRING BaseName
, BaseDirectory
;
774 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
775 PCHAR MissingApiName
, Buffer
;
776 PWCHAR MissingDriverName
;
777 PVOID DriverBase
= LdrEntry
->DllBase
;
779 /* Allocate a buffer we'll use for names */
780 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
784 return STATUS_INSUFFICIENT_RESOURCES
;
787 /* Check for a separator */
788 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
793 /* Loop the path until we get to the base name */
794 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
795 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
798 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
799 BaseLength
*= sizeof(WCHAR
);
801 /* Setup the string */
802 BaseName
.Length
= (USHORT
)BaseLength
;
807 /* Otherwise, we already have a base name */
808 BaseName
.Length
= FileName
->Length
;
809 BaseName
.Buffer
= FileName
->Buffer
;
812 /* Setup the maximum length */
813 BaseName
.MaximumLength
= BaseName
.Length
;
815 /* Now compute the base directory */
816 BaseDirectory
= *FileName
;
817 BaseDirectory
.Length
-= BaseName
.Length
;
818 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
820 /* Resolve imports */
821 MissingApiName
= Buffer
;
822 Status
= MiResolveImageReferences(DriverBase
,
829 /* Free the temporary buffer */
830 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
832 /* Check the result of the imports resolution */
833 if (!NT_SUCCESS(Status
)) return Status
;
836 *ModuleObject
= LdrEntry
;
837 return STATUS_SUCCESS
;
841 * IopInitializeBuiltinDriver
843 * Initialize a driver that is already loaded in memory.
849 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY BootLdrEntry
)
851 PDEVICE_NODE DeviceNode
;
852 PDRIVER_OBJECT DriverObject
;
854 PWCHAR FileNameWithoutPath
;
855 LPWSTR FileExtension
;
856 PUNICODE_STRING ModuleName
= &BootLdrEntry
->BaseDllName
;
857 PLDR_DATA_TABLE_ENTRY LdrEntry
;
858 PLIST_ENTRY NextEntry
;
859 UNICODE_STRING ServiceName
;
862 * Display 'Loading XXX...' message
864 IopDisplayLoadingMessage(ModuleName
);
865 InbvIndicateProgress();
868 * Generate filename without path (not needed by freeldr)
870 FileNameWithoutPath
= wcsrchr(ModuleName
->Buffer
, L
'\\');
871 if (FileNameWithoutPath
== NULL
)
873 FileNameWithoutPath
= ModuleName
->Buffer
;
877 FileNameWithoutPath
++;
881 * Strip the file extension from ServiceName
883 RtlCreateUnicodeString(&ServiceName
, FileNameWithoutPath
);
884 FileExtension
= wcsrchr(ServiceName
.Buffer
, '.');
885 if (FileExtension
!= NULL
)
887 ServiceName
.Length
-= (USHORT
)wcslen(FileExtension
) * sizeof(WCHAR
);
888 FileExtension
[0] = 0;
892 * Determine the right device object
894 /* Use IopRootDeviceNode for now */
895 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
896 if (!NT_SUCCESS(Status
))
898 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
902 /* Lookup the new Ldr entry in PsLoadedModuleList */
903 NextEntry
= PsLoadedModuleList
.Flink
;
904 while (NextEntry
!= &PsLoadedModuleList
)
906 LdrEntry
= CONTAINING_RECORD(NextEntry
,
907 LDR_DATA_TABLE_ENTRY
,
909 if (RtlEqualUnicodeString(ModuleName
, &LdrEntry
->BaseDllName
, TRUE
))
914 NextEntry
= NextEntry
->Flink
;
916 NT_ASSERT(NextEntry
!= &PsLoadedModuleList
);
919 * Initialize the driver
921 Status
= IopInitializeDriverModule(DeviceNode
, LdrEntry
,
922 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
924 if (!NT_SUCCESS(Status
))
926 IopFreeDeviceNode(DeviceNode
);
930 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
931 if (NT_SUCCESS(Status
))
933 Status
= IopStartDevice(DeviceNode
);
936 /* Remove extra reference from IopInitializeDriverModule */
937 ObDereferenceObject(DriverObject
);
943 * IopInitializeBootDrivers
945 * Initialize boot drivers and free memory for boot files.
956 IopInitializeBootDrivers(VOID
)
958 PLIST_ENTRY ListHead
, NextEntry
, NextEntry2
;
959 PLDR_DATA_TABLE_ENTRY LdrEntry
;
960 PDEVICE_NODE DeviceNode
;
961 PDRIVER_OBJECT DriverObject
;
962 LDR_DATA_TABLE_ENTRY ModuleObject
;
964 UNICODE_STRING DriverName
;
966 PDRIVER_INFORMATION DriverInfo
, DriverInfoTag
;
968 PBOOT_DRIVER_LIST_ENTRY BootEntry
;
969 DPRINT("IopInitializeBootDrivers()\n");
971 /* Use IopRootDeviceNode for now */
972 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, NULL
, &DeviceNode
);
973 if (!NT_SUCCESS(Status
)) return;
975 /* Setup the module object for the RAW FS Driver */
976 ModuleObject
.DllBase
= NULL
;
977 ModuleObject
.SizeOfImage
= 0;
978 ModuleObject
.EntryPoint
= RawFsDriverEntry
;
979 RtlInitUnicodeString(&DriverName
, L
"RAW");
982 Status
= IopInitializeDriverModule(DeviceNode
,
987 if (!NT_SUCCESS(Status
))
990 IopFreeDeviceNode(DeviceNode
);
994 /* Now initialize the associated device */
995 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
996 if (!NT_SUCCESS(Status
))
999 IopFreeDeviceNode(DeviceNode
);
1000 ObDereferenceObject(DriverObject
);
1005 Status
= IopStartDevice(DeviceNode
);
1006 if (!NT_SUCCESS(Status
))
1009 IopFreeDeviceNode(DeviceNode
);
1010 ObDereferenceObject(DriverObject
);
1014 /* Get highest group order index */
1015 IopGroupIndex
= PpInitGetGroupOrderIndex(NULL
);
1016 if (IopGroupIndex
== 0xFFFF) ASSERT(FALSE
);
1018 /* Allocate the group table */
1019 IopGroupTable
= ExAllocatePoolWithTag(PagedPool
,
1020 IopGroupIndex
* sizeof(LIST_ENTRY
),
1022 if (IopGroupTable
== NULL
) ASSERT(FALSE
);
1024 /* Initialize the group table lists */
1025 for (i
= 0; i
< IopGroupIndex
; i
++) InitializeListHead(&IopGroupTable
[i
]);
1027 /* Loop the boot modules */
1028 ListHead
= &KeLoaderBlock
->LoadOrderListHead
;
1029 NextEntry
= ListHead
->Flink
;
1030 while (ListHead
!= NextEntry
)
1033 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1034 LDR_DATA_TABLE_ENTRY
,
1037 /* Check if the DLL needs to be initialized */
1038 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
1040 /* Call its entrypoint */
1041 MmCallDllInitialize(LdrEntry
, NULL
);
1044 /* Go to the next driver */
1045 NextEntry
= NextEntry
->Flink
;
1048 /* Loop the boot drivers */
1049 ListHead
= &KeLoaderBlock
->BootDriverListHead
;
1050 NextEntry
= ListHead
->Flink
;
1051 while (ListHead
!= NextEntry
)
1054 BootEntry
= CONTAINING_RECORD(NextEntry
,
1055 BOOT_DRIVER_LIST_ENTRY
,
1058 /* Get the driver loader entry */
1059 LdrEntry
= BootEntry
->LdrEntry
;
1061 /* Allocate our internal accounting structure */
1062 DriverInfo
= ExAllocatePoolWithTag(PagedPool
,
1063 sizeof(DRIVER_INFORMATION
),
1067 /* Zero it and initialize it */
1068 RtlZeroMemory(DriverInfo
, sizeof(DRIVER_INFORMATION
));
1069 InitializeListHead(&DriverInfo
->Link
);
1070 DriverInfo
->DataTableEntry
= BootEntry
;
1072 /* Open the registry key */
1073 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
1075 &BootEntry
->RegistryPath
,
1077 if ((NT_SUCCESS(Status
)) || /* ReactOS HACK for SETUPLDR */
1078 ((KeLoaderBlock
->SetupLdrBlock
) && ((KeyHandle
= (PVOID
)1)))) // yes, it's an assignment!
1080 /* Save the handle */
1081 DriverInfo
->ServiceHandle
= KeyHandle
;
1083 /* Get the group oder index */
1084 Index
= PpInitGetGroupOrderIndex(KeyHandle
);
1086 /* Get the tag position */
1087 DriverInfo
->TagPosition
= PipGetDriverTagPriority(KeyHandle
);
1089 /* Insert it into the list, at the right place */
1090 ASSERT(Index
< IopGroupIndex
);
1091 NextEntry2
= IopGroupTable
[Index
].Flink
;
1092 while (NextEntry2
!= &IopGroupTable
[Index
])
1094 /* Get the driver info */
1095 DriverInfoTag
= CONTAINING_RECORD(NextEntry2
,
1099 /* Check if we found the right tag position */
1100 if (DriverInfoTag
->TagPosition
> DriverInfo
->TagPosition
)
1107 NextEntry2
= NextEntry2
->Flink
;
1110 /* Insert us right before the next entry */
1111 NextEntry2
= NextEntry2
->Blink
;
1112 InsertHeadList(NextEntry2
, &DriverInfo
->Link
);
1116 /* Go to the next driver */
1117 NextEntry
= NextEntry
->Flink
;
1120 /* Loop each group index */
1121 for (i
= 0; i
< IopGroupIndex
; i
++)
1123 /* Loop each group table */
1124 NextEntry
= IopGroupTable
[i
].Flink
;
1125 while (NextEntry
!= &IopGroupTable
[i
])
1128 DriverInfo
= CONTAINING_RECORD(NextEntry
,
1132 /* Get the driver loader entry */
1133 LdrEntry
= DriverInfo
->DataTableEntry
->LdrEntry
;
1136 IopInitializeBuiltinDriver(LdrEntry
);
1139 NextEntry
= NextEntry
->Flink
;
1143 /* In old ROS, the loader list became empty after this point. Simulate. */
1144 InitializeListHead(&KeLoaderBlock
->LoadOrderListHead
);
1150 IopInitializeSystemDrivers(VOID
)
1152 PUNICODE_STRING
*DriverList
, *SavedList
;
1154 /* No system drivers on the boot cd */
1155 if (KeLoaderBlock
->SetupLdrBlock
) return;
1157 /* Get the driver list */
1158 SavedList
= DriverList
= CmGetSystemDriverList();
1164 /* Load the driver */
1165 ZwLoadDriver(*DriverList
);
1167 /* Free the entry */
1168 RtlFreeUnicodeString(*DriverList
);
1169 ExFreePool(*DriverList
);
1172 InbvIndicateProgress();
1177 ExFreePool(SavedList
);
1183 * Unloads a device driver.
1187 * Name of the service to unload (registry key).
1190 * Whether to unload Plug & Plug or only legacy drivers. If this
1191 * parameter is set to FALSE, the routine will unload only legacy
1198 * Guard the whole function by SEH.
1202 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1204 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1205 UNICODE_STRING ImagePath
;
1206 UNICODE_STRING ServiceName
;
1207 UNICODE_STRING ObjectName
;
1208 PDRIVER_OBJECT DriverObject
;
1209 PDEVICE_OBJECT DeviceObject
;
1210 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1211 LOAD_UNLOAD_PARAMS LoadParams
;
1214 BOOLEAN SafeToUnload
= TRUE
;
1216 DPRINT("IopUnloadDriver('%wZ', %u)\n", DriverServiceName
, UnloadPnpDrivers
);
1221 * Get the service name from the registry key name
1224 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1226 Start
= DriverServiceName
->Buffer
;
1230 RtlInitUnicodeString(&ServiceName
, Start
);
1233 * Construct the driver object name
1236 ObjectName
.Length
= ((USHORT
)wcslen(Start
) + 8) * sizeof(WCHAR
);
1237 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1238 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1239 if (!ObjectName
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1240 wcscpy(ObjectName
.Buffer
, DRIVER_ROOT_NAME
);
1241 memcpy(ObjectName
.Buffer
+ 8, Start
, ObjectName
.Length
- 8 * sizeof(WCHAR
));
1242 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1245 * Find the driver object
1247 Status
= ObReferenceObjectByName(&ObjectName
,
1254 (PVOID
*)&DriverObject
);
1256 if (!NT_SUCCESS(Status
))
1258 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName
);
1259 ExFreePool(ObjectName
.Buffer
);
1264 * Free the buffer for driver object name
1266 ExFreePool(ObjectName
.Buffer
);
1268 /* Check that driver is not already unloading */
1269 if (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
)
1271 DPRINT1("Driver deletion pending\n");
1272 ObDereferenceObject(DriverObject
);
1273 return STATUS_DELETE_PENDING
;
1277 * Get path of service...
1280 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1282 RtlInitUnicodeString(&ImagePath
, NULL
);
1284 QueryTable
[0].Name
= L
"ImagePath";
1285 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1286 QueryTable
[0].EntryContext
= &ImagePath
;
1288 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1289 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1291 if (!NT_SUCCESS(Status
))
1293 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1294 ObDereferenceObject(DriverObject
);
1299 * Normalize the image path for all later processing.
1302 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1304 if (!NT_SUCCESS(Status
))
1306 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1307 ObDereferenceObject(DriverObject
);
1312 * Free the service path
1315 ExFreePool(ImagePath
.Buffer
);
1318 * Unload the module and release the references to the device object
1321 /* Call the load/unload routine, depending on current process */
1322 if (DriverObject
->DriverUnload
&& DriverObject
->DriverSection
&&
1323 (UnloadPnpDrivers
|| (DriverObject
->Flags
& DRVO_LEGACY_DRIVER
)))
1325 /* Loop through each device object of the driver
1326 and set DOE_UNLOAD_PENDING flag */
1327 DeviceObject
= DriverObject
->DeviceObject
;
1328 while (DeviceObject
)
1330 /* Set the unload pending flag for the device */
1331 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1332 DeviceExtension
->ExtensionFlags
|= DOE_UNLOAD_PENDING
;
1334 /* Make sure there are no attached devices or no reference counts */
1335 if ((DeviceObject
->ReferenceCount
) || (DeviceObject
->AttachedDevice
))
1337 /* Not safe to unload */
1338 DPRINT1("Drivers device object is referenced or has attached devices\n");
1340 SafeToUnload
= FALSE
;
1343 DeviceObject
= DeviceObject
->NextDevice
;
1346 /* If not safe to unload, then return success */
1349 ObDereferenceObject(DriverObject
);
1350 return STATUS_SUCCESS
;
1353 DPRINT1("Unloading driver '%wZ' (manual)\n", &DriverObject
->DriverName
);
1355 /* Set the unload invoked flag */
1356 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
1358 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1360 /* Just call right away */
1361 (*DriverObject
->DriverUnload
)(DriverObject
);
1365 /* Load/Unload must be called from system process */
1367 /* Prepare parameters block */
1368 LoadParams
.DriverObject
= DriverObject
;
1369 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1371 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1372 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1373 (PVOID
)&LoadParams
);
1376 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1378 /* And wait when it completes */
1379 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1383 /* Mark the driver object temporary, so it could be deleted later */
1384 ObMakeTemporaryObject(DriverObject
);
1386 /* Dereference it 2 times */
1387 ObDereferenceObject(DriverObject
);
1388 ObDereferenceObject(DriverObject
);
1390 return STATUS_SUCCESS
;
1394 DPRINT1("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject
->DriverName
);
1396 /* Dereference one time (refd inside this function) */
1397 ObDereferenceObject(DriverObject
);
1399 /* Return unloading failure */
1400 return STATUS_INVALID_DEVICE_REQUEST
;
1406 IopReinitializeDrivers(VOID
)
1408 PDRIVER_REINIT_ITEM ReinitItem
;
1411 /* Get the first entry and start looping */
1412 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1413 &DriverReinitListLock
);
1417 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1419 /* Increment reinitialization counter */
1420 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1422 /* Remove the device object flag */
1423 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1425 /* Call the routine */
1426 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1427 ReinitItem
->Context
,
1428 ReinitItem
->DriverObject
->
1429 DriverExtension
->Count
);
1431 /* Free the entry */
1434 /* Move to the next one */
1435 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1436 &DriverReinitListLock
);
1442 IopReinitializeBootDrivers(VOID
)
1444 PDRIVER_REINIT_ITEM ReinitItem
;
1447 /* Get the first entry and start looping */
1448 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1449 &DriverBootReinitListLock
);
1453 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1455 /* Increment reinitialization counter */
1456 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1458 /* Remove the device object flag */
1459 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1461 /* Call the routine */
1462 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1463 ReinitItem
->Context
,
1464 ReinitItem
->DriverObject
->
1465 DriverExtension
->Count
);
1467 /* Free the entry */
1470 /* Move to the next one */
1471 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1472 &DriverBootReinitListLock
);
1478 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1479 IN PDRIVER_INITIALIZE InitializationFunction
,
1480 IN PUNICODE_STRING RegistryPath
,
1481 IN PCUNICODE_STRING ServiceName
,
1482 PLDR_DATA_TABLE_ENTRY ModuleObject
,
1483 OUT PDRIVER_OBJECT
*pDriverObject
)
1485 WCHAR NameBuffer
[100];
1487 UNICODE_STRING LocalDriverName
;
1489 OBJECT_ATTRIBUTES ObjectAttributes
;
1491 PDRIVER_OBJECT DriverObject
;
1492 UNICODE_STRING ServiceKeyName
;
1494 ULONG i
, RetryCount
= 0;
1497 /* First, create a unique name for the driver if we don't have one */
1500 /* Create a random name and set up the string*/
1501 NameLength
= (USHORT
)swprintf(NameBuffer
,
1502 DRIVER_ROOT_NAME L
"%08u",
1504 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1505 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1506 LocalDriverName
.Buffer
= NameBuffer
;
1510 /* So we can avoid another code path, use a local var */
1511 LocalDriverName
= *DriverName
;
1514 /* Initialize the Attributes */
1515 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1516 InitializeObjectAttributes(&ObjectAttributes
,
1518 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1522 /* Create the Object */
1523 Status
= ObCreateObject(KernelMode
,
1531 (PVOID
*)&DriverObject
);
1532 if (!NT_SUCCESS(Status
)) return Status
;
1534 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1536 /* Set up the Object */
1537 RtlZeroMemory(DriverObject
, ObjectSize
);
1538 DriverObject
->Type
= IO_TYPE_DRIVER
;
1539 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1540 DriverObject
->Flags
= DRVO_LEGACY_DRIVER
;
1541 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1542 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1543 DriverObject
->DriverInit
= InitializationFunction
;
1544 DriverObject
->DriverSection
= ModuleObject
;
1545 /* Loop all Major Functions */
1546 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1548 /* Invalidate each function */
1549 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1552 /* Set up the service key name buffer */
1553 ServiceKeyName
.MaximumLength
= ServiceName
->Length
+ sizeof(UNICODE_NULL
);
1554 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1555 ServiceKeyName
.MaximumLength
,
1557 if (!ServiceKeyName
.Buffer
)
1560 ObMakeTemporaryObject(DriverObject
);
1561 ObDereferenceObject(DriverObject
);
1562 return STATUS_INSUFFICIENT_RESOURCES
;
1565 /* Copy the name and set it in the driver extension */
1566 RtlCopyUnicodeString(&ServiceKeyName
,
1568 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1570 /* Make a copy of the driver name to store in the driver object */
1571 DriverObject
->DriverName
.MaximumLength
= LocalDriverName
.Length
;
1572 DriverObject
->DriverName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1573 DriverObject
->DriverName
.MaximumLength
,
1575 if (!DriverObject
->DriverName
.Buffer
)
1578 ObMakeTemporaryObject(DriverObject
);
1579 ObDereferenceObject(DriverObject
);
1580 return STATUS_INSUFFICIENT_RESOURCES
;
1583 RtlCopyUnicodeString(&DriverObject
->DriverName
,
1586 /* Add the Object and get its handle */
1587 Status
= ObInsertObject(DriverObject
,
1594 /* Eliminate small possibility when this function is called more than
1595 once in a row, and KeTickCount doesn't get enough time to change */
1596 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1602 if (!NT_SUCCESS(Status
)) return Status
;
1604 /* Now reference it */
1605 Status
= ObReferenceObjectByHandle(hDriver
,
1609 (PVOID
*)&DriverObject
,
1612 /* Close the extra handle */
1615 if (!NT_SUCCESS(Status
))
1618 ObMakeTemporaryObject(DriverObject
);
1619 ObDereferenceObject(DriverObject
);
1623 DriverObject
->HardwareDatabase
= &IopHardwareDatabaseKey
;
1624 DriverObject
->DriverStart
= ModuleObject
? ModuleObject
->DllBase
: 0;
1625 DriverObject
->DriverSize
= ModuleObject
? ModuleObject
->SizeOfImage
: 0;
1627 /* Finally, call its init function */
1628 DPRINT("RegistryKey: %wZ\n", RegistryPath
);
1629 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction
);
1630 Status
= (*InitializationFunction
)(DriverObject
, RegistryPath
);
1631 if (!NT_SUCCESS(Status
))
1633 /* If it didn't work, then kill the object */
1634 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName
, Status
);
1635 DriverObject
->DriverSection
= NULL
;
1636 ObMakeTemporaryObject(DriverObject
);
1637 ObDereferenceObject(DriverObject
);
1642 /* Returns to caller the object */
1643 *pDriverObject
= DriverObject
;
1646 /* We're going to say if we don't have any DOs from DriverEntry, then we're not legacy.
1647 * Other parts of the I/O manager depend on this behavior */
1648 if (!DriverObject
->DeviceObject
) DriverObject
->Flags
&= ~DRVO_LEGACY_DRIVER
;
1650 /* Loop all Major Functions */
1651 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1654 * Make sure the driver didn't set any dispatch entry point to NULL!
1655 * Doing so is illegal; drivers shouldn't touch entry points they
1659 /* Check if it did so anyway */
1660 if (!DriverObject
->MajorFunction
[i
])
1662 /* Print a warning in the debug log */
1663 DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%lu] to NULL!\n",
1664 &DriverObject
->DriverName
, i
);
1667 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1671 /* Return the Status */
1675 /* PUBLIC FUNCTIONS ***********************************************************/
1682 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1683 IN PDRIVER_INITIALIZE InitializationFunction
)
1685 PDRIVER_OBJECT DriverObject
;
1686 return IopCreateDriver(DriverName
, InitializationFunction
, NULL
, DriverName
, NULL
, &DriverObject
);
1694 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1696 /* Simply dereference the Object */
1697 ObDereferenceObject(DriverObject
);
1705 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1706 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1709 PDRIVER_REINIT_ITEM ReinitItem
;
1711 /* Allocate the entry */
1712 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1713 sizeof(DRIVER_REINIT_ITEM
),
1715 if (!ReinitItem
) return;
1718 ReinitItem
->DriverObject
= DriverObject
;
1719 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1720 ReinitItem
->Context
= Context
;
1722 /* Set the Driver Object flag and insert the entry into the list */
1723 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1724 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1725 &ReinitItem
->ItemEntry
,
1726 &DriverBootReinitListLock
);
1734 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1735 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1738 PDRIVER_REINIT_ITEM ReinitItem
;
1740 /* Allocate the entry */
1741 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1742 sizeof(DRIVER_REINIT_ITEM
),
1744 if (!ReinitItem
) return;
1747 ReinitItem
->DriverObject
= DriverObject
;
1748 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1749 ReinitItem
->Context
= Context
;
1751 /* Set the Driver Object flag and insert the entry into the list */
1752 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1753 ExInterlockedInsertTailList(&DriverReinitListHead
,
1754 &ReinitItem
->ItemEntry
,
1755 &DriverReinitListLock
);
1763 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1764 IN PVOID ClientIdentificationAddress
,
1765 IN ULONG DriverObjectExtensionSize
,
1766 OUT PVOID
*DriverObjectExtension
)
1769 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1770 BOOLEAN Inserted
= FALSE
;
1772 /* Assume failure */
1773 *DriverObjectExtension
= NULL
;
1775 /* Allocate the extension */
1776 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1777 sizeof(IO_CLIENT_EXTENSION
) +
1778 DriverObjectExtensionSize
,
1779 TAG_DRIVER_EXTENSION
);
1780 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1782 /* Clear the extension for teh caller */
1783 RtlZeroMemory(NewDriverExtension
,
1784 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1787 OldIrql
= KeRaiseIrqlToDpcLevel();
1789 /* Fill out the extension */
1790 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1792 /* Loop the current extensions */
1793 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1794 ClientDriverExtension
;
1795 while (DriverExtensions
)
1797 /* Check if the identifier matches */
1798 if (DriverExtensions
->ClientIdentificationAddress
==
1799 ClientIdentificationAddress
)
1801 /* We have a collision, break out */
1805 /* Go to the next one */
1806 DriverExtensions
= DriverExtensions
->NextExtension
;
1809 /* Check if we didn't collide */
1810 if (!DriverExtensions
)
1812 /* Link this one in */
1813 NewDriverExtension
->NextExtension
=
1814 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1815 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1820 /* Release the lock */
1821 KeLowerIrql(OldIrql
);
1823 /* Check if insertion failed */
1826 /* Free the entry and fail */
1827 ExFreePoolWithTag(NewDriverExtension
, TAG_DRIVER_EXTENSION
);
1828 return STATUS_OBJECT_NAME_COLLISION
;
1831 /* Otherwise, return the pointer */
1832 *DriverObjectExtension
= NewDriverExtension
+ 1;
1833 return STATUS_SUCCESS
;
1841 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1842 IN PVOID ClientIdentificationAddress
)
1845 PIO_CLIENT_EXTENSION DriverExtensions
;
1848 OldIrql
= KeRaiseIrqlToDpcLevel();
1850 /* Loop the list until we find the right one */
1851 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1852 while (DriverExtensions
)
1854 /* Check for a match */
1855 if (DriverExtensions
->ClientIdentificationAddress
==
1856 ClientIdentificationAddress
)
1863 DriverExtensions
= DriverExtensions
->NextExtension
;
1867 KeLowerIrql(OldIrql
);
1869 /* Return nothing or the extension */
1870 if (!DriverExtensions
) return NULL
;
1871 return DriverExtensions
+ 1;
1875 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams
)
1877 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1878 UNICODE_STRING ImagePath
;
1879 UNICODE_STRING ServiceName
;
1882 PDEVICE_NODE DeviceNode
;
1883 PDRIVER_OBJECT DriverObject
;
1884 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1888 /* Check if it's an unload request */
1889 if (LoadParams
->DriverObject
)
1891 (*LoadParams
->DriverObject
->DriverUnload
)(LoadParams
->DriverObject
);
1893 /* Return success and signal the event */
1894 LoadParams
->Status
= STATUS_SUCCESS
;
1895 KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1899 RtlInitUnicodeString(&ImagePath
, NULL
);
1902 * Get the service name from the registry key name.
1904 ASSERT(LoadParams
->ServiceName
->Length
>= sizeof(WCHAR
));
1906 ServiceName
= *LoadParams
->ServiceName
;
1907 cur
= LoadParams
->ServiceName
->Buffer
+
1908 (LoadParams
->ServiceName
->Length
/ sizeof(WCHAR
)) - 1;
1909 while (LoadParams
->ServiceName
->Buffer
!= cur
)
1913 ServiceName
.Buffer
= cur
+ 1;
1914 ServiceName
.Length
= LoadParams
->ServiceName
->Length
-
1915 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1916 (ULONG_PTR
)LoadParams
->ServiceName
->Buffer
);
1926 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1928 RtlInitUnicodeString(&ImagePath
, NULL
);
1930 QueryTable
[0].Name
= L
"Type";
1931 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1932 QueryTable
[0].EntryContext
= &Type
;
1934 QueryTable
[1].Name
= L
"ImagePath";
1935 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1936 QueryTable
[1].EntryContext
= &ImagePath
;
1938 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1939 LoadParams
->ServiceName
->Buffer
,
1940 QueryTable
, NULL
, NULL
);
1941 if (!NT_SUCCESS(Status
))
1943 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1944 if (ImagePath
.Buffer
) ExFreePool(ImagePath
.Buffer
);
1945 LoadParams
->Status
= Status
;
1946 KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1951 * Normalize the image path for all later processing.
1954 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1955 if (!NT_SUCCESS(Status
))
1957 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1958 LoadParams
->Status
= Status
;
1959 KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1963 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1964 DPRINT("Type: %lx\n", Type
);
1967 * Get existing DriverObject pointer (in case the driver
1968 * has already been loaded and initialized).
1970 Status
= IopGetDriverObject(&DriverObject
,
1972 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1973 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */));
1975 if (!NT_SUCCESS(Status
))
1978 * Load the driver module
1981 DPRINT("Loading module from %wZ\n", &ImagePath
);
1982 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, &BaseAddress
);
1983 if (!NT_SUCCESS(Status
))
1985 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1986 LoadParams
->Status
= Status
;
1987 KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1992 * Initialize the driver module if it's loaded for the first time
1994 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1995 if (!NT_SUCCESS(Status
))
1997 DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1998 MmUnloadSystemImage(ModuleObject
);
1999 LoadParams
->Status
= Status
;
2000 KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
2004 IopDisplayLoadingMessage(&DeviceNode
->ServiceName
);
2006 Status
= IopInitializeDriverModule(DeviceNode
,
2008 &DeviceNode
->ServiceName
,
2009 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
2010 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
2012 if (!NT_SUCCESS(Status
))
2014 DPRINT1("IopInitializeDriverModule() failed (Status %lx)\n", Status
);
2015 MmUnloadSystemImage(ModuleObject
);
2016 IopFreeDeviceNode(DeviceNode
);
2017 LoadParams
->Status
= Status
;
2018 KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
2022 /* Initialize and start device */
2023 IopInitializeDevice(DeviceNode
, DriverObject
);
2024 Status
= IopStartDevice(DeviceNode
);
2028 DPRINT("DriverObject already exist in ObjectManager\n");
2029 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2031 /* IopGetDriverObject references the DriverObject, so dereference it */
2032 ObDereferenceObject(DriverObject
);
2035 /* Pass status to the caller and signal the event */
2036 LoadParams
->Status
= Status
;
2037 KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
2043 * Loads a device driver.
2047 * Name of the service to load (registry key).
2056 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
2058 UNICODE_STRING CapturedDriverServiceName
= { 0, 0, NULL
};
2059 KPROCESSOR_MODE PreviousMode
;
2060 LOAD_UNLOAD_PARAMS LoadParams
;
2065 PreviousMode
= KeGetPreviousMode();
2068 * Check security privileges
2071 /* FIXME: Uncomment when privileges will be correctly implemented. */
2073 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
2075 DPRINT("Privilege not held\n");
2076 return STATUS_PRIVILEGE_NOT_HELD
;
2080 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
2083 if (!NT_SUCCESS(Status
))
2088 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
2090 LoadParams
.ServiceName
= &CapturedDriverServiceName
;
2091 LoadParams
.DriverObject
= NULL
;
2092 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
2094 /* Call the load/unload routine, depending on current process */
2095 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
2097 /* Just call right away */
2098 IopLoadUnloadDriver(&LoadParams
);
2102 /* Load/Unload must be called from system process */
2103 ExInitializeWorkItem(&LoadParams
.WorkItem
,
2104 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
2105 (PVOID
)&LoadParams
);
2108 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
2110 /* And wait when it completes */
2111 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
2115 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
2118 return LoadParams
.Status
;
2124 * Unloads a legacy device driver.
2128 * Name of the service to unload (registry key).
2138 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
2140 return IopUnloadDriver(DriverServiceName
, FALSE
);