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