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