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 *******************************************************************/
15 #include <internal/debug.h>
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 extern BOOLEAN ExpInTextModeSetup
;
34 /* PRIVATE FUNCTIONS **********************************************************/
37 IopInvalidDeviceRequest(
38 PDEVICE_OBJECT DeviceObject
,
41 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
42 Irp
->IoStatus
.Information
= 0;
43 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
44 return STATUS_INVALID_DEVICE_REQUEST
;
49 IopDeleteDriver(IN PVOID ObjectBody
)
51 PDRIVER_OBJECT DriverObject
= ObjectBody
;
52 PIO_CLIENT_EXTENSION DriverExtension
, NextDriverExtension
;
55 /* Get the extension and loop them */
56 DriverExtension
= IoGetDrvObjExtension(DriverObject
)->
57 ClientDriverExtension
;
58 while (DriverExtension
)
60 /* Get the next one */
61 NextDriverExtension
= DriverExtension
->NextExtension
;
62 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
65 DriverExtension
= NextDriverExtension
;
68 /* Check if the driver image is still loaded */
69 if (DriverObject
->DriverSection
)
72 //LdrpUnloadImage(DriverObject->DriverSection);
75 /* Check if it has a name */
76 if (DriverObject
->DriverName
.Buffer
)
79 ExFreePool(DriverObject
->DriverName
.Buffer
);
82 #if 0 /* See a bit of hack in IopCreateDriver */
83 /* Check if it has a service key name */
84 if (DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
)
87 ExFreePool(DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
);
94 PDRIVER_OBJECT
*DriverObject
,
95 PUNICODE_STRING ServiceName
,
98 PDRIVER_OBJECT Object
;
99 WCHAR NameBuffer
[MAX_PATH
];
100 UNICODE_STRING DriverName
;
103 DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
104 DriverObject
, ServiceName
, FileSystem
);
106 *DriverObject
= NULL
;
108 /* Create ModuleName string */
109 if (ServiceName
== NULL
|| ServiceName
->Buffer
== NULL
)
110 /* We don't know which DriverObject we have to open */
111 return STATUS_INVALID_PARAMETER_2
;
113 DriverName
.Buffer
= NameBuffer
;
114 DriverName
.Length
= 0;
115 DriverName
.MaximumLength
= sizeof(NameBuffer
);
117 if (FileSystem
== TRUE
)
118 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
120 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
121 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
123 DPRINT("Driver name: '%wZ'\n", &DriverName
);
125 /* Open driver object */
126 Status
= ObReferenceObjectByName(
128 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, /* Attributes */
129 NULL
, /* PassedAccessState */
130 0, /* DesiredAccess */
133 NULL
, /* ParseContext */
136 if (!NT_SUCCESS(Status
))
138 DPRINT("Failed to reference driver object, status=0x%08x\n", Status
);
142 *DriverObject
= Object
;
144 DPRINT("Driver Object: %p\n", Object
);
146 return STATUS_SUCCESS
;
150 * IopDisplayLoadingMessage
152 * Display 'Loading XXX...' message.
158 IopDisplayLoadingMessage(PVOID ServiceName
,
161 CHAR TextBuffer
[256];
162 PCHAR Extra
= ".sys";
164 if (ExpInTextModeSetup
) return;
167 if (wcsstr(_wcsupr(ServiceName
), L
".SYS")) Extra
= "";
170 KeLoaderBlock
->ArcBootDeviceName
,
171 KeLoaderBlock
->NtBootPathName
,
178 if (strstr(_strupr(ServiceName
), ".SYS")) Extra
= "";
181 KeLoaderBlock
->ArcBootDeviceName
,
182 KeLoaderBlock
->NtBootPathName
,
187 HalDisplayString(TextBuffer
);
191 * IopNormalizeImagePath
193 * Normalize an image path to contain complete path.
197 * The input path and on exit the result path. ImagePath.Buffer
198 * must be allocated by ExAllocatePool on input. Caller is responsible
199 * for freeing the buffer when it's no longer needed.
202 * Name of the service that ImagePath belongs to.
208 * The input image path isn't freed on error.
212 IopNormalizeImagePath(
213 IN OUT PUNICODE_STRING ImagePath
,
214 IN PUNICODE_STRING ServiceName
)
216 UNICODE_STRING InputImagePath
;
221 sizeof(UNICODE_STRING
));
223 if (InputImagePath
.Length
== 0)
225 ImagePath
->Length
= 0;
226 ImagePath
->MaximumLength
=
227 (33 * sizeof(WCHAR
)) + ServiceName
->Length
+ sizeof(UNICODE_NULL
);
228 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
229 if (ImagePath
->Buffer
== NULL
)
230 return STATUS_NO_MEMORY
;
232 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\system32\\drivers\\");
233 RtlAppendUnicodeStringToString(ImagePath
, ServiceName
);
234 RtlAppendUnicodeToString(ImagePath
, L
".sys");
236 if (InputImagePath
.Buffer
[0] != L
'\\')
238 ImagePath
->Length
= 0;
239 ImagePath
->MaximumLength
=
240 12 * sizeof(WCHAR
) + InputImagePath
.Length
+ sizeof(UNICODE_NULL
);
241 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
242 if (ImagePath
->Buffer
== NULL
)
243 return STATUS_NO_MEMORY
;
245 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\");
246 RtlAppendUnicodeStringToString(ImagePath
, &InputImagePath
);
248 /* Free caller's string */
249 RtlFreeUnicodeString(&InputImagePath
);
252 return STATUS_SUCCESS
;
256 * IopLoadServiceModule
258 * Load a module specified by registry settings for service.
262 * Name of the service to load.
269 IopLoadServiceModule(
270 IN PUNICODE_STRING ServiceName
,
271 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
273 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
275 UNICODE_STRING ServiceImagePath
, CCSName
;
277 HANDLE CCSKey
, ServiceKey
;
279 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
281 /* FIXME: This check may be removed once the bug is fixed */
282 if (ServiceName
->Buffer
== NULL
)
284 DPRINT1("If you see this, please report to Fireball or hpoussin!\n");
285 return STATUS_UNSUCCESSFUL
;
288 /* Open CurrentControlSet */
289 RtlInitUnicodeString(&CCSName
,
290 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
291 Status
= IopOpenRegistryKeyEx(&CCSKey
, NULL
, &CCSName
, KEY_READ
);
292 if (!NT_SUCCESS(Status
))
294 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
298 /* Open service key */
299 Status
= IopOpenRegistryKeyEx(&ServiceKey
, CCSKey
, ServiceName
, KEY_READ
);
300 if (!NT_SUCCESS(Status
))
302 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
308 * Get information about the service.
311 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
313 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
315 QueryTable
[0].Name
= L
"Start";
316 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
317 QueryTable
[0].EntryContext
= &ServiceStart
;
319 QueryTable
[1].Name
= L
"ImagePath";
320 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
321 QueryTable
[1].EntryContext
= &ServiceImagePath
;
323 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
324 (PWSTR
)ServiceKey
, QueryTable
, NULL
, NULL
);
329 if (!NT_SUCCESS(Status
))
331 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
336 * Normalize the image path for all later processing.
339 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
341 if (!NT_SUCCESS(Status
))
343 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
348 * Case for disabled drivers
351 if (ServiceStart
>= 4)
353 /* FIXME: Check if it is the right status code */
354 Status
= STATUS_PLUGPLAY_NO_DEVICE
;
358 DPRINT("Loading module\n");
359 Status
= MmLoadSystemImage(&ServiceImagePath
, NULL
, NULL
, 0, (PVOID
)ModuleObject
, NULL
);
362 ExFreePool(ServiceImagePath
.Buffer
);
365 * Now check if the module was loaded successfully.
368 if (!NT_SUCCESS(Status
))
370 DPRINT("Module loading failed (Status %x)\n", Status
);
373 DPRINT("Module loading (Status %x)\n", Status
);
379 * IopInitializeDriverModule
381 * Initalize a loaded driver.
385 * Pointer to device node.
388 * Module object representing the driver. It can be retrieve by
389 * IopLoadServiceModule.
392 * Name of the service (as in registry).
395 * Set to TRUE for file system drivers.
398 * On successful return this contains the driver object representing
403 IopInitializeDriverModule(
404 IN PDEVICE_NODE DeviceNode
,
405 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
406 IN PUNICODE_STRING ServiceName
,
407 IN BOOLEAN FileSystemDriver
,
408 OUT PDRIVER_OBJECT
*DriverObject
)
410 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
411 WCHAR NameBuffer
[MAX_PATH
];
412 UNICODE_STRING DriverName
;
413 UNICODE_STRING RegistryKey
;
414 PDRIVER_INITIALIZE DriverEntry
;
415 PDRIVER_OBJECT Driver
;
416 PDEVICE_OBJECT DeviceObject
;
419 DriverEntry
= ModuleObject
->EntryPoint
;
421 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
423 RegistryKey
.Length
= 0;
424 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
425 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
426 if (RegistryKey
.Buffer
== NULL
)
428 return STATUS_INSUFFICIENT_RESOURCES
;
430 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
431 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
435 RtlInitUnicodeString(&RegistryKey
, NULL
);
438 /* Create ModuleName string */
439 if (ServiceName
&& ServiceName
->Length
> 0)
441 if (FileSystemDriver
== TRUE
)
442 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
444 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
446 RtlInitUnicodeString(&DriverName
, NameBuffer
);
447 DriverName
.MaximumLength
= sizeof(NameBuffer
);
449 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
451 DPRINT("Driver name: '%wZ'\n", &DriverName
);
454 DriverName
.Length
= 0;
456 Status
= IopCreateDriver(
457 DriverName
.Length
> 0 ? &DriverName
: NULL
,
460 ModuleObject
->DllBase
,
461 ModuleObject
->SizeOfImage
,
463 RtlFreeUnicodeString(&RegistryKey
);
465 *DriverObject
= Driver
;
466 if (!NT_SUCCESS(Status
))
468 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status
);
472 /* Set the driver as initialized */
473 Driver
->Flags
|= DRVO_INITIALIZED
;
474 DeviceObject
= Driver
->DeviceObject
;
477 /* Set every device as initialized too */
478 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
479 DeviceObject
= DeviceObject
->NextDevice
;
482 IopReinitializeDrivers();
484 return STATUS_SUCCESS
;
488 * IopAttachFilterDriversCallback
490 * Internal routine used by IopAttachFilterDrivers.
494 IopAttachFilterDriversCallback(
502 PDEVICE_NODE DeviceNode
= Context
;
503 UNICODE_STRING ServiceName
;
505 PLDR_DATA_TABLE_ENTRY ModuleObject
;
506 PDRIVER_OBJECT DriverObject
;
509 for (Filters
= ValueData
;
510 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
512 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
514 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
515 ServiceName
.Buffer
= Filters
;
516 ServiceName
.MaximumLength
=
517 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
519 /* Load and initialize the filter driver */
520 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
521 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
523 if (!NT_SUCCESS(Status
))
526 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
527 FALSE
, &DriverObject
);
528 if (!NT_SUCCESS(Status
))
533 /* get existing DriverObject pointer */
534 Status
= IopGetDriverObject(
538 if (!NT_SUCCESS(Status
))
540 DPRINT1("IopGetDriverObject() returned status 0x%08x!\n", Status
);
545 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
546 if (!NT_SUCCESS(Status
))
550 return STATUS_SUCCESS
;
554 * IopAttachFilterDrivers
556 * Load filter drivers for specified device node.
560 * Set to TRUE for loading lower level filters or FALSE for upper
565 IopAttachFilterDrivers(
566 PDEVICE_NODE DeviceNode
,
569 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = {{0}};
570 UNICODE_STRING Class
;
571 WCHAR ClassBuffer
[40];
572 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
573 HANDLE EnumRootKey
, SubKey
;
576 /* Open enumeration root key */
577 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
578 &EnumRoot
, KEY_READ
);
579 if (!NT_SUCCESS(Status
))
581 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
586 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
587 &DeviceNode
->InstancePath
, KEY_READ
);
588 if (!NT_SUCCESS(Status
))
590 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
591 ZwClose(EnumRootKey
);
596 * First load the device filters
598 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
600 QueryTable
[0].Name
= L
"LowerFilters";
602 QueryTable
[0].Name
= L
"UpperFilters";
603 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
605 RtlQueryRegistryValues(
613 * Now get the class GUID
616 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
617 Class
.Buffer
= ClassBuffer
;
618 QueryTable
[0].QueryRoutine
= NULL
;
619 QueryTable
[0].Name
= L
"ClassGUID";
620 QueryTable
[0].EntryContext
= &Class
;
621 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
623 Status
= RtlQueryRegistryValues(
632 ZwClose(EnumRootKey
);
635 * Load the class filter driver
637 if (NT_SUCCESS(Status
))
639 UNICODE_STRING ControlClass
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
641 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
642 &ControlClass
, KEY_READ
);
643 if (!NT_SUCCESS(Status
))
645 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
650 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
652 if (!NT_SUCCESS(Status
))
654 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
655 ZwClose(EnumRootKey
);
659 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
661 QueryTable
[0].Name
= L
"LowerFilters";
663 QueryTable
[0].Name
= L
"UpperFilters";
664 QueryTable
[0].EntryContext
= NULL
;
665 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
667 RtlQueryRegistryValues(
676 ZwClose(EnumRootKey
);
679 return STATUS_SUCCESS
;
684 MiResolveImageReferences(IN PVOID ImageBase
,
685 IN PUNICODE_STRING ImageFileDirectory
,
686 IN PUNICODE_STRING NamePrefix OPTIONAL
,
687 OUT PCHAR
*MissingApi
,
688 OUT PWCHAR
*MissingDriver
,
689 OUT PLOAD_IMPORTS
*LoadImports
);
691 extern KSPIN_LOCK PsLoadedModuleSpinLock
;
694 // Used for images already loaded (boot drivers)
698 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry
,
699 PUNICODE_STRING FileName
,
700 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
703 PLDR_DATA_TABLE_ENTRY NewEntry
;
704 UNICODE_STRING BaseName
, BaseDirectory
;
705 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
706 PCHAR MissingApiName
, Buffer
;
707 PWCHAR MissingDriverName
;
708 PVOID DriverBase
= LdrEntry
->DllBase
;
710 /* Allocate a buffer we'll use for names */
711 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
715 return STATUS_INSUFFICIENT_RESOURCES
;
718 /* Check for a separator */
719 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
724 /* Loop the path until we get to the base name */
725 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
726 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
729 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
730 BaseLength
*= sizeof(WCHAR
);
732 /* Setup the string */
733 BaseName
.Length
= (USHORT
)BaseLength
;
738 /* Otherwise, we already have a base name */
739 BaseName
.Length
= FileName
->Length
;
740 BaseName
.Buffer
= FileName
->Buffer
;
743 /* Setup the maximum length */
744 BaseName
.MaximumLength
= BaseName
.Length
;
746 /* Now compute the base directory */
747 BaseDirectory
= *FileName
;
748 BaseDirectory
.Length
-= BaseName
.Length
;
749 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
753 /* Resolve imports */
754 MissingApiName
= Buffer
;
755 Status
= MiResolveImageReferences(DriverBase
,
761 if (!NT_SUCCESS(Status
)) return Status
;
764 *ModuleObject
= LdrEntry
;
765 return STATUS_SUCCESS
;
769 * IopInitializeBuiltinDriver
771 * Initialize a driver that is already loaded in memory.
776 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
778 PDEVICE_NODE DeviceNode
;
779 PDRIVER_OBJECT DriverObject
;
781 PWCHAR FileNameWithoutPath
;
782 LPWSTR FileExtension
;
783 PUNICODE_STRING ModuleName
= &LdrEntry
->BaseDllName
;
784 UNICODE_STRING ServiceName
;
785 #if 1 // Disable for FreeLDR 2.5
786 UNICODE_STRING ServiceNameWithExtension
;
787 PLDR_DATA_TABLE_ENTRY ModuleObject
;
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
++;
811 #if 1 // Remove for FreeLDR 2.5.
812 RtlCreateUnicodeString(&ServiceNameWithExtension
, FileNameWithoutPath
);
813 Status
= LdrProcessDriverModule(LdrEntry
, &ServiceNameWithExtension
, &ModuleObject
);
814 if (!NT_SUCCESS(Status
))
816 CPRINT("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
822 * Strip the file extension from ServiceName
824 RtlCreateUnicodeString(&ServiceName
, FileNameWithoutPath
);
825 FileExtension
= wcsrchr(ServiceName
.Buffer
, '.');
826 if (FileExtension
!= NULL
)
828 ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
829 FileExtension
[0] = 0;
833 * Determine the right device object
835 /* Use IopRootDeviceNode for now */
836 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
837 if (!NT_SUCCESS(Status
))
839 CPRINT("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
842 DeviceNode
->ServiceName
= ServiceName
;
845 * Initialize the driver
847 DeviceNode
->Flags
|= DN_DRIVER_LOADED
;
848 Status
= IopInitializeDriverModule(DeviceNode
, LdrEntry
,
849 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
851 if (!NT_SUCCESS(Status
))
853 IopFreeDeviceNode(DeviceNode
);
857 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
858 if (NT_SUCCESS(Status
))
860 Status
= IopStartDevice(DeviceNode
);
867 * IopInitializeBootDrivers
869 * Initialize boot drivers and free memory for boot files.
879 IopInitializeBootDrivers(VOID
)
881 PLIST_ENTRY ListHead
, NextEntry
;
882 PLDR_DATA_TABLE_ENTRY LdrEntry
;
883 PDEVICE_NODE DeviceNode
;
884 PDRIVER_OBJECT DriverObject
;
885 LDR_DATA_TABLE_ENTRY ModuleObject
;
887 UNICODE_STRING DriverName
;
889 DPRINT("IopInitializeBootDrivers()\n");
891 /* Use IopRootDeviceNode for now */
892 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, NULL
, &DeviceNode
);
893 if (!NT_SUCCESS(Status
)) return;
895 /* Setup the module object for the RAW FS Driver */
896 ModuleObject
.DllBase
= NULL
;
897 ModuleObject
.SizeOfImage
= 0;
898 ModuleObject
.EntryPoint
= RawFsDriverEntry
;
899 RtlInitUnicodeString(&DriverName
, L
"RAW");
902 Status
= IopInitializeDriverModule(DeviceNode
,
907 if (!NT_SUCCESS(Status
))
910 IopFreeDeviceNode(DeviceNode
);
914 /* Now initialize the associated device */
915 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
916 if (!NT_SUCCESS(Status
))
919 IopFreeDeviceNode(DeviceNode
);
924 Status
= IopStartDevice(DeviceNode
);
925 if (!NT_SUCCESS(Status
))
928 IopFreeDeviceNode(DeviceNode
);
932 /* Loop the boot modules */
933 ListHead
= &KeLoaderBlock
->LoadOrderListHead
;
934 NextEntry
= ListHead
->Flink
;
935 while (ListHead
!= NextEntry
)
938 LdrEntry
= CONTAINING_RECORD(NextEntry
,
939 LDR_DATA_TABLE_ENTRY
,
943 * HACK: Make sure we're loading a driver
944 * (we should be using BootDriverListHead!)
946 if (wcsstr(_wcsupr(LdrEntry
->BaseDllName
.Buffer
), L
".SYS"))
948 /* Make sure we didn't load this driver already */
949 if (!(LdrEntry
->Flags
& LDRP_ENTRY_INSERTED
))
951 DPRINT("Initializing bootdriver %wZ\n", &LdrEntry
->BaseDllName
);
953 IopInitializeBuiltinDriver(LdrEntry
);
957 /* Go to the next driver */
958 NextEntry
= NextEntry
->Flink
;
961 /* In old ROS, the loader list became empty after this point. Simulate. */
962 InitializeListHead(&KeLoaderBlock
->LoadOrderListHead
);
968 * Unloads a device driver.
972 * Name of the service to unload (registry key).
975 * Whether to unload Plug & Plug or only legacy drivers. If this
976 * parameter is set to FALSE, the routine will unload only legacy
983 * Guard the whole function by SEH.
987 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
989 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
990 UNICODE_STRING ImagePath
;
991 UNICODE_STRING ServiceName
;
992 UNICODE_STRING ObjectName
;
993 PDRIVER_OBJECT DriverObject
;
994 LOAD_UNLOAD_PARAMS LoadParams
;
998 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1003 * Get the service name from the registry key name
1006 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1008 Start
= DriverServiceName
->Buffer
;
1012 RtlInitUnicodeString(&ServiceName
, Start
);
1015 * Construct the driver object name
1018 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1019 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1020 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1021 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1022 memcpy(ObjectName
.Buffer
+ 8, Start
, ObjectName
.Length
- 8 * sizeof(WCHAR
));
1023 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1026 * Find the driver object
1029 Status
= ObReferenceObjectByName(&ObjectName
, 0, 0, 0, IoDriverObjectType
,
1030 KernelMode
, 0, (PVOID
*)&DriverObject
);
1032 if (!NT_SUCCESS(Status
))
1034 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName
);
1039 * Free the buffer for driver object name
1042 ExFreePool(ObjectName
.Buffer
);
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
);
1066 * Normalize the image path for all later processing.
1069 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1071 if (!NT_SUCCESS(Status
))
1073 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1078 * Free the service path
1081 ExFreePool(ImagePath
.Buffer
);
1084 * Unload the module and release the references to the device object
1087 /* Call the load/unload routine, depending on current process */
1088 if (DriverObject
->DriverUnload
)
1090 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1092 /* Just call right away */
1093 (*DriverObject
->DriverUnload
)(DriverObject
);
1097 /* Load/Unload must be called from system process */
1099 /* Prepare parameters block */
1100 LoadParams
.DriverObject
= DriverObject
;
1101 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1103 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1104 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1105 (PVOID
)&LoadParams
);
1108 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1110 /* And wait when it completes */
1111 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1116 ObDereferenceObject(DriverObject
);
1117 ObDereferenceObject(DriverObject
);
1118 MmUnloadSystemImage(DriverObject
->DriverSection
);
1120 return STATUS_SUCCESS
;
1125 IopReinitializeDrivers(VOID
)
1127 PDRIVER_REINIT_ITEM ReinitItem
;
1130 /* Get the first entry and start looping */
1131 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1132 &DriverReinitListLock
);
1136 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1138 /* Increment reinitialization counter */
1139 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1141 /* Remove the device object flag */
1142 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1144 /* Call the routine */
1145 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1146 ReinitItem
->Context
,
1147 ReinitItem
->DriverObject
->
1148 DriverExtension
->Count
);
1150 /* Free the entry */
1153 /* Move to the next one */
1154 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1155 &DriverReinitListLock
);
1161 IopReinitializeBootDrivers(VOID
)
1163 PDRIVER_REINIT_ITEM ReinitItem
;
1166 /* Get the first entry and start looping */
1167 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1168 &DriverBootReinitListLock
);
1172 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1174 /* Increment reinitialization counter */
1175 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1177 /* Remove the device object flag */
1178 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1180 /* Call the routine */
1181 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1182 ReinitItem
->Context
,
1183 ReinitItem
->DriverObject
->
1184 DriverExtension
->Count
);
1186 /* Free the entry */
1189 /* Move to the next one */
1190 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1191 &DriverBootReinitListLock
);
1197 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1198 IN PDRIVER_INITIALIZE InitializationFunction
,
1199 IN PUNICODE_STRING RegistryPath
,
1201 IN ULONG SizeOfImage
,
1202 OUT PDRIVER_OBJECT
*pDriverObject
)
1204 WCHAR NameBuffer
[100];
1206 UNICODE_STRING LocalDriverName
;
1208 OBJECT_ATTRIBUTES ObjectAttributes
;
1210 PDRIVER_OBJECT DriverObject
;
1211 UNICODE_STRING ServiceKeyName
;
1213 ULONG i
, RetryCount
= 0;
1216 /* First, create a unique name for the driver if we don't have one */
1219 /* Create a random name and set up the string*/
1220 NameLength
= (USHORT
)swprintf(NameBuffer
,
1223 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1224 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1225 LocalDriverName
.Buffer
= NameBuffer
;
1229 /* So we can avoid another code path, use a local var */
1230 LocalDriverName
= *DriverName
;
1233 /* Initialize the Attributes */
1234 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1235 InitializeObjectAttributes(&ObjectAttributes
,
1237 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1241 /* Create the Object */
1242 Status
= ObCreateObject(KernelMode
,
1250 (PVOID
*)&DriverObject
);
1251 if (!NT_SUCCESS(Status
)) return Status
;
1253 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1255 /* Set up the Object */
1256 RtlZeroMemory(DriverObject
, ObjectSize
);
1257 DriverObject
->Type
= IO_TYPE_DRIVER
;
1258 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1259 DriverObject
->Flags
= DRVO_BUILTIN_DRIVER
;
1260 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1261 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1262 DriverObject
->DriverInit
= InitializationFunction
;
1264 /* Loop all Major Functions */
1265 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1267 /* Invalidate each function */
1268 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1271 /* Set up the service key name buffer */
1272 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1273 LocalDriverName
.Length
+
1276 if (!ServiceKeyName
.Buffer
)
1279 ObMakeTemporaryObject(DriverObject
);
1280 ObDereferenceObject(DriverObject
);
1281 return STATUS_INSUFFICIENT_RESOURCES
;
1284 /* Fill out the key data and copy the buffer */
1285 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1286 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1287 RtlCopyMemory(ServiceKeyName
.Buffer
,
1288 LocalDriverName
.Buffer
,
1289 LocalDriverName
.Length
);
1291 /* Null-terminate it and set it */
1292 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1293 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1295 /* Also store it in the Driver Object. This is a bit of a hack. */
1296 RtlCopyMemory(&DriverObject
->DriverName
,
1298 sizeof(UNICODE_STRING
));
1300 /* Add the Object and get its handle */
1301 Status
= ObInsertObject(DriverObject
,
1308 /* Eliminate small possibility when this function is called more than
1309 once in a row, and KeTickCount doesn't get enough time to change */
1310 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1316 if (!NT_SUCCESS(Status
)) return Status
;
1318 /* Now reference it */
1319 Status
= ObReferenceObjectByHandle(hDriver
,
1323 (PVOID
*)&DriverObject
,
1325 if (!NT_SUCCESS(Status
))
1328 ObMakeTemporaryObject(DriverObject
);
1329 ObDereferenceObject(DriverObject
);
1333 /* Close the extra handle */
1336 DriverObject
->HardwareDatabase
= &IopHardwareDatabaseKey
;
1337 DriverObject
->DriverStart
= DllBase
;
1338 DriverObject
->DriverSize
= SizeOfImage
;
1340 /* Finally, call its init function */
1341 DPRINT("RegistryKey: %wZ\n", RegistryPath
);
1342 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction
);
1343 Status
= (*InitializationFunction
)(DriverObject
, RegistryPath
);
1344 if (!NT_SUCCESS(Status
))
1346 /* If it didn't work, then kill the object */
1347 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName
, Status
);
1348 ObMakeTemporaryObject(DriverObject
);
1349 ObDereferenceObject(DriverObject
);
1353 /* Returns to caller the object */
1354 *pDriverObject
= DriverObject
;
1357 /* Return the Status */
1361 /* PUBLIC FUNCTIONS ***********************************************************/
1368 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1369 IN PDRIVER_INITIALIZE InitializationFunction
)
1371 PDRIVER_OBJECT DriverObject
;
1372 return IopCreateDriver(DriverName
, InitializationFunction
, NULL
, 0, 0, &DriverObject
);
1380 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1382 /* Simply dereference the Object */
1383 ObDereferenceObject(DriverObject
);
1391 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1392 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1395 PDRIVER_REINIT_ITEM ReinitItem
;
1397 /* Allocate the entry */
1398 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1399 sizeof(DRIVER_REINIT_ITEM
),
1401 if (!ReinitItem
) return;
1404 ReinitItem
->DriverObject
= DriverObject
;
1405 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1406 ReinitItem
->Context
= Context
;
1408 /* Set the Driver Object flag and insert the entry into the list */
1409 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1410 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1411 &ReinitItem
->ItemEntry
,
1412 &DriverBootReinitListLock
);
1420 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1421 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1424 PDRIVER_REINIT_ITEM ReinitItem
;
1426 /* Allocate the entry */
1427 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1428 sizeof(DRIVER_REINIT_ITEM
),
1430 if (!ReinitItem
) return;
1433 ReinitItem
->DriverObject
= DriverObject
;
1434 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1435 ReinitItem
->Context
= Context
;
1437 /* Set the Driver Object flag and insert the entry into the list */
1438 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1439 ExInterlockedInsertTailList(&DriverReinitListHead
,
1440 &ReinitItem
->ItemEntry
,
1441 &DriverReinitListLock
);
1449 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1450 IN PVOID ClientIdentificationAddress
,
1451 IN ULONG DriverObjectExtensionSize
,
1452 OUT PVOID
*DriverObjectExtension
)
1455 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1456 BOOLEAN Inserted
= FALSE
;
1458 /* Assume failure */
1459 *DriverObjectExtension
= NULL
;
1461 /* Allocate the extension */
1462 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1463 sizeof(IO_CLIENT_EXTENSION
) +
1464 DriverObjectExtensionSize
,
1465 TAG_DRIVER_EXTENSION
);
1466 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1468 /* Clear the extension for teh caller */
1469 RtlZeroMemory(NewDriverExtension
,
1470 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1473 OldIrql
= KeRaiseIrqlToDpcLevel();
1475 /* Fill out the extension */
1476 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1478 /* Loop the current extensions */
1479 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1480 ClientDriverExtension
;
1481 while (DriverExtensions
)
1483 /* Check if the identifier matches */
1484 if (DriverExtensions
->ClientIdentificationAddress
==
1485 ClientIdentificationAddress
)
1487 /* We have a collision, break out */
1491 /* Go to the next one */
1492 DriverExtensions
= DriverExtensions
->NextExtension
;
1495 /* Check if we didn't collide */
1496 if (!DriverExtensions
)
1498 /* Link this one in */
1499 NewDriverExtension
->NextExtension
=
1500 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1501 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1506 /* Release the lock */
1507 KeLowerIrql(OldIrql
);
1509 /* Check if insertion failed */
1512 /* Free the entry and fail */
1513 ExFreePool(NewDriverExtension
);
1514 return STATUS_OBJECT_NAME_COLLISION
;
1517 /* Otherwise, return the pointer */
1518 *DriverObjectExtension
= NewDriverExtension
+ 1;
1519 return STATUS_SUCCESS
;
1527 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1528 IN PVOID ClientIdentificationAddress
)
1531 PIO_CLIENT_EXTENSION DriverExtensions
;
1534 OldIrql
= KeRaiseIrqlToDpcLevel();
1536 /* Loop the list until we find the right one */
1537 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1538 while (DriverExtensions
)
1540 /* Check for a match */
1541 if (DriverExtensions
->ClientIdentificationAddress
==
1542 ClientIdentificationAddress
)
1549 DriverExtensions
= DriverExtensions
->NextExtension
;
1553 KeLowerIrql(OldIrql
);
1555 /* Return nothing or the extension */
1556 if (!DriverExtensions
) return NULL
;
1557 return DriverExtensions
+ 1;
1561 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams
)
1563 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1564 UNICODE_STRING ImagePath
;
1565 UNICODE_STRING ServiceName
;
1568 PDEVICE_NODE DeviceNode
;
1569 PDRIVER_OBJECT DriverObject
;
1570 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1573 /* Check if it's an unload request */
1574 if (LoadParams
->DriverObject
)
1576 (*LoadParams
->DriverObject
->DriverUnload
)(LoadParams
->DriverObject
);
1578 /* Return success and signal the event */
1579 LoadParams
->Status
= STATUS_SUCCESS
;
1580 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1584 RtlInitUnicodeString(&ImagePath
, NULL
);
1587 * Get the service name from the registry key name.
1589 ASSERT(LoadParams
->ServiceName
->Length
>= sizeof(WCHAR
));
1591 ServiceName
= *LoadParams
->ServiceName
;
1592 cur
= LoadParams
->ServiceName
->Buffer
+
1593 (LoadParams
->ServiceName
->Length
/ sizeof(WCHAR
)) - 1;
1594 while (LoadParams
->ServiceName
->Buffer
!= cur
)
1598 ServiceName
.Buffer
= cur
+ 1;
1599 ServiceName
.Length
= LoadParams
->ServiceName
->Length
-
1600 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1601 (ULONG_PTR
)LoadParams
->ServiceName
->Buffer
);
1611 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1613 RtlInitUnicodeString(&ImagePath
, NULL
);
1615 QueryTable
[0].Name
= L
"Type";
1616 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1617 QueryTable
[0].EntryContext
= &Type
;
1619 QueryTable
[1].Name
= L
"ImagePath";
1620 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1621 QueryTable
[1].EntryContext
= &ImagePath
;
1623 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1624 LoadParams
->ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1626 if (!NT_SUCCESS(Status
))
1628 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1629 ExFreePool(ImagePath
.Buffer
);
1630 LoadParams
->Status
= Status
;
1631 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1636 * Normalize the image path for all later processing.
1639 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1641 if (!NT_SUCCESS(Status
))
1643 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1644 LoadParams
->Status
= Status
;
1645 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1649 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1650 DPRINT("Type: %lx\n", Type
);
1653 * Create device node
1656 /* Use IopRootDeviceNode for now */
1657 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1659 if (!NT_SUCCESS(Status
))
1661 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1662 LoadParams
->Status
= Status
;
1663 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1667 /* Get existing DriverObject pointer (in case the driver has
1668 already been loaded and initialized) */
1669 Status
= IopGetDriverObject(
1672 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1673 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */));
1675 if (!NT_SUCCESS(Status
))
1678 * Load the driver module
1681 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, NULL
);
1682 if (!NT_SUCCESS(Status
) && Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1684 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1685 IopFreeDeviceNode(DeviceNode
);
1686 LoadParams
->Status
= Status
;
1687 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1692 * Set a service name for the device node
1695 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
);
1698 * Initialize the driver module if it's loaded for the first time
1700 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1702 Status
= IopInitializeDriverModule(
1705 &DeviceNode
->ServiceName
,
1706 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1707 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1710 if (!NT_SUCCESS(Status
))
1712 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1713 MmUnloadSystemImage(ModuleObject
);
1714 IopFreeDeviceNode(DeviceNode
);
1715 LoadParams
->Status
= Status
;
1716 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1721 /* We have a driver for this DeviceNode */
1722 DeviceNode
->Flags
|= DN_DRIVER_LOADED
;
1725 IopInitializeDevice(DeviceNode
, DriverObject
);
1726 LoadParams
->Status
= IopStartDevice(DeviceNode
);
1727 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1733 * Loads a device driver.
1737 * Name of the service to load (registry key).
1746 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1748 UNICODE_STRING CapturedDriverServiceName
= {0};
1749 KPROCESSOR_MODE PreviousMode
;
1750 LOAD_UNLOAD_PARAMS LoadParams
;
1755 PreviousMode
= KeGetPreviousMode();
1758 * Check security privileges
1761 /* FIXME: Uncomment when privileges will be correctly implemented. */
1763 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1765 DPRINT("Privilege not held\n");
1766 return STATUS_PRIVILEGE_NOT_HELD
;
1770 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
1773 if (!NT_SUCCESS(Status
))
1778 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1780 LoadParams
.ServiceName
= &CapturedDriverServiceName
;
1781 LoadParams
.DriverObject
= NULL
;
1782 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1784 /* Call the load/unload routine, depending on current process */
1785 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1787 /* Just call right away */
1788 IopLoadUnloadDriver(&LoadParams
);
1792 /* Load/Unload must be called from system process */
1793 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1794 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1795 (PVOID
)&LoadParams
);
1798 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1800 /* And wait when it completes */
1801 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1805 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
1808 return LoadParams
.Status
;
1814 * Unloads a legacy device driver.
1818 * Name of the service to unload (registry key).
1828 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
1830 return IopUnloadDriver(DriverServiceName
, FALSE
);