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 ERESOURCE IopDriverLoadResource
;
21 LIST_ENTRY DriverReinitListHead
;
22 KSPIN_LOCK DriverReinitListLock
;
23 PLIST_ENTRY DriverReinitTailEntry
;
25 PLIST_ENTRY DriverBootReinitTailEntry
;
26 LIST_ENTRY DriverBootReinitListHead
;
27 KSPIN_LOCK DriverBootReinitListLock
;
29 UNICODE_STRING IopHardwareDatabaseKey
=
30 RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
32 POBJECT_TYPE IoDriverObjectType
= NULL
;
34 #define TAG_RTLREGISTRY 'vrqR'
36 extern BOOLEAN ExpInTextModeSetup
;
37 extern BOOLEAN PnpSystemInit
;
40 PLIST_ENTRY IopGroupTable
;
42 /* PRIVATE FUNCTIONS **********************************************************/
46 IopInvalidDeviceRequest(
47 PDEVICE_OBJECT DeviceObject
,
50 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
51 Irp
->IoStatus
.Information
= 0;
52 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
53 return STATUS_INVALID_DEVICE_REQUEST
;
58 IopDeleteDriver(IN PVOID ObjectBody
)
60 PDRIVER_OBJECT DriverObject
= ObjectBody
;
61 PIO_CLIENT_EXTENSION DriverExtension
, NextDriverExtension
;
64 DPRINT1("Deleting driver object '%wZ'\n", &DriverObject
->DriverName
);
66 /* There must be no device objects remaining at this point */
67 ASSERT(!DriverObject
->DeviceObject
);
69 /* Get the extension and loop them */
70 DriverExtension
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
71 while (DriverExtension
)
73 /* Get the next one */
74 NextDriverExtension
= DriverExtension
->NextExtension
;
75 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
78 DriverExtension
= NextDriverExtension
;
81 /* Check if the driver image is still loaded */
82 if (DriverObject
->DriverSection
)
85 MmUnloadSystemImage(DriverObject
->DriverSection
);
88 /* Check if it has a name */
89 if (DriverObject
->DriverName
.Buffer
)
92 ExFreePool(DriverObject
->DriverName
.Buffer
);
95 /* Check if it has a service key name */
96 if (DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
)
99 ExFreePool(DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
);
106 PDRIVER_OBJECT
*DriverObject
,
107 PUNICODE_STRING ServiceName
,
110 PDRIVER_OBJECT Object
;
111 WCHAR NameBuffer
[MAX_PATH
];
112 UNICODE_STRING DriverName
;
115 DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
116 DriverObject
, ServiceName
, FileSystem
);
118 ASSERT(ExIsResourceAcquiredExclusiveLite(&IopDriverLoadResource
));
119 *DriverObject
= NULL
;
121 /* Create ModuleName string */
122 if (ServiceName
== NULL
|| ServiceName
->Buffer
== NULL
)
123 /* We don't know which DriverObject we have to open */
124 return STATUS_INVALID_PARAMETER_2
;
126 DriverName
.Buffer
= NameBuffer
;
127 DriverName
.Length
= 0;
128 DriverName
.MaximumLength
= sizeof(NameBuffer
);
130 if (FileSystem
!= FALSE
)
131 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
133 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
134 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
136 DPRINT("Driver name: '%wZ'\n", &DriverName
);
138 /* Open driver object */
139 Status
= ObReferenceObjectByName(&DriverName
,
140 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, /* Attributes */
141 NULL
, /* PassedAccessState */
142 0, /* DesiredAccess */
145 NULL
, /* ParseContext */
147 if (!NT_SUCCESS(Status
))
149 DPRINT("Failed to reference driver object, status=0x%08x\n", Status
);
153 *DriverObject
= Object
;
155 DPRINT("Driver Object: %p\n", Object
);
157 return STATUS_SUCCESS
;
162 * TRUE if String2 contains String1 as a suffix.
166 IopSuffixUnicodeString(
167 IN PCUNICODE_STRING String1
,
168 IN PCUNICODE_STRING String2
)
174 if (String2
->Length
< String1
->Length
)
177 Length
= String1
->Length
/ 2;
178 pc1
= String1
->Buffer
;
179 pc2
= &String2
->Buffer
[String2
->Length
/ sizeof(WCHAR
) - Length
];
185 if( *pc1
++ != *pc2
++ )
194 * IopDisplayLoadingMessage
196 * 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.
239 IopNormalizeImagePath(
240 _Inout_
_When_(return>=0, _At_(ImagePath
->Buffer
, _Post_notnull_
__drv_allocatesMem(Mem
)))
241 PUNICODE_STRING ImagePath
,
242 _In_ PUNICODE_STRING ServiceName
)
244 UNICODE_STRING SystemRootString
= RTL_CONSTANT_STRING(L
"\\SystemRoot\\");
245 UNICODE_STRING DriversPathString
= RTL_CONSTANT_STRING(L
"\\SystemRoot\\System32\\drivers\\");
246 UNICODE_STRING DotSysString
= RTL_CONSTANT_STRING(L
".sys");
247 UNICODE_STRING InputImagePath
;
249 DPRINT("Normalizing image path '%wZ' for service '%wZ'\n", ImagePath
, ServiceName
);
251 InputImagePath
= *ImagePath
;
252 if (InputImagePath
.Length
== 0)
254 ImagePath
->Length
= 0;
255 ImagePath
->MaximumLength
= DriversPathString
.Length
+
256 ServiceName
->Length
+
257 DotSysString
.Length
+
258 sizeof(UNICODE_NULL
);
259 ImagePath
->Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
260 ImagePath
->MaximumLength
,
262 if (ImagePath
->Buffer
== NULL
)
263 return STATUS_NO_MEMORY
;
265 RtlCopyUnicodeString(ImagePath
, &DriversPathString
);
266 RtlAppendUnicodeStringToString(ImagePath
, ServiceName
);
267 RtlAppendUnicodeStringToString(ImagePath
, &DotSysString
);
269 else if (InputImagePath
.Buffer
[0] != L
'\\')
271 ImagePath
->Length
= 0;
272 ImagePath
->MaximumLength
= SystemRootString
.Length
+
273 InputImagePath
.Length
+
274 sizeof(UNICODE_NULL
);
275 ImagePath
->Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
276 ImagePath
->MaximumLength
,
278 if (ImagePath
->Buffer
== NULL
)
279 return STATUS_NO_MEMORY
;
281 RtlCopyUnicodeString(ImagePath
, &SystemRootString
);
282 RtlAppendUnicodeStringToString(ImagePath
, &InputImagePath
);
284 /* Free caller's string */
285 ExFreePoolWithTag(InputImagePath
.Buffer
, TAG_RTLREGISTRY
);
288 DPRINT("Normalized image path is '%wZ' for service '%wZ'\n", ImagePath
, ServiceName
);
290 return STATUS_SUCCESS
;
294 * IopLoadServiceModule
296 * Load a module specified by registry settings for service.
300 * Name of the service to load.
307 IopLoadServiceModule(
308 IN PUNICODE_STRING ServiceName
,
309 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
311 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
313 UNICODE_STRING ServiceImagePath
, CCSName
;
315 HANDLE CCSKey
, ServiceKey
;
318 ASSERT(ExIsResourceAcquiredExclusiveLite(&IopDriverLoadResource
));
319 ASSERT(ServiceName
->Length
);
320 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
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 RtlInitEmptyUnicodeString(&ServiceImagePath
, NULL
, 0);
334 /* Open CurrentControlSet */
335 RtlInitUnicodeString(&CCSName
,
336 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
337 Status
= IopOpenRegistryKeyEx(&CCSKey
, NULL
, &CCSName
, KEY_READ
);
338 if (!NT_SUCCESS(Status
))
340 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with Status %08X\n",
345 /* Open service key */
346 Status
= IopOpenRegistryKeyEx(&ServiceKey
, CCSKey
, ServiceName
, KEY_READ
);
347 if (!NT_SUCCESS(Status
))
349 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with Status %08X\n",
350 ServiceName
, Status
);
356 * Get information about the service.
358 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
360 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
362 QueryTable
[0].Name
= L
"Start";
363 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
364 QueryTable
[0].EntryContext
= &ServiceStart
;
366 QueryTable
[1].Name
= L
"ImagePath";
367 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
368 QueryTable
[1].EntryContext
= &ServiceImagePath
;
370 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
379 if (!NT_SUCCESS(Status
))
381 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
387 * 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
400 if (ServiceStart
>= 4)
402 /* We can't load this */
403 Status
= STATUS_DRIVER_UNABLE_TO_LOAD
;
407 DPRINT("Loading module from %wZ\n", &ServiceImagePath
);
408 Status
= MmLoadSystemImage(&ServiceImagePath
, NULL
, NULL
, 0, (PVOID
)ModuleObject
, &BaseAddress
);
409 if (NT_SUCCESS(Status
))
411 IopDisplayLoadingMessage(ServiceName
);
415 ExFreePool(ServiceImagePath
.Buffer
);
418 * Now check if the module was loaded successfully.
420 if (!NT_SUCCESS(Status
))
422 DPRINT("Module loading failed (Status %x)\n", Status
);
425 DPRINT("Module loading (Status %x)\n", Status
);
432 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry
);
435 * IopInitializeDriverModule
437 * Initialize a loaded driver.
441 * Pointer to device node.
444 * Module object representing the driver. It can be retrieve by
445 * IopLoadServiceModule.
448 * Name of the service (as in registry).
451 * Set to TRUE for file system drivers.
454 * On successful return this contains the driver object representing
459 IopInitializeDriverModule(
460 IN PDEVICE_NODE DeviceNode
,
461 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
462 IN PUNICODE_STRING ServiceName
,
463 IN BOOLEAN FileSystemDriver
,
464 OUT PDRIVER_OBJECT
*DriverObject
)
466 static const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
467 UNICODE_STRING DriverName
;
468 UNICODE_STRING RegistryKey
;
469 PDRIVER_INITIALIZE DriverEntry
;
470 PDRIVER_OBJECT Driver
;
473 DriverEntry
= ModuleObject
->EntryPoint
;
475 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
477 RegistryKey
.Length
= 0;
478 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
479 RegistryKey
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
480 RegistryKey
.MaximumLength
,
482 if (RegistryKey
.Buffer
== NULL
)
484 return STATUS_INSUFFICIENT_RESOURCES
;
486 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
487 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
491 RtlInitEmptyUnicodeString(&RegistryKey
, NULL
, 0);
494 /* Create ModuleName string */
495 if (ServiceName
&& ServiceName
->Length
> 0)
497 DriverName
.Length
= 0;
498 DriverName
.MaximumLength
= sizeof(FILESYSTEM_ROOT_NAME
) + ServiceName
->Length
;
499 DriverName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
500 DriverName
.MaximumLength
,
502 if (DriverName
.Buffer
== NULL
)
504 RtlFreeUnicodeString(&RegistryKey
);
505 return STATUS_INSUFFICIENT_RESOURCES
;
508 if (FileSystemDriver
!= FALSE
)
509 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
511 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
512 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
514 DPRINT("Driver name: '%wZ'\n", &DriverName
);
518 RtlInitEmptyUnicodeString(&DriverName
, NULL
, 0);
521 Status
= IopCreateDriver(DriverName
.Length
> 0 ? &DriverName
: NULL
,
527 RtlFreeUnicodeString(&RegistryKey
);
528 RtlFreeUnicodeString(&DriverName
);
530 if (!NT_SUCCESS(Status
))
532 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status
);
536 *DriverObject
= Driver
;
538 MmFreeDriverInitialization((PLDR_DATA_TABLE_ENTRY
)Driver
->DriverSection
);
540 /* Set the driver as initialized */
541 IopReadyDeviceObjects(Driver
);
543 if (PnpSystemInit
) IopReinitializeDrivers();
545 return STATUS_SUCCESS
;
549 * IopAttachFilterDriversCallback
551 * Internal routine used by IopAttachFilterDrivers.
555 IopAttachFilterDriversCallback(
563 PDEVICE_NODE DeviceNode
= Context
;
564 UNICODE_STRING ServiceName
;
566 PLDR_DATA_TABLE_ENTRY ModuleObject
;
567 PDRIVER_OBJECT DriverObject
;
570 /* No filter value present */
571 if (ValueType
== REG_NONE
)
572 return STATUS_SUCCESS
;
574 for (Filters
= ValueData
;
575 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
577 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
579 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
581 ServiceName
.Buffer
= Filters
;
582 ServiceName
.MaximumLength
=
583 ServiceName
.Length
= (USHORT
)wcslen(Filters
) * sizeof(WCHAR
);
585 KeEnterCriticalRegion();
586 ExAcquireResourceExclusiveLite(&IopDriverLoadResource
, TRUE
);
587 Status
= IopGetDriverObject(&DriverObject
,
590 if (!NT_SUCCESS(Status
))
592 /* Load and initialize the filter driver */
593 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
594 if (!NT_SUCCESS(Status
))
596 ExReleaseResourceLite(&IopDriverLoadResource
);
597 KeLeaveCriticalRegion();
601 Status
= IopInitializeDriverModule(DeviceNode
,
606 if (!NT_SUCCESS(Status
))
608 ExReleaseResourceLite(&IopDriverLoadResource
);
609 KeLeaveCriticalRegion();
614 ExReleaseResourceLite(&IopDriverLoadResource
);
615 KeLeaveCriticalRegion();
617 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
619 /* Remove extra reference */
620 ObDereferenceObject(DriverObject
);
622 if (!NT_SUCCESS(Status
))
626 return STATUS_SUCCESS
;
630 * IopAttachFilterDrivers
632 * Load filter drivers for specified device node.
636 * Set to TRUE for loading lower level filters or FALSE for upper
641 IopAttachFilterDrivers(
642 PDEVICE_NODE DeviceNode
,
645 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = { { NULL
, 0, NULL
, NULL
, 0, NULL
, 0 }, };
646 UNICODE_STRING Class
;
647 WCHAR ClassBuffer
[40];
648 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
649 HANDLE EnumRootKey
, SubKey
;
652 /* Open enumeration root key */
653 Status
= IopOpenRegistryKeyEx(&EnumRootKey
,
657 if (!NT_SUCCESS(Status
))
659 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
664 Status
= IopOpenRegistryKeyEx(&SubKey
,
666 &DeviceNode
->InstancePath
,
668 if (!NT_SUCCESS(Status
))
670 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
671 ZwClose(EnumRootKey
);
676 * First load the device filters
678 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
680 QueryTable
[0].Name
= L
"LowerFilters";
682 QueryTable
[0].Name
= L
"UpperFilters";
683 QueryTable
[0].Flags
= 0;
684 QueryTable
[0].DefaultType
= REG_NONE
;
686 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
691 if (!NT_SUCCESS(Status
))
693 DPRINT1("Failed to load device %s filters: %08X\n",
694 Lower
? "lower" : "upper", Status
);
696 ZwClose(EnumRootKey
);
701 * Now get the class GUID
704 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
705 Class
.Buffer
= ClassBuffer
;
706 QueryTable
[0].QueryRoutine
= NULL
;
707 QueryTable
[0].Name
= L
"ClassGUID";
708 QueryTable
[0].EntryContext
= &Class
;
709 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
711 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
719 ZwClose(EnumRootKey
);
722 * Load the class filter driver
724 if (NT_SUCCESS(Status
))
726 UNICODE_STRING ControlClass
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
728 Status
= IopOpenRegistryKeyEx(&EnumRootKey
,
732 if (!NT_SUCCESS(Status
))
734 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
739 Status
= IopOpenRegistryKeyEx(&SubKey
,
743 if (!NT_SUCCESS(Status
))
745 /* It's okay if there's no class key */
746 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
747 ZwClose(EnumRootKey
);
748 return STATUS_SUCCESS
;
751 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
753 QueryTable
[0].Name
= L
"LowerFilters";
755 QueryTable
[0].Name
= L
"UpperFilters";
756 QueryTable
[0].EntryContext
= NULL
;
757 QueryTable
[0].Flags
= 0;
758 QueryTable
[0].DefaultType
= REG_NONE
;
760 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
768 ZwClose(EnumRootKey
);
770 if (!NT_SUCCESS(Status
))
772 DPRINT1("Failed to load class %s filters: %08X\n",
773 Lower
? "lower" : "upper", Status
);
775 ZwClose(EnumRootKey
);
780 return STATUS_SUCCESS
;
785 MiResolveImageReferences(IN PVOID ImageBase
,
786 IN PUNICODE_STRING ImageFileDirectory
,
787 IN PUNICODE_STRING NamePrefix OPTIONAL
,
788 OUT PCHAR
*MissingApi
,
789 OUT PWCHAR
*MissingDriver
,
790 OUT PLOAD_IMPORTS
*LoadImports
);
793 // Used for images already loaded (boot drivers)
798 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry
,
799 PUNICODE_STRING FileName
,
800 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
803 UNICODE_STRING BaseName
, BaseDirectory
;
804 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
805 PCHAR MissingApiName
, Buffer
;
806 PWCHAR MissingDriverName
;
807 PVOID DriverBase
= LdrEntry
->DllBase
;
809 /* Allocate a buffer we'll use for names */
810 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
814 return STATUS_INSUFFICIENT_RESOURCES
;
817 /* Check for a separator */
818 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
823 /* Loop the path until we get to the base name */
824 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
825 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
828 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
829 BaseLength
*= sizeof(WCHAR
);
831 /* Setup the string */
832 BaseName
.Length
= (USHORT
)BaseLength
;
837 /* Otherwise, we already have a base name */
838 BaseName
.Length
= FileName
->Length
;
839 BaseName
.Buffer
= FileName
->Buffer
;
842 /* Setup the maximum length */
843 BaseName
.MaximumLength
= BaseName
.Length
;
845 /* Now compute the base directory */
846 BaseDirectory
= *FileName
;
847 BaseDirectory
.Length
-= BaseName
.Length
;
848 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
850 /* Resolve imports */
851 MissingApiName
= Buffer
;
852 Status
= MiResolveImageReferences(DriverBase
,
859 /* Free the temporary buffer */
860 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
862 /* Check the result of the imports resolution */
863 if (!NT_SUCCESS(Status
)) return Status
;
866 *ModuleObject
= LdrEntry
;
867 return STATUS_SUCCESS
;
871 * IopInitializeBuiltinDriver
873 * Initialize a driver that is already loaded in memory.
878 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY BootLdrEntry
)
880 PDEVICE_NODE DeviceNode
;
881 PDRIVER_OBJECT DriverObject
;
883 PWCHAR FileNameWithoutPath
;
884 LPWSTR FileExtension
;
885 PUNICODE_STRING ModuleName
= &BootLdrEntry
->BaseDllName
;
886 PLDR_DATA_TABLE_ENTRY LdrEntry
;
887 PLIST_ENTRY NextEntry
;
888 UNICODE_STRING ServiceName
;
892 * Display 'Loading XXX...' message
894 IopDisplayLoadingMessage(ModuleName
);
895 InbvIndicateProgress();
898 * Generate filename without path (not needed by freeldr)
900 FileNameWithoutPath
= wcsrchr(ModuleName
->Buffer
, L
'\\');
901 if (FileNameWithoutPath
== NULL
)
903 FileNameWithoutPath
= ModuleName
->Buffer
;
907 FileNameWithoutPath
++;
911 * Strip the file extension from ServiceName
913 Success
= RtlCreateUnicodeString(&ServiceName
, FileNameWithoutPath
);
916 return STATUS_INSUFFICIENT_RESOURCES
;
919 FileExtension
= wcsrchr(ServiceName
.Buffer
, '.');
920 if (FileExtension
!= NULL
)
922 ServiceName
.Length
-= (USHORT
)wcslen(FileExtension
) * sizeof(WCHAR
);
923 FileExtension
[0] = 0;
927 * Determine the right device object
929 /* Use IopRootDeviceNode for now */
930 Status
= IopCreateDeviceNode(IopRootDeviceNode
,
934 RtlFreeUnicodeString(&ServiceName
);
935 if (!NT_SUCCESS(Status
))
937 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
941 /* Lookup the new Ldr entry in PsLoadedModuleList */
942 NextEntry
= PsLoadedModuleList
.Flink
;
943 while (NextEntry
!= &PsLoadedModuleList
)
945 LdrEntry
= CONTAINING_RECORD(NextEntry
,
946 LDR_DATA_TABLE_ENTRY
,
948 if (RtlEqualUnicodeString(ModuleName
, &LdrEntry
->BaseDllName
, TRUE
))
953 NextEntry
= NextEntry
->Flink
;
955 ASSERT(NextEntry
!= &PsLoadedModuleList
);
958 * Initialize the driver
960 Status
= IopInitializeDriverModule(DeviceNode
,
962 &DeviceNode
->ServiceName
,
966 if (!NT_SUCCESS(Status
))
971 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
972 if (NT_SUCCESS(Status
))
974 Status
= IopStartDevice(DeviceNode
);
977 /* Remove extra reference from IopInitializeDriverModule */
978 ObDereferenceObject(DriverObject
);
984 * IopInitializeBootDrivers
986 * Initialize boot drivers and free memory for boot files.
997 IopInitializeBootDrivers(VOID
)
999 PLIST_ENTRY ListHead
, NextEntry
, NextEntry2
;
1000 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1001 PDEVICE_NODE DeviceNode
;
1002 PDRIVER_OBJECT DriverObject
;
1003 LDR_DATA_TABLE_ENTRY ModuleObject
;
1005 UNICODE_STRING DriverName
;
1007 PDRIVER_INFORMATION DriverInfo
, DriverInfoTag
;
1009 PBOOT_DRIVER_LIST_ENTRY BootEntry
;
1010 DPRINT("IopInitializeBootDrivers()\n");
1012 /* Use IopRootDeviceNode for now */
1013 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, NULL
, &DeviceNode
);
1014 if (!NT_SUCCESS(Status
)) return;
1016 /* Setup the module object for the RAW FS Driver */
1017 ModuleObject
.DllBase
= NULL
;
1018 ModuleObject
.SizeOfImage
= 0;
1019 ModuleObject
.EntryPoint
= RawFsDriverEntry
;
1020 RtlInitUnicodeString(&DriverName
, L
"RAW");
1023 Status
= IopInitializeDriverModule(DeviceNode
,
1028 if (!NT_SUCCESS(Status
))
1034 /* Now initialize the associated device */
1035 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
1036 if (!NT_SUCCESS(Status
))
1039 ObDereferenceObject(DriverObject
);
1044 Status
= IopStartDevice(DeviceNode
);
1045 if (!NT_SUCCESS(Status
))
1048 ObDereferenceObject(DriverObject
);
1052 /* Get highest group order index */
1053 IopGroupIndex
= PpInitGetGroupOrderIndex(NULL
);
1054 if (IopGroupIndex
== 0xFFFF) ASSERT(FALSE
);
1056 /* Allocate the group table */
1057 IopGroupTable
= ExAllocatePoolWithTag(PagedPool
,
1058 IopGroupIndex
* sizeof(LIST_ENTRY
),
1060 if (IopGroupTable
== NULL
) ASSERT(FALSE
);
1062 /* Initialize the group table lists */
1063 for (i
= 0; i
< IopGroupIndex
; i
++) InitializeListHead(&IopGroupTable
[i
]);
1065 /* Loop the boot modules */
1066 ListHead
= &KeLoaderBlock
->LoadOrderListHead
;
1067 NextEntry
= ListHead
->Flink
;
1068 while (ListHead
!= NextEntry
)
1071 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1072 LDR_DATA_TABLE_ENTRY
,
1075 /* Check if the DLL needs to be initialized */
1076 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
1078 /* Call its entrypoint */
1079 MmCallDllInitialize(LdrEntry
, NULL
);
1082 /* Go to the next driver */
1083 NextEntry
= NextEntry
->Flink
;
1086 /* Loop the boot drivers */
1087 ListHead
= &KeLoaderBlock
->BootDriverListHead
;
1088 NextEntry
= ListHead
->Flink
;
1089 while (ListHead
!= NextEntry
)
1092 BootEntry
= CONTAINING_RECORD(NextEntry
,
1093 BOOT_DRIVER_LIST_ENTRY
,
1096 /* Get the driver loader entry */
1097 LdrEntry
= BootEntry
->LdrEntry
;
1099 /* Allocate our internal accounting structure */
1100 DriverInfo
= ExAllocatePoolWithTag(PagedPool
,
1101 sizeof(DRIVER_INFORMATION
),
1105 /* Zero it and initialize it */
1106 RtlZeroMemory(DriverInfo
, sizeof(DRIVER_INFORMATION
));
1107 InitializeListHead(&DriverInfo
->Link
);
1108 DriverInfo
->DataTableEntry
= BootEntry
;
1110 /* Open the registry key */
1111 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
1113 &BootEntry
->RegistryPath
,
1115 if ((NT_SUCCESS(Status
)) || /* ReactOS HACK for SETUPLDR */
1116 ((KeLoaderBlock
->SetupLdrBlock
) && ((KeyHandle
= (PVOID
)1)))) // yes, it's an assignment!
1118 /* Save the handle */
1119 DriverInfo
->ServiceHandle
= KeyHandle
;
1121 /* Get the group oder index */
1122 Index
= PpInitGetGroupOrderIndex(KeyHandle
);
1124 /* Get the tag position */
1125 DriverInfo
->TagPosition
= PipGetDriverTagPriority(KeyHandle
);
1127 /* Insert it into the list, at the right place */
1128 ASSERT(Index
< IopGroupIndex
);
1129 NextEntry2
= IopGroupTable
[Index
].Flink
;
1130 while (NextEntry2
!= &IopGroupTable
[Index
])
1132 /* Get the driver info */
1133 DriverInfoTag
= CONTAINING_RECORD(NextEntry2
,
1137 /* Check if we found the right tag position */
1138 if (DriverInfoTag
->TagPosition
> DriverInfo
->TagPosition
)
1145 NextEntry2
= NextEntry2
->Flink
;
1148 /* Insert us right before the next entry */
1149 NextEntry2
= NextEntry2
->Blink
;
1150 InsertHeadList(NextEntry2
, &DriverInfo
->Link
);
1154 /* Go to the next driver */
1155 NextEntry
= NextEntry
->Flink
;
1158 /* Loop each group index */
1159 for (i
= 0; i
< IopGroupIndex
; i
++)
1161 /* Loop each group table */
1162 NextEntry
= IopGroupTable
[i
].Flink
;
1163 while (NextEntry
!= &IopGroupTable
[i
])
1166 DriverInfo
= CONTAINING_RECORD(NextEntry
,
1170 /* Get the driver loader entry */
1171 LdrEntry
= DriverInfo
->DataTableEntry
->LdrEntry
;
1174 IopInitializeBuiltinDriver(LdrEntry
);
1177 NextEntry
= NextEntry
->Flink
;
1181 /* In old ROS, the loader list became empty after this point. Simulate. */
1182 InitializeListHead(&KeLoaderBlock
->LoadOrderListHead
);
1188 IopInitializeSystemDrivers(VOID
)
1190 PUNICODE_STRING
*DriverList
, *SavedList
;
1192 /* No system drivers on the boot cd */
1193 if (KeLoaderBlock
->SetupLdrBlock
) return;
1195 /* Get the driver list */
1196 SavedList
= DriverList
= CmGetSystemDriverList();
1202 /* Load the driver */
1203 ZwLoadDriver(*DriverList
);
1205 /* Free the entry */
1206 RtlFreeUnicodeString(*DriverList
);
1207 ExFreePool(*DriverList
);
1210 InbvIndicateProgress();
1215 ExFreePool(SavedList
);
1221 * Unloads a device driver.
1225 * Name of the service to unload (registry key).
1228 * Whether to unload Plug & Plug or only legacy drivers. If this
1229 * parameter is set to FALSE, the routine will unload only legacy
1236 * Guard the whole function by SEH.
1240 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1242 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1243 UNICODE_STRING ImagePath
;
1244 UNICODE_STRING ServiceName
;
1245 UNICODE_STRING ObjectName
;
1246 PDRIVER_OBJECT DriverObject
;
1247 PDEVICE_OBJECT DeviceObject
;
1248 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1251 BOOLEAN SafeToUnload
= TRUE
;
1253 DPRINT("IopUnloadDriver('%wZ', %u)\n", DriverServiceName
, UnloadPnpDrivers
);
1258 * Get the service name from the registry key name
1261 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1263 Start
= DriverServiceName
->Buffer
;
1267 RtlInitUnicodeString(&ServiceName
, Start
);
1270 * Construct the driver object name
1273 ObjectName
.Length
= ((USHORT
)wcslen(Start
) + 8) * sizeof(WCHAR
);
1274 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1275 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1276 if (!ObjectName
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1277 wcscpy(ObjectName
.Buffer
, DRIVER_ROOT_NAME
);
1278 memcpy(ObjectName
.Buffer
+ 8, Start
, ObjectName
.Length
- 8 * sizeof(WCHAR
));
1279 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1282 * Find the driver object
1284 Status
= ObReferenceObjectByName(&ObjectName
,
1291 (PVOID
*)&DriverObject
);
1293 if (!NT_SUCCESS(Status
))
1295 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName
);
1296 ExFreePool(ObjectName
.Buffer
);
1301 * Free the buffer for driver object name
1303 ExFreePool(ObjectName
.Buffer
);
1305 /* Check that driver is not already unloading */
1306 if (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
)
1308 DPRINT1("Driver deletion pending\n");
1309 ObDereferenceObject(DriverObject
);
1310 return STATUS_DELETE_PENDING
;
1314 * Get path of service...
1316 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1318 RtlInitUnicodeString(&ImagePath
, NULL
);
1320 QueryTable
[0].Name
= L
"ImagePath";
1321 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1322 QueryTable
[0].EntryContext
= &ImagePath
;
1324 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1325 DriverServiceName
->Buffer
,
1330 if (!NT_SUCCESS(Status
))
1332 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1333 ObDereferenceObject(DriverObject
);
1338 * Normalize the image path for all later processing.
1340 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1342 if (!NT_SUCCESS(Status
))
1344 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1345 ObDereferenceObject(DriverObject
);
1350 * Free the service path
1352 ExFreePool(ImagePath
.Buffer
);
1355 * Unload the module and release the references to the device object
1358 /* Call the load/unload routine, depending on current process */
1359 if (DriverObject
->DriverUnload
&& DriverObject
->DriverSection
&&
1360 (UnloadPnpDrivers
|| (DriverObject
->Flags
& DRVO_LEGACY_DRIVER
)))
1362 /* Loop through each device object of the driver
1363 and set DOE_UNLOAD_PENDING flag */
1364 DeviceObject
= DriverObject
->DeviceObject
;
1365 while (DeviceObject
)
1367 /* Set the unload pending flag for the device */
1368 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1369 DeviceExtension
->ExtensionFlags
|= DOE_UNLOAD_PENDING
;
1371 /* Make sure there are no attached devices or no reference counts */
1372 if ((DeviceObject
->ReferenceCount
) || (DeviceObject
->AttachedDevice
))
1374 /* Not safe to unload */
1375 DPRINT1("Drivers device object is referenced or has attached devices\n");
1377 SafeToUnload
= FALSE
;
1380 DeviceObject
= DeviceObject
->NextDevice
;
1383 /* If not safe to unload, then return success */
1386 ObDereferenceObject(DriverObject
);
1387 return STATUS_SUCCESS
;
1390 DPRINT1("Unloading driver '%wZ' (manual)\n", &DriverObject
->DriverName
);
1392 /* Set the unload invoked flag and call the unload routine */
1393 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
1394 Status
= IopLoadUnloadDriver(NULL
, &DriverObject
);
1395 ASSERT(Status
== STATUS_SUCCESS
);
1397 /* Mark the driver object temporary, so it could be deleted later */
1398 ObMakeTemporaryObject(DriverObject
);
1400 /* Dereference it 2 times */
1401 ObDereferenceObject(DriverObject
);
1402 ObDereferenceObject(DriverObject
);
1408 DPRINT1("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject
->DriverName
);
1410 /* Dereference one time (refd inside this function) */
1411 ObDereferenceObject(DriverObject
);
1413 /* Return unloading failure */
1414 return STATUS_INVALID_DEVICE_REQUEST
;
1420 IopReinitializeDrivers(VOID
)
1422 PDRIVER_REINIT_ITEM ReinitItem
;
1425 /* Get the first entry and start looping */
1426 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1427 &DriverReinitListLock
);
1431 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1433 /* Increment reinitialization counter */
1434 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1436 /* Remove the device object flag */
1437 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1439 /* Call the routine */
1440 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1441 ReinitItem
->Context
,
1442 ReinitItem
->DriverObject
->
1443 DriverExtension
->Count
);
1445 /* Free the entry */
1448 /* Move to the next one */
1449 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1450 &DriverReinitListLock
);
1456 IopReinitializeBootDrivers(VOID
)
1458 PDRIVER_REINIT_ITEM ReinitItem
;
1461 /* Get the first entry and start looping */
1462 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1463 &DriverBootReinitListLock
);
1467 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1469 /* Increment reinitialization counter */
1470 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1472 /* Remove the device object flag */
1473 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1475 /* Call the routine */
1476 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1477 ReinitItem
->Context
,
1478 ReinitItem
->DriverObject
->
1479 DriverExtension
->Count
);
1481 /* Free the entry */
1484 /* Move to the next one */
1485 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1486 &DriverBootReinitListLock
);
1492 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1493 IN PDRIVER_INITIALIZE InitializationFunction
,
1494 IN PUNICODE_STRING RegistryPath
,
1495 IN PCUNICODE_STRING ServiceName
,
1496 PLDR_DATA_TABLE_ENTRY ModuleObject
,
1497 OUT PDRIVER_OBJECT
*pDriverObject
)
1499 WCHAR NameBuffer
[100];
1501 UNICODE_STRING LocalDriverName
;
1503 OBJECT_ATTRIBUTES ObjectAttributes
;
1505 PDRIVER_OBJECT DriverObject
;
1506 UNICODE_STRING ServiceKeyName
;
1508 ULONG i
, RetryCount
= 0;
1511 /* First, create a unique name for the driver if we don't have one */
1514 /* Create a random name and set up the string */
1515 NameLength
= (USHORT
)swprintf(NameBuffer
,
1516 DRIVER_ROOT_NAME L
"%08u",
1517 KeTickCount
.LowPart
);
1518 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1519 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1520 LocalDriverName
.Buffer
= NameBuffer
;
1524 /* So we can avoid another code path, use a local var */
1525 LocalDriverName
= *DriverName
;
1528 /* Initialize the Attributes */
1529 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1530 InitializeObjectAttributes(&ObjectAttributes
,
1532 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1536 /* Create the Object */
1537 Status
= ObCreateObject(KernelMode
,
1545 (PVOID
*)&DriverObject
);
1546 if (!NT_SUCCESS(Status
)) return Status
;
1548 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1550 /* Set up the Object */
1551 RtlZeroMemory(DriverObject
, ObjectSize
);
1552 DriverObject
->Type
= IO_TYPE_DRIVER
;
1553 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1554 DriverObject
->Flags
= DRVO_LEGACY_DRIVER
;
1555 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1556 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1557 DriverObject
->DriverInit
= InitializationFunction
;
1558 DriverObject
->DriverSection
= ModuleObject
;
1559 /* Loop all Major Functions */
1560 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1562 /* Invalidate each function */
1563 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1566 /* Set up the service key name buffer */
1567 ServiceKeyName
.MaximumLength
= ServiceName
->Length
+ sizeof(UNICODE_NULL
);
1568 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1569 ServiceKeyName
.MaximumLength
,
1571 if (!ServiceKeyName
.Buffer
)
1574 ObMakeTemporaryObject(DriverObject
);
1575 ObDereferenceObject(DriverObject
);
1576 return STATUS_INSUFFICIENT_RESOURCES
;
1579 /* Copy the name and set it in the driver extension */
1580 RtlCopyUnicodeString(&ServiceKeyName
,
1582 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1584 /* Make a copy of the driver name to store in the driver object */
1585 DriverObject
->DriverName
.MaximumLength
= LocalDriverName
.Length
;
1586 DriverObject
->DriverName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1587 DriverObject
->DriverName
.MaximumLength
,
1589 if (!DriverObject
->DriverName
.Buffer
)
1592 ObMakeTemporaryObject(DriverObject
);
1593 ObDereferenceObject(DriverObject
);
1594 return STATUS_INSUFFICIENT_RESOURCES
;
1597 RtlCopyUnicodeString(&DriverObject
->DriverName
,
1600 /* Add the Object and get its handle */
1601 Status
= ObInsertObject(DriverObject
,
1608 /* Eliminate small possibility when this function is called more than
1609 once in a row, and KeTickCount doesn't get enough time to change */
1610 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1616 if (!NT_SUCCESS(Status
)) return Status
;
1618 /* Now reference it */
1619 Status
= ObReferenceObjectByHandle(hDriver
,
1623 (PVOID
*)&DriverObject
,
1626 /* Close the extra handle */
1629 if (!NT_SUCCESS(Status
))
1632 ObMakeTemporaryObject(DriverObject
);
1633 ObDereferenceObject(DriverObject
);
1637 DriverObject
->HardwareDatabase
= &IopHardwareDatabaseKey
;
1638 DriverObject
->DriverStart
= ModuleObject
? ModuleObject
->DllBase
: 0;
1639 DriverObject
->DriverSize
= ModuleObject
? ModuleObject
->SizeOfImage
: 0;
1641 /* Finally, call its init function */
1642 DPRINT("RegistryKey: %wZ\n", RegistryPath
);
1643 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction
);
1644 Status
= (*InitializationFunction
)(DriverObject
, RegistryPath
);
1645 if (!NT_SUCCESS(Status
))
1647 /* If it didn't work, then kill the object */
1648 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName
, Status
);
1649 DriverObject
->DriverSection
= NULL
;
1650 ObMakeTemporaryObject(DriverObject
);
1651 ObDereferenceObject(DriverObject
);
1656 /* Returns to caller the object */
1657 *pDriverObject
= DriverObject
;
1660 /* We're going to say if we don't have any DOs from DriverEntry, then we're not legacy.
1661 * Other parts of the I/O manager depend on this behavior */
1662 if (!DriverObject
->DeviceObject
) DriverObject
->Flags
&= ~DRVO_LEGACY_DRIVER
;
1664 /* Loop all Major Functions */
1665 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1668 * Make sure the driver didn't set any dispatch entry point to NULL!
1669 * Doing so is illegal; drivers shouldn't touch entry points they
1673 /* Check if it did so anyway */
1674 if (!DriverObject
->MajorFunction
[i
])
1676 /* Print a warning in the debug log */
1677 DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%lu] to NULL!\n",
1678 &DriverObject
->DriverName
, i
);
1681 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1685 /* Return the Status */
1689 /* PUBLIC FUNCTIONS ***********************************************************/
1696 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1697 IN PDRIVER_INITIALIZE InitializationFunction
)
1699 PDRIVER_OBJECT DriverObject
;
1700 return IopCreateDriver(DriverName
, InitializationFunction
, NULL
, DriverName
, NULL
, &DriverObject
);
1708 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1710 /* Simply dereference the Object */
1711 ObDereferenceObject(DriverObject
);
1719 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1720 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1723 PDRIVER_REINIT_ITEM ReinitItem
;
1725 /* Allocate the entry */
1726 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1727 sizeof(DRIVER_REINIT_ITEM
),
1729 if (!ReinitItem
) return;
1732 ReinitItem
->DriverObject
= DriverObject
;
1733 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1734 ReinitItem
->Context
= Context
;
1736 /* Set the Driver Object flag and insert the entry into the list */
1737 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1738 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1739 &ReinitItem
->ItemEntry
,
1740 &DriverBootReinitListLock
);
1748 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1749 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1752 PDRIVER_REINIT_ITEM ReinitItem
;
1754 /* Allocate the entry */
1755 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1756 sizeof(DRIVER_REINIT_ITEM
),
1758 if (!ReinitItem
) return;
1761 ReinitItem
->DriverObject
= DriverObject
;
1762 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1763 ReinitItem
->Context
= Context
;
1765 /* Set the Driver Object flag and insert the entry into the list */
1766 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1767 ExInterlockedInsertTailList(&DriverReinitListHead
,
1768 &ReinitItem
->ItemEntry
,
1769 &DriverReinitListLock
);
1777 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1778 IN PVOID ClientIdentificationAddress
,
1779 IN ULONG DriverObjectExtensionSize
,
1780 OUT PVOID
*DriverObjectExtension
)
1783 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1784 BOOLEAN Inserted
= FALSE
;
1786 /* Assume failure */
1787 *DriverObjectExtension
= NULL
;
1789 /* Allocate the extension */
1790 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1791 sizeof(IO_CLIENT_EXTENSION
) +
1792 DriverObjectExtensionSize
,
1793 TAG_DRIVER_EXTENSION
);
1794 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1796 /* Clear the extension for teh caller */
1797 RtlZeroMemory(NewDriverExtension
,
1798 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1801 OldIrql
= KeRaiseIrqlToDpcLevel();
1803 /* Fill out the extension */
1804 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1806 /* Loop the current extensions */
1807 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1808 ClientDriverExtension
;
1809 while (DriverExtensions
)
1811 /* Check if the identifier matches */
1812 if (DriverExtensions
->ClientIdentificationAddress
==
1813 ClientIdentificationAddress
)
1815 /* We have a collision, break out */
1819 /* Go to the next one */
1820 DriverExtensions
= DriverExtensions
->NextExtension
;
1823 /* Check if we didn't collide */
1824 if (!DriverExtensions
)
1826 /* Link this one in */
1827 NewDriverExtension
->NextExtension
=
1828 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1829 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1834 /* Release the lock */
1835 KeLowerIrql(OldIrql
);
1837 /* Check if insertion failed */
1840 /* Free the entry and fail */
1841 ExFreePoolWithTag(NewDriverExtension
, TAG_DRIVER_EXTENSION
);
1842 return STATUS_OBJECT_NAME_COLLISION
;
1845 /* Otherwise, return the pointer */
1846 *DriverObjectExtension
= NewDriverExtension
+ 1;
1847 return STATUS_SUCCESS
;
1855 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1856 IN PVOID ClientIdentificationAddress
)
1859 PIO_CLIENT_EXTENSION DriverExtensions
;
1862 OldIrql
= KeRaiseIrqlToDpcLevel();
1864 /* Loop the list until we find the right one */
1865 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1866 while (DriverExtensions
)
1868 /* Check for a match */
1869 if (DriverExtensions
->ClientIdentificationAddress
==
1870 ClientIdentificationAddress
)
1877 DriverExtensions
= DriverExtensions
->NextExtension
;
1881 KeLowerIrql(OldIrql
);
1883 /* Return nothing or the extension */
1884 if (!DriverExtensions
) return NULL
;
1885 return DriverExtensions
+ 1;
1890 IopLoadUnloadDriverWorker(
1891 _Inout_ PVOID Parameter
)
1893 PLOAD_UNLOAD_PARAMS LoadParams
= Parameter
;
1895 ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess
);
1896 LoadParams
->Status
= IopLoadUnloadDriver(LoadParams
->RegistryPath
,
1897 &LoadParams
->DriverObject
);
1898 KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1903 IopLoadUnloadDriver(
1904 _In_opt_ PCUNICODE_STRING RegistryPath
,
1905 _Inout_ PDRIVER_OBJECT
*DriverObject
)
1907 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1908 UNICODE_STRING ImagePath
;
1909 UNICODE_STRING ServiceName
;
1912 PDEVICE_NODE DeviceNode
;
1913 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1917 /* Load/Unload must be called from system process */
1918 if (PsGetCurrentProcess() != PsInitialSystemProcess
)
1920 LOAD_UNLOAD_PARAMS LoadParams
;
1922 /* Prepare parameters block */
1923 LoadParams
.RegistryPath
= RegistryPath
;
1924 LoadParams
.DriverObject
= *DriverObject
;
1925 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1927 /* Initialize and queue a work item */
1928 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1929 IopLoadUnloadDriverWorker
,
1931 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1933 /* And wait till it completes */
1934 KeWaitForSingleObject(&LoadParams
.Event
,
1939 return LoadParams
.Status
;
1942 /* Check if it's an unload request */
1945 (*DriverObject
)->DriverUnload(*DriverObject
);
1946 return STATUS_SUCCESS
;
1949 RtlInitUnicodeString(&ImagePath
, NULL
);
1952 * Get the service name from the registry key name.
1954 ASSERT(RegistryPath
->Length
>= sizeof(WCHAR
));
1956 ServiceName
= *RegistryPath
;
1957 cur
= RegistryPath
->Buffer
+ RegistryPath
->Length
/ sizeof(WCHAR
) - 1;
1958 while (RegistryPath
->Buffer
!= cur
)
1962 ServiceName
.Buffer
= cur
+ 1;
1963 ServiceName
.Length
= RegistryPath
->Length
-
1964 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1965 (ULONG_PTR
)RegistryPath
->Buffer
);
1974 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1976 RtlInitUnicodeString(&ImagePath
, NULL
);
1978 QueryTable
[0].Name
= L
"Type";
1979 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1980 QueryTable
[0].EntryContext
= &Type
;
1982 QueryTable
[1].Name
= L
"ImagePath";
1983 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1984 QueryTable
[1].EntryContext
= &ImagePath
;
1986 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1987 RegistryPath
->Buffer
,
1988 QueryTable
, NULL
, NULL
);
1989 if (!NT_SUCCESS(Status
))
1991 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1992 if (ImagePath
.Buffer
) ExFreePool(ImagePath
.Buffer
);
1997 * Normalize the image path for all later processing.
1999 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
2000 if (!NT_SUCCESS(Status
))
2002 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
2006 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
2007 DPRINT("Type: %lx\n", Type
);
2009 KeEnterCriticalRegion();
2010 ExAcquireResourceExclusiveLite(&IopDriverLoadResource
, TRUE
);
2012 * Get existing DriverObject pointer (in case the driver
2013 * has already been loaded and initialized).
2015 Status
= IopGetDriverObject(DriverObject
,
2017 (Type
== SERVICE_FILE_SYSTEM_DRIVER
||
2018 Type
== SERVICE_RECOGNIZER_DRIVER
));
2020 if (!NT_SUCCESS(Status
))
2023 * Load the driver module
2025 DPRINT("Loading module from %wZ\n", &ImagePath
);
2026 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, &BaseAddress
);
2027 if (!NT_SUCCESS(Status
))
2029 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
2030 ExReleaseResourceLite(&IopDriverLoadResource
);
2031 KeLeaveCriticalRegion();
2036 * Initialize the driver module if it's loaded for the first time
2038 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
2039 if (!NT_SUCCESS(Status
))
2041 DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
2042 ExReleaseResourceLite(&IopDriverLoadResource
);
2043 KeLeaveCriticalRegion();
2044 MmUnloadSystemImage(ModuleObject
);
2048 IopDisplayLoadingMessage(&DeviceNode
->ServiceName
);
2050 Status
= IopInitializeDriverModule(DeviceNode
,
2052 &DeviceNode
->ServiceName
,
2053 (Type
== SERVICE_FILE_SYSTEM_DRIVER
||
2054 Type
== SERVICE_RECOGNIZER_DRIVER
),
2056 if (!NT_SUCCESS(Status
))
2058 DPRINT1("IopInitializeDriverModule() failed (Status %lx)\n", Status
);
2059 ExReleaseResourceLite(&IopDriverLoadResource
);
2060 KeLeaveCriticalRegion();
2061 MmUnloadSystemImage(ModuleObject
);
2065 ExReleaseResourceLite(&IopDriverLoadResource
);
2066 KeLeaveCriticalRegion();
2068 /* Initialize and start device */
2069 IopInitializeDevice(DeviceNode
, *DriverObject
);
2070 Status
= IopStartDevice(DeviceNode
);
2074 ExReleaseResourceLite(&IopDriverLoadResource
);
2075 KeLeaveCriticalRegion();
2077 DPRINT("DriverObject already exist in ObjectManager\n");
2078 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2080 /* IopGetDriverObject references the DriverObject, so dereference it */
2081 ObDereferenceObject(*DriverObject
);
2090 * Loads a device driver.
2094 * Name of the service to load (registry key).
2103 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
2105 UNICODE_STRING CapturedDriverServiceName
= { 0, 0, NULL
};
2106 KPROCESSOR_MODE PreviousMode
;
2107 PDRIVER_OBJECT DriverObject
;
2112 PreviousMode
= KeGetPreviousMode();
2115 * Check security privileges
2118 /* FIXME: Uncomment when privileges will be correctly implemented. */
2120 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
2122 DPRINT("Privilege not held\n");
2123 return STATUS_PRIVILEGE_NOT_HELD
;
2127 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
2130 if (!NT_SUCCESS(Status
))
2135 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
2137 /* Load driver and call its entry point */
2138 DriverObject
= NULL
;
2139 Status
= IopLoadUnloadDriver(&CapturedDriverServiceName
, &DriverObject
);
2141 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
2150 * Unloads a legacy device driver.
2154 * Name of the service to unload (registry key).
2164 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
2166 return IopUnloadDriver(DriverServiceName
, FALSE
);