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