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 /* Check if it has a service key name */
83 if (DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
)
86 //ExFreePool(DriverObject->DriverExtension->ServiceKeyName.Buffer);
92 PDRIVER_OBJECT
*DriverObject
,
93 PUNICODE_STRING ServiceName
,
96 PDRIVER_OBJECT Object
;
97 WCHAR NameBuffer
[MAX_PATH
];
98 UNICODE_STRING DriverName
;
101 DPRINT("IopOpenDriverObject(%p '%wZ' %x)\n",
102 DriverObject
, ServiceName
, FileSystem
);
104 *DriverObject
= NULL
;
106 /* Create ModuleName string */
107 if (ServiceName
== NULL
|| ServiceName
->Buffer
== NULL
)
108 /* We don't know which DriverObject we have to open */
109 return STATUS_INVALID_PARAMETER_2
;
111 DriverName
.Buffer
= NameBuffer
;
112 DriverName
.Length
= 0;
113 DriverName
.MaximumLength
= sizeof(NameBuffer
);
115 if (FileSystem
== TRUE
)
116 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
118 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
119 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
121 DPRINT("Driver name: '%wZ'\n", &DriverName
);
123 /* Open driver object */
124 Status
= ObReferenceObjectByName(
126 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
, /* Attributes */
127 NULL
, /* PassedAccessState */
128 0, /* DesiredAccess */
131 NULL
, /* ParseContext */
134 if (!NT_SUCCESS(Status
))
137 *DriverObject
= Object
;
139 return STATUS_SUCCESS
;
143 * IopDisplayLoadingMessage
145 * Display 'Loading XXX...' message.
151 IopDisplayLoadingMessage(PVOID ServiceName
,
154 CHAR TextBuffer
[256];
155 PCHAR Extra
= ".sys";
157 if (ExpInTextModeSetup
) return;
160 if (wcsstr(_wcsupr(ServiceName
), L
".SYS")) Extra
= "";
163 KeLoaderBlock
->ArcBootDeviceName
,
164 KeLoaderBlock
->NtBootPathName
,
171 if (strstr(_strupr(ServiceName
), ".SYS")) Extra
= "";
174 KeLoaderBlock
->ArcBootDeviceName
,
175 KeLoaderBlock
->NtBootPathName
,
180 HalDisplayString(TextBuffer
);
184 * IopNormalizeImagePath
186 * Normalize an image path to contain complete path.
190 * The input path and on exit the result path. ImagePath.Buffer
191 * must be allocated by ExAllocatePool on input. Caller is responsible
192 * for freeing the buffer when it's no longer needed.
195 * Name of the service that ImagePath belongs to.
201 * The input image path isn't freed on error.
205 IopNormalizeImagePath(
206 IN OUT PUNICODE_STRING ImagePath
,
207 IN PUNICODE_STRING ServiceName
)
209 UNICODE_STRING InputImagePath
;
214 sizeof(UNICODE_STRING
));
216 if (InputImagePath
.Length
== 0)
218 ImagePath
->Length
= (33 * sizeof(WCHAR
)) + ServiceName
->Length
;
219 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
220 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
221 if (ImagePath
->Buffer
== NULL
)
222 return STATUS_NO_MEMORY
;
224 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\system32\\drivers\\");
225 wcscat(ImagePath
->Buffer
, ServiceName
->Buffer
);
226 wcscat(ImagePath
->Buffer
, L
".sys");
228 if (InputImagePath
.Buffer
[0] != L
'\\')
230 ImagePath
->Length
= (12 * sizeof(WCHAR
)) + InputImagePath
.Length
;
231 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
232 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
233 if (ImagePath
->Buffer
== NULL
)
234 return STATUS_NO_MEMORY
;
236 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\");
237 wcscat(ImagePath
->Buffer
, InputImagePath
.Buffer
);
238 ExFreePool(InputImagePath
.Buffer
);
241 return STATUS_SUCCESS
;
245 * IopLoadServiceModule
247 * Load a module specified by registry settings for service.
251 * Name of the service to load.
258 IopLoadServiceModule(
259 IN PUNICODE_STRING ServiceName
,
260 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
262 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
264 UNICODE_STRING ServiceImagePath
;
267 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
269 /* FIXME: This check may be removed once the bug is fixed */
270 if (ServiceName
->Buffer
== NULL
)
271 return STATUS_UNSUCCESSFUL
;
274 * Get information about the service.
277 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
279 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
281 QueryTable
[0].Name
= L
"Start";
282 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
283 QueryTable
[0].EntryContext
= &ServiceStart
;
285 QueryTable
[1].Name
= L
"ImagePath";
286 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
287 QueryTable
[1].EntryContext
= &ServiceImagePath
;
289 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
290 ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
292 if (!NT_SUCCESS(Status
))
294 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
299 * Normalize the image path for all later processing.
302 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
304 if (!NT_SUCCESS(Status
))
306 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
311 * Case for disabled drivers
314 if (ServiceStart
>= 4)
316 /* FIXME: Check if it is the right status code */
317 Status
= STATUS_PLUGPLAY_NO_DEVICE
;
321 DPRINT("Loading module\n");
322 Status
= MmLoadSystemImage(&ServiceImagePath
, NULL
, NULL
, 0, (PVOID
)ModuleObject
, NULL
);
325 ExFreePool(ServiceImagePath
.Buffer
);
328 * Now check if the module was loaded successfully.
331 if (!NT_SUCCESS(Status
))
333 DPRINT("Module loading failed (Status %x)\n", Status
);
336 DPRINT("Module loading (Status %x)\n", Status
);
343 IopDriverInitializeEmpty(IN
struct _DRIVER_OBJECT
*DriverObject
, IN PUNICODE_STRING RegistryPath
)
345 return STATUS_SUCCESS
;
349 * IopInitializeDriverModule
351 * Initalize a loaded driver.
355 * Pointer to device node.
358 * Module object representing the driver. It can be retrieve by
359 * IopLoadServiceModule.
362 * Name of the service (as in registry).
365 * Set to TRUE for file system drivers.
368 * On successful return this contains the driver object representing
373 IopInitializeDriverModule(
374 IN PDEVICE_NODE DeviceNode
,
375 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
376 IN PUNICODE_STRING ServiceName
,
377 IN BOOLEAN FileSystemDriver
,
378 OUT PDRIVER_OBJECT
*DriverObject
)
380 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
381 WCHAR NameBuffer
[MAX_PATH
];
382 UNICODE_STRING DriverName
;
383 UNICODE_STRING RegistryKey
;
384 PDRIVER_INITIALIZE DriverEntry
;
385 PDRIVER_OBJECT Driver
;
386 PDEVICE_OBJECT DeviceObject
;
389 DriverEntry
= ModuleObject
->EntryPoint
;
391 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
393 RegistryKey
.Length
= 0;
394 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
395 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
396 if (RegistryKey
.Buffer
== NULL
)
398 return STATUS_INSUFFICIENT_RESOURCES
;
400 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
401 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
405 RtlInitUnicodeString(&RegistryKey
, NULL
);
408 /* Create ModuleName string */
409 if (ServiceName
&& ServiceName
->Length
> 0)
411 if (FileSystemDriver
== TRUE
)
412 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
414 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
415 wcscat(NameBuffer
, ServiceName
->Buffer
);
417 RtlInitUnicodeString(&DriverName
, NameBuffer
);
418 DPRINT("Driver name: '%wZ'\n", &DriverName
);
419 Status
= IopCreateDriver(&DriverName
, IopDriverInitializeEmpty
, &Driver
);
423 Status
= IopCreateDriver(NULL
, IopDriverInitializeEmpty
, &Driver
);
426 *DriverObject
= Driver
;
427 if (!NT_SUCCESS(Status
))
429 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status
);
433 Driver
->HardwareDatabase
= &IopHardwareDatabaseKey
;
434 Driver
->DriverStart
= ModuleObject
->DllBase
;
435 Driver
->DriverSize
= ModuleObject
->SizeOfImage
;
437 DPRINT("RegistryKey: %wZ\n", &RegistryKey
);
438 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry
);
440 Status
= DriverEntry(Driver
, &RegistryKey
);
442 RtlFreeUnicodeString(&RegistryKey
);
444 if (!NT_SUCCESS(Status
))
446 ObMakeTemporaryObject(Driver
);
447 ObDereferenceObject(Driver
);
451 /* Set the driver as initialized */
452 Driver
->Flags
|= DRVO_INITIALIZED
;
453 DeviceObject
= Driver
->DeviceObject
;
456 /* Set every device as initialized too */
457 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
458 DeviceObject
= DeviceObject
->NextDevice
;
461 IopReinitializeDrivers();
463 return STATUS_SUCCESS
;
467 * IopAttachFilterDriversCallback
469 * Internal routine used by IopAttachFilterDrivers.
473 IopAttachFilterDriversCallback(
481 PDEVICE_NODE DeviceNode
= Context
;
482 UNICODE_STRING ServiceName
;
484 PLDR_DATA_TABLE_ENTRY ModuleObject
;
485 PDRIVER_OBJECT DriverObject
;
488 for (Filters
= ValueData
;
489 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
491 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
493 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
494 ServiceName
.Buffer
= Filters
;
495 ServiceName
.MaximumLength
=
496 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
498 /* Load and initialize the filter driver */
499 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
500 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
502 if (!NT_SUCCESS(Status
))
505 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
506 FALSE
, &DriverObject
);
507 if (!NT_SUCCESS(Status
))
512 /* get existing DriverObject pointer */
513 Status
= IopGetDriverObject(
517 if (!NT_SUCCESS(Status
))
521 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
522 if (!NT_SUCCESS(Status
))
526 return STATUS_SUCCESS
;
530 * IopAttachFilterDrivers
532 * Load filter drivers for specified device node.
536 * Set to TRUE for loading lower level filters or FALSE for upper
541 IopAttachFilterDrivers(
542 PDEVICE_NODE DeviceNode
,
545 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = {{0}};
547 UNICODE_STRING Class
;
548 WCHAR ClassBuffer
[40];
552 * First load the device filters
555 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
557 QueryTable
[0].Name
= L
"LowerFilters";
559 QueryTable
[0].Name
= L
"UpperFilters";
560 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
562 KeyBuffer
= ExAllocatePool(
564 (49 * sizeof(WCHAR
)) + DeviceNode
->InstancePath
.Length
);
565 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
566 wcscat(KeyBuffer
, DeviceNode
->InstancePath
.Buffer
);
568 RtlQueryRegistryValues(
569 RTL_REGISTRY_ABSOLUTE
,
576 * Now get the class GUID
580 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
581 Class
.Buffer
= ClassBuffer
;
582 QueryTable
[0].QueryRoutine
= NULL
;
583 QueryTable
[0].Name
= L
"ClassGUID";
584 QueryTable
[0].EntryContext
= &Class
;
585 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
587 Status
= RtlQueryRegistryValues(
588 RTL_REGISTRY_ABSOLUTE
,
594 ExFreePool(KeyBuffer
);
597 * Load the class filter driver
600 if (NT_SUCCESS(Status
))
602 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
604 QueryTable
[0].Name
= L
"LowerFilters";
606 QueryTable
[0].Name
= L
"UpperFilters";
607 QueryTable
[0].EntryContext
= NULL
;
608 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
610 KeyBuffer
= ExAllocatePool(PagedPool
, (58 * sizeof(WCHAR
)) + Class
.Length
);
611 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\");
612 wcscat(KeyBuffer
, ClassBuffer
);
614 RtlQueryRegistryValues(
615 RTL_REGISTRY_ABSOLUTE
,
621 ExFreePool(KeyBuffer
);
624 return STATUS_SUCCESS
;
629 MiResolveImageReferences(IN PVOID ImageBase
,
630 IN PUNICODE_STRING ImageFileDirectory
,
631 IN PUNICODE_STRING NamePrefix OPTIONAL
,
632 OUT PCHAR
*MissingApi
,
633 OUT PWCHAR
*MissingDriver
,
634 OUT PLOAD_IMPORTS
*LoadImports
);
636 extern KSPIN_LOCK PsLoadedModuleSpinLock
;
639 // Used for images already loaded (boot drivers)
643 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry
,
644 PUNICODE_STRING FileName
,
645 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
648 PLDR_DATA_TABLE_ENTRY NewEntry
;
649 UNICODE_STRING BaseName
, BaseDirectory
;
650 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
651 PCHAR MissingApiName
, Buffer
;
652 PWCHAR MissingDriverName
;
653 PVOID DriverBase
= LdrEntry
->DllBase
;
655 /* Allocate a buffer we'll use for names */
656 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
660 return STATUS_INSUFFICIENT_RESOURCES
;
663 /* Check for a separator */
664 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
669 /* Loop the path until we get to the base name */
670 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
671 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
674 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
675 BaseLength
*= sizeof(WCHAR
);
677 /* Setup the string */
678 BaseName
.Length
= (USHORT
)BaseLength
;
683 /* Otherwise, we already have a base name */
684 BaseName
.Length
= FileName
->Length
;
685 BaseName
.Buffer
= FileName
->Buffer
;
688 /* Setup the maximum length */
689 BaseName
.MaximumLength
= BaseName
.Length
;
691 /* Now compute the base directory */
692 BaseDirectory
= *FileName
;
693 BaseDirectory
.Length
-= BaseName
.Length
;
694 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
698 /* Resolve imports */
699 MissingApiName
= Buffer
;
700 Status
= MiResolveImageReferences(DriverBase
,
706 if (!NT_SUCCESS(Status
)) return Status
;
709 *ModuleObject
= LdrEntry
;
710 return STATUS_SUCCESS
;
714 * IopInitializeBuiltinDriver
716 * Initialize a driver that is already loaded in memory.
721 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
723 PDEVICE_NODE DeviceNode
;
724 PDRIVER_OBJECT DriverObject
;
726 PWCHAR FileNameWithoutPath
;
727 LPWSTR FileExtension
;
728 PUNICODE_STRING ModuleName
= &LdrEntry
->BaseDllName
;
729 UNICODE_STRING ServiceName
;
730 #if 1 // Disable for FreeLDR 2.5
731 UNICODE_STRING ServiceNameWithExtension
;
732 PLDR_DATA_TABLE_ENTRY ModuleObject
;
736 * Display 'Loading XXX...' message
738 IopDisplayLoadingMessage(ModuleName
->Buffer
, TRUE
);
741 * Generate filename without path (not needed by freeldr)
743 FileNameWithoutPath
= wcsrchr(ModuleName
->Buffer
, L
'\\');
744 if (FileNameWithoutPath
== NULL
)
746 FileNameWithoutPath
= ModuleName
->Buffer
;
750 FileNameWithoutPath
++;
756 #if 1 // Remove for FreeLDR 2.5.
757 RtlCreateUnicodeString(&ServiceNameWithExtension
, FileNameWithoutPath
);
758 Status
= LdrProcessDriverModule(LdrEntry
, &ServiceNameWithExtension
, &ModuleObject
);
759 if (!NT_SUCCESS(Status
))
761 CPRINT("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
767 * Strip the file extension from ServiceName
769 RtlCreateUnicodeString(&ServiceName
, FileNameWithoutPath
);
770 FileExtension
= wcsrchr(ServiceName
.Buffer
, '.');
771 if (FileExtension
!= NULL
)
773 ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
774 FileExtension
[0] = 0;
778 * Determine the right device object
780 /* Use IopRootDeviceNode for now */
781 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
782 if (!NT_SUCCESS(Status
))
784 CPRINT("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
787 DeviceNode
->ServiceName
= ServiceName
;
790 * Initialize the driver
792 Status
= IopInitializeDriverModule(DeviceNode
, LdrEntry
,
793 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
795 if (!NT_SUCCESS(Status
))
797 IopFreeDeviceNode(DeviceNode
);
798 CPRINT("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
802 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
803 if (NT_SUCCESS(Status
))
805 Status
= IopStartDevice(DeviceNode
);
812 * IopInitializeBootDrivers
814 * Initialize boot drivers and free memory for boot files.
824 IopInitializeBootDrivers(VOID
)
826 PLIST_ENTRY ListHead
, NextEntry
;
827 PLDR_DATA_TABLE_ENTRY LdrEntry
;
828 PDEVICE_NODE DeviceNode
;
829 PDRIVER_OBJECT DriverObject
;
830 LDR_DATA_TABLE_ENTRY ModuleObject
;
833 /* Use IopRootDeviceNode for now */
834 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, NULL
, &DeviceNode
);
835 if (!NT_SUCCESS(Status
)) return;
837 /* Setup the module object for the RAW FS Driver */
838 ModuleObject
.DllBase
= NULL
;
839 ModuleObject
.SizeOfImage
= 0;
840 ModuleObject
.EntryPoint
= RawFsDriverEntry
;
843 Status
= IopInitializeDriverModule(DeviceNode
,
845 &DeviceNode
->ServiceName
,
848 if (!NT_SUCCESS(Status
))
851 IopFreeDeviceNode(DeviceNode
);
855 /* Now initialize the associated device */
856 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
857 if (!NT_SUCCESS(Status
))
860 IopFreeDeviceNode(DeviceNode
);
865 Status
= IopStartDevice(DeviceNode
);
866 if (!NT_SUCCESS(Status
))
869 IopFreeDeviceNode(DeviceNode
);
873 /* Loop the boot modules */
874 ListHead
= &KeLoaderBlock
->LoadOrderListHead
;
875 NextEntry
= ListHead
->Flink
;
876 while (ListHead
!= NextEntry
)
879 LdrEntry
= CONTAINING_RECORD(NextEntry
,
880 LDR_DATA_TABLE_ENTRY
,
884 * HACK: Make sure we're loading a driver
885 * (we should be using BootDriverListHead!)
887 if (wcsstr(_wcsupr(LdrEntry
->BaseDllName
.Buffer
), L
".SYS"))
889 /* Make sure we didn't load this driver already */
890 if (!(LdrEntry
->Flags
& LDRP_ENTRY_INSERTED
))
893 IopInitializeBuiltinDriver(LdrEntry
);
897 /* Go to the next driver */
898 NextEntry
= NextEntry
->Flink
;
901 /* In old ROS, the loader list became empty after this point. Simulate. */
902 InitializeListHead(&KeLoaderBlock
->LoadOrderListHead
);
908 * Unloads a device driver.
912 * Name of the service to unload (registry key).
915 * Whether to unload Plug & Plug or only legacy drivers. If this
916 * parameter is set to FALSE, the routine will unload only legacy
923 * Guard the whole function by SEH.
927 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
929 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
930 UNICODE_STRING ImagePath
;
931 UNICODE_STRING ServiceName
;
932 UNICODE_STRING ObjectName
;
933 PDRIVER_OBJECT DriverObject
;
937 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
942 * Get the service name from the registry key name
945 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
947 Start
= DriverServiceName
->Buffer
;
951 RtlInitUnicodeString(&ServiceName
, Start
);
954 * Construct the driver object name
957 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
958 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
959 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
960 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
961 memcpy(ObjectName
.Buffer
+ 8, Start
, (ObjectName
.Length
- 8) * sizeof(WCHAR
));
962 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
965 * Find the driver object
968 Status
= ObReferenceObjectByName(&ObjectName
, 0, 0, 0, IoDriverObjectType
,
969 KernelMode
, 0, (PVOID
*)&DriverObject
);
971 if (!NT_SUCCESS(Status
))
973 DPRINT("Can't locate driver object for %wZ\n", ObjectName
);
978 * Free the buffer for driver object name
981 ExFreePool(ObjectName
.Buffer
);
984 * Get path of service...
987 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
989 RtlInitUnicodeString(&ImagePath
, NULL
);
991 QueryTable
[0].Name
= L
"ImagePath";
992 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
993 QueryTable
[0].EntryContext
= &ImagePath
;
995 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
996 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
998 if (!NT_SUCCESS(Status
))
1000 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1005 * Normalize the image path for all later processing.
1008 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1010 if (!NT_SUCCESS(Status
))
1012 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1017 * Free the service path
1020 ExFreePool(ImagePath
.Buffer
);
1023 * Unload the module and release the references to the device object
1026 if (DriverObject
->DriverUnload
)
1027 (*DriverObject
->DriverUnload
)(DriverObject
);
1028 ObDereferenceObject(DriverObject
);
1029 ObDereferenceObject(DriverObject
);
1030 MmUnloadSystemImage(DriverObject
->DriverSection
);
1032 return STATUS_SUCCESS
;
1037 IopReinitializeDrivers(VOID
)
1039 PDRIVER_REINIT_ITEM ReinitItem
;
1042 /* Get the first entry and start looping */
1043 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1044 &DriverReinitListLock
);
1048 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1050 /* Increment reinitialization counter */
1051 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1053 /* Remove the device object flag */
1054 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1056 /* Call the routine */
1057 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1058 ReinitItem
->Context
,
1059 ReinitItem
->DriverObject
->
1060 DriverExtension
->Count
);
1062 /* Free the entry */
1065 /* Move to the next one */
1066 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1067 &DriverReinitListLock
);
1073 IopReinitializeBootDrivers(VOID
)
1075 PDRIVER_REINIT_ITEM ReinitItem
;
1078 /* Get the first entry and start looping */
1079 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1080 &DriverBootReinitListLock
);
1084 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1086 /* Increment reinitialization counter */
1087 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1089 /* Remove the device object flag */
1090 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1092 /* Call the routine */
1093 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1094 ReinitItem
->Context
,
1095 ReinitItem
->DriverObject
->
1096 DriverExtension
->Count
);
1098 /* Free the entry */
1101 /* Move to the next one */
1102 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1103 &DriverBootReinitListLock
);
1109 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1110 IN PDRIVER_INITIALIZE InitializationFunction
,
1111 OUT PDRIVER_OBJECT
*pDriverObject
)
1113 WCHAR NameBuffer
[100];
1115 UNICODE_STRING LocalDriverName
;
1117 OBJECT_ATTRIBUTES ObjectAttributes
;
1119 PDRIVER_OBJECT DriverObject
;
1120 UNICODE_STRING ServiceKeyName
;
1124 /* First, create a unique name for the driver if we don't have one */
1127 /* Create a random name and set up the string*/
1128 NameLength
= swprintf(NameBuffer
, L
"\\Driver\\%08u", KeTickCount
);
1129 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1130 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1131 LocalDriverName
.Buffer
= NameBuffer
;
1135 /* So we can avoid another code path, use a local var */
1136 LocalDriverName
= *DriverName
;
1139 /* Initialize the Attributes */
1140 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1141 InitializeObjectAttributes(&ObjectAttributes
,
1143 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1147 /* Create the Object */
1148 Status
= ObCreateObject(KernelMode
,
1156 (PVOID
*)&DriverObject
);
1157 if (!NT_SUCCESS(Status
)) return Status
;
1159 /* Set up the Object */
1160 RtlZeroMemory(DriverObject
, ObjectSize
);
1161 DriverObject
->Type
= IO_TYPE_DRIVER
;
1162 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1163 DriverObject
->Flags
= DRVO_BUILTIN_DRIVER
;
1164 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1165 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1166 DriverObject
->DriverInit
= InitializationFunction
;
1168 /* Loop all Major Functions */
1169 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1171 /* Invalidate each function */
1172 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1175 /* Set up the service key name buffer */
1176 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1177 LocalDriverName
.Length
+
1180 if (!ServiceKeyName
.Buffer
)
1183 ObMakeTemporaryObject(DriverObject
);
1184 ObDereferenceObject(DriverObject
);
1185 return STATUS_INSUFFICIENT_RESOURCES
;
1188 /* Fill out the key data and copy the buffer */
1189 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1190 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1191 RtlCopyMemory(ServiceKeyName
.Buffer
,
1192 LocalDriverName
.Buffer
,
1193 LocalDriverName
.Length
);
1195 /* Null-terminate it and set it */
1196 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1197 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1199 /* Also store it in the Driver Object. This is a bit of a hack. */
1200 RtlCopyMemory(&DriverObject
->DriverName
,
1202 sizeof(UNICODE_STRING
));
1206 /* HACK: Something goes wrong in next lines in this case.
1207 * Just leave to prevent a freeze */
1208 *pDriverObject
= DriverObject
;
1212 /* Add the Object and get its handle */
1213 Status
= ObInsertObject(DriverObject
,
1219 if (!NT_SUCCESS(Status
)) return Status
;
1221 /* Now reference it */
1222 Status
= ObReferenceObjectByHandle(hDriver
,
1226 (PVOID
*)&DriverObject
,
1228 if (!NT_SUCCESS(Status
))
1231 ObMakeTemporaryObject(DriverObject
);
1232 ObDereferenceObject(DriverObject
);
1236 /* Close the extra handle */
1239 /* Finally, call its init function */
1240 Status
= (*InitializationFunction
)(DriverObject
, NULL
);
1241 if (!NT_SUCCESS(Status
))
1243 /* If it didn't work, then kill the object */
1244 ObMakeTemporaryObject(DriverObject
);
1245 ObDereferenceObject(DriverObject
);
1249 /* Returns to caller the object */
1250 *pDriverObject
= DriverObject
;
1253 /* Return the Status */
1257 /* PUBLIC FUNCTIONS ***********************************************************/
1264 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1265 IN PDRIVER_INITIALIZE InitializationFunction
)
1267 PDRIVER_OBJECT DriverObject
;
1268 return IopCreateDriver(DriverName
, InitializationFunction
, &DriverObject
);
1276 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1278 /* Simply derefence the Object */
1279 ObDereferenceObject(DriverObject
);
1287 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1288 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1291 PDRIVER_REINIT_ITEM ReinitItem
;
1293 /* Allocate the entry */
1294 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1295 sizeof(DRIVER_REINIT_ITEM
),
1297 if (!ReinitItem
) return;
1300 ReinitItem
->DriverObject
= DriverObject
;
1301 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1302 ReinitItem
->Context
= Context
;
1304 /* Set the Driver Object flag and insert the entry into the list */
1305 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1306 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1307 &ReinitItem
->ItemEntry
,
1308 &DriverBootReinitListLock
);
1316 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1317 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1320 PDRIVER_REINIT_ITEM ReinitItem
;
1322 /* Allocate the entry */
1323 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1324 sizeof(DRIVER_REINIT_ITEM
),
1326 if (!ReinitItem
) return;
1329 ReinitItem
->DriverObject
= DriverObject
;
1330 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1331 ReinitItem
->Context
= Context
;
1333 /* Set the Driver Object flag and insert the entry into the list */
1334 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1335 ExInterlockedInsertTailList(&DriverReinitListHead
,
1336 &ReinitItem
->ItemEntry
,
1337 &DriverReinitListLock
);
1345 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1346 IN PVOID ClientIdentificationAddress
,
1347 IN ULONG DriverObjectExtensionSize
,
1348 OUT PVOID
*DriverObjectExtension
)
1351 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1352 BOOLEAN Inserted
= FALSE
;
1354 /* Assume failure */
1355 *DriverObjectExtension
= NULL
;
1357 /* Allocate the extension */
1358 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1359 sizeof(IO_CLIENT_EXTENSION
) +
1360 DriverObjectExtensionSize
,
1361 TAG_DRIVER_EXTENSION
);
1362 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1364 /* Clear the extension for teh caller */
1365 RtlZeroMemory(NewDriverExtension
,
1366 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1369 OldIrql
= KeRaiseIrqlToDpcLevel();
1371 /* Fill out the extension */
1372 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1374 /* Loop the current extensions */
1375 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1376 ClientDriverExtension
;
1377 while (DriverExtensions
)
1379 /* Check if the identifier matches */
1380 if (DriverExtensions
->ClientIdentificationAddress
==
1381 ClientIdentificationAddress
)
1383 /* We have a collision, break out */
1387 /* Go to the next one */
1388 DriverExtensions
= DriverExtensions
->NextExtension
;
1391 /* Check if we didn't collide */
1392 if (!DriverExtensions
)
1394 /* Link this one in */
1395 NewDriverExtension
->NextExtension
=
1396 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1397 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1402 /* Release the lock */
1403 KeLowerIrql(OldIrql
);
1405 /* Check if insertion failed */
1408 /* Free the entry and fail */
1409 ExFreePool(NewDriverExtension
);
1410 return STATUS_OBJECT_NAME_COLLISION
;
1413 /* Otherwise, return the pointer */
1414 *DriverObjectExtension
= NewDriverExtension
+ 1;
1415 return STATUS_SUCCESS
;
1423 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1424 IN PVOID ClientIdentificationAddress
)
1427 PIO_CLIENT_EXTENSION DriverExtensions
;
1430 OldIrql
= KeRaiseIrqlToDpcLevel();
1432 /* Loop the list until we find the right one */
1433 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1434 while (DriverExtensions
)
1436 /* Check for a match */
1437 if (DriverExtensions
->ClientIdentificationAddress
==
1438 ClientIdentificationAddress
)
1445 DriverExtensions
= DriverExtensions
->NextExtension
;
1449 KeLowerIrql(OldIrql
);
1451 /* Return nothing or the extension */
1452 if (!DriverExtensions
) return NULL
;
1453 return DriverExtensions
+ 1;
1459 * Loads a device driver.
1463 * Name of the service to load (registry key).
1472 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1474 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1475 UNICODE_STRING ImagePath
;
1476 UNICODE_STRING ServiceName
;
1477 UNICODE_STRING CapturedDriverServiceName
= {0};
1478 KPROCESSOR_MODE PreviousMode
;
1481 PDEVICE_NODE DeviceNode
;
1482 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1483 PDRIVER_OBJECT DriverObject
;
1488 PreviousMode
= KeGetPreviousMode();
1491 * Check security privileges
1494 /* FIXME: Uncomment when privileges will be correctly implemented. */
1496 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1498 DPRINT("Privilege not held\n");
1499 return STATUS_PRIVILEGE_NOT_HELD
;
1503 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
1506 if (!NT_SUCCESS(Status
))
1511 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1513 RtlInitUnicodeString(&ImagePath
, NULL
);
1516 * Get the service name from the registry key name.
1518 ASSERT(CapturedDriverServiceName
.Length
>= sizeof(WCHAR
));
1520 ServiceName
= CapturedDriverServiceName
;
1521 cur
= CapturedDriverServiceName
.Buffer
+ (CapturedDriverServiceName
.Length
/ sizeof(WCHAR
)) - 1;
1522 while (CapturedDriverServiceName
.Buffer
!= cur
)
1526 ServiceName
.Buffer
= cur
+ 1;
1527 ServiceName
.Length
= CapturedDriverServiceName
.Length
-
1528 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1529 (ULONG_PTR
)CapturedDriverServiceName
.Buffer
);
1539 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1541 RtlInitUnicodeString(&ImagePath
, NULL
);
1543 QueryTable
[0].Name
= L
"Type";
1544 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1545 QueryTable
[0].EntryContext
= &Type
;
1547 QueryTable
[1].Name
= L
"ImagePath";
1548 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1549 QueryTable
[1].EntryContext
= &ImagePath
;
1551 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1552 CapturedDriverServiceName
.Buffer
, QueryTable
, NULL
, NULL
);
1554 if (!NT_SUCCESS(Status
))
1556 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1557 ExFreePool(ImagePath
.Buffer
);
1558 goto ReleaseCapturedString
;
1562 * Normalize the image path for all later processing.
1565 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1567 if (!NT_SUCCESS(Status
))
1569 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1570 goto ReleaseCapturedString
;
1573 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1574 DPRINT("Type: %lx\n", Type
);
1577 * Create device node
1580 /* Use IopRootDeviceNode for now */
1581 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1583 if (!NT_SUCCESS(Status
))
1585 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1586 goto ReleaseCapturedString
;
1590 * Load the driver module
1593 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, NULL
);
1594 if (!NT_SUCCESS(Status
))
1596 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1597 IopFreeDeviceNode(DeviceNode
);
1598 goto ReleaseCapturedString
;
1602 * Set a service name for the device node
1605 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
);
1608 * Initialize the driver module
1611 Status
= IopInitializeDriverModule(
1614 &DeviceNode
->ServiceName
,
1615 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1616 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1619 if (!NT_SUCCESS(Status
))
1621 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1622 MmUnloadSystemImage(ModuleObject
);
1623 IopFreeDeviceNode(DeviceNode
);
1624 goto ReleaseCapturedString
;
1627 IopInitializeDevice(DeviceNode
, DriverObject
);
1628 Status
= IopStartDevice(DeviceNode
);
1630 ReleaseCapturedString
:
1631 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
1640 * Unloads a legacy device driver.
1644 * Name of the service to unload (registry key).
1654 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
1656 return IopUnloadDriver(DriverServiceName
, FALSE
);