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