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