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