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
;
36 /* PRIVATE FUNCTIONS **********************************************************/
39 IopInvalidDeviceRequest(
40 PDEVICE_OBJECT DeviceObject
,
43 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
44 Irp
->IoStatus
.Information
= 0;
45 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
46 return STATUS_INVALID_DEVICE_REQUEST
;
51 IopDeleteDriver(IN PVOID ObjectBody
)
53 PDRIVER_OBJECT DriverObject
= ObjectBody
;
54 PIO_CLIENT_EXTENSION DriverExtension
, NextDriverExtension
;
57 /* Get the extension and loop them */
58 DriverExtension
= IoGetDrvObjExtension(DriverObject
)->
59 ClientDriverExtension
;
60 while (DriverExtension
)
62 /* Get the next one */
63 NextDriverExtension
= DriverExtension
->NextExtension
;
64 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
67 DriverExtension
= NextDriverExtension
;
70 /* Check if the driver image is still loaded */
71 if (DriverObject
->DriverSection
)
74 //LdrpUnloadImage(DriverObject->DriverSection);
77 /* Check if it has a name */
78 if (DriverObject
->DriverName
.Buffer
)
81 ExFreePool(DriverObject
->DriverName
.Buffer
);
84 #if 0 /* See a bit of hack in IopCreateDriver */
85 /* Check if it has a service key name */
86 if (DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
)
89 ExFreePool(DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
);
96 PDRIVER_OBJECT
*DriverObject
,
97 PUNICODE_STRING ServiceName
,
100 PDRIVER_OBJECT Object
;
101 WCHAR NameBuffer
[MAX_PATH
];
102 UNICODE_STRING DriverName
;
105 DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
106 DriverObject
, ServiceName
, FileSystem
);
108 *DriverObject
= NULL
;
110 /* Create ModuleName string */
111 if (ServiceName
== NULL
|| ServiceName
->Buffer
== NULL
)
112 /* We don't know which DriverObject we have to open */
113 return STATUS_INVALID_PARAMETER_2
;
115 DriverName
.Buffer
= NameBuffer
;
116 DriverName
.Length
= 0;
117 DriverName
.MaximumLength
= sizeof(NameBuffer
);
119 if (FileSystem
== TRUE
)
120 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
122 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
123 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
125 DPRINT("Driver name: '%wZ'\n", &DriverName
);
127 /* Open driver object */
128 Status
= ObReferenceObjectByName(
130 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, /* Attributes */
131 NULL
, /* PassedAccessState */
132 0, /* DesiredAccess */
135 NULL
, /* ParseContext */
138 if (!NT_SUCCESS(Status
))
140 DPRINT("Failed to reference driver object, status=0x%08x\n", Status
);
144 *DriverObject
= Object
;
146 DPRINT("Driver Object: %p\n", Object
);
148 return STATUS_SUCCESS
;
152 * IopDisplayLoadingMessage
154 * Display 'Loading XXX...' message.
160 IopDisplayLoadingMessage(PVOID ServiceName
,
163 CHAR TextBuffer
[256];
164 PCHAR Extra
= ".sys";
166 if (ExpInTextModeSetup
) return;
169 if (wcsstr(_wcsupr(ServiceName
), L
".SYS")) Extra
= "";
172 KeLoaderBlock
->ArcBootDeviceName
,
173 KeLoaderBlock
->NtBootPathName
,
180 if (strstr(_strupr(ServiceName
), ".SYS")) Extra
= "";
183 KeLoaderBlock
->ArcBootDeviceName
,
184 KeLoaderBlock
->NtBootPathName
,
189 HalDisplayString(TextBuffer
);
193 * IopNormalizeImagePath
195 * Normalize an image path to contain complete path.
199 * The input path and on exit the result path. ImagePath.Buffer
200 * must be allocated by ExAllocatePool on input. Caller is responsible
201 * for freeing the buffer when it's no longer needed.
204 * Name of the service that ImagePath belongs to.
210 * The input image path isn't freed on error.
214 IopNormalizeImagePath(
215 IN OUT PUNICODE_STRING ImagePath
,
216 IN PUNICODE_STRING ServiceName
)
218 UNICODE_STRING InputImagePath
;
223 sizeof(UNICODE_STRING
));
225 if (InputImagePath
.Length
== 0)
227 ImagePath
->Length
= 0;
228 ImagePath
->MaximumLength
=
229 (33 * sizeof(WCHAR
)) + ServiceName
->Length
+ sizeof(UNICODE_NULL
);
230 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
231 if (ImagePath
->Buffer
== NULL
)
232 return STATUS_NO_MEMORY
;
234 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\system32\\drivers\\");
235 RtlAppendUnicodeStringToString(ImagePath
, ServiceName
);
236 RtlAppendUnicodeToString(ImagePath
, L
".sys");
238 if (InputImagePath
.Buffer
[0] != L
'\\')
240 ImagePath
->Length
= 0;
241 ImagePath
->MaximumLength
=
242 12 * sizeof(WCHAR
) + InputImagePath
.Length
+ sizeof(UNICODE_NULL
);
243 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
244 if (ImagePath
->Buffer
== NULL
)
245 return STATUS_NO_MEMORY
;
247 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\");
248 RtlAppendUnicodeStringToString(ImagePath
, &InputImagePath
);
250 /* Free caller's string */
251 ExFreePoolWithTag(InputImagePath
.Buffer
, TAG_RTLREGISTRY
);
254 return STATUS_SUCCESS
;
258 * IopLoadServiceModule
260 * Load a module specified by registry settings for service.
264 * Name of the service to load.
271 IopLoadServiceModule(
272 IN PUNICODE_STRING ServiceName
,
273 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
275 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
277 UNICODE_STRING ServiceImagePath
, CCSName
;
279 HANDLE CCSKey
, ServiceKey
;
282 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
284 /* FIXME: This check may be removed once the bug is fixed */
285 if (ServiceName
->Buffer
== NULL
)
287 DPRINT1("If you see this, please report to Fireball or hpoussin!\n");
288 return STATUS_UNSUCCESSFUL
;
291 /* Open CurrentControlSet */
292 RtlInitUnicodeString(&CCSName
,
293 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
294 Status
= IopOpenRegistryKeyEx(&CCSKey
, NULL
, &CCSName
, KEY_READ
);
295 if (!NT_SUCCESS(Status
))
297 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
301 /* Open service key */
302 Status
= IopOpenRegistryKeyEx(&ServiceKey
, CCSKey
, ServiceName
, KEY_READ
);
303 if (!NT_SUCCESS(Status
))
305 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
311 * Get information about the service.
314 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
316 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
318 QueryTable
[0].Name
= L
"Start";
319 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
320 QueryTable
[0].EntryContext
= &ServiceStart
;
322 QueryTable
[1].Name
= L
"ImagePath";
323 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
324 QueryTable
[1].EntryContext
= &ServiceImagePath
;
326 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
327 (PWSTR
)ServiceKey
, QueryTable
, NULL
, NULL
);
332 if (!NT_SUCCESS(Status
))
334 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
339 * Normalize the image path for all later processing.
342 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
344 if (!NT_SUCCESS(Status
))
346 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
351 * Case for disabled drivers
354 if (ServiceStart
>= 4)
356 /* FIXME: Check if it is the right status code */
357 Status
= STATUS_PLUGPLAY_NO_DEVICE
;
361 DPRINT("Loading module\n");
362 Status
= MmLoadSystemImage(&ServiceImagePath
, NULL
, NULL
, 0, (PVOID
)ModuleObject
, &BaseAddress
);
365 ExFreePool(ServiceImagePath
.Buffer
);
368 * Now check if the module was loaded successfully.
371 if (!NT_SUCCESS(Status
))
373 DPRINT("Module loading failed (Status %x)\n", Status
);
376 DPRINT("Module loading (Status %x)\n", Status
);
382 * IopInitializeDriverModule
384 * Initalize a loaded driver.
388 * Pointer to device node.
391 * Module object representing the driver. It can be retrieve by
392 * IopLoadServiceModule.
395 * Name of the service (as in registry).
398 * Set to TRUE for file system drivers.
401 * On successful return this contains the driver object representing
406 IopInitializeDriverModule(
407 IN PDEVICE_NODE DeviceNode
,
408 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
409 IN PUNICODE_STRING ServiceName
,
410 IN BOOLEAN FileSystemDriver
,
411 OUT PDRIVER_OBJECT
*DriverObject
)
413 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
414 WCHAR NameBuffer
[MAX_PATH
];
415 UNICODE_STRING DriverName
;
416 UNICODE_STRING RegistryKey
;
417 PDRIVER_INITIALIZE DriverEntry
;
418 PDRIVER_OBJECT Driver
;
419 PDEVICE_OBJECT DeviceObject
;
422 DriverEntry
= ModuleObject
->EntryPoint
;
424 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
426 RegistryKey
.Length
= 0;
427 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
428 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
429 if (RegistryKey
.Buffer
== NULL
)
431 return STATUS_INSUFFICIENT_RESOURCES
;
433 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
434 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
438 RtlInitUnicodeString(&RegistryKey
, NULL
);
441 /* Create ModuleName string */
442 if (ServiceName
&& ServiceName
->Length
> 0)
444 if (FileSystemDriver
== TRUE
)
445 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
447 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
449 RtlInitUnicodeString(&DriverName
, NameBuffer
);
450 DriverName
.MaximumLength
= sizeof(NameBuffer
);
452 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
454 DPRINT("Driver name: '%wZ'\n", &DriverName
);
457 DriverName
.Length
= 0;
459 Status
= IopCreateDriver(
460 DriverName
.Length
> 0 ? &DriverName
: NULL
,
463 ModuleObject
->DllBase
,
464 ModuleObject
->SizeOfImage
,
466 RtlFreeUnicodeString(&RegistryKey
);
468 *DriverObject
= Driver
;
469 if (!NT_SUCCESS(Status
))
471 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status
);
475 /* Set the driver as initialized */
476 Driver
->Flags
|= DRVO_INITIALIZED
;
477 DeviceObject
= Driver
->DeviceObject
;
480 /* Set every device as initialized too */
481 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
482 DeviceObject
= DeviceObject
->NextDevice
;
485 IopReinitializeDrivers();
487 return STATUS_SUCCESS
;
491 * IopAttachFilterDriversCallback
493 * Internal routine used by IopAttachFilterDrivers.
497 IopAttachFilterDriversCallback(
505 PDEVICE_NODE DeviceNode
= Context
;
506 UNICODE_STRING ServiceName
;
508 PLDR_DATA_TABLE_ENTRY ModuleObject
;
509 PDRIVER_OBJECT DriverObject
;
512 for (Filters
= ValueData
;
513 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
515 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
517 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
518 ServiceName
.Buffer
= Filters
;
519 ServiceName
.MaximumLength
=
520 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
522 /* Load and initialize the filter driver */
523 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
524 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
526 if (!NT_SUCCESS(Status
))
529 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
530 FALSE
, &DriverObject
);
531 if (!NT_SUCCESS(Status
))
536 /* get existing DriverObject pointer */
537 Status
= IopGetDriverObject(
541 if (!NT_SUCCESS(Status
))
543 DPRINT1("IopGetDriverObject() returned status 0x%08x!\n", Status
);
548 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
549 if (!NT_SUCCESS(Status
))
553 return STATUS_SUCCESS
;
557 * IopAttachFilterDrivers
559 * Load filter drivers for specified device node.
563 * Set to TRUE for loading lower level filters or FALSE for upper
568 IopAttachFilterDrivers(
569 PDEVICE_NODE DeviceNode
,
572 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = {{0}};
573 UNICODE_STRING Class
;
574 WCHAR ClassBuffer
[40];
575 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
576 HANDLE EnumRootKey
, SubKey
;
579 /* Open enumeration root key */
580 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
581 &EnumRoot
, KEY_READ
);
582 if (!NT_SUCCESS(Status
))
584 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
589 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
590 &DeviceNode
->InstancePath
, KEY_READ
);
591 if (!NT_SUCCESS(Status
))
593 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
594 ZwClose(EnumRootKey
);
599 * First load the device filters
601 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
603 QueryTable
[0].Name
= L
"LowerFilters";
605 QueryTable
[0].Name
= L
"UpperFilters";
606 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
608 RtlQueryRegistryValues(
616 * Now get the class GUID
619 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
620 Class
.Buffer
= ClassBuffer
;
621 QueryTable
[0].QueryRoutine
= NULL
;
622 QueryTable
[0].Name
= L
"ClassGUID";
623 QueryTable
[0].EntryContext
= &Class
;
624 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
626 Status
= RtlQueryRegistryValues(
635 ZwClose(EnumRootKey
);
638 * Load the class filter driver
640 if (NT_SUCCESS(Status
))
642 UNICODE_STRING ControlClass
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
644 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
645 &ControlClass
, KEY_READ
);
646 if (!NT_SUCCESS(Status
))
648 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
653 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
655 if (!NT_SUCCESS(Status
))
657 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
658 ZwClose(EnumRootKey
);
662 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
664 QueryTable
[0].Name
= L
"LowerFilters";
666 QueryTable
[0].Name
= L
"UpperFilters";
667 QueryTable
[0].EntryContext
= NULL
;
668 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
670 RtlQueryRegistryValues(
679 ZwClose(EnumRootKey
);
682 return STATUS_SUCCESS
;
687 MiResolveImageReferences(IN PVOID ImageBase
,
688 IN PUNICODE_STRING ImageFileDirectory
,
689 IN PUNICODE_STRING NamePrefix OPTIONAL
,
690 OUT PCHAR
*MissingApi
,
691 OUT PWCHAR
*MissingDriver
,
692 OUT PLOAD_IMPORTS
*LoadImports
);
694 extern KSPIN_LOCK PsLoadedModuleSpinLock
;
697 // Used for images already loaded (boot drivers)
701 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry
,
702 PUNICODE_STRING FileName
,
703 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
706 PLDR_DATA_TABLE_ENTRY NewEntry
;
707 UNICODE_STRING BaseName
, BaseDirectory
;
708 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
709 PCHAR MissingApiName
, Buffer
;
710 PWCHAR MissingDriverName
;
711 PVOID DriverBase
= LdrEntry
->DllBase
;
713 /* Allocate a buffer we'll use for names */
714 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
718 return STATUS_INSUFFICIENT_RESOURCES
;
721 /* Check for a separator */
722 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
727 /* Loop the path until we get to the base name */
728 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
729 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
732 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
733 BaseLength
*= sizeof(WCHAR
);
735 /* Setup the string */
736 BaseName
.Length
= (USHORT
)BaseLength
;
741 /* Otherwise, we already have a base name */
742 BaseName
.Length
= FileName
->Length
;
743 BaseName
.Buffer
= FileName
->Buffer
;
746 /* Setup the maximum length */
747 BaseName
.MaximumLength
= BaseName
.Length
;
749 /* Now compute the base directory */
750 BaseDirectory
= *FileName
;
751 BaseDirectory
.Length
-= BaseName
.Length
;
752 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
756 /* Resolve imports */
757 MissingApiName
= Buffer
;
758 Status
= MiResolveImageReferences(DriverBase
,
764 if (!NT_SUCCESS(Status
)) return Status
;
767 *ModuleObject
= LdrEntry
;
768 return STATUS_SUCCESS
;
772 * IopInitializeBuiltinDriver
774 * Initialize a driver that is already loaded in memory.
779 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
781 PDEVICE_NODE DeviceNode
;
782 PDRIVER_OBJECT DriverObject
;
784 PWCHAR FileNameWithoutPath
;
785 LPWSTR FileExtension
;
786 PUNICODE_STRING ModuleName
= &LdrEntry
->BaseDllName
;
787 UNICODE_STRING ServiceName
;
790 * Display 'Loading XXX...' message
792 IopDisplayLoadingMessage(ModuleName
->Buffer
, TRUE
);
795 * Generate filename without path (not needed by freeldr)
797 FileNameWithoutPath
= wcsrchr(ModuleName
->Buffer
, L
'\\');
798 if (FileNameWithoutPath
== NULL
)
800 FileNameWithoutPath
= ModuleName
->Buffer
;
804 FileNameWithoutPath
++;
808 * Strip the file extension from ServiceName
810 RtlCreateUnicodeString(&ServiceName
, FileNameWithoutPath
);
811 FileExtension
= wcsrchr(ServiceName
.Buffer
, '.');
812 if (FileExtension
!= NULL
)
814 ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
815 FileExtension
[0] = 0;
819 * Determine the right device object
821 /* Use IopRootDeviceNode for now */
822 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
823 if (!NT_SUCCESS(Status
))
825 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
828 DeviceNode
->ServiceName
= ServiceName
;
831 * Initialize the driver
833 Status
= IopInitializeDriverModule(DeviceNode
, LdrEntry
,
834 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
836 if (!NT_SUCCESS(Status
))
838 IopFreeDeviceNode(DeviceNode
);
842 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
843 if (NT_SUCCESS(Status
))
845 Status
= IopStartDevice(DeviceNode
);
852 * IopInitializeBootDrivers
854 * Initialize boot drivers and free memory for boot files.
864 IopInitializeBootDrivers(VOID
)
866 PLIST_ENTRY ListHead
, NextEntry
;
867 PLDR_DATA_TABLE_ENTRY LdrEntry
;
868 PDEVICE_NODE DeviceNode
;
869 PDRIVER_OBJECT DriverObject
;
870 LDR_DATA_TABLE_ENTRY ModuleObject
;
872 UNICODE_STRING DriverName
;
874 DPRINT("IopInitializeBootDrivers()\n");
876 /* Use IopRootDeviceNode for now */
877 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, NULL
, &DeviceNode
);
878 if (!NT_SUCCESS(Status
)) return;
880 /* Setup the module object for the RAW FS Driver */
881 ModuleObject
.DllBase
= NULL
;
882 ModuleObject
.SizeOfImage
= 0;
883 ModuleObject
.EntryPoint
= RawFsDriverEntry
;
884 RtlInitUnicodeString(&DriverName
, L
"RAW");
887 Status
= IopInitializeDriverModule(DeviceNode
,
892 if (!NT_SUCCESS(Status
))
895 IopFreeDeviceNode(DeviceNode
);
899 /* Now initialize the associated device */
900 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
901 if (!NT_SUCCESS(Status
))
904 IopFreeDeviceNode(DeviceNode
);
909 Status
= IopStartDevice(DeviceNode
);
910 if (!NT_SUCCESS(Status
))
913 IopFreeDeviceNode(DeviceNode
);
917 /* Loop the boot modules */
918 ListHead
= &KeLoaderBlock
->LoadOrderListHead
;
919 NextEntry
= ListHead
->Flink
;
920 while (ListHead
!= NextEntry
)
923 LdrEntry
= CONTAINING_RECORD(NextEntry
,
924 LDR_DATA_TABLE_ENTRY
,
928 * HACK: Make sure we're loading a driver
929 * (we should be using BootDriverListHead!)
931 if (wcsstr(_wcsupr(LdrEntry
->BaseDllName
.Buffer
), L
".SYS"))
933 /* Make sure we didn't load this driver already */
934 if (!(LdrEntry
->Flags
& LDRP_ENTRY_INSERTED
))
936 DPRINT("Initializing bootdriver %wZ\n", &LdrEntry
->BaseDllName
);
938 IopInitializeBuiltinDriver(LdrEntry
);
942 /* Go to the next driver */
943 NextEntry
= NextEntry
->Flink
;
946 /* In old ROS, the loader list became empty after this point. Simulate. */
947 InitializeListHead(&KeLoaderBlock
->LoadOrderListHead
);
953 * Unloads a device driver.
957 * Name of the service to unload (registry key).
960 * Whether to unload Plug & Plug or only legacy drivers. If this
961 * parameter is set to FALSE, the routine will unload only legacy
968 * Guard the whole function by SEH.
972 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
974 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
975 UNICODE_STRING ImagePath
;
976 UNICODE_STRING ServiceName
;
977 UNICODE_STRING ObjectName
;
978 PDRIVER_OBJECT DriverObject
;
979 LOAD_UNLOAD_PARAMS LoadParams
;
983 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
988 * Get the service name from the registry key name
991 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
993 Start
= DriverServiceName
->Buffer
;
997 RtlInitUnicodeString(&ServiceName
, Start
);
1000 * Construct the driver object name
1003 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1004 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1005 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1006 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1007 memcpy(ObjectName
.Buffer
+ 8, Start
, ObjectName
.Length
- 8 * sizeof(WCHAR
));
1008 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1011 * Find the driver object
1013 Status
= ObReferenceObjectByName(&ObjectName
,
1020 (PVOID
*)&DriverObject
);
1023 * Free the buffer for driver object name
1025 ExFreePool(ObjectName
.Buffer
);
1027 if (!NT_SUCCESS(Status
))
1029 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName
);
1034 * Get path of service...
1037 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1039 RtlInitUnicodeString(&ImagePath
, NULL
);
1041 QueryTable
[0].Name
= L
"ImagePath";
1042 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1043 QueryTable
[0].EntryContext
= &ImagePath
;
1045 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1046 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1048 if (!NT_SUCCESS(Status
))
1050 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1055 * Normalize the image path for all later processing.
1058 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1060 if (!NT_SUCCESS(Status
))
1062 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1067 * Free the service path
1070 ExFreePool(ImagePath
.Buffer
);
1073 * Unload the module and release the references to the device object
1076 /* Call the load/unload routine, depending on current process */
1077 if (DriverObject
->DriverUnload
&& DriverObject
->DriverSection
)
1079 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1081 /* Just call right away */
1082 (*DriverObject
->DriverUnload
)(DriverObject
);
1086 /* Load/Unload must be called from system process */
1088 /* Prepare parameters block */
1089 LoadParams
.DriverObject
= DriverObject
;
1090 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1092 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1093 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1094 (PVOID
)&LoadParams
);
1097 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1099 /* And wait when it completes */
1100 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1104 /* Mark the driver object temporary, so it could be deleted later */
1105 ObMakeTemporaryObject(DriverObject
);
1107 /* Dereference it 2 times */
1108 ObDereferenceObject(DriverObject
);
1109 ObDereferenceObject(DriverObject
);
1111 /* Unload the driver */
1112 MmUnloadSystemImage(DriverObject
->DriverSection
);
1114 return STATUS_SUCCESS
;
1118 /* Dereference one time (refd inside this function) */
1119 ObDereferenceObject(DriverObject
);
1121 /* Return unloading failure */
1122 return STATUS_INVALID_DEVICE_REQUEST
;
1128 IopReinitializeDrivers(VOID
)
1130 PDRIVER_REINIT_ITEM ReinitItem
;
1133 /* Get the first entry and start looping */
1134 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1135 &DriverReinitListLock
);
1139 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1141 /* Increment reinitialization counter */
1142 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1144 /* Remove the device object flag */
1145 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1147 /* Call the routine */
1148 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1149 ReinitItem
->Context
,
1150 ReinitItem
->DriverObject
->
1151 DriverExtension
->Count
);
1153 /* Free the entry */
1156 /* Move to the next one */
1157 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1158 &DriverReinitListLock
);
1164 IopReinitializeBootDrivers(VOID
)
1166 PDRIVER_REINIT_ITEM ReinitItem
;
1169 /* Get the first entry and start looping */
1170 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1171 &DriverBootReinitListLock
);
1175 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1177 /* Increment reinitialization counter */
1178 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1180 /* Remove the device object flag */
1181 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1183 /* Call the routine */
1184 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1185 ReinitItem
->Context
,
1186 ReinitItem
->DriverObject
->
1187 DriverExtension
->Count
);
1189 /* Free the entry */
1192 /* Move to the next one */
1193 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1194 &DriverBootReinitListLock
);
1200 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1201 IN PDRIVER_INITIALIZE InitializationFunction
,
1202 IN PUNICODE_STRING RegistryPath
,
1204 IN ULONG SizeOfImage
,
1205 OUT PDRIVER_OBJECT
*pDriverObject
)
1207 WCHAR NameBuffer
[100];
1209 UNICODE_STRING LocalDriverName
;
1211 OBJECT_ATTRIBUTES ObjectAttributes
;
1213 PDRIVER_OBJECT DriverObject
;
1214 UNICODE_STRING ServiceKeyName
;
1216 ULONG i
, RetryCount
= 0;
1219 /* First, create a unique name for the driver if we don't have one */
1222 /* Create a random name and set up the string*/
1223 NameLength
= (USHORT
)swprintf(NameBuffer
,
1226 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1227 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1228 LocalDriverName
.Buffer
= NameBuffer
;
1232 /* So we can avoid another code path, use a local var */
1233 LocalDriverName
= *DriverName
;
1236 /* Initialize the Attributes */
1237 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1238 InitializeObjectAttributes(&ObjectAttributes
,
1240 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1244 /* Create the Object */
1245 Status
= ObCreateObject(KernelMode
,
1253 (PVOID
*)&DriverObject
);
1254 if (!NT_SUCCESS(Status
)) return Status
;
1256 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1258 /* Set up the Object */
1259 RtlZeroMemory(DriverObject
, ObjectSize
);
1260 DriverObject
->Type
= IO_TYPE_DRIVER
;
1261 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1262 DriverObject
->Flags
= DRVO_BUILTIN_DRIVER
;
1263 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1264 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1265 DriverObject
->DriverInit
= InitializationFunction
;
1267 /* Loop all Major Functions */
1268 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1270 /* Invalidate each function */
1271 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1274 /* Set up the service key name buffer */
1275 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1276 LocalDriverName
.Length
+
1279 if (!ServiceKeyName
.Buffer
)
1282 ObMakeTemporaryObject(DriverObject
);
1283 ObDereferenceObject(DriverObject
);
1284 return STATUS_INSUFFICIENT_RESOURCES
;
1287 /* Fill out the key data and copy the buffer */
1288 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1289 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1290 RtlCopyMemory(ServiceKeyName
.Buffer
,
1291 LocalDriverName
.Buffer
,
1292 LocalDriverName
.Length
);
1294 /* Null-terminate it and set it */
1295 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1296 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1298 /* Also store it in the Driver Object. This is a bit of a hack. */
1299 RtlCopyMemory(&DriverObject
->DriverName
,
1301 sizeof(UNICODE_STRING
));
1303 /* Add the Object and get its handle */
1304 Status
= ObInsertObject(DriverObject
,
1311 /* Eliminate small possibility when this function is called more than
1312 once in a row, and KeTickCount doesn't get enough time to change */
1313 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1319 if (!NT_SUCCESS(Status
)) return Status
;
1321 /* Now reference it */
1322 Status
= ObReferenceObjectByHandle(hDriver
,
1326 (PVOID
*)&DriverObject
,
1328 if (!NT_SUCCESS(Status
))
1331 ObMakeTemporaryObject(DriverObject
);
1332 ObDereferenceObject(DriverObject
);
1336 /* Close the extra handle */
1339 DriverObject
->HardwareDatabase
= &IopHardwareDatabaseKey
;
1340 DriverObject
->DriverStart
= DllBase
;
1341 DriverObject
->DriverSize
= SizeOfImage
;
1343 /* Finally, call its init function */
1344 DPRINT("RegistryKey: %wZ\n", RegistryPath
);
1345 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction
);
1346 Status
= (*InitializationFunction
)(DriverObject
, RegistryPath
);
1347 if (!NT_SUCCESS(Status
))
1349 /* If it didn't work, then kill the object */
1350 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName
, Status
);
1351 ObMakeTemporaryObject(DriverObject
);
1352 ObDereferenceObject(DriverObject
);
1356 /* Returns to caller the object */
1357 *pDriverObject
= DriverObject
;
1360 /* Return the Status */
1364 /* PUBLIC FUNCTIONS ***********************************************************/
1371 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1372 IN PDRIVER_INITIALIZE InitializationFunction
)
1374 PDRIVER_OBJECT DriverObject
;
1375 return IopCreateDriver(DriverName
, InitializationFunction
, NULL
, 0, 0, &DriverObject
);
1383 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1385 /* Simply dereference the Object */
1386 ObDereferenceObject(DriverObject
);
1394 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1395 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1398 PDRIVER_REINIT_ITEM ReinitItem
;
1400 /* Allocate the entry */
1401 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1402 sizeof(DRIVER_REINIT_ITEM
),
1404 if (!ReinitItem
) return;
1407 ReinitItem
->DriverObject
= DriverObject
;
1408 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1409 ReinitItem
->Context
= Context
;
1411 /* Set the Driver Object flag and insert the entry into the list */
1412 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1413 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1414 &ReinitItem
->ItemEntry
,
1415 &DriverBootReinitListLock
);
1423 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1424 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1427 PDRIVER_REINIT_ITEM ReinitItem
;
1429 /* Allocate the entry */
1430 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1431 sizeof(DRIVER_REINIT_ITEM
),
1433 if (!ReinitItem
) return;
1436 ReinitItem
->DriverObject
= DriverObject
;
1437 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1438 ReinitItem
->Context
= Context
;
1440 /* Set the Driver Object flag and insert the entry into the list */
1441 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1442 ExInterlockedInsertTailList(&DriverReinitListHead
,
1443 &ReinitItem
->ItemEntry
,
1444 &DriverReinitListLock
);
1452 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1453 IN PVOID ClientIdentificationAddress
,
1454 IN ULONG DriverObjectExtensionSize
,
1455 OUT PVOID
*DriverObjectExtension
)
1458 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1459 BOOLEAN Inserted
= FALSE
;
1461 /* Assume failure */
1462 *DriverObjectExtension
= NULL
;
1464 /* Allocate the extension */
1465 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1466 sizeof(IO_CLIENT_EXTENSION
) +
1467 DriverObjectExtensionSize
,
1468 TAG_DRIVER_EXTENSION
);
1469 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1471 /* Clear the extension for teh caller */
1472 RtlZeroMemory(NewDriverExtension
,
1473 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1476 OldIrql
= KeRaiseIrqlToDpcLevel();
1478 /* Fill out the extension */
1479 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1481 /* Loop the current extensions */
1482 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1483 ClientDriverExtension
;
1484 while (DriverExtensions
)
1486 /* Check if the identifier matches */
1487 if (DriverExtensions
->ClientIdentificationAddress
==
1488 ClientIdentificationAddress
)
1490 /* We have a collision, break out */
1494 /* Go to the next one */
1495 DriverExtensions
= DriverExtensions
->NextExtension
;
1498 /* Check if we didn't collide */
1499 if (!DriverExtensions
)
1501 /* Link this one in */
1502 NewDriverExtension
->NextExtension
=
1503 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1504 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1509 /* Release the lock */
1510 KeLowerIrql(OldIrql
);
1512 /* Check if insertion failed */
1515 /* Free the entry and fail */
1516 ExFreePool(NewDriverExtension
);
1517 return STATUS_OBJECT_NAME_COLLISION
;
1520 /* Otherwise, return the pointer */
1521 *DriverObjectExtension
= NewDriverExtension
+ 1;
1522 return STATUS_SUCCESS
;
1530 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1531 IN PVOID ClientIdentificationAddress
)
1534 PIO_CLIENT_EXTENSION DriverExtensions
;
1537 OldIrql
= KeRaiseIrqlToDpcLevel();
1539 /* Loop the list until we find the right one */
1540 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1541 while (DriverExtensions
)
1543 /* Check for a match */
1544 if (DriverExtensions
->ClientIdentificationAddress
==
1545 ClientIdentificationAddress
)
1552 DriverExtensions
= DriverExtensions
->NextExtension
;
1556 KeLowerIrql(OldIrql
);
1558 /* Return nothing or the extension */
1559 if (!DriverExtensions
) return NULL
;
1560 return DriverExtensions
+ 1;
1564 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams
)
1566 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1567 UNICODE_STRING ImagePath
;
1568 UNICODE_STRING ServiceName
;
1571 PDEVICE_NODE DeviceNode
;
1572 PDRIVER_OBJECT DriverObject
;
1573 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1577 /* Check if it's an unload request */
1578 if (LoadParams
->DriverObject
)
1580 (*LoadParams
->DriverObject
->DriverUnload
)(LoadParams
->DriverObject
);
1582 /* Return success and signal the event */
1583 LoadParams
->Status
= STATUS_SUCCESS
;
1584 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1588 RtlInitUnicodeString(&ImagePath
, NULL
);
1591 * Get the service name from the registry key name.
1593 ASSERT(LoadParams
->ServiceName
->Length
>= sizeof(WCHAR
));
1595 ServiceName
= *LoadParams
->ServiceName
;
1596 cur
= LoadParams
->ServiceName
->Buffer
+
1597 (LoadParams
->ServiceName
->Length
/ sizeof(WCHAR
)) - 1;
1598 while (LoadParams
->ServiceName
->Buffer
!= cur
)
1602 ServiceName
.Buffer
= cur
+ 1;
1603 ServiceName
.Length
= LoadParams
->ServiceName
->Length
-
1604 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1605 (ULONG_PTR
)LoadParams
->ServiceName
->Buffer
);
1615 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1617 RtlInitUnicodeString(&ImagePath
, NULL
);
1619 QueryTable
[0].Name
= L
"Type";
1620 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1621 QueryTable
[0].EntryContext
= &Type
;
1623 QueryTable
[1].Name
= L
"ImagePath";
1624 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1625 QueryTable
[1].EntryContext
= &ImagePath
;
1627 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1628 LoadParams
->ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1630 if (!NT_SUCCESS(Status
))
1632 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1633 ExFreePool(ImagePath
.Buffer
);
1634 LoadParams
->Status
= Status
;
1635 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1640 * Normalize the image path for all later processing.
1643 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1645 if (!NT_SUCCESS(Status
))
1647 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1648 LoadParams
->Status
= Status
;
1649 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1653 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1654 DPRINT("Type: %lx\n", Type
);
1657 * Create device node
1660 /* Use IopRootDeviceNode for now */
1661 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1663 if (!NT_SUCCESS(Status
))
1665 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1666 LoadParams
->Status
= Status
;
1667 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1671 /* Get existing DriverObject pointer (in case the driver has
1672 already been loaded and initialized) */
1673 Status
= IopGetDriverObject(
1676 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1677 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */));
1679 if (!NT_SUCCESS(Status
))
1682 * Load the driver module
1685 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, &BaseAddress
);
1686 if (!NT_SUCCESS(Status
) && Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1688 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1689 IopFreeDeviceNode(DeviceNode
);
1690 LoadParams
->Status
= Status
;
1691 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1696 * Set a service name for the device node
1699 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
);
1702 * Initialize the driver module if it's loaded for the first time
1704 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1706 Status
= IopInitializeDriverModule(
1709 &DeviceNode
->ServiceName
,
1710 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1711 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1714 if (!NT_SUCCESS(Status
))
1716 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1717 MmUnloadSystemImage(ModuleObject
);
1718 IopFreeDeviceNode(DeviceNode
);
1719 LoadParams
->Status
= Status
;
1720 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1725 /* Store its DriverSection, so that it could be unloaded */
1726 DriverObject
->DriverSection
= ModuleObject
;
1729 IopInitializeDevice(DeviceNode
, DriverObject
);
1730 LoadParams
->Status
= IopStartDevice(DeviceNode
);
1731 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1737 * Loads a device driver.
1741 * Name of the service to load (registry key).
1750 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1752 UNICODE_STRING CapturedDriverServiceName
= {0};
1753 KPROCESSOR_MODE PreviousMode
;
1754 LOAD_UNLOAD_PARAMS LoadParams
;
1759 PreviousMode
= KeGetPreviousMode();
1762 * Check security privileges
1765 /* FIXME: Uncomment when privileges will be correctly implemented. */
1767 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1769 DPRINT("Privilege not held\n");
1770 return STATUS_PRIVILEGE_NOT_HELD
;
1774 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
1777 if (!NT_SUCCESS(Status
))
1782 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1784 LoadParams
.ServiceName
= &CapturedDriverServiceName
;
1785 LoadParams
.DriverObject
= NULL
;
1786 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1788 /* Call the load/unload routine, depending on current process */
1789 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1791 /* Just call right away */
1792 IopLoadUnloadDriver(&LoadParams
);
1796 /* Load/Unload must be called from system process */
1797 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1798 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1799 (PVOID
)&LoadParams
);
1802 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1804 /* And wait when it completes */
1805 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1809 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
1812 return LoadParams
.Status
;
1818 * Unloads a legacy device driver.
1822 * Name of the service to unload (registry key).
1832 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
1834 return IopUnloadDriver(DriverServiceName
, FALSE
);