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