2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/driver.c
5 * PURPOSE: Driver Object Management
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Filip Navara (navaraf@reactos.org)
8 * Hervé Poussineau (hpoussin@reactos.org)
11 /* INCLUDES *******************************************************************/
17 /* GLOBALS ********************************************************************/
19 LIST_ENTRY DriverReinitListHead
;
20 KSPIN_LOCK DriverReinitListLock
;
21 PLIST_ENTRY DriverReinitTailEntry
;
23 PLIST_ENTRY DriverBootReinitTailEntry
;
24 LIST_ENTRY DriverBootReinitListHead
;
25 KSPIN_LOCK DriverBootReinitListLock
;
27 UNICODE_STRING IopHardwareDatabaseKey
=
28 RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
30 POBJECT_TYPE IoDriverObjectType
= NULL
;
32 #define TAG_RTLREGISTRY 'vrqR'
34 extern BOOLEAN ExpInTextModeSetup
;
35 extern BOOLEAN PnpSystemInit
;
37 /* PRIVATE FUNCTIONS **********************************************************/
40 IopInvalidDeviceRequest(
41 PDEVICE_OBJECT DeviceObject
,
44 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
45 Irp
->IoStatus
.Information
= 0;
46 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
47 return STATUS_INVALID_DEVICE_REQUEST
;
52 IopDeleteDriver(IN PVOID ObjectBody
)
54 PDRIVER_OBJECT DriverObject
= ObjectBody
;
55 PIO_CLIENT_EXTENSION DriverExtension
, NextDriverExtension
;
58 /* Get the extension and loop them */
59 DriverExtension
= IoGetDrvObjExtension(DriverObject
)->
60 ClientDriverExtension
;
61 while (DriverExtension
)
63 /* Get the next one */
64 NextDriverExtension
= DriverExtension
->NextExtension
;
65 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
68 DriverExtension
= NextDriverExtension
;
71 /* Check if the driver image is still loaded */
72 if (DriverObject
->DriverSection
)
75 MmUnloadSystemImage(DriverObject
->DriverSection
);
78 /* Check if it has a name */
79 if (DriverObject
->DriverName
.Buffer
)
82 ExFreePool(DriverObject
->DriverName
.Buffer
);
85 #if 0 /* See a bit of hack in IopCreateDriver */
86 /* Check if it has a service key name */
87 if (DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
)
90 ExFreePool(DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
);
97 PDRIVER_OBJECT
*DriverObject
,
98 PUNICODE_STRING ServiceName
,
101 PDRIVER_OBJECT Object
;
102 WCHAR NameBuffer
[MAX_PATH
];
103 UNICODE_STRING DriverName
;
106 DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
107 DriverObject
, ServiceName
, FileSystem
);
109 *DriverObject
= NULL
;
111 /* Create ModuleName string */
112 if (ServiceName
== NULL
|| ServiceName
->Buffer
== NULL
)
113 /* We don't know which DriverObject we have to open */
114 return STATUS_INVALID_PARAMETER_2
;
116 DriverName
.Buffer
= NameBuffer
;
117 DriverName
.Length
= 0;
118 DriverName
.MaximumLength
= sizeof(NameBuffer
);
120 if (FileSystem
== TRUE
)
121 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
123 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
124 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
126 DPRINT("Driver name: '%wZ'\n", &DriverName
);
128 /* Open driver object */
129 Status
= ObReferenceObjectByName(
131 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, /* Attributes */
132 NULL
, /* PassedAccessState */
133 0, /* DesiredAccess */
136 NULL
, /* ParseContext */
139 if (!NT_SUCCESS(Status
))
141 DPRINT("Failed to reference driver object, status=0x%08x\n", Status
);
145 *DriverObject
= Object
;
147 DPRINT("Driver Object: %p\n", Object
);
149 return STATUS_SUCCESS
;
154 * TRUE if String2 contains String1 as a suffix.
158 IopSuffixUnicodeString(
159 IN PCUNICODE_STRING String1
,
160 IN PCUNICODE_STRING String2
)
166 if (String2
->Length
< String1
->Length
)
169 Length
= String1
->Length
/ 2;
170 pc1
= String1
->Buffer
;
171 pc2
= &String2
->Buffer
[String2
->Length
/ sizeof(WCHAR
) - Length
];
177 if( *pc1
++ != *pc2
++ )
186 * IopDisplayLoadingMessage
188 * Display 'Loading XXX...' message.
194 IopDisplayLoadingMessage(PUNICODE_STRING ServiceName
)
196 CHAR TextBuffer
[256];
197 UNICODE_STRING DotSys
= RTL_CONSTANT_STRING(L
".SYS");
199 if (ExpInTextModeSetup
) return;
200 RtlUpcaseUnicodeString(ServiceName
, ServiceName
, FALSE
);
201 snprintf(TextBuffer
, sizeof(TextBuffer
),
202 "%s%sSystem32\\Drivers\\%wZ%s\n",
203 KeLoaderBlock
->ArcBootDeviceName
,
204 KeLoaderBlock
->NtBootPathName
,
206 IopSuffixUnicodeString(&DotSys
, ServiceName
) ? "" : ".SYS");
207 HalDisplayString(TextBuffer
);
211 * IopNormalizeImagePath
213 * Normalize an image path to contain complete path.
217 * The input path and on exit the result path. ImagePath.Buffer
218 * must be allocated by ExAllocatePool on input. Caller is responsible
219 * for freeing the buffer when it's no longer needed.
222 * Name of the service that ImagePath belongs to.
228 * The input image path isn't freed on error.
232 IopNormalizeImagePath(
233 IN OUT PUNICODE_STRING ImagePath
,
234 IN PUNICODE_STRING ServiceName
)
236 UNICODE_STRING InputImagePath
;
241 sizeof(UNICODE_STRING
));
243 if (InputImagePath
.Length
== 0)
245 ImagePath
->Length
= 0;
246 ImagePath
->MaximumLength
=
247 (33 * sizeof(WCHAR
)) + ServiceName
->Length
+ sizeof(UNICODE_NULL
);
248 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
249 if (ImagePath
->Buffer
== NULL
)
250 return STATUS_NO_MEMORY
;
252 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\system32\\drivers\\");
253 RtlAppendUnicodeStringToString(ImagePath
, ServiceName
);
254 RtlAppendUnicodeToString(ImagePath
, L
".sys");
256 if (InputImagePath
.Buffer
[0] != L
'\\')
258 ImagePath
->Length
= 0;
259 ImagePath
->MaximumLength
=
260 12 * sizeof(WCHAR
) + InputImagePath
.Length
+ sizeof(UNICODE_NULL
);
261 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
262 if (ImagePath
->Buffer
== NULL
)
263 return STATUS_NO_MEMORY
;
265 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\");
266 RtlAppendUnicodeStringToString(ImagePath
, &InputImagePath
);
268 /* Free caller's string */
269 ExFreePoolWithTag(InputImagePath
.Buffer
, TAG_RTLREGISTRY
);
272 return STATUS_SUCCESS
;
276 * IopLoadServiceModule
278 * Load a module specified by registry settings for service.
282 * Name of the service to load.
289 IopLoadServiceModule(
290 IN PUNICODE_STRING ServiceName
,
291 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
293 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
295 UNICODE_STRING ServiceImagePath
, CCSName
;
297 HANDLE CCSKey
, ServiceKey
;
300 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
302 /* FIXME: This check may be removed once the bug is fixed */
303 if (ServiceName
->Buffer
== NULL
)
305 DPRINT1("If you see this, please report to Fireball or hpoussin!\n");
306 return STATUS_UNSUCCESSFUL
;
309 /* Open CurrentControlSet */
310 RtlInitUnicodeString(&CCSName
,
311 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
312 Status
= IopOpenRegistryKeyEx(&CCSKey
, NULL
, &CCSName
, KEY_READ
);
313 if (!NT_SUCCESS(Status
))
315 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
319 /* Open service key */
320 Status
= IopOpenRegistryKeyEx(&ServiceKey
, CCSKey
, ServiceName
, KEY_READ
);
321 if (!NT_SUCCESS(Status
))
323 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
329 * Get information about the service.
332 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
334 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
336 QueryTable
[0].Name
= L
"Start";
337 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
338 QueryTable
[0].EntryContext
= &ServiceStart
;
340 QueryTable
[1].Name
= L
"ImagePath";
341 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
342 QueryTable
[1].EntryContext
= &ServiceImagePath
;
344 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
345 (PWSTR
)ServiceKey
, QueryTable
, NULL
, NULL
);
350 if (!NT_SUCCESS(Status
))
352 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
357 * Normalize the image path for all later processing.
360 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
362 if (!NT_SUCCESS(Status
))
364 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
369 * Case for disabled drivers
372 if (ServiceStart
>= 4)
374 /* FIXME: Check if it is the right status code */
375 Status
= STATUS_PLUGPLAY_NO_DEVICE
;
379 DPRINT("Loading module\n");
380 Status
= MmLoadSystemImage(&ServiceImagePath
, NULL
, NULL
, 0, (PVOID
)ModuleObject
, &BaseAddress
);
383 ExFreePool(ServiceImagePath
.Buffer
);
386 * Now check if the module was loaded successfully.
389 if (!NT_SUCCESS(Status
))
391 DPRINT("Module loading failed (Status %x)\n", Status
);
394 DPRINT("Module loading (Status %x)\n", Status
);
400 * IopInitializeDriverModule
402 * Initalize a loaded driver.
406 * Pointer to device node.
409 * Module object representing the driver. It can be retrieve by
410 * IopLoadServiceModule.
413 * Name of the service (as in registry).
416 * Set to TRUE for file system drivers.
419 * On successful return this contains the driver object representing
424 IopInitializeDriverModule(
425 IN PDEVICE_NODE DeviceNode
,
426 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
427 IN PUNICODE_STRING ServiceName
,
428 IN BOOLEAN FileSystemDriver
,
429 OUT PDRIVER_OBJECT
*DriverObject
)
431 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
432 WCHAR NameBuffer
[MAX_PATH
];
433 UNICODE_STRING DriverName
;
434 UNICODE_STRING RegistryKey
;
435 PDRIVER_INITIALIZE DriverEntry
;
436 PDRIVER_OBJECT Driver
;
437 PDEVICE_OBJECT DeviceObject
;
440 DriverEntry
= ModuleObject
->EntryPoint
;
442 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
444 RegistryKey
.Length
= 0;
445 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
446 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
447 if (RegistryKey
.Buffer
== NULL
)
449 return STATUS_INSUFFICIENT_RESOURCES
;
451 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
452 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
456 RtlInitUnicodeString(&RegistryKey
, NULL
);
459 /* Create ModuleName string */
460 if (ServiceName
&& ServiceName
->Length
> 0)
462 if (FileSystemDriver
== TRUE
)
463 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
465 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
467 RtlInitUnicodeString(&DriverName
, NameBuffer
);
468 DriverName
.MaximumLength
= sizeof(NameBuffer
);
470 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
472 DPRINT("Driver name: '%wZ'\n", &DriverName
);
475 DriverName
.Length
= 0;
477 Status
= IopCreateDriver(
478 DriverName
.Length
> 0 ? &DriverName
: NULL
,
481 ModuleObject
->DllBase
,
482 ModuleObject
->SizeOfImage
,
484 RtlFreeUnicodeString(&RegistryKey
);
486 *DriverObject
= Driver
;
487 if (!NT_SUCCESS(Status
))
489 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status
);
493 /* Set the driver as initialized */
494 Driver
->Flags
|= DRVO_INITIALIZED
;
495 DeviceObject
= Driver
->DeviceObject
;
498 /* Set every device as initialized too */
499 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
500 DeviceObject
= DeviceObject
->NextDevice
;
503 if (PnpSystemInit
) IopReinitializeDrivers();
505 return STATUS_SUCCESS
;
509 * IopAttachFilterDriversCallback
511 * Internal routine used by IopAttachFilterDrivers.
515 IopAttachFilterDriversCallback(
523 PDEVICE_NODE DeviceNode
= Context
;
524 UNICODE_STRING ServiceName
;
526 PLDR_DATA_TABLE_ENTRY ModuleObject
;
527 PDRIVER_OBJECT DriverObject
;
530 for (Filters
= ValueData
;
531 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
533 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
535 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
536 ServiceName
.Buffer
= Filters
;
537 ServiceName
.MaximumLength
=
538 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
540 /* Load and initialize the filter driver */
541 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
542 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
544 if (!NT_SUCCESS(Status
))
547 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
548 FALSE
, &DriverObject
);
549 if (!NT_SUCCESS(Status
))
554 /* get existing DriverObject pointer */
555 Status
= IopGetDriverObject(
559 if (!NT_SUCCESS(Status
))
561 DPRINT1("IopGetDriverObject() returned status 0x%08x!\n", Status
);
566 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
567 if (!NT_SUCCESS(Status
))
571 return STATUS_SUCCESS
;
575 * IopAttachFilterDrivers
577 * Load filter drivers for specified device node.
581 * Set to TRUE for loading lower level filters or FALSE for upper
586 IopAttachFilterDrivers(
587 PDEVICE_NODE DeviceNode
,
590 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = { { NULL
, 0, NULL
, NULL
, 0, NULL
, 0 }, };
591 UNICODE_STRING Class
;
592 WCHAR ClassBuffer
[40];
593 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
594 HANDLE EnumRootKey
, SubKey
;
597 /* Open enumeration root key */
598 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
599 &EnumRoot
, KEY_READ
);
600 if (!NT_SUCCESS(Status
))
602 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
607 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
608 &DeviceNode
->InstancePath
, KEY_READ
);
609 if (!NT_SUCCESS(Status
))
611 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
612 ZwClose(EnumRootKey
);
617 * First load the device filters
619 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
621 QueryTable
[0].Name
= L
"LowerFilters";
623 QueryTable
[0].Name
= L
"UpperFilters";
624 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
626 RtlQueryRegistryValues(
634 * Now get the class GUID
637 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
638 Class
.Buffer
= ClassBuffer
;
639 QueryTable
[0].QueryRoutine
= NULL
;
640 QueryTable
[0].Name
= L
"ClassGUID";
641 QueryTable
[0].EntryContext
= &Class
;
642 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
644 Status
= RtlQueryRegistryValues(
653 ZwClose(EnumRootKey
);
656 * Load the class filter driver
658 if (NT_SUCCESS(Status
))
660 UNICODE_STRING ControlClass
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
662 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
663 &ControlClass
, KEY_READ
);
664 if (!NT_SUCCESS(Status
))
666 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
671 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
673 if (!NT_SUCCESS(Status
))
675 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
676 ZwClose(EnumRootKey
);
680 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
682 QueryTable
[0].Name
= L
"LowerFilters";
684 QueryTable
[0].Name
= L
"UpperFilters";
685 QueryTable
[0].EntryContext
= NULL
;
686 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
688 RtlQueryRegistryValues(
697 ZwClose(EnumRootKey
);
700 return STATUS_SUCCESS
;
705 MiResolveImageReferences(IN PVOID ImageBase
,
706 IN PUNICODE_STRING ImageFileDirectory
,
707 IN PUNICODE_STRING NamePrefix OPTIONAL
,
708 OUT PCHAR
*MissingApi
,
709 OUT PWCHAR
*MissingDriver
,
710 OUT PLOAD_IMPORTS
*LoadImports
);
713 // Used for images already loaded (boot drivers)
717 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry
,
718 PUNICODE_STRING FileName
,
719 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
722 PLDR_DATA_TABLE_ENTRY NewEntry
;
723 UNICODE_STRING BaseName
, BaseDirectory
;
724 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
725 PCHAR MissingApiName
, Buffer
;
726 PWCHAR MissingDriverName
;
727 PVOID DriverBase
= LdrEntry
->DllBase
;
729 /* Allocate a buffer we'll use for names */
730 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
734 return STATUS_INSUFFICIENT_RESOURCES
;
737 /* Check for a separator */
738 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
743 /* Loop the path until we get to the base name */
744 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
745 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
748 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
749 BaseLength
*= sizeof(WCHAR
);
751 /* Setup the string */
752 BaseName
.Length
= (USHORT
)BaseLength
;
757 /* Otherwise, we already have a base name */
758 BaseName
.Length
= FileName
->Length
;
759 BaseName
.Buffer
= FileName
->Buffer
;
762 /* Setup the maximum length */
763 BaseName
.MaximumLength
= BaseName
.Length
;
765 /* Now compute the base directory */
766 BaseDirectory
= *FileName
;
767 BaseDirectory
.Length
-= BaseName
.Length
;
768 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
772 /* Resolve imports */
773 MissingApiName
= Buffer
;
774 Status
= MiResolveImageReferences(DriverBase
,
780 if (!NT_SUCCESS(Status
)) return Status
;
783 *ModuleObject
= LdrEntry
;
784 return STATUS_SUCCESS
;
788 * IopInitializeBuiltinDriver
790 * Initialize a driver that is already loaded in memory.
795 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
797 PDEVICE_NODE DeviceNode
;
798 PDRIVER_OBJECT DriverObject
;
800 PWCHAR FileNameWithoutPath
;
801 LPWSTR FileExtension
;
802 PUNICODE_STRING ModuleName
= &LdrEntry
->BaseDllName
;
803 UNICODE_STRING ServiceName
;
806 * Display 'Loading XXX...' message
808 IopDisplayLoadingMessage(ModuleName
);
809 InbvIndicateProgress();
812 * Generate filename without path (not needed by freeldr)
814 FileNameWithoutPath
= wcsrchr(ModuleName
->Buffer
, L
'\\');
815 if (FileNameWithoutPath
== NULL
)
817 FileNameWithoutPath
= ModuleName
->Buffer
;
821 FileNameWithoutPath
++;
825 * Strip the file extension from ServiceName
827 RtlCreateUnicodeString(&ServiceName
, FileNameWithoutPath
);
828 FileExtension
= wcsrchr(ServiceName
.Buffer
, '.');
829 if (FileExtension
!= NULL
)
831 ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
832 FileExtension
[0] = 0;
836 * Determine the right device object
838 /* Use IopRootDeviceNode for now */
839 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
840 if (!NT_SUCCESS(Status
))
842 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
845 DeviceNode
->ServiceName
= ServiceName
;
848 * Initialize the driver
850 Status
= IopInitializeDriverModule(DeviceNode
, LdrEntry
,
851 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
853 if (!NT_SUCCESS(Status
))
855 IopFreeDeviceNode(DeviceNode
);
859 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
860 if (NT_SUCCESS(Status
))
862 Status
= IopStartDevice(DeviceNode
);
869 * IopInitializeBootDrivers
871 * Initialize boot drivers and free memory for boot files.
881 IopInitializeBootDrivers(VOID
)
883 PLIST_ENTRY ListHead
, NextEntry
;
884 PLDR_DATA_TABLE_ENTRY LdrEntry
;
885 PDEVICE_NODE DeviceNode
;
886 PDRIVER_OBJECT DriverObject
;
887 LDR_DATA_TABLE_ENTRY ModuleObject
;
889 UNICODE_STRING DriverName
;
891 DPRINT("IopInitializeBootDrivers()\n");
893 /* Use IopRootDeviceNode for now */
894 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, NULL
, &DeviceNode
);
895 if (!NT_SUCCESS(Status
)) return;
897 /* Setup the module object for the RAW FS Driver */
898 ModuleObject
.DllBase
= NULL
;
899 ModuleObject
.SizeOfImage
= 0;
900 ModuleObject
.EntryPoint
= RawFsDriverEntry
;
901 RtlInitUnicodeString(&DriverName
, L
"RAW");
904 Status
= IopInitializeDriverModule(DeviceNode
,
909 if (!NT_SUCCESS(Status
))
912 IopFreeDeviceNode(DeviceNode
);
916 /* Now initialize the associated device */
917 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
918 if (!NT_SUCCESS(Status
))
921 IopFreeDeviceNode(DeviceNode
);
926 Status
= IopStartDevice(DeviceNode
);
927 if (!NT_SUCCESS(Status
))
930 IopFreeDeviceNode(DeviceNode
);
934 /* Loop the boot modules */
935 ListHead
= &KeLoaderBlock
->LoadOrderListHead
;
936 NextEntry
= ListHead
->Flink
;
937 while (ListHead
!= NextEntry
)
940 LdrEntry
= CONTAINING_RECORD(NextEntry
,
941 LDR_DATA_TABLE_ENTRY
,
945 * HACK: Make sure we're loading a driver
946 * (we should be using BootDriverListHead!)
948 if (wcsstr(_wcsupr(LdrEntry
->BaseDllName
.Buffer
), L
".SYS"))
950 /* Make sure we didn't load this driver already */
951 if (!(LdrEntry
->Flags
& LDRP_ENTRY_INSERTED
))
953 DPRINT("Initializing bootdriver %wZ\n", &LdrEntry
->BaseDllName
);
955 IopInitializeBuiltinDriver(LdrEntry
);
959 /* Go to the next driver */
960 NextEntry
= NextEntry
->Flink
;
963 /* In old ROS, the loader list became empty after this point. Simulate. */
964 InitializeListHead(&KeLoaderBlock
->LoadOrderListHead
);
970 * Unloads a device driver.
974 * Name of the service to unload (registry key).
977 * Whether to unload Plug & Plug or only legacy drivers. If this
978 * parameter is set to FALSE, the routine will unload only legacy
985 * Guard the whole function by SEH.
989 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
991 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
992 UNICODE_STRING ImagePath
;
993 UNICODE_STRING ServiceName
;
994 UNICODE_STRING ObjectName
;
995 PDRIVER_OBJECT DriverObject
;
996 PDEVICE_OBJECT DeviceObject
;
997 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
998 LOAD_UNLOAD_PARAMS LoadParams
;
1001 BOOLEAN SafeToUnload
= TRUE
;
1003 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1008 * Get the service name from the registry key name
1011 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1013 Start
= DriverServiceName
->Buffer
;
1017 RtlInitUnicodeString(&ServiceName
, Start
);
1020 * Construct the driver object name
1023 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1024 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1025 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1026 if (!ObjectName
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1027 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1028 memcpy(ObjectName
.Buffer
+ 8, Start
, ObjectName
.Length
- 8 * sizeof(WCHAR
));
1029 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1032 * Find the driver object
1034 Status
= ObReferenceObjectByName(&ObjectName
,
1041 (PVOID
*)&DriverObject
);
1044 * Free the buffer for driver object name
1046 ExFreePool(ObjectName
.Buffer
);
1048 if (!NT_SUCCESS(Status
))
1050 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName
);
1054 /* Check that driver is not already unloading */
1055 if (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
)
1057 DPRINT1("Driver deletion pending\n");
1058 ObDereferenceObject(DriverObject
);
1059 return STATUS_DELETE_PENDING
;
1063 * Get path of service...
1066 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1068 RtlInitUnicodeString(&ImagePath
, NULL
);
1070 QueryTable
[0].Name
= L
"ImagePath";
1071 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1072 QueryTable
[0].EntryContext
= &ImagePath
;
1074 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1075 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1077 if (!NT_SUCCESS(Status
))
1079 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1080 ObDereferenceObject(DriverObject
);
1085 * Normalize the image path for all later processing.
1088 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1090 if (!NT_SUCCESS(Status
))
1092 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1093 ObDereferenceObject(DriverObject
);
1098 * Free the service path
1101 ExFreePool(ImagePath
.Buffer
);
1104 * Unload the module and release the references to the device object
1107 /* Call the load/unload routine, depending on current process */
1108 if (DriverObject
->DriverUnload
&& DriverObject
->DriverSection
)
1110 /* Loop through each device object of the driver
1111 and set DOE_UNLOAD_PENDING flag */
1112 DeviceObject
= DriverObject
->DeviceObject
;
1113 while (DeviceObject
)
1115 /* Set the unload pending flag for the device */
1116 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1117 DeviceExtension
->ExtensionFlags
|= DOE_UNLOAD_PENDING
;
1119 /* Make sure there are no attached devices or no reference counts */
1120 if ((DeviceObject
->ReferenceCount
) || (DeviceObject
->AttachedDevice
))
1122 /* Not safe to unload */
1123 DPRINT1("Drivers device object is referenced or has attached devices\n");
1125 SafeToUnload
= FALSE
;
1128 DeviceObject
= DeviceObject
->NextDevice
;
1131 /* If not safe to unload, then return success */
1134 ObDereferenceObject(DriverObject
);
1135 return STATUS_SUCCESS
;
1138 /* Set the unload invoked flag */
1139 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
1141 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1143 /* Just call right away */
1144 (*DriverObject
->DriverUnload
)(DriverObject
);
1148 /* Load/Unload must be called from system process */
1150 /* Prepare parameters block */
1151 LoadParams
.DriverObject
= DriverObject
;
1152 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1154 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1155 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1156 (PVOID
)&LoadParams
);
1159 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1161 /* And wait when it completes */
1162 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1166 /* Mark the driver object temporary, so it could be deleted later */
1167 ObMakeTemporaryObject(DriverObject
);
1169 /* Dereference it 2 times */
1170 ObDereferenceObject(DriverObject
);
1171 ObDereferenceObject(DriverObject
);
1173 return STATUS_SUCCESS
;
1177 /* Dereference one time (refd inside this function) */
1178 ObDereferenceObject(DriverObject
);
1180 /* Return unloading failure */
1181 return STATUS_INVALID_DEVICE_REQUEST
;
1187 IopReinitializeDrivers(VOID
)
1189 PDRIVER_REINIT_ITEM ReinitItem
;
1192 /* Get the first entry and start looping */
1193 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1194 &DriverReinitListLock
);
1198 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1200 /* Increment reinitialization counter */
1201 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1203 /* Remove the device object flag */
1204 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1206 /* Call the routine */
1207 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1208 ReinitItem
->Context
,
1209 ReinitItem
->DriverObject
->
1210 DriverExtension
->Count
);
1212 /* Free the entry */
1215 /* Move to the next one */
1216 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1217 &DriverReinitListLock
);
1223 IopReinitializeBootDrivers(VOID
)
1225 PDRIVER_REINIT_ITEM ReinitItem
;
1228 /* Get the first entry and start looping */
1229 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1230 &DriverBootReinitListLock
);
1234 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1236 /* Increment reinitialization counter */
1237 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1239 /* Remove the device object flag */
1240 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1242 /* Call the routine */
1243 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1244 ReinitItem
->Context
,
1245 ReinitItem
->DriverObject
->
1246 DriverExtension
->Count
);
1248 /* Free the entry */
1251 /* Move to the next one */
1252 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1253 &DriverBootReinitListLock
);
1259 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1260 IN PDRIVER_INITIALIZE InitializationFunction
,
1261 IN PUNICODE_STRING RegistryPath
,
1263 IN ULONG SizeOfImage
,
1264 OUT PDRIVER_OBJECT
*pDriverObject
)
1266 WCHAR NameBuffer
[100];
1268 UNICODE_STRING LocalDriverName
;
1270 OBJECT_ATTRIBUTES ObjectAttributes
;
1272 PDRIVER_OBJECT DriverObject
;
1273 UNICODE_STRING ServiceKeyName
;
1275 ULONG i
, RetryCount
= 0;
1278 /* First, create a unique name for the driver if we don't have one */
1281 /* Create a random name and set up the string*/
1282 NameLength
= (USHORT
)swprintf(NameBuffer
,
1285 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1286 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1287 LocalDriverName
.Buffer
= NameBuffer
;
1291 /* So we can avoid another code path, use a local var */
1292 LocalDriverName
= *DriverName
;
1295 /* Initialize the Attributes */
1296 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1297 InitializeObjectAttributes(&ObjectAttributes
,
1299 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1303 /* Create the Object */
1304 Status
= ObCreateObject(KernelMode
,
1312 (PVOID
*)&DriverObject
);
1313 if (!NT_SUCCESS(Status
)) return Status
;
1315 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1317 /* Set up the Object */
1318 RtlZeroMemory(DriverObject
, ObjectSize
);
1319 DriverObject
->Type
= IO_TYPE_DRIVER
;
1320 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1321 DriverObject
->Flags
= DRVO_LEGACY_DRIVER
;//DRVO_BUILTIN_DRIVER;
1322 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1323 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1324 DriverObject
->DriverInit
= InitializationFunction
;
1326 /* Loop all Major Functions */
1327 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1329 /* Invalidate each function */
1330 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1333 /* Set up the service key name buffer */
1334 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1335 LocalDriverName
.Length
+
1338 if (!ServiceKeyName
.Buffer
)
1341 ObMakeTemporaryObject(DriverObject
);
1342 ObDereferenceObject(DriverObject
);
1343 return STATUS_INSUFFICIENT_RESOURCES
;
1346 /* Fill out the key data and copy the buffer */
1347 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1348 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1349 RtlCopyMemory(ServiceKeyName
.Buffer
,
1350 LocalDriverName
.Buffer
,
1351 LocalDriverName
.Length
);
1353 /* Null-terminate it and set it */
1354 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1355 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1357 /* Also store it in the Driver Object. This is a bit of a hack. */
1358 RtlCopyMemory(&DriverObject
->DriverName
,
1360 sizeof(UNICODE_STRING
));
1362 /* Add the Object and get its handle */
1363 Status
= ObInsertObject(DriverObject
,
1370 /* Eliminate small possibility when this function is called more than
1371 once in a row, and KeTickCount doesn't get enough time to change */
1372 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1378 if (!NT_SUCCESS(Status
)) return Status
;
1380 /* Now reference it */
1381 Status
= ObReferenceObjectByHandle(hDriver
,
1385 (PVOID
*)&DriverObject
,
1387 if (!NT_SUCCESS(Status
))
1390 ObMakeTemporaryObject(DriverObject
);
1391 ObDereferenceObject(DriverObject
);
1395 /* Close the extra handle */
1398 DriverObject
->HardwareDatabase
= &IopHardwareDatabaseKey
;
1399 DriverObject
->DriverStart
= DllBase
;
1400 DriverObject
->DriverSize
= SizeOfImage
;
1402 /* Finally, call its init function */
1403 DPRINT("RegistryKey: %wZ\n", RegistryPath
);
1404 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction
);
1405 Status
= (*InitializationFunction
)(DriverObject
, RegistryPath
);
1406 if (!NT_SUCCESS(Status
))
1408 /* If it didn't work, then kill the object */
1409 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName
, Status
);
1410 ObMakeTemporaryObject(DriverObject
);
1411 ObDereferenceObject(DriverObject
);
1415 /* Returns to caller the object */
1416 *pDriverObject
= DriverObject
;
1419 /* Loop all Major Functions */
1420 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1423 * Make sure the driver didn't set any dispatch entry point to NULL!
1424 * Doing so is illegal; drivers shouldn't touch entry points they
1427 ASSERT(DriverObject
->MajorFunction
[i
] != NULL
);
1429 /* Check if it did so anyway */
1430 if (!DriverObject
->MajorFunction
[i
])
1433 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1437 /* Return the Status */
1441 /* PUBLIC FUNCTIONS ***********************************************************/
1448 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1449 IN PDRIVER_INITIALIZE InitializationFunction
)
1451 PDRIVER_OBJECT DriverObject
;
1452 return IopCreateDriver(DriverName
, InitializationFunction
, NULL
, 0, 0, &DriverObject
);
1460 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1462 /* Simply dereference the Object */
1463 ObDereferenceObject(DriverObject
);
1471 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1472 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1475 PDRIVER_REINIT_ITEM ReinitItem
;
1477 /* Allocate the entry */
1478 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1479 sizeof(DRIVER_REINIT_ITEM
),
1481 if (!ReinitItem
) return;
1484 ReinitItem
->DriverObject
= DriverObject
;
1485 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1486 ReinitItem
->Context
= Context
;
1488 /* Set the Driver Object flag and insert the entry into the list */
1489 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1490 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1491 &ReinitItem
->ItemEntry
,
1492 &DriverBootReinitListLock
);
1500 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1501 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1504 PDRIVER_REINIT_ITEM ReinitItem
;
1506 /* Allocate the entry */
1507 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1508 sizeof(DRIVER_REINIT_ITEM
),
1510 if (!ReinitItem
) return;
1513 ReinitItem
->DriverObject
= DriverObject
;
1514 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1515 ReinitItem
->Context
= Context
;
1517 /* Set the Driver Object flag and insert the entry into the list */
1518 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1519 ExInterlockedInsertTailList(&DriverReinitListHead
,
1520 &ReinitItem
->ItemEntry
,
1521 &DriverReinitListLock
);
1529 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1530 IN PVOID ClientIdentificationAddress
,
1531 IN ULONG DriverObjectExtensionSize
,
1532 OUT PVOID
*DriverObjectExtension
)
1535 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1536 BOOLEAN Inserted
= FALSE
;
1538 /* Assume failure */
1539 *DriverObjectExtension
= NULL
;
1541 /* Allocate the extension */
1542 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1543 sizeof(IO_CLIENT_EXTENSION
) +
1544 DriverObjectExtensionSize
,
1545 TAG_DRIVER_EXTENSION
);
1546 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1548 /* Clear the extension for teh caller */
1549 RtlZeroMemory(NewDriverExtension
,
1550 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1553 OldIrql
= KeRaiseIrqlToDpcLevel();
1555 /* Fill out the extension */
1556 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1558 /* Loop the current extensions */
1559 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1560 ClientDriverExtension
;
1561 while (DriverExtensions
)
1563 /* Check if the identifier matches */
1564 if (DriverExtensions
->ClientIdentificationAddress
==
1565 ClientIdentificationAddress
)
1567 /* We have a collision, break out */
1571 /* Go to the next one */
1572 DriverExtensions
= DriverExtensions
->NextExtension
;
1575 /* Check if we didn't collide */
1576 if (!DriverExtensions
)
1578 /* Link this one in */
1579 NewDriverExtension
->NextExtension
=
1580 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1581 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1586 /* Release the lock */
1587 KeLowerIrql(OldIrql
);
1589 /* Check if insertion failed */
1592 /* Free the entry and fail */
1593 ExFreePool(NewDriverExtension
);
1594 return STATUS_OBJECT_NAME_COLLISION
;
1597 /* Otherwise, return the pointer */
1598 *DriverObjectExtension
= NewDriverExtension
+ 1;
1599 return STATUS_SUCCESS
;
1607 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1608 IN PVOID ClientIdentificationAddress
)
1611 PIO_CLIENT_EXTENSION DriverExtensions
;
1614 OldIrql
= KeRaiseIrqlToDpcLevel();
1616 /* Loop the list until we find the right one */
1617 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1618 while (DriverExtensions
)
1620 /* Check for a match */
1621 if (DriverExtensions
->ClientIdentificationAddress
==
1622 ClientIdentificationAddress
)
1629 DriverExtensions
= DriverExtensions
->NextExtension
;
1633 KeLowerIrql(OldIrql
);
1635 /* Return nothing or the extension */
1636 if (!DriverExtensions
) return NULL
;
1637 return DriverExtensions
+ 1;
1641 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams
)
1643 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1644 UNICODE_STRING ImagePath
;
1645 UNICODE_STRING ServiceName
;
1648 PDEVICE_NODE DeviceNode
;
1649 PDRIVER_OBJECT DriverObject
;
1650 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1654 /* Check if it's an unload request */
1655 if (LoadParams
->DriverObject
)
1657 (*LoadParams
->DriverObject
->DriverUnload
)(LoadParams
->DriverObject
);
1659 /* Return success and signal the event */
1660 LoadParams
->Status
= STATUS_SUCCESS
;
1661 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1665 RtlInitUnicodeString(&ImagePath
, NULL
);
1668 * Get the service name from the registry key name.
1670 ASSERT(LoadParams
->ServiceName
->Length
>= sizeof(WCHAR
));
1672 ServiceName
= *LoadParams
->ServiceName
;
1673 cur
= LoadParams
->ServiceName
->Buffer
+
1674 (LoadParams
->ServiceName
->Length
/ sizeof(WCHAR
)) - 1;
1675 while (LoadParams
->ServiceName
->Buffer
!= cur
)
1679 ServiceName
.Buffer
= cur
+ 1;
1680 ServiceName
.Length
= LoadParams
->ServiceName
->Length
-
1681 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1682 (ULONG_PTR
)LoadParams
->ServiceName
->Buffer
);
1692 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1694 RtlInitUnicodeString(&ImagePath
, NULL
);
1696 QueryTable
[0].Name
= L
"Type";
1697 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1698 QueryTable
[0].EntryContext
= &Type
;
1700 QueryTable
[1].Name
= L
"ImagePath";
1701 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1702 QueryTable
[1].EntryContext
= &ImagePath
;
1704 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1705 LoadParams
->ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1707 if (!NT_SUCCESS(Status
))
1709 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1710 if (ImagePath
.Buffer
)
1711 ExFreePool(ImagePath
.Buffer
);
1712 LoadParams
->Status
= Status
;
1713 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1718 * Normalize the image path for all later processing.
1721 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1723 if (!NT_SUCCESS(Status
))
1725 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1726 LoadParams
->Status
= Status
;
1727 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1731 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1732 DPRINT("Type: %lx\n", Type
);
1735 * Create device node
1738 /* Use IopRootDeviceNode for now */
1739 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1741 if (!NT_SUCCESS(Status
))
1743 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1744 LoadParams
->Status
= Status
;
1745 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1749 /* Get existing DriverObject pointer (in case the driver has
1750 already been loaded and initialized) */
1751 Status
= IopGetDriverObject(
1754 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1755 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */));
1757 if (!NT_SUCCESS(Status
))
1760 * Load the driver module
1763 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, &BaseAddress
);
1764 if (!NT_SUCCESS(Status
) && Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1766 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1767 IopFreeDeviceNode(DeviceNode
);
1768 LoadParams
->Status
= Status
;
1769 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1774 * Set a service name for the device node
1777 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
);
1780 * Initialize the driver module if it's loaded for the first time
1782 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1784 Status
= IopInitializeDriverModule(
1787 &DeviceNode
->ServiceName
,
1788 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1789 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1792 if (!NT_SUCCESS(Status
))
1794 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1795 MmUnloadSystemImage(ModuleObject
);
1796 IopFreeDeviceNode(DeviceNode
);
1797 LoadParams
->Status
= Status
;
1798 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1803 /* Store its DriverSection, so that it could be unloaded */
1804 DriverObject
->DriverSection
= ModuleObject
;
1806 /* Initialize and start device */
1807 IopInitializeDevice(DeviceNode
, DriverObject
);
1808 Status
= IopStartDevice(DeviceNode
);
1812 DPRINT("DriverObject already exist in ObjectManager\n");
1814 /* IopGetDriverObject references the DriverObject, so dereference it */
1815 ObDereferenceObject(DriverObject
);
1817 /* Free device node since driver loading failed */
1818 IopFreeDeviceNode(DeviceNode
);
1821 /* Pass status to the caller and signal the event */
1822 LoadParams
->Status
= Status
;
1823 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1829 * Loads a device driver.
1833 * Name of the service to load (registry key).
1842 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1844 UNICODE_STRING CapturedDriverServiceName
= { 0, 0, NULL
};
1845 KPROCESSOR_MODE PreviousMode
;
1846 LOAD_UNLOAD_PARAMS LoadParams
;
1851 PreviousMode
= KeGetPreviousMode();
1854 * Check security privileges
1857 /* FIXME: Uncomment when privileges will be correctly implemented. */
1859 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1861 DPRINT("Privilege not held\n");
1862 return STATUS_PRIVILEGE_NOT_HELD
;
1866 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
1869 if (!NT_SUCCESS(Status
))
1874 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1876 LoadParams
.ServiceName
= &CapturedDriverServiceName
;
1877 LoadParams
.DriverObject
= NULL
;
1878 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1880 /* Call the load/unload routine, depending on current process */
1881 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1883 /* Just call right away */
1884 IopLoadUnloadDriver(&LoadParams
);
1888 /* Load/Unload must be called from system process */
1889 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1890 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1891 (PVOID
)&LoadParams
);
1894 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1896 /* And wait when it completes */
1897 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1901 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
1904 return LoadParams
.Status
;
1910 * Unloads a legacy device driver.
1914 * Name of the service to unload (registry key).
1924 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
1926 return IopUnloadDriver(DriverServiceName
, FALSE
);