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
;
153 * IopDisplayLoadingMessage
155 * Display 'Loading XXX...' message.
161 IopDisplayLoadingMessage(PVOID ServiceName
,
164 CHAR TextBuffer
[256];
165 PCHAR Extra
= ".sys";
167 if (ExpInTextModeSetup
) return;
170 if (wcsstr(_wcsupr(ServiceName
), L
".SYS")) Extra
= "";
173 KeLoaderBlock
->ArcBootDeviceName
,
174 KeLoaderBlock
->NtBootPathName
,
181 if (strstr(_strupr(ServiceName
), ".SYS")) Extra
= "";
184 KeLoaderBlock
->ArcBootDeviceName
,
185 KeLoaderBlock
->NtBootPathName
,
190 HalDisplayString(TextBuffer
);
194 * IopNormalizeImagePath
196 * Normalize an image path to contain complete path.
200 * The input path and on exit the result path. ImagePath.Buffer
201 * must be allocated by ExAllocatePool on input. Caller is responsible
202 * for freeing the buffer when it's no longer needed.
205 * Name of the service that ImagePath belongs to.
211 * The input image path isn't freed on error.
215 IopNormalizeImagePath(
216 IN OUT PUNICODE_STRING ImagePath
,
217 IN PUNICODE_STRING ServiceName
)
219 UNICODE_STRING InputImagePath
;
224 sizeof(UNICODE_STRING
));
226 if (InputImagePath
.Length
== 0)
228 ImagePath
->Length
= 0;
229 ImagePath
->MaximumLength
=
230 (33 * sizeof(WCHAR
)) + ServiceName
->Length
+ sizeof(UNICODE_NULL
);
231 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
232 if (ImagePath
->Buffer
== NULL
)
233 return STATUS_NO_MEMORY
;
235 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\system32\\drivers\\");
236 RtlAppendUnicodeStringToString(ImagePath
, ServiceName
);
237 RtlAppendUnicodeToString(ImagePath
, L
".sys");
239 if (InputImagePath
.Buffer
[0] != L
'\\')
241 ImagePath
->Length
= 0;
242 ImagePath
->MaximumLength
=
243 12 * sizeof(WCHAR
) + InputImagePath
.Length
+ sizeof(UNICODE_NULL
);
244 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
245 if (ImagePath
->Buffer
== NULL
)
246 return STATUS_NO_MEMORY
;
248 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\");
249 RtlAppendUnicodeStringToString(ImagePath
, &InputImagePath
);
251 /* Free caller's string */
252 ExFreePoolWithTag(InputImagePath
.Buffer
, TAG_RTLREGISTRY
);
255 return STATUS_SUCCESS
;
259 * IopLoadServiceModule
261 * Load a module specified by registry settings for service.
265 * Name of the service to load.
272 IopLoadServiceModule(
273 IN PUNICODE_STRING ServiceName
,
274 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
276 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
278 UNICODE_STRING ServiceImagePath
, CCSName
;
280 HANDLE CCSKey
, ServiceKey
;
283 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
285 /* FIXME: This check may be removed once the bug is fixed */
286 if (ServiceName
->Buffer
== NULL
)
288 DPRINT1("If you see this, please report to Fireball or hpoussin!\n");
289 return STATUS_UNSUCCESSFUL
;
292 /* Open CurrentControlSet */
293 RtlInitUnicodeString(&CCSName
,
294 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
295 Status
= IopOpenRegistryKeyEx(&CCSKey
, NULL
, &CCSName
, KEY_READ
);
296 if (!NT_SUCCESS(Status
))
298 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
302 /* Open service key */
303 Status
= IopOpenRegistryKeyEx(&ServiceKey
, CCSKey
, ServiceName
, KEY_READ
);
304 if (!NT_SUCCESS(Status
))
306 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
312 * Get information about the service.
315 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
317 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
319 QueryTable
[0].Name
= L
"Start";
320 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
321 QueryTable
[0].EntryContext
= &ServiceStart
;
323 QueryTable
[1].Name
= L
"ImagePath";
324 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
325 QueryTable
[1].EntryContext
= &ServiceImagePath
;
327 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
328 (PWSTR
)ServiceKey
, QueryTable
, NULL
, NULL
);
333 if (!NT_SUCCESS(Status
))
335 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
340 * Normalize the image path for all later processing.
343 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
345 if (!NT_SUCCESS(Status
))
347 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
352 * Case for disabled drivers
355 if (ServiceStart
>= 4)
357 /* FIXME: Check if it is the right status code */
358 Status
= STATUS_PLUGPLAY_NO_DEVICE
;
362 DPRINT("Loading module\n");
363 Status
= MmLoadSystemImage(&ServiceImagePath
, NULL
, NULL
, 0, (PVOID
)ModuleObject
, &BaseAddress
);
366 ExFreePool(ServiceImagePath
.Buffer
);
369 * Now check if the module was loaded successfully.
372 if (!NT_SUCCESS(Status
))
374 DPRINT("Module loading failed (Status %x)\n", Status
);
377 DPRINT("Module loading (Status %x)\n", Status
);
383 * IopInitializeDriverModule
385 * Initalize a loaded driver.
389 * Pointer to device node.
392 * Module object representing the driver. It can be retrieve by
393 * IopLoadServiceModule.
396 * Name of the service (as in registry).
399 * Set to TRUE for file system drivers.
402 * On successful return this contains the driver object representing
407 IopInitializeDriverModule(
408 IN PDEVICE_NODE DeviceNode
,
409 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
410 IN PUNICODE_STRING ServiceName
,
411 IN BOOLEAN FileSystemDriver
,
412 OUT PDRIVER_OBJECT
*DriverObject
)
414 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
415 WCHAR NameBuffer
[MAX_PATH
];
416 UNICODE_STRING DriverName
;
417 UNICODE_STRING RegistryKey
;
418 PDRIVER_INITIALIZE DriverEntry
;
419 PDRIVER_OBJECT Driver
;
420 PDEVICE_OBJECT DeviceObject
;
423 DriverEntry
= ModuleObject
->EntryPoint
;
425 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
427 RegistryKey
.Length
= 0;
428 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
429 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
430 if (RegistryKey
.Buffer
== NULL
)
432 return STATUS_INSUFFICIENT_RESOURCES
;
434 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
435 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
439 RtlInitUnicodeString(&RegistryKey
, NULL
);
442 /* Create ModuleName string */
443 if (ServiceName
&& ServiceName
->Length
> 0)
445 if (FileSystemDriver
== TRUE
)
446 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
448 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
450 RtlInitUnicodeString(&DriverName
, NameBuffer
);
451 DriverName
.MaximumLength
= sizeof(NameBuffer
);
453 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
455 DPRINT("Driver name: '%wZ'\n", &DriverName
);
458 DriverName
.Length
= 0;
460 Status
= IopCreateDriver(
461 DriverName
.Length
> 0 ? &DriverName
: NULL
,
464 ModuleObject
->DllBase
,
465 ModuleObject
->SizeOfImage
,
467 RtlFreeUnicodeString(&RegistryKey
);
469 *DriverObject
= Driver
;
470 if (!NT_SUCCESS(Status
))
472 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status
);
476 /* Set the driver as initialized */
477 Driver
->Flags
|= DRVO_INITIALIZED
;
478 DeviceObject
= Driver
->DeviceObject
;
481 /* Set every device as initialized too */
482 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
483 DeviceObject
= DeviceObject
->NextDevice
;
486 if (PnpSystemInit
) IopReinitializeDrivers();
488 return STATUS_SUCCESS
;
492 * IopAttachFilterDriversCallback
494 * Internal routine used by IopAttachFilterDrivers.
498 IopAttachFilterDriversCallback(
506 PDEVICE_NODE DeviceNode
= Context
;
507 UNICODE_STRING ServiceName
;
509 PLDR_DATA_TABLE_ENTRY ModuleObject
;
510 PDRIVER_OBJECT DriverObject
;
513 for (Filters
= ValueData
;
514 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
516 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
518 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
519 ServiceName
.Buffer
= Filters
;
520 ServiceName
.MaximumLength
=
521 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
523 /* Load and initialize the filter driver */
524 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
525 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
527 if (!NT_SUCCESS(Status
))
530 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
531 FALSE
, &DriverObject
);
532 if (!NT_SUCCESS(Status
))
537 /* get existing DriverObject pointer */
538 Status
= IopGetDriverObject(
542 if (!NT_SUCCESS(Status
))
544 DPRINT1("IopGetDriverObject() returned status 0x%08x!\n", Status
);
549 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
550 if (!NT_SUCCESS(Status
))
554 return STATUS_SUCCESS
;
558 * IopAttachFilterDrivers
560 * Load filter drivers for specified device node.
564 * Set to TRUE for loading lower level filters or FALSE for upper
569 IopAttachFilterDrivers(
570 PDEVICE_NODE DeviceNode
,
573 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = { { NULL
, 0, NULL
, NULL
, 0, NULL
, 0 }, };
574 UNICODE_STRING Class
;
575 WCHAR ClassBuffer
[40];
576 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
577 HANDLE EnumRootKey
, SubKey
;
580 /* Open enumeration root key */
581 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
582 &EnumRoot
, KEY_READ
);
583 if (!NT_SUCCESS(Status
))
585 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
590 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
591 &DeviceNode
->InstancePath
, KEY_READ
);
592 if (!NT_SUCCESS(Status
))
594 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
595 ZwClose(EnumRootKey
);
600 * First load the device filters
602 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
604 QueryTable
[0].Name
= L
"LowerFilters";
606 QueryTable
[0].Name
= L
"UpperFilters";
607 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
609 RtlQueryRegistryValues(
617 * Now get the class GUID
620 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
621 Class
.Buffer
= ClassBuffer
;
622 QueryTable
[0].QueryRoutine
= NULL
;
623 QueryTable
[0].Name
= L
"ClassGUID";
624 QueryTable
[0].EntryContext
= &Class
;
625 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
627 Status
= RtlQueryRegistryValues(
636 ZwClose(EnumRootKey
);
639 * Load the class filter driver
641 if (NT_SUCCESS(Status
))
643 UNICODE_STRING ControlClass
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
645 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
646 &ControlClass
, KEY_READ
);
647 if (!NT_SUCCESS(Status
))
649 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
654 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
656 if (!NT_SUCCESS(Status
))
658 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
659 ZwClose(EnumRootKey
);
663 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
665 QueryTable
[0].Name
= L
"LowerFilters";
667 QueryTable
[0].Name
= L
"UpperFilters";
668 QueryTable
[0].EntryContext
= NULL
;
669 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
671 RtlQueryRegistryValues(
680 ZwClose(EnumRootKey
);
683 return STATUS_SUCCESS
;
688 MiResolveImageReferences(IN PVOID ImageBase
,
689 IN PUNICODE_STRING ImageFileDirectory
,
690 IN PUNICODE_STRING NamePrefix OPTIONAL
,
691 OUT PCHAR
*MissingApi
,
692 OUT PWCHAR
*MissingDriver
,
693 OUT PLOAD_IMPORTS
*LoadImports
);
695 extern KSPIN_LOCK PsLoadedModuleSpinLock
;
698 // Used for images already loaded (boot drivers)
702 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry
,
703 PUNICODE_STRING FileName
,
704 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
707 PLDR_DATA_TABLE_ENTRY NewEntry
;
708 UNICODE_STRING BaseName
, BaseDirectory
;
709 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
710 PCHAR MissingApiName
, Buffer
;
711 PWCHAR MissingDriverName
;
712 PVOID DriverBase
= LdrEntry
->DllBase
;
714 /* Allocate a buffer we'll use for names */
715 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
719 return STATUS_INSUFFICIENT_RESOURCES
;
722 /* Check for a separator */
723 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
728 /* Loop the path until we get to the base name */
729 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
730 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
733 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
734 BaseLength
*= sizeof(WCHAR
);
736 /* Setup the string */
737 BaseName
.Length
= (USHORT
)BaseLength
;
742 /* Otherwise, we already have a base name */
743 BaseName
.Length
= FileName
->Length
;
744 BaseName
.Buffer
= FileName
->Buffer
;
747 /* Setup the maximum length */
748 BaseName
.MaximumLength
= BaseName
.Length
;
750 /* Now compute the base directory */
751 BaseDirectory
= *FileName
;
752 BaseDirectory
.Length
-= BaseName
.Length
;
753 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
757 /* Resolve imports */
758 MissingApiName
= Buffer
;
759 Status
= MiResolveImageReferences(DriverBase
,
765 if (!NT_SUCCESS(Status
)) return Status
;
768 *ModuleObject
= LdrEntry
;
769 return STATUS_SUCCESS
;
773 * IopInitializeBuiltinDriver
775 * Initialize a driver that is already loaded in memory.
780 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
782 PDEVICE_NODE DeviceNode
;
783 PDRIVER_OBJECT DriverObject
;
785 PWCHAR FileNameWithoutPath
;
786 LPWSTR FileExtension
;
787 PUNICODE_STRING ModuleName
= &LdrEntry
->BaseDllName
;
788 UNICODE_STRING ServiceName
;
791 * Display 'Loading XXX...' message
793 IopDisplayLoadingMessage(ModuleName
->Buffer
, TRUE
);
796 * Generate filename without path (not needed by freeldr)
798 FileNameWithoutPath
= wcsrchr(ModuleName
->Buffer
, L
'\\');
799 if (FileNameWithoutPath
== NULL
)
801 FileNameWithoutPath
= ModuleName
->Buffer
;
805 FileNameWithoutPath
++;
809 * Strip the file extension from ServiceName
811 RtlCreateUnicodeString(&ServiceName
, FileNameWithoutPath
);
812 FileExtension
= wcsrchr(ServiceName
.Buffer
, '.');
813 if (FileExtension
!= NULL
)
815 ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
816 FileExtension
[0] = 0;
820 * Determine the right device object
822 /* Use IopRootDeviceNode for now */
823 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
824 if (!NT_SUCCESS(Status
))
826 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
829 DeviceNode
->ServiceName
= ServiceName
;
832 * Initialize the driver
834 Status
= IopInitializeDriverModule(DeviceNode
, LdrEntry
,
835 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
837 if (!NT_SUCCESS(Status
))
839 IopFreeDeviceNode(DeviceNode
);
843 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
844 if (NT_SUCCESS(Status
))
846 Status
= IopStartDevice(DeviceNode
);
853 * IopInitializeBootDrivers
855 * Initialize boot drivers and free memory for boot files.
865 IopInitializeBootDrivers(VOID
)
867 PLIST_ENTRY ListHead
, NextEntry
;
868 PLDR_DATA_TABLE_ENTRY LdrEntry
;
869 PDEVICE_NODE DeviceNode
;
870 PDRIVER_OBJECT DriverObject
;
871 LDR_DATA_TABLE_ENTRY ModuleObject
;
873 UNICODE_STRING DriverName
;
875 DPRINT("IopInitializeBootDrivers()\n");
877 /* Use IopRootDeviceNode for now */
878 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, NULL
, &DeviceNode
);
879 if (!NT_SUCCESS(Status
)) return;
881 /* Setup the module object for the RAW FS Driver */
882 ModuleObject
.DllBase
= NULL
;
883 ModuleObject
.SizeOfImage
= 0;
884 ModuleObject
.EntryPoint
= RawFsDriverEntry
;
885 RtlInitUnicodeString(&DriverName
, L
"RAW");
888 Status
= IopInitializeDriverModule(DeviceNode
,
893 if (!NT_SUCCESS(Status
))
896 IopFreeDeviceNode(DeviceNode
);
900 /* Now initialize the associated device */
901 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
902 if (!NT_SUCCESS(Status
))
905 IopFreeDeviceNode(DeviceNode
);
910 Status
= IopStartDevice(DeviceNode
);
911 if (!NT_SUCCESS(Status
))
914 IopFreeDeviceNode(DeviceNode
);
918 /* Loop the boot modules */
919 ListHead
= &KeLoaderBlock
->LoadOrderListHead
;
920 NextEntry
= ListHead
->Flink
;
921 while (ListHead
!= NextEntry
)
924 LdrEntry
= CONTAINING_RECORD(NextEntry
,
925 LDR_DATA_TABLE_ENTRY
,
929 * HACK: Make sure we're loading a driver
930 * (we should be using BootDriverListHead!)
932 if (wcsstr(_wcsupr(LdrEntry
->BaseDllName
.Buffer
), L
".SYS"))
934 /* Make sure we didn't load this driver already */
935 if (!(LdrEntry
->Flags
& LDRP_ENTRY_INSERTED
))
937 DPRINT("Initializing bootdriver %wZ\n", &LdrEntry
->BaseDllName
);
939 IopInitializeBuiltinDriver(LdrEntry
);
943 /* Go to the next driver */
944 NextEntry
= NextEntry
->Flink
;
947 /* In old ROS, the loader list became empty after this point. Simulate. */
948 InitializeListHead(&KeLoaderBlock
->LoadOrderListHead
);
954 * Unloads a device driver.
958 * Name of the service to unload (registry key).
961 * Whether to unload Plug & Plug or only legacy drivers. If this
962 * parameter is set to FALSE, the routine will unload only legacy
969 * Guard the whole function by SEH.
973 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
975 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
976 UNICODE_STRING ImagePath
;
977 UNICODE_STRING ServiceName
;
978 UNICODE_STRING ObjectName
;
979 PDRIVER_OBJECT DriverObject
;
980 PDEVICE_OBJECT DeviceObject
;
981 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
982 LOAD_UNLOAD_PARAMS LoadParams
;
985 BOOLEAN SafeToUnload
= TRUE
;
987 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
992 * Get the service name from the registry key name
995 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
997 Start
= DriverServiceName
->Buffer
;
1001 RtlInitUnicodeString(&ServiceName
, Start
);
1004 * Construct the driver object name
1007 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1008 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1009 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1010 if (!ObjectName
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1011 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1012 memcpy(ObjectName
.Buffer
+ 8, Start
, ObjectName
.Length
- 8 * sizeof(WCHAR
));
1013 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1016 * Find the driver object
1018 Status
= ObReferenceObjectByName(&ObjectName
,
1025 (PVOID
*)&DriverObject
);
1028 * Free the buffer for driver object name
1030 ExFreePool(ObjectName
.Buffer
);
1032 if (!NT_SUCCESS(Status
))
1034 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName
);
1038 /* Check that driver is not already unloading */
1039 if (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
)
1041 DPRINT1("Driver deletion pending\n");
1042 ObDereferenceObject(DriverObject
);
1043 return STATUS_DELETE_PENDING
;
1047 * Get path of service...
1050 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1052 RtlInitUnicodeString(&ImagePath
, NULL
);
1054 QueryTable
[0].Name
= L
"ImagePath";
1055 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1056 QueryTable
[0].EntryContext
= &ImagePath
;
1058 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1059 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1061 if (!NT_SUCCESS(Status
))
1063 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1064 ObDereferenceObject(DriverObject
);
1069 * Normalize the image path for all later processing.
1072 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1074 if (!NT_SUCCESS(Status
))
1076 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1077 ObDereferenceObject(DriverObject
);
1082 * Free the service path
1085 ExFreePool(ImagePath
.Buffer
);
1088 * Unload the module and release the references to the device object
1091 /* Call the load/unload routine, depending on current process */
1092 if (DriverObject
->DriverUnload
&& DriverObject
->DriverSection
)
1094 /* Loop through each device object of the driver
1095 and set DOE_UNLOAD_PENDING flag */
1096 DeviceObject
= DriverObject
->DeviceObject
;
1097 while (DeviceObject
)
1099 /* Set the unload pending flag for the device */
1100 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1101 DeviceExtension
->ExtensionFlags
|= DOE_UNLOAD_PENDING
;
1103 /* Make sure there are no attached devices or no reference counts */
1104 if ((DeviceObject
->ReferenceCount
) || (DeviceObject
->AttachedDevice
))
1106 /* Not safe to unload */
1107 DPRINT1("Drivers device object is referenced or has attached devices\n");
1109 SafeToUnload
= FALSE
;
1112 DeviceObject
= DeviceObject
->NextDevice
;
1115 /* If not safe to unload, then return success */
1118 ObDereferenceObject(DriverObject
);
1119 return STATUS_SUCCESS
;
1122 /* Set the unload invoked flag */
1123 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
1125 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1127 /* Just call right away */
1128 (*DriverObject
->DriverUnload
)(DriverObject
);
1132 /* Load/Unload must be called from system process */
1134 /* Prepare parameters block */
1135 LoadParams
.DriverObject
= DriverObject
;
1136 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1138 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1139 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1140 (PVOID
)&LoadParams
);
1143 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1145 /* And wait when it completes */
1146 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1150 /* Mark the driver object temporary, so it could be deleted later */
1151 ObMakeTemporaryObject(DriverObject
);
1153 /* Dereference it 2 times */
1154 ObDereferenceObject(DriverObject
);
1155 ObDereferenceObject(DriverObject
);
1157 return STATUS_SUCCESS
;
1161 /* Dereference one time (refd inside this function) */
1162 ObDereferenceObject(DriverObject
);
1164 /* Return unloading failure */
1165 return STATUS_INVALID_DEVICE_REQUEST
;
1171 IopReinitializeDrivers(VOID
)
1173 PDRIVER_REINIT_ITEM ReinitItem
;
1176 /* Get the first entry and start looping */
1177 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1178 &DriverReinitListLock
);
1182 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1184 /* Increment reinitialization counter */
1185 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1187 /* Remove the device object flag */
1188 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1190 /* Call the routine */
1191 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1192 ReinitItem
->Context
,
1193 ReinitItem
->DriverObject
->
1194 DriverExtension
->Count
);
1196 /* Free the entry */
1199 /* Move to the next one */
1200 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1201 &DriverReinitListLock
);
1207 IopReinitializeBootDrivers(VOID
)
1209 PDRIVER_REINIT_ITEM ReinitItem
;
1212 /* Get the first entry and start looping */
1213 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1214 &DriverBootReinitListLock
);
1218 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1220 /* Increment reinitialization counter */
1221 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1223 /* Remove the device object flag */
1224 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1226 /* Call the routine */
1227 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1228 ReinitItem
->Context
,
1229 ReinitItem
->DriverObject
->
1230 DriverExtension
->Count
);
1232 /* Free the entry */
1235 /* Move to the next one */
1236 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1237 &DriverBootReinitListLock
);
1243 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1244 IN PDRIVER_INITIALIZE InitializationFunction
,
1245 IN PUNICODE_STRING RegistryPath
,
1247 IN ULONG SizeOfImage
,
1248 OUT PDRIVER_OBJECT
*pDriverObject
)
1250 WCHAR NameBuffer
[100];
1252 UNICODE_STRING LocalDriverName
;
1254 OBJECT_ATTRIBUTES ObjectAttributes
;
1256 PDRIVER_OBJECT DriverObject
;
1257 UNICODE_STRING ServiceKeyName
;
1259 ULONG i
, RetryCount
= 0;
1262 /* First, create a unique name for the driver if we don't have one */
1265 /* Create a random name and set up the string*/
1266 NameLength
= (USHORT
)swprintf(NameBuffer
,
1269 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1270 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1271 LocalDriverName
.Buffer
= NameBuffer
;
1275 /* So we can avoid another code path, use a local var */
1276 LocalDriverName
= *DriverName
;
1279 /* Initialize the Attributes */
1280 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1281 InitializeObjectAttributes(&ObjectAttributes
,
1283 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1287 /* Create the Object */
1288 Status
= ObCreateObject(KernelMode
,
1296 (PVOID
*)&DriverObject
);
1297 if (!NT_SUCCESS(Status
)) return Status
;
1299 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1301 /* Set up the Object */
1302 RtlZeroMemory(DriverObject
, ObjectSize
);
1303 DriverObject
->Type
= IO_TYPE_DRIVER
;
1304 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1305 DriverObject
->Flags
= DRVO_LEGACY_DRIVER
;//DRVO_BUILTIN_DRIVER;
1306 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1307 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1308 DriverObject
->DriverInit
= InitializationFunction
;
1310 /* Loop all Major Functions */
1311 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1313 /* Invalidate each function */
1314 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1317 /* Set up the service key name buffer */
1318 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1319 LocalDriverName
.Length
+
1322 if (!ServiceKeyName
.Buffer
)
1325 ObMakeTemporaryObject(DriverObject
);
1326 ObDereferenceObject(DriverObject
);
1327 return STATUS_INSUFFICIENT_RESOURCES
;
1330 /* Fill out the key data and copy the buffer */
1331 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1332 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1333 RtlCopyMemory(ServiceKeyName
.Buffer
,
1334 LocalDriverName
.Buffer
,
1335 LocalDriverName
.Length
);
1337 /* Null-terminate it and set it */
1338 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1339 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1341 /* Also store it in the Driver Object. This is a bit of a hack. */
1342 RtlCopyMemory(&DriverObject
->DriverName
,
1344 sizeof(UNICODE_STRING
));
1346 /* Add the Object and get its handle */
1347 Status
= ObInsertObject(DriverObject
,
1354 /* Eliminate small possibility when this function is called more than
1355 once in a row, and KeTickCount doesn't get enough time to change */
1356 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1362 if (!NT_SUCCESS(Status
)) return Status
;
1364 /* Now reference it */
1365 Status
= ObReferenceObjectByHandle(hDriver
,
1369 (PVOID
*)&DriverObject
,
1371 if (!NT_SUCCESS(Status
))
1374 ObMakeTemporaryObject(DriverObject
);
1375 ObDereferenceObject(DriverObject
);
1379 /* Close the extra handle */
1382 DriverObject
->HardwareDatabase
= &IopHardwareDatabaseKey
;
1383 DriverObject
->DriverStart
= DllBase
;
1384 DriverObject
->DriverSize
= SizeOfImage
;
1386 /* Finally, call its init function */
1387 DPRINT("RegistryKey: %wZ\n", RegistryPath
);
1388 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction
);
1389 Status
= (*InitializationFunction
)(DriverObject
, RegistryPath
);
1390 if (!NT_SUCCESS(Status
))
1392 /* If it didn't work, then kill the object */
1393 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName
, Status
);
1394 ObMakeTemporaryObject(DriverObject
);
1395 ObDereferenceObject(DriverObject
);
1399 /* Returns to caller the object */
1400 *pDriverObject
= DriverObject
;
1403 /* Loop all Major Functions */
1404 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1407 * Make sure the driver didn't set any dispatch entry point to NULL!
1408 * Doing so is illegal; drivers shouldn't touch entry points they
1411 ASSERT(DriverObject
->MajorFunction
[i
] != NULL
);
1413 /* Check if it did so anyway */
1414 if (!DriverObject
->MajorFunction
[i
])
1417 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1421 /* Return the Status */
1425 /* PUBLIC FUNCTIONS ***********************************************************/
1432 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1433 IN PDRIVER_INITIALIZE InitializationFunction
)
1435 PDRIVER_OBJECT DriverObject
;
1436 return IopCreateDriver(DriverName
, InitializationFunction
, NULL
, 0, 0, &DriverObject
);
1444 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1446 /* Simply dereference the Object */
1447 ObDereferenceObject(DriverObject
);
1455 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1456 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1459 PDRIVER_REINIT_ITEM ReinitItem
;
1461 /* Allocate the entry */
1462 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1463 sizeof(DRIVER_REINIT_ITEM
),
1465 if (!ReinitItem
) return;
1468 ReinitItem
->DriverObject
= DriverObject
;
1469 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1470 ReinitItem
->Context
= Context
;
1472 /* Set the Driver Object flag and insert the entry into the list */
1473 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1474 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1475 &ReinitItem
->ItemEntry
,
1476 &DriverBootReinitListLock
);
1484 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1485 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1488 PDRIVER_REINIT_ITEM ReinitItem
;
1490 /* Allocate the entry */
1491 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1492 sizeof(DRIVER_REINIT_ITEM
),
1494 if (!ReinitItem
) return;
1497 ReinitItem
->DriverObject
= DriverObject
;
1498 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1499 ReinitItem
->Context
= Context
;
1501 /* Set the Driver Object flag and insert the entry into the list */
1502 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1503 ExInterlockedInsertTailList(&DriverReinitListHead
,
1504 &ReinitItem
->ItemEntry
,
1505 &DriverReinitListLock
);
1513 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1514 IN PVOID ClientIdentificationAddress
,
1515 IN ULONG DriverObjectExtensionSize
,
1516 OUT PVOID
*DriverObjectExtension
)
1519 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1520 BOOLEAN Inserted
= FALSE
;
1522 /* Assume failure */
1523 *DriverObjectExtension
= NULL
;
1525 /* Allocate the extension */
1526 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1527 sizeof(IO_CLIENT_EXTENSION
) +
1528 DriverObjectExtensionSize
,
1529 TAG_DRIVER_EXTENSION
);
1530 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1532 /* Clear the extension for teh caller */
1533 RtlZeroMemory(NewDriverExtension
,
1534 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1537 OldIrql
= KeRaiseIrqlToDpcLevel();
1539 /* Fill out the extension */
1540 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1542 /* Loop the current extensions */
1543 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1544 ClientDriverExtension
;
1545 while (DriverExtensions
)
1547 /* Check if the identifier matches */
1548 if (DriverExtensions
->ClientIdentificationAddress
==
1549 ClientIdentificationAddress
)
1551 /* We have a collision, break out */
1555 /* Go to the next one */
1556 DriverExtensions
= DriverExtensions
->NextExtension
;
1559 /* Check if we didn't collide */
1560 if (!DriverExtensions
)
1562 /* Link this one in */
1563 NewDriverExtension
->NextExtension
=
1564 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1565 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1570 /* Release the lock */
1571 KeLowerIrql(OldIrql
);
1573 /* Check if insertion failed */
1576 /* Free the entry and fail */
1577 ExFreePool(NewDriverExtension
);
1578 return STATUS_OBJECT_NAME_COLLISION
;
1581 /* Otherwise, return the pointer */
1582 *DriverObjectExtension
= NewDriverExtension
+ 1;
1583 return STATUS_SUCCESS
;
1591 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1592 IN PVOID ClientIdentificationAddress
)
1595 PIO_CLIENT_EXTENSION DriverExtensions
;
1598 OldIrql
= KeRaiseIrqlToDpcLevel();
1600 /* Loop the list until we find the right one */
1601 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1602 while (DriverExtensions
)
1604 /* Check for a match */
1605 if (DriverExtensions
->ClientIdentificationAddress
==
1606 ClientIdentificationAddress
)
1613 DriverExtensions
= DriverExtensions
->NextExtension
;
1617 KeLowerIrql(OldIrql
);
1619 /* Return nothing or the extension */
1620 if (!DriverExtensions
) return NULL
;
1621 return DriverExtensions
+ 1;
1625 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams
)
1627 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1628 UNICODE_STRING ImagePath
;
1629 UNICODE_STRING ServiceName
;
1632 PDEVICE_NODE DeviceNode
;
1633 PDRIVER_OBJECT DriverObject
;
1634 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1638 /* Check if it's an unload request */
1639 if (LoadParams
->DriverObject
)
1641 (*LoadParams
->DriverObject
->DriverUnload
)(LoadParams
->DriverObject
);
1643 /* Return success and signal the event */
1644 LoadParams
->Status
= STATUS_SUCCESS
;
1645 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1649 RtlInitUnicodeString(&ImagePath
, NULL
);
1652 * Get the service name from the registry key name.
1654 ASSERT(LoadParams
->ServiceName
->Length
>= sizeof(WCHAR
));
1656 ServiceName
= *LoadParams
->ServiceName
;
1657 cur
= LoadParams
->ServiceName
->Buffer
+
1658 (LoadParams
->ServiceName
->Length
/ sizeof(WCHAR
)) - 1;
1659 while (LoadParams
->ServiceName
->Buffer
!= cur
)
1663 ServiceName
.Buffer
= cur
+ 1;
1664 ServiceName
.Length
= LoadParams
->ServiceName
->Length
-
1665 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1666 (ULONG_PTR
)LoadParams
->ServiceName
->Buffer
);
1676 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1678 RtlInitUnicodeString(&ImagePath
, NULL
);
1680 QueryTable
[0].Name
= L
"Type";
1681 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1682 QueryTable
[0].EntryContext
= &Type
;
1684 QueryTable
[1].Name
= L
"ImagePath";
1685 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1686 QueryTable
[1].EntryContext
= &ImagePath
;
1688 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1689 LoadParams
->ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1691 if (!NT_SUCCESS(Status
))
1693 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1694 if (ImagePath
.Buffer
)
1695 ExFreePool(ImagePath
.Buffer
);
1696 LoadParams
->Status
= Status
;
1697 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1702 * Normalize the image path for all later processing.
1705 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1707 if (!NT_SUCCESS(Status
))
1709 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1710 LoadParams
->Status
= Status
;
1711 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1715 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1716 DPRINT("Type: %lx\n", Type
);
1719 * Create device node
1722 /* Use IopRootDeviceNode for now */
1723 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1725 if (!NT_SUCCESS(Status
))
1727 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1728 LoadParams
->Status
= Status
;
1729 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1733 /* Get existing DriverObject pointer (in case the driver has
1734 already been loaded and initialized) */
1735 Status
= IopGetDriverObject(
1738 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1739 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */));
1741 if (!NT_SUCCESS(Status
))
1744 * Load the driver module
1747 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, &BaseAddress
);
1748 if (!NT_SUCCESS(Status
) && Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1750 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1751 IopFreeDeviceNode(DeviceNode
);
1752 LoadParams
->Status
= Status
;
1753 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1758 * Set a service name for the device node
1761 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
);
1764 * Initialize the driver module if it's loaded for the first time
1766 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1768 Status
= IopInitializeDriverModule(
1771 &DeviceNode
->ServiceName
,
1772 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1773 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1776 if (!NT_SUCCESS(Status
))
1778 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1779 MmUnloadSystemImage(ModuleObject
);
1780 IopFreeDeviceNode(DeviceNode
);
1781 LoadParams
->Status
= Status
;
1782 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1787 /* Store its DriverSection, so that it could be unloaded */
1788 DriverObject
->DriverSection
= ModuleObject
;
1790 /* Initialize and start device */
1791 IopInitializeDevice(DeviceNode
, DriverObject
);
1792 Status
= IopStartDevice(DeviceNode
);
1796 DPRINT("DriverObject already exist in ObjectManager\n");
1798 /* IopGetDriverObject references the DriverObject, so dereference it */
1799 ObDereferenceObject(DriverObject
);
1801 /* Free device node since driver loading failed */
1802 IopFreeDeviceNode(DeviceNode
);
1805 /* Pass status to the caller and signal the event */
1806 LoadParams
->Status
= Status
;
1807 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1813 * Loads a device driver.
1817 * Name of the service to load (registry key).
1826 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1828 UNICODE_STRING CapturedDriverServiceName
= { 0, 0, NULL
};
1829 KPROCESSOR_MODE PreviousMode
;
1830 LOAD_UNLOAD_PARAMS LoadParams
;
1835 PreviousMode
= KeGetPreviousMode();
1838 * Check security privileges
1841 /* FIXME: Uncomment when privileges will be correctly implemented. */
1843 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1845 DPRINT("Privilege not held\n");
1846 return STATUS_PRIVILEGE_NOT_HELD
;
1850 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
1853 if (!NT_SUCCESS(Status
))
1858 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1860 LoadParams
.ServiceName
= &CapturedDriverServiceName
;
1861 LoadParams
.DriverObject
= NULL
;
1862 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1864 /* Call the load/unload routine, depending on current process */
1865 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1867 /* Just call right away */
1868 IopLoadUnloadDriver(&LoadParams
);
1872 /* Load/Unload must be called from system process */
1873 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1874 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1875 (PVOID
)&LoadParams
);
1878 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1880 /* And wait when it completes */
1881 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1885 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
1888 return LoadParams
.Status
;
1894 * Unloads a legacy device driver.
1898 * Name of the service to unload (registry key).
1908 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
1910 return IopUnloadDriver(DriverServiceName
, FALSE
);