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 TAG('R', 'q', 'r', 'v')
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 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1011 memcpy(ObjectName
.Buffer
+ 8, Start
, ObjectName
.Length
- 8 * sizeof(WCHAR
));
1012 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1015 * Find the driver object
1017 Status
= ObReferenceObjectByName(&ObjectName
,
1024 (PVOID
*)&DriverObject
);
1027 * Free the buffer for driver object name
1029 ExFreePool(ObjectName
.Buffer
);
1031 if (!NT_SUCCESS(Status
))
1033 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName
);
1037 /* Check that driver is not already unloading */
1038 if (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
)
1040 DPRINT1("Driver deletion pending\n");
1041 ObDereferenceObject(DriverObject
);
1042 return STATUS_DELETE_PENDING
;
1046 * Get path of service...
1049 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1051 RtlInitUnicodeString(&ImagePath
, NULL
);
1053 QueryTable
[0].Name
= L
"ImagePath";
1054 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1055 QueryTable
[0].EntryContext
= &ImagePath
;
1057 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1058 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1060 if (!NT_SUCCESS(Status
))
1062 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1063 ObDereferenceObject(DriverObject
);
1068 * Normalize the image path for all later processing.
1071 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1073 if (!NT_SUCCESS(Status
))
1075 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1076 ObDereferenceObject(DriverObject
);
1081 * Free the service path
1084 ExFreePool(ImagePath
.Buffer
);
1087 * Unload the module and release the references to the device object
1090 /* Call the load/unload routine, depending on current process */
1091 if (DriverObject
->DriverUnload
&& DriverObject
->DriverSection
)
1093 /* Loop through each device object of the driver
1094 and set DOE_UNLOAD_PENDING flag */
1095 DeviceObject
= DriverObject
->DeviceObject
;
1096 while (DeviceObject
)
1098 /* Set the unload pending flag for the device */
1099 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1100 DeviceExtension
->ExtensionFlags
|= DOE_UNLOAD_PENDING
;
1102 /* Make sure there are no attached devices or no reference counts */
1103 if ((DeviceObject
->ReferenceCount
) || (DeviceObject
->AttachedDevice
))
1105 /* Not safe to unload */
1106 DPRINT1("Drivers device object is referenced or has attached devices\n");
1108 SafeToUnload
= FALSE
;
1111 DeviceObject
= DeviceObject
->NextDevice
;
1114 /* If not safe to unload, then return success */
1117 ObDereferenceObject(DriverObject
);
1118 return STATUS_SUCCESS
;
1121 /* Set the unload invoked flag */
1122 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
1124 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1126 /* Just call right away */
1127 (*DriverObject
->DriverUnload
)(DriverObject
);
1131 /* Load/Unload must be called from system process */
1133 /* Prepare parameters block */
1134 LoadParams
.DriverObject
= DriverObject
;
1135 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1137 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1138 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1139 (PVOID
)&LoadParams
);
1142 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1144 /* And wait when it completes */
1145 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1149 /* Mark the driver object temporary, so it could be deleted later */
1150 ObMakeTemporaryObject(DriverObject
);
1152 /* Dereference it 2 times */
1153 ObDereferenceObject(DriverObject
);
1154 ObDereferenceObject(DriverObject
);
1156 return STATUS_SUCCESS
;
1160 /* Dereference one time (refd inside this function) */
1161 ObDereferenceObject(DriverObject
);
1163 /* Return unloading failure */
1164 return STATUS_INVALID_DEVICE_REQUEST
;
1170 IopReinitializeDrivers(VOID
)
1172 PDRIVER_REINIT_ITEM ReinitItem
;
1175 /* Get the first entry and start looping */
1176 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1177 &DriverReinitListLock
);
1181 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1183 /* Increment reinitialization counter */
1184 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1186 /* Remove the device object flag */
1187 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1189 /* Call the routine */
1190 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1191 ReinitItem
->Context
,
1192 ReinitItem
->DriverObject
->
1193 DriverExtension
->Count
);
1195 /* Free the entry */
1198 /* Move to the next one */
1199 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1200 &DriverReinitListLock
);
1206 IopReinitializeBootDrivers(VOID
)
1208 PDRIVER_REINIT_ITEM ReinitItem
;
1211 /* Get the first entry and start looping */
1212 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1213 &DriverBootReinitListLock
);
1217 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1219 /* Increment reinitialization counter */
1220 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1222 /* Remove the device object flag */
1223 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1225 /* Call the routine */
1226 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1227 ReinitItem
->Context
,
1228 ReinitItem
->DriverObject
->
1229 DriverExtension
->Count
);
1231 /* Free the entry */
1234 /* Move to the next one */
1235 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1236 &DriverBootReinitListLock
);
1242 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1243 IN PDRIVER_INITIALIZE InitializationFunction
,
1244 IN PUNICODE_STRING RegistryPath
,
1246 IN ULONG SizeOfImage
,
1247 OUT PDRIVER_OBJECT
*pDriverObject
)
1249 WCHAR NameBuffer
[100];
1251 UNICODE_STRING LocalDriverName
;
1253 OBJECT_ATTRIBUTES ObjectAttributes
;
1255 PDRIVER_OBJECT DriverObject
;
1256 UNICODE_STRING ServiceKeyName
;
1258 ULONG i
, RetryCount
= 0;
1261 /* First, create a unique name for the driver if we don't have one */
1264 /* Create a random name and set up the string*/
1265 NameLength
= (USHORT
)swprintf(NameBuffer
,
1268 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1269 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1270 LocalDriverName
.Buffer
= NameBuffer
;
1274 /* So we can avoid another code path, use a local var */
1275 LocalDriverName
= *DriverName
;
1278 /* Initialize the Attributes */
1279 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1280 InitializeObjectAttributes(&ObjectAttributes
,
1282 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1286 /* Create the Object */
1287 Status
= ObCreateObject(KernelMode
,
1295 (PVOID
*)&DriverObject
);
1296 if (!NT_SUCCESS(Status
)) return Status
;
1298 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1300 /* Set up the Object */
1301 RtlZeroMemory(DriverObject
, ObjectSize
);
1302 DriverObject
->Type
= IO_TYPE_DRIVER
;
1303 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1304 DriverObject
->Flags
= DRVO_LEGACY_DRIVER
;//DRVO_BUILTIN_DRIVER;
1305 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1306 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1307 DriverObject
->DriverInit
= InitializationFunction
;
1309 /* Loop all Major Functions */
1310 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1312 /* Invalidate each function */
1313 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1316 /* Set up the service key name buffer */
1317 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1318 LocalDriverName
.Length
+
1321 if (!ServiceKeyName
.Buffer
)
1324 ObMakeTemporaryObject(DriverObject
);
1325 ObDereferenceObject(DriverObject
);
1326 return STATUS_INSUFFICIENT_RESOURCES
;
1329 /* Fill out the key data and copy the buffer */
1330 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1331 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1332 RtlCopyMemory(ServiceKeyName
.Buffer
,
1333 LocalDriverName
.Buffer
,
1334 LocalDriverName
.Length
);
1336 /* Null-terminate it and set it */
1337 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1338 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1340 /* Also store it in the Driver Object. This is a bit of a hack. */
1341 RtlCopyMemory(&DriverObject
->DriverName
,
1343 sizeof(UNICODE_STRING
));
1345 /* Add the Object and get its handle */
1346 Status
= ObInsertObject(DriverObject
,
1353 /* Eliminate small possibility when this function is called more than
1354 once in a row, and KeTickCount doesn't get enough time to change */
1355 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1361 if (!NT_SUCCESS(Status
)) return Status
;
1363 /* Now reference it */
1364 Status
= ObReferenceObjectByHandle(hDriver
,
1368 (PVOID
*)&DriverObject
,
1370 if (!NT_SUCCESS(Status
))
1373 ObMakeTemporaryObject(DriverObject
);
1374 ObDereferenceObject(DriverObject
);
1378 /* Close the extra handle */
1381 DriverObject
->HardwareDatabase
= &IopHardwareDatabaseKey
;
1382 DriverObject
->DriverStart
= DllBase
;
1383 DriverObject
->DriverSize
= SizeOfImage
;
1385 /* Finally, call its init function */
1386 DPRINT("RegistryKey: %wZ\n", RegistryPath
);
1387 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction
);
1388 Status
= (*InitializationFunction
)(DriverObject
, RegistryPath
);
1389 if (!NT_SUCCESS(Status
))
1391 /* If it didn't work, then kill the object */
1392 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName
, Status
);
1393 ObMakeTemporaryObject(DriverObject
);
1394 ObDereferenceObject(DriverObject
);
1398 /* Returns to caller the object */
1399 *pDriverObject
= DriverObject
;
1402 /* Loop all Major Functions */
1403 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1405 /* Set each function that was set to NULL to internal routine */
1406 if (!DriverObject
->MajorFunction
[i
])
1407 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1410 /* Return the Status */
1414 /* PUBLIC FUNCTIONS ***********************************************************/
1421 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1422 IN PDRIVER_INITIALIZE InitializationFunction
)
1424 PDRIVER_OBJECT DriverObject
;
1425 return IopCreateDriver(DriverName
, InitializationFunction
, NULL
, 0, 0, &DriverObject
);
1433 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1435 /* Simply dereference the Object */
1436 ObDereferenceObject(DriverObject
);
1444 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1445 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1448 PDRIVER_REINIT_ITEM ReinitItem
;
1450 /* Allocate the entry */
1451 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1452 sizeof(DRIVER_REINIT_ITEM
),
1454 if (!ReinitItem
) return;
1457 ReinitItem
->DriverObject
= DriverObject
;
1458 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1459 ReinitItem
->Context
= Context
;
1461 /* Set the Driver Object flag and insert the entry into the list */
1462 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1463 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1464 &ReinitItem
->ItemEntry
,
1465 &DriverBootReinitListLock
);
1473 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1474 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1477 PDRIVER_REINIT_ITEM ReinitItem
;
1479 /* Allocate the entry */
1480 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1481 sizeof(DRIVER_REINIT_ITEM
),
1483 if (!ReinitItem
) return;
1486 ReinitItem
->DriverObject
= DriverObject
;
1487 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1488 ReinitItem
->Context
= Context
;
1490 /* Set the Driver Object flag and insert the entry into the list */
1491 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1492 ExInterlockedInsertTailList(&DriverReinitListHead
,
1493 &ReinitItem
->ItemEntry
,
1494 &DriverReinitListLock
);
1502 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1503 IN PVOID ClientIdentificationAddress
,
1504 IN ULONG DriverObjectExtensionSize
,
1505 OUT PVOID
*DriverObjectExtension
)
1508 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1509 BOOLEAN Inserted
= FALSE
;
1511 /* Assume failure */
1512 *DriverObjectExtension
= NULL
;
1514 /* Allocate the extension */
1515 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1516 sizeof(IO_CLIENT_EXTENSION
) +
1517 DriverObjectExtensionSize
,
1518 TAG_DRIVER_EXTENSION
);
1519 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1521 /* Clear the extension for teh caller */
1522 RtlZeroMemory(NewDriverExtension
,
1523 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1526 OldIrql
= KeRaiseIrqlToDpcLevel();
1528 /* Fill out the extension */
1529 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1531 /* Loop the current extensions */
1532 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1533 ClientDriverExtension
;
1534 while (DriverExtensions
)
1536 /* Check if the identifier matches */
1537 if (DriverExtensions
->ClientIdentificationAddress
==
1538 ClientIdentificationAddress
)
1540 /* We have a collision, break out */
1544 /* Go to the next one */
1545 DriverExtensions
= DriverExtensions
->NextExtension
;
1548 /* Check if we didn't collide */
1549 if (!DriverExtensions
)
1551 /* Link this one in */
1552 NewDriverExtension
->NextExtension
=
1553 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1554 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1559 /* Release the lock */
1560 KeLowerIrql(OldIrql
);
1562 /* Check if insertion failed */
1565 /* Free the entry and fail */
1566 ExFreePool(NewDriverExtension
);
1567 return STATUS_OBJECT_NAME_COLLISION
;
1570 /* Otherwise, return the pointer */
1571 *DriverObjectExtension
= NewDriverExtension
+ 1;
1572 return STATUS_SUCCESS
;
1580 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1581 IN PVOID ClientIdentificationAddress
)
1584 PIO_CLIENT_EXTENSION DriverExtensions
;
1587 OldIrql
= KeRaiseIrqlToDpcLevel();
1589 /* Loop the list until we find the right one */
1590 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1591 while (DriverExtensions
)
1593 /* Check for a match */
1594 if (DriverExtensions
->ClientIdentificationAddress
==
1595 ClientIdentificationAddress
)
1602 DriverExtensions
= DriverExtensions
->NextExtension
;
1606 KeLowerIrql(OldIrql
);
1608 /* Return nothing or the extension */
1609 if (!DriverExtensions
) return NULL
;
1610 return DriverExtensions
+ 1;
1614 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams
)
1616 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1617 UNICODE_STRING ImagePath
;
1618 UNICODE_STRING ServiceName
;
1621 PDEVICE_NODE DeviceNode
;
1622 PDRIVER_OBJECT DriverObject
;
1623 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1627 /* Check if it's an unload request */
1628 if (LoadParams
->DriverObject
)
1630 (*LoadParams
->DriverObject
->DriverUnload
)(LoadParams
->DriverObject
);
1632 /* Return success and signal the event */
1633 LoadParams
->Status
= STATUS_SUCCESS
;
1634 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1638 RtlInitUnicodeString(&ImagePath
, NULL
);
1641 * Get the service name from the registry key name.
1643 ASSERT(LoadParams
->ServiceName
->Length
>= sizeof(WCHAR
));
1645 ServiceName
= *LoadParams
->ServiceName
;
1646 cur
= LoadParams
->ServiceName
->Buffer
+
1647 (LoadParams
->ServiceName
->Length
/ sizeof(WCHAR
)) - 1;
1648 while (LoadParams
->ServiceName
->Buffer
!= cur
)
1652 ServiceName
.Buffer
= cur
+ 1;
1653 ServiceName
.Length
= LoadParams
->ServiceName
->Length
-
1654 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1655 (ULONG_PTR
)LoadParams
->ServiceName
->Buffer
);
1665 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1667 RtlInitUnicodeString(&ImagePath
, NULL
);
1669 QueryTable
[0].Name
= L
"Type";
1670 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1671 QueryTable
[0].EntryContext
= &Type
;
1673 QueryTable
[1].Name
= L
"ImagePath";
1674 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1675 QueryTable
[1].EntryContext
= &ImagePath
;
1677 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1678 LoadParams
->ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1680 if (!NT_SUCCESS(Status
))
1682 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1683 if (ImagePath
.Buffer
)
1684 ExFreePool(ImagePath
.Buffer
);
1685 LoadParams
->Status
= Status
;
1686 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1691 * Normalize the image path for all later processing.
1694 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1696 if (!NT_SUCCESS(Status
))
1698 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1699 LoadParams
->Status
= Status
;
1700 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1704 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1705 DPRINT("Type: %lx\n", Type
);
1708 * Create device node
1711 /* Use IopRootDeviceNode for now */
1712 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1714 if (!NT_SUCCESS(Status
))
1716 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1717 LoadParams
->Status
= Status
;
1718 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1722 /* Get existing DriverObject pointer (in case the driver has
1723 already been loaded and initialized) */
1724 Status
= IopGetDriverObject(
1727 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1728 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */));
1730 if (!NT_SUCCESS(Status
))
1733 * Load the driver module
1736 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, &BaseAddress
);
1737 if (!NT_SUCCESS(Status
) && Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1739 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1740 IopFreeDeviceNode(DeviceNode
);
1741 LoadParams
->Status
= Status
;
1742 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1747 * Set a service name for the device node
1750 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
);
1753 * Initialize the driver module if it's loaded for the first time
1755 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1757 Status
= IopInitializeDriverModule(
1760 &DeviceNode
->ServiceName
,
1761 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1762 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1765 if (!NT_SUCCESS(Status
))
1767 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1768 MmUnloadSystemImage(ModuleObject
);
1769 IopFreeDeviceNode(DeviceNode
);
1770 LoadParams
->Status
= Status
;
1771 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1776 /* Store its DriverSection, so that it could be unloaded */
1777 DriverObject
->DriverSection
= ModuleObject
;
1780 IopInitializeDevice(DeviceNode
, DriverObject
);
1781 LoadParams
->Status
= IopStartDevice(DeviceNode
);
1782 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1788 * Loads a device driver.
1792 * Name of the service to load (registry key).
1801 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1803 UNICODE_STRING CapturedDriverServiceName
= { 0, 0, NULL
};
1804 KPROCESSOR_MODE PreviousMode
;
1805 LOAD_UNLOAD_PARAMS LoadParams
;
1810 PreviousMode
= KeGetPreviousMode();
1813 * Check security privileges
1816 /* FIXME: Uncomment when privileges will be correctly implemented. */
1818 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1820 DPRINT("Privilege not held\n");
1821 return STATUS_PRIVILEGE_NOT_HELD
;
1825 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
1828 if (!NT_SUCCESS(Status
))
1833 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1835 LoadParams
.ServiceName
= &CapturedDriverServiceName
;
1836 LoadParams
.DriverObject
= NULL
;
1837 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1839 /* Call the load/unload routine, depending on current process */
1840 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1842 /* Just call right away */
1843 IopLoadUnloadDriver(&LoadParams
);
1847 /* Load/Unload must be called from system process */
1848 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1849 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1850 (PVOID
)&LoadParams
);
1853 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1855 /* And wait when it completes */
1856 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1860 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
1863 return LoadParams
.Status
;
1869 * Unloads a legacy device driver.
1873 * Name of the service to unload (registry key).
1883 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
1885 return IopUnloadDriver(DriverServiceName
, FALSE
);