ba23a12bd9ac17622a42359c71be9a5bd1b96187
[reactos.git] / reactos / ntoskrnl / io / iomgr / driver.c
1 /*
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)
9 */
10
11 /* INCLUDES *******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS ********************************************************************/
18
19 LIST_ENTRY DriverReinitListHead;
20 KSPIN_LOCK DriverReinitListLock;
21 PLIST_ENTRY DriverReinitTailEntry;
22
23 PLIST_ENTRY DriverBootReinitTailEntry;
24 LIST_ENTRY DriverBootReinitListHead;
25 KSPIN_LOCK DriverBootReinitListLock;
26
27 UNICODE_STRING IopHardwareDatabaseKey =
28 RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
29
30 POBJECT_TYPE IoDriverObjectType = NULL;
31
32 #define TAG_RTLREGISTRY 'vrqR'
33
34 extern BOOLEAN ExpInTextModeSetup;
35 extern BOOLEAN PnpSystemInit;
36
37 USHORT IopGroupIndex;
38 PLIST_ENTRY IopGroupTable;
39
40 /* PRIVATE FUNCTIONS **********************************************************/
41
42 NTSTATUS NTAPI
43 IopInvalidDeviceRequest(
44 PDEVICE_OBJECT DeviceObject,
45 PIRP Irp)
46 {
47 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
48 Irp->IoStatus.Information = 0;
49 IoCompleteRequest(Irp, IO_NO_INCREMENT);
50 return STATUS_INVALID_DEVICE_REQUEST;
51 }
52
53 VOID
54 NTAPI
55 IopDeleteDriver(IN PVOID ObjectBody)
56 {
57 PDRIVER_OBJECT DriverObject = ObjectBody;
58 PIO_CLIENT_EXTENSION DriverExtension, NextDriverExtension;
59 PAGED_CODE();
60
61 DPRINT1("Deleting driver object '%wZ'\n", &DriverObject->DriverName);
62
63 /* There must be no device objects remaining at this point */
64 ASSERT(!DriverObject->DeviceObject);
65
66 /* Get the extension and loop them */
67 DriverExtension = IoGetDrvObjExtension(DriverObject)->
68 ClientDriverExtension;
69 while (DriverExtension)
70 {
71 /* Get the next one */
72 NextDriverExtension = DriverExtension->NextExtension;
73 ExFreePoolWithTag(DriverExtension, TAG_DRIVER_EXTENSION);
74
75 /* Move on */
76 DriverExtension = NextDriverExtension;
77 }
78
79 /* Check if the driver image is still loaded */
80 if (DriverObject->DriverSection)
81 {
82 /* Unload it */
83 MmUnloadSystemImage(DriverObject->DriverSection);
84 }
85
86 /* Check if it has a name */
87 if (DriverObject->DriverName.Buffer)
88 {
89 /* Free it */
90 ExFreePool(DriverObject->DriverName.Buffer);
91 }
92
93 #if 0 /* See a bit of hack in IopCreateDriver */
94 /* Check if it has a service key name */
95 if (DriverObject->DriverExtension->ServiceKeyName.Buffer)
96 {
97 /* Free it */
98 ExFreePool(DriverObject->DriverExtension->ServiceKeyName.Buffer);
99 }
100 #endif
101 }
102
103 NTSTATUS FASTCALL
104 IopGetDriverObject(
105 PDRIVER_OBJECT *DriverObject,
106 PUNICODE_STRING ServiceName,
107 BOOLEAN FileSystem)
108 {
109 PDRIVER_OBJECT Object;
110 WCHAR NameBuffer[MAX_PATH];
111 UNICODE_STRING DriverName;
112 NTSTATUS Status;
113
114 DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
115 DriverObject, ServiceName, FileSystem);
116
117 *DriverObject = NULL;
118
119 /* Create ModuleName string */
120 if (ServiceName == NULL || ServiceName->Buffer == NULL)
121 /* We don't know which DriverObject we have to open */
122 return STATUS_INVALID_PARAMETER_2;
123
124 DriverName.Buffer = NameBuffer;
125 DriverName.Length = 0;
126 DriverName.MaximumLength = sizeof(NameBuffer);
127
128 if (FileSystem == TRUE)
129 RtlAppendUnicodeToString(&DriverName, FILESYSTEM_ROOT_NAME);
130 else
131 RtlAppendUnicodeToString(&DriverName, DRIVER_ROOT_NAME);
132 RtlAppendUnicodeStringToString(&DriverName, ServiceName);
133
134 DPRINT("Driver name: '%wZ'\n", &DriverName);
135
136 /* Open driver object */
137 Status = ObReferenceObjectByName(
138 &DriverName,
139 OBJ_OPENIF | OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, /* Attributes */
140 NULL, /* PassedAccessState */
141 0, /* DesiredAccess */
142 IoDriverObjectType,
143 KernelMode,
144 NULL, /* ParseContext */
145 (PVOID*)&Object);
146
147 if (!NT_SUCCESS(Status))
148 {
149 DPRINT("Failed to reference driver object, status=0x%08x\n", Status);
150 return Status;
151 }
152
153 *DriverObject = Object;
154
155 DPRINT("Driver Object: %p\n", Object);
156
157 return STATUS_SUCCESS;
158 }
159
160 /*
161 * RETURNS
162 * TRUE if String2 contains String1 as a suffix.
163 */
164 BOOLEAN
165 NTAPI
166 IopSuffixUnicodeString(
167 IN PCUNICODE_STRING String1,
168 IN PCUNICODE_STRING String2)
169 {
170 PWCHAR pc1;
171 PWCHAR pc2;
172 ULONG Length;
173
174 if (String2->Length < String1->Length)
175 return FALSE;
176
177 Length = String1->Length / 2;
178 pc1 = String1->Buffer;
179 pc2 = &String2->Buffer[String2->Length / sizeof(WCHAR) - Length];
180
181 if (pc1 && pc2)
182 {
183 while (Length--)
184 {
185 if( *pc1++ != *pc2++ )
186 return FALSE;
187 }
188 return TRUE;
189 }
190 return FALSE;
191 }
192
193 /*
194 * IopDisplayLoadingMessage
195 *
196 * Display 'Loading XXX...' message.
197 */
198
199 VOID
200 FASTCALL
201 INIT_FUNCTION
202 IopDisplayLoadingMessage(PUNICODE_STRING ServiceName)
203 {
204 CHAR TextBuffer[256];
205 UNICODE_STRING DotSys = RTL_CONSTANT_STRING(L".SYS");
206
207 if (ExpInTextModeSetup) return;
208 if (!KeLoaderBlock) return;
209 RtlUpcaseUnicodeString(ServiceName, ServiceName, FALSE);
210 snprintf(TextBuffer, sizeof(TextBuffer),
211 "%s%sSystem32\\Drivers\\%wZ%s\n",
212 KeLoaderBlock->ArcBootDeviceName,
213 KeLoaderBlock->NtBootPathName,
214 ServiceName,
215 IopSuffixUnicodeString(&DotSys, ServiceName) ? "" : ".SYS");
216 HalDisplayString(TextBuffer);
217 }
218
219 /*
220 * IopNormalizeImagePath
221 *
222 * Normalize an image path to contain complete path.
223 *
224 * Parameters
225 * ImagePath
226 * The input path and on exit the result path. ImagePath.Buffer
227 * must be allocated by ExAllocatePool on input. Caller is responsible
228 * for freeing the buffer when it's no longer needed.
229 *
230 * ServiceName
231 * Name of the service that ImagePath belongs to.
232 *
233 * Return Value
234 * Status
235 *
236 * Remarks
237 * The input image path isn't freed on error.
238 */
239
240 NTSTATUS FASTCALL
241 IopNormalizeImagePath(
242 IN OUT PUNICODE_STRING ImagePath,
243 IN PUNICODE_STRING ServiceName)
244 {
245 UNICODE_STRING InputImagePath;
246
247 DPRINT("Normalizing image path '%wZ' for service '%wZ'\n", ImagePath, ServiceName);
248
249 RtlCopyMemory(
250 &InputImagePath,
251 ImagePath,
252 sizeof(UNICODE_STRING));
253
254 if (InputImagePath.Length == 0)
255 {
256 ImagePath->Length = 0;
257 ImagePath->MaximumLength =
258 (33 * sizeof(WCHAR)) + ServiceName->Length + sizeof(UNICODE_NULL);
259 ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
260 if (ImagePath->Buffer == NULL)
261 return STATUS_NO_MEMORY;
262
263 RtlAppendUnicodeToString(ImagePath, L"\\SystemRoot\\system32\\drivers\\");
264 RtlAppendUnicodeStringToString(ImagePath, ServiceName);
265 RtlAppendUnicodeToString(ImagePath, L".sys");
266 } else
267 if (InputImagePath.Buffer[0] != L'\\')
268 {
269 ImagePath->Length = 0;
270 ImagePath->MaximumLength =
271 12 * sizeof(WCHAR) + InputImagePath.Length + sizeof(UNICODE_NULL);
272 ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
273 if (ImagePath->Buffer == NULL)
274 return STATUS_NO_MEMORY;
275
276 RtlAppendUnicodeToString(ImagePath, L"\\SystemRoot\\");
277 RtlAppendUnicodeStringToString(ImagePath, &InputImagePath);
278
279 /* Free caller's string */
280 ExFreePoolWithTag(InputImagePath.Buffer, TAG_RTLREGISTRY);
281 }
282
283 DPRINT("Normalized image path is '%wZ' for service '%wZ'\n", ImagePath, ServiceName);
284
285 return STATUS_SUCCESS;
286 }
287
288 /*
289 * IopLoadServiceModule
290 *
291 * Load a module specified by registry settings for service.
292 *
293 * Parameters
294 * ServiceName
295 * Name of the service to load.
296 *
297 * Return Value
298 * Status
299 */
300
301 NTSTATUS FASTCALL
302 IopLoadServiceModule(
303 IN PUNICODE_STRING ServiceName,
304 OUT PLDR_DATA_TABLE_ENTRY *ModuleObject)
305 {
306 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
307 ULONG ServiceStart;
308 UNICODE_STRING ServiceImagePath, CCSName;
309 NTSTATUS Status;
310 HANDLE CCSKey, ServiceKey;
311 PVOID BaseAddress;
312
313 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName, ModuleObject);
314
315 /* FIXME: This check may be removed once the bug is fixed */
316 if (ServiceName->Buffer == NULL)
317 {
318 DPRINT1("If you see this, please report to Fireball or hpoussin!\n");
319 return STATUS_UNSUCCESSFUL;
320 }
321
322 if (ExpInTextModeSetup)
323 {
324 /* We have no registry, but luckily we know where all the drivers are */
325
326 /* ServiceStart < 4 is all that matters */
327 ServiceStart = 0;
328
329 /* IopNormalizeImagePath will do all of the work for us if we give it an empty string */
330 ServiceImagePath.Length = ServiceImagePath.MaximumLength = 0;
331 ServiceImagePath.Buffer = NULL;
332 }
333 else
334 {
335 /* Open CurrentControlSet */
336 RtlInitUnicodeString(&CCSName,
337 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
338 Status = IopOpenRegistryKeyEx(&CCSKey, NULL, &CCSName, KEY_READ);
339 if (!NT_SUCCESS(Status))
340 {
341 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
342 return Status;
343 }
344
345 /* Open service key */
346 Status = IopOpenRegistryKeyEx(&ServiceKey, CCSKey, ServiceName, KEY_READ);
347 if (!NT_SUCCESS(Status))
348 {
349 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
350 ZwClose(CCSKey);
351 return Status;
352 }
353
354 /*
355 * Get information about the service.
356 */
357
358 RtlZeroMemory(QueryTable, sizeof(QueryTable));
359
360 RtlInitUnicodeString(&ServiceImagePath, NULL);
361
362 QueryTable[0].Name = L"Start";
363 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
364 QueryTable[0].EntryContext = &ServiceStart;
365
366 QueryTable[1].Name = L"ImagePath";
367 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
368 QueryTable[1].EntryContext = &ServiceImagePath;
369
370 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
371 (PWSTR)ServiceKey, QueryTable, NULL, NULL);
372
373 ZwClose(ServiceKey);
374 ZwClose(CCSKey);
375
376 if (!NT_SUCCESS(Status))
377 {
378 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
379 return Status;
380 }
381 }
382
383 /*
384 * Normalize the image path for all later processing.
385 */
386
387 Status = IopNormalizeImagePath(&ServiceImagePath, ServiceName);
388
389 if (!NT_SUCCESS(Status))
390 {
391 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
392 return Status;
393 }
394
395 /*
396 * Case for disabled drivers
397 */
398
399 if (ServiceStart >= 4)
400 {
401 /* We can't load this */
402 Status = STATUS_DRIVER_UNABLE_TO_LOAD;
403 }
404 else
405 {
406 DPRINT("Loading module from %wZ\n", &ServiceImagePath);
407 Status = MmLoadSystemImage(&ServiceImagePath, NULL, NULL, 0, (PVOID)ModuleObject, &BaseAddress);
408 if (NT_SUCCESS(Status))
409 {
410 IopDisplayLoadingMessage(ServiceName);
411 }
412 }
413
414 ExFreePool(ServiceImagePath.Buffer);
415
416 /*
417 * Now check if the module was loaded successfully.
418 */
419
420 if (!NT_SUCCESS(Status))
421 {
422 DPRINT("Module loading failed (Status %x)\n", Status);
423 }
424
425 DPRINT("Module loading (Status %x)\n", Status);
426
427 return Status;
428 }
429
430 VOID
431 NTAPI
432 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry);
433
434 /*
435 * IopInitializeDriverModule
436 *
437 * Initalize a loaded driver.
438 *
439 * Parameters
440 * DeviceNode
441 * Pointer to device node.
442 *
443 * ModuleObject
444 * Module object representing the driver. It can be retrieve by
445 * IopLoadServiceModule.
446 *
447 * ServiceName
448 * Name of the service (as in registry).
449 *
450 * FileSystemDriver
451 * Set to TRUE for file system drivers.
452 *
453 * DriverObject
454 * On successful return this contains the driver object representing
455 * the loaded driver.
456 */
457
458 NTSTATUS FASTCALL
459 IopInitializeDriverModule(
460 IN PDEVICE_NODE DeviceNode,
461 IN PLDR_DATA_TABLE_ENTRY ModuleObject,
462 IN PUNICODE_STRING ServiceName,
463 IN BOOLEAN FileSystemDriver,
464 OUT PDRIVER_OBJECT *DriverObject)
465 {
466 const WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
467 WCHAR NameBuffer[MAX_PATH];
468 UNICODE_STRING DriverName;
469 UNICODE_STRING RegistryKey;
470 PDRIVER_INITIALIZE DriverEntry;
471 PDRIVER_OBJECT Driver;
472 NTSTATUS Status;
473
474 DriverEntry = ModuleObject->EntryPoint;
475
476 if (ServiceName != NULL && ServiceName->Length != 0)
477 {
478 RegistryKey.Length = 0;
479 RegistryKey.MaximumLength = sizeof(ServicesKeyName) + ServiceName->Length;
480 RegistryKey.Buffer = ExAllocatePool(PagedPool, RegistryKey.MaximumLength);
481 if (RegistryKey.Buffer == NULL)
482 {
483 return STATUS_INSUFFICIENT_RESOURCES;
484 }
485 RtlAppendUnicodeToString(&RegistryKey, ServicesKeyName);
486 RtlAppendUnicodeStringToString(&RegistryKey, ServiceName);
487 }
488 else
489 {
490 RtlInitUnicodeString(&RegistryKey, NULL);
491 }
492
493 /* Create ModuleName string */
494 if (ServiceName && ServiceName->Length > 0)
495 {
496 if (FileSystemDriver == TRUE)
497 wcscpy(NameBuffer, FILESYSTEM_ROOT_NAME);
498 else
499 wcscpy(NameBuffer, DRIVER_ROOT_NAME);
500
501 RtlInitUnicodeString(&DriverName, NameBuffer);
502 DriverName.MaximumLength = sizeof(NameBuffer);
503
504 RtlAppendUnicodeStringToString(&DriverName, ServiceName);
505
506 DPRINT("Driver name: '%wZ'\n", &DriverName);
507 }
508 else
509 DriverName.Length = 0;
510
511 Status = IopCreateDriver(
512 DriverName.Length > 0 ? &DriverName : NULL,
513 DriverEntry,
514 &RegistryKey,
515 ModuleObject,
516 &Driver);
517 RtlFreeUnicodeString(&RegistryKey);
518
519 *DriverObject = Driver;
520 if (!NT_SUCCESS(Status))
521 {
522 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status);
523 return Status;
524 }
525
526 MmFreeDriverInitialization((PLDR_DATA_TABLE_ENTRY)Driver->DriverSection);
527
528 /* Set the driver as initialized */
529 IopReadyDeviceObjects(Driver);
530
531 if (PnpSystemInit) IopReinitializeDrivers();
532
533 return STATUS_SUCCESS;
534 }
535
536 /*
537 * IopAttachFilterDriversCallback
538 *
539 * Internal routine used by IopAttachFilterDrivers.
540 */
541
542 NTSTATUS NTAPI
543 IopAttachFilterDriversCallback(
544 PWSTR ValueName,
545 ULONG ValueType,
546 PVOID ValueData,
547 ULONG ValueLength,
548 PVOID Context,
549 PVOID EntryContext)
550 {
551 PDEVICE_NODE DeviceNode = Context;
552 UNICODE_STRING ServiceName;
553 PWCHAR Filters;
554 PLDR_DATA_TABLE_ENTRY ModuleObject;
555 PDRIVER_OBJECT DriverObject;
556 NTSTATUS Status;
557
558 for (Filters = ValueData;
559 ((ULONG_PTR)Filters - (ULONG_PTR)ValueData) < ValueLength &&
560 *Filters != 0;
561 Filters += (ServiceName.Length / sizeof(WCHAR)) + 1)
562 {
563 DPRINT("Filter Driver: %S (%wZ)\n", Filters, &DeviceNode->InstancePath);
564
565 ServiceName.Buffer = Filters;
566 ServiceName.MaximumLength =
567 ServiceName.Length = (USHORT)wcslen(Filters) * sizeof(WCHAR);
568
569 Status = IopGetDriverObject(&DriverObject,
570 &ServiceName,
571 FALSE);
572 if (!NT_SUCCESS(Status))
573 {
574 /* Load and initialize the filter driver */
575 Status = IopLoadServiceModule(&ServiceName, &ModuleObject);
576 if (!NT_SUCCESS(Status))
577 continue;
578
579 Status = IopInitializeDriverModule(DeviceNode, ModuleObject, &ServiceName,
580 FALSE, &DriverObject);
581 if (!NT_SUCCESS(Status))
582 continue;
583 }
584
585 Status = IopInitializeDevice(DeviceNode, DriverObject);
586
587 /* Remove extra reference */
588 ObDereferenceObject(DriverObject);
589 }
590
591 return STATUS_SUCCESS;
592 }
593
594 /*
595 * IopAttachFilterDrivers
596 *
597 * Load filter drivers for specified device node.
598 *
599 * Parameters
600 * Lower
601 * Set to TRUE for loading lower level filters or FALSE for upper
602 * level filters.
603 */
604
605 NTSTATUS FASTCALL
606 IopAttachFilterDrivers(
607 PDEVICE_NODE DeviceNode,
608 BOOLEAN Lower)
609 {
610 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { NULL, 0, NULL, NULL, 0, NULL, 0 }, };
611 UNICODE_STRING Class;
612 WCHAR ClassBuffer[40];
613 UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
614 HANDLE EnumRootKey, SubKey;
615 NTSTATUS Status;
616
617 /* Open enumeration root key */
618 Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL,
619 &EnumRoot, KEY_READ);
620 if (!NT_SUCCESS(Status))
621 {
622 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
623 return Status;
624 }
625
626 /* Open subkey */
627 Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey,
628 &DeviceNode->InstancePath, KEY_READ);
629 if (!NT_SUCCESS(Status))
630 {
631 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
632 ZwClose(EnumRootKey);
633 return Status;
634 }
635
636 /*
637 * First load the device filters
638 */
639 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
640 if (Lower)
641 QueryTable[0].Name = L"LowerFilters";
642 else
643 QueryTable[0].Name = L"UpperFilters";
644 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
645
646 RtlQueryRegistryValues(
647 RTL_REGISTRY_HANDLE,
648 (PWSTR)SubKey,
649 QueryTable,
650 DeviceNode,
651 NULL);
652
653 /*
654 * Now get the class GUID
655 */
656 Class.Length = 0;
657 Class.MaximumLength = 40 * sizeof(WCHAR);
658 Class.Buffer = ClassBuffer;
659 QueryTable[0].QueryRoutine = NULL;
660 QueryTable[0].Name = L"ClassGUID";
661 QueryTable[0].EntryContext = &Class;
662 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
663
664 Status = RtlQueryRegistryValues(
665 RTL_REGISTRY_HANDLE,
666 (PWSTR)SubKey,
667 QueryTable,
668 DeviceNode,
669 NULL);
670
671 /* Close handles */
672 ZwClose(SubKey);
673 ZwClose(EnumRootKey);
674
675 /*
676 * Load the class filter driver
677 */
678 if (NT_SUCCESS(Status))
679 {
680 UNICODE_STRING ControlClass = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
681
682 Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL,
683 &ControlClass, KEY_READ);
684 if (!NT_SUCCESS(Status))
685 {
686 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
687 return Status;
688 }
689
690 /* Open subkey */
691 Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey,
692 &Class, KEY_READ);
693 if (!NT_SUCCESS(Status))
694 {
695 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
696 ZwClose(EnumRootKey);
697 return Status;
698 }
699
700 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
701 if (Lower)
702 QueryTable[0].Name = L"LowerFilters";
703 else
704 QueryTable[0].Name = L"UpperFilters";
705 QueryTable[0].EntryContext = NULL;
706 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
707
708 RtlQueryRegistryValues(
709 RTL_REGISTRY_HANDLE,
710 (PWSTR)SubKey,
711 QueryTable,
712 DeviceNode,
713 NULL);
714
715 /* Clean up */
716 ZwClose(SubKey);
717 ZwClose(EnumRootKey);
718 }
719
720 return STATUS_SUCCESS;
721 }
722
723 NTSTATUS
724 NTAPI
725 MiResolveImageReferences(IN PVOID ImageBase,
726 IN PUNICODE_STRING ImageFileDirectory,
727 IN PUNICODE_STRING NamePrefix OPTIONAL,
728 OUT PCHAR *MissingApi,
729 OUT PWCHAR *MissingDriver,
730 OUT PLOAD_IMPORTS *LoadImports);
731
732 //
733 // Used for images already loaded (boot drivers)
734 //
735 NTSTATUS
736 NTAPI
737 INIT_FUNCTION
738 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry,
739 PUNICODE_STRING FileName,
740 PLDR_DATA_TABLE_ENTRY *ModuleObject)
741 {
742 NTSTATUS Status;
743 UNICODE_STRING BaseName, BaseDirectory;
744 PLOAD_IMPORTS LoadedImports = (PVOID)-2;
745 PCHAR MissingApiName, Buffer;
746 PWCHAR MissingDriverName;
747 PVOID DriverBase = LdrEntry->DllBase;
748
749 /* Allocate a buffer we'll use for names */
750 Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
751 if (!Buffer)
752 {
753 /* Fail */
754 return STATUS_INSUFFICIENT_RESOURCES;
755 }
756
757 /* Check for a separator */
758 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
759 {
760 PWCHAR p;
761 ULONG BaseLength;
762
763 /* Loop the path until we get to the base name */
764 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
765 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
766
767 /* Get the length */
768 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
769 BaseLength *= sizeof(WCHAR);
770
771 /* Setup the string */
772 BaseName.Length = (USHORT)BaseLength;
773 BaseName.Buffer = p;
774 }
775 else
776 {
777 /* Otherwise, we already have a base name */
778 BaseName.Length = FileName->Length;
779 BaseName.Buffer = FileName->Buffer;
780 }
781
782 /* Setup the maximum length */
783 BaseName.MaximumLength = BaseName.Length;
784
785 /* Now compute the base directory */
786 BaseDirectory = *FileName;
787 BaseDirectory.Length -= BaseName.Length;
788 BaseDirectory.MaximumLength = BaseDirectory.Length;
789
790 /* Resolve imports */
791 MissingApiName = Buffer;
792 Status = MiResolveImageReferences(DriverBase,
793 &BaseDirectory,
794 NULL,
795 &MissingApiName,
796 &MissingDriverName,
797 &LoadedImports);
798 if (!NT_SUCCESS(Status)) return Status;
799
800 /* Return */
801 *ModuleObject = LdrEntry;
802 return STATUS_SUCCESS;
803 }
804
805 /*
806 * IopInitializeBuiltinDriver
807 *
808 * Initialize a driver that is already loaded in memory.
809 */
810
811 NTSTATUS
812 NTAPI
813 INIT_FUNCTION
814 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
815 {
816 PDEVICE_NODE DeviceNode;
817 PDRIVER_OBJECT DriverObject;
818 NTSTATUS Status;
819 PWCHAR FileNameWithoutPath;
820 LPWSTR FileExtension;
821 PUNICODE_STRING ModuleName = &LdrEntry->BaseDllName;
822 UNICODE_STRING ServiceName;
823
824 /*
825 * Display 'Loading XXX...' message
826 */
827 IopDisplayLoadingMessage(ModuleName);
828 InbvIndicateProgress();
829
830 /*
831 * Generate filename without path (not needed by freeldr)
832 */
833 FileNameWithoutPath = wcsrchr(ModuleName->Buffer, L'\\');
834 if (FileNameWithoutPath == NULL)
835 {
836 FileNameWithoutPath = ModuleName->Buffer;
837 }
838 else
839 {
840 FileNameWithoutPath++;
841 }
842
843 /*
844 * Strip the file extension from ServiceName
845 */
846 RtlCreateUnicodeString(&ServiceName, FileNameWithoutPath);
847 FileExtension = wcsrchr(ServiceName.Buffer, '.');
848 if (FileExtension != NULL)
849 {
850 ServiceName.Length -= (USHORT)wcslen(FileExtension) * sizeof(WCHAR);
851 FileExtension[0] = 0;
852 }
853
854 /*
855 * Determine the right device object
856 */
857 /* Use IopRootDeviceNode for now */
858 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
859 if (!NT_SUCCESS(Status))
860 {
861 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
862 return(Status);
863 }
864
865 /*
866 * Initialize the driver
867 */
868 Status = IopInitializeDriverModule(DeviceNode, LdrEntry,
869 &DeviceNode->ServiceName, FALSE, &DriverObject);
870
871 if (!NT_SUCCESS(Status))
872 {
873 IopFreeDeviceNode(DeviceNode);
874 return Status;
875 }
876
877 Status = IopInitializeDevice(DeviceNode, DriverObject);
878 if (NT_SUCCESS(Status))
879 {
880 Status = IopStartDevice(DeviceNode);
881 }
882
883 /* Remove extra reference from IopInitializeDriverModule */
884 ObDereferenceObject(DriverObject);
885
886 return Status;
887 }
888
889 /*
890 * IopInitializeBootDrivers
891 *
892 * Initialize boot drivers and free memory for boot files.
893 *
894 * Parameters
895 * None
896 *
897 * Return Value
898 * None
899 */
900 VOID
901 FASTCALL
902 INIT_FUNCTION
903 IopInitializeBootDrivers(VOID)
904 {
905 PLIST_ENTRY ListHead, NextEntry, NextEntry2;
906 PLDR_DATA_TABLE_ENTRY LdrEntry;
907 PDEVICE_NODE DeviceNode;
908 PDRIVER_OBJECT DriverObject;
909 LDR_DATA_TABLE_ENTRY ModuleObject;
910 NTSTATUS Status;
911 UNICODE_STRING DriverName;
912 ULONG i, Index;
913 PDRIVER_INFORMATION DriverInfo, DriverInfoTag;
914 HANDLE KeyHandle;
915 PBOOT_DRIVER_LIST_ENTRY BootEntry;
916 DPRINT("IopInitializeBootDrivers()\n");
917
918 /* Use IopRootDeviceNode for now */
919 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, NULL, &DeviceNode);
920 if (!NT_SUCCESS(Status)) return;
921
922 /* Setup the module object for the RAW FS Driver */
923 ModuleObject.DllBase = NULL;
924 ModuleObject.SizeOfImage = 0;
925 ModuleObject.EntryPoint = RawFsDriverEntry;
926 RtlInitUnicodeString(&DriverName, L"RAW");
927
928 /* Initialize it */
929 Status = IopInitializeDriverModule(DeviceNode,
930 &ModuleObject,
931 &DriverName,
932 TRUE,
933 &DriverObject);
934 if (!NT_SUCCESS(Status))
935 {
936 /* Fail */
937 IopFreeDeviceNode(DeviceNode);
938 return;
939 }
940
941 /* Now initialize the associated device */
942 Status = IopInitializeDevice(DeviceNode, DriverObject);
943 if (!NT_SUCCESS(Status))
944 {
945 /* Fail */
946 IopFreeDeviceNode(DeviceNode);
947 ObDereferenceObject(DriverObject);
948 return;
949 }
950
951 /* Start it up */
952 Status = IopStartDevice(DeviceNode);
953 if (!NT_SUCCESS(Status))
954 {
955 /* Fail */
956 IopFreeDeviceNode(DeviceNode);
957 ObDereferenceObject(DriverObject);
958 return;
959 }
960
961 /* Get highest group order index */
962 IopGroupIndex = PpInitGetGroupOrderIndex(NULL);
963 if (IopGroupIndex == 0xFFFF) ASSERT(FALSE);
964
965 /* Allocate the group table */
966 IopGroupTable = ExAllocatePoolWithTag(PagedPool,
967 IopGroupIndex * sizeof(LIST_ENTRY),
968 TAG_IO);
969 if (IopGroupTable == NULL) ASSERT(FALSE);
970
971 /* Initialize the group table lists */
972 for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]);
973
974 /* Loop the boot modules */
975 ListHead = &KeLoaderBlock->LoadOrderListHead;
976 NextEntry = ListHead->Flink;
977 while (ListHead != NextEntry)
978 {
979 /* Get the entry */
980 LdrEntry = CONTAINING_RECORD(NextEntry,
981 LDR_DATA_TABLE_ENTRY,
982 InLoadOrderLinks);
983
984 /* Check if the DLL needs to be initialized */
985 if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
986 {
987 /* Call its entrypoint */
988 MmCallDllInitialize(LdrEntry, NULL);
989 }
990
991 /* Go to the next driver */
992 NextEntry = NextEntry->Flink;
993 }
994
995 /* Loop the boot drivers */
996 ListHead = &KeLoaderBlock->BootDriverListHead;
997 NextEntry = ListHead->Flink;
998 while (ListHead != NextEntry)
999 {
1000 /* Get the entry */
1001 BootEntry = CONTAINING_RECORD(NextEntry,
1002 BOOT_DRIVER_LIST_ENTRY,
1003 Link);
1004
1005 /* Get the driver loader entry */
1006 LdrEntry = BootEntry->LdrEntry;
1007
1008 /* Allocate our internal accounting structure */
1009 DriverInfo = ExAllocatePoolWithTag(PagedPool,
1010 sizeof(DRIVER_INFORMATION),
1011 TAG_IO);
1012 if (DriverInfo)
1013 {
1014 /* Zero it and initialize it */
1015 RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION));
1016 InitializeListHead(&DriverInfo->Link);
1017 DriverInfo->DataTableEntry = BootEntry;
1018
1019 /* Open the registry key */
1020 Status = IopOpenRegistryKeyEx(&KeyHandle,
1021 NULL,
1022 &BootEntry->RegistryPath,
1023 KEY_READ);
1024 if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */
1025 ((KeLoaderBlock->SetupLdrBlock) && ((KeyHandle = (PVOID)1)))) // yes, it's an assignment!
1026 {
1027 /* Save the handle */
1028 DriverInfo->ServiceHandle = KeyHandle;
1029
1030 /* Get the group oder index */
1031 Index = PpInitGetGroupOrderIndex(KeyHandle);
1032
1033 /* Get the tag position */
1034 DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle);
1035
1036 /* Insert it into the list, at the right place */
1037 ASSERT(Index < IopGroupIndex);
1038 NextEntry2 = IopGroupTable[Index].Flink;
1039 while (NextEntry2 != &IopGroupTable[Index])
1040 {
1041 /* Get the driver info */
1042 DriverInfoTag = CONTAINING_RECORD(NextEntry2,
1043 DRIVER_INFORMATION,
1044 Link);
1045
1046 /* Check if we found the right tag position */
1047 if (DriverInfoTag->TagPosition > DriverInfo->TagPosition)
1048 {
1049 /* We're done */
1050 break;
1051 }
1052
1053 /* Next entry */
1054 NextEntry2 = NextEntry2->Flink;
1055 }
1056
1057 /* Insert us right before the next entry */
1058 NextEntry2 = NextEntry2->Blink;
1059 InsertHeadList(NextEntry2, &DriverInfo->Link);
1060 }
1061 }
1062
1063 /* Go to the next driver */
1064 NextEntry = NextEntry->Flink;
1065 }
1066
1067 /* Loop each group index */
1068 for (i = 0; i < IopGroupIndex; i++)
1069 {
1070 /* Loop each group table */
1071 NextEntry = IopGroupTable[i].Flink;
1072 while (NextEntry != &IopGroupTable[i])
1073 {
1074 /* Get the entry */
1075 DriverInfo = CONTAINING_RECORD(NextEntry,
1076 DRIVER_INFORMATION,
1077 Link);
1078
1079 /* Get the driver loader entry */
1080 LdrEntry = DriverInfo->DataTableEntry->LdrEntry;
1081
1082 /* Initialize it */
1083 IopInitializeBuiltinDriver(LdrEntry);
1084
1085 /* Next entry */
1086 NextEntry = NextEntry->Flink;
1087 }
1088 }
1089
1090 /* In old ROS, the loader list became empty after this point. Simulate. */
1091 InitializeListHead(&KeLoaderBlock->LoadOrderListHead);
1092 }
1093
1094 VOID
1095 FASTCALL
1096 INIT_FUNCTION
1097 IopInitializeSystemDrivers(VOID)
1098 {
1099 PUNICODE_STRING *DriverList, *SavedList;
1100
1101 /* No system drivers on the boot cd */
1102 if (KeLoaderBlock->SetupLdrBlock) return;
1103
1104 /* Get the driver list */
1105 SavedList = DriverList = CmGetSystemDriverList();
1106 ASSERT(DriverList);
1107
1108 /* Loop it */
1109 while (*DriverList)
1110 {
1111 /* Load the driver */
1112 ZwLoadDriver(*DriverList);
1113
1114 /* Free the entry */
1115 RtlFreeUnicodeString(*DriverList);
1116 ExFreePool(*DriverList);
1117
1118 /* Next entry */
1119 InbvIndicateProgress();
1120 DriverList++;
1121 }
1122
1123 /* Free the list */
1124 ExFreePool(SavedList);
1125 }
1126
1127 /*
1128 * IopUnloadDriver
1129 *
1130 * Unloads a device driver.
1131 *
1132 * Parameters
1133 * DriverServiceName
1134 * Name of the service to unload (registry key).
1135 *
1136 * UnloadPnpDrivers
1137 * Whether to unload Plug & Plug or only legacy drivers. If this
1138 * parameter is set to FALSE, the routine will unload only legacy
1139 * drivers.
1140 *
1141 * Return Value
1142 * Status
1143 *
1144 * To do
1145 * Guard the whole function by SEH.
1146 */
1147
1148 NTSTATUS NTAPI
1149 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
1150 {
1151 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1152 UNICODE_STRING ImagePath;
1153 UNICODE_STRING ServiceName;
1154 UNICODE_STRING ObjectName;
1155 PDRIVER_OBJECT DriverObject;
1156 PDEVICE_OBJECT DeviceObject;
1157 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1158 LOAD_UNLOAD_PARAMS LoadParams;
1159 NTSTATUS Status;
1160 LPWSTR Start;
1161 BOOLEAN SafeToUnload = TRUE;
1162
1163 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName, UnloadPnpDrivers);
1164
1165 PAGED_CODE();
1166
1167 /*
1168 * Get the service name from the registry key name
1169 */
1170
1171 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
1172 if (Start == NULL)
1173 Start = DriverServiceName->Buffer;
1174 else
1175 Start++;
1176
1177 RtlInitUnicodeString(&ServiceName, Start);
1178
1179 /*
1180 * Construct the driver object name
1181 */
1182
1183 ObjectName.Length = ((USHORT)wcslen(Start) + 8) * sizeof(WCHAR);
1184 ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
1185 ObjectName.Buffer = ExAllocatePool(PagedPool, ObjectName.MaximumLength);
1186 if (!ObjectName.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
1187 wcscpy(ObjectName.Buffer, L"\\Driver\\");
1188 memcpy(ObjectName.Buffer + 8, Start, ObjectName.Length - 8 * sizeof(WCHAR));
1189 ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = 0;
1190
1191 /*
1192 * Find the driver object
1193 */
1194 Status = ObReferenceObjectByName(&ObjectName,
1195 0,
1196 0,
1197 0,
1198 IoDriverObjectType,
1199 KernelMode,
1200 0,
1201 (PVOID*)&DriverObject);
1202
1203 if (!NT_SUCCESS(Status))
1204 {
1205 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
1206 ExFreePool(ObjectName.Buffer);
1207 return Status;
1208 }
1209
1210 /*
1211 * Free the buffer for driver object name
1212 */
1213 ExFreePool(ObjectName.Buffer);
1214
1215 /* Check that driver is not already unloading */
1216 if (DriverObject->Flags & DRVO_UNLOAD_INVOKED)
1217 {
1218 DPRINT1("Driver deletion pending\n");
1219 ObDereferenceObject(DriverObject);
1220 return STATUS_DELETE_PENDING;
1221 }
1222
1223 /*
1224 * Get path of service...
1225 */
1226
1227 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1228
1229 RtlInitUnicodeString(&ImagePath, NULL);
1230
1231 QueryTable[0].Name = L"ImagePath";
1232 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1233 QueryTable[0].EntryContext = &ImagePath;
1234
1235 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1236 DriverServiceName->Buffer, QueryTable, NULL, NULL);
1237
1238 if (!NT_SUCCESS(Status))
1239 {
1240 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1241 ObDereferenceObject(DriverObject);
1242 return Status;
1243 }
1244
1245 /*
1246 * Normalize the image path for all later processing.
1247 */
1248
1249 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1250
1251 if (!NT_SUCCESS(Status))
1252 {
1253 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status);
1254 ObDereferenceObject(DriverObject);
1255 return Status;
1256 }
1257
1258 /*
1259 * Free the service path
1260 */
1261
1262 ExFreePool(ImagePath.Buffer);
1263
1264 /*
1265 * Unload the module and release the references to the device object
1266 */
1267
1268 /* Call the load/unload routine, depending on current process */
1269 if (DriverObject->DriverUnload && DriverObject->DriverSection &&
1270 (UnloadPnpDrivers || (DriverObject->Flags & DRVO_LEGACY_DRIVER)))
1271 {
1272 /* Loop through each device object of the driver
1273 and set DOE_UNLOAD_PENDING flag */
1274 DeviceObject = DriverObject->DeviceObject;
1275 while (DeviceObject)
1276 {
1277 /* Set the unload pending flag for the device */
1278 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1279 DeviceExtension->ExtensionFlags |= DOE_UNLOAD_PENDING;
1280
1281 /* Make sure there are no attached devices or no reference counts */
1282 if ((DeviceObject->ReferenceCount) || (DeviceObject->AttachedDevice))
1283 {
1284 /* Not safe to unload */
1285 DPRINT1("Drivers device object is referenced or has attached devices\n");
1286
1287 SafeToUnload = FALSE;
1288 }
1289
1290 DeviceObject = DeviceObject->NextDevice;
1291 }
1292
1293 /* If not safe to unload, then return success */
1294 if (!SafeToUnload)
1295 {
1296 ObDereferenceObject(DriverObject);
1297 return STATUS_SUCCESS;
1298 }
1299
1300 DPRINT1("Unloading driver '%wZ' (manual)\n", &DriverObject->DriverName);
1301
1302 /* Set the unload invoked flag */
1303 DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
1304
1305 if (PsGetCurrentProcess() == PsInitialSystemProcess)
1306 {
1307 /* Just call right away */
1308 (*DriverObject->DriverUnload)(DriverObject);
1309 }
1310 else
1311 {
1312 /* Load/Unload must be called from system process */
1313
1314 /* Prepare parameters block */
1315 LoadParams.DriverObject = DriverObject;
1316 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
1317
1318 ExInitializeWorkItem(&LoadParams.WorkItem,
1319 (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
1320 (PVOID)&LoadParams);
1321
1322 /* Queue it */
1323 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
1324
1325 /* And wait when it completes */
1326 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
1327 FALSE, NULL);
1328 }
1329
1330 /* Mark the driver object temporary, so it could be deleted later */
1331 ObMakeTemporaryObject(DriverObject);
1332
1333 /* Dereference it 2 times */
1334 ObDereferenceObject(DriverObject);
1335 ObDereferenceObject(DriverObject);
1336
1337 return STATUS_SUCCESS;
1338 }
1339 else
1340 {
1341 DPRINT1("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
1342
1343 /* Dereference one time (refd inside this function) */
1344 ObDereferenceObject(DriverObject);
1345
1346 /* Return unloading failure */
1347 return STATUS_INVALID_DEVICE_REQUEST;
1348 }
1349 }
1350
1351 VOID
1352 NTAPI
1353 IopReinitializeDrivers(VOID)
1354 {
1355 PDRIVER_REINIT_ITEM ReinitItem;
1356 PLIST_ENTRY Entry;
1357
1358 /* Get the first entry and start looping */
1359 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1360 &DriverReinitListLock);
1361 while (Entry)
1362 {
1363 /* Get the item*/
1364 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1365
1366 /* Increment reinitialization counter */
1367 ReinitItem->DriverObject->DriverExtension->Count++;
1368
1369 /* Remove the device object flag */
1370 ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED;
1371
1372 /* Call the routine */
1373 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1374 ReinitItem->Context,
1375 ReinitItem->DriverObject->
1376 DriverExtension->Count);
1377
1378 /* Free the entry */
1379 ExFreePool(Entry);
1380
1381 /* Move to the next one */
1382 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1383 &DriverReinitListLock);
1384 }
1385 }
1386
1387 VOID
1388 NTAPI
1389 IopReinitializeBootDrivers(VOID)
1390 {
1391 PDRIVER_REINIT_ITEM ReinitItem;
1392 PLIST_ENTRY Entry;
1393
1394 /* Get the first entry and start looping */
1395 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1396 &DriverBootReinitListLock);
1397 while (Entry)
1398 {
1399 /* Get the item*/
1400 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1401
1402 /* Increment reinitialization counter */
1403 ReinitItem->DriverObject->DriverExtension->Count++;
1404
1405 /* Remove the device object flag */
1406 ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED;
1407
1408 /* Call the routine */
1409 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1410 ReinitItem->Context,
1411 ReinitItem->DriverObject->
1412 DriverExtension->Count);
1413
1414 /* Free the entry */
1415 ExFreePool(Entry);
1416
1417 /* Move to the next one */
1418 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1419 &DriverBootReinitListLock);
1420 }
1421 }
1422
1423 NTSTATUS
1424 NTAPI
1425 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1426 IN PDRIVER_INITIALIZE InitializationFunction,
1427 IN PUNICODE_STRING RegistryPath,
1428 PLDR_DATA_TABLE_ENTRY ModuleObject,
1429 OUT PDRIVER_OBJECT *pDriverObject)
1430 {
1431 WCHAR NameBuffer[100];
1432 USHORT NameLength;
1433 UNICODE_STRING LocalDriverName;
1434 NTSTATUS Status;
1435 OBJECT_ATTRIBUTES ObjectAttributes;
1436 ULONG ObjectSize;
1437 PDRIVER_OBJECT DriverObject;
1438 UNICODE_STRING ServiceKeyName;
1439 HANDLE hDriver;
1440 ULONG i, RetryCount = 0;
1441
1442 try_again:
1443 /* First, create a unique name for the driver if we don't have one */
1444 if (!DriverName)
1445 {
1446 /* Create a random name and set up the string*/
1447 NameLength = (USHORT)swprintf(NameBuffer,
1448 L"\\Driver\\%08u",
1449 KeTickCount);
1450 LocalDriverName.Length = NameLength * sizeof(WCHAR);
1451 LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1452 LocalDriverName.Buffer = NameBuffer;
1453 }
1454 else
1455 {
1456 /* So we can avoid another code path, use a local var */
1457 LocalDriverName = *DriverName;
1458 }
1459
1460 /* Initialize the Attributes */
1461 ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION);
1462 InitializeObjectAttributes(&ObjectAttributes,
1463 &LocalDriverName,
1464 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
1465 NULL,
1466 NULL);
1467
1468 /* Create the Object */
1469 Status = ObCreateObject(KernelMode,
1470 IoDriverObjectType,
1471 &ObjectAttributes,
1472 KernelMode,
1473 NULL,
1474 ObjectSize,
1475 0,
1476 0,
1477 (PVOID*)&DriverObject);
1478 if (!NT_SUCCESS(Status)) return Status;
1479
1480 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject);
1481
1482 /* Set up the Object */
1483 RtlZeroMemory(DriverObject, ObjectSize);
1484 DriverObject->Type = IO_TYPE_DRIVER;
1485 DriverObject->Size = sizeof(DRIVER_OBJECT);
1486 DriverObject->Flags = DRVO_LEGACY_DRIVER;
1487 DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1488 DriverObject->DriverExtension->DriverObject = DriverObject;
1489 DriverObject->DriverInit = InitializationFunction;
1490 DriverObject->DriverSection = ModuleObject;
1491 /* Loop all Major Functions */
1492 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1493 {
1494 /* Invalidate each function */
1495 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1496 }
1497
1498 /* Set up the service key name buffer */
1499 ServiceKeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
1500 LocalDriverName.Length +
1501 sizeof(WCHAR),
1502 TAG_IO);
1503 if (!ServiceKeyName.Buffer)
1504 {
1505 /* Fail */
1506 ObMakeTemporaryObject(DriverObject);
1507 ObDereferenceObject(DriverObject);
1508 return STATUS_INSUFFICIENT_RESOURCES;
1509 }
1510
1511 /* Fill out the key data and copy the buffer */
1512 ServiceKeyName.Length = LocalDriverName.Length;
1513 ServiceKeyName.MaximumLength = LocalDriverName.MaximumLength;
1514 RtlCopyMemory(ServiceKeyName.Buffer,
1515 LocalDriverName.Buffer,
1516 LocalDriverName.Length);
1517
1518 /* Null-terminate it and set it */
1519 ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1520 DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1521
1522 /* Also store it in the Driver Object. This is a bit of a hack. */
1523 RtlCopyMemory(&DriverObject->DriverName,
1524 &ServiceKeyName,
1525 sizeof(UNICODE_STRING));
1526
1527 /* Add the Object and get its handle */
1528 Status = ObInsertObject(DriverObject,
1529 NULL,
1530 FILE_READ_DATA,
1531 0,
1532 NULL,
1533 &hDriver);
1534
1535 /* Eliminate small possibility when this function is called more than
1536 once in a row, and KeTickCount doesn't get enough time to change */
1537 if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100))
1538 {
1539 RetryCount++;
1540 goto try_again;
1541 }
1542
1543 if (!NT_SUCCESS(Status)) return Status;
1544
1545 /* Now reference it */
1546 Status = ObReferenceObjectByHandle(hDriver,
1547 0,
1548 IoDriverObjectType,
1549 KernelMode,
1550 (PVOID*)&DriverObject,
1551 NULL);
1552
1553 /* Close the extra handle */
1554 ZwClose(hDriver);
1555
1556 if (!NT_SUCCESS(Status))
1557 {
1558 /* Fail */
1559 ObMakeTemporaryObject(DriverObject);
1560 ObDereferenceObject(DriverObject);
1561 return Status;
1562 }
1563
1564 DriverObject->HardwareDatabase = &IopHardwareDatabaseKey;
1565 DriverObject->DriverStart = ModuleObject ? ModuleObject->DllBase : 0;
1566 DriverObject->DriverSize = ModuleObject ? ModuleObject->SizeOfImage : 0;
1567
1568 /* Finally, call its init function */
1569 DPRINT("RegistryKey: %wZ\n", RegistryPath);
1570 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction);
1571 Status = (*InitializationFunction)(DriverObject, RegistryPath);
1572 if (!NT_SUCCESS(Status))
1573 {
1574 /* If it didn't work, then kill the object */
1575 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status);
1576 DriverObject->DriverSection = NULL;
1577 ObMakeTemporaryObject(DriverObject);
1578 ObDereferenceObject(DriverObject);
1579 return Status;
1580 }
1581 else
1582 {
1583 /* Returns to caller the object */
1584 *pDriverObject = DriverObject;
1585 }
1586
1587 /* We're going to say if we don't have any DOs from DriverEntry, then we're not legacy.
1588 * Other parts of the I/O manager depend on this behavior */
1589 if (!DriverObject->DeviceObject) DriverObject->Flags &= ~DRVO_LEGACY_DRIVER;
1590
1591 /* Loop all Major Functions */
1592 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1593 {
1594 /*
1595 * Make sure the driver didn't set any dispatch entry point to NULL!
1596 * Doing so is illegal; drivers shouldn't touch entry points they
1597 * do not implement.
1598 */
1599
1600 /* Check if it did so anyway */
1601 if (!DriverObject->MajorFunction[i])
1602 {
1603 /* Print a warning in the debug log */
1604 DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%d] to NULL!\n",
1605 &DriverObject->DriverName, i);
1606
1607 /* Fix it up */
1608 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1609 }
1610 }
1611
1612 /* Return the Status */
1613 return Status;
1614 }
1615
1616 /* PUBLIC FUNCTIONS ***********************************************************/
1617
1618 /*
1619 * @implemented
1620 */
1621 NTSTATUS
1622 NTAPI
1623 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1624 IN PDRIVER_INITIALIZE InitializationFunction)
1625 {
1626 PDRIVER_OBJECT DriverObject;
1627 return IopCreateDriver(DriverName, InitializationFunction, NULL, NULL, &DriverObject);
1628 }
1629
1630 /*
1631 * @implemented
1632 */
1633 VOID
1634 NTAPI
1635 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject)
1636 {
1637 /* Simply dereference the Object */
1638 ObDereferenceObject(DriverObject);
1639 }
1640
1641 /*
1642 * @implemented
1643 */
1644 VOID
1645 NTAPI
1646 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1647 IN PDRIVER_REINITIALIZE ReinitRoutine,
1648 IN PVOID Context)
1649 {
1650 PDRIVER_REINIT_ITEM ReinitItem;
1651
1652 /* Allocate the entry */
1653 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1654 sizeof(DRIVER_REINIT_ITEM),
1655 TAG_REINIT);
1656 if (!ReinitItem) return;
1657
1658 /* Fill it out */
1659 ReinitItem->DriverObject = DriverObject;
1660 ReinitItem->ReinitRoutine = ReinitRoutine;
1661 ReinitItem->Context = Context;
1662
1663 /* Set the Driver Object flag and insert the entry into the list */
1664 DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
1665 ExInterlockedInsertTailList(&DriverBootReinitListHead,
1666 &ReinitItem->ItemEntry,
1667 &DriverBootReinitListLock);
1668 }
1669
1670 /*
1671 * @implemented
1672 */
1673 VOID
1674 NTAPI
1675 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1676 IN PDRIVER_REINITIALIZE ReinitRoutine,
1677 IN PVOID Context)
1678 {
1679 PDRIVER_REINIT_ITEM ReinitItem;
1680
1681 /* Allocate the entry */
1682 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1683 sizeof(DRIVER_REINIT_ITEM),
1684 TAG_REINIT);
1685 if (!ReinitItem) return;
1686
1687 /* Fill it out */
1688 ReinitItem->DriverObject = DriverObject;
1689 ReinitItem->ReinitRoutine = ReinitRoutine;
1690 ReinitItem->Context = Context;
1691
1692 /* Set the Driver Object flag and insert the entry into the list */
1693 DriverObject->Flags |= DRVO_REINIT_REGISTERED;
1694 ExInterlockedInsertTailList(&DriverReinitListHead,
1695 &ReinitItem->ItemEntry,
1696 &DriverReinitListLock);
1697 }
1698
1699 /*
1700 * @implemented
1701 */
1702 NTSTATUS
1703 NTAPI
1704 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1705 IN PVOID ClientIdentificationAddress,
1706 IN ULONG DriverObjectExtensionSize,
1707 OUT PVOID *DriverObjectExtension)
1708 {
1709 KIRQL OldIrql;
1710 PIO_CLIENT_EXTENSION DriverExtensions, NewDriverExtension;
1711 BOOLEAN Inserted = FALSE;
1712
1713 /* Assume failure */
1714 *DriverObjectExtension = NULL;
1715
1716 /* Allocate the extension */
1717 NewDriverExtension = ExAllocatePoolWithTag(NonPagedPool,
1718 sizeof(IO_CLIENT_EXTENSION) +
1719 DriverObjectExtensionSize,
1720 TAG_DRIVER_EXTENSION);
1721 if (!NewDriverExtension) return STATUS_INSUFFICIENT_RESOURCES;
1722
1723 /* Clear the extension for teh caller */
1724 RtlZeroMemory(NewDriverExtension,
1725 sizeof(IO_CLIENT_EXTENSION) + DriverObjectExtensionSize);
1726
1727 /* Acqure lock */
1728 OldIrql = KeRaiseIrqlToDpcLevel();
1729
1730 /* Fill out the extension */
1731 NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
1732
1733 /* Loop the current extensions */
1734 DriverExtensions = IoGetDrvObjExtension(DriverObject)->
1735 ClientDriverExtension;
1736 while (DriverExtensions)
1737 {
1738 /* Check if the identifier matches */
1739 if (DriverExtensions->ClientIdentificationAddress ==
1740 ClientIdentificationAddress)
1741 {
1742 /* We have a collision, break out */
1743 break;
1744 }
1745
1746 /* Go to the next one */
1747 DriverExtensions = DriverExtensions->NextExtension;
1748 }
1749
1750 /* Check if we didn't collide */
1751 if (!DriverExtensions)
1752 {
1753 /* Link this one in */
1754 NewDriverExtension->NextExtension =
1755 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1756 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension =
1757 NewDriverExtension;
1758 Inserted = TRUE;
1759 }
1760
1761 /* Release the lock */
1762 KeLowerIrql(OldIrql);
1763
1764 /* Check if insertion failed */
1765 if (!Inserted)
1766 {
1767 /* Free the entry and fail */
1768 ExFreePool(NewDriverExtension);
1769 return STATUS_OBJECT_NAME_COLLISION;
1770 }
1771
1772 /* Otherwise, return the pointer */
1773 *DriverObjectExtension = NewDriverExtension + 1;
1774 return STATUS_SUCCESS;
1775 }
1776
1777 /*
1778 * @implemented
1779 */
1780 PVOID
1781 NTAPI
1782 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1783 IN PVOID ClientIdentificationAddress)
1784 {
1785 KIRQL OldIrql;
1786 PIO_CLIENT_EXTENSION DriverExtensions;
1787
1788 /* Acquire lock */
1789 OldIrql = KeRaiseIrqlToDpcLevel();
1790
1791 /* Loop the list until we find the right one */
1792 DriverExtensions = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1793 while (DriverExtensions)
1794 {
1795 /* Check for a match */
1796 if (DriverExtensions->ClientIdentificationAddress ==
1797 ClientIdentificationAddress)
1798 {
1799 /* Break out */
1800 break;
1801 }
1802
1803 /* Keep looping */
1804 DriverExtensions = DriverExtensions->NextExtension;
1805 }
1806
1807 /* Release lock */
1808 KeLowerIrql(OldIrql);
1809
1810 /* Return nothing or the extension */
1811 if (!DriverExtensions) return NULL;
1812 return DriverExtensions + 1;
1813 }
1814
1815 VOID NTAPI
1816 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams)
1817 {
1818 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
1819 UNICODE_STRING ImagePath;
1820 UNICODE_STRING ServiceName;
1821 NTSTATUS Status;
1822 ULONG Type;
1823 PDEVICE_NODE DeviceNode;
1824 PDRIVER_OBJECT DriverObject;
1825 PLDR_DATA_TABLE_ENTRY ModuleObject;
1826 PVOID BaseAddress;
1827 WCHAR *cur;
1828
1829 /* Check if it's an unload request */
1830 if (LoadParams->DriverObject)
1831 {
1832 (*LoadParams->DriverObject->DriverUnload)(LoadParams->DriverObject);
1833
1834 /* Return success and signal the event */
1835 LoadParams->Status = STATUS_SUCCESS;
1836 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1837 return;
1838 }
1839
1840 RtlInitUnicodeString(&ImagePath, NULL);
1841
1842 /*
1843 * Get the service name from the registry key name.
1844 */
1845 ASSERT(LoadParams->ServiceName->Length >= sizeof(WCHAR));
1846
1847 ServiceName = *LoadParams->ServiceName;
1848 cur = LoadParams->ServiceName->Buffer +
1849 (LoadParams->ServiceName->Length / sizeof(WCHAR)) - 1;
1850 while (LoadParams->ServiceName->Buffer != cur)
1851 {
1852 if(*cur == L'\\')
1853 {
1854 ServiceName.Buffer = cur + 1;
1855 ServiceName.Length = LoadParams->ServiceName->Length -
1856 (USHORT)((ULONG_PTR)ServiceName.Buffer -
1857 (ULONG_PTR)LoadParams->ServiceName->Buffer);
1858 break;
1859 }
1860 cur--;
1861 }
1862
1863 /*
1864 * Get service type.
1865 */
1866
1867 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
1868
1869 RtlInitUnicodeString(&ImagePath, NULL);
1870
1871 QueryTable[0].Name = L"Type";
1872 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1873 QueryTable[0].EntryContext = &Type;
1874
1875 QueryTable[1].Name = L"ImagePath";
1876 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1877 QueryTable[1].EntryContext = &ImagePath;
1878
1879 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1880 LoadParams->ServiceName->Buffer, QueryTable, NULL, NULL);
1881
1882 if (!NT_SUCCESS(Status))
1883 {
1884 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
1885 if (ImagePath.Buffer)
1886 ExFreePool(ImagePath.Buffer);
1887 LoadParams->Status = Status;
1888 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1889 return;
1890 }
1891
1892 /*
1893 * Normalize the image path for all later processing.
1894 */
1895
1896 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1897
1898 if (!NT_SUCCESS(Status))
1899 {
1900 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1901 LoadParams->Status = Status;
1902 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1903 return;
1904 }
1905
1906 DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
1907 DPRINT("Type: %lx\n", Type);
1908
1909 /* Get existing DriverObject pointer (in case the driver has
1910 already been loaded and initialized) */
1911 Status = IopGetDriverObject(
1912 &DriverObject,
1913 &ServiceName,
1914 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1915 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */));
1916
1917 if (!NT_SUCCESS(Status))
1918 {
1919 /*
1920 * Load the driver module
1921 */
1922
1923 DPRINT("Loading module from %wZ\n", &ImagePath);
1924 Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress);
1925
1926 if (!NT_SUCCESS(Status))
1927 {
1928 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
1929 LoadParams->Status = Status;
1930 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1931 return;
1932 }
1933
1934 /*
1935 * Initialize the driver module if it's loaded for the first time
1936 */
1937 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
1938 if (!NT_SUCCESS(Status))
1939 {
1940 DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status);
1941 MmUnloadSystemImage(ModuleObject);
1942 LoadParams->Status = Status;
1943 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1944 return;
1945 }
1946
1947 IopDisplayLoadingMessage(&DeviceNode->ServiceName);
1948
1949 Status = IopInitializeDriverModule(DeviceNode,
1950 ModuleObject,
1951 &DeviceNode->ServiceName,
1952 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1953 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
1954 &DriverObject);
1955 if (!NT_SUCCESS(Status))
1956 {
1957 DPRINT1("IopInitializeDriver() failed (Status %lx)\n", Status);
1958 MmUnloadSystemImage(ModuleObject);
1959 IopFreeDeviceNode(DeviceNode);
1960 LoadParams->Status = Status;
1961 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1962 return;
1963 }
1964
1965 /* Initialize and start device */
1966 IopInitializeDevice(DeviceNode, DriverObject);
1967 Status = IopStartDevice(DeviceNode);
1968 }
1969 else
1970 {
1971 DPRINT("DriverObject already exist in ObjectManager\n");
1972 Status = STATUS_IMAGE_ALREADY_LOADED;
1973
1974 /* IopGetDriverObject references the DriverObject, so dereference it */
1975 ObDereferenceObject(DriverObject);
1976 }
1977
1978 /* Pass status to the caller and signal the event */
1979 LoadParams->Status = Status;
1980 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1981 }
1982
1983 /*
1984 * NtLoadDriver
1985 *
1986 * Loads a device driver.
1987 *
1988 * Parameters
1989 * DriverServiceName
1990 * Name of the service to load (registry key).
1991 *
1992 * Return Value
1993 * Status
1994 *
1995 * Status
1996 * implemented
1997 */
1998 NTSTATUS NTAPI
1999 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
2000 {
2001 UNICODE_STRING CapturedDriverServiceName = { 0, 0, NULL };
2002 KPROCESSOR_MODE PreviousMode;
2003 LOAD_UNLOAD_PARAMS LoadParams;
2004 NTSTATUS Status;
2005
2006 PAGED_CODE();
2007
2008 PreviousMode = KeGetPreviousMode();
2009
2010 /*
2011 * Check security privileges
2012 */
2013
2014 /* FIXME: Uncomment when privileges will be correctly implemented. */
2015 #if 0
2016 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2017 {
2018 DPRINT("Privilege not held\n");
2019 return STATUS_PRIVILEGE_NOT_HELD;
2020 }
2021 #endif
2022
2023 Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
2024 PreviousMode,
2025 DriverServiceName);
2026 if (!NT_SUCCESS(Status))
2027 {
2028 return Status;
2029 }
2030
2031 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
2032
2033 LoadParams.ServiceName = &CapturedDriverServiceName;
2034 LoadParams.DriverObject = NULL;
2035 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
2036
2037 /* Call the load/unload routine, depending on current process */
2038 if (PsGetCurrentProcess() == PsInitialSystemProcess)
2039 {
2040 /* Just call right away */
2041 IopLoadUnloadDriver(&LoadParams);
2042 }
2043 else
2044 {
2045 /* Load/Unload must be called from system process */
2046 ExInitializeWorkItem(&LoadParams.WorkItem,
2047 (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
2048 (PVOID)&LoadParams);
2049
2050 /* Queue it */
2051 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
2052
2053 /* And wait when it completes */
2054 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
2055 FALSE, NULL);
2056 }
2057
2058 ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
2059 PreviousMode);
2060
2061 return LoadParams.Status;
2062 }
2063
2064 /*
2065 * NtUnloadDriver
2066 *
2067 * Unloads a legacy device driver.
2068 *
2069 * Parameters
2070 * DriverServiceName
2071 * Name of the service to unload (registry key).
2072 *
2073 * Return Value
2074 * Status
2075 *
2076 * Status
2077 * implemented
2078 */
2079
2080 NTSTATUS NTAPI
2081 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
2082 {
2083 return IopUnloadDriver(DriverServiceName, FALSE);
2084 }
2085
2086 /* EOF */