[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 /*
1175 * Free the buffer for driver object name
1176 */
1177 ExFreePool(ObjectName.Buffer);
1178
1179 if (!NT_SUCCESS(Status))
1180 {
1181 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
1182 return Status;
1183 }
1184
1185 /* Check that driver is not already unloading */
1186 if (DriverObject->Flags & DRVO_UNLOAD_INVOKED)
1187 {
1188 DPRINT1("Driver deletion pending\n");
1189 ObDereferenceObject(DriverObject);
1190 return STATUS_DELETE_PENDING;
1191 }
1192
1193 /*
1194 * Get path of service...
1195 */
1196
1197 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1198
1199 RtlInitUnicodeString(&ImagePath, NULL);
1200
1201 QueryTable[0].Name = L"ImagePath";
1202 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1203 QueryTable[0].EntryContext = &ImagePath;
1204
1205 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1206 DriverServiceName->Buffer, QueryTable, NULL, NULL);
1207
1208 if (!NT_SUCCESS(Status))
1209 {
1210 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1211 ObDereferenceObject(DriverObject);
1212 return Status;
1213 }
1214
1215 /*
1216 * Normalize the image path for all later processing.
1217 */
1218
1219 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1220
1221 if (!NT_SUCCESS(Status))
1222 {
1223 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status);
1224 ObDereferenceObject(DriverObject);
1225 return Status;
1226 }
1227
1228 /*
1229 * Free the service path
1230 */
1231
1232 ExFreePool(ImagePath.Buffer);
1233
1234 /*
1235 * Unload the module and release the references to the device object
1236 */
1237
1238 /* Call the load/unload routine, depending on current process */
1239 if (DriverObject->DriverUnload && DriverObject->DriverSection)
1240 {
1241 /* Loop through each device object of the driver
1242 and set DOE_UNLOAD_PENDING flag */
1243 DeviceObject = DriverObject->DeviceObject;
1244 while (DeviceObject)
1245 {
1246 /* Set the unload pending flag for the device */
1247 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1248 DeviceExtension->ExtensionFlags |= DOE_UNLOAD_PENDING;
1249
1250 /* Make sure there are no attached devices or no reference counts */
1251 if ((DeviceObject->ReferenceCount) || (DeviceObject->AttachedDevice))
1252 {
1253 /* Not safe to unload */
1254 DPRINT1("Drivers device object is referenced or has attached devices\n");
1255
1256 SafeToUnload = FALSE;
1257 }
1258
1259 DeviceObject = DeviceObject->NextDevice;
1260 }
1261
1262 /* If not safe to unload, then return success */
1263 if (!SafeToUnload)
1264 {
1265 ObDereferenceObject(DriverObject);
1266 return STATUS_SUCCESS;
1267 }
1268
1269 /* Set the unload invoked flag */
1270 DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
1271
1272 if (PsGetCurrentProcess() == PsInitialSystemProcess)
1273 {
1274 /* Just call right away */
1275 (*DriverObject->DriverUnload)(DriverObject);
1276 }
1277 else
1278 {
1279 /* Load/Unload must be called from system process */
1280
1281 /* Prepare parameters block */
1282 LoadParams.DriverObject = DriverObject;
1283 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
1284
1285 ExInitializeWorkItem(&LoadParams.WorkItem,
1286 (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
1287 (PVOID)&LoadParams);
1288
1289 /* Queue it */
1290 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
1291
1292 /* And wait when it completes */
1293 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
1294 FALSE, NULL);
1295 }
1296
1297 /* Mark the driver object temporary, so it could be deleted later */
1298 ObMakeTemporaryObject(DriverObject);
1299
1300 /* Dereference it 2 times */
1301 ObDereferenceObject(DriverObject);
1302 ObDereferenceObject(DriverObject);
1303
1304 return STATUS_SUCCESS;
1305 }
1306 else
1307 {
1308 /* Dereference one time (refd inside this function) */
1309 ObDereferenceObject(DriverObject);
1310
1311 /* Return unloading failure */
1312 return STATUS_INVALID_DEVICE_REQUEST;
1313 }
1314 }
1315
1316 VOID
1317 NTAPI
1318 IopReinitializeDrivers(VOID)
1319 {
1320 PDRIVER_REINIT_ITEM ReinitItem;
1321 PLIST_ENTRY Entry;
1322
1323 /* Get the first entry and start looping */
1324 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1325 &DriverReinitListLock);
1326 while (Entry)
1327 {
1328 /* Get the item*/
1329 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1330
1331 /* Increment reinitialization counter */
1332 ReinitItem->DriverObject->DriverExtension->Count++;
1333
1334 /* Remove the device object flag */
1335 ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED;
1336
1337 /* Call the routine */
1338 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1339 ReinitItem->Context,
1340 ReinitItem->DriverObject->
1341 DriverExtension->Count);
1342
1343 /* Free the entry */
1344 ExFreePool(Entry);
1345
1346 /* Move to the next one */
1347 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1348 &DriverReinitListLock);
1349 }
1350 }
1351
1352 VOID
1353 NTAPI
1354 IopReinitializeBootDrivers(VOID)
1355 {
1356 PDRIVER_REINIT_ITEM ReinitItem;
1357 PLIST_ENTRY Entry;
1358
1359 /* Get the first entry and start looping */
1360 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1361 &DriverBootReinitListLock);
1362 while (Entry)
1363 {
1364 /* Get the item*/
1365 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1366
1367 /* Increment reinitialization counter */
1368 ReinitItem->DriverObject->DriverExtension->Count++;
1369
1370 /* Remove the device object flag */
1371 ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED;
1372
1373 /* Call the routine */
1374 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1375 ReinitItem->Context,
1376 ReinitItem->DriverObject->
1377 DriverExtension->Count);
1378
1379 /* Free the entry */
1380 ExFreePool(Entry);
1381
1382 /* Move to the next one */
1383 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1384 &DriverBootReinitListLock);
1385 }
1386 }
1387
1388 NTSTATUS
1389 NTAPI
1390 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1391 IN PDRIVER_INITIALIZE InitializationFunction,
1392 IN PUNICODE_STRING RegistryPath,
1393 IN PVOID DllBase,
1394 IN ULONG SizeOfImage,
1395 OUT PDRIVER_OBJECT *pDriverObject)
1396 {
1397 WCHAR NameBuffer[100];
1398 USHORT NameLength;
1399 UNICODE_STRING LocalDriverName;
1400 NTSTATUS Status;
1401 OBJECT_ATTRIBUTES ObjectAttributes;
1402 ULONG ObjectSize;
1403 PDRIVER_OBJECT DriverObject;
1404 UNICODE_STRING ServiceKeyName;
1405 HANDLE hDriver;
1406 ULONG i, RetryCount = 0;
1407
1408 try_again:
1409 /* First, create a unique name for the driver if we don't have one */
1410 if (!DriverName)
1411 {
1412 /* Create a random name and set up the string*/
1413 NameLength = (USHORT)swprintf(NameBuffer,
1414 L"\\Driver\\%08u",
1415 KeTickCount);
1416 LocalDriverName.Length = NameLength * sizeof(WCHAR);
1417 LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1418 LocalDriverName.Buffer = NameBuffer;
1419 }
1420 else
1421 {
1422 /* So we can avoid another code path, use a local var */
1423 LocalDriverName = *DriverName;
1424 }
1425
1426 /* Initialize the Attributes */
1427 ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION);
1428 InitializeObjectAttributes(&ObjectAttributes,
1429 &LocalDriverName,
1430 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
1431 NULL,
1432 NULL);
1433
1434 /* Create the Object */
1435 Status = ObCreateObject(KernelMode,
1436 IoDriverObjectType,
1437 &ObjectAttributes,
1438 KernelMode,
1439 NULL,
1440 ObjectSize,
1441 0,
1442 0,
1443 (PVOID*)&DriverObject);
1444 if (!NT_SUCCESS(Status)) return Status;
1445
1446 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject);
1447
1448 /* Set up the Object */
1449 RtlZeroMemory(DriverObject, ObjectSize);
1450 DriverObject->Type = IO_TYPE_DRIVER;
1451 DriverObject->Size = sizeof(DRIVER_OBJECT);
1452 DriverObject->Flags = DRVO_LEGACY_DRIVER;//DRVO_BUILTIN_DRIVER;
1453 DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1454 DriverObject->DriverExtension->DriverObject = DriverObject;
1455 DriverObject->DriverInit = InitializationFunction;
1456
1457 /* Loop all Major Functions */
1458 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1459 {
1460 /* Invalidate each function */
1461 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1462 }
1463
1464 /* Set up the service key name buffer */
1465 ServiceKeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
1466 LocalDriverName.Length +
1467 sizeof(WCHAR),
1468 TAG_IO);
1469 if (!ServiceKeyName.Buffer)
1470 {
1471 /* Fail */
1472 ObMakeTemporaryObject(DriverObject);
1473 ObDereferenceObject(DriverObject);
1474 return STATUS_INSUFFICIENT_RESOURCES;
1475 }
1476
1477 /* Fill out the key data and copy the buffer */
1478 ServiceKeyName.Length = LocalDriverName.Length;
1479 ServiceKeyName.MaximumLength = LocalDriverName.MaximumLength;
1480 RtlCopyMemory(ServiceKeyName.Buffer,
1481 LocalDriverName.Buffer,
1482 LocalDriverName.Length);
1483
1484 /* Null-terminate it and set it */
1485 ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1486 DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1487
1488 /* Also store it in the Driver Object. This is a bit of a hack. */
1489 RtlCopyMemory(&DriverObject->DriverName,
1490 &ServiceKeyName,
1491 sizeof(UNICODE_STRING));
1492
1493 /* Add the Object and get its handle */
1494 Status = ObInsertObject(DriverObject,
1495 NULL,
1496 FILE_READ_DATA,
1497 0,
1498 NULL,
1499 &hDriver);
1500
1501 /* Eliminate small possibility when this function is called more than
1502 once in a row, and KeTickCount doesn't get enough time to change */
1503 if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100))
1504 {
1505 RetryCount++;
1506 goto try_again;
1507 }
1508
1509 if (!NT_SUCCESS(Status)) return Status;
1510
1511 /* Now reference it */
1512 Status = ObReferenceObjectByHandle(hDriver,
1513 0,
1514 IoDriverObjectType,
1515 KernelMode,
1516 (PVOID*)&DriverObject,
1517 NULL);
1518 if (!NT_SUCCESS(Status))
1519 {
1520 /* Fail */
1521 ObMakeTemporaryObject(DriverObject);
1522 ObDereferenceObject(DriverObject);
1523 return Status;
1524 }
1525
1526 /* Close the extra handle */
1527 ZwClose(hDriver);
1528
1529 DriverObject->HardwareDatabase = &IopHardwareDatabaseKey;
1530 DriverObject->DriverStart = DllBase;
1531 DriverObject->DriverSize = SizeOfImage;
1532
1533 /* Finally, call its init function */
1534 DPRINT("RegistryKey: %wZ\n", RegistryPath);
1535 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction);
1536 Status = (*InitializationFunction)(DriverObject, RegistryPath);
1537 if (!NT_SUCCESS(Status))
1538 {
1539 /* If it didn't work, then kill the object */
1540 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status);
1541 ObMakeTemporaryObject(DriverObject);
1542 ObDereferenceObject(DriverObject);
1543 }
1544 else
1545 {
1546 /* Returns to caller the object */
1547 *pDriverObject = DriverObject;
1548 }
1549
1550 /* Loop all Major Functions */
1551 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1552 {
1553 /*
1554 * Make sure the driver didn't set any dispatch entry point to NULL!
1555 * Doing so is illegal; drivers shouldn't touch entry points they
1556 * do not implement.
1557 */
1558 ASSERT(DriverObject->MajorFunction[i] != NULL);
1559
1560 /* Check if it did so anyway */
1561 if (!DriverObject->MajorFunction[i])
1562 {
1563 /* Fix it up */
1564 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1565 }
1566 }
1567
1568 /* Return the Status */
1569 return Status;
1570 }
1571
1572 /* PUBLIC FUNCTIONS ***********************************************************/
1573
1574 /*
1575 * @implemented
1576 */
1577 NTSTATUS
1578 NTAPI
1579 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1580 IN PDRIVER_INITIALIZE InitializationFunction)
1581 {
1582 PDRIVER_OBJECT DriverObject;
1583 return IopCreateDriver(DriverName, InitializationFunction, NULL, 0, 0, &DriverObject);
1584 }
1585
1586 /*
1587 * @implemented
1588 */
1589 VOID
1590 NTAPI
1591 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject)
1592 {
1593 /* Simply dereference the Object */
1594 ObDereferenceObject(DriverObject);
1595 }
1596
1597 /*
1598 * @implemented
1599 */
1600 VOID
1601 NTAPI
1602 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1603 IN PDRIVER_REINITIALIZE ReinitRoutine,
1604 IN PVOID Context)
1605 {
1606 PDRIVER_REINIT_ITEM ReinitItem;
1607
1608 /* Allocate the entry */
1609 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1610 sizeof(DRIVER_REINIT_ITEM),
1611 TAG_REINIT);
1612 if (!ReinitItem) return;
1613
1614 /* Fill it out */
1615 ReinitItem->DriverObject = DriverObject;
1616 ReinitItem->ReinitRoutine = ReinitRoutine;
1617 ReinitItem->Context = Context;
1618
1619 /* Set the Driver Object flag and insert the entry into the list */
1620 DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
1621 ExInterlockedInsertTailList(&DriverBootReinitListHead,
1622 &ReinitItem->ItemEntry,
1623 &DriverBootReinitListLock);
1624 }
1625
1626 /*
1627 * @implemented
1628 */
1629 VOID
1630 NTAPI
1631 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1632 IN PDRIVER_REINITIALIZE ReinitRoutine,
1633 IN PVOID Context)
1634 {
1635 PDRIVER_REINIT_ITEM ReinitItem;
1636
1637 /* Allocate the entry */
1638 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1639 sizeof(DRIVER_REINIT_ITEM),
1640 TAG_REINIT);
1641 if (!ReinitItem) return;
1642
1643 /* Fill it out */
1644 ReinitItem->DriverObject = DriverObject;
1645 ReinitItem->ReinitRoutine = ReinitRoutine;
1646 ReinitItem->Context = Context;
1647
1648 /* Set the Driver Object flag and insert the entry into the list */
1649 DriverObject->Flags |= DRVO_REINIT_REGISTERED;
1650 ExInterlockedInsertTailList(&DriverReinitListHead,
1651 &ReinitItem->ItemEntry,
1652 &DriverReinitListLock);
1653 }
1654
1655 /*
1656 * @implemented
1657 */
1658 NTSTATUS
1659 NTAPI
1660 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1661 IN PVOID ClientIdentificationAddress,
1662 IN ULONG DriverObjectExtensionSize,
1663 OUT PVOID *DriverObjectExtension)
1664 {
1665 KIRQL OldIrql;
1666 PIO_CLIENT_EXTENSION DriverExtensions, NewDriverExtension;
1667 BOOLEAN Inserted = FALSE;
1668
1669 /* Assume failure */
1670 *DriverObjectExtension = NULL;
1671
1672 /* Allocate the extension */
1673 NewDriverExtension = ExAllocatePoolWithTag(NonPagedPool,
1674 sizeof(IO_CLIENT_EXTENSION) +
1675 DriverObjectExtensionSize,
1676 TAG_DRIVER_EXTENSION);
1677 if (!NewDriverExtension) return STATUS_INSUFFICIENT_RESOURCES;
1678
1679 /* Clear the extension for teh caller */
1680 RtlZeroMemory(NewDriverExtension,
1681 sizeof(IO_CLIENT_EXTENSION) + DriverObjectExtensionSize);
1682
1683 /* Acqure lock */
1684 OldIrql = KeRaiseIrqlToDpcLevel();
1685
1686 /* Fill out the extension */
1687 NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
1688
1689 /* Loop the current extensions */
1690 DriverExtensions = IoGetDrvObjExtension(DriverObject)->
1691 ClientDriverExtension;
1692 while (DriverExtensions)
1693 {
1694 /* Check if the identifier matches */
1695 if (DriverExtensions->ClientIdentificationAddress ==
1696 ClientIdentificationAddress)
1697 {
1698 /* We have a collision, break out */
1699 break;
1700 }
1701
1702 /* Go to the next one */
1703 DriverExtensions = DriverExtensions->NextExtension;
1704 }
1705
1706 /* Check if we didn't collide */
1707 if (!DriverExtensions)
1708 {
1709 /* Link this one in */
1710 NewDriverExtension->NextExtension =
1711 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1712 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension =
1713 NewDriverExtension;
1714 Inserted = TRUE;
1715 }
1716
1717 /* Release the lock */
1718 KeLowerIrql(OldIrql);
1719
1720 /* Check if insertion failed */
1721 if (!Inserted)
1722 {
1723 /* Free the entry and fail */
1724 ExFreePool(NewDriverExtension);
1725 return STATUS_OBJECT_NAME_COLLISION;
1726 }
1727
1728 /* Otherwise, return the pointer */
1729 *DriverObjectExtension = NewDriverExtension + 1;
1730 return STATUS_SUCCESS;
1731 }
1732
1733 /*
1734 * @implemented
1735 */
1736 PVOID
1737 NTAPI
1738 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1739 IN PVOID ClientIdentificationAddress)
1740 {
1741 KIRQL OldIrql;
1742 PIO_CLIENT_EXTENSION DriverExtensions;
1743
1744 /* Acquire lock */
1745 OldIrql = KeRaiseIrqlToDpcLevel();
1746
1747 /* Loop the list until we find the right one */
1748 DriverExtensions = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1749 while (DriverExtensions)
1750 {
1751 /* Check for a match */
1752 if (DriverExtensions->ClientIdentificationAddress ==
1753 ClientIdentificationAddress)
1754 {
1755 /* Break out */
1756 break;
1757 }
1758
1759 /* Keep looping */
1760 DriverExtensions = DriverExtensions->NextExtension;
1761 }
1762
1763 /* Release lock */
1764 KeLowerIrql(OldIrql);
1765
1766 /* Return nothing or the extension */
1767 if (!DriverExtensions) return NULL;
1768 return DriverExtensions + 1;
1769 }
1770
1771 VOID NTAPI
1772 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams)
1773 {
1774 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
1775 UNICODE_STRING ImagePath;
1776 UNICODE_STRING ServiceName;
1777 NTSTATUS Status;
1778 ULONG Type;
1779 PDEVICE_NODE DeviceNode;
1780 PDRIVER_OBJECT DriverObject;
1781 PLDR_DATA_TABLE_ENTRY ModuleObject;
1782 PVOID BaseAddress;
1783 WCHAR *cur;
1784
1785 /* Check if it's an unload request */
1786 if (LoadParams->DriverObject)
1787 {
1788 (*LoadParams->DriverObject->DriverUnload)(LoadParams->DriverObject);
1789
1790 /* Return success and signal the event */
1791 LoadParams->Status = STATUS_SUCCESS;
1792 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1793 return;
1794 }
1795
1796 RtlInitUnicodeString(&ImagePath, NULL);
1797
1798 /*
1799 * Get the service name from the registry key name.
1800 */
1801 ASSERT(LoadParams->ServiceName->Length >= sizeof(WCHAR));
1802
1803 ServiceName = *LoadParams->ServiceName;
1804 cur = LoadParams->ServiceName->Buffer +
1805 (LoadParams->ServiceName->Length / sizeof(WCHAR)) - 1;
1806 while (LoadParams->ServiceName->Buffer != cur)
1807 {
1808 if(*cur == L'\\')
1809 {
1810 ServiceName.Buffer = cur + 1;
1811 ServiceName.Length = LoadParams->ServiceName->Length -
1812 (USHORT)((ULONG_PTR)ServiceName.Buffer -
1813 (ULONG_PTR)LoadParams->ServiceName->Buffer);
1814 break;
1815 }
1816 cur--;
1817 }
1818
1819 IopDisplayLoadingMessage(&ServiceName);
1820
1821 /*
1822 * Get service type.
1823 */
1824
1825 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
1826
1827 RtlInitUnicodeString(&ImagePath, NULL);
1828
1829 QueryTable[0].Name = L"Type";
1830 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1831 QueryTable[0].EntryContext = &Type;
1832
1833 QueryTable[1].Name = L"ImagePath";
1834 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1835 QueryTable[1].EntryContext = &ImagePath;
1836
1837 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1838 LoadParams->ServiceName->Buffer, QueryTable, NULL, NULL);
1839
1840 if (!NT_SUCCESS(Status))
1841 {
1842 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
1843 if (ImagePath.Buffer)
1844 ExFreePool(ImagePath.Buffer);
1845 LoadParams->Status = Status;
1846 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1847 return;
1848 }
1849
1850 /*
1851 * Normalize the image path for all later processing.
1852 */
1853
1854 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1855
1856 if (!NT_SUCCESS(Status))
1857 {
1858 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1859 LoadParams->Status = Status;
1860 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1861 return;
1862 }
1863
1864 DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
1865 DPRINT("Type: %lx\n", Type);
1866
1867 /*
1868 * Create device node
1869 */
1870
1871 /* Use IopRootDeviceNode for now */
1872 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
1873
1874 if (!NT_SUCCESS(Status))
1875 {
1876 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
1877 LoadParams->Status = Status;
1878 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1879 return;
1880 }
1881
1882 /* Get existing DriverObject pointer (in case the driver has
1883 already been loaded and initialized) */
1884 Status = IopGetDriverObject(
1885 &DriverObject,
1886 &ServiceName,
1887 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1888 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */));
1889
1890 if (!NT_SUCCESS(Status))
1891 {
1892 /*
1893 * Load the driver module
1894 */
1895
1896 Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress);
1897 if (!NT_SUCCESS(Status) && Status != STATUS_IMAGE_ALREADY_LOADED)
1898 {
1899 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
1900 IopFreeDeviceNode(DeviceNode);
1901 LoadParams->Status = Status;
1902 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1903 return;
1904 }
1905
1906 /*
1907 * Set a service name for the device node
1908 */
1909
1910 RtlCreateUnicodeString(&DeviceNode->ServiceName, ServiceName.Buffer);
1911
1912 /*
1913 * Initialize the driver module if it's loaded for the first time
1914 */
1915 if (Status != STATUS_IMAGE_ALREADY_LOADED)
1916 {
1917 Status = IopInitializeDriverModule(
1918 DeviceNode,
1919 ModuleObject,
1920 &DeviceNode->ServiceName,
1921 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1922 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
1923 &DriverObject);
1924
1925 if (!NT_SUCCESS(Status))
1926 {
1927 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
1928 MmUnloadSystemImage(ModuleObject);
1929 IopFreeDeviceNode(DeviceNode);
1930 LoadParams->Status = Status;
1931 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1932 return;
1933 }
1934 }
1935
1936 /* Store its DriverSection, so that it could be unloaded */
1937 DriverObject->DriverSection = ModuleObject;
1938
1939 /* Initialize and start device */
1940 IopInitializeDevice(DeviceNode, DriverObject);
1941 Status = IopStartDevice(DeviceNode);
1942 }
1943 else
1944 {
1945 DPRINT("DriverObject already exist in ObjectManager\n");
1946
1947 /* IopGetDriverObject references the DriverObject, so dereference it */
1948 ObDereferenceObject(DriverObject);
1949
1950 /* Free device node since driver loading failed */
1951 IopFreeDeviceNode(DeviceNode);
1952 }
1953
1954 /* Pass status to the caller and signal the event */
1955 LoadParams->Status = Status;
1956 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1957 }
1958
1959 /*
1960 * NtLoadDriver
1961 *
1962 * Loads a device driver.
1963 *
1964 * Parameters
1965 * DriverServiceName
1966 * Name of the service to load (registry key).
1967 *
1968 * Return Value
1969 * Status
1970 *
1971 * Status
1972 * implemented
1973 */
1974 NTSTATUS NTAPI
1975 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
1976 {
1977 UNICODE_STRING CapturedDriverServiceName = { 0, 0, NULL };
1978 KPROCESSOR_MODE PreviousMode;
1979 LOAD_UNLOAD_PARAMS LoadParams;
1980 NTSTATUS Status;
1981
1982 PAGED_CODE();
1983
1984 PreviousMode = KeGetPreviousMode();
1985
1986 /*
1987 * Check security privileges
1988 */
1989
1990 /* FIXME: Uncomment when privileges will be correctly implemented. */
1991 #if 0
1992 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
1993 {
1994 DPRINT("Privilege not held\n");
1995 return STATUS_PRIVILEGE_NOT_HELD;
1996 }
1997 #endif
1998
1999 Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
2000 PreviousMode,
2001 DriverServiceName);
2002 if (!NT_SUCCESS(Status))
2003 {
2004 return Status;
2005 }
2006
2007 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
2008
2009 LoadParams.ServiceName = &CapturedDriverServiceName;
2010 LoadParams.DriverObject = NULL;
2011 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
2012
2013 /* Call the load/unload routine, depending on current process */
2014 if (PsGetCurrentProcess() == PsInitialSystemProcess)
2015 {
2016 /* Just call right away */
2017 IopLoadUnloadDriver(&LoadParams);
2018 }
2019 else
2020 {
2021 /* Load/Unload must be called from system process */
2022 ExInitializeWorkItem(&LoadParams.WorkItem,
2023 (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
2024 (PVOID)&LoadParams);
2025
2026 /* Queue it */
2027 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
2028
2029 /* And wait when it completes */
2030 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
2031 FALSE, NULL);
2032 }
2033
2034 ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
2035 PreviousMode);
2036
2037 return LoadParams.Status;
2038 }
2039
2040 /*
2041 * NtUnloadDriver
2042 *
2043 * Unloads a legacy device driver.
2044 *
2045 * Parameters
2046 * DriverServiceName
2047 * Name of the service to unload (registry key).
2048 *
2049 * Return Value
2050 * Status
2051 *
2052 * Status
2053 * implemented
2054 */
2055
2056 NTSTATUS NTAPI
2057 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
2058 {
2059 return IopUnloadDriver(DriverServiceName, FALSE);
2060 }
2061
2062 /* EOF */