[NTOSKRNL]
[reactos.git] / reactos / 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->DllBase,
485 ModuleObject->SizeOfImage,
486 &Driver);
487 RtlFreeUnicodeString(&RegistryKey);
488
489 *DriverObject = Driver;
490 if (!NT_SUCCESS(Status))
491 {
492 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status);
493 return Status;
494 }
495
496 /* Set the driver as initialized */
497 IopReadyDeviceObjects(Driver);
498
499 if (PnpSystemInit) IopReinitializeDrivers();
500
501 return STATUS_SUCCESS;
502 }
503
504 /*
505 * IopAttachFilterDriversCallback
506 *
507 * Internal routine used by IopAttachFilterDrivers.
508 */
509
510 NTSTATUS NTAPI
511 IopAttachFilterDriversCallback(
512 PWSTR ValueName,
513 ULONG ValueType,
514 PVOID ValueData,
515 ULONG ValueLength,
516 PVOID Context,
517 PVOID EntryContext)
518 {
519 PDEVICE_NODE DeviceNode = Context;
520 UNICODE_STRING ServiceName;
521 PWCHAR Filters;
522 PLDR_DATA_TABLE_ENTRY ModuleObject;
523 PDRIVER_OBJECT DriverObject;
524 NTSTATUS Status;
525
526 for (Filters = ValueData;
527 ((ULONG_PTR)Filters - (ULONG_PTR)ValueData) < ValueLength &&
528 *Filters != 0;
529 Filters += (ServiceName.Length / sizeof(WCHAR)) + 1)
530 {
531 DPRINT("Filter Driver: %S (%wZ)\n", Filters, &DeviceNode->InstancePath);
532 ServiceName.Buffer = Filters;
533 ServiceName.MaximumLength =
534 ServiceName.Length = wcslen(Filters) * sizeof(WCHAR);
535
536 /* Load and initialize the filter driver */
537 Status = IopLoadServiceModule(&ServiceName, &ModuleObject);
538 if (Status != STATUS_IMAGE_ALREADY_LOADED)
539 {
540 if (!NT_SUCCESS(Status))
541 continue;
542
543 Status = IopInitializeDriverModule(DeviceNode, ModuleObject, &ServiceName,
544 FALSE, &DriverObject);
545 if (!NT_SUCCESS(Status))
546 continue;
547 }
548 else
549 {
550 /* get existing DriverObject pointer */
551 Status = IopGetDriverObject(
552 &DriverObject,
553 &ServiceName,
554 FALSE);
555 if (!NT_SUCCESS(Status))
556 {
557 DPRINT1("IopGetDriverObject() returned status 0x%08x!\n", Status);
558 continue;
559 }
560 }
561
562 Status = IopInitializeDevice(DeviceNode, DriverObject);
563 if (!NT_SUCCESS(Status))
564 continue;
565 }
566
567 return STATUS_SUCCESS;
568 }
569
570 /*
571 * IopAttachFilterDrivers
572 *
573 * Load filter drivers for specified device node.
574 *
575 * Parameters
576 * Lower
577 * Set to TRUE for loading lower level filters or FALSE for upper
578 * level filters.
579 */
580
581 NTSTATUS FASTCALL
582 IopAttachFilterDrivers(
583 PDEVICE_NODE DeviceNode,
584 BOOLEAN Lower)
585 {
586 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { NULL, 0, NULL, NULL, 0, NULL, 0 }, };
587 UNICODE_STRING Class;
588 WCHAR ClassBuffer[40];
589 UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
590 HANDLE EnumRootKey, SubKey;
591 NTSTATUS Status;
592
593 /* Open enumeration root key */
594 Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL,
595 &EnumRoot, KEY_READ);
596 if (!NT_SUCCESS(Status))
597 {
598 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
599 return Status;
600 }
601
602 /* Open subkey */
603 Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey,
604 &DeviceNode->InstancePath, KEY_READ);
605 if (!NT_SUCCESS(Status))
606 {
607 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
608 ZwClose(EnumRootKey);
609 return Status;
610 }
611
612 /*
613 * First load the device filters
614 */
615 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
616 if (Lower)
617 QueryTable[0].Name = L"LowerFilters";
618 else
619 QueryTable[0].Name = L"UpperFilters";
620 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
621
622 RtlQueryRegistryValues(
623 RTL_REGISTRY_HANDLE,
624 (PWSTR)SubKey,
625 QueryTable,
626 DeviceNode,
627 NULL);
628
629 /*
630 * Now get the class GUID
631 */
632 Class.Length = 0;
633 Class.MaximumLength = 40 * sizeof(WCHAR);
634 Class.Buffer = ClassBuffer;
635 QueryTable[0].QueryRoutine = NULL;
636 QueryTable[0].Name = L"ClassGUID";
637 QueryTable[0].EntryContext = &Class;
638 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
639
640 Status = RtlQueryRegistryValues(
641 RTL_REGISTRY_HANDLE,
642 (PWSTR)SubKey,
643 QueryTable,
644 DeviceNode,
645 NULL);
646
647 /* Close handles */
648 ZwClose(SubKey);
649 ZwClose(EnumRootKey);
650
651 /*
652 * Load the class filter driver
653 */
654 if (NT_SUCCESS(Status))
655 {
656 UNICODE_STRING ControlClass = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
657
658 Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL,
659 &ControlClass, KEY_READ);
660 if (!NT_SUCCESS(Status))
661 {
662 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
663 return Status;
664 }
665
666 /* Open subkey */
667 Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey,
668 &Class, KEY_READ);
669 if (!NT_SUCCESS(Status))
670 {
671 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
672 ZwClose(EnumRootKey);
673 return Status;
674 }
675
676 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
677 if (Lower)
678 QueryTable[0].Name = L"LowerFilters";
679 else
680 QueryTable[0].Name = L"UpperFilters";
681 QueryTable[0].EntryContext = NULL;
682 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
683
684 RtlQueryRegistryValues(
685 RTL_REGISTRY_HANDLE,
686 (PWSTR)SubKey,
687 QueryTable,
688 DeviceNode,
689 NULL);
690
691 /* Clean up */
692 ZwClose(SubKey);
693 ZwClose(EnumRootKey);
694 }
695
696 return STATUS_SUCCESS;
697 }
698
699 NTSTATUS
700 NTAPI
701 MiResolveImageReferences(IN PVOID ImageBase,
702 IN PUNICODE_STRING ImageFileDirectory,
703 IN PUNICODE_STRING NamePrefix OPTIONAL,
704 OUT PCHAR *MissingApi,
705 OUT PWCHAR *MissingDriver,
706 OUT PLOAD_IMPORTS *LoadImports);
707
708 //
709 // Used for images already loaded (boot drivers)
710 //
711 NTSTATUS
712 NTAPI
713 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry,
714 PUNICODE_STRING FileName,
715 PLDR_DATA_TABLE_ENTRY *ModuleObject)
716 {
717 NTSTATUS Status;
718 PLDR_DATA_TABLE_ENTRY NewEntry;
719 UNICODE_STRING BaseName, BaseDirectory;
720 PLOAD_IMPORTS LoadedImports = (PVOID)-2;
721 PCHAR MissingApiName, Buffer;
722 PWCHAR MissingDriverName;
723 PVOID DriverBase = LdrEntry->DllBase;
724
725 /* Allocate a buffer we'll use for names */
726 Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
727 if (!Buffer)
728 {
729 /* Fail */
730 return STATUS_INSUFFICIENT_RESOURCES;
731 }
732
733 /* Check for a separator */
734 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
735 {
736 PWCHAR p;
737 ULONG BaseLength;
738
739 /* Loop the path until we get to the base name */
740 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
741 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
742
743 /* Get the length */
744 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
745 BaseLength *= sizeof(WCHAR);
746
747 /* Setup the string */
748 BaseName.Length = (USHORT)BaseLength;
749 BaseName.Buffer = p;
750 }
751 else
752 {
753 /* Otherwise, we already have a base name */
754 BaseName.Length = FileName->Length;
755 BaseName.Buffer = FileName->Buffer;
756 }
757
758 /* Setup the maximum length */
759 BaseName.MaximumLength = BaseName.Length;
760
761 /* Now compute the base directory */
762 BaseDirectory = *FileName;
763 BaseDirectory.Length -= BaseName.Length;
764 BaseDirectory.MaximumLength = BaseDirectory.Length;
765
766 NewEntry = LdrEntry;
767
768 /* Resolve imports */
769 MissingApiName = Buffer;
770 Status = MiResolveImageReferences(DriverBase,
771 &BaseDirectory,
772 NULL,
773 &MissingApiName,
774 &MissingDriverName,
775 &LoadedImports);
776 if (!NT_SUCCESS(Status)) return Status;
777
778 /* Return */
779 *ModuleObject = LdrEntry;
780 return STATUS_SUCCESS;
781 }
782
783 /*
784 * IopInitializeBuiltinDriver
785 *
786 * Initialize a driver that is already loaded in memory.
787 */
788
789 NTSTATUS
790 NTAPI
791 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
792 {
793 PDEVICE_NODE DeviceNode;
794 PDRIVER_OBJECT DriverObject;
795 NTSTATUS Status;
796 PWCHAR FileNameWithoutPath;
797 LPWSTR FileExtension;
798 PUNICODE_STRING ModuleName = &LdrEntry->BaseDllName;
799 UNICODE_STRING ServiceName;
800
801 /*
802 * Display 'Loading XXX...' message
803 */
804 IopDisplayLoadingMessage(ModuleName);
805 InbvIndicateProgress();
806
807 /*
808 * Generate filename without path (not needed by freeldr)
809 */
810 FileNameWithoutPath = wcsrchr(ModuleName->Buffer, L'\\');
811 if (FileNameWithoutPath == NULL)
812 {
813 FileNameWithoutPath = ModuleName->Buffer;
814 }
815 else
816 {
817 FileNameWithoutPath++;
818 }
819
820 /*
821 * Strip the file extension from ServiceName
822 */
823 RtlCreateUnicodeString(&ServiceName, FileNameWithoutPath);
824 FileExtension = wcsrchr(ServiceName.Buffer, '.');
825 if (FileExtension != NULL)
826 {
827 ServiceName.Length -= wcslen(FileExtension) * sizeof(WCHAR);
828 FileExtension[0] = 0;
829 }
830
831 /*
832 * Determine the right device object
833 */
834 /* Use IopRootDeviceNode for now */
835 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
836 if (!NT_SUCCESS(Status))
837 {
838 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
839 return(Status);
840 }
841 DeviceNode->ServiceName = ServiceName;
842
843 /*
844 * Initialize the driver
845 */
846 Status = IopInitializeDriverModule(DeviceNode, LdrEntry,
847 &DeviceNode->ServiceName, FALSE, &DriverObject);
848
849 if (!NT_SUCCESS(Status))
850 {
851 IopFreeDeviceNode(DeviceNode);
852 return Status;
853 }
854
855 Status = IopInitializeDevice(DeviceNode, DriverObject);
856 if (NT_SUCCESS(Status))
857 {
858 Status = IopStartDevice(DeviceNode);
859 }
860
861 return Status;
862 }
863
864 /*
865 * IopInitializeBootDrivers
866 *
867 * Initialize boot drivers and free memory for boot files.
868 *
869 * Parameters
870 * None
871 *
872 * Return Value
873 * None
874 */
875 VOID
876 FASTCALL
877 IopInitializeBootDrivers(VOID)
878 {
879 PLIST_ENTRY ListHead, NextEntry, NextEntry2;
880 PLDR_DATA_TABLE_ENTRY LdrEntry;
881 PDEVICE_NODE DeviceNode;
882 PDRIVER_OBJECT DriverObject;
883 LDR_DATA_TABLE_ENTRY ModuleObject;
884 NTSTATUS Status;
885 UNICODE_STRING DriverName;
886 ULONG i, Index;
887 PDRIVER_INFORMATION DriverInfo, DriverInfoTag;
888 HANDLE KeyHandle;
889 PBOOT_DRIVER_LIST_ENTRY BootEntry;
890 DPRINT("IopInitializeBootDrivers()\n");
891
892 /* Use IopRootDeviceNode for now */
893 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, NULL, &DeviceNode);
894 if (!NT_SUCCESS(Status)) return;
895
896 /* Setup the module object for the RAW FS Driver */
897 ModuleObject.DllBase = NULL;
898 ModuleObject.SizeOfImage = 0;
899 ModuleObject.EntryPoint = RawFsDriverEntry;
900 RtlInitUnicodeString(&DriverName, L"RAW");
901
902 /* Initialize it */
903 Status = IopInitializeDriverModule(DeviceNode,
904 &ModuleObject,
905 &DriverName,
906 TRUE,
907 &DriverObject);
908 if (!NT_SUCCESS(Status))
909 {
910 /* Fail */
911 IopFreeDeviceNode(DeviceNode);
912 return;
913 }
914
915 /* Now initialize the associated device */
916 Status = IopInitializeDevice(DeviceNode, DriverObject);
917 if (!NT_SUCCESS(Status))
918 {
919 /* Fail */
920 IopFreeDeviceNode(DeviceNode);
921 return;
922 }
923
924 /* Start it up */
925 Status = IopStartDevice(DeviceNode);
926 if (!NT_SUCCESS(Status))
927 {
928 /* Fail */
929 IopFreeDeviceNode(DeviceNode);
930 return;
931 }
932
933 /* Get highest group order index */
934 IopGroupIndex = PpInitGetGroupOrderIndex(NULL);
935 if (IopGroupIndex == 0xFFFF) ASSERT(FALSE);
936
937 /* Allocate the group table */
938 IopGroupTable = ExAllocatePoolWithTag(PagedPool,
939 IopGroupIndex * sizeof(LIST_ENTRY),
940 TAG_IO);
941 if (IopGroupTable == NULL) ASSERT(FALSE);
942
943 /* Initialize the group table lists */
944 for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]);
945
946 /* Loop the boot modules */
947 ListHead = &KeLoaderBlock->LoadOrderListHead;
948 NextEntry = ListHead->Flink;
949 while (ListHead != NextEntry)
950 {
951 /* Get the entry */
952 LdrEntry = CONTAINING_RECORD(NextEntry,
953 LDR_DATA_TABLE_ENTRY,
954 InLoadOrderLinks);
955
956 /* Check if the DLL needs to be initialized */
957 if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
958 {
959 /* Call its entrypoint */
960 MmCallDllInitialize(LdrEntry, NULL);
961 }
962
963 /* Go to the next driver */
964 NextEntry = NextEntry->Flink;
965 }
966
967 /* Loop the boot drivers */
968 ListHead = &KeLoaderBlock->BootDriverListHead;
969 NextEntry = ListHead->Flink;
970 while (ListHead != NextEntry)
971 {
972 /* Get the entry */
973 BootEntry = CONTAINING_RECORD(NextEntry,
974 BOOT_DRIVER_LIST_ENTRY,
975 Link);
976
977 /* Get the driver loader entry */
978 LdrEntry = BootEntry->LdrEntry;
979
980 /* Allocate our internal accounting structure */
981 DriverInfo = ExAllocatePoolWithTag(PagedPool,
982 sizeof(DRIVER_INFORMATION),
983 TAG_IO);
984 if (DriverInfo)
985 {
986 /* Zero it and initialize it */
987 RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION));
988 InitializeListHead(&DriverInfo->Link);
989 DriverInfo->DataTableEntry = BootEntry;
990
991 /* Open the registry key */
992 Status = IopOpenRegistryKeyEx(&KeyHandle,
993 NULL,
994 &BootEntry->RegistryPath,
995 KEY_READ);
996 if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */
997 ((KeLoaderBlock->SetupLdrBlock) && (KeyHandle = (PVOID)1)))
998 {
999 /* Save the handle */
1000 DriverInfo->ServiceHandle = KeyHandle;
1001
1002 /* Get the group oder index */
1003 Index = PpInitGetGroupOrderIndex(KeyHandle);
1004
1005 /* Get the tag position */
1006 DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle);
1007
1008 /* Insert it into the list, at the right place */
1009 ASSERT(Index < IopGroupIndex);
1010 NextEntry2 = IopGroupTable[Index].Flink;
1011 while (NextEntry2 != &IopGroupTable[Index])
1012 {
1013 /* Get the driver info */
1014 DriverInfoTag = CONTAINING_RECORD(NextEntry2,
1015 DRIVER_INFORMATION,
1016 Link);
1017
1018 /* Check if we found the right tag position */
1019 if (DriverInfoTag->TagPosition > DriverInfo->TagPosition)
1020 {
1021 /* We're done */
1022 break;
1023 }
1024
1025 /* Next entry */
1026 NextEntry2 = NextEntry2->Flink;
1027 }
1028
1029 /* Insert us right before the next entry */
1030 NextEntry2 = NextEntry2->Blink;
1031 InsertHeadList(NextEntry2, &DriverInfo->Link);
1032 }
1033 }
1034
1035 /* Go to the next driver */
1036 NextEntry = NextEntry->Flink;
1037 }
1038
1039 /* Loop each group index */
1040 for (i = 0; i < IopGroupIndex; i++)
1041 {
1042 /* Loop each group table */
1043 NextEntry = IopGroupTable[i].Flink;
1044 while (NextEntry != &IopGroupTable[i])
1045 {
1046 /* Get the entry */
1047 DriverInfo = CONTAINING_RECORD(NextEntry,
1048 DRIVER_INFORMATION,
1049 Link);
1050
1051 /* Get the driver loader entry */
1052 LdrEntry = DriverInfo->DataTableEntry->LdrEntry;
1053
1054 /* Initialize it */
1055 IopInitializeBuiltinDriver(LdrEntry);
1056
1057 /* Next entry */
1058 NextEntry = NextEntry->Flink;
1059 }
1060 }
1061
1062 /* In old ROS, the loader list became empty after this point. Simulate. */
1063 InitializeListHead(&KeLoaderBlock->LoadOrderListHead);
1064 }
1065
1066 VOID
1067 FASTCALL
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 IN PVOID DllBase,
1395 IN ULONG SizeOfImage,
1396 OUT PDRIVER_OBJECT *pDriverObject)
1397 {
1398 WCHAR NameBuffer[100];
1399 USHORT NameLength;
1400 UNICODE_STRING LocalDriverName;
1401 NTSTATUS Status;
1402 OBJECT_ATTRIBUTES ObjectAttributes;
1403 ULONG ObjectSize;
1404 PDRIVER_OBJECT DriverObject;
1405 UNICODE_STRING ServiceKeyName;
1406 HANDLE hDriver;
1407 ULONG i, RetryCount = 0;
1408
1409 try_again:
1410 /* First, create a unique name for the driver if we don't have one */
1411 if (!DriverName)
1412 {
1413 /* Create a random name and set up the string*/
1414 NameLength = (USHORT)swprintf(NameBuffer,
1415 L"\\Driver\\%08u",
1416 KeTickCount);
1417 LocalDriverName.Length = NameLength * sizeof(WCHAR);
1418 LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1419 LocalDriverName.Buffer = NameBuffer;
1420 }
1421 else
1422 {
1423 /* So we can avoid another code path, use a local var */
1424 LocalDriverName = *DriverName;
1425 }
1426
1427 /* Initialize the Attributes */
1428 ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION);
1429 InitializeObjectAttributes(&ObjectAttributes,
1430 &LocalDriverName,
1431 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
1432 NULL,
1433 NULL);
1434
1435 /* Create the Object */
1436 Status = ObCreateObject(KernelMode,
1437 IoDriverObjectType,
1438 &ObjectAttributes,
1439 KernelMode,
1440 NULL,
1441 ObjectSize,
1442 0,
1443 0,
1444 (PVOID*)&DriverObject);
1445 if (!NT_SUCCESS(Status)) return Status;
1446
1447 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject);
1448
1449 /* Set up the Object */
1450 RtlZeroMemory(DriverObject, ObjectSize);
1451 DriverObject->Type = IO_TYPE_DRIVER;
1452 DriverObject->Size = sizeof(DRIVER_OBJECT);
1453 DriverObject->Flags = DRVO_LEGACY_DRIVER;//DRVO_BUILTIN_DRIVER;
1454 DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1455 DriverObject->DriverExtension->DriverObject = DriverObject;
1456 DriverObject->DriverInit = InitializationFunction;
1457
1458 /* Loop all Major Functions */
1459 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1460 {
1461 /* Invalidate each function */
1462 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1463 }
1464
1465 /* Set up the service key name buffer */
1466 ServiceKeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
1467 LocalDriverName.Length +
1468 sizeof(WCHAR),
1469 TAG_IO);
1470 if (!ServiceKeyName.Buffer)
1471 {
1472 /* Fail */
1473 ObMakeTemporaryObject(DriverObject);
1474 ObDereferenceObject(DriverObject);
1475 return STATUS_INSUFFICIENT_RESOURCES;
1476 }
1477
1478 /* Fill out the key data and copy the buffer */
1479 ServiceKeyName.Length = LocalDriverName.Length;
1480 ServiceKeyName.MaximumLength = LocalDriverName.MaximumLength;
1481 RtlCopyMemory(ServiceKeyName.Buffer,
1482 LocalDriverName.Buffer,
1483 LocalDriverName.Length);
1484
1485 /* Null-terminate it and set it */
1486 ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1487 DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1488
1489 /* Also store it in the Driver Object. This is a bit of a hack. */
1490 RtlCopyMemory(&DriverObject->DriverName,
1491 &ServiceKeyName,
1492 sizeof(UNICODE_STRING));
1493
1494 /* Add the Object and get its handle */
1495 Status = ObInsertObject(DriverObject,
1496 NULL,
1497 FILE_READ_DATA,
1498 0,
1499 NULL,
1500 &hDriver);
1501
1502 /* Eliminate small possibility when this function is called more than
1503 once in a row, and KeTickCount doesn't get enough time to change */
1504 if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100))
1505 {
1506 RetryCount++;
1507 goto try_again;
1508 }
1509
1510 if (!NT_SUCCESS(Status)) return Status;
1511
1512 /* Now reference it */
1513 Status = ObReferenceObjectByHandle(hDriver,
1514 0,
1515 IoDriverObjectType,
1516 KernelMode,
1517 (PVOID*)&DriverObject,
1518 NULL);
1519 if (!NT_SUCCESS(Status))
1520 {
1521 /* Fail */
1522 ObMakeTemporaryObject(DriverObject);
1523 ObDereferenceObject(DriverObject);
1524 return Status;
1525 }
1526
1527 /* Close the extra handle */
1528 ZwClose(hDriver);
1529
1530 DriverObject->HardwareDatabase = &IopHardwareDatabaseKey;
1531 DriverObject->DriverStart = DllBase;
1532 DriverObject->DriverSize = SizeOfImage;
1533
1534 /* Finally, call its init function */
1535 DPRINT("RegistryKey: %wZ\n", RegistryPath);
1536 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction);
1537 Status = (*InitializationFunction)(DriverObject, RegistryPath);
1538 if (!NT_SUCCESS(Status))
1539 {
1540 /* If it didn't work, then kill the object */
1541 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status);
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, 0, 0, &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 if (!NT_SUCCESS(Status) && Status != STATUS_IMAGE_ALREADY_LOADED)
1902 {
1903 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
1904 IopFreeDeviceNode(DeviceNode);
1905 LoadParams->Status = Status;
1906 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1907 return;
1908 }
1909
1910 /*
1911 * Set a service name for the device node
1912 */
1913
1914 RtlCreateUnicodeString(&DeviceNode->ServiceName, ServiceName.Buffer);
1915
1916 /*
1917 * Initialize the driver module if it's loaded for the first time
1918 */
1919 if (Status != STATUS_IMAGE_ALREADY_LOADED)
1920 {
1921 Status = IopInitializeDriverModule(
1922 DeviceNode,
1923 ModuleObject,
1924 &DeviceNode->ServiceName,
1925 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1926 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
1927 &DriverObject);
1928
1929 if (!NT_SUCCESS(Status))
1930 {
1931 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
1932 MmUnloadSystemImage(ModuleObject);
1933 IopFreeDeviceNode(DeviceNode);
1934 LoadParams->Status = Status;
1935 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1936 return;
1937 }
1938 }
1939
1940 /* Store its DriverSection, so that it could be unloaded */
1941 DriverObject->DriverSection = ModuleObject;
1942
1943 /* Initialize and start device */
1944 IopInitializeDevice(DeviceNode, DriverObject);
1945 Status = IopStartDevice(DeviceNode);
1946 }
1947 else
1948 {
1949 DPRINT("DriverObject already exist in ObjectManager\n");
1950
1951 /* IopGetDriverObject references the DriverObject, so dereference it */
1952 ObDereferenceObject(DriverObject);
1953
1954 /* Free device node since driver loading failed */
1955 IopFreeDeviceNode(DeviceNode);
1956 }
1957
1958 /* Pass status to the caller and signal the event */
1959 LoadParams->Status = Status;
1960 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1961 }
1962
1963 /*
1964 * NtLoadDriver
1965 *
1966 * Loads a device driver.
1967 *
1968 * Parameters
1969 * DriverServiceName
1970 * Name of the service to load (registry key).
1971 *
1972 * Return Value
1973 * Status
1974 *
1975 * Status
1976 * implemented
1977 */
1978 NTSTATUS NTAPI
1979 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
1980 {
1981 UNICODE_STRING CapturedDriverServiceName = { 0, 0, NULL };
1982 KPROCESSOR_MODE PreviousMode;
1983 LOAD_UNLOAD_PARAMS LoadParams;
1984 NTSTATUS Status;
1985
1986 PAGED_CODE();
1987
1988 PreviousMode = KeGetPreviousMode();
1989
1990 /*
1991 * Check security privileges
1992 */
1993
1994 /* FIXME: Uncomment when privileges will be correctly implemented. */
1995 #if 0
1996 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
1997 {
1998 DPRINT("Privilege not held\n");
1999 return STATUS_PRIVILEGE_NOT_HELD;
2000 }
2001 #endif
2002
2003 Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
2004 PreviousMode,
2005 DriverServiceName);
2006 if (!NT_SUCCESS(Status))
2007 {
2008 return Status;
2009 }
2010
2011 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
2012
2013 LoadParams.ServiceName = &CapturedDriverServiceName;
2014 LoadParams.DriverObject = NULL;
2015 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
2016
2017 /* Call the load/unload routine, depending on current process */
2018 if (PsGetCurrentProcess() == PsInitialSystemProcess)
2019 {
2020 /* Just call right away */
2021 IopLoadUnloadDriver(&LoadParams);
2022 }
2023 else
2024 {
2025 /* Load/Unload must be called from system process */
2026 ExInitializeWorkItem(&LoadParams.WorkItem,
2027 (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
2028 (PVOID)&LoadParams);
2029
2030 /* Queue it */
2031 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
2032
2033 /* And wait when it completes */
2034 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
2035 FALSE, NULL);
2036 }
2037
2038 ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
2039 PreviousMode);
2040
2041 return LoadParams.Status;
2042 }
2043
2044 /*
2045 * NtUnloadDriver
2046 *
2047 * Unloads a legacy device driver.
2048 *
2049 * Parameters
2050 * DriverServiceName
2051 * Name of the service to unload (registry key).
2052 *
2053 * Return Value
2054 * Status
2055 *
2056 * Status
2057 * implemented
2058 */
2059
2060 NTSTATUS NTAPI
2061 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
2062 {
2063 return IopUnloadDriver(DriverServiceName, FALSE);
2064 }
2065
2066 /* EOF */