Sync to trunk revision 61757.
[reactos.git] / 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 BootLdrEntry)
822 {
823 PDEVICE_NODE DeviceNode;
824 PDRIVER_OBJECT DriverObject;
825 NTSTATUS Status;
826 PWCHAR FileNameWithoutPath;
827 LPWSTR FileExtension;
828 PUNICODE_STRING ModuleName = &BootLdrEntry->BaseDllName;
829 PLDR_DATA_TABLE_ENTRY LdrEntry;
830 PLIST_ENTRY NextEntry;
831 UNICODE_STRING ServiceName;
832
833 /*
834 * Display 'Loading XXX...' message
835 */
836 IopDisplayLoadingMessage(ModuleName);
837 InbvIndicateProgress();
838
839 /*
840 * Generate filename without path (not needed by freeldr)
841 */
842 FileNameWithoutPath = wcsrchr(ModuleName->Buffer, L'\\');
843 if (FileNameWithoutPath == NULL)
844 {
845 FileNameWithoutPath = ModuleName->Buffer;
846 }
847 else
848 {
849 FileNameWithoutPath++;
850 }
851
852 /*
853 * Strip the file extension from ServiceName
854 */
855 RtlCreateUnicodeString(&ServiceName, FileNameWithoutPath);
856 FileExtension = wcsrchr(ServiceName.Buffer, '.');
857 if (FileExtension != NULL)
858 {
859 ServiceName.Length -= (USHORT)wcslen(FileExtension) * sizeof(WCHAR);
860 FileExtension[0] = 0;
861 }
862
863 /*
864 * Determine the right device object
865 */
866 /* Use IopRootDeviceNode for now */
867 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
868 if (!NT_SUCCESS(Status))
869 {
870 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
871 return(Status);
872 }
873
874 /* Lookup the new Ldr entry in PsLoadedModuleList */
875 NextEntry = PsLoadedModuleList.Flink;
876 while (NextEntry != &PsLoadedModuleList)
877 {
878 LdrEntry = CONTAINING_RECORD(NextEntry,
879 LDR_DATA_TABLE_ENTRY,
880 InLoadOrderLinks);
881 if (RtlEqualUnicodeString(ModuleName, &LdrEntry->BaseDllName, TRUE))
882 {
883 break;
884 }
885
886 NextEntry = NextEntry->Flink;
887 }
888 NT_ASSERT(NextEntry != &PsLoadedModuleList);
889
890 /*
891 * Initialize the driver
892 */
893 Status = IopInitializeDriverModule(DeviceNode, LdrEntry,
894 &DeviceNode->ServiceName, FALSE, &DriverObject);
895
896 if (!NT_SUCCESS(Status))
897 {
898 IopFreeDeviceNode(DeviceNode);
899 return Status;
900 }
901
902 Status = IopInitializeDevice(DeviceNode, DriverObject);
903 if (NT_SUCCESS(Status))
904 {
905 Status = IopStartDevice(DeviceNode);
906 }
907
908 /* Remove extra reference from IopInitializeDriverModule */
909 ObDereferenceObject(DriverObject);
910
911 return Status;
912 }
913
914 /*
915 * IopInitializeBootDrivers
916 *
917 * Initialize boot drivers and free memory for boot files.
918 *
919 * Parameters
920 * None
921 *
922 * Return Value
923 * None
924 */
925 VOID
926 FASTCALL
927 INIT_FUNCTION
928 IopInitializeBootDrivers(VOID)
929 {
930 PLIST_ENTRY ListHead, NextEntry, NextEntry2;
931 PLDR_DATA_TABLE_ENTRY LdrEntry;
932 PDEVICE_NODE DeviceNode;
933 PDRIVER_OBJECT DriverObject;
934 LDR_DATA_TABLE_ENTRY ModuleObject;
935 NTSTATUS Status;
936 UNICODE_STRING DriverName;
937 ULONG i, Index;
938 PDRIVER_INFORMATION DriverInfo, DriverInfoTag;
939 HANDLE KeyHandle;
940 PBOOT_DRIVER_LIST_ENTRY BootEntry;
941 DPRINT("IopInitializeBootDrivers()\n");
942
943 /* Use IopRootDeviceNode for now */
944 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, NULL, &DeviceNode);
945 if (!NT_SUCCESS(Status)) return;
946
947 /* Setup the module object for the RAW FS Driver */
948 ModuleObject.DllBase = NULL;
949 ModuleObject.SizeOfImage = 0;
950 ModuleObject.EntryPoint = RawFsDriverEntry;
951 RtlInitUnicodeString(&DriverName, L"RAW");
952
953 /* Initialize it */
954 Status = IopInitializeDriverModule(DeviceNode,
955 &ModuleObject,
956 &DriverName,
957 TRUE,
958 &DriverObject);
959 if (!NT_SUCCESS(Status))
960 {
961 /* Fail */
962 IopFreeDeviceNode(DeviceNode);
963 return;
964 }
965
966 /* Now initialize the associated device */
967 Status = IopInitializeDevice(DeviceNode, DriverObject);
968 if (!NT_SUCCESS(Status))
969 {
970 /* Fail */
971 IopFreeDeviceNode(DeviceNode);
972 ObDereferenceObject(DriverObject);
973 return;
974 }
975
976 /* Start it up */
977 Status = IopStartDevice(DeviceNode);
978 if (!NT_SUCCESS(Status))
979 {
980 /* Fail */
981 IopFreeDeviceNode(DeviceNode);
982 ObDereferenceObject(DriverObject);
983 return;
984 }
985
986 /* Get highest group order index */
987 IopGroupIndex = PpInitGetGroupOrderIndex(NULL);
988 if (IopGroupIndex == 0xFFFF) ASSERT(FALSE);
989
990 /* Allocate the group table */
991 IopGroupTable = ExAllocatePoolWithTag(PagedPool,
992 IopGroupIndex * sizeof(LIST_ENTRY),
993 TAG_IO);
994 if (IopGroupTable == NULL) ASSERT(FALSE);
995
996 /* Initialize the group table lists */
997 for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]);
998
999 /* Loop the boot modules */
1000 ListHead = &KeLoaderBlock->LoadOrderListHead;
1001 NextEntry = ListHead->Flink;
1002 while (ListHead != NextEntry)
1003 {
1004 /* Get the entry */
1005 LdrEntry = CONTAINING_RECORD(NextEntry,
1006 LDR_DATA_TABLE_ENTRY,
1007 InLoadOrderLinks);
1008
1009 /* Check if the DLL needs to be initialized */
1010 if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
1011 {
1012 /* Call its entrypoint */
1013 MmCallDllInitialize(LdrEntry, NULL);
1014 }
1015
1016 /* Go to the next driver */
1017 NextEntry = NextEntry->Flink;
1018 }
1019
1020 /* Loop the boot drivers */
1021 ListHead = &KeLoaderBlock->BootDriverListHead;
1022 NextEntry = ListHead->Flink;
1023 while (ListHead != NextEntry)
1024 {
1025 /* Get the entry */
1026 BootEntry = CONTAINING_RECORD(NextEntry,
1027 BOOT_DRIVER_LIST_ENTRY,
1028 Link);
1029
1030 /* Get the driver loader entry */
1031 LdrEntry = BootEntry->LdrEntry;
1032
1033 /* Allocate our internal accounting structure */
1034 DriverInfo = ExAllocatePoolWithTag(PagedPool,
1035 sizeof(DRIVER_INFORMATION),
1036 TAG_IO);
1037 if (DriverInfo)
1038 {
1039 /* Zero it and initialize it */
1040 RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION));
1041 InitializeListHead(&DriverInfo->Link);
1042 DriverInfo->DataTableEntry = BootEntry;
1043
1044 /* Open the registry key */
1045 Status = IopOpenRegistryKeyEx(&KeyHandle,
1046 NULL,
1047 &BootEntry->RegistryPath,
1048 KEY_READ);
1049 if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */
1050 ((KeLoaderBlock->SetupLdrBlock) && ((KeyHandle = (PVOID)1)))) // yes, it's an assignment!
1051 {
1052 /* Save the handle */
1053 DriverInfo->ServiceHandle = KeyHandle;
1054
1055 /* Get the group oder index */
1056 Index = PpInitGetGroupOrderIndex(KeyHandle);
1057
1058 /* Get the tag position */
1059 DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle);
1060
1061 /* Insert it into the list, at the right place */
1062 ASSERT(Index < IopGroupIndex);
1063 NextEntry2 = IopGroupTable[Index].Flink;
1064 while (NextEntry2 != &IopGroupTable[Index])
1065 {
1066 /* Get the driver info */
1067 DriverInfoTag = CONTAINING_RECORD(NextEntry2,
1068 DRIVER_INFORMATION,
1069 Link);
1070
1071 /* Check if we found the right tag position */
1072 if (DriverInfoTag->TagPosition > DriverInfo->TagPosition)
1073 {
1074 /* We're done */
1075 break;
1076 }
1077
1078 /* Next entry */
1079 NextEntry2 = NextEntry2->Flink;
1080 }
1081
1082 /* Insert us right before the next entry */
1083 NextEntry2 = NextEntry2->Blink;
1084 InsertHeadList(NextEntry2, &DriverInfo->Link);
1085 }
1086 }
1087
1088 /* Go to the next driver */
1089 NextEntry = NextEntry->Flink;
1090 }
1091
1092 /* Loop each group index */
1093 for (i = 0; i < IopGroupIndex; i++)
1094 {
1095 /* Loop each group table */
1096 NextEntry = IopGroupTable[i].Flink;
1097 while (NextEntry != &IopGroupTable[i])
1098 {
1099 /* Get the entry */
1100 DriverInfo = CONTAINING_RECORD(NextEntry,
1101 DRIVER_INFORMATION,
1102 Link);
1103
1104 /* Get the driver loader entry */
1105 LdrEntry = DriverInfo->DataTableEntry->LdrEntry;
1106
1107 /* Initialize it */
1108 IopInitializeBuiltinDriver(LdrEntry);
1109
1110 /* Next entry */
1111 NextEntry = NextEntry->Flink;
1112 }
1113 }
1114
1115 /* In old ROS, the loader list became empty after this point. Simulate. */
1116 InitializeListHead(&KeLoaderBlock->LoadOrderListHead);
1117 }
1118
1119 VOID
1120 FASTCALL
1121 INIT_FUNCTION
1122 IopInitializeSystemDrivers(VOID)
1123 {
1124 PUNICODE_STRING *DriverList, *SavedList;
1125
1126 /* No system drivers on the boot cd */
1127 if (KeLoaderBlock->SetupLdrBlock) return;
1128
1129 /* Get the driver list */
1130 SavedList = DriverList = CmGetSystemDriverList();
1131 ASSERT(DriverList);
1132
1133 /* Loop it */
1134 while (*DriverList)
1135 {
1136 /* Load the driver */
1137 ZwLoadDriver(*DriverList);
1138
1139 /* Free the entry */
1140 RtlFreeUnicodeString(*DriverList);
1141 ExFreePool(*DriverList);
1142
1143 /* Next entry */
1144 InbvIndicateProgress();
1145 DriverList++;
1146 }
1147
1148 /* Free the list */
1149 ExFreePool(SavedList);
1150 }
1151
1152 /*
1153 * IopUnloadDriver
1154 *
1155 * Unloads a device driver.
1156 *
1157 * Parameters
1158 * DriverServiceName
1159 * Name of the service to unload (registry key).
1160 *
1161 * UnloadPnpDrivers
1162 * Whether to unload Plug & Plug or only legacy drivers. If this
1163 * parameter is set to FALSE, the routine will unload only legacy
1164 * drivers.
1165 *
1166 * Return Value
1167 * Status
1168 *
1169 * To do
1170 * Guard the whole function by SEH.
1171 */
1172
1173 NTSTATUS NTAPI
1174 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
1175 {
1176 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1177 UNICODE_STRING ImagePath;
1178 UNICODE_STRING ServiceName;
1179 UNICODE_STRING ObjectName;
1180 PDRIVER_OBJECT DriverObject;
1181 PDEVICE_OBJECT DeviceObject;
1182 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1183 LOAD_UNLOAD_PARAMS LoadParams;
1184 NTSTATUS Status;
1185 LPWSTR Start;
1186 BOOLEAN SafeToUnload = TRUE;
1187
1188 DPRINT("IopUnloadDriver('%wZ', %u)\n", DriverServiceName, UnloadPnpDrivers);
1189
1190 PAGED_CODE();
1191
1192 /*
1193 * Get the service name from the registry key name
1194 */
1195
1196 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
1197 if (Start == NULL)
1198 Start = DriverServiceName->Buffer;
1199 else
1200 Start++;
1201
1202 RtlInitUnicodeString(&ServiceName, Start);
1203
1204 /*
1205 * Construct the driver object name
1206 */
1207
1208 ObjectName.Length = ((USHORT)wcslen(Start) + 8) * sizeof(WCHAR);
1209 ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
1210 ObjectName.Buffer = ExAllocatePool(PagedPool, ObjectName.MaximumLength);
1211 if (!ObjectName.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
1212 wcscpy(ObjectName.Buffer, DRIVER_ROOT_NAME);
1213 memcpy(ObjectName.Buffer + 8, Start, ObjectName.Length - 8 * sizeof(WCHAR));
1214 ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = 0;
1215
1216 /*
1217 * Find the driver object
1218 */
1219 Status = ObReferenceObjectByName(&ObjectName,
1220 0,
1221 0,
1222 0,
1223 IoDriverObjectType,
1224 KernelMode,
1225 0,
1226 (PVOID*)&DriverObject);
1227
1228 if (!NT_SUCCESS(Status))
1229 {
1230 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
1231 ExFreePool(ObjectName.Buffer);
1232 return Status;
1233 }
1234
1235 /*
1236 * Free the buffer for driver object name
1237 */
1238 ExFreePool(ObjectName.Buffer);
1239
1240 /* Check that driver is not already unloading */
1241 if (DriverObject->Flags & DRVO_UNLOAD_INVOKED)
1242 {
1243 DPRINT1("Driver deletion pending\n");
1244 ObDereferenceObject(DriverObject);
1245 return STATUS_DELETE_PENDING;
1246 }
1247
1248 /*
1249 * Get path of service...
1250 */
1251
1252 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1253
1254 RtlInitUnicodeString(&ImagePath, NULL);
1255
1256 QueryTable[0].Name = L"ImagePath";
1257 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1258 QueryTable[0].EntryContext = &ImagePath;
1259
1260 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1261 DriverServiceName->Buffer, QueryTable, NULL, NULL);
1262
1263 if (!NT_SUCCESS(Status))
1264 {
1265 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1266 ObDereferenceObject(DriverObject);
1267 return Status;
1268 }
1269
1270 /*
1271 * Normalize the image path for all later processing.
1272 */
1273
1274 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1275
1276 if (!NT_SUCCESS(Status))
1277 {
1278 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status);
1279 ObDereferenceObject(DriverObject);
1280 return Status;
1281 }
1282
1283 /*
1284 * Free the service path
1285 */
1286
1287 ExFreePool(ImagePath.Buffer);
1288
1289 /*
1290 * Unload the module and release the references to the device object
1291 */
1292
1293 /* Call the load/unload routine, depending on current process */
1294 if (DriverObject->DriverUnload && DriverObject->DriverSection &&
1295 (UnloadPnpDrivers || (DriverObject->Flags & DRVO_LEGACY_DRIVER)))
1296 {
1297 /* Loop through each device object of the driver
1298 and set DOE_UNLOAD_PENDING flag */
1299 DeviceObject = DriverObject->DeviceObject;
1300 while (DeviceObject)
1301 {
1302 /* Set the unload pending flag for the device */
1303 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1304 DeviceExtension->ExtensionFlags |= DOE_UNLOAD_PENDING;
1305
1306 /* Make sure there are no attached devices or no reference counts */
1307 if ((DeviceObject->ReferenceCount) || (DeviceObject->AttachedDevice))
1308 {
1309 /* Not safe to unload */
1310 DPRINT1("Drivers device object is referenced or has attached devices\n");
1311
1312 SafeToUnload = FALSE;
1313 }
1314
1315 DeviceObject = DeviceObject->NextDevice;
1316 }
1317
1318 /* If not safe to unload, then return success */
1319 if (!SafeToUnload)
1320 {
1321 ObDereferenceObject(DriverObject);
1322 return STATUS_SUCCESS;
1323 }
1324
1325 DPRINT1("Unloading driver '%wZ' (manual)\n", &DriverObject->DriverName);
1326
1327 /* Set the unload invoked flag */
1328 DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
1329
1330 if (PsGetCurrentProcess() == PsInitialSystemProcess)
1331 {
1332 /* Just call right away */
1333 (*DriverObject->DriverUnload)(DriverObject);
1334 }
1335 else
1336 {
1337 /* Load/Unload must be called from system process */
1338
1339 /* Prepare parameters block */
1340 LoadParams.DriverObject = DriverObject;
1341 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
1342
1343 ExInitializeWorkItem(&LoadParams.WorkItem,
1344 (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
1345 (PVOID)&LoadParams);
1346
1347 /* Queue it */
1348 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
1349
1350 /* And wait when it completes */
1351 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
1352 FALSE, NULL);
1353 }
1354
1355 /* Mark the driver object temporary, so it could be deleted later */
1356 ObMakeTemporaryObject(DriverObject);
1357
1358 /* Dereference it 2 times */
1359 ObDereferenceObject(DriverObject);
1360 ObDereferenceObject(DriverObject);
1361
1362 return STATUS_SUCCESS;
1363 }
1364 else
1365 {
1366 DPRINT1("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
1367
1368 /* Dereference one time (refd inside this function) */
1369 ObDereferenceObject(DriverObject);
1370
1371 /* Return unloading failure */
1372 return STATUS_INVALID_DEVICE_REQUEST;
1373 }
1374 }
1375
1376 VOID
1377 NTAPI
1378 IopReinitializeDrivers(VOID)
1379 {
1380 PDRIVER_REINIT_ITEM ReinitItem;
1381 PLIST_ENTRY Entry;
1382
1383 /* Get the first entry and start looping */
1384 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1385 &DriverReinitListLock);
1386 while (Entry)
1387 {
1388 /* Get the item*/
1389 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1390
1391 /* Increment reinitialization counter */
1392 ReinitItem->DriverObject->DriverExtension->Count++;
1393
1394 /* Remove the device object flag */
1395 ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED;
1396
1397 /* Call the routine */
1398 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1399 ReinitItem->Context,
1400 ReinitItem->DriverObject->
1401 DriverExtension->Count);
1402
1403 /* Free the entry */
1404 ExFreePool(Entry);
1405
1406 /* Move to the next one */
1407 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1408 &DriverReinitListLock);
1409 }
1410 }
1411
1412 VOID
1413 NTAPI
1414 IopReinitializeBootDrivers(VOID)
1415 {
1416 PDRIVER_REINIT_ITEM ReinitItem;
1417 PLIST_ENTRY Entry;
1418
1419 /* Get the first entry and start looping */
1420 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1421 &DriverBootReinitListLock);
1422 while (Entry)
1423 {
1424 /* Get the item*/
1425 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1426
1427 /* Increment reinitialization counter */
1428 ReinitItem->DriverObject->DriverExtension->Count++;
1429
1430 /* Remove the device object flag */
1431 ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED;
1432
1433 /* Call the routine */
1434 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1435 ReinitItem->Context,
1436 ReinitItem->DriverObject->
1437 DriverExtension->Count);
1438
1439 /* Free the entry */
1440 ExFreePool(Entry);
1441
1442 /* Move to the next one */
1443 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1444 &DriverBootReinitListLock);
1445 }
1446 }
1447
1448 NTSTATUS
1449 NTAPI
1450 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1451 IN PDRIVER_INITIALIZE InitializationFunction,
1452 IN PUNICODE_STRING RegistryPath,
1453 PLDR_DATA_TABLE_ENTRY ModuleObject,
1454 OUT PDRIVER_OBJECT *pDriverObject)
1455 {
1456 WCHAR NameBuffer[100];
1457 USHORT NameLength;
1458 UNICODE_STRING LocalDriverName;
1459 NTSTATUS Status;
1460 OBJECT_ATTRIBUTES ObjectAttributes;
1461 ULONG ObjectSize;
1462 PDRIVER_OBJECT DriverObject;
1463 UNICODE_STRING ServiceKeyName;
1464 HANDLE hDriver;
1465 ULONG i, RetryCount = 0;
1466
1467 try_again:
1468 /* First, create a unique name for the driver if we don't have one */
1469 if (!DriverName)
1470 {
1471 /* Create a random name and set up the string*/
1472 NameLength = (USHORT)swprintf(NameBuffer,
1473 DRIVER_ROOT_NAME L"%08u",
1474 KeTickCount);
1475 LocalDriverName.Length = NameLength * sizeof(WCHAR);
1476 LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1477 LocalDriverName.Buffer = NameBuffer;
1478 }
1479 else
1480 {
1481 /* So we can avoid another code path, use a local var */
1482 LocalDriverName = *DriverName;
1483 }
1484
1485 /* Initialize the Attributes */
1486 ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION);
1487 InitializeObjectAttributes(&ObjectAttributes,
1488 &LocalDriverName,
1489 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
1490 NULL,
1491 NULL);
1492
1493 /* Create the Object */
1494 Status = ObCreateObject(KernelMode,
1495 IoDriverObjectType,
1496 &ObjectAttributes,
1497 KernelMode,
1498 NULL,
1499 ObjectSize,
1500 0,
1501 0,
1502 (PVOID*)&DriverObject);
1503 if (!NT_SUCCESS(Status)) return Status;
1504
1505 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject);
1506
1507 /* Set up the Object */
1508 RtlZeroMemory(DriverObject, ObjectSize);
1509 DriverObject->Type = IO_TYPE_DRIVER;
1510 DriverObject->Size = sizeof(DRIVER_OBJECT);
1511 DriverObject->Flags = DRVO_LEGACY_DRIVER;
1512 DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1513 DriverObject->DriverExtension->DriverObject = DriverObject;
1514 DriverObject->DriverInit = InitializationFunction;
1515 DriverObject->DriverSection = ModuleObject;
1516 /* Loop all Major Functions */
1517 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1518 {
1519 /* Invalidate each function */
1520 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1521 }
1522
1523 /* Set up the service key name buffer */
1524 ServiceKeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
1525 LocalDriverName.Length +
1526 sizeof(WCHAR),
1527 TAG_IO);
1528 if (!ServiceKeyName.Buffer)
1529 {
1530 /* Fail */
1531 ObMakeTemporaryObject(DriverObject);
1532 ObDereferenceObject(DriverObject);
1533 return STATUS_INSUFFICIENT_RESOURCES;
1534 }
1535
1536 /* Fill out the key data and copy the buffer */
1537 ServiceKeyName.Length = LocalDriverName.Length;
1538 ServiceKeyName.MaximumLength = LocalDriverName.MaximumLength;
1539 RtlCopyMemory(ServiceKeyName.Buffer,
1540 LocalDriverName.Buffer,
1541 LocalDriverName.Length);
1542
1543 /* Null-terminate it and set it */
1544 ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1545 DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1546
1547 /* Also store it in the Driver Object. This is a bit of a hack. */
1548 RtlCopyMemory(&DriverObject->DriverName,
1549 &ServiceKeyName,
1550 sizeof(UNICODE_STRING));
1551
1552 /* Add the Object and get its handle */
1553 Status = ObInsertObject(DriverObject,
1554 NULL,
1555 FILE_READ_DATA,
1556 0,
1557 NULL,
1558 &hDriver);
1559
1560 /* Eliminate small possibility when this function is called more than
1561 once in a row, and KeTickCount doesn't get enough time to change */
1562 if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100))
1563 {
1564 RetryCount++;
1565 goto try_again;
1566 }
1567
1568 if (!NT_SUCCESS(Status)) return Status;
1569
1570 /* Now reference it */
1571 Status = ObReferenceObjectByHandle(hDriver,
1572 0,
1573 IoDriverObjectType,
1574 KernelMode,
1575 (PVOID*)&DriverObject,
1576 NULL);
1577
1578 /* Close the extra handle */
1579 ZwClose(hDriver);
1580
1581 if (!NT_SUCCESS(Status))
1582 {
1583 /* Fail */
1584 ObMakeTemporaryObject(DriverObject);
1585 ObDereferenceObject(DriverObject);
1586 return Status;
1587 }
1588
1589 DriverObject->HardwareDatabase = &IopHardwareDatabaseKey;
1590 DriverObject->DriverStart = ModuleObject ? ModuleObject->DllBase : 0;
1591 DriverObject->DriverSize = ModuleObject ? ModuleObject->SizeOfImage : 0;
1592
1593 /* Finally, call its init function */
1594 DPRINT("RegistryKey: %wZ\n", RegistryPath);
1595 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction);
1596 Status = (*InitializationFunction)(DriverObject, RegistryPath);
1597 if (!NT_SUCCESS(Status))
1598 {
1599 /* If it didn't work, then kill the object */
1600 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status);
1601 DriverObject->DriverSection = NULL;
1602 ObMakeTemporaryObject(DriverObject);
1603 ObDereferenceObject(DriverObject);
1604 return Status;
1605 }
1606 else
1607 {
1608 /* Returns to caller the object */
1609 *pDriverObject = DriverObject;
1610 }
1611
1612 /* We're going to say if we don't have any DOs from DriverEntry, then we're not legacy.
1613 * Other parts of the I/O manager depend on this behavior */
1614 if (!DriverObject->DeviceObject) DriverObject->Flags &= ~DRVO_LEGACY_DRIVER;
1615
1616 /* Loop all Major Functions */
1617 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1618 {
1619 /*
1620 * Make sure the driver didn't set any dispatch entry point to NULL!
1621 * Doing so is illegal; drivers shouldn't touch entry points they
1622 * do not implement.
1623 */
1624
1625 /* Check if it did so anyway */
1626 if (!DriverObject->MajorFunction[i])
1627 {
1628 /* Print a warning in the debug log */
1629 DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%lu] to NULL!\n",
1630 &DriverObject->DriverName, i);
1631
1632 /* Fix it up */
1633 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1634 }
1635 }
1636
1637 /* Return the Status */
1638 return Status;
1639 }
1640
1641 /* PUBLIC FUNCTIONS ***********************************************************/
1642
1643 /*
1644 * @implemented
1645 */
1646 NTSTATUS
1647 NTAPI
1648 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1649 IN PDRIVER_INITIALIZE InitializationFunction)
1650 {
1651 PDRIVER_OBJECT DriverObject;
1652 return IopCreateDriver(DriverName, InitializationFunction, NULL, NULL, &DriverObject);
1653 }
1654
1655 /*
1656 * @implemented
1657 */
1658 VOID
1659 NTAPI
1660 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject)
1661 {
1662 /* Simply dereference the Object */
1663 ObDereferenceObject(DriverObject);
1664 }
1665
1666 /*
1667 * @implemented
1668 */
1669 VOID
1670 NTAPI
1671 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1672 IN PDRIVER_REINITIALIZE ReinitRoutine,
1673 IN PVOID Context)
1674 {
1675 PDRIVER_REINIT_ITEM ReinitItem;
1676
1677 /* Allocate the entry */
1678 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1679 sizeof(DRIVER_REINIT_ITEM),
1680 TAG_REINIT);
1681 if (!ReinitItem) return;
1682
1683 /* Fill it out */
1684 ReinitItem->DriverObject = DriverObject;
1685 ReinitItem->ReinitRoutine = ReinitRoutine;
1686 ReinitItem->Context = Context;
1687
1688 /* Set the Driver Object flag and insert the entry into the list */
1689 DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
1690 ExInterlockedInsertTailList(&DriverBootReinitListHead,
1691 &ReinitItem->ItemEntry,
1692 &DriverBootReinitListLock);
1693 }
1694
1695 /*
1696 * @implemented
1697 */
1698 VOID
1699 NTAPI
1700 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1701 IN PDRIVER_REINITIALIZE ReinitRoutine,
1702 IN PVOID Context)
1703 {
1704 PDRIVER_REINIT_ITEM ReinitItem;
1705
1706 /* Allocate the entry */
1707 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1708 sizeof(DRIVER_REINIT_ITEM),
1709 TAG_REINIT);
1710 if (!ReinitItem) return;
1711
1712 /* Fill it out */
1713 ReinitItem->DriverObject = DriverObject;
1714 ReinitItem->ReinitRoutine = ReinitRoutine;
1715 ReinitItem->Context = Context;
1716
1717 /* Set the Driver Object flag and insert the entry into the list */
1718 DriverObject->Flags |= DRVO_REINIT_REGISTERED;
1719 ExInterlockedInsertTailList(&DriverReinitListHead,
1720 &ReinitItem->ItemEntry,
1721 &DriverReinitListLock);
1722 }
1723
1724 /*
1725 * @implemented
1726 */
1727 NTSTATUS
1728 NTAPI
1729 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1730 IN PVOID ClientIdentificationAddress,
1731 IN ULONG DriverObjectExtensionSize,
1732 OUT PVOID *DriverObjectExtension)
1733 {
1734 KIRQL OldIrql;
1735 PIO_CLIENT_EXTENSION DriverExtensions, NewDriverExtension;
1736 BOOLEAN Inserted = FALSE;
1737
1738 /* Assume failure */
1739 *DriverObjectExtension = NULL;
1740
1741 /* Allocate the extension */
1742 NewDriverExtension = ExAllocatePoolWithTag(NonPagedPool,
1743 sizeof(IO_CLIENT_EXTENSION) +
1744 DriverObjectExtensionSize,
1745 TAG_DRIVER_EXTENSION);
1746 if (!NewDriverExtension) return STATUS_INSUFFICIENT_RESOURCES;
1747
1748 /* Clear the extension for teh caller */
1749 RtlZeroMemory(NewDriverExtension,
1750 sizeof(IO_CLIENT_EXTENSION) + DriverObjectExtensionSize);
1751
1752 /* Acqure lock */
1753 OldIrql = KeRaiseIrqlToDpcLevel();
1754
1755 /* Fill out the extension */
1756 NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
1757
1758 /* Loop the current extensions */
1759 DriverExtensions = IoGetDrvObjExtension(DriverObject)->
1760 ClientDriverExtension;
1761 while (DriverExtensions)
1762 {
1763 /* Check if the identifier matches */
1764 if (DriverExtensions->ClientIdentificationAddress ==
1765 ClientIdentificationAddress)
1766 {
1767 /* We have a collision, break out */
1768 break;
1769 }
1770
1771 /* Go to the next one */
1772 DriverExtensions = DriverExtensions->NextExtension;
1773 }
1774
1775 /* Check if we didn't collide */
1776 if (!DriverExtensions)
1777 {
1778 /* Link this one in */
1779 NewDriverExtension->NextExtension =
1780 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1781 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension =
1782 NewDriverExtension;
1783 Inserted = TRUE;
1784 }
1785
1786 /* Release the lock */
1787 KeLowerIrql(OldIrql);
1788
1789 /* Check if insertion failed */
1790 if (!Inserted)
1791 {
1792 /* Free the entry and fail */
1793 ExFreePoolWithTag(NewDriverExtension, TAG_DRIVER_EXTENSION);
1794 return STATUS_OBJECT_NAME_COLLISION;
1795 }
1796
1797 /* Otherwise, return the pointer */
1798 *DriverObjectExtension = NewDriverExtension + 1;
1799 return STATUS_SUCCESS;
1800 }
1801
1802 /*
1803 * @implemented
1804 */
1805 PVOID
1806 NTAPI
1807 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1808 IN PVOID ClientIdentificationAddress)
1809 {
1810 KIRQL OldIrql;
1811 PIO_CLIENT_EXTENSION DriverExtensions;
1812
1813 /* Acquire lock */
1814 OldIrql = KeRaiseIrqlToDpcLevel();
1815
1816 /* Loop the list until we find the right one */
1817 DriverExtensions = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1818 while (DriverExtensions)
1819 {
1820 /* Check for a match */
1821 if (DriverExtensions->ClientIdentificationAddress ==
1822 ClientIdentificationAddress)
1823 {
1824 /* Break out */
1825 break;
1826 }
1827
1828 /* Keep looping */
1829 DriverExtensions = DriverExtensions->NextExtension;
1830 }
1831
1832 /* Release lock */
1833 KeLowerIrql(OldIrql);
1834
1835 /* Return nothing or the extension */
1836 if (!DriverExtensions) return NULL;
1837 return DriverExtensions + 1;
1838 }
1839
1840 VOID NTAPI
1841 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams)
1842 {
1843 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
1844 UNICODE_STRING ImagePath;
1845 UNICODE_STRING ServiceName;
1846 NTSTATUS Status;
1847 ULONG Type;
1848 PDEVICE_NODE DeviceNode;
1849 PDRIVER_OBJECT DriverObject;
1850 PLDR_DATA_TABLE_ENTRY ModuleObject;
1851 PVOID BaseAddress;
1852 WCHAR *cur;
1853
1854 /* Check if it's an unload request */
1855 if (LoadParams->DriverObject)
1856 {
1857 (*LoadParams->DriverObject->DriverUnload)(LoadParams->DriverObject);
1858
1859 /* Return success and signal the event */
1860 LoadParams->Status = STATUS_SUCCESS;
1861 KeSetEvent(&LoadParams->Event, 0, FALSE);
1862 return;
1863 }
1864
1865 RtlInitUnicodeString(&ImagePath, NULL);
1866
1867 /*
1868 * Get the service name from the registry key name.
1869 */
1870 ASSERT(LoadParams->ServiceName->Length >= sizeof(WCHAR));
1871
1872 ServiceName = *LoadParams->ServiceName;
1873 cur = LoadParams->ServiceName->Buffer +
1874 (LoadParams->ServiceName->Length / sizeof(WCHAR)) - 1;
1875 while (LoadParams->ServiceName->Buffer != cur)
1876 {
1877 if (*cur == L'\\')
1878 {
1879 ServiceName.Buffer = cur + 1;
1880 ServiceName.Length = LoadParams->ServiceName->Length -
1881 (USHORT)((ULONG_PTR)ServiceName.Buffer -
1882 (ULONG_PTR)LoadParams->ServiceName->Buffer);
1883 break;
1884 }
1885 cur--;
1886 }
1887
1888 /*
1889 * Get service type.
1890 */
1891
1892 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
1893
1894 RtlInitUnicodeString(&ImagePath, NULL);
1895
1896 QueryTable[0].Name = L"Type";
1897 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1898 QueryTable[0].EntryContext = &Type;
1899
1900 QueryTable[1].Name = L"ImagePath";
1901 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1902 QueryTable[1].EntryContext = &ImagePath;
1903
1904 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1905 LoadParams->ServiceName->Buffer,
1906 QueryTable, NULL, NULL);
1907 if (!NT_SUCCESS(Status))
1908 {
1909 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
1910 if (ImagePath.Buffer) ExFreePool(ImagePath.Buffer);
1911 LoadParams->Status = Status;
1912 KeSetEvent(&LoadParams->Event, 0, FALSE);
1913 return;
1914 }
1915
1916 /*
1917 * Normalize the image path for all later processing.
1918 */
1919
1920 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1921 if (!NT_SUCCESS(Status))
1922 {
1923 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1924 LoadParams->Status = Status;
1925 KeSetEvent(&LoadParams->Event, 0, FALSE);
1926 return;
1927 }
1928
1929 DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
1930 DPRINT("Type: %lx\n", Type);
1931
1932 /*
1933 * Get existing DriverObject pointer (in case the driver
1934 * has already been loaded and initialized).
1935 */
1936 Status = IopGetDriverObject(&DriverObject,
1937 &ServiceName,
1938 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1939 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */));
1940
1941 if (!NT_SUCCESS(Status))
1942 {
1943 /*
1944 * Load the driver module
1945 */
1946
1947 DPRINT("Loading module from %wZ\n", &ImagePath);
1948 Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress);
1949 if (!NT_SUCCESS(Status))
1950 {
1951 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
1952 LoadParams->Status = Status;
1953 KeSetEvent(&LoadParams->Event, 0, FALSE);
1954 return;
1955 }
1956
1957 /*
1958 * Initialize the driver module if it's loaded for the first time
1959 */
1960 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
1961 if (!NT_SUCCESS(Status))
1962 {
1963 DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status);
1964 MmUnloadSystemImage(ModuleObject);
1965 LoadParams->Status = Status;
1966 KeSetEvent(&LoadParams->Event, 0, FALSE);
1967 return;
1968 }
1969
1970 IopDisplayLoadingMessage(&DeviceNode->ServiceName);
1971
1972 Status = IopInitializeDriverModule(DeviceNode,
1973 ModuleObject,
1974 &DeviceNode->ServiceName,
1975 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1976 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
1977 &DriverObject);
1978 if (!NT_SUCCESS(Status))
1979 {
1980 DPRINT1("IopInitializeDriverModule() failed (Status %lx)\n", Status);
1981 MmUnloadSystemImage(ModuleObject);
1982 IopFreeDeviceNode(DeviceNode);
1983 LoadParams->Status = Status;
1984 KeSetEvent(&LoadParams->Event, 0, FALSE);
1985 return;
1986 }
1987
1988 /* Initialize and start device */
1989 IopInitializeDevice(DeviceNode, DriverObject);
1990 Status = IopStartDevice(DeviceNode);
1991 }
1992 else
1993 {
1994 DPRINT("DriverObject already exist in ObjectManager\n");
1995 Status = STATUS_IMAGE_ALREADY_LOADED;
1996
1997 /* IopGetDriverObject references the DriverObject, so dereference it */
1998 ObDereferenceObject(DriverObject);
1999 }
2000
2001 /* Pass status to the caller and signal the event */
2002 LoadParams->Status = Status;
2003 KeSetEvent(&LoadParams->Event, 0, FALSE);
2004 }
2005
2006 /*
2007 * NtLoadDriver
2008 *
2009 * Loads a device driver.
2010 *
2011 * Parameters
2012 * DriverServiceName
2013 * Name of the service to load (registry key).
2014 *
2015 * Return Value
2016 * Status
2017 *
2018 * Status
2019 * implemented
2020 */
2021 NTSTATUS NTAPI
2022 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
2023 {
2024 UNICODE_STRING CapturedDriverServiceName = { 0, 0, NULL };
2025 KPROCESSOR_MODE PreviousMode;
2026 LOAD_UNLOAD_PARAMS LoadParams;
2027 NTSTATUS Status;
2028
2029 PAGED_CODE();
2030
2031 PreviousMode = KeGetPreviousMode();
2032
2033 /*
2034 * Check security privileges
2035 */
2036
2037 /* FIXME: Uncomment when privileges will be correctly implemented. */
2038 #if 0
2039 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2040 {
2041 DPRINT("Privilege not held\n");
2042 return STATUS_PRIVILEGE_NOT_HELD;
2043 }
2044 #endif
2045
2046 Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
2047 PreviousMode,
2048 DriverServiceName);
2049 if (!NT_SUCCESS(Status))
2050 {
2051 return Status;
2052 }
2053
2054 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
2055
2056 LoadParams.ServiceName = &CapturedDriverServiceName;
2057 LoadParams.DriverObject = NULL;
2058 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
2059
2060 /* Call the load/unload routine, depending on current process */
2061 if (PsGetCurrentProcess() == PsInitialSystemProcess)
2062 {
2063 /* Just call right away */
2064 IopLoadUnloadDriver(&LoadParams);
2065 }
2066 else
2067 {
2068 /* Load/Unload must be called from system process */
2069 ExInitializeWorkItem(&LoadParams.WorkItem,
2070 (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
2071 (PVOID)&LoadParams);
2072
2073 /* Queue it */
2074 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
2075
2076 /* And wait when it completes */
2077 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
2078 FALSE, NULL);
2079 }
2080
2081 ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
2082 PreviousMode);
2083
2084 return LoadParams.Status;
2085 }
2086
2087 /*
2088 * NtUnloadDriver
2089 *
2090 * Unloads a legacy device driver.
2091 *
2092 * Parameters
2093 * DriverServiceName
2094 * Name of the service to unload (registry key).
2095 *
2096 * Return Value
2097 * Status
2098 *
2099 * Status
2100 * implemented
2101 */
2102
2103 NTSTATUS NTAPI
2104 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
2105 {
2106 return IopUnloadDriver(DriverServiceName, FALSE);
2107 }
2108
2109 /* EOF */