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