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