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