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