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
);
696 // Used for images already loaded (boot drivers)
700 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry
,
701 PUNICODE_STRING FileName
,
702 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
705 PLDR_DATA_TABLE_ENTRY NewEntry
;
706 UNICODE_STRING BaseName
, BaseDirectory
;
707 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
708 PCHAR MissingApiName
, Buffer
;
709 PWCHAR MissingDriverName
;
710 PVOID DriverBase
= LdrEntry
->DllBase
;
712 /* Allocate a buffer we'll use for names */
713 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
717 return STATUS_INSUFFICIENT_RESOURCES
;
720 /* Check for a separator */
721 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
726 /* Loop the path until we get to the base name */
727 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
728 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
731 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
732 BaseLength
*= sizeof(WCHAR
);
734 /* Setup the string */
735 BaseName
.Length
= (USHORT
)BaseLength
;
740 /* Otherwise, we already have a base name */
741 BaseName
.Length
= FileName
->Length
;
742 BaseName
.Buffer
= FileName
->Buffer
;
745 /* Setup the maximum length */
746 BaseName
.MaximumLength
= BaseName
.Length
;
748 /* Now compute the base directory */
749 BaseDirectory
= *FileName
;
750 BaseDirectory
.Length
-= BaseName
.Length
;
751 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
755 /* Resolve imports */
756 MissingApiName
= Buffer
;
757 Status
= MiResolveImageReferences(DriverBase
,
763 if (!NT_SUCCESS(Status
)) return Status
;
766 *ModuleObject
= LdrEntry
;
767 return STATUS_SUCCESS
;
771 * IopInitializeBuiltinDriver
773 * Initialize a driver that is already loaded in memory.
778 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
780 PDEVICE_NODE DeviceNode
;
781 PDRIVER_OBJECT DriverObject
;
783 PWCHAR FileNameWithoutPath
;
784 LPWSTR FileExtension
;
785 PUNICODE_STRING ModuleName
= &LdrEntry
->BaseDllName
;
786 UNICODE_STRING ServiceName
;
789 * Display 'Loading XXX...' message
791 IopDisplayLoadingMessage(ModuleName
->Buffer
, TRUE
);
794 * Generate filename without path (not needed by freeldr)
796 FileNameWithoutPath
= wcsrchr(ModuleName
->Buffer
, L
'\\');
797 if (FileNameWithoutPath
== NULL
)
799 FileNameWithoutPath
= ModuleName
->Buffer
;
803 FileNameWithoutPath
++;
807 * Strip the file extension from ServiceName
809 RtlCreateUnicodeString(&ServiceName
, FileNameWithoutPath
);
810 FileExtension
= wcsrchr(ServiceName
.Buffer
, '.');
811 if (FileExtension
!= NULL
)
813 ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
814 FileExtension
[0] = 0;
818 * Determine the right device object
820 /* Use IopRootDeviceNode for now */
821 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
822 if (!NT_SUCCESS(Status
))
824 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
827 DeviceNode
->ServiceName
= ServiceName
;
830 * Initialize the driver
832 Status
= IopInitializeDriverModule(DeviceNode
, LdrEntry
,
833 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
835 if (!NT_SUCCESS(Status
))
837 IopFreeDeviceNode(DeviceNode
);
841 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
842 if (NT_SUCCESS(Status
))
844 Status
= IopStartDevice(DeviceNode
);
851 * IopInitializeBootDrivers
853 * Initialize boot drivers and free memory for boot files.
863 IopInitializeBootDrivers(VOID
)
865 PLIST_ENTRY ListHead
, NextEntry
;
866 PLDR_DATA_TABLE_ENTRY LdrEntry
;
867 PDEVICE_NODE DeviceNode
;
868 PDRIVER_OBJECT DriverObject
;
869 LDR_DATA_TABLE_ENTRY ModuleObject
;
871 UNICODE_STRING DriverName
;
873 DPRINT("IopInitializeBootDrivers()\n");
875 /* Use IopRootDeviceNode for now */
876 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, NULL
, &DeviceNode
);
877 if (!NT_SUCCESS(Status
)) return;
879 /* Setup the module object for the RAW FS Driver */
880 ModuleObject
.DllBase
= NULL
;
881 ModuleObject
.SizeOfImage
= 0;
882 ModuleObject
.EntryPoint
= RawFsDriverEntry
;
883 RtlInitUnicodeString(&DriverName
, L
"RAW");
886 Status
= IopInitializeDriverModule(DeviceNode
,
891 if (!NT_SUCCESS(Status
))
894 IopFreeDeviceNode(DeviceNode
);
898 /* Now initialize the associated device */
899 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
900 if (!NT_SUCCESS(Status
))
903 IopFreeDeviceNode(DeviceNode
);
908 Status
= IopStartDevice(DeviceNode
);
909 if (!NT_SUCCESS(Status
))
912 IopFreeDeviceNode(DeviceNode
);
916 /* Loop the boot modules */
917 ListHead
= &KeLoaderBlock
->LoadOrderListHead
;
918 NextEntry
= ListHead
->Flink
;
919 while (ListHead
!= NextEntry
)
922 LdrEntry
= CONTAINING_RECORD(NextEntry
,
923 LDR_DATA_TABLE_ENTRY
,
927 * HACK: Make sure we're loading a driver
928 * (we should be using BootDriverListHead!)
930 if (wcsstr(_wcsupr(LdrEntry
->BaseDllName
.Buffer
), L
".SYS"))
932 /* Make sure we didn't load this driver already */
933 if (!(LdrEntry
->Flags
& LDRP_ENTRY_INSERTED
))
935 DPRINT("Initializing bootdriver %wZ\n", &LdrEntry
->BaseDllName
);
937 IopInitializeBuiltinDriver(LdrEntry
);
941 /* Go to the next driver */
942 NextEntry
= NextEntry
->Flink
;
945 /* In old ROS, the loader list became empty after this point. Simulate. */
946 InitializeListHead(&KeLoaderBlock
->LoadOrderListHead
);
952 * Unloads a device driver.
956 * Name of the service to unload (registry key).
959 * Whether to unload Plug & Plug or only legacy drivers. If this
960 * parameter is set to FALSE, the routine will unload only legacy
967 * Guard the whole function by SEH.
971 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
973 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
974 UNICODE_STRING ImagePath
;
975 UNICODE_STRING ServiceName
;
976 UNICODE_STRING ObjectName
;
977 PDRIVER_OBJECT DriverObject
;
978 PDEVICE_OBJECT DeviceObject
;
979 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
980 LOAD_UNLOAD_PARAMS LoadParams
;
983 BOOLEAN SafeToUnload
= TRUE
;
985 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
990 * Get the service name from the registry key name
993 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
995 Start
= DriverServiceName
->Buffer
;
999 RtlInitUnicodeString(&ServiceName
, Start
);
1002 * Construct the driver object name
1005 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1006 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1007 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1008 if (!ObjectName
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1009 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1010 memcpy(ObjectName
.Buffer
+ 8, Start
, ObjectName
.Length
- 8 * sizeof(WCHAR
));
1011 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1014 * Find the driver object
1016 Status
= ObReferenceObjectByName(&ObjectName
,
1023 (PVOID
*)&DriverObject
);
1026 * Free the buffer for driver object name
1028 ExFreePool(ObjectName
.Buffer
);
1030 if (!NT_SUCCESS(Status
))
1032 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName
);
1036 /* Check that driver is not already unloading */
1037 if (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
)
1039 DPRINT1("Driver deletion pending\n");
1040 ObDereferenceObject(DriverObject
);
1041 return STATUS_DELETE_PENDING
;
1045 * Get path of service...
1048 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1050 RtlInitUnicodeString(&ImagePath
, NULL
);
1052 QueryTable
[0].Name
= L
"ImagePath";
1053 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1054 QueryTable
[0].EntryContext
= &ImagePath
;
1056 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1057 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1059 if (!NT_SUCCESS(Status
))
1061 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1062 ObDereferenceObject(DriverObject
);
1067 * Normalize the image path for all later processing.
1070 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1072 if (!NT_SUCCESS(Status
))
1074 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1075 ObDereferenceObject(DriverObject
);
1080 * Free the service path
1083 ExFreePool(ImagePath
.Buffer
);
1086 * Unload the module and release the references to the device object
1089 /* Call the load/unload routine, depending on current process */
1090 if (DriverObject
->DriverUnload
&& DriverObject
->DriverSection
)
1092 /* Loop through each device object of the driver
1093 and set DOE_UNLOAD_PENDING flag */
1094 DeviceObject
= DriverObject
->DeviceObject
;
1095 while (DeviceObject
)
1097 /* Set the unload pending flag for the device */
1098 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1099 DeviceExtension
->ExtensionFlags
|= DOE_UNLOAD_PENDING
;
1101 /* Make sure there are no attached devices or no reference counts */
1102 if ((DeviceObject
->ReferenceCount
) || (DeviceObject
->AttachedDevice
))
1104 /* Not safe to unload */
1105 DPRINT1("Drivers device object is referenced or has attached devices\n");
1107 SafeToUnload
= FALSE
;
1110 DeviceObject
= DeviceObject
->NextDevice
;
1113 /* If not safe to unload, then return success */
1116 ObDereferenceObject(DriverObject
);
1117 return STATUS_SUCCESS
;
1120 /* Set the unload invoked flag */
1121 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
1123 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1125 /* Just call right away */
1126 (*DriverObject
->DriverUnload
)(DriverObject
);
1130 /* Load/Unload must be called from system process */
1132 /* Prepare parameters block */
1133 LoadParams
.DriverObject
= DriverObject
;
1134 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1136 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1137 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1138 (PVOID
)&LoadParams
);
1141 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1143 /* And wait when it completes */
1144 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1148 /* Mark the driver object temporary, so it could be deleted later */
1149 ObMakeTemporaryObject(DriverObject
);
1151 /* Dereference it 2 times */
1152 ObDereferenceObject(DriverObject
);
1153 ObDereferenceObject(DriverObject
);
1155 return STATUS_SUCCESS
;
1159 /* Dereference one time (refd inside this function) */
1160 ObDereferenceObject(DriverObject
);
1162 /* Return unloading failure */
1163 return STATUS_INVALID_DEVICE_REQUEST
;
1169 IopReinitializeDrivers(VOID
)
1171 PDRIVER_REINIT_ITEM ReinitItem
;
1174 /* Get the first entry and start looping */
1175 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1176 &DriverReinitListLock
);
1180 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1182 /* Increment reinitialization counter */
1183 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1185 /* Remove the device object flag */
1186 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1188 /* Call the routine */
1189 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1190 ReinitItem
->Context
,
1191 ReinitItem
->DriverObject
->
1192 DriverExtension
->Count
);
1194 /* Free the entry */
1197 /* Move to the next one */
1198 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1199 &DriverReinitListLock
);
1205 IopReinitializeBootDrivers(VOID
)
1207 PDRIVER_REINIT_ITEM ReinitItem
;
1210 /* Get the first entry and start looping */
1211 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1212 &DriverBootReinitListLock
);
1216 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1218 /* Increment reinitialization counter */
1219 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1221 /* Remove the device object flag */
1222 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1224 /* Call the routine */
1225 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1226 ReinitItem
->Context
,
1227 ReinitItem
->DriverObject
->
1228 DriverExtension
->Count
);
1230 /* Free the entry */
1233 /* Move to the next one */
1234 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1235 &DriverBootReinitListLock
);
1241 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1242 IN PDRIVER_INITIALIZE InitializationFunction
,
1243 IN PUNICODE_STRING RegistryPath
,
1245 IN ULONG SizeOfImage
,
1246 OUT PDRIVER_OBJECT
*pDriverObject
)
1248 WCHAR NameBuffer
[100];
1250 UNICODE_STRING LocalDriverName
;
1252 OBJECT_ATTRIBUTES ObjectAttributes
;
1254 PDRIVER_OBJECT DriverObject
;
1255 UNICODE_STRING ServiceKeyName
;
1257 ULONG i
, RetryCount
= 0;
1260 /* First, create a unique name for the driver if we don't have one */
1263 /* Create a random name and set up the string*/
1264 NameLength
= (USHORT
)swprintf(NameBuffer
,
1267 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1268 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1269 LocalDriverName
.Buffer
= NameBuffer
;
1273 /* So we can avoid another code path, use a local var */
1274 LocalDriverName
= *DriverName
;
1277 /* Initialize the Attributes */
1278 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1279 InitializeObjectAttributes(&ObjectAttributes
,
1281 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1285 /* Create the Object */
1286 Status
= ObCreateObject(KernelMode
,
1294 (PVOID
*)&DriverObject
);
1295 if (!NT_SUCCESS(Status
)) return Status
;
1297 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1299 /* Set up the Object */
1300 RtlZeroMemory(DriverObject
, ObjectSize
);
1301 DriverObject
->Type
= IO_TYPE_DRIVER
;
1302 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1303 DriverObject
->Flags
= DRVO_LEGACY_DRIVER
;//DRVO_BUILTIN_DRIVER;
1304 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1305 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1306 DriverObject
->DriverInit
= InitializationFunction
;
1308 /* Loop all Major Functions */
1309 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1311 /* Invalidate each function */
1312 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1315 /* Set up the service key name buffer */
1316 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1317 LocalDriverName
.Length
+
1320 if (!ServiceKeyName
.Buffer
)
1323 ObMakeTemporaryObject(DriverObject
);
1324 ObDereferenceObject(DriverObject
);
1325 return STATUS_INSUFFICIENT_RESOURCES
;
1328 /* Fill out the key data and copy the buffer */
1329 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1330 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1331 RtlCopyMemory(ServiceKeyName
.Buffer
,
1332 LocalDriverName
.Buffer
,
1333 LocalDriverName
.Length
);
1335 /* Null-terminate it and set it */
1336 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1337 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1339 /* Also store it in the Driver Object. This is a bit of a hack. */
1340 RtlCopyMemory(&DriverObject
->DriverName
,
1342 sizeof(UNICODE_STRING
));
1344 /* Add the Object and get its handle */
1345 Status
= ObInsertObject(DriverObject
,
1352 /* Eliminate small possibility when this function is called more than
1353 once in a row, and KeTickCount doesn't get enough time to change */
1354 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1360 if (!NT_SUCCESS(Status
)) return Status
;
1362 /* Now reference it */
1363 Status
= ObReferenceObjectByHandle(hDriver
,
1367 (PVOID
*)&DriverObject
,
1369 if (!NT_SUCCESS(Status
))
1372 ObMakeTemporaryObject(DriverObject
);
1373 ObDereferenceObject(DriverObject
);
1377 /* Close the extra handle */
1380 DriverObject
->HardwareDatabase
= &IopHardwareDatabaseKey
;
1381 DriverObject
->DriverStart
= DllBase
;
1382 DriverObject
->DriverSize
= SizeOfImage
;
1384 /* Finally, call its init function */
1385 DPRINT("RegistryKey: %wZ\n", RegistryPath
);
1386 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction
);
1387 Status
= (*InitializationFunction
)(DriverObject
, RegistryPath
);
1388 if (!NT_SUCCESS(Status
))
1390 /* If it didn't work, then kill the object */
1391 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName
, Status
);
1392 ObMakeTemporaryObject(DriverObject
);
1393 ObDereferenceObject(DriverObject
);
1397 /* Returns to caller the object */
1398 *pDriverObject
= DriverObject
;
1401 /* Loop all Major Functions */
1402 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1405 * Make sure the driver didn't set any dispatch entry point to NULL!
1406 * Doing so is illegal; drivers shouldn't touch entry points they
1409 ASSERT(DriverObject
->MajorFunction
[i
] != NULL
);
1411 /* Check if it did so anyway */
1412 if (!DriverObject
->MajorFunction
[i
])
1415 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1419 /* Return the Status */
1423 /* PUBLIC FUNCTIONS ***********************************************************/
1430 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1431 IN PDRIVER_INITIALIZE InitializationFunction
)
1433 PDRIVER_OBJECT DriverObject
;
1434 return IopCreateDriver(DriverName
, InitializationFunction
, NULL
, 0, 0, &DriverObject
);
1442 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1444 /* Simply dereference the Object */
1445 ObDereferenceObject(DriverObject
);
1453 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1454 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1457 PDRIVER_REINIT_ITEM ReinitItem
;
1459 /* Allocate the entry */
1460 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1461 sizeof(DRIVER_REINIT_ITEM
),
1463 if (!ReinitItem
) return;
1466 ReinitItem
->DriverObject
= DriverObject
;
1467 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1468 ReinitItem
->Context
= Context
;
1470 /* Set the Driver Object flag and insert the entry into the list */
1471 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1472 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1473 &ReinitItem
->ItemEntry
,
1474 &DriverBootReinitListLock
);
1482 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1483 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1486 PDRIVER_REINIT_ITEM ReinitItem
;
1488 /* Allocate the entry */
1489 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1490 sizeof(DRIVER_REINIT_ITEM
),
1492 if (!ReinitItem
) return;
1495 ReinitItem
->DriverObject
= DriverObject
;
1496 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1497 ReinitItem
->Context
= Context
;
1499 /* Set the Driver Object flag and insert the entry into the list */
1500 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1501 ExInterlockedInsertTailList(&DriverReinitListHead
,
1502 &ReinitItem
->ItemEntry
,
1503 &DriverReinitListLock
);
1511 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1512 IN PVOID ClientIdentificationAddress
,
1513 IN ULONG DriverObjectExtensionSize
,
1514 OUT PVOID
*DriverObjectExtension
)
1517 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1518 BOOLEAN Inserted
= FALSE
;
1520 /* Assume failure */
1521 *DriverObjectExtension
= NULL
;
1523 /* Allocate the extension */
1524 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1525 sizeof(IO_CLIENT_EXTENSION
) +
1526 DriverObjectExtensionSize
,
1527 TAG_DRIVER_EXTENSION
);
1528 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1530 /* Clear the extension for teh caller */
1531 RtlZeroMemory(NewDriverExtension
,
1532 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1535 OldIrql
= KeRaiseIrqlToDpcLevel();
1537 /* Fill out the extension */
1538 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1540 /* Loop the current extensions */
1541 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1542 ClientDriverExtension
;
1543 while (DriverExtensions
)
1545 /* Check if the identifier matches */
1546 if (DriverExtensions
->ClientIdentificationAddress
==
1547 ClientIdentificationAddress
)
1549 /* We have a collision, break out */
1553 /* Go to the next one */
1554 DriverExtensions
= DriverExtensions
->NextExtension
;
1557 /* Check if we didn't collide */
1558 if (!DriverExtensions
)
1560 /* Link this one in */
1561 NewDriverExtension
->NextExtension
=
1562 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1563 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1568 /* Release the lock */
1569 KeLowerIrql(OldIrql
);
1571 /* Check if insertion failed */
1574 /* Free the entry and fail */
1575 ExFreePool(NewDriverExtension
);
1576 return STATUS_OBJECT_NAME_COLLISION
;
1579 /* Otherwise, return the pointer */
1580 *DriverObjectExtension
= NewDriverExtension
+ 1;
1581 return STATUS_SUCCESS
;
1589 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1590 IN PVOID ClientIdentificationAddress
)
1593 PIO_CLIENT_EXTENSION DriverExtensions
;
1596 OldIrql
= KeRaiseIrqlToDpcLevel();
1598 /* Loop the list until we find the right one */
1599 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1600 while (DriverExtensions
)
1602 /* Check for a match */
1603 if (DriverExtensions
->ClientIdentificationAddress
==
1604 ClientIdentificationAddress
)
1611 DriverExtensions
= DriverExtensions
->NextExtension
;
1615 KeLowerIrql(OldIrql
);
1617 /* Return nothing or the extension */
1618 if (!DriverExtensions
) return NULL
;
1619 return DriverExtensions
+ 1;
1623 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams
)
1625 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1626 UNICODE_STRING ImagePath
;
1627 UNICODE_STRING ServiceName
;
1630 PDEVICE_NODE DeviceNode
;
1631 PDRIVER_OBJECT DriverObject
;
1632 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1636 /* Check if it's an unload request */
1637 if (LoadParams
->DriverObject
)
1639 (*LoadParams
->DriverObject
->DriverUnload
)(LoadParams
->DriverObject
);
1641 /* Return success and signal the event */
1642 LoadParams
->Status
= STATUS_SUCCESS
;
1643 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1647 RtlInitUnicodeString(&ImagePath
, NULL
);
1650 * Get the service name from the registry key name.
1652 ASSERT(LoadParams
->ServiceName
->Length
>= sizeof(WCHAR
));
1654 ServiceName
= *LoadParams
->ServiceName
;
1655 cur
= LoadParams
->ServiceName
->Buffer
+
1656 (LoadParams
->ServiceName
->Length
/ sizeof(WCHAR
)) - 1;
1657 while (LoadParams
->ServiceName
->Buffer
!= cur
)
1661 ServiceName
.Buffer
= cur
+ 1;
1662 ServiceName
.Length
= LoadParams
->ServiceName
->Length
-
1663 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1664 (ULONG_PTR
)LoadParams
->ServiceName
->Buffer
);
1674 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1676 RtlInitUnicodeString(&ImagePath
, NULL
);
1678 QueryTable
[0].Name
= L
"Type";
1679 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1680 QueryTable
[0].EntryContext
= &Type
;
1682 QueryTable
[1].Name
= L
"ImagePath";
1683 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1684 QueryTable
[1].EntryContext
= &ImagePath
;
1686 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1687 LoadParams
->ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1689 if (!NT_SUCCESS(Status
))
1691 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1692 if (ImagePath
.Buffer
)
1693 ExFreePool(ImagePath
.Buffer
);
1694 LoadParams
->Status
= Status
;
1695 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1700 * Normalize the image path for all later processing.
1703 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1705 if (!NT_SUCCESS(Status
))
1707 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1708 LoadParams
->Status
= Status
;
1709 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1713 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1714 DPRINT("Type: %lx\n", Type
);
1717 * Create device node
1720 /* Use IopRootDeviceNode for now */
1721 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1723 if (!NT_SUCCESS(Status
))
1725 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1726 LoadParams
->Status
= Status
;
1727 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1731 /* Get existing DriverObject pointer (in case the driver has
1732 already been loaded and initialized) */
1733 Status
= IopGetDriverObject(
1736 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1737 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */));
1739 if (!NT_SUCCESS(Status
))
1742 * Load the driver module
1745 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, &BaseAddress
);
1746 if (!NT_SUCCESS(Status
) && Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1748 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1749 IopFreeDeviceNode(DeviceNode
);
1750 LoadParams
->Status
= Status
;
1751 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1756 * Set a service name for the device node
1759 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
);
1762 * Initialize the driver module if it's loaded for the first time
1764 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1766 Status
= IopInitializeDriverModule(
1769 &DeviceNode
->ServiceName
,
1770 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1771 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1774 if (!NT_SUCCESS(Status
))
1776 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1777 MmUnloadSystemImage(ModuleObject
);
1778 IopFreeDeviceNode(DeviceNode
);
1779 LoadParams
->Status
= Status
;
1780 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1785 /* Store its DriverSection, so that it could be unloaded */
1786 DriverObject
->DriverSection
= ModuleObject
;
1788 /* Initialize and start device */
1789 IopInitializeDevice(DeviceNode
, DriverObject
);
1790 Status
= IopStartDevice(DeviceNode
);
1794 DPRINT("DriverObject already exist in ObjectManager\n");
1796 /* IopGetDriverObject references the DriverObject, so dereference it */
1797 ObDereferenceObject(DriverObject
);
1799 /* Free device node since driver loading failed */
1800 IopFreeDeviceNode(DeviceNode
);
1803 /* Pass status to the caller and signal the event */
1804 LoadParams
->Status
= Status
;
1805 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1811 * Loads a device driver.
1815 * Name of the service to load (registry key).
1824 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1826 UNICODE_STRING CapturedDriverServiceName
= { 0, 0, NULL
};
1827 KPROCESSOR_MODE PreviousMode
;
1828 LOAD_UNLOAD_PARAMS LoadParams
;
1833 PreviousMode
= KeGetPreviousMode();
1836 * Check security privileges
1839 /* FIXME: Uncomment when privileges will be correctly implemented. */
1841 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1843 DPRINT("Privilege not held\n");
1844 return STATUS_PRIVILEGE_NOT_HELD
;
1848 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
1851 if (!NT_SUCCESS(Status
))
1856 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1858 LoadParams
.ServiceName
= &CapturedDriverServiceName
;
1859 LoadParams
.DriverObject
= NULL
;
1860 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1862 /* Call the load/unload routine, depending on current process */
1863 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1865 /* Just call right away */
1866 IopLoadUnloadDriver(&LoadParams
);
1870 /* Load/Unload must be called from system process */
1871 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1872 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1873 (PVOID
)&LoadParams
);
1876 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1878 /* And wait when it completes */
1879 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1883 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
1886 return LoadParams
.Status
;
1892 * Unloads a legacy device driver.
1896 * Name of the service to unload (registry key).
1906 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
1908 return IopUnloadDriver(DriverServiceName
, FALSE
);