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 *******************************************************************/
15 #include <internal/debug.h>
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 extern BOOLEAN ExpInTextModeSetup
;
34 /* PRIVATE FUNCTIONS **********************************************************/
37 IopInvalidDeviceRequest(
38 PDEVICE_OBJECT DeviceObject
,
41 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
42 Irp
->IoStatus
.Information
= 0;
43 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
44 return STATUS_INVALID_DEVICE_REQUEST
;
49 IopDeleteDriver(IN PVOID ObjectBody
)
51 PDRIVER_OBJECT DriverObject
= ObjectBody
;
52 PIO_CLIENT_EXTENSION DriverExtension
, NextDriverExtension
;
55 /* Get the extension and loop them */
56 DriverExtension
= IoGetDrvObjExtension(DriverObject
)->
57 ClientDriverExtension
;
58 while (DriverExtension
)
60 /* Get the next one */
61 NextDriverExtension
= DriverExtension
->NextExtension
;
62 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
65 DriverExtension
= NextDriverExtension
;
68 /* Check if the driver image is still loaded */
69 if (DriverObject
->DriverSection
)
72 //LdrpUnloadImage(DriverObject->DriverSection);
75 /* Check if it has a name */
76 if (DriverObject
->DriverName
.Buffer
)
79 ExFreePool(DriverObject
->DriverName
.Buffer
);
82 #if 0 /* See a bit of hack in IopCreateDriver */
83 /* Check if it has a service key name */
84 if (DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
)
87 ExFreePool(DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
);
94 PDRIVER_OBJECT
*DriverObject
,
95 PUNICODE_STRING ServiceName
,
98 PDRIVER_OBJECT Object
;
99 WCHAR NameBuffer
[MAX_PATH
];
100 UNICODE_STRING DriverName
;
103 DPRINT("IopOpenDriverObject(%p '%wZ' %x)\n",
104 DriverObject
, ServiceName
, FileSystem
);
106 *DriverObject
= NULL
;
108 /* Create ModuleName string */
109 if (ServiceName
== NULL
|| ServiceName
->Buffer
== NULL
)
110 /* We don't know which DriverObject we have to open */
111 return STATUS_INVALID_PARAMETER_2
;
113 DriverName
.Buffer
= NameBuffer
;
114 DriverName
.Length
= 0;
115 DriverName
.MaximumLength
= sizeof(NameBuffer
);
117 if (FileSystem
== TRUE
)
118 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
120 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
121 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
123 DPRINT("Driver name: '%wZ'\n", &DriverName
);
125 /* Open driver object */
126 Status
= ObReferenceObjectByName(
128 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
, /* Attributes */
129 NULL
, /* PassedAccessState */
130 0, /* DesiredAccess */
133 NULL
, /* ParseContext */
136 if (!NT_SUCCESS(Status
))
139 *DriverObject
= Object
;
141 return STATUS_SUCCESS
;
145 * IopDisplayLoadingMessage
147 * Display 'Loading XXX...' message.
153 IopDisplayLoadingMessage(PVOID ServiceName
,
156 CHAR TextBuffer
[256];
157 PCHAR Extra
= ".sys";
159 if (ExpInTextModeSetup
) return;
162 if (wcsstr(_wcsupr(ServiceName
), L
".SYS")) Extra
= "";
165 KeLoaderBlock
->ArcBootDeviceName
,
166 KeLoaderBlock
->NtBootPathName
,
173 if (strstr(_strupr(ServiceName
), ".SYS")) Extra
= "";
176 KeLoaderBlock
->ArcBootDeviceName
,
177 KeLoaderBlock
->NtBootPathName
,
182 HalDisplayString(TextBuffer
);
186 * IopNormalizeImagePath
188 * Normalize an image path to contain complete path.
192 * The input path and on exit the result path. ImagePath.Buffer
193 * must be allocated by ExAllocatePool on input. Caller is responsible
194 * for freeing the buffer when it's no longer needed.
197 * Name of the service that ImagePath belongs to.
203 * The input image path isn't freed on error.
207 IopNormalizeImagePath(
208 IN OUT PUNICODE_STRING ImagePath
,
209 IN PUNICODE_STRING ServiceName
)
211 UNICODE_STRING InputImagePath
;
216 sizeof(UNICODE_STRING
));
218 if (InputImagePath
.Length
== 0)
220 ImagePath
->Length
= (33 * sizeof(WCHAR
)) + ServiceName
->Length
;
221 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
222 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
223 if (ImagePath
->Buffer
== NULL
)
224 return STATUS_NO_MEMORY
;
226 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\system32\\drivers\\");
227 wcscat(ImagePath
->Buffer
, ServiceName
->Buffer
);
228 wcscat(ImagePath
->Buffer
, L
".sys");
230 if (InputImagePath
.Buffer
[0] != L
'\\')
232 ImagePath
->Length
= (12 * sizeof(WCHAR
)) + InputImagePath
.Length
;
233 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
234 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
235 if (ImagePath
->Buffer
== NULL
)
236 return STATUS_NO_MEMORY
;
238 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\");
239 wcscat(ImagePath
->Buffer
, InputImagePath
.Buffer
);
240 ExFreePool(InputImagePath
.Buffer
);
243 return STATUS_SUCCESS
;
247 * IopLoadServiceModule
249 * Load a module specified by registry settings for service.
253 * Name of the service to load.
260 IopLoadServiceModule(
261 IN PUNICODE_STRING ServiceName
,
262 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
264 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
266 UNICODE_STRING ServiceImagePath
;
269 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
271 /* FIXME: This check may be removed once the bug is fixed */
272 if (ServiceName
->Buffer
== NULL
)
273 return STATUS_UNSUCCESSFUL
;
276 * Get information about the service.
279 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
281 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
283 QueryTable
[0].Name
= L
"Start";
284 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
285 QueryTable
[0].EntryContext
= &ServiceStart
;
287 QueryTable
[1].Name
= L
"ImagePath";
288 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
289 QueryTable
[1].EntryContext
= &ServiceImagePath
;
291 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
292 ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
294 if (!NT_SUCCESS(Status
))
296 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
301 * Normalize the image path for all later processing.
304 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
306 if (!NT_SUCCESS(Status
))
308 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
313 * Case for disabled drivers
316 if (ServiceStart
>= 4)
318 /* FIXME: Check if it is the right status code */
319 Status
= STATUS_PLUGPLAY_NO_DEVICE
;
323 DPRINT("Loading module\n");
324 Status
= MmLoadSystemImage(&ServiceImagePath
, NULL
, NULL
, 0, (PVOID
)ModuleObject
, NULL
);
327 ExFreePool(ServiceImagePath
.Buffer
);
330 * Now check if the module was loaded successfully.
333 if (!NT_SUCCESS(Status
))
335 DPRINT("Module loading failed (Status %x)\n", Status
);
338 DPRINT("Module loading (Status %x)\n", Status
);
345 IopDriverInitializeEmpty(IN
struct _DRIVER_OBJECT
*DriverObject
, IN PUNICODE_STRING RegistryPath
)
347 return STATUS_SUCCESS
;
351 * IopInitializeDriverModule
353 * Initalize a loaded driver.
357 * Pointer to device node.
360 * Module object representing the driver. It can be retrieve by
361 * IopLoadServiceModule.
364 * Name of the service (as in registry).
367 * Set to TRUE for file system drivers.
370 * On successful return this contains the driver object representing
375 IopInitializeDriverModule(
376 IN PDEVICE_NODE DeviceNode
,
377 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
378 IN PUNICODE_STRING ServiceName
,
379 IN BOOLEAN FileSystemDriver
,
380 OUT PDRIVER_OBJECT
*DriverObject
)
382 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
383 WCHAR NameBuffer
[MAX_PATH
];
384 UNICODE_STRING DriverName
;
385 UNICODE_STRING RegistryKey
;
386 PDRIVER_INITIALIZE DriverEntry
;
387 PDRIVER_OBJECT Driver
;
388 PDEVICE_OBJECT DeviceObject
;
391 DriverEntry
= ModuleObject
->EntryPoint
;
393 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
395 RegistryKey
.Length
= 0;
396 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
397 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
398 if (RegistryKey
.Buffer
== NULL
)
400 return STATUS_INSUFFICIENT_RESOURCES
;
402 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
403 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
407 RtlInitUnicodeString(&RegistryKey
, NULL
);
410 /* Create ModuleName string */
411 if (ServiceName
&& ServiceName
->Length
> 0)
413 if (FileSystemDriver
== TRUE
)
414 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
416 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
417 wcscat(NameBuffer
, ServiceName
->Buffer
);
419 RtlInitUnicodeString(&DriverName
, NameBuffer
);
420 DPRINT("Driver name: '%wZ'\n", &DriverName
);
421 Status
= IopCreateDriver(&DriverName
, IopDriverInitializeEmpty
, &Driver
);
425 Status
= IopCreateDriver(NULL
, IopDriverInitializeEmpty
, &Driver
);
428 *DriverObject
= Driver
;
429 if (!NT_SUCCESS(Status
))
431 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status
);
435 Driver
->HardwareDatabase
= &IopHardwareDatabaseKey
;
436 Driver
->DriverStart
= ModuleObject
->DllBase
;
437 Driver
->DriverSize
= ModuleObject
->SizeOfImage
;
439 DPRINT("RegistryKey: %wZ\n", &RegistryKey
);
440 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry
);
442 Status
= DriverEntry(Driver
, &RegistryKey
);
444 RtlFreeUnicodeString(&RegistryKey
);
446 if (!NT_SUCCESS(Status
))
448 DPRINT1("DriverEntry() returned Status=0x%08X\n", Status
);
449 ObMakeTemporaryObject(Driver
);
450 ObDereferenceObject(Driver
);
454 /* Set the driver as initialized */
455 Driver
->Flags
|= DRVO_INITIALIZED
;
456 DeviceObject
= Driver
->DeviceObject
;
459 /* Set every device as initialized too */
460 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
461 DeviceObject
= DeviceObject
->NextDevice
;
464 IopReinitializeDrivers();
466 return STATUS_SUCCESS
;
470 * IopAttachFilterDriversCallback
472 * Internal routine used by IopAttachFilterDrivers.
476 IopAttachFilterDriversCallback(
484 PDEVICE_NODE DeviceNode
= Context
;
485 UNICODE_STRING ServiceName
;
487 PLDR_DATA_TABLE_ENTRY ModuleObject
;
488 PDRIVER_OBJECT DriverObject
;
491 for (Filters
= ValueData
;
492 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
494 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
496 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
497 ServiceName
.Buffer
= Filters
;
498 ServiceName
.MaximumLength
=
499 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
501 /* Load and initialize the filter driver */
502 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
503 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
505 if (!NT_SUCCESS(Status
))
508 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
509 FALSE
, &DriverObject
);
510 if (!NT_SUCCESS(Status
))
515 /* get existing DriverObject pointer */
516 Status
= IopGetDriverObject(
520 if (!NT_SUCCESS(Status
))
524 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
525 if (!NT_SUCCESS(Status
))
529 return STATUS_SUCCESS
;
533 * IopAttachFilterDrivers
535 * Load filter drivers for specified device node.
539 * Set to TRUE for loading lower level filters or FALSE for upper
544 IopAttachFilterDrivers(
545 PDEVICE_NODE DeviceNode
,
548 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = {{0}};
550 UNICODE_STRING Class
;
551 WCHAR ClassBuffer
[40];
555 * First load the device filters
558 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
560 QueryTable
[0].Name
= L
"LowerFilters";
562 QueryTable
[0].Name
= L
"UpperFilters";
563 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
565 KeyBuffer
= ExAllocatePool(
567 (49 * sizeof(WCHAR
)) + DeviceNode
->InstancePath
.Length
);
568 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
569 wcscat(KeyBuffer
, DeviceNode
->InstancePath
.Buffer
);
571 RtlQueryRegistryValues(
572 RTL_REGISTRY_ABSOLUTE
,
579 * Now get the class GUID
583 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
584 Class
.Buffer
= ClassBuffer
;
585 QueryTable
[0].QueryRoutine
= NULL
;
586 QueryTable
[0].Name
= L
"ClassGUID";
587 QueryTable
[0].EntryContext
= &Class
;
588 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
590 Status
= RtlQueryRegistryValues(
591 RTL_REGISTRY_ABSOLUTE
,
597 ExFreePool(KeyBuffer
);
600 * Load the class filter driver
603 if (NT_SUCCESS(Status
))
605 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
607 QueryTable
[0].Name
= L
"LowerFilters";
609 QueryTable
[0].Name
= L
"UpperFilters";
610 QueryTable
[0].EntryContext
= NULL
;
611 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
613 KeyBuffer
= ExAllocatePool(PagedPool
, (58 * sizeof(WCHAR
)) + Class
.Length
);
614 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\");
615 wcscat(KeyBuffer
, ClassBuffer
);
617 RtlQueryRegistryValues(
618 RTL_REGISTRY_ABSOLUTE
,
624 ExFreePool(KeyBuffer
);
627 return STATUS_SUCCESS
;
632 MiResolveImageReferences(IN PVOID ImageBase
,
633 IN PUNICODE_STRING ImageFileDirectory
,
634 IN PUNICODE_STRING NamePrefix OPTIONAL
,
635 OUT PCHAR
*MissingApi
,
636 OUT PWCHAR
*MissingDriver
,
637 OUT PLOAD_IMPORTS
*LoadImports
);
639 extern KSPIN_LOCK PsLoadedModuleSpinLock
;
642 // Used for images already loaded (boot drivers)
646 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry
,
647 PUNICODE_STRING FileName
,
648 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
651 PLDR_DATA_TABLE_ENTRY NewEntry
;
652 UNICODE_STRING BaseName
, BaseDirectory
;
653 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
654 PCHAR MissingApiName
, Buffer
;
655 PWCHAR MissingDriverName
;
656 PVOID DriverBase
= LdrEntry
->DllBase
;
658 /* Allocate a buffer we'll use for names */
659 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
663 return STATUS_INSUFFICIENT_RESOURCES
;
666 /* Check for a separator */
667 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
672 /* Loop the path until we get to the base name */
673 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
674 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
677 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
678 BaseLength
*= sizeof(WCHAR
);
680 /* Setup the string */
681 BaseName
.Length
= (USHORT
)BaseLength
;
686 /* Otherwise, we already have a base name */
687 BaseName
.Length
= FileName
->Length
;
688 BaseName
.Buffer
= FileName
->Buffer
;
691 /* Setup the maximum length */
692 BaseName
.MaximumLength
= BaseName
.Length
;
694 /* Now compute the base directory */
695 BaseDirectory
= *FileName
;
696 BaseDirectory
.Length
-= BaseName
.Length
;
697 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
701 /* Resolve imports */
702 MissingApiName
= Buffer
;
703 Status
= MiResolveImageReferences(DriverBase
,
709 if (!NT_SUCCESS(Status
)) return Status
;
712 *ModuleObject
= LdrEntry
;
713 return STATUS_SUCCESS
;
717 * IopInitializeBuiltinDriver
719 * Initialize a driver that is already loaded in memory.
724 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
726 PDEVICE_NODE DeviceNode
;
727 PDRIVER_OBJECT DriverObject
;
729 PWCHAR FileNameWithoutPath
;
730 LPWSTR FileExtension
;
731 PUNICODE_STRING ModuleName
= &LdrEntry
->BaseDllName
;
732 UNICODE_STRING ServiceName
;
733 #if 1 // Disable for FreeLDR 2.5
734 UNICODE_STRING ServiceNameWithExtension
;
735 PLDR_DATA_TABLE_ENTRY ModuleObject
;
739 * Display 'Loading XXX...' message
741 IopDisplayLoadingMessage(ModuleName
->Buffer
, TRUE
);
744 * Generate filename without path (not needed by freeldr)
746 FileNameWithoutPath
= wcsrchr(ModuleName
->Buffer
, L
'\\');
747 if (FileNameWithoutPath
== NULL
)
749 FileNameWithoutPath
= ModuleName
->Buffer
;
753 FileNameWithoutPath
++;
759 #if 1 // Remove for FreeLDR 2.5.
760 RtlCreateUnicodeString(&ServiceNameWithExtension
, FileNameWithoutPath
);
761 Status
= LdrProcessDriverModule(LdrEntry
, &ServiceNameWithExtension
, &ModuleObject
);
762 if (!NT_SUCCESS(Status
))
764 CPRINT("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
770 * Strip the file extension from ServiceName
772 RtlCreateUnicodeString(&ServiceName
, FileNameWithoutPath
);
773 FileExtension
= wcsrchr(ServiceName
.Buffer
, '.');
774 if (FileExtension
!= NULL
)
776 ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
777 FileExtension
[0] = 0;
781 * Determine the right device object
783 /* Use IopRootDeviceNode for now */
784 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
785 if (!NT_SUCCESS(Status
))
787 CPRINT("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
790 DeviceNode
->ServiceName
= ServiceName
;
793 * Initialize the driver
795 Status
= IopInitializeDriverModule(DeviceNode
, LdrEntry
,
796 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
798 if (!NT_SUCCESS(Status
))
800 IopFreeDeviceNode(DeviceNode
);
801 CPRINT("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
805 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
806 if (NT_SUCCESS(Status
))
808 Status
= IopStartDevice(DeviceNode
);
815 * IopInitializeBootDrivers
817 * Initialize boot drivers and free memory for boot files.
827 IopInitializeBootDrivers(VOID
)
829 PLIST_ENTRY ListHead
, NextEntry
;
830 PLDR_DATA_TABLE_ENTRY LdrEntry
;
831 PDEVICE_NODE DeviceNode
;
832 PDRIVER_OBJECT DriverObject
;
833 LDR_DATA_TABLE_ENTRY ModuleObject
;
835 UNICODE_STRING DriverName
;
837 /* Use IopRootDeviceNode for now */
838 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, NULL
, &DeviceNode
);
839 if (!NT_SUCCESS(Status
)) return;
841 /* Setup the module object for the RAW FS Driver */
842 ModuleObject
.DllBase
= NULL
;
843 ModuleObject
.SizeOfImage
= 0;
844 ModuleObject
.EntryPoint
= RawFsDriverEntry
;
845 RtlInitUnicodeString(&DriverName
, L
"RAW");
848 Status
= IopInitializeDriverModule(DeviceNode
,
853 if (!NT_SUCCESS(Status
))
856 IopFreeDeviceNode(DeviceNode
);
860 /* Now initialize the associated device */
861 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
862 if (!NT_SUCCESS(Status
))
865 IopFreeDeviceNode(DeviceNode
);
870 Status
= IopStartDevice(DeviceNode
);
871 if (!NT_SUCCESS(Status
))
874 IopFreeDeviceNode(DeviceNode
);
878 /* Loop the boot modules */
879 ListHead
= &KeLoaderBlock
->LoadOrderListHead
;
880 NextEntry
= ListHead
->Flink
;
881 while (ListHead
!= NextEntry
)
884 LdrEntry
= CONTAINING_RECORD(NextEntry
,
885 LDR_DATA_TABLE_ENTRY
,
889 * HACK: Make sure we're loading a driver
890 * (we should be using BootDriverListHead!)
892 if (wcsstr(_wcsupr(LdrEntry
->BaseDllName
.Buffer
), L
".SYS"))
894 /* Make sure we didn't load this driver already */
895 if (!(LdrEntry
->Flags
& LDRP_ENTRY_INSERTED
))
898 IopInitializeBuiltinDriver(LdrEntry
);
902 /* Go to the next driver */
903 NextEntry
= NextEntry
->Flink
;
906 /* In old ROS, the loader list became empty after this point. Simulate. */
907 InitializeListHead(&KeLoaderBlock
->LoadOrderListHead
);
913 * Unloads a device driver.
917 * Name of the service to unload (registry key).
920 * Whether to unload Plug & Plug or only legacy drivers. If this
921 * parameter is set to FALSE, the routine will unload only legacy
928 * Guard the whole function by SEH.
932 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
934 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
935 UNICODE_STRING ImagePath
;
936 UNICODE_STRING ServiceName
;
937 UNICODE_STRING ObjectName
;
938 PDRIVER_OBJECT DriverObject
;
942 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
947 * Get the service name from the registry key name
950 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
952 Start
= DriverServiceName
->Buffer
;
956 RtlInitUnicodeString(&ServiceName
, Start
);
959 * Construct the driver object name
962 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
963 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
964 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
965 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
966 memcpy(ObjectName
.Buffer
+ 8, Start
, (ObjectName
.Length
- 8) * sizeof(WCHAR
));
967 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
970 * Find the driver object
973 Status
= ObReferenceObjectByName(&ObjectName
, 0, 0, 0, IoDriverObjectType
,
974 KernelMode
, 0, (PVOID
*)&DriverObject
);
976 if (!NT_SUCCESS(Status
))
978 DPRINT("Can't locate driver object for %wZ\n", ObjectName
);
983 * Free the buffer for driver object name
986 ExFreePool(ObjectName
.Buffer
);
989 * Get path of service...
992 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
994 RtlInitUnicodeString(&ImagePath
, NULL
);
996 QueryTable
[0].Name
= L
"ImagePath";
997 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
998 QueryTable
[0].EntryContext
= &ImagePath
;
1000 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1001 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1003 if (!NT_SUCCESS(Status
))
1005 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1010 * Normalize the image path for all later processing.
1013 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1015 if (!NT_SUCCESS(Status
))
1017 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1022 * Free the service path
1025 ExFreePool(ImagePath
.Buffer
);
1028 * Unload the module and release the references to the device object
1031 if (DriverObject
->DriverUnload
)
1032 (*DriverObject
->DriverUnload
)(DriverObject
);
1033 ObDereferenceObject(DriverObject
);
1034 ObDereferenceObject(DriverObject
);
1035 MmUnloadSystemImage(DriverObject
->DriverSection
);
1037 return STATUS_SUCCESS
;
1042 IopReinitializeDrivers(VOID
)
1044 PDRIVER_REINIT_ITEM ReinitItem
;
1047 /* Get the first entry and start looping */
1048 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1049 &DriverReinitListLock
);
1053 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1055 /* Increment reinitialization counter */
1056 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1058 /* Remove the device object flag */
1059 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1061 /* Call the routine */
1062 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1063 ReinitItem
->Context
,
1064 ReinitItem
->DriverObject
->
1065 DriverExtension
->Count
);
1067 /* Free the entry */
1070 /* Move to the next one */
1071 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1072 &DriverReinitListLock
);
1078 IopReinitializeBootDrivers(VOID
)
1080 PDRIVER_REINIT_ITEM ReinitItem
;
1083 /* Get the first entry and start looping */
1084 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1085 &DriverBootReinitListLock
);
1089 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1091 /* Increment reinitialization counter */
1092 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1094 /* Remove the device object flag */
1095 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1097 /* Call the routine */
1098 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1099 ReinitItem
->Context
,
1100 ReinitItem
->DriverObject
->
1101 DriverExtension
->Count
);
1103 /* Free the entry */
1106 /* Move to the next one */
1107 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1108 &DriverBootReinitListLock
);
1114 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1115 IN PDRIVER_INITIALIZE InitializationFunction
,
1116 OUT PDRIVER_OBJECT
*pDriverObject
)
1118 WCHAR NameBuffer
[100];
1120 UNICODE_STRING LocalDriverName
;
1122 OBJECT_ATTRIBUTES ObjectAttributes
;
1124 PDRIVER_OBJECT DriverObject
;
1125 UNICODE_STRING ServiceKeyName
;
1127 ULONG i
, RetryCount
= 0;
1130 /* First, create a unique name for the driver if we don't have one */
1133 /* Create a random name and set up the string*/
1134 NameLength
= swprintf(NameBuffer
, L
"\\Driver\\%08u", KeTickCount
);
1135 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1136 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1137 LocalDriverName
.Buffer
= NameBuffer
;
1141 /* So we can avoid another code path, use a local var */
1142 LocalDriverName
= *DriverName
;
1145 /* Initialize the Attributes */
1146 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1147 InitializeObjectAttributes(&ObjectAttributes
,
1149 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1153 /* Create the Object */
1154 Status
= ObCreateObject(KernelMode
,
1162 (PVOID
*)&DriverObject
);
1163 if (!NT_SUCCESS(Status
)) return Status
;
1165 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1167 /* Set up the Object */
1168 RtlZeroMemory(DriverObject
, ObjectSize
);
1169 DriverObject
->Type
= IO_TYPE_DRIVER
;
1170 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1171 DriverObject
->Flags
= DRVO_BUILTIN_DRIVER
;
1172 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1173 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1174 DriverObject
->DriverInit
= InitializationFunction
;
1176 /* Loop all Major Functions */
1177 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1179 /* Invalidate each function */
1180 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1183 /* Set up the service key name buffer */
1184 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1185 LocalDriverName
.Length
+
1188 if (!ServiceKeyName
.Buffer
)
1191 ObMakeTemporaryObject(DriverObject
);
1192 ObDereferenceObject(DriverObject
);
1193 return STATUS_INSUFFICIENT_RESOURCES
;
1196 /* Fill out the key data and copy the buffer */
1197 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1198 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1199 RtlCopyMemory(ServiceKeyName
.Buffer
,
1200 LocalDriverName
.Buffer
,
1201 LocalDriverName
.Length
);
1203 /* Null-terminate it and set it */
1204 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1205 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1207 /* Also store it in the Driver Object. This is a bit of a hack. */
1208 RtlCopyMemory(&DriverObject
->DriverName
,
1210 sizeof(UNICODE_STRING
));
1212 /* Add the Object and get its handle */
1213 Status
= ObInsertObject(DriverObject
,
1220 /* Eliminate small possibility when this function is called more than
1221 once in a row, and KeTickCount doesn't get enough time to change */
1222 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1228 if (!NT_SUCCESS(Status
)) return Status
;
1230 /* Now reference it */
1231 Status
= ObReferenceObjectByHandle(hDriver
,
1235 (PVOID
*)&DriverObject
,
1237 if (!NT_SUCCESS(Status
))
1240 ObMakeTemporaryObject(DriverObject
);
1241 ObDereferenceObject(DriverObject
);
1245 /* Close the extra handle */
1248 /* Finally, call its init function */
1249 Status
= (*InitializationFunction
)(DriverObject
, NULL
);
1250 if (!NT_SUCCESS(Status
))
1252 /* If it didn't work, then kill the object */
1253 ObMakeTemporaryObject(DriverObject
);
1254 ObDereferenceObject(DriverObject
);
1258 /* Returns to caller the object */
1259 *pDriverObject
= DriverObject
;
1262 /* Return the Status */
1266 /* PUBLIC FUNCTIONS ***********************************************************/
1273 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1274 IN PDRIVER_INITIALIZE InitializationFunction
)
1276 PDRIVER_OBJECT DriverObject
;
1277 return IopCreateDriver(DriverName
, InitializationFunction
, &DriverObject
);
1285 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1287 /* Simply derefence the Object */
1288 ObDereferenceObject(DriverObject
);
1296 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1297 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1300 PDRIVER_REINIT_ITEM ReinitItem
;
1302 /* Allocate the entry */
1303 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1304 sizeof(DRIVER_REINIT_ITEM
),
1306 if (!ReinitItem
) return;
1309 ReinitItem
->DriverObject
= DriverObject
;
1310 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1311 ReinitItem
->Context
= Context
;
1313 /* Set the Driver Object flag and insert the entry into the list */
1314 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1315 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1316 &ReinitItem
->ItemEntry
,
1317 &DriverBootReinitListLock
);
1325 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1326 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1329 PDRIVER_REINIT_ITEM ReinitItem
;
1331 /* Allocate the entry */
1332 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1333 sizeof(DRIVER_REINIT_ITEM
),
1335 if (!ReinitItem
) return;
1338 ReinitItem
->DriverObject
= DriverObject
;
1339 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1340 ReinitItem
->Context
= Context
;
1342 /* Set the Driver Object flag and insert the entry into the list */
1343 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1344 ExInterlockedInsertTailList(&DriverReinitListHead
,
1345 &ReinitItem
->ItemEntry
,
1346 &DriverReinitListLock
);
1354 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1355 IN PVOID ClientIdentificationAddress
,
1356 IN ULONG DriverObjectExtensionSize
,
1357 OUT PVOID
*DriverObjectExtension
)
1360 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1361 BOOLEAN Inserted
= FALSE
;
1363 /* Assume failure */
1364 *DriverObjectExtension
= NULL
;
1366 /* Allocate the extension */
1367 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1368 sizeof(IO_CLIENT_EXTENSION
) +
1369 DriverObjectExtensionSize
,
1370 TAG_DRIVER_EXTENSION
);
1371 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1373 /* Clear the extension for teh caller */
1374 RtlZeroMemory(NewDriverExtension
,
1375 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1378 OldIrql
= KeRaiseIrqlToDpcLevel();
1380 /* Fill out the extension */
1381 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1383 /* Loop the current extensions */
1384 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1385 ClientDriverExtension
;
1386 while (DriverExtensions
)
1388 /* Check if the identifier matches */
1389 if (DriverExtensions
->ClientIdentificationAddress
==
1390 ClientIdentificationAddress
)
1392 /* We have a collision, break out */
1396 /* Go to the next one */
1397 DriverExtensions
= DriverExtensions
->NextExtension
;
1400 /* Check if we didn't collide */
1401 if (!DriverExtensions
)
1403 /* Link this one in */
1404 NewDriverExtension
->NextExtension
=
1405 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1406 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1411 /* Release the lock */
1412 KeLowerIrql(OldIrql
);
1414 /* Check if insertion failed */
1417 /* Free the entry and fail */
1418 ExFreePool(NewDriverExtension
);
1419 return STATUS_OBJECT_NAME_COLLISION
;
1422 /* Otherwise, return the pointer */
1423 *DriverObjectExtension
= NewDriverExtension
+ 1;
1424 return STATUS_SUCCESS
;
1432 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1433 IN PVOID ClientIdentificationAddress
)
1436 PIO_CLIENT_EXTENSION DriverExtensions
;
1439 OldIrql
= KeRaiseIrqlToDpcLevel();
1441 /* Loop the list until we find the right one */
1442 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1443 while (DriverExtensions
)
1445 /* Check for a match */
1446 if (DriverExtensions
->ClientIdentificationAddress
==
1447 ClientIdentificationAddress
)
1454 DriverExtensions
= DriverExtensions
->NextExtension
;
1458 KeLowerIrql(OldIrql
);
1460 /* Return nothing or the extension */
1461 if (!DriverExtensions
) return NULL
;
1462 return DriverExtensions
+ 1;
1468 * Loads a device driver.
1472 * Name of the service to load (registry key).
1481 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1483 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1484 UNICODE_STRING ImagePath
;
1485 UNICODE_STRING ServiceName
;
1486 UNICODE_STRING CapturedDriverServiceName
= {0};
1487 KPROCESSOR_MODE PreviousMode
;
1490 PDEVICE_NODE DeviceNode
;
1491 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1492 PDRIVER_OBJECT DriverObject
;
1497 PreviousMode
= KeGetPreviousMode();
1500 * Check security privileges
1503 /* FIXME: Uncomment when privileges will be correctly implemented. */
1505 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1507 DPRINT("Privilege not held\n");
1508 return STATUS_PRIVILEGE_NOT_HELD
;
1512 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
1515 if (!NT_SUCCESS(Status
))
1520 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1522 RtlInitUnicodeString(&ImagePath
, NULL
);
1525 * Get the service name from the registry key name.
1527 ASSERT(CapturedDriverServiceName
.Length
>= sizeof(WCHAR
));
1529 ServiceName
= CapturedDriverServiceName
;
1530 cur
= CapturedDriverServiceName
.Buffer
+ (CapturedDriverServiceName
.Length
/ sizeof(WCHAR
)) - 1;
1531 while (CapturedDriverServiceName
.Buffer
!= cur
)
1535 ServiceName
.Buffer
= cur
+ 1;
1536 ServiceName
.Length
= CapturedDriverServiceName
.Length
-
1537 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1538 (ULONG_PTR
)CapturedDriverServiceName
.Buffer
);
1548 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1550 RtlInitUnicodeString(&ImagePath
, NULL
);
1552 QueryTable
[0].Name
= L
"Type";
1553 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1554 QueryTable
[0].EntryContext
= &Type
;
1556 QueryTable
[1].Name
= L
"ImagePath";
1557 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1558 QueryTable
[1].EntryContext
= &ImagePath
;
1560 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1561 CapturedDriverServiceName
.Buffer
, QueryTable
, NULL
, NULL
);
1563 if (!NT_SUCCESS(Status
))
1565 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1566 ExFreePool(ImagePath
.Buffer
);
1567 goto ReleaseCapturedString
;
1571 * Normalize the image path for all later processing.
1574 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1576 if (!NT_SUCCESS(Status
))
1578 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1579 goto ReleaseCapturedString
;
1582 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1583 DPRINT("Type: %lx\n", Type
);
1586 * Create device node
1589 /* Use IopRootDeviceNode for now */
1590 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1592 if (!NT_SUCCESS(Status
))
1594 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1595 goto ReleaseCapturedString
;
1599 * Load the driver module
1602 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, NULL
);
1603 if (!NT_SUCCESS(Status
))
1605 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1606 IopFreeDeviceNode(DeviceNode
);
1607 goto ReleaseCapturedString
;
1611 * Set a service name for the device node
1614 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
);
1617 * Initialize the driver module
1620 Status
= IopInitializeDriverModule(
1623 &DeviceNode
->ServiceName
,
1624 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1625 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1628 if (!NT_SUCCESS(Status
))
1630 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1631 MmUnloadSystemImage(ModuleObject
);
1632 IopFreeDeviceNode(DeviceNode
);
1633 goto ReleaseCapturedString
;
1636 IopInitializeDevice(DeviceNode
, DriverObject
);
1637 Status
= IopStartDevice(DeviceNode
);
1639 ReleaseCapturedString
:
1640 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
1649 * Unloads a legacy device driver.
1653 * Name of the service to unload (registry key).
1663 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
1665 return IopUnloadDriver(DriverServiceName
, FALSE
);