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 LOAD_UNLOAD_PARAMS LoadParams
;
984 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
989 * Get the service name from the registry key name
992 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
994 Start
= DriverServiceName
->Buffer
;
998 RtlInitUnicodeString(&ServiceName
, Start
);
1001 * Construct the driver object name
1004 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1005 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1006 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1007 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1008 memcpy(ObjectName
.Buffer
+ 8, Start
, ObjectName
.Length
- 8 * sizeof(WCHAR
));
1009 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1012 * Find the driver object
1014 Status
= ObReferenceObjectByName(&ObjectName
,
1021 (PVOID
*)&DriverObject
);
1024 * Free the buffer for driver object name
1026 ExFreePool(ObjectName
.Buffer
);
1028 if (!NT_SUCCESS(Status
))
1030 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName
);
1035 * Get path of service...
1038 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1040 RtlInitUnicodeString(&ImagePath
, NULL
);
1042 QueryTable
[0].Name
= L
"ImagePath";
1043 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1044 QueryTable
[0].EntryContext
= &ImagePath
;
1046 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1047 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1049 if (!NT_SUCCESS(Status
))
1051 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1056 * Normalize the image path for all later processing.
1059 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1061 if (!NT_SUCCESS(Status
))
1063 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1068 * Free the service path
1071 ExFreePool(ImagePath
.Buffer
);
1074 * Unload the module and release the references to the device object
1077 /* Call the load/unload routine, depending on current process */
1078 if (DriverObject
->DriverUnload
&& DriverObject
->DriverSection
)
1080 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1082 /* Just call right away */
1083 (*DriverObject
->DriverUnload
)(DriverObject
);
1087 /* Load/Unload must be called from system process */
1089 /* Prepare parameters block */
1090 LoadParams
.DriverObject
= DriverObject
;
1091 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1093 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1094 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1095 (PVOID
)&LoadParams
);
1098 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1100 /* And wait when it completes */
1101 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1105 /* Mark the driver object temporary, so it could be deleted later */
1106 ObMakeTemporaryObject(DriverObject
);
1108 /* Dereference it 2 times */
1109 ObDereferenceObject(DriverObject
);
1110 ObDereferenceObject(DriverObject
);
1112 return STATUS_SUCCESS
;
1116 /* Dereference one time (refd inside this function) */
1117 ObDereferenceObject(DriverObject
);
1119 /* Return unloading failure */
1120 return STATUS_INVALID_DEVICE_REQUEST
;
1126 IopReinitializeDrivers(VOID
)
1128 PDRIVER_REINIT_ITEM ReinitItem
;
1131 /* Get the first entry and start looping */
1132 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1133 &DriverReinitListLock
);
1137 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1139 /* Increment reinitialization counter */
1140 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1142 /* Remove the device object flag */
1143 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1145 /* Call the routine */
1146 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1147 ReinitItem
->Context
,
1148 ReinitItem
->DriverObject
->
1149 DriverExtension
->Count
);
1151 /* Free the entry */
1154 /* Move to the next one */
1155 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1156 &DriverReinitListLock
);
1162 IopReinitializeBootDrivers(VOID
)
1164 PDRIVER_REINIT_ITEM ReinitItem
;
1167 /* Get the first entry and start looping */
1168 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1169 &DriverBootReinitListLock
);
1173 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1175 /* Increment reinitialization counter */
1176 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1178 /* Remove the device object flag */
1179 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1181 /* Call the routine */
1182 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1183 ReinitItem
->Context
,
1184 ReinitItem
->DriverObject
->
1185 DriverExtension
->Count
);
1187 /* Free the entry */
1190 /* Move to the next one */
1191 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1192 &DriverBootReinitListLock
);
1198 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1199 IN PDRIVER_INITIALIZE InitializationFunction
,
1200 IN PUNICODE_STRING RegistryPath
,
1202 IN ULONG SizeOfImage
,
1203 OUT PDRIVER_OBJECT
*pDriverObject
)
1205 WCHAR NameBuffer
[100];
1207 UNICODE_STRING LocalDriverName
;
1209 OBJECT_ATTRIBUTES ObjectAttributes
;
1211 PDRIVER_OBJECT DriverObject
;
1212 UNICODE_STRING ServiceKeyName
;
1214 ULONG i
, RetryCount
= 0;
1217 /* First, create a unique name for the driver if we don't have one */
1220 /* Create a random name and set up the string*/
1221 NameLength
= (USHORT
)swprintf(NameBuffer
,
1224 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1225 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1226 LocalDriverName
.Buffer
= NameBuffer
;
1230 /* So we can avoid another code path, use a local var */
1231 LocalDriverName
= *DriverName
;
1234 /* Initialize the Attributes */
1235 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1236 InitializeObjectAttributes(&ObjectAttributes
,
1238 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1242 /* Create the Object */
1243 Status
= ObCreateObject(KernelMode
,
1251 (PVOID
*)&DriverObject
);
1252 if (!NT_SUCCESS(Status
)) return Status
;
1254 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1256 /* Set up the Object */
1257 RtlZeroMemory(DriverObject
, ObjectSize
);
1258 DriverObject
->Type
= IO_TYPE_DRIVER
;
1259 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1260 DriverObject
->Flags
= DRVO_BUILTIN_DRIVER
;
1261 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1262 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1263 DriverObject
->DriverInit
= InitializationFunction
;
1265 /* Loop all Major Functions */
1266 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1268 /* Invalidate each function */
1269 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1272 /* Set up the service key name buffer */
1273 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1274 LocalDriverName
.Length
+
1277 if (!ServiceKeyName
.Buffer
)
1280 ObMakeTemporaryObject(DriverObject
);
1281 ObDereferenceObject(DriverObject
);
1282 return STATUS_INSUFFICIENT_RESOURCES
;
1285 /* Fill out the key data and copy the buffer */
1286 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1287 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1288 RtlCopyMemory(ServiceKeyName
.Buffer
,
1289 LocalDriverName
.Buffer
,
1290 LocalDriverName
.Length
);
1292 /* Null-terminate it and set it */
1293 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1294 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1296 /* Also store it in the Driver Object. This is a bit of a hack. */
1297 RtlCopyMemory(&DriverObject
->DriverName
,
1299 sizeof(UNICODE_STRING
));
1301 /* Add the Object and get its handle */
1302 Status
= ObInsertObject(DriverObject
,
1309 /* Eliminate small possibility when this function is called more than
1310 once in a row, and KeTickCount doesn't get enough time to change */
1311 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1317 if (!NT_SUCCESS(Status
)) return Status
;
1319 /* Now reference it */
1320 Status
= ObReferenceObjectByHandle(hDriver
,
1324 (PVOID
*)&DriverObject
,
1326 if (!NT_SUCCESS(Status
))
1329 ObMakeTemporaryObject(DriverObject
);
1330 ObDereferenceObject(DriverObject
);
1334 /* Close the extra handle */
1337 DriverObject
->HardwareDatabase
= &IopHardwareDatabaseKey
;
1338 DriverObject
->DriverStart
= DllBase
;
1339 DriverObject
->DriverSize
= SizeOfImage
;
1341 /* Finally, call its init function */
1342 DPRINT("RegistryKey: %wZ\n", RegistryPath
);
1343 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction
);
1344 Status
= (*InitializationFunction
)(DriverObject
, RegistryPath
);
1345 if (!NT_SUCCESS(Status
))
1347 /* If it didn't work, then kill the object */
1348 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName
, Status
);
1349 ObMakeTemporaryObject(DriverObject
);
1350 ObDereferenceObject(DriverObject
);
1354 /* Returns to caller the object */
1355 *pDriverObject
= DriverObject
;
1358 /* Return the Status */
1362 /* PUBLIC FUNCTIONS ***********************************************************/
1369 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1370 IN PDRIVER_INITIALIZE InitializationFunction
)
1372 PDRIVER_OBJECT DriverObject
;
1373 return IopCreateDriver(DriverName
, InitializationFunction
, NULL
, 0, 0, &DriverObject
);
1381 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1383 /* Simply dereference the Object */
1384 ObDereferenceObject(DriverObject
);
1392 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1393 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1396 PDRIVER_REINIT_ITEM ReinitItem
;
1398 /* Allocate the entry */
1399 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1400 sizeof(DRIVER_REINIT_ITEM
),
1402 if (!ReinitItem
) return;
1405 ReinitItem
->DriverObject
= DriverObject
;
1406 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1407 ReinitItem
->Context
= Context
;
1409 /* Set the Driver Object flag and insert the entry into the list */
1410 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1411 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1412 &ReinitItem
->ItemEntry
,
1413 &DriverBootReinitListLock
);
1421 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1422 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1425 PDRIVER_REINIT_ITEM ReinitItem
;
1427 /* Allocate the entry */
1428 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1429 sizeof(DRIVER_REINIT_ITEM
),
1431 if (!ReinitItem
) return;
1434 ReinitItem
->DriverObject
= DriverObject
;
1435 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1436 ReinitItem
->Context
= Context
;
1438 /* Set the Driver Object flag and insert the entry into the list */
1439 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1440 ExInterlockedInsertTailList(&DriverReinitListHead
,
1441 &ReinitItem
->ItemEntry
,
1442 &DriverReinitListLock
);
1450 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1451 IN PVOID ClientIdentificationAddress
,
1452 IN ULONG DriverObjectExtensionSize
,
1453 OUT PVOID
*DriverObjectExtension
)
1456 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1457 BOOLEAN Inserted
= FALSE
;
1459 /* Assume failure */
1460 *DriverObjectExtension
= NULL
;
1462 /* Allocate the extension */
1463 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1464 sizeof(IO_CLIENT_EXTENSION
) +
1465 DriverObjectExtensionSize
,
1466 TAG_DRIVER_EXTENSION
);
1467 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1469 /* Clear the extension for teh caller */
1470 RtlZeroMemory(NewDriverExtension
,
1471 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1474 OldIrql
= KeRaiseIrqlToDpcLevel();
1476 /* Fill out the extension */
1477 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1479 /* Loop the current extensions */
1480 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1481 ClientDriverExtension
;
1482 while (DriverExtensions
)
1484 /* Check if the identifier matches */
1485 if (DriverExtensions
->ClientIdentificationAddress
==
1486 ClientIdentificationAddress
)
1488 /* We have a collision, break out */
1492 /* Go to the next one */
1493 DriverExtensions
= DriverExtensions
->NextExtension
;
1496 /* Check if we didn't collide */
1497 if (!DriverExtensions
)
1499 /* Link this one in */
1500 NewDriverExtension
->NextExtension
=
1501 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1502 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1507 /* Release the lock */
1508 KeLowerIrql(OldIrql
);
1510 /* Check if insertion failed */
1513 /* Free the entry and fail */
1514 ExFreePool(NewDriverExtension
);
1515 return STATUS_OBJECT_NAME_COLLISION
;
1518 /* Otherwise, return the pointer */
1519 *DriverObjectExtension
= NewDriverExtension
+ 1;
1520 return STATUS_SUCCESS
;
1528 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1529 IN PVOID ClientIdentificationAddress
)
1532 PIO_CLIENT_EXTENSION DriverExtensions
;
1535 OldIrql
= KeRaiseIrqlToDpcLevel();
1537 /* Loop the list until we find the right one */
1538 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1539 while (DriverExtensions
)
1541 /* Check for a match */
1542 if (DriverExtensions
->ClientIdentificationAddress
==
1543 ClientIdentificationAddress
)
1550 DriverExtensions
= DriverExtensions
->NextExtension
;
1554 KeLowerIrql(OldIrql
);
1556 /* Return nothing or the extension */
1557 if (!DriverExtensions
) return NULL
;
1558 return DriverExtensions
+ 1;
1562 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams
)
1564 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1565 UNICODE_STRING ImagePath
;
1566 UNICODE_STRING ServiceName
;
1569 PDEVICE_NODE DeviceNode
;
1570 PDRIVER_OBJECT DriverObject
;
1571 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1575 /* Check if it's an unload request */
1576 if (LoadParams
->DriverObject
)
1578 (*LoadParams
->DriverObject
->DriverUnload
)(LoadParams
->DriverObject
);
1580 /* Return success and signal the event */
1581 LoadParams
->Status
= STATUS_SUCCESS
;
1582 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1586 RtlInitUnicodeString(&ImagePath
, NULL
);
1589 * Get the service name from the registry key name.
1591 ASSERT(LoadParams
->ServiceName
->Length
>= sizeof(WCHAR
));
1593 ServiceName
= *LoadParams
->ServiceName
;
1594 cur
= LoadParams
->ServiceName
->Buffer
+
1595 (LoadParams
->ServiceName
->Length
/ sizeof(WCHAR
)) - 1;
1596 while (LoadParams
->ServiceName
->Buffer
!= cur
)
1600 ServiceName
.Buffer
= cur
+ 1;
1601 ServiceName
.Length
= LoadParams
->ServiceName
->Length
-
1602 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1603 (ULONG_PTR
)LoadParams
->ServiceName
->Buffer
);
1613 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1615 RtlInitUnicodeString(&ImagePath
, NULL
);
1617 QueryTable
[0].Name
= L
"Type";
1618 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1619 QueryTable
[0].EntryContext
= &Type
;
1621 QueryTable
[1].Name
= L
"ImagePath";
1622 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1623 QueryTable
[1].EntryContext
= &ImagePath
;
1625 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1626 LoadParams
->ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1628 if (!NT_SUCCESS(Status
))
1630 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1631 ExFreePool(ImagePath
.Buffer
);
1632 LoadParams
->Status
= Status
;
1633 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1638 * Normalize the image path for all later processing.
1641 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1643 if (!NT_SUCCESS(Status
))
1645 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1646 LoadParams
->Status
= Status
;
1647 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1651 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1652 DPRINT("Type: %lx\n", Type
);
1655 * Create device node
1658 /* Use IopRootDeviceNode for now */
1659 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1661 if (!NT_SUCCESS(Status
))
1663 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1664 LoadParams
->Status
= Status
;
1665 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1669 /* Get existing DriverObject pointer (in case the driver has
1670 already been loaded and initialized) */
1671 Status
= IopGetDriverObject(
1674 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1675 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */));
1677 if (!NT_SUCCESS(Status
))
1680 * Load the driver module
1683 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, &BaseAddress
);
1684 if (!NT_SUCCESS(Status
) && Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1686 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1687 IopFreeDeviceNode(DeviceNode
);
1688 LoadParams
->Status
= Status
;
1689 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1694 * Set a service name for the device node
1697 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
);
1700 * Initialize the driver module if it's loaded for the first time
1702 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1704 Status
= IopInitializeDriverModule(
1707 &DeviceNode
->ServiceName
,
1708 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1709 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1712 if (!NT_SUCCESS(Status
))
1714 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1715 MmUnloadSystemImage(ModuleObject
);
1716 IopFreeDeviceNode(DeviceNode
);
1717 LoadParams
->Status
= Status
;
1718 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1723 /* Store its DriverSection, so that it could be unloaded */
1724 DriverObject
->DriverSection
= ModuleObject
;
1727 IopInitializeDevice(DeviceNode
, DriverObject
);
1728 LoadParams
->Status
= IopStartDevice(DeviceNode
);
1729 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1735 * Loads a device driver.
1739 * Name of the service to load (registry key).
1748 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1750 UNICODE_STRING CapturedDriverServiceName
= { 0, 0, NULL
};
1751 KPROCESSOR_MODE PreviousMode
;
1752 LOAD_UNLOAD_PARAMS LoadParams
;
1757 PreviousMode
= KeGetPreviousMode();
1760 * Check security privileges
1763 /* FIXME: Uncomment when privileges will be correctly implemented. */
1765 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1767 DPRINT("Privilege not held\n");
1768 return STATUS_PRIVILEGE_NOT_HELD
;
1772 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
1775 if (!NT_SUCCESS(Status
))
1780 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1782 LoadParams
.ServiceName
= &CapturedDriverServiceName
;
1783 LoadParams
.DriverObject
= NULL
;
1784 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1786 /* Call the load/unload routine, depending on current process */
1787 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1789 /* Just call right away */
1790 IopLoadUnloadDriver(&LoadParams
);
1794 /* Load/Unload must be called from system process */
1795 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1796 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1797 (PVOID
)&LoadParams
);
1800 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1802 /* And wait when it completes */
1803 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1807 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
1810 return LoadParams
.Status
;
1816 * Unloads a legacy device driver.
1820 * Name of the service to unload (registry key).
1830 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
1832 return IopUnloadDriver(DriverServiceName
, FALSE
);