Sync with trunk r63743.
[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 /* No filter value present */
563 if (ValueType == REG_NONE)
564 return STATUS_SUCCESS;
565
566 for (Filters = ValueData;
567 ((ULONG_PTR)Filters - (ULONG_PTR)ValueData) < ValueLength &&
568 *Filters != 0;
569 Filters += (ServiceName.Length / sizeof(WCHAR)) + 1)
570 {
571 DPRINT("Filter Driver: %S (%wZ)\n", Filters, &DeviceNode->InstancePath);
572
573 ServiceName.Buffer = Filters;
574 ServiceName.MaximumLength =
575 ServiceName.Length = (USHORT)wcslen(Filters) * sizeof(WCHAR);
576
577 Status = IopGetDriverObject(&DriverObject,
578 &ServiceName,
579 FALSE);
580 if (!NT_SUCCESS(Status))
581 {
582 /* Load and initialize the filter driver */
583 Status = IopLoadServiceModule(&ServiceName, &ModuleObject);
584 if (!NT_SUCCESS(Status))
585 return Status;
586
587 Status = IopInitializeDriverModule(DeviceNode, ModuleObject, &ServiceName,
588 FALSE, &DriverObject);
589 if (!NT_SUCCESS(Status))
590 return Status;
591 }
592
593 Status = IopInitializeDevice(DeviceNode, DriverObject);
594
595 /* Remove extra reference */
596 ObDereferenceObject(DriverObject);
597
598 if (!NT_SUCCESS(Status))
599 return Status;
600 }
601
602 return STATUS_SUCCESS;
603 }
604
605 /*
606 * IopAttachFilterDrivers
607 *
608 * Load filter drivers for specified device node.
609 *
610 * Parameters
611 * Lower
612 * Set to TRUE for loading lower level filters or FALSE for upper
613 * level filters.
614 */
615
616 NTSTATUS FASTCALL
617 IopAttachFilterDrivers(
618 PDEVICE_NODE DeviceNode,
619 BOOLEAN Lower)
620 {
621 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { NULL, 0, NULL, NULL, 0, NULL, 0 }, };
622 UNICODE_STRING Class;
623 WCHAR ClassBuffer[40];
624 UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
625 HANDLE EnumRootKey, SubKey;
626 NTSTATUS Status;
627
628 /* Open enumeration root key */
629 Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL,
630 &EnumRoot, KEY_READ);
631 if (!NT_SUCCESS(Status))
632 {
633 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
634 return Status;
635 }
636
637 /* Open subkey */
638 Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey,
639 &DeviceNode->InstancePath, KEY_READ);
640 if (!NT_SUCCESS(Status))
641 {
642 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
643 ZwClose(EnumRootKey);
644 return Status;
645 }
646
647 /*
648 * First load the device filters
649 */
650 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
651 if (Lower)
652 QueryTable[0].Name = L"LowerFilters";
653 else
654 QueryTable[0].Name = L"UpperFilters";
655 QueryTable[0].Flags = 0;
656 QueryTable[0].DefaultType = REG_NONE;
657
658 Status = RtlQueryRegistryValues(
659 RTL_REGISTRY_HANDLE,
660 (PWSTR)SubKey,
661 QueryTable,
662 DeviceNode,
663 NULL);
664 if (!NT_SUCCESS(Status))
665 {
666 DPRINT1("Failed to load device %s filters: %08X\n",
667 Lower ? "lower" : "upper", Status);
668 ZwClose(SubKey);
669 ZwClose(EnumRootKey);
670 return Status;
671 }
672
673 /*
674 * Now get the class GUID
675 */
676 Class.Length = 0;
677 Class.MaximumLength = 40 * sizeof(WCHAR);
678 Class.Buffer = ClassBuffer;
679 QueryTable[0].QueryRoutine = NULL;
680 QueryTable[0].Name = L"ClassGUID";
681 QueryTable[0].EntryContext = &Class;
682 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
683
684 Status = RtlQueryRegistryValues(
685 RTL_REGISTRY_HANDLE,
686 (PWSTR)SubKey,
687 QueryTable,
688 DeviceNode,
689 NULL);
690
691 /* Close handles */
692 ZwClose(SubKey);
693 ZwClose(EnumRootKey);
694
695 /*
696 * Load the class filter driver
697 */
698 if (NT_SUCCESS(Status))
699 {
700 UNICODE_STRING ControlClass = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
701
702 Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL,
703 &ControlClass, KEY_READ);
704 if (!NT_SUCCESS(Status))
705 {
706 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
707 return Status;
708 }
709
710 /* Open subkey */
711 Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey,
712 &Class, KEY_READ);
713 if (!NT_SUCCESS(Status))
714 {
715 /* It's okay if there's no class key */
716 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
717 ZwClose(EnumRootKey);
718 return STATUS_SUCCESS;
719 }
720
721 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
722 if (Lower)
723 QueryTable[0].Name = L"LowerFilters";
724 else
725 QueryTable[0].Name = L"UpperFilters";
726 QueryTable[0].EntryContext = NULL;
727 QueryTable[0].Flags = 0;
728 QueryTable[0].DefaultType = REG_NONE;
729
730 Status = RtlQueryRegistryValues(
731 RTL_REGISTRY_HANDLE,
732 (PWSTR)SubKey,
733 QueryTable,
734 DeviceNode,
735 NULL);
736
737 /* Clean up */
738 ZwClose(SubKey);
739 ZwClose(EnumRootKey);
740
741 if (!NT_SUCCESS(Status))
742 {
743 DPRINT1("Failed to load class %s filters: %08X\n",
744 Lower ? "lower" : "upper", Status);
745 ZwClose(SubKey);
746 ZwClose(EnumRootKey);
747 return Status;
748 }
749 }
750
751 return STATUS_SUCCESS;
752 }
753
754 NTSTATUS
755 NTAPI
756 MiResolveImageReferences(IN PVOID ImageBase,
757 IN PUNICODE_STRING ImageFileDirectory,
758 IN PUNICODE_STRING NamePrefix OPTIONAL,
759 OUT PCHAR *MissingApi,
760 OUT PWCHAR *MissingDriver,
761 OUT PLOAD_IMPORTS *LoadImports);
762
763 //
764 // Used for images already loaded (boot drivers)
765 //
766 NTSTATUS
767 NTAPI
768 INIT_FUNCTION
769 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry,
770 PUNICODE_STRING FileName,
771 PLDR_DATA_TABLE_ENTRY *ModuleObject)
772 {
773 NTSTATUS Status;
774 UNICODE_STRING BaseName, BaseDirectory;
775 PLOAD_IMPORTS LoadedImports = (PVOID)-2;
776 PCHAR MissingApiName, Buffer;
777 PWCHAR MissingDriverName;
778 PVOID DriverBase = LdrEntry->DllBase;
779
780 /* Allocate a buffer we'll use for names */
781 Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
782 if (!Buffer)
783 {
784 /* Fail */
785 return STATUS_INSUFFICIENT_RESOURCES;
786 }
787
788 /* Check for a separator */
789 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
790 {
791 PWCHAR p;
792 ULONG BaseLength;
793
794 /* Loop the path until we get to the base name */
795 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
796 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
797
798 /* Get the length */
799 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
800 BaseLength *= sizeof(WCHAR);
801
802 /* Setup the string */
803 BaseName.Length = (USHORT)BaseLength;
804 BaseName.Buffer = p;
805 }
806 else
807 {
808 /* Otherwise, we already have a base name */
809 BaseName.Length = FileName->Length;
810 BaseName.Buffer = FileName->Buffer;
811 }
812
813 /* Setup the maximum length */
814 BaseName.MaximumLength = BaseName.Length;
815
816 /* Now compute the base directory */
817 BaseDirectory = *FileName;
818 BaseDirectory.Length -= BaseName.Length;
819 BaseDirectory.MaximumLength = BaseDirectory.Length;
820
821 /* Resolve imports */
822 MissingApiName = Buffer;
823 Status = MiResolveImageReferences(DriverBase,
824 &BaseDirectory,
825 NULL,
826 &MissingApiName,
827 &MissingDriverName,
828 &LoadedImports);
829
830 /* Free the temporary buffer */
831 ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);
832
833 /* Check the result of the imports resolution */
834 if (!NT_SUCCESS(Status)) return Status;
835
836 /* Return */
837 *ModuleObject = LdrEntry;
838 return STATUS_SUCCESS;
839 }
840
841 /*
842 * IopInitializeBuiltinDriver
843 *
844 * Initialize a driver that is already loaded in memory.
845 */
846
847 NTSTATUS
848 NTAPI
849 INIT_FUNCTION
850 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY BootLdrEntry)
851 {
852 PDEVICE_NODE DeviceNode;
853 PDRIVER_OBJECT DriverObject;
854 NTSTATUS Status;
855 PWCHAR FileNameWithoutPath;
856 LPWSTR FileExtension;
857 PUNICODE_STRING ModuleName = &BootLdrEntry->BaseDllName;
858 PLDR_DATA_TABLE_ENTRY LdrEntry;
859 PLIST_ENTRY NextEntry;
860 UNICODE_STRING ServiceName;
861
862 /*
863 * Display 'Loading XXX...' message
864 */
865 IopDisplayLoadingMessage(ModuleName);
866 InbvIndicateProgress();
867
868 /*
869 * Generate filename without path (not needed by freeldr)
870 */
871 FileNameWithoutPath = wcsrchr(ModuleName->Buffer, L'\\');
872 if (FileNameWithoutPath == NULL)
873 {
874 FileNameWithoutPath = ModuleName->Buffer;
875 }
876 else
877 {
878 FileNameWithoutPath++;
879 }
880
881 /*
882 * Strip the file extension from ServiceName
883 */
884 RtlCreateUnicodeString(&ServiceName, FileNameWithoutPath);
885 FileExtension = wcsrchr(ServiceName.Buffer, '.');
886 if (FileExtension != NULL)
887 {
888 ServiceName.Length -= (USHORT)wcslen(FileExtension) * sizeof(WCHAR);
889 FileExtension[0] = 0;
890 }
891
892 /*
893 * Determine the right device object
894 */
895 /* Use IopRootDeviceNode for now */
896 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
897 if (!NT_SUCCESS(Status))
898 {
899 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
900 return(Status);
901 }
902
903 /* Lookup the new Ldr entry in PsLoadedModuleList */
904 NextEntry = PsLoadedModuleList.Flink;
905 while (NextEntry != &PsLoadedModuleList)
906 {
907 LdrEntry = CONTAINING_RECORD(NextEntry,
908 LDR_DATA_TABLE_ENTRY,
909 InLoadOrderLinks);
910 if (RtlEqualUnicodeString(ModuleName, &LdrEntry->BaseDllName, TRUE))
911 {
912 break;
913 }
914
915 NextEntry = NextEntry->Flink;
916 }
917 NT_ASSERT(NextEntry != &PsLoadedModuleList);
918
919 /*
920 * Initialize the driver
921 */
922 Status = IopInitializeDriverModule(DeviceNode, LdrEntry,
923 &DeviceNode->ServiceName, FALSE, &DriverObject);
924
925 if (!NT_SUCCESS(Status))
926 {
927 IopFreeDeviceNode(DeviceNode);
928 return Status;
929 }
930
931 Status = IopInitializeDevice(DeviceNode, DriverObject);
932 if (NT_SUCCESS(Status))
933 {
934 Status = IopStartDevice(DeviceNode);
935 }
936
937 /* Remove extra reference from IopInitializeDriverModule */
938 ObDereferenceObject(DriverObject);
939
940 return Status;
941 }
942
943 /*
944 * IopInitializeBootDrivers
945 *
946 * Initialize boot drivers and free memory for boot files.
947 *
948 * Parameters
949 * None
950 *
951 * Return Value
952 * None
953 */
954 VOID
955 FASTCALL
956 INIT_FUNCTION
957 IopInitializeBootDrivers(VOID)
958 {
959 PLIST_ENTRY ListHead, NextEntry, NextEntry2;
960 PLDR_DATA_TABLE_ENTRY LdrEntry;
961 PDEVICE_NODE DeviceNode;
962 PDRIVER_OBJECT DriverObject;
963 LDR_DATA_TABLE_ENTRY ModuleObject;
964 NTSTATUS Status;
965 UNICODE_STRING DriverName;
966 ULONG i, Index;
967 PDRIVER_INFORMATION DriverInfo, DriverInfoTag;
968 HANDLE KeyHandle;
969 PBOOT_DRIVER_LIST_ENTRY BootEntry;
970 DPRINT("IopInitializeBootDrivers()\n");
971
972 /* Use IopRootDeviceNode for now */
973 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, NULL, &DeviceNode);
974 if (!NT_SUCCESS(Status)) return;
975
976 /* Setup the module object for the RAW FS Driver */
977 ModuleObject.DllBase = NULL;
978 ModuleObject.SizeOfImage = 0;
979 ModuleObject.EntryPoint = RawFsDriverEntry;
980 RtlInitUnicodeString(&DriverName, L"RAW");
981
982 /* Initialize it */
983 Status = IopInitializeDriverModule(DeviceNode,
984 &ModuleObject,
985 &DriverName,
986 TRUE,
987 &DriverObject);
988 if (!NT_SUCCESS(Status))
989 {
990 /* Fail */
991 IopFreeDeviceNode(DeviceNode);
992 return;
993 }
994
995 /* Now initialize the associated device */
996 Status = IopInitializeDevice(DeviceNode, DriverObject);
997 if (!NT_SUCCESS(Status))
998 {
999 /* Fail */
1000 IopFreeDeviceNode(DeviceNode);
1001 ObDereferenceObject(DriverObject);
1002 return;
1003 }
1004
1005 /* Start it up */
1006 Status = IopStartDevice(DeviceNode);
1007 if (!NT_SUCCESS(Status))
1008 {
1009 /* Fail */
1010 IopFreeDeviceNode(DeviceNode);
1011 ObDereferenceObject(DriverObject);
1012 return;
1013 }
1014
1015 /* Get highest group order index */
1016 IopGroupIndex = PpInitGetGroupOrderIndex(NULL);
1017 if (IopGroupIndex == 0xFFFF) ASSERT(FALSE);
1018
1019 /* Allocate the group table */
1020 IopGroupTable = ExAllocatePoolWithTag(PagedPool,
1021 IopGroupIndex * sizeof(LIST_ENTRY),
1022 TAG_IO);
1023 if (IopGroupTable == NULL) ASSERT(FALSE);
1024
1025 /* Initialize the group table lists */
1026 for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]);
1027
1028 /* Loop the boot modules */
1029 ListHead = &KeLoaderBlock->LoadOrderListHead;
1030 NextEntry = ListHead->Flink;
1031 while (ListHead != NextEntry)
1032 {
1033 /* Get the entry */
1034 LdrEntry = CONTAINING_RECORD(NextEntry,
1035 LDR_DATA_TABLE_ENTRY,
1036 InLoadOrderLinks);
1037
1038 /* Check if the DLL needs to be initialized */
1039 if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
1040 {
1041 /* Call its entrypoint */
1042 MmCallDllInitialize(LdrEntry, NULL);
1043 }
1044
1045 /* Go to the next driver */
1046 NextEntry = NextEntry->Flink;
1047 }
1048
1049 /* Loop the boot drivers */
1050 ListHead = &KeLoaderBlock->BootDriverListHead;
1051 NextEntry = ListHead->Flink;
1052 while (ListHead != NextEntry)
1053 {
1054 /* Get the entry */
1055 BootEntry = CONTAINING_RECORD(NextEntry,
1056 BOOT_DRIVER_LIST_ENTRY,
1057 Link);
1058
1059 /* Get the driver loader entry */
1060 LdrEntry = BootEntry->LdrEntry;
1061
1062 /* Allocate our internal accounting structure */
1063 DriverInfo = ExAllocatePoolWithTag(PagedPool,
1064 sizeof(DRIVER_INFORMATION),
1065 TAG_IO);
1066 if (DriverInfo)
1067 {
1068 /* Zero it and initialize it */
1069 RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION));
1070 InitializeListHead(&DriverInfo->Link);
1071 DriverInfo->DataTableEntry = BootEntry;
1072
1073 /* Open the registry key */
1074 Status = IopOpenRegistryKeyEx(&KeyHandle,
1075 NULL,
1076 &BootEntry->RegistryPath,
1077 KEY_READ);
1078 if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */
1079 ((KeLoaderBlock->SetupLdrBlock) && ((KeyHandle = (PVOID)1)))) // yes, it's an assignment!
1080 {
1081 /* Save the handle */
1082 DriverInfo->ServiceHandle = KeyHandle;
1083
1084 /* Get the group oder index */
1085 Index = PpInitGetGroupOrderIndex(KeyHandle);
1086
1087 /* Get the tag position */
1088 DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle);
1089
1090 /* Insert it into the list, at the right place */
1091 ASSERT(Index < IopGroupIndex);
1092 NextEntry2 = IopGroupTable[Index].Flink;
1093 while (NextEntry2 != &IopGroupTable[Index])
1094 {
1095 /* Get the driver info */
1096 DriverInfoTag = CONTAINING_RECORD(NextEntry2,
1097 DRIVER_INFORMATION,
1098 Link);
1099
1100 /* Check if we found the right tag position */
1101 if (DriverInfoTag->TagPosition > DriverInfo->TagPosition)
1102 {
1103 /* We're done */
1104 break;
1105 }
1106
1107 /* Next entry */
1108 NextEntry2 = NextEntry2->Flink;
1109 }
1110
1111 /* Insert us right before the next entry */
1112 NextEntry2 = NextEntry2->Blink;
1113 InsertHeadList(NextEntry2, &DriverInfo->Link);
1114 }
1115 }
1116
1117 /* Go to the next driver */
1118 NextEntry = NextEntry->Flink;
1119 }
1120
1121 /* Loop each group index */
1122 for (i = 0; i < IopGroupIndex; i++)
1123 {
1124 /* Loop each group table */
1125 NextEntry = IopGroupTable[i].Flink;
1126 while (NextEntry != &IopGroupTable[i])
1127 {
1128 /* Get the entry */
1129 DriverInfo = CONTAINING_RECORD(NextEntry,
1130 DRIVER_INFORMATION,
1131 Link);
1132
1133 /* Get the driver loader entry */
1134 LdrEntry = DriverInfo->DataTableEntry->LdrEntry;
1135
1136 /* Initialize it */
1137 IopInitializeBuiltinDriver(LdrEntry);
1138
1139 /* Next entry */
1140 NextEntry = NextEntry->Flink;
1141 }
1142 }
1143
1144 /* In old ROS, the loader list became empty after this point. Simulate. */
1145 InitializeListHead(&KeLoaderBlock->LoadOrderListHead);
1146 }
1147
1148 VOID
1149 FASTCALL
1150 INIT_FUNCTION
1151 IopInitializeSystemDrivers(VOID)
1152 {
1153 PUNICODE_STRING *DriverList, *SavedList;
1154
1155 /* No system drivers on the boot cd */
1156 if (KeLoaderBlock->SetupLdrBlock) return;
1157
1158 /* Get the driver list */
1159 SavedList = DriverList = CmGetSystemDriverList();
1160 ASSERT(DriverList);
1161
1162 /* Loop it */
1163 while (*DriverList)
1164 {
1165 /* Load the driver */
1166 ZwLoadDriver(*DriverList);
1167
1168 /* Free the entry */
1169 RtlFreeUnicodeString(*DriverList);
1170 ExFreePool(*DriverList);
1171
1172 /* Next entry */
1173 InbvIndicateProgress();
1174 DriverList++;
1175 }
1176
1177 /* Free the list */
1178 ExFreePool(SavedList);
1179 }
1180
1181 /*
1182 * IopUnloadDriver
1183 *
1184 * Unloads a device driver.
1185 *
1186 * Parameters
1187 * DriverServiceName
1188 * Name of the service to unload (registry key).
1189 *
1190 * UnloadPnpDrivers
1191 * Whether to unload Plug & Plug or only legacy drivers. If this
1192 * parameter is set to FALSE, the routine will unload only legacy
1193 * drivers.
1194 *
1195 * Return Value
1196 * Status
1197 *
1198 * To do
1199 * Guard the whole function by SEH.
1200 */
1201
1202 NTSTATUS NTAPI
1203 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
1204 {
1205 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1206 UNICODE_STRING ImagePath;
1207 UNICODE_STRING ServiceName;
1208 UNICODE_STRING ObjectName;
1209 PDRIVER_OBJECT DriverObject;
1210 PDEVICE_OBJECT DeviceObject;
1211 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1212 LOAD_UNLOAD_PARAMS LoadParams;
1213 NTSTATUS Status;
1214 LPWSTR Start;
1215 BOOLEAN SafeToUnload = TRUE;
1216
1217 DPRINT("IopUnloadDriver('%wZ', %u)\n", DriverServiceName, UnloadPnpDrivers);
1218
1219 PAGED_CODE();
1220
1221 /*
1222 * Get the service name from the registry key name
1223 */
1224
1225 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
1226 if (Start == NULL)
1227 Start = DriverServiceName->Buffer;
1228 else
1229 Start++;
1230
1231 RtlInitUnicodeString(&ServiceName, Start);
1232
1233 /*
1234 * Construct the driver object name
1235 */
1236
1237 ObjectName.Length = ((USHORT)wcslen(Start) + 8) * sizeof(WCHAR);
1238 ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
1239 ObjectName.Buffer = ExAllocatePool(PagedPool, ObjectName.MaximumLength);
1240 if (!ObjectName.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
1241 wcscpy(ObjectName.Buffer, DRIVER_ROOT_NAME);
1242 memcpy(ObjectName.Buffer + 8, Start, ObjectName.Length - 8 * sizeof(WCHAR));
1243 ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = 0;
1244
1245 /*
1246 * Find the driver object
1247 */
1248 Status = ObReferenceObjectByName(&ObjectName,
1249 0,
1250 0,
1251 0,
1252 IoDriverObjectType,
1253 KernelMode,
1254 0,
1255 (PVOID*)&DriverObject);
1256
1257 if (!NT_SUCCESS(Status))
1258 {
1259 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
1260 ExFreePool(ObjectName.Buffer);
1261 return Status;
1262 }
1263
1264 /*
1265 * Free the buffer for driver object name
1266 */
1267 ExFreePool(ObjectName.Buffer);
1268
1269 /* Check that driver is not already unloading */
1270 if (DriverObject->Flags & DRVO_UNLOAD_INVOKED)
1271 {
1272 DPRINT1("Driver deletion pending\n");
1273 ObDereferenceObject(DriverObject);
1274 return STATUS_DELETE_PENDING;
1275 }
1276
1277 /*
1278 * Get path of service...
1279 */
1280
1281 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1282
1283 RtlInitUnicodeString(&ImagePath, NULL);
1284
1285 QueryTable[0].Name = L"ImagePath";
1286 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1287 QueryTable[0].EntryContext = &ImagePath;
1288
1289 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1290 DriverServiceName->Buffer, QueryTable, NULL, NULL);
1291
1292 if (!NT_SUCCESS(Status))
1293 {
1294 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1295 ObDereferenceObject(DriverObject);
1296 return Status;
1297 }
1298
1299 /*
1300 * Normalize the image path for all later processing.
1301 */
1302
1303 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1304
1305 if (!NT_SUCCESS(Status))
1306 {
1307 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status);
1308 ObDereferenceObject(DriverObject);
1309 return Status;
1310 }
1311
1312 /*
1313 * Free the service path
1314 */
1315
1316 ExFreePool(ImagePath.Buffer);
1317
1318 /*
1319 * Unload the module and release the references to the device object
1320 */
1321
1322 /* Call the load/unload routine, depending on current process */
1323 if (DriverObject->DriverUnload && DriverObject->DriverSection &&
1324 (UnloadPnpDrivers || (DriverObject->Flags & DRVO_LEGACY_DRIVER)))
1325 {
1326 /* Loop through each device object of the driver
1327 and set DOE_UNLOAD_PENDING flag */
1328 DeviceObject = DriverObject->DeviceObject;
1329 while (DeviceObject)
1330 {
1331 /* Set the unload pending flag for the device */
1332 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1333 DeviceExtension->ExtensionFlags |= DOE_UNLOAD_PENDING;
1334
1335 /* Make sure there are no attached devices or no reference counts */
1336 if ((DeviceObject->ReferenceCount) || (DeviceObject->AttachedDevice))
1337 {
1338 /* Not safe to unload */
1339 DPRINT1("Drivers device object is referenced or has attached devices\n");
1340
1341 SafeToUnload = FALSE;
1342 }
1343
1344 DeviceObject = DeviceObject->NextDevice;
1345 }
1346
1347 /* If not safe to unload, then return success */
1348 if (!SafeToUnload)
1349 {
1350 ObDereferenceObject(DriverObject);
1351 return STATUS_SUCCESS;
1352 }
1353
1354 DPRINT1("Unloading driver '%wZ' (manual)\n", &DriverObject->DriverName);
1355
1356 /* Set the unload invoked flag */
1357 DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
1358
1359 if (PsGetCurrentProcess() == PsInitialSystemProcess)
1360 {
1361 /* Just call right away */
1362 (*DriverObject->DriverUnload)(DriverObject);
1363 }
1364 else
1365 {
1366 /* Load/Unload must be called from system process */
1367
1368 /* Prepare parameters block */
1369 LoadParams.DriverObject = DriverObject;
1370 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
1371
1372 ExInitializeWorkItem(&LoadParams.WorkItem,
1373 (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
1374 (PVOID)&LoadParams);
1375
1376 /* Queue it */
1377 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
1378
1379 /* And wait when it completes */
1380 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
1381 FALSE, NULL);
1382 }
1383
1384 /* Mark the driver object temporary, so it could be deleted later */
1385 ObMakeTemporaryObject(DriverObject);
1386
1387 /* Dereference it 2 times */
1388 ObDereferenceObject(DriverObject);
1389 ObDereferenceObject(DriverObject);
1390
1391 return STATUS_SUCCESS;
1392 }
1393 else
1394 {
1395 DPRINT1("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
1396
1397 /* Dereference one time (refd inside this function) */
1398 ObDereferenceObject(DriverObject);
1399
1400 /* Return unloading failure */
1401 return STATUS_INVALID_DEVICE_REQUEST;
1402 }
1403 }
1404
1405 VOID
1406 NTAPI
1407 IopReinitializeDrivers(VOID)
1408 {
1409 PDRIVER_REINIT_ITEM ReinitItem;
1410 PLIST_ENTRY Entry;
1411
1412 /* Get the first entry and start looping */
1413 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1414 &DriverReinitListLock);
1415 while (Entry)
1416 {
1417 /* Get the item*/
1418 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1419
1420 /* Increment reinitialization counter */
1421 ReinitItem->DriverObject->DriverExtension->Count++;
1422
1423 /* Remove the device object flag */
1424 ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED;
1425
1426 /* Call the routine */
1427 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1428 ReinitItem->Context,
1429 ReinitItem->DriverObject->
1430 DriverExtension->Count);
1431
1432 /* Free the entry */
1433 ExFreePool(Entry);
1434
1435 /* Move to the next one */
1436 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1437 &DriverReinitListLock);
1438 }
1439 }
1440
1441 VOID
1442 NTAPI
1443 IopReinitializeBootDrivers(VOID)
1444 {
1445 PDRIVER_REINIT_ITEM ReinitItem;
1446 PLIST_ENTRY Entry;
1447
1448 /* Get the first entry and start looping */
1449 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1450 &DriverBootReinitListLock);
1451 while (Entry)
1452 {
1453 /* Get the item*/
1454 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1455
1456 /* Increment reinitialization counter */
1457 ReinitItem->DriverObject->DriverExtension->Count++;
1458
1459 /* Remove the device object flag */
1460 ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED;
1461
1462 /* Call the routine */
1463 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1464 ReinitItem->Context,
1465 ReinitItem->DriverObject->
1466 DriverExtension->Count);
1467
1468 /* Free the entry */
1469 ExFreePool(Entry);
1470
1471 /* Move to the next one */
1472 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1473 &DriverBootReinitListLock);
1474 }
1475 }
1476
1477 NTSTATUS
1478 NTAPI
1479 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1480 IN PDRIVER_INITIALIZE InitializationFunction,
1481 IN PUNICODE_STRING RegistryPath,
1482 PLDR_DATA_TABLE_ENTRY ModuleObject,
1483 OUT PDRIVER_OBJECT *pDriverObject)
1484 {
1485 WCHAR NameBuffer[100];
1486 USHORT NameLength;
1487 UNICODE_STRING LocalDriverName;
1488 NTSTATUS Status;
1489 OBJECT_ATTRIBUTES ObjectAttributes;
1490 ULONG ObjectSize;
1491 PDRIVER_OBJECT DriverObject;
1492 UNICODE_STRING ServiceKeyName;
1493 HANDLE hDriver;
1494 ULONG i, RetryCount = 0;
1495
1496 try_again:
1497 /* First, create a unique name for the driver if we don't have one */
1498 if (!DriverName)
1499 {
1500 /* Create a random name and set up the string*/
1501 NameLength = (USHORT)swprintf(NameBuffer,
1502 DRIVER_ROOT_NAME L"%08u",
1503 KeTickCount);
1504 LocalDriverName.Length = NameLength * sizeof(WCHAR);
1505 LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1506 LocalDriverName.Buffer = NameBuffer;
1507 }
1508 else
1509 {
1510 /* So we can avoid another code path, use a local var */
1511 LocalDriverName = *DriverName;
1512 }
1513
1514 /* Initialize the Attributes */
1515 ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION);
1516 InitializeObjectAttributes(&ObjectAttributes,
1517 &LocalDriverName,
1518 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
1519 NULL,
1520 NULL);
1521
1522 /* Create the Object */
1523 Status = ObCreateObject(KernelMode,
1524 IoDriverObjectType,
1525 &ObjectAttributes,
1526 KernelMode,
1527 NULL,
1528 ObjectSize,
1529 0,
1530 0,
1531 (PVOID*)&DriverObject);
1532 if (!NT_SUCCESS(Status)) return Status;
1533
1534 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject);
1535
1536 /* Set up the Object */
1537 RtlZeroMemory(DriverObject, ObjectSize);
1538 DriverObject->Type = IO_TYPE_DRIVER;
1539 DriverObject->Size = sizeof(DRIVER_OBJECT);
1540 DriverObject->Flags = DRVO_LEGACY_DRIVER;
1541 DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1542 DriverObject->DriverExtension->DriverObject = DriverObject;
1543 DriverObject->DriverInit = InitializationFunction;
1544 DriverObject->DriverSection = ModuleObject;
1545 /* Loop all Major Functions */
1546 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1547 {
1548 /* Invalidate each function */
1549 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1550 }
1551
1552 /* Set up the service key name buffer */
1553 ServiceKeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
1554 LocalDriverName.Length +
1555 sizeof(WCHAR),
1556 TAG_IO);
1557 if (!ServiceKeyName.Buffer)
1558 {
1559 /* Fail */
1560 ObMakeTemporaryObject(DriverObject);
1561 ObDereferenceObject(DriverObject);
1562 return STATUS_INSUFFICIENT_RESOURCES;
1563 }
1564
1565 /* Fill out the key data and copy the buffer */
1566 ServiceKeyName.Length = LocalDriverName.Length;
1567 ServiceKeyName.MaximumLength = LocalDriverName.MaximumLength;
1568 RtlCopyMemory(ServiceKeyName.Buffer,
1569 LocalDriverName.Buffer,
1570 LocalDriverName.Length);
1571
1572 /* Null-terminate it and set it */
1573 ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1574 DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1575
1576 /* Also store it in the Driver Object. This is a bit of a hack. */
1577 RtlCopyMemory(&DriverObject->DriverName,
1578 &ServiceKeyName,
1579 sizeof(UNICODE_STRING));
1580
1581 /* Add the Object and get its handle */
1582 Status = ObInsertObject(DriverObject,
1583 NULL,
1584 FILE_READ_DATA,
1585 0,
1586 NULL,
1587 &hDriver);
1588
1589 /* Eliminate small possibility when this function is called more than
1590 once in a row, and KeTickCount doesn't get enough time to change */
1591 if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100))
1592 {
1593 RetryCount++;
1594 goto try_again;
1595 }
1596
1597 if (!NT_SUCCESS(Status)) return Status;
1598
1599 /* Now reference it */
1600 Status = ObReferenceObjectByHandle(hDriver,
1601 0,
1602 IoDriverObjectType,
1603 KernelMode,
1604 (PVOID*)&DriverObject,
1605 NULL);
1606
1607 /* Close the extra handle */
1608 ZwClose(hDriver);
1609
1610 if (!NT_SUCCESS(Status))
1611 {
1612 /* Fail */
1613 ObMakeTemporaryObject(DriverObject);
1614 ObDereferenceObject(DriverObject);
1615 return Status;
1616 }
1617
1618 DriverObject->HardwareDatabase = &IopHardwareDatabaseKey;
1619 DriverObject->DriverStart = ModuleObject ? ModuleObject->DllBase : 0;
1620 DriverObject->DriverSize = ModuleObject ? ModuleObject->SizeOfImage : 0;
1621
1622 /* Finally, call its init function */
1623 DPRINT("RegistryKey: %wZ\n", RegistryPath);
1624 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction);
1625 Status = (*InitializationFunction)(DriverObject, RegistryPath);
1626 if (!NT_SUCCESS(Status))
1627 {
1628 /* If it didn't work, then kill the object */
1629 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status);
1630 DriverObject->DriverSection = NULL;
1631 ObMakeTemporaryObject(DriverObject);
1632 ObDereferenceObject(DriverObject);
1633 return Status;
1634 }
1635 else
1636 {
1637 /* Returns to caller the object */
1638 *pDriverObject = DriverObject;
1639 }
1640
1641 /* We're going to say if we don't have any DOs from DriverEntry, then we're not legacy.
1642 * Other parts of the I/O manager depend on this behavior */
1643 if (!DriverObject->DeviceObject) DriverObject->Flags &= ~DRVO_LEGACY_DRIVER;
1644
1645 /* Loop all Major Functions */
1646 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1647 {
1648 /*
1649 * Make sure the driver didn't set any dispatch entry point to NULL!
1650 * Doing so is illegal; drivers shouldn't touch entry points they
1651 * do not implement.
1652 */
1653
1654 /* Check if it did so anyway */
1655 if (!DriverObject->MajorFunction[i])
1656 {
1657 /* Print a warning in the debug log */
1658 DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%lu] to NULL!\n",
1659 &DriverObject->DriverName, i);
1660
1661 /* Fix it up */
1662 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1663 }
1664 }
1665
1666 /* Return the Status */
1667 return Status;
1668 }
1669
1670 /* PUBLIC FUNCTIONS ***********************************************************/
1671
1672 /*
1673 * @implemented
1674 */
1675 NTSTATUS
1676 NTAPI
1677 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1678 IN PDRIVER_INITIALIZE InitializationFunction)
1679 {
1680 PDRIVER_OBJECT DriverObject;
1681 return IopCreateDriver(DriverName, InitializationFunction, NULL, NULL, &DriverObject);
1682 }
1683
1684 /*
1685 * @implemented
1686 */
1687 VOID
1688 NTAPI
1689 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject)
1690 {
1691 /* Simply dereference the Object */
1692 ObDereferenceObject(DriverObject);
1693 }
1694
1695 /*
1696 * @implemented
1697 */
1698 VOID
1699 NTAPI
1700 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1701 IN PDRIVER_REINITIALIZE ReinitRoutine,
1702 IN PVOID Context)
1703 {
1704 PDRIVER_REINIT_ITEM ReinitItem;
1705
1706 /* Allocate the entry */
1707 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1708 sizeof(DRIVER_REINIT_ITEM),
1709 TAG_REINIT);
1710 if (!ReinitItem) return;
1711
1712 /* Fill it out */
1713 ReinitItem->DriverObject = DriverObject;
1714 ReinitItem->ReinitRoutine = ReinitRoutine;
1715 ReinitItem->Context = Context;
1716
1717 /* Set the Driver Object flag and insert the entry into the list */
1718 DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
1719 ExInterlockedInsertTailList(&DriverBootReinitListHead,
1720 &ReinitItem->ItemEntry,
1721 &DriverBootReinitListLock);
1722 }
1723
1724 /*
1725 * @implemented
1726 */
1727 VOID
1728 NTAPI
1729 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1730 IN PDRIVER_REINITIALIZE ReinitRoutine,
1731 IN PVOID Context)
1732 {
1733 PDRIVER_REINIT_ITEM ReinitItem;
1734
1735 /* Allocate the entry */
1736 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1737 sizeof(DRIVER_REINIT_ITEM),
1738 TAG_REINIT);
1739 if (!ReinitItem) return;
1740
1741 /* Fill it out */
1742 ReinitItem->DriverObject = DriverObject;
1743 ReinitItem->ReinitRoutine = ReinitRoutine;
1744 ReinitItem->Context = Context;
1745
1746 /* Set the Driver Object flag and insert the entry into the list */
1747 DriverObject->Flags |= DRVO_REINIT_REGISTERED;
1748 ExInterlockedInsertTailList(&DriverReinitListHead,
1749 &ReinitItem->ItemEntry,
1750 &DriverReinitListLock);
1751 }
1752
1753 /*
1754 * @implemented
1755 */
1756 NTSTATUS
1757 NTAPI
1758 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1759 IN PVOID ClientIdentificationAddress,
1760 IN ULONG DriverObjectExtensionSize,
1761 OUT PVOID *DriverObjectExtension)
1762 {
1763 KIRQL OldIrql;
1764 PIO_CLIENT_EXTENSION DriverExtensions, NewDriverExtension;
1765 BOOLEAN Inserted = FALSE;
1766
1767 /* Assume failure */
1768 *DriverObjectExtension = NULL;
1769
1770 /* Allocate the extension */
1771 NewDriverExtension = ExAllocatePoolWithTag(NonPagedPool,
1772 sizeof(IO_CLIENT_EXTENSION) +
1773 DriverObjectExtensionSize,
1774 TAG_DRIVER_EXTENSION);
1775 if (!NewDriverExtension) return STATUS_INSUFFICIENT_RESOURCES;
1776
1777 /* Clear the extension for teh caller */
1778 RtlZeroMemory(NewDriverExtension,
1779 sizeof(IO_CLIENT_EXTENSION) + DriverObjectExtensionSize);
1780
1781 /* Acqure lock */
1782 OldIrql = KeRaiseIrqlToDpcLevel();
1783
1784 /* Fill out the extension */
1785 NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
1786
1787 /* Loop the current extensions */
1788 DriverExtensions = IoGetDrvObjExtension(DriverObject)->
1789 ClientDriverExtension;
1790 while (DriverExtensions)
1791 {
1792 /* Check if the identifier matches */
1793 if (DriverExtensions->ClientIdentificationAddress ==
1794 ClientIdentificationAddress)
1795 {
1796 /* We have a collision, break out */
1797 break;
1798 }
1799
1800 /* Go to the next one */
1801 DriverExtensions = DriverExtensions->NextExtension;
1802 }
1803
1804 /* Check if we didn't collide */
1805 if (!DriverExtensions)
1806 {
1807 /* Link this one in */
1808 NewDriverExtension->NextExtension =
1809 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1810 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension =
1811 NewDriverExtension;
1812 Inserted = TRUE;
1813 }
1814
1815 /* Release the lock */
1816 KeLowerIrql(OldIrql);
1817
1818 /* Check if insertion failed */
1819 if (!Inserted)
1820 {
1821 /* Free the entry and fail */
1822 ExFreePoolWithTag(NewDriverExtension, TAG_DRIVER_EXTENSION);
1823 return STATUS_OBJECT_NAME_COLLISION;
1824 }
1825
1826 /* Otherwise, return the pointer */
1827 *DriverObjectExtension = NewDriverExtension + 1;
1828 return STATUS_SUCCESS;
1829 }
1830
1831 /*
1832 * @implemented
1833 */
1834 PVOID
1835 NTAPI
1836 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1837 IN PVOID ClientIdentificationAddress)
1838 {
1839 KIRQL OldIrql;
1840 PIO_CLIENT_EXTENSION DriverExtensions;
1841
1842 /* Acquire lock */
1843 OldIrql = KeRaiseIrqlToDpcLevel();
1844
1845 /* Loop the list until we find the right one */
1846 DriverExtensions = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1847 while (DriverExtensions)
1848 {
1849 /* Check for a match */
1850 if (DriverExtensions->ClientIdentificationAddress ==
1851 ClientIdentificationAddress)
1852 {
1853 /* Break out */
1854 break;
1855 }
1856
1857 /* Keep looping */
1858 DriverExtensions = DriverExtensions->NextExtension;
1859 }
1860
1861 /* Release lock */
1862 KeLowerIrql(OldIrql);
1863
1864 /* Return nothing or the extension */
1865 if (!DriverExtensions) return NULL;
1866 return DriverExtensions + 1;
1867 }
1868
1869 VOID NTAPI
1870 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams)
1871 {
1872 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
1873 UNICODE_STRING ImagePath;
1874 UNICODE_STRING ServiceName;
1875 NTSTATUS Status;
1876 ULONG Type;
1877 PDEVICE_NODE DeviceNode;
1878 PDRIVER_OBJECT DriverObject;
1879 PLDR_DATA_TABLE_ENTRY ModuleObject;
1880 PVOID BaseAddress;
1881 WCHAR *cur;
1882
1883 /* Check if it's an unload request */
1884 if (LoadParams->DriverObject)
1885 {
1886 (*LoadParams->DriverObject->DriverUnload)(LoadParams->DriverObject);
1887
1888 /* Return success and signal the event */
1889 LoadParams->Status = STATUS_SUCCESS;
1890 KeSetEvent(&LoadParams->Event, 0, FALSE);
1891 return;
1892 }
1893
1894 RtlInitUnicodeString(&ImagePath, NULL);
1895
1896 /*
1897 * Get the service name from the registry key name.
1898 */
1899 ASSERT(LoadParams->ServiceName->Length >= sizeof(WCHAR));
1900
1901 ServiceName = *LoadParams->ServiceName;
1902 cur = LoadParams->ServiceName->Buffer +
1903 (LoadParams->ServiceName->Length / sizeof(WCHAR)) - 1;
1904 while (LoadParams->ServiceName->Buffer != cur)
1905 {
1906 if (*cur == L'\\')
1907 {
1908 ServiceName.Buffer = cur + 1;
1909 ServiceName.Length = LoadParams->ServiceName->Length -
1910 (USHORT)((ULONG_PTR)ServiceName.Buffer -
1911 (ULONG_PTR)LoadParams->ServiceName->Buffer);
1912 break;
1913 }
1914 cur--;
1915 }
1916
1917 /*
1918 * Get service type.
1919 */
1920
1921 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
1922
1923 RtlInitUnicodeString(&ImagePath, NULL);
1924
1925 QueryTable[0].Name = L"Type";
1926 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1927 QueryTable[0].EntryContext = &Type;
1928
1929 QueryTable[1].Name = L"ImagePath";
1930 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1931 QueryTable[1].EntryContext = &ImagePath;
1932
1933 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1934 LoadParams->ServiceName->Buffer,
1935 QueryTable, NULL, NULL);
1936 if (!NT_SUCCESS(Status))
1937 {
1938 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
1939 if (ImagePath.Buffer) ExFreePool(ImagePath.Buffer);
1940 LoadParams->Status = Status;
1941 KeSetEvent(&LoadParams->Event, 0, FALSE);
1942 return;
1943 }
1944
1945 /*
1946 * Normalize the image path for all later processing.
1947 */
1948
1949 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1950 if (!NT_SUCCESS(Status))
1951 {
1952 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1953 LoadParams->Status = Status;
1954 KeSetEvent(&LoadParams->Event, 0, FALSE);
1955 return;
1956 }
1957
1958 DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
1959 DPRINT("Type: %lx\n", Type);
1960
1961 /*
1962 * Get existing DriverObject pointer (in case the driver
1963 * has already been loaded and initialized).
1964 */
1965 Status = IopGetDriverObject(&DriverObject,
1966 &ServiceName,
1967 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1968 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */));
1969
1970 if (!NT_SUCCESS(Status))
1971 {
1972 /*
1973 * Load the driver module
1974 */
1975
1976 DPRINT("Loading module from %wZ\n", &ImagePath);
1977 Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress);
1978 if (!NT_SUCCESS(Status))
1979 {
1980 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
1981 LoadParams->Status = Status;
1982 KeSetEvent(&LoadParams->Event, 0, FALSE);
1983 return;
1984 }
1985
1986 /*
1987 * Initialize the driver module if it's loaded for the first time
1988 */
1989 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
1990 if (!NT_SUCCESS(Status))
1991 {
1992 DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status);
1993 MmUnloadSystemImage(ModuleObject);
1994 LoadParams->Status = Status;
1995 KeSetEvent(&LoadParams->Event, 0, FALSE);
1996 return;
1997 }
1998
1999 IopDisplayLoadingMessage(&DeviceNode->ServiceName);
2000
2001 Status = IopInitializeDriverModule(DeviceNode,
2002 ModuleObject,
2003 &DeviceNode->ServiceName,
2004 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
2005 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
2006 &DriverObject);
2007 if (!NT_SUCCESS(Status))
2008 {
2009 DPRINT1("IopInitializeDriverModule() failed (Status %lx)\n", Status);
2010 MmUnloadSystemImage(ModuleObject);
2011 IopFreeDeviceNode(DeviceNode);
2012 LoadParams->Status = Status;
2013 KeSetEvent(&LoadParams->Event, 0, FALSE);
2014 return;
2015 }
2016
2017 /* Initialize and start device */
2018 IopInitializeDevice(DeviceNode, DriverObject);
2019 Status = IopStartDevice(DeviceNode);
2020 }
2021 else
2022 {
2023 DPRINT("DriverObject already exist in ObjectManager\n");
2024 Status = STATUS_IMAGE_ALREADY_LOADED;
2025
2026 /* IopGetDriverObject references the DriverObject, so dereference it */
2027 ObDereferenceObject(DriverObject);
2028 }
2029
2030 /* Pass status to the caller and signal the event */
2031 LoadParams->Status = Status;
2032 KeSetEvent(&LoadParams->Event, 0, FALSE);
2033 }
2034
2035 /*
2036 * NtLoadDriver
2037 *
2038 * Loads a device driver.
2039 *
2040 * Parameters
2041 * DriverServiceName
2042 * Name of the service to load (registry key).
2043 *
2044 * Return Value
2045 * Status
2046 *
2047 * Status
2048 * implemented
2049 */
2050 NTSTATUS NTAPI
2051 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
2052 {
2053 UNICODE_STRING CapturedDriverServiceName = { 0, 0, NULL };
2054 KPROCESSOR_MODE PreviousMode;
2055 LOAD_UNLOAD_PARAMS LoadParams;
2056 NTSTATUS Status;
2057
2058 PAGED_CODE();
2059
2060 PreviousMode = KeGetPreviousMode();
2061
2062 /*
2063 * Check security privileges
2064 */
2065
2066 /* FIXME: Uncomment when privileges will be correctly implemented. */
2067 #if 0
2068 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2069 {
2070 DPRINT("Privilege not held\n");
2071 return STATUS_PRIVILEGE_NOT_HELD;
2072 }
2073 #endif
2074
2075 Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
2076 PreviousMode,
2077 DriverServiceName);
2078 if (!NT_SUCCESS(Status))
2079 {
2080 return Status;
2081 }
2082
2083 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
2084
2085 LoadParams.ServiceName = &CapturedDriverServiceName;
2086 LoadParams.DriverObject = NULL;
2087 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
2088
2089 /* Call the load/unload routine, depending on current process */
2090 if (PsGetCurrentProcess() == PsInitialSystemProcess)
2091 {
2092 /* Just call right away */
2093 IopLoadUnloadDriver(&LoadParams);
2094 }
2095 else
2096 {
2097 /* Load/Unload must be called from system process */
2098 ExInitializeWorkItem(&LoadParams.WorkItem,
2099 (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
2100 (PVOID)&LoadParams);
2101
2102 /* Queue it */
2103 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
2104
2105 /* And wait when it completes */
2106 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
2107 FALSE, NULL);
2108 }
2109
2110 ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
2111 PreviousMode);
2112
2113 return LoadParams.Status;
2114 }
2115
2116 /*
2117 * NtUnloadDriver
2118 *
2119 * Unloads a legacy device driver.
2120 *
2121 * Parameters
2122 * DriverServiceName
2123 * Name of the service to unload (registry key).
2124 *
2125 * Return Value
2126 * Status
2127 *
2128 * Status
2129 * implemented
2130 */
2131
2132 NTSTATUS NTAPI
2133 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
2134 {
2135 return IopUnloadDriver(DriverServiceName, FALSE);
2136 }
2137
2138 /* EOF */