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